@atlaskit/editor-plugin-show-diff 13.0.11 → 13.1.1

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/afm-cc/tsconfig.json +3 -0
  3. package/afm-products/tsconfig.json +3 -0
  4. package/dist/cjs/pm-plugins/decorations/colorSchemes/factory.js +259 -23
  5. package/dist/cjs/pm-plugins/decorations/colorSchemes/schemes.js +21 -5
  6. package/dist/cjs/pm-plugins/decorations/createBlockChangedDecoration.js +87 -105
  7. package/dist/cjs/pm-plugins/decorations/createBlockChangedDecoration.styles.legacy.js +124 -0
  8. package/dist/cjs/pm-plugins/decorations/createChangedRowDecorationWidgets.js +15 -12
  9. package/dist/cjs/pm-plugins/decorations/createChangedRowDecorationWidgets.styles.legacy.js +37 -0
  10. package/dist/cjs/pm-plugins/decorations/createInlineChangedDecoration.js +109 -59
  11. package/dist/cjs/pm-plugins/decorations/createInlineChangedDecoration.styles.legacy.js +67 -0
  12. package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeView.js +30 -168
  13. package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +205 -0
  14. package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.legacy.js +225 -0
  15. package/dist/es2019/pm-plugins/decorations/colorSchemes/factory.js +247 -23
  16. package/dist/es2019/pm-plugins/decorations/colorSchemes/schemes.js +20 -4
  17. package/dist/es2019/pm-plugins/decorations/createBlockChangedDecoration.js +85 -105
  18. package/dist/es2019/pm-plugins/decorations/createBlockChangedDecoration.styles.legacy.js +118 -0
  19. package/dist/es2019/pm-plugins/decorations/createChangedRowDecorationWidgets.js +15 -12
  20. package/dist/es2019/pm-plugins/decorations/createChangedRowDecorationWidgets.styles.legacy.js +33 -0
  21. package/dist/es2019/pm-plugins/decorations/createInlineChangedDecoration.js +82 -37
  22. package/dist/es2019/pm-plugins/decorations/createInlineChangedDecoration.styles.legacy.js +62 -0
  23. package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeView.js +15 -140
  24. package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +143 -0
  25. package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.legacy.js +200 -0
  26. package/dist/esm/pm-plugins/decorations/colorSchemes/factory.js +248 -23
  27. package/dist/esm/pm-plugins/decorations/colorSchemes/schemes.js +20 -4
  28. package/dist/esm/pm-plugins/decorations/createBlockChangedDecoration.js +87 -105
  29. package/dist/esm/pm-plugins/decorations/createBlockChangedDecoration.styles.legacy.js +118 -0
  30. package/dist/esm/pm-plugins/decorations/createChangedRowDecorationWidgets.js +15 -12
  31. package/dist/esm/pm-plugins/decorations/createChangedRowDecorationWidgets.styles.legacy.js +32 -0
  32. package/dist/esm/pm-plugins/decorations/createInlineChangedDecoration.js +109 -59
  33. package/dist/esm/pm-plugins/decorations/createInlineChangedDecoration.styles.legacy.js +61 -0
  34. package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeView.js +15 -153
  35. package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.js +198 -0
  36. package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.legacy.js +218 -0
  37. package/dist/types/pm-plugins/decorations/colorSchemes/factory.d.ts +78 -6
  38. package/dist/types/pm-plugins/decorations/colorSchemes/schemes.d.ts +3 -0
  39. package/dist/types/pm-plugins/decorations/colorSchemes/types.d.ts +13 -3
  40. package/dist/types/pm-plugins/decorations/createBlockChangedDecoration.styles.legacy.d.ts +14 -0
  41. package/dist/types/pm-plugins/decorations/createChangedRowDecorationWidgets.styles.legacy.d.ts +22 -0
  42. package/dist/types/pm-plugins/decorations/createInlineChangedDecoration.styles.legacy.d.ts +26 -0
  43. package/dist/types/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.d.ts +39 -0
  44. package/dist/types/pm-plugins/decorations/utils/wrapBlockNodeViewStyles.legacy.d.ts +40 -0
  45. package/package.json +4 -3
@@ -73,16 +73,16 @@ function textAccent(color) {
73
73
  return textAccentMap[color];
74
74
  }
75
75
 
76
- /** Outline colour for deleted table-cell overlays. */
77
- function deletedCellOutline(colors) {
78
- return colors.deletedCellBorderProminence === 'subtle' ? "var(--ds-border-disabled, #0515240F)" : borderAccent(colors.deletedCellColor);
79
- }
80
-
81
76
  /** Ring colour for an active (scroll-target) deleted block outline. */
82
77
  function deletedBlockOutlineActiveRing(colors) {
83
78
  return colors.deletedBlockOutlineActiveEmphasis === 'border' ? borderAccent(colors.deleteActiveColor) : bgSubtlerPressed(colors.deleteActiveColor);
84
79
  }
85
80
 
81
+ /** Outline colour for deleted table-cell overlays. */
82
+ function deletedCellOutline(colors) {
83
+ return colors.deletedCellBorderProminence === 'subtle' ? "var(--ds-border-disabled, #0515240F)" : borderAccent(colors.deletedCellColor);
84
+ }
85
+
86
86
  // --- Inserted content styles ---
