@atlaskit/editor-plugin-show-diff 19.0.2 → 19.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/cjs/pm-plugins/calculateDiff/calculateDiffDecorations.js +57 -93
- package/dist/cjs/pm-plugins/decorations/colorSchemes/factory.js +1 -1
- package/dist/cjs/pm-plugins/decorations/colorSchemes/standard.js +1 -26
- package/dist/cjs/pm-plugins/decorations/createBlockChangedDecoration.js +12 -24
- package/dist/cjs/pm-plugins/decorations/createBlockChangedDecoration.styles.legacy.js +25 -57
- package/dist/cjs/pm-plugins/decorations/createChangedRowDecorationWidgets.js +22 -60
- package/dist/cjs/pm-plugins/decorations/createInlineChangedDecoration.js +8 -16
- package/dist/cjs/pm-plugins/decorations/createInlineChangedDecoration.styles.legacy.js +7 -22
- package/dist/cjs/pm-plugins/decorations/createNodeChangedDecorationWidget.js +34 -52
- package/dist/cjs/pm-plugins/decorations/decorationKeys.js +6 -14
- package/dist/cjs/pm-plugins/decorations/utils/createDeletedLineBreakWidget.js +3 -8
- package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeView.js +132 -205
- package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +13 -20
- package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.legacy.js +6 -10
- package/dist/cjs/pm-plugins/getDefaultDiffType.js +10 -0
- package/dist/cjs/pm-plugins/getScrollableDecorations.js +5 -15
- package/dist/cjs/pm-plugins/main.js +45 -53
- package/dist/cjs/pm-plugins/resolveDiffContributors.js +18 -4
- package/dist/cjs/showDiffPlugin.js +14 -24
- package/dist/cjs/showDiffPluginType.js +1 -1
- package/dist/cjs/ui/ContributorTag/contributorAvatarRenderer.js +19 -9
- package/dist/cjs/ui/ContributorTag/contributorTagController.js +28 -3
- package/dist/cjs/ui/ContributorTag/contributorTagIcons.js +2 -2
- package/dist/es2019/pm-plugins/calculateDiff/calculateDiffDecorations.js +67 -105
- package/dist/es2019/pm-plugins/decorations/colorSchemes/factory.js +1 -1
- package/dist/es2019/pm-plugins/decorations/colorSchemes/standard.js +0 -26
- package/dist/es2019/pm-plugins/decorations/createBlockChangedDecoration.js +11 -23
- package/dist/es2019/pm-plugins/decorations/createBlockChangedDecoration.styles.legacy.js +25 -57
- package/dist/es2019/pm-plugins/decorations/createChangedRowDecorationWidgets.js +22 -60
- package/dist/es2019/pm-plugins/decorations/createInlineChangedDecoration.js +8 -18
- package/dist/es2019/pm-plugins/decorations/createInlineChangedDecoration.styles.legacy.js +8 -23
- package/dist/es2019/pm-plugins/decorations/createNodeChangedDecorationWidget.js +34 -54
- package/dist/es2019/pm-plugins/decorations/decorationKeys.js +6 -16
- package/dist/es2019/pm-plugins/decorations/utils/createDeletedLineBreakWidget.js +2 -7
- package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeView.js +53 -125
- package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +11 -12
- package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.legacy.js +6 -7
- package/dist/es2019/pm-plugins/getDefaultDiffType.js +2 -0
- package/dist/es2019/pm-plugins/getScrollableDecorations.js +6 -19
- package/dist/es2019/pm-plugins/main.js +49 -65
- package/dist/es2019/pm-plugins/resolveDiffContributors.js +18 -3
- package/dist/es2019/showDiffPlugin.js +12 -24
- package/dist/es2019/showDiffPluginType.js +1 -1
- package/dist/es2019/ui/ContributorTag/contributorAvatarRenderer.js +19 -9
- package/dist/es2019/ui/ContributorTag/contributorTagController.js +30 -2
- package/dist/es2019/ui/ContributorTag/contributorTagIcons.js +2 -2
- package/dist/esm/pm-plugins/calculateDiff/calculateDiffDecorations.js +56 -92
- package/dist/esm/pm-plugins/decorations/colorSchemes/factory.js +1 -1
- package/dist/esm/pm-plugins/decorations/colorSchemes/standard.js +0 -26
- package/dist/esm/pm-plugins/decorations/createBlockChangedDecoration.js +12 -24
- package/dist/esm/pm-plugins/decorations/createBlockChangedDecoration.styles.legacy.js +25 -57
- package/dist/esm/pm-plugins/decorations/createChangedRowDecorationWidgets.js +22 -60
- package/dist/esm/pm-plugins/decorations/createInlineChangedDecoration.js +8 -16
- package/dist/esm/pm-plugins/decorations/createInlineChangedDecoration.styles.legacy.js +8 -23
- package/dist/esm/pm-plugins/decorations/createNodeChangedDecorationWidget.js +34 -52
- package/dist/esm/pm-plugins/decorations/decorationKeys.js +6 -14
- package/dist/esm/pm-plugins/decorations/utils/createDeletedLineBreakWidget.js +3 -8
- package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeView.js +132 -205
- package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +13 -20
- package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.legacy.js +6 -10
- package/dist/esm/pm-plugins/getDefaultDiffType.js +4 -0
- package/dist/esm/pm-plugins/getScrollableDecorations.js +6 -16
- package/dist/esm/pm-plugins/main.js +44 -52
- package/dist/esm/pm-plugins/resolveDiffContributors.js +18 -4
- package/dist/esm/showDiffPlugin.js +14 -24
- package/dist/esm/showDiffPluginType.js +1 -1
- package/dist/esm/ui/ContributorTag/contributorAvatarRenderer.js +19 -9
- package/dist/esm/ui/ContributorTag/contributorTagController.js +28 -3
- package/dist/esm/ui/ContributorTag/contributorTagIcons.js +2 -2
- package/dist/types/pm-plugins/decorations/colorSchemes/factory.d.ts +1 -1
- package/dist/types/pm-plugins/decorations/colorSchemes/standard.d.ts +0 -3
- package/dist/types/pm-plugins/decorations/colorSchemes/types.d.ts +1 -1
- package/dist/types/pm-plugins/decorations/createBlockChangedDecoration.d.ts +1 -3
- package/dist/types/pm-plugins/decorations/createBlockChangedDecoration.styles.legacy.d.ts +2 -3
- package/dist/types/pm-plugins/decorations/createChangedRowDecorationWidgets.d.ts +1 -3
- package/dist/types/pm-plugins/decorations/createInlineChangedDecoration.d.ts +2 -3
- package/dist/types/pm-plugins/decorations/createInlineChangedDecoration.styles.legacy.d.ts +2 -3
- package/dist/types/pm-plugins/decorations/createNodeChangedDecorationWidget.d.ts +2 -3
- package/dist/types/pm-plugins/decorations/decorationKeys.d.ts +5 -8
- package/dist/types/pm-plugins/decorations/utils/createDeletedLineBreakWidget.d.ts +3 -5
- package/dist/types/pm-plugins/decorations/utils/wrapBlockNodeView.d.ts +4 -6
- package/dist/types/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.d.ts +3 -4
- package/dist/types/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.legacy.d.ts +4 -4
- package/dist/types/pm-plugins/getDefaultDiffType.d.ts +2 -0
- package/dist/types/pm-plugins/getScrollableDecorations.d.ts +1 -2
- package/dist/types/pm-plugins/main.d.ts +0 -1
- package/dist/types/showDiffPluginType.d.ts +1 -3
- package/docs/smart-diff-design.md +13 -29
- package/package.json +5 -5
- package/dist/cjs/pm-plugins/isExtendedEnabled.js +0 -23
- package/dist/es2019/pm-plugins/isExtendedEnabled.js +0 -13
- package/dist/esm/pm-plugins/isExtendedEnabled.js +0 -17
- package/dist/types/pm-plugins/isExtendedEnabled.d.ts +0 -12
|
@@ -20,8 +20,8 @@ import { createDeletedLineBreakDecoration } from '../decorations/utils/createDel
|
|
|
20
20
|
import { getAttrChangeRanges, stepIsValidAttrChange } from '../decorations/utils/getAttrChangeRanges';
|
|
21
21
|
import { getMarkChangeRanges } from '../decorations/utils/getMarkChangeRanges';
|
|
22
22
|
import { createRemovedLozenge } from '../decorations/utils/wrapBlockNodeView';
|
|
23
|
+
import { getDefaultDiffType } from '../getDefaultDiffType';
|
|
23
24
|
import { getScrollableDecorations } from '../getScrollableDecorations';
|
|
24
|
-
import { getDefaultDiffType, isExtendedEnabled } from '../isExtendedEnabled';
|
|
25
25
|
import { emptyTextBlockContentPositions } from '../utils/emptyTextBlocks';
|
|
26
26
|
import { diffBySteps } from './diffBySteps';
|
|
27
27
|
import { groupChangesByBlock } from './groupChangesByBlock';
|
|
@@ -44,28 +44,24 @@ const getChanges = ({
|
|
|
44
44
|
intl,
|
|
45
45
|
smartThresholds
|
|
46
46
|
}) => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (diffType === 'smart' && fg('platform_editor_ai_smart_diff')) {
|
|
52
|
-
const changes = simplifyChanges(changeset.changes, tr.doc);
|
|
53
|
-
return classifySmartChanges({
|
|
54
|
-
changes,
|
|
55
|
-
originalDoc,
|
|
56
|
-
newDoc: tr.doc,
|
|
57
|
-
locale: intl.locale,
|
|
58
|
-
thresholds: smartThresholds
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
if (diffType === 'step') {
|
|
62
|
-
return diffBySteps(originalDoc, steps);
|
|
63
|
-
}
|
|
64
|
-
if (diffType === 'block') {
|
|
65
|
-
return groupChangesByBlock(changeset.changes, originalDoc, steppedDoc);
|
|
66
|
-
}
|
|
47
|
+
// The `smart` diff type is gated behind `platform_editor_ai_smart_diff`. When the gate is
|
|
48
|
+
// off, `smart` falls through to the default (`inline`) path below so behaviour degrades
|
|
49
|
+
// gracefully (see docs/smart-diff-design.md §3).
|
|
50
|
+
if (diffType === 'smart' && fg('platform_editor_ai_smart_diff')) {
|
|
67
51
|
const changes = simplifyChanges(changeset.changes, tr.doc);
|
|
68
|
-
return
|
|
52
|
+
return classifySmartChanges({
|
|
53
|
+
changes,
|
|
54
|
+
originalDoc,
|
|
55
|
+
newDoc: tr.doc,
|
|
56
|
+
locale: intl.locale,
|
|
57
|
+
thresholds: smartThresholds
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (diffType === 'step') {
|
|
61
|
+
return diffBySteps(originalDoc, steps);
|
|
62
|
+
}
|
|
63
|
+
if (diffType === 'block') {
|
|
64
|
+
return groupChangesByBlock(changeset.changes, originalDoc, steppedDoc);
|
|
69
65
|
}
|
|
70
66
|
const changes = simplifyChanges(changeset.changes, tr.doc);
|
|
71
67
|
return optimizeChanges(changes);
|
|
@@ -82,13 +78,11 @@ const getAttributedChanges = ({
|
|
|
82
78
|
// the step attribution and promotes ranges to sentence/paragraph/node granularity, so a promoted
|
|
83
79
|
// range covers several actors' steps and the latest-writer rule credits all of it to one of them.
|
|
84
80
|
// The attributed changeset keeps step granularity instead.
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return groupChangesByBlock(changeset.changes, originalDoc, steppedDoc);
|
|
91
|
-
}
|
|
81
|
+
if (diffType === 'step') {
|
|
82
|
+
return attributedChanges;
|
|
83
|
+
}
|
|
84
|
+
if (diffType === 'block') {
|
|
85
|
+
return groupChangesByBlock(changeset.changes, originalDoc, steppedDoc);
|
|
92
86
|
}
|
|
93
87
|
return simplifyChangesWithAttribution(attributedChanges, tr.doc);
|
|
94
88
|
};
|
|
@@ -176,7 +170,6 @@ const calculateNodesForBlockDecoration = ({
|
|
|
176
170
|
shouldHideDeleted = false,
|
|
177
171
|
showContributorTags = false,
|
|
178
172
|
showIndicators = false,
|
|
179
|
-
diffType,
|
|
180
173
|
coarseTableCellsOnly = false,
|
|
181
174
|
tagMountContext,
|
|
182
175
|
nodeRanges
|
|
@@ -210,7 +203,6 @@ const calculateNodesForBlockDecoration = ({
|
|
|
210
203
|
showContributorTags,
|
|
211
204
|
showIndicators,
|
|
212
205
|
doc,
|
|
213
|
-
diffType,
|
|
214
206
|
tagMountContext
|
|
215
207
|
}));
|
|
216
208
|
}
|
|
@@ -232,7 +224,7 @@ const calculateNodesForBlockDecoration = ({
|
|
|
232
224
|
return;
|
|
233
225
|
}
|
|
234
226
|
}
|
|
235
|
-
if (node.isBlock && (!
|
|
227
|
+
if (node.isBlock && (!requireContainedBlocks || pos >= from) && pos + node.nodeSize <= to) {
|
|
236
228
|
const nodeEnd = pos + node.nodeSize;
|
|
237
229
|
const isActive = isRangeActive(activeIndexPos, pos, nodeEnd);
|
|
238
230
|
decorations.push(...createBlockChangedDecoration({
|
|
@@ -250,7 +242,6 @@ const calculateNodesForBlockDecoration = ({
|
|
|
250
242
|
showContributorTags,
|
|
251
243
|
showIndicators,
|
|
252
244
|
doc,
|
|
253
|
-
diffType,
|
|
254
245
|
tagMountContext
|
|
255
246
|
}));
|
|
256
247
|
}
|
|
@@ -300,10 +291,9 @@ export const isDeletedContentPlacedBelow = ({
|
|
|
300
291
|
*/
|
|
301
292
|
const shouldHideDeletedSide = ({
|
|
302
293
|
change,
|
|
303
|
-
diffType,
|
|
304
294
|
hideDeletedDiffs,
|
|
305
295
|
isInverted
|
|
306
|
-
}) =>
|
|
296
|
+
}) => !isInverted && !!hideDeletedDiffs && (change.inserted.length > 0 || fg('platform_editor_diff_hide_pure_deletions') && UNSAFE_expValNoExposure('platform_editor_ai_streaming_ux_experience_m1', 'isEnabled', false) === true);
|
|
307
297
|
const calculateDiffDecorationsInner = ({
|
|
308
298
|
state,
|
|
309
299
|
pluginState,
|
|
@@ -445,7 +435,7 @@ const calculateDiffDecorationsInner = ({
|
|
|
445
435
|
...attribution,
|
|
446
436
|
stepIndex
|
|
447
437
|
})));
|
|
448
|
-
attributedChanges =
|
|
438
|
+
attributedChanges = diffType === 'step' ? diffBySteps(originalDoc, simplifiedSteps, simplifiedStepAttributions) : [...changeset.changes];
|
|
449
439
|
// The attributed pipeline gives no guarantee that its output ranges are disjoint — see
|
|
450
440
|
// `collapseOverlappingChanges`.
|
|
451
441
|
const uncollapsedChanges = getAttributedChanges({
|
|
@@ -480,15 +470,13 @@ const calculateDiffDecorationsInner = ({
|
|
|
480
470
|
/**
|
|
481
471
|
* If showIndicators is on, we create an anchor widget here to mark the doc margin.
|
|
482
472
|
*/
|
|
483
|
-
if (showIndicators
|
|
473
|
+
if (showIndicators) {
|
|
484
474
|
decorations.push(createDocMarginAnchorWidget());
|
|
485
475
|
}
|
|
486
476
|
|
|
487
477
|
// Our default operations are insertions, so it should match the opposite of isInverted.
|
|
488
478
|
const isInserted = !isInverted;
|
|
489
|
-
|
|
490
|
-
changes = groupDeletedColumnChanges(changes, originalDoc, tr.doc, new Mapping(stepMaps), isInverted);
|
|
491
|
-
}
|
|
479
|
+
changes = groupDeletedColumnChanges(changes, originalDoc, tr.doc, new Mapping(stepMaps), isInverted);
|
|
492
480
|
// A whole-table change owns every mark and attribute range inside its bounds, so those ranges
|
|
493
481
|
// do not also get their own decoration.
|
|
494
482
|
const tableChanges = changes.filter(change => change.deletedColumns !== undefined);
|
|
@@ -547,7 +535,7 @@ const calculateDiffDecorationsInner = ({
|
|
|
547
535
|
});
|
|
548
536
|
if (change.inserted.length > 0) {
|
|
549
537
|
// On an inverted diff the inserted side is visually the deleted side.
|
|
550
|
-
const shouldHideDeleted =
|
|
538
|
+
const shouldHideDeleted = isInverted && hideDeletedDiffs;
|
|
551
539
|
|
|
552
540
|
// A removed blank line — an empty paragraph or heading — has nothing to mark up. On an
|
|
553
541
|
// inverted diff, the shape AI suggested edits renders, the block is still in the displayed
|
|
@@ -566,7 +554,6 @@ const calculateDiffDecorationsInner = ({
|
|
|
566
554
|
decorations.push(createDeletedLineBreakDecoration({
|
|
567
555
|
attributionKey,
|
|
568
556
|
colorScheme: changeColorScheme,
|
|
569
|
-
diffType,
|
|
570
557
|
isActive,
|
|
571
558
|
pos,
|
|
572
559
|
reveal,
|
|
@@ -596,7 +583,6 @@ const calculateDiffDecorationsInner = ({
|
|
|
596
583
|
// boundary to keep the indicator bar continuous with the deleted content.
|
|
597
584
|
const willRenderDeletedWidget = change.deleted.length > 0 && !isMarkOnly && !shouldHideDeletedSide({
|
|
598
585
|
change,
|
|
599
|
-
diffType,
|
|
600
586
|
hideDeletedDiffs,
|
|
601
587
|
isInverted
|
|
602
588
|
});
|
|
@@ -619,18 +605,15 @@ const calculateDiffDecorationsInner = ({
|
|
|
619
605
|
doc: tr.doc,
|
|
620
606
|
colorScheme: changeColorScheme,
|
|
621
607
|
isActive,
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
reveal,
|
|
632
|
-
tagMountContext
|
|
633
|
-
})
|
|
608
|
+
isInserted,
|
|
609
|
+
shouldHideDeleted,
|
|
610
|
+
showContributorTags,
|
|
611
|
+
showIndicators,
|
|
612
|
+
hideAddedDiffsUnderline,
|
|
613
|
+
hasDeletedWidget: willRenderDeletedWidget,
|
|
614
|
+
isDeletedWidgetBelow,
|
|
615
|
+
reveal,
|
|
616
|
+
tagMountContext
|
|
634
617
|
}));
|
|
635
618
|
}
|
|
636
619
|
} else {
|
|
@@ -641,18 +624,15 @@ const calculateDiffDecorationsInner = ({
|
|
|
641
624
|
doc: tr.doc,
|
|
642
625
|
colorScheme: changeColorScheme,
|
|
643
626
|
isActive,
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
reveal,
|
|
654
|
-
tagMountContext
|
|
655
|
-
})
|
|
627
|
+
isInserted,
|
|
628
|
+
shouldHideDeleted,
|
|
629
|
+
showContributorTags,
|
|
630
|
+
showIndicators,
|
|
631
|
+
hideAddedDiffsUnderline,
|
|
632
|
+
hasDeletedWidget: willRenderDeletedWidget,
|
|
633
|
+
isDeletedWidgetBelow,
|
|
634
|
+
reveal,
|
|
635
|
+
tagMountContext
|
|
656
636
|
}));
|
|
657
637
|
}
|
|
658
638
|
decorations.push(...calculateNodesForBlockDecoration({
|
|
@@ -663,16 +643,13 @@ const calculateDiffDecorationsInner = ({
|
|
|
663
643
|
// A split piece's own range no longer covers the container it opened (EDITOR-8932).
|
|
664
644
|
nodeRanges: change.blockNodeRangesB,
|
|
665
645
|
colorScheme: changeColorScheme,
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
tagMountContext
|
|
672
|
-
}),
|
|
646
|
+
isInserted,
|
|
647
|
+
shouldHideDeleted,
|
|
648
|
+
showContributorTags,
|
|
649
|
+
showIndicators,
|
|
650
|
+
tagMountContext,
|
|
673
651
|
activeIndexPos,
|
|
674
652
|
intl,
|
|
675
|
-
diffType,
|
|
676
653
|
coarseTableCellsOnly: useCoarseTableDecoration,
|
|
677
654
|
leftAnchorId
|
|
678
655
|
}));
|
|
@@ -680,7 +657,6 @@ const calculateDiffDecorationsInner = ({
|
|
|
680
657
|
if (change.deleted.length > 0 && !isMarkOnly && !hasNoDeletedContent) {
|
|
681
658
|
const shouldHideDeleted = shouldHideDeletedSide({
|
|
682
659
|
change,
|
|
683
|
-
diffType,
|
|
684
660
|
hideDeletedDiffs,
|
|
685
661
|
isInverted
|
|
686
662
|
});
|
|
@@ -689,9 +665,7 @@ const calculateDiffDecorationsInner = ({
|
|
|
689
665
|
deletedColumns,
|
|
690
666
|
// The deleted side has no inline decoration, so the widget carries the actor.
|
|
691
667
|
attributionKey,
|
|
692
|
-
|
|
693
|
-
// background for the wipe to act on.
|
|
694
|
-
reveal: isExtendedEnabled(diffType) ? reveal : undefined,
|
|
668
|
+
reveal,
|
|
695
669
|
change,
|
|
696
670
|
doc: originalDoc,
|
|
697
671
|
nodeViewSerializer,
|
|
@@ -702,12 +676,9 @@ const calculateDiffDecorationsInner = ({
|
|
|
702
676
|
leftAnchorId,
|
|
703
677
|
showContributorTags,
|
|
704
678
|
tagMountContext,
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
hideAddedDiffsUnderline,
|
|
709
|
-
placeBelow: isDeletedWidgetBelow
|
|
710
|
-
}),
|
|
679
|
+
isInserted: !isInserted,
|
|
680
|
+
hideAddedDiffsUnderline,
|
|
681
|
+
placeBelow: isDeletedWidgetBelow,
|
|
711
682
|
showIndicators
|
|
712
683
|
}));
|
|
713
684
|
}
|
|
@@ -736,7 +707,6 @@ const calculateDiffDecorationsInner = ({
|
|
|
736
707
|
change,
|
|
737
708
|
colorScheme: changeColorScheme,
|
|
738
709
|
doc: tr.doc,
|
|
739
|
-
diffType,
|
|
740
710
|
isActive,
|
|
741
711
|
isInserted: true,
|
|
742
712
|
reveal,
|
|
@@ -770,8 +740,7 @@ const calculateDiffDecorationsInner = ({
|
|
|
770
740
|
tagMountContext,
|
|
771
741
|
// Suppress the border-bottom underline for atomic inline nodeviews —
|
|
772
742
|
// it doesn't render on custom nodeview DOM elements and is unnecessary noise.
|
|
773
|
-
hideAddedDiffsUnderline: true
|
|
774
|
-
diffType
|
|
743
|
+
hideAddedDiffsUnderline: true
|
|
775
744
|
}));
|
|
776
745
|
// If we have the original node position, also render the old node as a "deleted" widget
|
|
777
746
|
// so the user can see what it looked like before the change.
|
|
@@ -831,11 +800,8 @@ const calculateDiffDecorationsInner = ({
|
|
|
831
800
|
intl,
|
|
832
801
|
activeIndexPos,
|
|
833
802
|
isInserted: false,
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
hideAddedDiffsUnderline,
|
|
837
|
-
placeBelow
|
|
838
|
-
}),
|
|
803
|
+
hideAddedDiffsUnderline,
|
|
804
|
+
placeBelow,
|
|
839
805
|
showIndicators,
|
|
840
806
|
showContributorTags,
|
|
841
807
|
tagMountContext
|
|
@@ -848,7 +814,7 @@ const calculateDiffDecorationsInner = ({
|
|
|
848
814
|
contributorTags: showContributorTags ? extractContributorTags(decorationSet, contributors, activeIndexPos,
|
|
849
815
|
// The stops the step buttons walk, so a stop cannot hold a second tag for one
|
|
850
816
|
// contributor that navigation can never reach.
|
|
851
|
-
getScrollableDecorations(decorationSet, tr.doc
|
|
817
|
+
getScrollableDecorations(decorationSet, tr.doc)) : [],
|
|
852
818
|
decorations: decorationSet,
|
|
853
819
|
diffDescriptors: extractDiffDescriptors(decorationSet)
|
|
854
820
|
};
|
|
@@ -887,16 +853,12 @@ export const calculateDiffDecorations = memoizeOne(calculateDiffDecorationsInner
|
|
|
887
853
|
inlineDeletedDiffPlacement: lastInlineDeletedDiffPlacement,
|
|
888
854
|
reveal: lastReveal
|
|
889
855
|
}]) => {
|
|
890
|
-
var
|
|
856
|
+
var _ref;
|
|
891
857
|
const originalDocIsSame = lastPluginState.originalDoc && pluginState.originalDoc && pluginState.originalDoc.eq(lastPluginState.originalDoc);
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
// other setting would leave the diff painted in the wrong resting state.
|
|
899
|
-
isEqual(reveal, lastReveal)) !== null && _ref !== void 0 ? _ref : false;
|
|
900
|
-
}
|
|
901
|
-
return (_ref2 = originalDocIsSame && isEqual(pluginState.steps, lastPluginState.steps) && isEqual(pluginState.stepAttributions, lastPluginState.stepAttributions) && isEqual(pluginState.contributors, lastPluginState.contributors) && state.doc.eq(lastState.doc) && colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isEqual(activeIndexPos, lastActiveIndexPos) && hideDeletedDiffs === lastHideDeletedDiffs) !== null && _ref2 !== void 0 ? _ref2 : false;
|
|
858
|
+
return (_ref = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && isEqual(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && isEqual(pluginState.steps, lastPluginState.steps) && isEqual(pluginState.stepAttributions, lastPluginState.stepAttributions) &&
|
|
859
|
+
// Contributors can arrive after the first calculation; without this, tags never appear.
|
|
860
|
+
isEqual(pluginState.contributors, lastPluginState.contributors) && state.doc.eq(lastState.doc) && hideDeletedDiffs === lastHideDeletedDiffs && hideAddedDiffsUnderline === lastHideAddedDiffsUnderline && showIndicators === lastShowIndicators && isEqual(smartThresholds, lastSmartThresholds) && deletedDiffPlacement === lastDeletedDiffPlacement && inlineDeletedDiffPlacement === lastInlineDeletedDiffPlacement &&
|
|
861
|
+
// Turning the reveal on or off changes the emitted styles, so a cached result from the
|
|
862
|
+
// other setting would leave the diff painted in the wrong resting state.
|
|
863
|
+
isEqual(reveal, lastReveal)) !== null && _ref !== void 0 ? _ref : false;
|
|
902
864
|
});
|
|
@@ -829,7 +829,7 @@ export function buildDeletedCellOverlayRoundedStyle(colors) {
|
|
|
829
829
|
// --- Inline content style dispatch ---
|
|
830
830
|
|
|
831
831
|
/**
|
|
832
|
-
* Inserted inline content
|
|
832
|
+
* Inserted inline content. `insertedInlineTreatment` picks
|
|
833
833
|
* `text-decoration` vs a `border-bottom` rule; only the latter honours `hideAddedDiffsUnderline`.
|
|
834
834
|
*/
|
|
835
835
|
export function buildInsertedInlineStyle(colors, isActive, hideAddedDiffsUnderline) {
|
|
@@ -1,31 +1,5 @@
|
|
|
1
1
|
import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
|
|
2
2
|
import { getStandardDeletedTextDecorationStyle } from './getStandardDeletedTextDecorationStyle';
|
|
3
|
-
|
|
4
|
-
// delete on platform_editor_diff_plugin_extended cleanup
|
|
5
|
-
export const editingStyle = convertToInlineCss({
|
|
6
|
-
background: "var(--ds-background-accent-purple-subtlest, #F8EEFE)",
|
|
7
|
-
textDecoration: 'underline',
|
|
8
|
-
textDecorationStyle: 'dotted',
|
|
9
|
-
textDecorationThickness: "var(--ds-space-025, 2px)",
|
|
10
|
-
textDecorationColor: "var(--ds-border-accent-purple, #AF59E1)"
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
// delete on platform_editor_diff_plugin_extended cleanup
|
|
14
|
-
export const editingContentStyleInBlock = convertToInlineCss({
|
|
15
|
-
textDecoration: 'underline',
|
|
16
|
-
textDecorationStyle: 'dotted',
|
|
17
|
-
textDecorationThickness: "var(--ds-space-025, 2px)",
|
|
18
|
-
textDecorationColor: "var(--ds-border-accent-purple, #AF59E1)"
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
// delete on platform_editor_diff_plugin_extended cleanup
|
|
22
|
-
export const editingStyleActive = convertToInlineCss({
|
|
23
|
-
background: "var(--ds-background-accent-purple-subtler-pressed, #D8A0F7)",
|
|
24
|
-
textDecoration: 'underline',
|
|
25
|
-
textDecorationStyle: 'dotted',
|
|
26
|
-
textDecorationThickness: "var(--ds-space-025, 2px)",
|
|
27
|
-
textDecorationColor: "var(--ds-text-accent-purple, #803FA5)"
|
|
28
|
-
});
|
|
29
3
|
export const editingStyleExtended = convertToInlineCss({
|
|
30
4
|
background: "var(--ds-background-accent-purple-subtlest, #F8EEFE)",
|
|
31
5
|
borderBottom: `2px solid ${"var(--ds-border-accent-purple, #AF59E1)"}`,
|
|
@@ -3,7 +3,6 @@ import { findParentNodeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
|
|
|
3
3
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
4
4
|
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
5
5
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
6
|
-
import { isExtendedEnabled } from '../isExtendedEnabled';
|
|
7
6
|
import { isTaggableBlockNode } from '../utils/taggableBlockNodes';
|
|
8
7
|
import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildDeletedBlockNodeStyle, buildDeletedCellOverlayRoundedStyle, buildDeletedCellOverlayStyle, buildInsertedBlockNodeStyle } from './colorSchemes/factory';
|
|
9
8
|
import { colorSchemeRegistry, getLegacyColorScheme } from './colorSchemes/schemes';
|
|
@@ -35,12 +34,11 @@ const isInsideTable = (doc, pos) => findParentNodeClosestToPos(doc.resolve(pos),
|
|
|
35
34
|
* position, so `nodeAt` returns exactly the node being decorated.
|
|
36
35
|
*/
|
|
37
36
|
const canTagBlock = ({
|
|
38
|
-
diffType,
|
|
39
37
|
doc,
|
|
40
38
|
from
|
|
41
39
|
}) => {
|
|
42
40
|
var _doc$nodeAt;
|
|
43
|
-
if (doc === undefined
|
|
41
|
+
if (doc === undefined) {
|
|
44
42
|
return false;
|
|
45
43
|
}
|
|
46
44
|
const nodeType = (_doc$nodeAt = doc.nodeAt(from)) === null || _doc$nodeAt === void 0 ? void 0 : _doc$nodeAt.type;
|
|
@@ -97,20 +95,16 @@ const getBlockNodeStyleNext = ({
|
|
|
97
95
|
nodeName,
|
|
98
96
|
colorScheme,
|
|
99
97
|
isInserted = true,
|
|
100
|
-
isActive = false
|
|
101
|
-
diffType
|
|
98
|
+
isActive = false
|
|
102
99
|
}) => {
|
|
103
100
|
if (UNSTYLED_NODES.includes(nodeName)) {
|
|
104
101
|
return undefined;
|
|
105
102
|
}
|
|
106
103
|
if (CELL_NODES.includes(nodeName)) {
|
|
107
|
-
|
|
108
|
-
return isExtendedEnabled(diffType) ? cellPositionStyle : undefined;
|
|
104
|
+
return cellPositionStyle;
|
|
109
105
|
}
|
|
110
106
|
const colors = colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : DEFAULT_COLOR_SCHEME];
|
|
111
|
-
|
|
112
|
-
// Deleted nodes only differ under the extended experience; otherwise all are insertions.
|
|
113
|
-
if (!isInserted && isExtendedEnabled(diffType)) {
|
|
107
|
+
if (!isInserted) {
|
|
114
108
|
return buildDeletedBlockNodeStyle(colors, getDeletedBlockNodeCategory(nodeName), isActive);
|
|
115
109
|
}
|
|
116
110
|
return buildInsertedBlockNodeStyle(colors, getInsertedBlockNodeShape(nodeName), isActive);
|
|
@@ -173,7 +167,6 @@ export const createBlockChangedDecoration = ({
|
|
|
173
167
|
showContributorTags = false,
|
|
174
168
|
showIndicators = false,
|
|
175
169
|
doc,
|
|
176
|
-
diffType,
|
|
177
170
|
tagMountContext
|
|
178
171
|
}) => {
|
|
179
172
|
const decorations = [];
|
|
@@ -181,7 +174,6 @@ export const createBlockChangedDecoration = ({
|
|
|
181
174
|
// `createInlineChangedDecoration`. Changes are disjoint, so no two of them decorate one node.
|
|
182
175
|
const diffId = showContributorTags ? `block-${change.from}-${change.to}` : crypto.randomUUID();
|
|
183
176
|
const shouldTagBlock = showContributorTags && canTagBlock({
|
|
184
|
-
diffType,
|
|
185
177
|
doc,
|
|
186
178
|
from: change.from
|
|
187
179
|
});
|
|
@@ -200,11 +192,10 @@ export const createBlockChangedDecoration = ({
|
|
|
200
192
|
leftAnchorId,
|
|
201
193
|
isActive,
|
|
202
194
|
isInserted,
|
|
203
|
-
nodeName: change.name
|
|
204
|
-
diffType
|
|
195
|
+
nodeName: change.name
|
|
205
196
|
}))];
|
|
206
197
|
}
|
|
207
|
-
if (
|
|
198
|
+
if (CELL_NODES.includes(change.name)) {
|
|
208
199
|
const cellOverlay = document.createElement('div');
|
|
209
200
|
const colors = colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : DEFAULT_COLOR_SCHEME];
|
|
210
201
|
const isRoundedTable = isExperimentEnabled('platform_editor_table_diff_rounded_corners');
|
|
@@ -228,15 +219,13 @@ export const createBlockChangedDecoration = ({
|
|
|
228
219
|
key: 'cell-overlay-decoration'
|
|
229
220
|
}));
|
|
230
221
|
}
|
|
231
|
-
//
|
|
232
|
-
//
|
|
233
|
-
// variant's legacy style is untouched — see `resolveBaseNodeName`.
|
|
222
|
+
// `change.name` verbatim: base-name resolution stays in `canTagBlock`, which needs tags on, so a
|
|
223
|
+
// schema variant's legacy style is untouched — see `resolveBaseNodeName`.
|
|
234
224
|
const nodeStyle = getBlockNodeStyle({
|
|
235
225
|
nodeName: change.name,
|
|
236
226
|
colorScheme,
|
|
237
227
|
isInserted,
|
|
238
|
-
isActive
|
|
239
|
-
diffType
|
|
228
|
+
isActive
|
|
240
229
|
});
|
|
241
230
|
const style = tagAnchorName ? [nodeStyle, convertToInlineCss({
|
|
242
231
|
anchorName: `--${tagAnchorName}`
|
|
@@ -259,8 +248,7 @@ export const createBlockChangedDecoration = ({
|
|
|
259
248
|
leftAnchorId,
|
|
260
249
|
isActive,
|
|
261
250
|
isInserted,
|
|
262
|
-
nodeName: change.name
|
|
263
|
-
diffType
|
|
251
|
+
nodeName: change.name
|
|
264
252
|
})));
|
|
265
253
|
}
|
|
266
254
|
if (decorations.length === 0) {
|
|
@@ -268,7 +256,7 @@ export const createBlockChangedDecoration = ({
|
|
|
268
256
|
// there is nothing for a tag to hang off even when the node type would otherwise be taggable.
|
|
269
257
|
return decorations;
|
|
270
258
|
}
|
|
271
|
-
if (showIndicators && doc
|
|
259
|
+
if (showIndicators && doc) {
|
|
272
260
|
decorations.push(...createBlockIndicatorAnchorWidgets({
|
|
273
261
|
doc,
|
|
274
262
|
from: change.from,
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
* cleanup, together with `colorSchemes/standard.ts`, `colorSchemes/traditional.ts` (EDITOR-8281).
|
|
10
10
|
*/
|
|
11
11
|
import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
|
|
12
|
-
import { isExtendedEnabled } from '../isExtendedEnabled';
|
|
13
12
|
import { standardDecorationMarkerVariable, deletedDecorationMarkerVariable, editingStyleQuoteNode, editingStyleRuleNode, editingStyleCardBlockNode, editingStyleNode, getStandardDeletedContentStyleNew, deletedStyleQuoteNode, addedCellOverlayStyle, addedCellOverlayRoundedStyle, deletedCellOverlayStyle, deletedCellOverlayRoundedStyle } from './colorSchemes/standard';
|
|
14
13
|
import { traditionalDecorationMarkerVariableActive, traditionalDecorationMarkerVariableNew, traditionalDeletedDecorationMarkerVariableActive, traditionalDeletedDecorationMarkerVariableNew, traditionalStyleQuoteNodeActive, traditionalStyleQuoteNodeNew, traditionalStyleRuleNodeActive, traditionalStyleRuleNodeNew, traditionalStyleCardBlockNodeActive, traditionalStyleCardBlockNodeNew, traditionalStyleNodeActive, traditionalStyleNodeNew, getDeletedTraditionalInlineStyle, deletedTraditionalStyleQuoteNode, traditionalAddedCellOverlayStyle, traditionalAddedCellOverlayRoundedStyle, deletedTraditionalCellOverlayStyle, deletedTraditionalCellOverlayRoundedStyle } from './colorSchemes/traditional';
|
|
15
14
|
|
|
@@ -28,8 +27,7 @@ export const getBlockNodeStyleLegacy = ({
|
|
|
28
27
|
nodeName,
|
|
29
28
|
colorScheme,
|
|
30
29
|
isInserted = true,
|
|
31
|
-
isActive = false
|
|
32
|
-
diffType
|
|
30
|
+
isActive = false
|
|
33
31
|
}) => {
|
|
34
32
|
const isTraditional = colorScheme === 'traditional';
|
|
35
33
|
if (['mediaSingle', 'mediaGroup', 'table',
|
|
@@ -42,77 +40,47 @@ export const getBlockNodeStyleLegacy = ({
|
|
|
42
40
|
}
|
|
43
41
|
// Media nodes inside mediaSingle should not get position:relative
|
|
44
42
|
// as it shifts the image outside its parent container (e.g. panel)
|
|
45
|
-
if (nodeName === 'media') {
|
|
46
|
-
if (!isInserted
|
|
43
|
+
if (nodeName === 'media' || nodeName === 'panel') {
|
|
44
|
+
if (!isInserted) {
|
|
47
45
|
return isTraditional ? getDeletedTraditionalInlineStyle(false) : deletedDecorationMarkerVariable;
|
|
48
46
|
}
|
|
49
47
|
return isTraditional ? isActive ? traditionalStyleNodeActive : traditionalStyleNodeNew : editingStyleNode;
|
|
50
48
|
}
|
|
51
49
|
if (['tableCell', 'tableHeader'].includes(nodeName)) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
// When gate is off, it should return undefined as above
|
|
59
|
-
return undefined;
|
|
60
|
-
}
|
|
61
|
-
if (nodeName === 'panel') {
|
|
62
|
-
if (!isInserted && isExtendedEnabled(diffType)) {
|
|
63
|
-
return isTraditional ? getDeletedTraditionalInlineStyle(false) : deletedDecorationMarkerVariable;
|
|
64
|
-
}
|
|
65
|
-
return isTraditional ? isActive ? traditionalStyleNodeActive : traditionalStyleNodeNew : editingStyleNode;
|
|
50
|
+
// This is used for positioning the cell overlay widget decorations
|
|
51
|
+
return convertToInlineCss({
|
|
52
|
+
position: 'relative'
|
|
53
|
+
});
|
|
66
54
|
}
|
|
67
55
|
if (['extension', 'embedCard', 'listItem'].includes(nodeName)) {
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
return isTraditional && isActive ? traditionalDecorationMarkerVariableActive : isTraditional ? traditionalDecorationMarkerVariableNew : standardDecorationMarkerVariable;
|
|
71
|
-
} else {
|
|
72
|
-
if (nodeName === 'listItem') {
|
|
73
|
-
return isTraditional && isActive ? traditionalDeletedDecorationMarkerVariableActive : isTraditional ? traditionalDeletedDecorationMarkerVariableNew : deletedDecorationMarkerVariable;
|
|
74
|
-
}
|
|
75
|
-
return isTraditional && isActive ? traditionalDeletedDecorationMarkerVariableActive : isTraditional ? traditionalDeletedDecorationMarkerVariableNew : getStandardDeletedContentStyleNew();
|
|
76
|
-
}
|
|
56
|
+
if (isInserted) {
|
|
57
|
+
return isTraditional && isActive ? traditionalDecorationMarkerVariableActive : isTraditional ? traditionalDecorationMarkerVariableNew : standardDecorationMarkerVariable;
|
|
77
58
|
}
|
|
78
|
-
|
|
59
|
+
if (nodeName === 'listItem') {
|
|
60
|
+
return isTraditional && isActive ? traditionalDeletedDecorationMarkerVariableActive : isTraditional ? traditionalDeletedDecorationMarkerVariableNew : deletedDecorationMarkerVariable;
|
|
61
|
+
}
|
|
62
|
+
return isTraditional && isActive ? traditionalDeletedDecorationMarkerVariableActive : isTraditional ? traditionalDeletedDecorationMarkerVariableNew : getStandardDeletedContentStyleNew();
|
|
79
63
|
}
|
|
80
64
|
if (nodeName === 'blockquote') {
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
return isTraditional ? isActive ? traditionalStyleQuoteNodeActive : traditionalStyleQuoteNodeNew : editingStyleQuoteNode;
|
|
84
|
-
} else {
|
|
85
|
-
return isTraditional ? deletedTraditionalStyleQuoteNode : deletedStyleQuoteNode;
|
|
86
|
-
}
|
|
65
|
+
if (isInserted) {
|
|
66
|
+
return isTraditional ? isActive ? traditionalStyleQuoteNodeActive : traditionalStyleQuoteNodeNew : editingStyleQuoteNode;
|
|
87
67
|
}
|
|
88
|
-
return isTraditional ?
|
|
68
|
+
return isTraditional ? deletedTraditionalStyleQuoteNode : deletedStyleQuoteNode;
|
|
89
69
|
}
|
|
90
70
|
if (nodeName === 'rule') {
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
-
return isTraditional ? isActive ? traditionalStyleRuleNodeActive : traditionalStyleRuleNodeNew : editingStyleRuleNode;
|
|
94
|
-
} else {
|
|
95
|
-
return isTraditional ? getDeletedTraditionalInlineStyle(false) : getStandardDeletedContentStyleNew();
|
|
96
|
-
}
|
|
71
|
+
if (isInserted) {
|
|
72
|
+
return isTraditional ? isActive ? traditionalStyleRuleNodeActive : traditionalStyleRuleNodeNew : editingStyleRuleNode;
|
|
97
73
|
}
|
|
98
|
-
return isTraditional ?
|
|
74
|
+
return isTraditional ? getDeletedTraditionalInlineStyle(false) : getStandardDeletedContentStyleNew();
|
|
99
75
|
}
|
|
100
76
|
if (nodeName === 'blockCard') {
|
|
101
|
-
if (isExtendedEnabled(diffType)) {
|
|
102
|
-
if (isInserted) {
|
|
103
|
-
return isTraditional ? isActive ? traditionalStyleCardBlockNodeActive : traditionalStyleCardBlockNodeNew : editingStyleCardBlockNode;
|
|
104
|
-
} else {
|
|
105
|
-
return isTraditional ? getDeletedTraditionalInlineStyle(false) : getStandardDeletedContentStyleNew();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return isTraditional ? isActive ? traditionalStyleCardBlockNodeActive : traditionalStyleCardBlockNodeNew : editingStyleCardBlockNode;
|
|
109
|
-
}
|
|
110
|
-
if (isExtendedEnabled(diffType)) {
|
|
111
77
|
if (isInserted) {
|
|
112
|
-
return isTraditional ? isActive ?
|
|
113
|
-
} else {
|
|
114
|
-
return isTraditional ? getDeletedTraditionalInlineStyle(false) : getStandardDeletedContentStyleNew();
|
|
78
|
+
return isTraditional ? isActive ? traditionalStyleCardBlockNodeActive : traditionalStyleCardBlockNodeNew : editingStyleCardBlockNode;
|
|
115
79
|
}
|
|
80
|
+
return isTraditional ? getDeletedTraditionalInlineStyle(false) : getStandardDeletedContentStyleNew();
|
|
81
|
+
}
|
|
82
|
+
if (isInserted) {
|
|
83
|
+
return isTraditional ? isActive ? traditionalStyleNodeActive : traditionalStyleNodeNew : editingStyleNode;
|
|
116
84
|
}
|
|
117
|
-
return isTraditional ?
|
|
85
|
+
return isTraditional ? getDeletedTraditionalInlineStyle(false) : getStandardDeletedContentStyleNew();
|
|
118
86
|
};
|