87
87
 
88
88
  /** Inline inserted content — default state. */
@@ -168,6 +168,7 @@ export function buildInsertStyleActive(colors) {
168
168
 
169
169
  // --- Deleted inline content styles ---
170
170
 
171
+ /** Base deleted-inline-style object, shared by several exports. */
171
172
  function deletedInlineStyleBase(colors) {
172
173
  return {
173
174
  textDecorationColor: borderAccent(colors.deleteColor),
@@ -176,6 +177,8 @@ function deletedInlineStyleBase(colors) {
176
177
  opacity: 1
177
178
  };
178
179
  }
180
+
181
+ /** Active deleted-inline-style object, extending the base. */
179
182
  function deletedInlineStyleActiveBase(colors) {
180
183
  return {
181
184
  ...deletedInlineStyleBase(colors),
@@ -253,8 +256,6 @@ export function buildDeletedStyleQuoteNodeWithLozengeActive(colors) {
253
256
  borderRadius: "var(--ds-radius-small, 4px)"
254
257
  });
255
258
  }
256
-
257
- /** Deleted quote node — a 2px left border, or a 1px ring with padding, per `deletedQuoteNodeShape`. */
258
259
  export function buildDeletedStyleQuoteNode(colors) {
259
260
  if (colors.deletedQuoteNodeShape === 'borderLeft') {
260
261
  return convertToInlineCss({
@@ -335,19 +336,19 @@ export function buildDeletedBlockOutlineRoundedNew(colors) {
335
336
 
336
337
  // --- Deleted table row style ---
337
338
 
338
- /** Table row style for deleted rows. See `deletedRowTreatment`. */
339
+ /** Table row style for deleted rows. */
339
340
  export function buildDeletedRowStyle(colors) {
340
- const base = {
341
+ // Each branch emits exactly the CSS the pre-factory shim did for its scheme.
342
+ return colors.deletedRowTreatment === 'textTint' ? convertToInlineCss({
343
+ color: textAccent(colors.deleteColor),
341
344
  textDecoration: 'line-through',
342
345
  opacity: 0.6,
343
346
  display: 'table-row'
344
- };
345
- return colors.deletedRowTreatment === 'textTint' ? convertToInlineCss({
346
- ...base,
347
- color: textAccent(colors.deleteColor)
348
347
  }) : convertToInlineCss({
349
- ...base,
350
- textDecorationColor: borderAccent(colors.deleteColor)
348
+ textDecorationColor: borderAccent(colors.deleteColor),
349
+ textDecoration: 'line-through',
350
+ opacity: 0.6,
351
+ display: 'table-row'
351
352
  });
352
353
  }
353
354
 
@@ -449,9 +450,11 @@ export function buildInsertStyleCardBlockNodeActive(colors) {
449
450
  });
450
451
  }
451
452
 
452
- // --- CSS custom properties ---
453
- // Applied inline on the decoration wrapper; cascade down to child/pseudo-element selectors in the
454
- // global stylesheet.
453
+ // ---------------------------------------------------------------------------
454
+ // CSS custom property variables (for nodes styled via global stylesheet)
455
+ // These are applied as inline styles on the decoration wrapper element and
456
+ // cascade down to child/pseudo-element selectors in the global stylesheet.
457
+ // ---------------------------------------------------------------------------
455
458
 
456
459
  /** CSS variables for an inserted node decoration marker — default state. */
457
460
  export function buildDecorationMarkerVariable(colors) {
@@ -486,7 +489,7 @@ export function buildDeletedDecorationMarkerVariable(colors) {
486
489
  });
487
490
  }
488
491
 
489
- /** Opacity only, no position or strikethrough. Used by the standard scheme. */
492
+ /** Opacity only, no position or strikethrough. Used by 'static' schemes. */
490
493
  export function buildDeletedDecorationMarkerVariableSimple(colors) {
491
494
  return convertToInlineCss({
492
495
  opacity: 0.8,
@@ -495,6 +498,10 @@ export function buildDeletedDecorationMarkerVariableSimple(colors) {
495
498
  });
496
499
  }
497
500
 
501
+ /**
502
+ * 'glyphTint' deleted inline style — tints the glyph itself via `color:`. Opacity ramps 0.6
503
+ * default, 0.83 "new", 1 active.
504
+ */
498
505
  /** Extended deleted inline style — background highlight + border-bottom underline (standard scheme). */
499
506
  export function buildDeletedInlineContentStyleExtended(colors) {
500
507
  return convertToInlineCss({
@@ -503,8 +510,6 @@ export function buildDeletedInlineContentStyleExtended(colors) {
503
510
  padding: `1px 0 2px`
504
511
  });
505
512
  }
506
-
507
- /** Standard deleted inline style — colours the glyph itself, not just the strikethrough. */
508
513
  export function buildDeletedInlineStyleStandard(colors, state) {
509
514
  if (state === 'active') {
510
515
  return convertToInlineCss({
@@ -543,7 +548,7 @@ export function buildDeletedDecorationMarkerVariableActive(colors) {
543
548
 
544
549
  // --- Table cell overlay styles ---
545
550
 
546
- /** Cell overlay for added table cells — default state. Stacking order varies by scheme. */
551
+ /** Cell overlay for added table cells — default state (zIndex 1). */
547
552
  export function buildAddedCellOverlayStyle(colors) {
548
553
  return convertToInlineCss({
549
554
  position: 'absolute',
@@ -558,7 +563,7 @@ export function buildAddedCellOverlayStyle(colors) {
558
563
  });
559
564
  }
560
565
 
561
- /** Added cell overlay — rounded variant. See `roundedAddedCellOverlayInheritsBorder`. */
566
+ /** Cell overlay for added table cells — rounded variant (zIndex 2, inherits border/radius). */
562
567
  export function buildAddedCellOverlayRoundedStyle(colors) {
563
568
  return convertToInlineCss({
564
569
  position: 'absolute',
@@ -622,4 +627,223 @@ export function buildDeletedCellOverlayRoundedStyle(colors) {
622
627
  border: 'inherit',
623
628
  borderRadius: 'inherit'
624
629
  });
630
+ }
631
+
632
+ // ---------------------------------------------------------------------------
633
+ // CSS custom property variables for deleted node global stylesheet
634
+ //
635
+ // These are set as inline styles on the deleted node wrapper element and cascade
636
+ // down to child/pseudo-element selectors in the global smartCardStyles stylesheet.
637
+ // The stylesheet reads var(--diff-delete-color) etc. — one set of selectors for
638
+ // all schemes, written once, never needs to change when new schemes are added.
639
+ // ---------------------------------------------------------------------------
640
+
641
+ // --- Inline content style dispatch ---
642
+
643
+ /**
644
+ * Inserted inline content under the extended diff experience. `insertedInlineTreatment` picks
645
+ * `text-decoration` vs a `border-bottom` rule; only the latter honours `hideAddedDiffsUnderline`.
646
+ */
647
+ export function buildInsertedInlineStyle(colors, isActive, hideAddedDiffsUnderline) {
648
+ if (colors.insertedInlineTreatment === 'underline') {
649
+ return isActive ? buildInsertStyleActive(colors) : buildInsertStyle(colors);
650
+ }
651
+ if (isActive) {
652
+ return hideAddedDiffsUnderline ? buildInsertStyleExtendedNoUnderlineActive(colors) : buildInsertStyleExtendedActive(colors);
653
+ }
654
+ return hideAddedDiffsUnderline ? buildInsertStyleExtendedNoUnderline(colors) : buildInsertStyleExtended(colors);
655
+ }
656
+
657
+ /** The three visual states deleted inline content can be in. */
658
+
659
+ /**
660
+ * Deleted inline content in a given state. 'strikethrough' renders 'default' and 'new'
661
+ * identically; the 'new' step exists only for the 'glyphTint' opacity ramp.
662
+ */
663
+ export function buildDeletedInlineContentStyle(colors, state) {
664
+ return colors.deletedInlineTreatment === 'strikethrough' ? buildDeletedInlineStyle(colors, state === 'active') : buildDeletedInlineStyleStandard(colors, state);
665
+ }
666
+
667
+ /**
668
+ * The positioned line across deleted content spanning an unbounded range. 'stateful' thickens
669
+ * 1px to 2px when active and tints with the border accent; 'static' uses the text accent always.
670
+ */
671
+ export function buildDeletedStrikethroughLine(colors, isActive) {
672
+ if (colors.deletedNodeEmphasis !== 'stateful') {
673
+ return buildDeletedInlineStyleUnbounded(colors);
674
+ }
675
+ return isActive ? buildDeletedContentStyleUnboundedActive(colors) : buildDeletedContentStyleUnbounded(colors);
676
+ }
677
+
678
+ // --- Deleted-content "REMOVED" lozenge ---
679
+
680
+ /** Structural CSS shared by both lozenge states — everything except the background tint. */
681
+ const deletedLozengeBase = {
682
+ display: 'inline-flex',
683
+ boxSizing: 'border-box',
684
+ position: 'static',
685
+ blockSize: 'min-content',
686
+ borderRadius: "var(--ds-radius-small, 4px)",
687
+ overflow: 'hidden',
688
+ paddingInlineStart: "var(--ds-space-050, 4px)",
689
+ paddingInlineEnd: "var(--ds-space-050, 4px)",
690
+ font: "var(--ds-font-body-small, normal 400 12px/16px \"Atlassian Sans\", ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu, \"Helvetica Neue\", sans-serif)",
691
+ fontWeight: "var(--ds-font-weight-bold, 653)",
692
+ textOverflow: 'ellipsis',
693
+ whiteSpace: 'nowrap',
694
+ color: "var(--ds-text-warning-inverse, #292A2E)"
695
+ };
696
+
697
+ /**
698
+ * The "REMOVED" lozenge on a deleted block node — resting state. Neutral gray in every scheme,
699
+ * so it takes no DiffColorScheme; only the active state is tinted.
700
+ */
701
+ export function buildDeletedLozengeStyle() {
702
+ return convertToInlineCss({
703
+ ...deletedLozengeBase,
704
+ backgroundColor: "var(--ds-background-accent-gray-subtler, #DDDEE1)"
705
+ });
706
+ }
707
+
708
+ /** The "REMOVED" lozenge — active state, tinted with the scheme's deleteActiveColor. */
709
+ export function buildDeletedLozengeActiveStyle(colors) {
710
+ return convertToInlineCss({
711
+ ...deletedLozengeBase,
712
+ backgroundColor: bgSubtlerPressed(colors.deleteActiveColor)
713
+ });
714
+ }
715
+
716
+ // ---------------------------------------------------------------------------
717
+ // Block node style dispatch
718
+ //
719
+ // A block node's decoration shape is a property of the *node type* — every scheme draws a
720
+ // blockquote with a left border and a horizontal rule as a filled bar. What varies per scheme
721
+ // is the emphasis and, for deleted content, which of the treatments below is used. Keeping that
722
+ // table here rather than in the decoration consumers means adding a scheme stays a change to
723
+ // `schemes.ts` alone.
724
+ // ---------------------------------------------------------------------------
725
+
726
+ /** The decoration shape an inserted block node takes. Determined by node type, not by scheme. */
727
+
728
+ /**
729
+ * Outline for an inserted block node. `insertedNodeEmphasis`: 'stateful' draws a 4px ring
730
+ * (`subtlest` at rest, `subtler.pressed` when focused), 'static' one 1px accent ring.
731
+ */
732
+ export function buildInsertedBlockNodeStyle(colors, shape, isActive) {
733
+ const isStateful = colors.insertedNodeEmphasis === 'stateful';
734
+ switch (shape) {
735
+ case 'quote':
736
+ if (!isStateful) {
737
+ return buildInsertStyleQuoteNode(colors);
738
+ }
739
+ return isActive ? buildInsertStyleQuoteNodeActive(colors) : buildInsertStyleQuoteNodeNew(colors);
740
+ case 'rule':
741
+ if (!isStateful) {
742
+ return buildInsertStyleRuleNode(colors);
743
+ }
744
+ return isActive ? buildInsertStyleRuleNodeActive(colors) : buildInsertStyleRuleNodeNew(colors);
745
+ case 'cardBlock':
746
+ if (!isStateful) {
747
+ return buildInsertStyleCardBlockNode(colors);
748
+ }
749
+ return isActive ? buildInsertStyleCardBlockNodeActive(colors) : buildInsertStyleCardBlockNodeNew(colors);
750
+ case 'marker':
751
+ if (!isStateful) {
752
+ return buildDecorationMarkerVariable(colors);
753
+ }
754
+ return isActive ? buildDecorationMarkerVariableActive(colors) : buildDecorationMarkerVariableNew(colors);
755
+ case 'node':
756
+ default:
757
+ if (!isStateful) {
758
+ return buildInsertStyleNode(colors);
759
+ }
760
+ return isActive ? buildInsertStyleNodeActive(colors) : buildInsertStyleNodeNew(colors);
761
+ }
762
+ }
763
+
764
+ /**
765
+ * The category a deleted block node falls into — by node type, not by scheme.
766
+ *
767
+ * 'container' — media, panel: content is a child element, so the node is only dimmed.
768
+ * 'listItem' — listItem: reads the marker variables via editor-core's list styles.
769
+ * 'marker' — extension, embedCard: same, via extension and smart-card styles.
770
+ * 'quote' — blockquote.
771
+ * 'generic' — rule, blockCard, everything else.
772
+ */
773
+
774
+ /**
775
+ * Outline for a deleted block node, driven by `deletedInlineTreatment` (strike vs tint) and
776
+ * `deletedNodeEmphasis` (whether the outline tracks scroll state and emits marker variables).
777
+ */
778
+ export function buildDeletedBlockNodeStyle(colors, category, isActive) {
779
+ const isStrikethrough = colors.deletedInlineTreatment === 'strikethrough';
780
+ const statefulMarker = () => isActive ? buildDeletedDecorationMarkerVariableActive(colors) : buildDeletedDecorationMarkerVariableNew(colors);
781
+ switch (category) {
782
+ case 'quote':
783
+ // Both emphases share one builder here — `deletedQuoteNodeShape` already carries the
784
+ // only variance (a ring versus a left border).
785
+ return buildDeletedStyleQuoteNode(colors);
786
+ case 'container':
787
+ return isStrikethrough ? buildDeletedInlineStyle(colors, false) : buildDeletedDecorationMarkerVariableSimple(colors);
788
+ case 'listItem':
789
+ return colors.deletedNodeEmphasis === 'stateful' ? statefulMarker() : buildDeletedDecorationMarkerVariableSimple(colors);
790
+ case 'marker':
791
+ return colors.deletedNodeEmphasis === 'stateful' ? statefulMarker() : buildDeletedInlineStyleStandard(colors, 'new');
792
+ case 'generic':
793
+ default:
794
+ return isStrikethrough ? buildDeletedInlineStyle(colors, false) : buildDeletedInlineStyleStandard(colors, 'new');
795
+ }
796
+ }
797
+
798
+ /**
799
+ * Deleted blockquote inside a lozenge wrapper (the nodeview path). Always a ring, since the
800
+ * lozenge needs an enclosed shape, so `deletedQuoteNodeShape` does not apply — only
801
+ * `deletedQuoteNodeActiveTone`, which picks the active ring's tone.
802
+ */
803
+ export function buildDeletedQuoteNodeWithLozengeStyle(colors, isActive) {
804
+ if (!isActive) {
805
+ return buildDeletedStyleQuoteNodeWithLozenge(colors);
806
+ }
807
+ return colors.deletedQuoteNodeActiveTone === 'backgroundPressed' ? buildDeletedStyleQuoteNodeActive(colors) : buildDeletedStyleQuoteNodeWithLozengeActive(colors);
808
+ }
809
+
810
+ /**
811
+ * Outline for a deleted block node via the nodeview wrapper (expand, decisionList, panel,
812
+ * codeBlock). Every scheme shares the active state; `deletedNodeEmphasis` changes only the
813
+ * resting one — 'stateful' a 4px subtlest ring, 'static' a 1px accent ring.
814
+ */
815
+ export function buildDeletedWrappedBlockOutline(colors, {
816
+ isActive,
817
+ isRounded
818
+ }) {
819
+ if (isActive) {
820
+ return isRounded ? buildDeletedBlockOutlineRoundedActive(colors) : buildDeletedBlockOutlineActive(colors);
821
+ }
822
+ if (colors.deletedNodeEmphasis === 'stateful') {
823
+ return isRounded ? buildDeletedBlockOutlineRoundedNew(colors) : buildDeletedBlockOutlineNew(colors);
824
+ }
825
+ return isRounded ? buildDeletedBlockOutlineRounded(colors) : buildDeletedBlockOutline(colors);
826
+ }
827
+
828
+ /**
829
+ * Accent colour for atomic inline changed nodes (date, emoji, mention, status). Set inline on the
830
+ * decoration span and read by the `.show-diff-atomic-inline-changed-*` selectors in
831
+ * EditorContentContainer, on the decorated element or a descendant, so it must inherit. Being
832
+ * inline it beats the stylesheet's fallback, making the plugin the only source of the colour.
833
+ */
834
+ export function buildAtomicInlineChangedCSSVariables(colors) {
835
+ return convertToInlineCss({
836
+ '--show-diff-atomic-inline-changed-border-color': borderAccent(colors.insertColor)
837
+ });
838
+ }
839
+
840
+ /** Deleted node wrapper variables, all three states. Read by the smartCardStyles selectors. */
841
+ export function buildDeletedNodeCSSVariables(colors) {
842
+ return convertToInlineCss({
843
+ '--diff-delete-color': borderAccent(colors.deleteColor),
844
+ '--diff-delete-color-default': borderAccent(colors.deleteActiveColor),
845
+ '--diff-delete-color-new': bgSubtlest(colors.deleteColor),
846
+ '--diff-delete-color-active': bgSubtlerPressed(colors.deleteActiveColor),
847
+ '--diff-delete-text-decoration-color': borderAccent(colors.deleteColor)
848
+ });
625
849
  }
@@ -6,13 +6,18 @@ export const traditionalScheme = {
6
6
  deleteColor: 'red',
7
7
  deleteActiveColor: 'red',
8
8
  deletedCellColor: 'gray',
9
+ deletedRowTreatment: 'strikeColor',
9
10
  insertedCellOpacity: 0.5,
10
11
  deletedQuoteNodeShape: 'ring',
11
12
  deletedCellBorderProminence: 'subtle',
12
- deletedRowTreatment: 'strikeColor',
13
13
  deletedBlockOutlineActiveEmphasis: 'background',
14
14
  addedCellOverlayZIndex: 1,
15
- roundedAddedCellOverlayInheritsBorder: true
15
+ roundedAddedCellOverlayInheritsBorder: true,
16
+ insertedInlineTreatment: 'underline',
17
+ deletedInlineTreatment: 'strikethrough',
18
+ insertedNodeEmphasis: 'stateful',
19
+ deletedNodeEmphasis: 'stateful',
20
+ deletedQuoteNodeActiveTone: 'backgroundPressed'
16
21
  };
17
22
 
18
23
  /** Purple insertions, gray deletions (red on active). */
@@ -23,11 +28,22 @@ export const standardScheme = {
23
28
  deleteColor: 'gray',
24
29
  deleteActiveColor: 'red',
25
30
  deletedCellColor: 'gray',
31
+ deletedRowTreatment: 'textTint',
26
32
  insertedCellOpacity: 0.2,
27
33
  deletedQuoteNodeShape: 'borderLeft',
28
34
  deletedCellBorderProminence: 'accent',
29
- deletedRowTreatment: 'textTint',
30
35
  deletedBlockOutlineActiveEmphasis: 'border',
31
36
  addedCellOverlayZIndex: 2,
32
- roundedAddedCellOverlayInheritsBorder: false
37
+ roundedAddedCellOverlayInheritsBorder: false,
38
+ insertedInlineTreatment: 'borderBottom',
39
+ deletedInlineTreatment: 'glyphTint',
40
+ insertedNodeEmphasis: 'static',
41
+ deletedNodeEmphasis: 'static',
42
+ deletedQuoteNodeActiveTone: 'borderAccent'
43
+ };
44
+
45
+ /** Maps the public ColorScheme string to its data object. Adding a scheme = one entry here. */
46
+ export const colorSchemeRegistry = {
47
+ traditional: traditionalScheme,
48
+ standard: standardScheme
33
49
  };
@@ -1,14 +1,64 @@
1
1
  import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
2
2
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
3
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
3
4
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
4
5
  import { isExtendedEnabled } from '../isExtendedEnabled';
5
- import { standardDecorationMarkerVariable, deletedDecorationMarkerVariable, editingStyleQuoteNode, editingStyleRuleNode, editingStyleCardBlockNode, editingStyleNode, deletedContentStyleNew, deletedStyleQuoteNode, addedCellOverlayRoundedStyle, addedCellOverlayStyle, deletedCellOverlayStyle, deletedCellOverlayRoundedStyle } from './colorSchemes/standard';
6
- import { traditionalDecorationMarkerVariableActive, traditionalDecorationMarkerVariableNew, traditionalDeletedDecorationMarkerVariableActive, traditionalDeletedDecorationMarkerVariableNew, traditionalStyleQuoteNodeActive, traditionalStyleQuoteNodeNew, traditionalStyleRuleNodeActive, traditionalStyleRuleNodeNew, traditionalStyleCardBlockNodeActive, traditionalStyleCardBlockNodeNew, traditionalStyleNodeActive, traditionalStyleNodeNew, getDeletedTraditionalInlineStyle, deletedTraditionalStyleQuoteNode, traditionalAddedCellOverlayRoundedStyle, traditionalAddedCellOverlayStyle, deletedTraditionalCellOverlayStyle, deletedTraditionalCellOverlayRoundedStyle } from './colorSchemes/traditional';
6
+ import { buildAddedCellOverlayRoundedStyle, buildAddedCellOverlayStyle, buildDeletedBlockNodeStyle, buildDeletedCellOverlayRoundedStyle, buildDeletedCellOverlayStyle, buildInsertedBlockNodeStyle } from './colorSchemes/factory';
7
+ import { colorSchemeRegistry } from './colorSchemes/schemes';
7
8
  import { createBlockIndicatorAnchorWidgets } from './createAnchorDecorationWidgets';
8
9
  import { buildDiffDecorationSpec } from './decorationKeys';
10
+ import { getBlockNodeStyleLegacy, resolveCellOverlayStyleLegacy } from './createBlockChangedDecoration.styles.legacy';
9
11
  const displayNoneStyle = convertToInlineCss({
10
12
  display: 'none'
11
13
  });
14
+ const DEFAULT_COLOR_SCHEME = 'standard';
15
+
16
+ /** Nodes that carry no decoration styling of their own — layout, lists, text blocks, media groups. */
17
+ const UNSTYLED_NODES = ['mediaSingle', 'mediaGroup', 'table',
18
+ // Handle table separately to avoid border issues
19
+ 'tableRow', 'paragraph',
20
+ // Paragraph and heading nodes do not need special styling
21
+ 'heading', 'hardBreak', 'decisionList', 'taskList', 'bulletList', 'orderedList', 'layoutSection'];
22
+ const CELL_NODES = ['tableCell', 'tableHeader'];
23
+
24
+ /** Positioning context for the cell overlay widget decorations. */
25
+ const cellPositionStyle = convertToInlineCss({
26
+ position: 'relative'
27
+ });
28
+ const getInsertedBlockNodeShape = nodeName => {
29
+ switch (nodeName) {
30
+ case 'blockquote':
31
+ return 'quote';
32
+ case 'rule':
33
+ return 'rule';
34
+ case 'blockCard':
35
+ return 'cardBlock';
36
+ case 'extension':
37
+ case 'embedCard':
38
+ case 'listItem':
39
+ return 'marker';
40
+ default:
41
+ return 'node';
42
+ }
43
+ };
44
+ const getDeletedBlockNodeCategory = nodeName => {
45
+ switch (nodeName) {
46
+ case 'blockquote':
47
+ return 'quote';
48
+ // Media nodes inside mediaSingle should not get position:relative
49
+ // as it shifts the image outside its parent container (e.g. panel)
50
+ case 'media':
51
+ case 'panel':
52
+ return 'container';
53
+ case 'listItem':
54
+ return 'listItem';
55
+ case 'extension':
56
+ case 'embedCard':
57
+ return 'marker';
58
+ default:
59
+ return 'generic';
60
+ }
61
+ };
12
62
  const getNodeClass = name => {
13
63
  switch (name) {
14
64
  case 'extension':
@@ -17,99 +67,36 @@ const getNodeClass = name => {
17
67
  return undefined;
18
68
  }
19
69
  };
20
- const getBlockNodeStyle = ({
70
+ const getBlockNodeStyleNext = ({
21
71
  nodeName,
22
72
  colorScheme,
23
73
  isInserted = true,
24
74
  isActive = false,
25
75
  diffType
26
76
  }) => {
27
- const isTraditional = colorScheme === 'traditional';
28
- if (['mediaSingle', 'mediaGroup', 'table',
29
- // Handle table separately to avoid border issues
30
- 'tableRow', 'paragraph',
31
- // Paragraph and heading nodes do not need special styling
32
- 'heading', 'hardBreak', 'decisionList', 'taskList', 'bulletList', 'orderedList', 'layoutSection'].includes(nodeName)) {
33
- // Layout nodes do not need special styling
77
+ if (UNSTYLED_NODES.includes(nodeName)) {
34
78
  return undefined;
35
79
  }
36
- // Media nodes inside mediaSingle should not get position:relative
37
- // as it shifts the image outside its parent container (e.g. panel)
38
- if (nodeName === 'media') {
39
- if (!isInserted && isExtendedEnabled(diffType)) {
40
- return isTraditional ? getDeletedTraditionalInlineStyle(false) : deletedDecorationMarkerVariable;
41
- }
42
- return isTraditional ? isActive ? traditionalStyleNodeActive : traditionalStyleNodeNew : editingStyleNode;
43
- }
44
- if (['tableCell', 'tableHeader'].includes(nodeName)) {
45
- if (isExtendedEnabled(diffType)) {
46
- // This is used for positioning the cell overlay widget decorations
47
- return convertToInlineCss({
48
- position: 'relative'
49
- });
50
- }
51
- // When gate is off, it should return undefined as above
52
- return undefined;
53
- }
54
- if (nodeName === 'panel') {
55
- if (!isInserted && isExtendedEnabled(diffType)) {
56
- return isTraditional ? getDeletedTraditionalInlineStyle(false) : deletedDecorationMarkerVariable;
57
- }
58
- return isTraditional ? isActive ? traditionalStyleNodeActive : traditionalStyleNodeNew : editingStyleNode;
59
- }
60
- if (['extension', 'embedCard', 'listItem'].includes(nodeName)) {
61
- if (isExtendedEnabled(diffType)) {
62
- if (isInserted) {
63
- return isTraditional && isActive ? traditionalDecorationMarkerVariableActive : isTraditional ? traditionalDecorationMarkerVariableNew : standardDecorationMarkerVariable;
64
- } else {
65
- if (nodeName === 'listItem') {
66
- return isTraditional && isActive ? traditionalDeletedDecorationMarkerVariableActive : isTraditional ? traditionalDeletedDecorationMarkerVariableNew : deletedDecorationMarkerVariable;
67
- }
68
- return isTraditional && isActive ? traditionalDeletedDecorationMarkerVariableActive : isTraditional ? traditionalDeletedDecorationMarkerVariableNew : deletedContentStyleNew;
69
- }
70
- }
71
- return isTraditional && isActive ? traditionalDecorationMarkerVariableActive : isTraditional ? traditionalDecorationMarkerVariableNew : standardDecorationMarkerVariable;
72
- }
73
- if (nodeName === 'blockquote') {
74
- if (isExtendedEnabled(diffType)) {
75
- if (isInserted) {
76
- return isTraditional ? isActive ? traditionalStyleQuoteNodeActive : traditionalStyleQuoteNodeNew : editingStyleQuoteNode;
77
- } else {
78
- return isTraditional ? deletedTraditionalStyleQuoteNode : deletedStyleQuoteNode;
79
- }
80
- }
81
- return isTraditional ? isActive ? traditionalStyleQuoteNodeActive : traditionalStyleQuoteNodeNew : editingStyleQuoteNode;
82
- }
83
- if (nodeName === 'rule') {
84
- if (isExtendedEnabled(diffType)) {
85
- if (isInserted) {
86
- return isTraditional ? isActive ? traditionalStyleRuleNodeActive : traditionalStyleRuleNodeNew : editingStyleRuleNode;
87
- } else {
88
- return isTraditional ? getDeletedTraditionalInlineStyle(false) : deletedContentStyleNew;
89
- }
90
- }
91
- return isTraditional ? isActive ? traditionalStyleRuleNodeActive : traditionalStyleRuleNodeNew : editingStyleRuleNode;
92
- }
93
- if (nodeName === 'blockCard') {
94
- if (isExtendedEnabled(diffType)) {
95
- if (isInserted) {
96
- return isTraditional ? isActive ? traditionalStyleCardBlockNodeActive : traditionalStyleCardBlockNodeNew : editingStyleCardBlockNode;
97
- } else {
98
- return isTraditional ? getDeletedTraditionalInlineStyle(false) : deletedContentStyleNew;
99
- }
100
- }
101
- return isTraditional ? isActive ? traditionalStyleCardBlockNodeActive : traditionalStyleCardBlockNodeNew : editingStyleCardBlockNode;
80
+ if (CELL_NODES.includes(nodeName)) {
81
+ // When the gate is off, cells get no styling — as with UNSTYLED_NODES above.
82
+ return isExtendedEnabled(diffType) ? cellPositionStyle : undefined;
102
83
  }
103
- if (isExtendedEnabled(diffType)) {
104
- if (isInserted) {
105
- return isTraditional ? isActive ? traditionalStyleNodeActive : traditionalStyleNodeNew : editingStyleNode;
106
- } else {
107
- return isTraditional ? getDeletedTraditionalInlineStyle(false) : deletedContentStyleNew;
108
- }
84
+ const colors = colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : DEFAULT_COLOR_SCHEME];
85
+
86
+ // Deleted nodes only differ under the extended experience; otherwise all are insertions.
87
+ if (!isInserted && isExtendedEnabled(diffType)) {
88
+ return buildDeletedBlockNodeStyle(colors, getDeletedBlockNodeCategory(nodeName), isActive);
109
89
  }
110
- return isTraditional ? isActive ? traditionalStyleNodeActive : traditionalStyleNodeNew : editingStyleNode;
90
+ return buildInsertedBlockNodeStyle(colors, getInsertedBlockNodeShape(nodeName), isActive);
111
91
  };
112
92
 
93
+ /**
94
+ * Dispatches to the registry-driven implementation, or to the verbatim pre-refactor one for the
95
+ * OFF cohort of `platform_editor_show_diff_color_scheme_refactor`. Both are built to emit the
96
+ * same style strings for both shipped schemes; see EDITOR-8281.
97
+ */
98
+ const getBlockNodeStyle = props => isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? getBlockNodeStyleNext(props) : getBlockNodeStyleLegacy(props);
99
+
113
100
  /**
114
101
  * A table cell is "empty" only when it has no content at all — no text AND no
115
102
  * non-text leaf/inline nodes (media, emoji, mention, inlineCard, status, date…).
@@ -167,20 +154,21 @@ export const createBlockChangedDecoration = ({
167
154
  diffType
168
155
  }))];
169
156
  }
170
- let style;
171
- if (isExtendedEnabled(diffType) && ['tableCell', 'tableHeader'].includes(change.name)) {
157
+ if (isExtendedEnabled(diffType) && CELL_NODES.includes(change.name)) {
172
158
  const cellOverlay = document.createElement('div');
173
- const isTraditional = colorScheme === 'traditional';
159
+ const colors = colorSchemeRegistry[colorScheme !== null && colorScheme !== void 0 ? colorScheme : DEFAULT_COLOR_SCHEME];
174
160
  const isRoundedTable = expValEquals('platform_editor_table_diff_rounded_corners', 'isEnabled', true);
175
- const addedCellStyle = isTraditional ? isRoundedTable ? traditionalAddedCellOverlayRoundedStyle : traditionalAddedCellOverlayStyle : isRoundedTable ? addedCellOverlayRoundedStyle : addedCellOverlayStyle;
176
- const deletedCellStyle = isTraditional ? isRoundedTable ? deletedTraditionalCellOverlayRoundedStyle : deletedTraditionalCellOverlayStyle : isRoundedTable ? deletedCellOverlayRoundedStyle : deletedCellOverlayStyle;
177
161
 
178
162
  // On an inverted diff, an empty cell being filled is an addition, so give it the
179
163
  // added (purple) overlay instead of the deleted (grey) one (EDITOR-8442).
180
164
  const cellNode = doc === null || doc === void 0 ? void 0 : doc.nodeAt(change.from);
181
165
  const isEmptyCellBeingFilled = !isInserted && !!cellNode && isCellEmpty(cellNode);
182
166
  const useAddedStyle = isInserted || isEmptyCellBeingFilled;
183
- const cellOverlayStyle = useAddedStyle ? addedCellStyle : deletedCellStyle;
167
+ const cellOverlayStyle = isExperimentEnabled('platform_editor_show_diff_color_scheme_refactor') ? useAddedStyle ? isRoundedTable ? buildAddedCellOverlayRoundedStyle(colors) : buildAddedCellOverlayStyle(colors) : isRoundedTable ? buildDeletedCellOverlayRoundedStyle(colors) : buildDeletedCellOverlayStyle(colors) : resolveCellOverlayStyleLegacy({
168
+ colorScheme,
169
+ isRoundedTable,
170
+ useAddedStyle
171
+ });
184
172
  cellOverlay.setAttribute('style', cellOverlayStyle);
185
173
  decorations.push(
186
174
  // change.to - 1 to position the overlay inside the end of the cell
@@ -190,22 +178,14 @@ export const createBlockChangedDecoration = ({
190
178
  key: 'cell-overlay-decoration'
191
179
  }));
192
180
  }
193
- if (isExtendedEnabled(diffType)) {
194
- style = getBlockNodeStyle({
195
- nodeName: change.name,
196
- colorScheme,
197
- isInserted,
198
- isActive,
199
- diffType
200
- });
201
- } else {
202
- style = getBlockNodeStyle({
203
- nodeName: change.name,
204
- colorScheme,
205
- isActive,
206
- diffType
207
- });
208
- }
181
+ // isInserted is only read under the extended experience, so pass it unconditionally.
182
+ const style = getBlockNodeStyle({
183
+ nodeName: change.name,
184
+ colorScheme,
185
+ isInserted,
186
+ isActive,
187
+ diffType
188
+ });
209
189
  const className = getNodeClass(change.name);
210
190
  if (style || className) {
211
191
  decorations.push(Decoration.node(change.from, change.to, {