@atlaskit/editor-plugin-code-block-advanced 10.1.0 → 10.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @atlaskit/editor-plugin-code-block-advanced
2
2
 
3
+ ## 10.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`7e8145e6a7ce6`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/7e8145e6a7ce6) -
8
+ Add ADF-backed code block line number visibility
9
+ - Updated dependencies
10
+
3
11
  ## 10.1.0
4
12
 
5
13
  ### Minor Changes
@@ -46,14 +46,15 @@ var codeBlockHeights = new WeakMap();
46
46
  // Based on: https://prosemirror.net/examples/codemirror/
47
47
  var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
48
48
  function CodeBlockAdvancedNodeView(node, view, getPos, innerDecorations, config) {
49
- var _config$api,
49
+ var _this = this,
50
+ _config$api,
50
51
  _contentFormatSharedS,
51
52
  _config$api2,
52
- _this = this,
53
53
  _config$api3,
54
54
  _config$api4;
55
55
  (0, _classCallCheck2.default)(this, CodeBlockAdvancedNodeView);
56
56
  (0, _defineProperty2.default)(this, "lineWrappingCompartment", new _state.Compartment());
57
+ (0, _defineProperty2.default)(this, "lineNumbersCompartment", new _state.Compartment());
57
58
  (0, _defineProperty2.default)(this, "languageCompartment", new _state.Compartment());
58
59
  (0, _defineProperty2.default)(this, "readOnlyCompartment", new _state.Compartment());
59
60
  (0, _defineProperty2.default)(this, "pmDecorationsCompartment", new _state.Compartment());
@@ -61,6 +62,11 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
61
62
  (0, _defineProperty2.default)(this, "maybeTryingToReachNodeSelection", false);
62
63
  (0, _defineProperty2.default)(this, "pmFacet", _state.Facet.define());
63
64
  (0, _defineProperty2.default)(this, "wordWrappingEnabled", false);
65
+ (0, _defineProperty2.default)(this, "lineNumbersHidden", false);
66
+ (0, _defineProperty2.default)(this, "selectCodeBlockNodeAndFocus", function () {
67
+ _this.selectCodeBlockNode(undefined);
68
+ _this.view.focus();
69
+ });
64
70
  this.config = config;
65
71
  this.node = node;
66
72
  this.view = view;
@@ -87,10 +93,6 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
87
93
  var _config$getIntl = config.getIntl(),
88
94
  formatMessage = _config$getIntl.formatMessage;
89
95
  var formattedAriaLabel = formatMessage(_messages.blockTypeMessages.codeblock);
90
- var selectNode = function selectNode() {
91
- _this.selectCodeBlockNode(undefined);
92
- _this.view.focus();
93
- };
94
96
  var isMacOS = (0, _browser.getBrowserInfo)().mac;
95
97
  this.cm = new _view.EditorView({
96
98
  doc: this.node.textContent,
@@ -107,16 +109,9 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
107
109
  // Goes before cmTheme to override styles
108
110
  config.allowCodeFolding ? [_theme.codeFoldingTheme] : [], this.themeCompartment.of((0, _theme.cmTheme)({
109
111
  contentMode: (0, _expValEquals.expValEquals)('confluence_compact_text_format', 'isEnabled', true) ? this.contentMode : undefined
110
- })), (0, _language.syntaxHighlighting)(_syntaxHighlightingTheme.highlightStyle), (0, _language.bracketMatching)(), (0, _view.lineNumbers)({
111
- domEventHandlers: {
112
- click: function click() {
113
- selectNode();
114
- return true;
115
- }
116
- }
117
- }),
118
- // Explicitly disable "sticky" positioning on line numbers to match
119
- // Renderer behaviour
112
+ })), (0, _language.syntaxHighlighting)(_syntaxHighlightingTheme.highlightStyle), (0, _language.bracketMatching)(), (0, _expValEquals.expValEquals)('platform_editor_code_block_q4_lovability', 'isEnabled', true) ? this.lineNumbersCompartment.of(this.getLineNumberVisibilityExtensions(node)) : this.getLineNumberExtensions(),
113
+ // Explicitly disable "sticky" positioning on all gutters to match
114
+ // Renderer behaviour.
120
115
  (0, _view.gutters)({
121
116
  fixed: false
122
117
  }), _view.EditorView.updateListener.of(function (update) {
@@ -139,7 +134,7 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
139
134
  'aria-label': formattedAriaLabel,
140
135
  'aria-describedby': "codesnippet-".concat(this.node.attrs.localId)
141
136
  })), config.allowCodeFolding ? [(0, _foldGutter.foldGutterExtension)({
142
- selectNode: selectNode,
137
+ selectNode: this.selectCodeBlockNodeAndFocus,
143
138
  getNode: function getNode() {
144
139
  return _this.node;
145
140
  }
@@ -221,6 +216,7 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
221
216
  this.updateLanguage();
222
217
  this.updateLocalIdAttribute();
223
218
  this.wordWrappingEnabled = (0, _codeBlock.isCodeBlockWordWrapEnabled)(node);
219
+ this.lineNumbersHidden = (0, _codeBlock.areCodeBlockLineNumbersHidden)(node);
224
220
 
225
221
  // Restore fold state after initialization
226
222
  if (config.allowCodeFolding) {
@@ -335,6 +331,37 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
335
331
  this.view.dispatch(tr);
336
332
  }
337
333
  }
334
+ }, {
335
+ key: "getLineNumberExtensions",
336
+ value: function getLineNumberExtensions() {
337
+ var _this2 = this;
338
+ return [(0, _view.lineNumbers)({
339
+ domEventHandlers: {
340
+ click: function click() {
341
+ _this2.selectCodeBlockNodeAndFocus();
342
+ return true;
343
+ }
344
+ }
345
+ })];
346
+ }
347
+ }, {
348
+ key: "getLineNumberVisibilityExtensions",
349
+ value: function getLineNumberVisibilityExtensions(node) {
350
+ if ((0, _codeBlock.areCodeBlockLineNumbersHidden)(node)) {
351
+ return [];
352
+ }
353
+ return this.getLineNumberExtensions();
354
+ }
355
+ }, {
356
+ key: "getLineNumbersEffects",
357
+ value: function getLineNumbersEffects(node) {
358
+ var lineNumbersHidden = (0, _codeBlock.areCodeBlockLineNumbersHidden)(node);
359
+ if (this.lineNumbersHidden !== lineNumbersHidden) {
360
+ this.lineNumbersHidden = lineNumbersHidden;
361
+ return this.lineNumbersCompartment.reconfigure(this.getLineNumberVisibilityExtensions(node));
362
+ }
363
+ return undefined;
364
+ }
338
365
  }, {
339
366
  key: "getWordWrapEffects",
340
367
  value: function getWordWrapEffects(node) {
@@ -393,11 +420,12 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
393
420
  // Updates bundled for performance (to avoid multiple-dispatches)
394
421
  var changes = (0, _updateCMSelection.getCMSelectionChanges)(curText, newText);
395
422
  var wordWrapEffect = this.getWordWrapEffects(node);
423
+ var lineNumbersEffect = (0, _expValEquals.expValEquals)('platform_editor_code_block_q4_lovability', 'isEnabled', true) ? this.getLineNumbersEffects(node) : undefined;
396
424
  var prosemirrorDecorationsEffect = this.getProseMirrorDecorationEffects(innerDecorations);
397
- if (changes || wordWrapEffect || prosemirrorDecorationsEffect) {
425
+ if (changes || wordWrapEffect || lineNumbersEffect || prosemirrorDecorationsEffect) {
398
426
  this.updating = true;
399
427
  this.cm.dispatch({
400
- effects: [wordWrapEffect, prosemirrorDecorationsEffect].filter(function (effect) {
428
+ effects: [wordWrapEffect, lineNumbersEffect, prosemirrorDecorationsEffect].filter(function (effect) {
401
429
  return !!effect;
402
430
  }),
403
431
  changes: changes
@@ -5,8 +5,10 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.codeBlockNodeWithFixedToDOM = void 0;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
8
9
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
10
  var _adfSchema = require("@atlaskit/adf-schema");
11
+ var _codeBlock = require("@atlaskit/editor-common/code-block");
10
12
  var _lazyNodeView = require("@atlaskit/editor-common/lazy-node-view");
11
13
  var _styles = require("@atlaskit/editor-common/styles");
12
14
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
@@ -24,6 +26,57 @@ var MATCH_NEWLINES = new RegExp('\n', 'gu');
24
26
  var getFontSize = function getFontSize() {
25
27
  return (0, _expValEquals.expValEquals)('confluence_compact_text_format', 'isEnabled', true) || (0, _expValEquals.expValEquals)('cc_editor_ai_content_mode', 'variant', 'test') && (0, _platformFeatureFlags.fg)('platform_editor_content_mode_button_mvp') ? '0.875em' : '0.875rem';
26
28
  };
29
+ var getGutterBaseStyle = function getGutterBaseStyle() {
30
+ return {
31
+ backgroundColor: "var(--ds-background-neutral, #0515240F)",
32
+ position: 'relative',
33
+ flexShrink: 0,
34
+ // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
35
+ fontSize: getFontSize(),
36
+ boxSizing: 'content-box'
37
+ };
38
+ };
39
+ var getGutterPadding = function getGutterPadding(allowCodeFolding) {
40
+ return allowCodeFolding ? "var(--ds-space-100, 8px)".concat(" ", "var(--ds-space-250, 20px)", " ", "var(--ds-space-100, 8px)", " ", "var(--ds-space-075, 6px)") : "var(--ds-space-100, 8px)";
41
+ };
42
+ var getGuttersWithLineNumbers = function getGuttersWithLineNumbers(content, config) {
43
+ return ['div', {
44
+ // Based on packages/editor/editor-common/src/styles/shared/code-block.ts
45
+ // But we can't reuse that class as it adds a ::before that intefers with this approach
46
+ style: (0, _lazyNodeView.convertToInlineCss)(_objectSpread(_objectSpread({}, getGutterBaseStyle()), {}, {
47
+ width: 'var(--lineNumberGutterWidth, 2rem)',
48
+ /* top and bottom | left and right */
49
+ padding: getGutterPadding(config.allowCodeFolding)
50
+ })),
51
+ contenteditable: 'false'
52
+ }, ['div', {
53
+ class: 'code-block-gutter-pseudo-element',
54
+ style: (0, _lazyNodeView.convertToInlineCss)({
55
+ textAlign: 'right',
56
+ color: "var(--ds-text-subtlest, #6B6E76)",
57
+ fontFamily: "var(--ds-font-family-code, \"Atlassian Mono\", ui-monospace, Menlo, \"Segoe UI Mono\", \"Ubuntu Mono\", monospace)",
58
+ whiteSpace: 'pre-wrap'
59
+ }),
60
+ 'data-label': content
61
+ }]];
62
+ };
63
+ var getFoldOnlyGutter = function getFoldOnlyGutter() {
64
+ return ['div', {
65
+ style: (0, _lazyNodeView.convertToInlineCss)(_objectSpread(_objectSpread({}, getGutterBaseStyle()), {}, {
66
+ padding: "var(--ds-space-100, 8px)".concat(" ", "var(--ds-space-150, 12px)", " ", "var(--ds-space-100, 8px)", " ", "var(--ds-space-100, 8px)")
67
+ })),
68
+ contenteditable: 'false'
69
+ }];
70
+ };
71
+ var getGutters = function getGutters(content, config, hideLineNumbers) {
72
+ if (!hideLineNumbers) {
73
+ return [getGuttersWithLineNumbers(content, config)];
74
+ }
75
+ if (config.allowCodeFolding) {
76
+ return [getFoldOnlyGutter()];
77
+ }
78
+ return [];
79
+ };
27
80
 
28
81
  // Based on: `packages/editor/editor-plugin-code-block/src/nodeviews/code-block.ts`
29
82
  var _toDOM = function toDOM(node, formattedAriaLabel, config) {
@@ -34,45 +87,26 @@ var _toDOM = function toDOM(node, formattedAriaLabel, config) {
34
87
  totalLineCount += (node.text.match(MATCH_NEWLINES) || []).length;
35
88
  }
36
89
  });
90
+ var hideLineNumbers = (0, _codeBlock.areCodeBlockLineNumbersHidden)(node);
37
91
  var maxDigits = totalLineCount.toString().length;
38
92
  var content = node.textContent.split('\n').map(function (_, i) {
39
93
  return i + 1;
40
94
  }).join('\n');
95
+ var gutters = getGutters(content, config, hideLineNumbers);
41
96
  return ['pre', _objectSpread({
42
97
  class: codeBlockClassNames.container,
43
98
  style: "--lineNumberGutterWidth:".concat(maxDigits, "ch;"),
44
99
  'data-language': node.attrs.language || ''
45
- }, (0, _expValEquals.expValEquals)('platform_editor_code_block_q4_lovability', 'isEnabled', true) && {
100
+ }, (0, _expValEquals.expValEquals)('platform_editor_code_block_q4_lovability', 'isEnabled', true) && _objectSpread({
46
101
  'data-wrap': node.attrs.wrap ? 'true' : 'false'
47
- }), ['div', {
102
+ }, hideLineNumbers && {
103
+ 'data-hide-line-numbers': 'true'
104
+ })), ['div', {
48
105
  class: codeBlockClassNames.start,
49
106
  contenteditable: 'false'
50
107
  }], ['div', {
51
108
  class: codeBlockClassNames.contentWrapper
52
- }, ['div', {
53
- // Based on packages/editor/editor-common/src/styles/shared/code-block.ts
54
- // But we can't reuse that class as it adds a ::before that intefers with this approach
55
- style: (0, _lazyNodeView.convertToInlineCss)({
56
- backgroundColor: "var(--ds-background-neutral, #0515240F)",
57
- position: 'relative',
58
- width: 'var(--lineNumberGutterWidth, 2rem)',
59
- /* top and bottom | left and right */
60
- padding: config.allowCodeFolding ? "var(--ds-space-100, 8px)".concat(" ", "var(--ds-space-250, 20px)", " ", "var(--ds-space-100, 8px)", " ", "var(--ds-space-075, 6px)") : "var(--ds-space-100, 8px)",
61
- flexShrink: 0,
62
- fontSize: getFontSize(),
63
- boxSizing: 'content-box'
64
- }),
65
- contenteditable: 'false'
66
- }, ['div', {
67
- class: 'code-block-gutter-pseudo-element',
68
- style: (0, _lazyNodeView.convertToInlineCss)({
69
- textAlign: 'right',
70
- color: "var(--ds-text-subtlest, #6B6E76)",
71
- fontFamily: "var(--ds-font-family-code, \"Atlassian Mono\", ui-monospace, Menlo, \"Segoe UI Mono\", \"Ubuntu Mono\", monospace)",
72
- whiteSpace: 'pre-wrap'
73
- }),
74
- 'data-label': content
75
- }]], ['div', {
109
+ }].concat((0, _toConsumableArray2.default)(gutters), [['div', {
76
110
  class: codeBlockClassNames.content
77
111
  }, ['code', _objectSpread({
78
112
  'data-language': node.attrs.language || '',
@@ -81,7 +115,7 @@ var _toDOM = function toDOM(node, formattedAriaLabel, config) {
81
115
  'aria-label': formattedAriaLabel
82
116
  }, (0, _platformFeatureFlags.fg)('platform_editor_adf_with_localid') && {
83
117
  'data-local-id': node.attrs.localId
84
- }), 0]]], ['div', {
118
+ }), 0]]]), ['div', {
85
119
  class: codeBlockClassNames.end,
86
120
  contenteditable: 'false'
87
121
  }]];
@@ -1,12 +1,16 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
7
  exports.codeFoldingTheme = exports.cmTheme = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
7
9
  var _view = require("@codemirror/view");
8
10
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
9
11
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
12
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
13
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
10
14
  var shouldUseCompactTypography = function shouldUseCompactTypography(contentMode) {
11
15
  return contentMode === 'compact' || (0, _expValEquals.expValEquals)('cc_editor_ai_content_mode', 'variant', 'test') && (0, _platformFeatureFlags.fg)('platform_editor_content_mode_button_mvp');
12
16
  };
@@ -65,12 +69,18 @@ var cmTheme = exports.cmTheme = function cmTheme(options) {
65
69
  '.cm-gutter': {
66
70
  padding: "var(--ds-space-100, 8px)"
67
71
  },
68
- '.cm-gutters': {
72
+ '.cm-gutters': _objectSpread({
69
73
  backgroundColor: "var(--ds-background-neutral, #0515240F)",
70
74
  border: 'none',
71
75
  padding: "var(--ds-space-0, 0px)",
72
76
  color: "var(--ds-text-subtlest, #6B6E76)"
73
- },
77
+ }, (0, _expValEquals.expValEquals)('platform_editor_code_block_q4_lovability', 'isEnabled', true) && {
78
+ // CodeMirror defaults this to height: 100%, which can resolve against an indefinite
79
+ // parent height in content-height editor and prevent flex stretching when gutter
80
+ // content is sparse, such as fold-only gutters.
81
+ height: 'unset',
82
+ alignSelf: 'stretch'
83
+ }),
74
84
  '.cm-lineNumbers .cm-gutterElement': {
75
85
  paddingLeft: "var(--ds-space-0, 0px)",
76
86
  paddingRight: "var(--ds-space-0, 0px)",
@@ -4,7 +4,7 @@ import { syntaxHighlighting, bracketMatching } from '@codemirror/language';
4
4
  import { Compartment, Facet, EditorState as CodeMirrorState } from '@codemirror/state';
5
5
  import { EditorView as CodeMirror, lineNumbers, gutters } from '@codemirror/view';
6
6
  import { getBrowserInfo } from '@atlaskit/editor-common/browser';
7
- import { isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
7
+ import { areCodeBlockLineNumbersHidden, isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
8
8
  import { messages as floatingToolbarMessages } from '@atlaskit/editor-common/floating-toolbar';
9
9
  import { blockTypeMessages, codeBlockMessages, roleDescriptionMessages } from '@atlaskit/editor-common/messages';
10
10
  import { ZERO_WIDTH_SPACE } from '@atlaskit/editor-common/whitespace';
@@ -34,6 +34,7 @@ class CodeBlockAdvancedNodeView {
34
34
  constructor(node, view, getPos, innerDecorations, config) {
35
35
  var _config$api, _config$api$contentFo, _contentFormatSharedS, _contentFormatSharedS2, _config$api2, _config$api2$selectio, _config$api3, _config$api3$editorDi, _config$api4;
36
36
  _defineProperty(this, "lineWrappingCompartment", new Compartment());
37
+ _defineProperty(this, "lineNumbersCompartment", new Compartment());
37
38
  _defineProperty(this, "languageCompartment", new Compartment());
38
39
  _defineProperty(this, "readOnlyCompartment", new Compartment());
39
40
  _defineProperty(this, "pmDecorationsCompartment", new Compartment());
@@ -41,6 +42,11 @@ class CodeBlockAdvancedNodeView {
41
42
  _defineProperty(this, "maybeTryingToReachNodeSelection", false);
42
43
  _defineProperty(this, "pmFacet", Facet.define());
43
44
  _defineProperty(this, "wordWrappingEnabled", false);
45
+ _defineProperty(this, "lineNumbersHidden", false);
46
+ _defineProperty(this, "selectCodeBlockNodeAndFocus", () => {
47
+ this.selectCodeBlockNode(undefined);
48
+ this.view.focus();
49
+ });
44
50
  this.config = config;
45
51
  this.node = node;
46
52
  this.view = view;
@@ -64,10 +70,6 @@ class CodeBlockAdvancedNodeView {
64
70
  formatMessage
65
71
  } = config.getIntl();
66
72
  const formattedAriaLabel = formatMessage(blockTypeMessages.codeblock);
67
- const selectNode = () => {
68
- this.selectCodeBlockNode(undefined);
69
- this.view.focus();
70
- };
71
73
  const isMacOS = getBrowserInfo().mac;
72
74
  this.cm = new CodeMirror({
73
75
  doc: this.node.textContent,
@@ -82,16 +84,9 @@ class CodeBlockAdvancedNodeView {
82
84
  // Goes before cmTheme to override styles
83
85
  config.allowCodeFolding ? [codeFoldingTheme] : [], this.themeCompartment.of(cmTheme({
84
86
  contentMode: expValEquals('confluence_compact_text_format', 'isEnabled', true) ? this.contentMode : undefined
85
- })), syntaxHighlighting(highlightStyle), bracketMatching(), lineNumbers({
86
- domEventHandlers: {
87
- click: () => {
88
- selectNode();
89
- return true;
90
- }
91
- }
92
- }),
93
- // Explicitly disable "sticky" positioning on line numbers to match
94
- // Renderer behaviour
87
+ })), syntaxHighlighting(highlightStyle), bracketMatching(), expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) ? this.lineNumbersCompartment.of(this.getLineNumberVisibilityExtensions(node)) : this.getLineNumberExtensions(),
88
+ // Explicitly disable "sticky" positioning on all gutters to match
89
+ // Renderer behaviour.
95
90
  gutters({
96
91
  fixed: false
97
92
  }), CodeMirror.updateListener.of(update => this.forwardUpdate(update)), this.readOnlyCompartment.of([CodeMirrorState.readOnly.of(!this.view.editable), CodeMirror.contentAttributes.of({
@@ -117,7 +112,7 @@ class CodeBlockAdvancedNodeView {
117
112
  'aria-describedby': `codesnippet-${this.node.attrs.localId}`
118
113
  })
119
114
  }), config.allowCodeFolding ? [foldGutterExtension({
120
- selectNode,
115
+ selectNode: this.selectCodeBlockNodeAndFocus,
121
116
  getNode: () => this.node
122
117
  })] : [],
123
118
  // With platform_editor_fix_advanced_codeblocks_crlf_patch the lineSeparatorExtension is not needed
@@ -189,6 +184,7 @@ class CodeBlockAdvancedNodeView {
189
184
  this.updateLanguage();
190
185
  this.updateLocalIdAttribute();
191
186
  this.wordWrappingEnabled = isCodeBlockWordWrapEnabled(node);
187
+ this.lineNumbersHidden = areCodeBlockLineNumbersHidden(node);
192
188
 
193
189
  // Restore fold state after initialization
194
190
  if (config.allowCodeFolding) {
@@ -288,6 +284,30 @@ class CodeBlockAdvancedNodeView {
288
284
  this.view.dispatch(tr);
289
285
  }
290
286
  }
287
+ getLineNumberExtensions() {
288
+ return [lineNumbers({
289
+ domEventHandlers: {
290
+ click: () => {
291
+ this.selectCodeBlockNodeAndFocus();
292
+ return true;
293
+ }
294
+ }
295
+ })];
296
+ }
297
+ getLineNumberVisibilityExtensions(node) {
298
+ if (areCodeBlockLineNumbersHidden(node)) {
299
+ return [];
300
+ }
301
+ return this.getLineNumberExtensions();
302
+ }
303
+ getLineNumbersEffects(node) {
304
+ const lineNumbersHidden = areCodeBlockLineNumbersHidden(node);
305
+ if (this.lineNumbersHidden !== lineNumbersHidden) {
306
+ this.lineNumbersHidden = lineNumbersHidden;
307
+ return this.lineNumbersCompartment.reconfigure(this.getLineNumberVisibilityExtensions(node));
308
+ }
309
+ return undefined;
310
+ }
291
311
  getWordWrapEffects(node) {
292
312
  if (this.wordWrappingEnabled !== isCodeBlockWordWrapEnabled(node)) {
293
313
  this.wordWrappingEnabled = !this.wordWrappingEnabled;
@@ -338,11 +358,12 @@ class CodeBlockAdvancedNodeView {
338
358
  // Updates bundled for performance (to avoid multiple-dispatches)
339
359
  const changes = getCMSelectionChanges(curText, newText);
340
360
  const wordWrapEffect = this.getWordWrapEffects(node);
361
+ const lineNumbersEffect = expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) ? this.getLineNumbersEffects(node) : undefined;
341
362
  const prosemirrorDecorationsEffect = this.getProseMirrorDecorationEffects(innerDecorations);
342
- if (changes || wordWrapEffect || prosemirrorDecorationsEffect) {
363
+ if (changes || wordWrapEffect || lineNumbersEffect || prosemirrorDecorationsEffect) {
343
364
  this.updating = true;
344
365
  this.cm.dispatch({
345
- effects: [wordWrapEffect, prosemirrorDecorationsEffect].filter(effect => !!effect),
366
+ effects: [wordWrapEffect, lineNumbersEffect, prosemirrorDecorationsEffect].filter(effect => !!effect),
346
367
  changes
347
368
  });
348
369
  this.updating = false;
@@ -1,4 +1,5 @@
1
1
  import { codeBlock, codeBlockWithExtendedAttributes, codeBlockWithLocalId } from '@atlaskit/adf-schema';
2
+ import { areCodeBlockLineNumbersHidden } from '@atlaskit/editor-common/code-block';
2
3
  import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
3
4
  import { CodeBlockSharedCssClassName } from '@atlaskit/editor-common/styles';
4
5
  import { fg } from '@atlaskit/platform-feature-flags';
@@ -12,6 +13,51 @@ const codeBlockClassNames = {
12
13
  };
13
14
  const MATCH_NEWLINES = new RegExp('\n', 'gu');
14
15
  const getFontSize = () => expValEquals('confluence_compact_text_format', 'isEnabled', true) || expValEquals('cc_editor_ai_content_mode', 'variant', 'test') && fg('platform_editor_content_mode_button_mvp') ? '0.875em' : '0.875rem';
16
+ const getGutterBaseStyle = () => ({
17
+ backgroundColor: "var(--ds-background-neutral, #0515240F)",
18
+ position: 'relative',
19
+ flexShrink: 0,
20
+ // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
21
+ fontSize: getFontSize(),
22
+ boxSizing: 'content-box'
23
+ });
24
+ const getGutterPadding = allowCodeFolding => allowCodeFolding ? `${"var(--ds-space-100, 8px)"} ${"var(--ds-space-250, 20px)"} ${"var(--ds-space-100, 8px)"} ${"var(--ds-space-075, 6px)"}` : "var(--ds-space-100, 8px)";
25
+ const getGuttersWithLineNumbers = (content, config) => ['div', {
26
+ // Based on packages/editor/editor-common/src/styles/shared/code-block.ts
27
+ // But we can't reuse that class as it adds a ::before that intefers with this approach
28
+ style: convertToInlineCss({
29
+ ...getGutterBaseStyle(),
30
+ width: 'var(--lineNumberGutterWidth, 2rem)',
31
+ /* top and bottom | left and right */
32
+ padding: getGutterPadding(config.allowCodeFolding)
33
+ }),
34
+ contenteditable: 'false'
35
+ }, ['div', {
36
+ class: 'code-block-gutter-pseudo-element',
37
+ style: convertToInlineCss({
38
+ textAlign: 'right',
39
+ color: "var(--ds-text-subtlest, #6B6E76)",
40
+ fontFamily: "var(--ds-font-family-code, \"Atlassian Mono\", ui-monospace, Menlo, \"Segoe UI Mono\", \"Ubuntu Mono\", monospace)",
41
+ whiteSpace: 'pre-wrap'
42
+ }),
43
+ 'data-label': content
44
+ }]];
45
+ const getFoldOnlyGutter = () => ['div', {
46
+ style: convertToInlineCss({
47
+ ...getGutterBaseStyle(),
48
+ padding: `${"var(--ds-space-100, 8px)"} ${"var(--ds-space-150, 12px)"} ${"var(--ds-space-100, 8px)"} ${"var(--ds-space-100, 8px)"}`
49
+ }),
50
+ contenteditable: 'false'
51
+ }];
52
+ const getGutters = (content, config, hideLineNumbers) => {
53
+ if (!hideLineNumbers) {
54
+ return [getGuttersWithLineNumbers(content, config)];
55
+ }
56
+ if (config.allowCodeFolding) {
57
+ return [getFoldOnlyGutter()];
58
+ }
59
+ return [];
60
+ };
15
61
 
16
62
  // Based on: `packages/editor/editor-plugin-code-block/src/nodeviews/code-block.ts`
17
63
  const toDOM = (node, formattedAriaLabel, config) => {
@@ -22,44 +68,26 @@ const toDOM = (node, formattedAriaLabel, config) => {
22
68
  totalLineCount += (node.text.match(MATCH_NEWLINES) || []).length;
23
69
  }
24
70
  });
71
+ const hideLineNumbers = areCodeBlockLineNumbersHidden(node);
25
72
  const maxDigits = totalLineCount.toString().length;
26
73
  const content = node.textContent.split('\n').map((_, i) => i + 1).join('\n');
74
+ const gutters = getGutters(content, config, hideLineNumbers);
27
75
  return ['pre', {
28
76
  class: codeBlockClassNames.container,
29
77
  style: `--lineNumberGutterWidth:${maxDigits}ch;`,
30
78
  'data-language': node.attrs.language || '',
31
79
  ...(expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) && {
32
- 'data-wrap': node.attrs.wrap ? 'true' : 'false'
80
+ 'data-wrap': node.attrs.wrap ? 'true' : 'false',
81
+ ...(hideLineNumbers && {
82
+ 'data-hide-line-numbers': 'true'
83
+ })
33
84
  })
34
85
  }, ['div', {
35
86
  class: codeBlockClassNames.start,
36
87
  contenteditable: 'false'
37
88
  }], ['div', {
38
89
  class: codeBlockClassNames.contentWrapper
39
- }, ['div', {
40
- // Based on packages/editor/editor-common/src/styles/shared/code-block.ts
41
- // But we can't reuse that class as it adds a ::before that intefers with this approach
42
- style: convertToInlineCss({
43
- backgroundColor: "var(--ds-background-neutral, #0515240F)",
44
- position: 'relative',
45
- width: 'var(--lineNumberGutterWidth, 2rem)',
46
- /* top and bottom | left and right */
47
- padding: config.allowCodeFolding ? `${"var(--ds-space-100, 8px)"} ${"var(--ds-space-250, 20px)"} ${"var(--ds-space-100, 8px)"} ${"var(--ds-space-075, 6px)"}` : "var(--ds-space-100, 8px)",
48
- flexShrink: 0,
49
- fontSize: getFontSize(),
50
- boxSizing: 'content-box'
51
- }),
52
- contenteditable: 'false'
53
- }, ['div', {
54
- class: 'code-block-gutter-pseudo-element',
55
- style: convertToInlineCss({
56
- textAlign: 'right',
57
- color: "var(--ds-text-subtlest, #6B6E76)",
58
- fontFamily: "var(--ds-font-family-code, \"Atlassian Mono\", ui-monospace, Menlo, \"Segoe UI Mono\", \"Ubuntu Mono\", monospace)",
59
- whiteSpace: 'pre-wrap'
60
- }),
61
- 'data-label': content
62
- }]], ['div', {
90
+ }, ...gutters, ['div', {
63
91
  class: codeBlockClassNames.content
64
92
  }, ['code', {
65
93
  'data-language': node.attrs.language || '',
@@ -56,7 +56,14 @@ export const cmTheme = options => CodeMirror.theme({
56
56
  backgroundColor: "var(--ds-background-neutral, #0515240F)",
57
57
  border: 'none',
58
58
  padding: "var(--ds-space-0, 0px)",
59
- color: "var(--ds-text-subtlest, #6B6E76)"
59
+ color: "var(--ds-text-subtlest, #6B6E76)",
60
+ ...(expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) && {
61
+ // CodeMirror defaults this to height: 100%, which can resolve against an indefinite
62
+ // parent height in content-height editor and prevent flex stretching when gutter
63
+ // content is sparse, such as fold-only gutters.
64
+ height: 'unset',
65
+ alignSelf: 'stretch'
66
+ })
60
67
  },
61
68
  '.cm-lineNumbers .cm-gutterElement': {
62
69
  paddingLeft: "var(--ds-space-0, 0px)",
@@ -12,7 +12,7 @@ import { syntaxHighlighting, bracketMatching } from '@codemirror/language';
12
12
  import { Compartment, Facet, EditorState as CodeMirrorState } from '@codemirror/state';
13
13
  import { EditorView as CodeMirror, lineNumbers, gutters } from '@codemirror/view';
14
14
  import { getBrowserInfo } from '@atlaskit/editor-common/browser';
15
- import { isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
15
+ import { areCodeBlockLineNumbersHidden, isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
16
16
  import { messages as floatingToolbarMessages } from '@atlaskit/editor-common/floating-toolbar';
17
17
  import { blockTypeMessages, codeBlockMessages, roleDescriptionMessages } from '@atlaskit/editor-common/messages';
18
18
  import { ZERO_WIDTH_SPACE } from '@atlaskit/editor-common/whitespace';
@@ -40,14 +40,15 @@ var codeBlockHeights = new WeakMap();
40
40
  // Based on: https://prosemirror.net/examples/codemirror/
41
41
  var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
42
42
  function CodeBlockAdvancedNodeView(node, view, getPos, innerDecorations, config) {
43
- var _config$api,
43
+ var _this = this,
44
+ _config$api,
44
45
  _contentFormatSharedS,
45
46
  _config$api2,
46
- _this = this,
47
47
  _config$api3,
48
48
  _config$api4;
49
49
  _classCallCheck(this, CodeBlockAdvancedNodeView);
50
50
  _defineProperty(this, "lineWrappingCompartment", new Compartment());
51
+ _defineProperty(this, "lineNumbersCompartment", new Compartment());
51
52
  _defineProperty(this, "languageCompartment", new Compartment());
52
53
  _defineProperty(this, "readOnlyCompartment", new Compartment());
53
54
  _defineProperty(this, "pmDecorationsCompartment", new Compartment());
@@ -55,6 +56,11 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
55
56
  _defineProperty(this, "maybeTryingToReachNodeSelection", false);
56
57
  _defineProperty(this, "pmFacet", Facet.define());
57
58
  _defineProperty(this, "wordWrappingEnabled", false);
59
+ _defineProperty(this, "lineNumbersHidden", false);
60
+ _defineProperty(this, "selectCodeBlockNodeAndFocus", function () {
61
+ _this.selectCodeBlockNode(undefined);
62
+ _this.view.focus();
63
+ });
58
64
  this.config = config;
59
65
  this.node = node;
60
66
  this.view = view;
@@ -81,10 +87,6 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
81
87
  var _config$getIntl = config.getIntl(),
82
88
  formatMessage = _config$getIntl.formatMessage;
83
89
  var formattedAriaLabel = formatMessage(blockTypeMessages.codeblock);
84
- var selectNode = function selectNode() {
85
- _this.selectCodeBlockNode(undefined);
86
- _this.view.focus();
87
- };
88
90
  var isMacOS = getBrowserInfo().mac;
89
91
  this.cm = new CodeMirror({
90
92
  doc: this.node.textContent,
@@ -101,16 +103,9 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
101
103
  // Goes before cmTheme to override styles
102
104
  config.allowCodeFolding ? [codeFoldingTheme] : [], this.themeCompartment.of(cmTheme({
103
105
  contentMode: expValEquals('confluence_compact_text_format', 'isEnabled', true) ? this.contentMode : undefined
104
- })), syntaxHighlighting(highlightStyle), bracketMatching(), lineNumbers({
105
- domEventHandlers: {
106
- click: function click() {
107
- selectNode();
108
- return true;
109
- }
110
- }
111
- }),
112
- // Explicitly disable "sticky" positioning on line numbers to match
113
- // Renderer behaviour
106
+ })), syntaxHighlighting(highlightStyle), bracketMatching(), expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) ? this.lineNumbersCompartment.of(this.getLineNumberVisibilityExtensions(node)) : this.getLineNumberExtensions(),
107
+ // Explicitly disable "sticky" positioning on all gutters to match
108
+ // Renderer behaviour.
114
109
  gutters({
115
110
  fixed: false
116
111
  }), CodeMirror.updateListener.of(function (update) {
@@ -133,7 +128,7 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
133
128
  'aria-label': formattedAriaLabel,
134
129
  'aria-describedby': "codesnippet-".concat(this.node.attrs.localId)
135
130
  })), config.allowCodeFolding ? [foldGutterExtension({
136
- selectNode: selectNode,
131
+ selectNode: this.selectCodeBlockNodeAndFocus,
137
132
  getNode: function getNode() {
138
133
  return _this.node;
139
134
  }
@@ -215,6 +210,7 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
215
210
  this.updateLanguage();
216
211
  this.updateLocalIdAttribute();
217
212
  this.wordWrappingEnabled = isCodeBlockWordWrapEnabled(node);
213
+ this.lineNumbersHidden = areCodeBlockLineNumbersHidden(node);
218
214
 
219
215
  // Restore fold state after initialization
220
216
  if (config.allowCodeFolding) {
@@ -329,6 +325,37 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
329
325
  this.view.dispatch(tr);
330
326
  }
331
327
  }
328
+ }, {
329
+ key: "getLineNumberExtensions",
330
+ value: function getLineNumberExtensions() {
331
+ var _this2 = this;
332
+ return [lineNumbers({
333
+ domEventHandlers: {
334
+ click: function click() {
335
+ _this2.selectCodeBlockNodeAndFocus();
336
+ return true;
337
+ }
338
+ }
339
+ })];
340
+ }
341
+ }, {
342
+ key: "getLineNumberVisibilityExtensions",
343
+ value: function getLineNumberVisibilityExtensions(node) {
344
+ if (areCodeBlockLineNumbersHidden(node)) {
345
+ return [];
346
+ }
347
+ return this.getLineNumberExtensions();
348
+ }
349
+ }, {
350
+ key: "getLineNumbersEffects",
351
+ value: function getLineNumbersEffects(node) {
352
+ var lineNumbersHidden = areCodeBlockLineNumbersHidden(node);
353
+ if (this.lineNumbersHidden !== lineNumbersHidden) {
354
+ this.lineNumbersHidden = lineNumbersHidden;
355
+ return this.lineNumbersCompartment.reconfigure(this.getLineNumberVisibilityExtensions(node));
356
+ }
357
+ return undefined;
358
+ }
332
359
  }, {
333
360
  key: "getWordWrapEffects",
334
361
  value: function getWordWrapEffects(node) {
@@ -387,11 +414,12 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
387
414
  // Updates bundled for performance (to avoid multiple-dispatches)
388
415
  var changes = getCMSelectionChanges(curText, newText);
389
416
  var wordWrapEffect = this.getWordWrapEffects(node);
417
+ var lineNumbersEffect = expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) ? this.getLineNumbersEffects(node) : undefined;
390
418
  var prosemirrorDecorationsEffect = this.getProseMirrorDecorationEffects(innerDecorations);
391
- if (changes || wordWrapEffect || prosemirrorDecorationsEffect) {
419
+ if (changes || wordWrapEffect || lineNumbersEffect || prosemirrorDecorationsEffect) {
392
420
  this.updating = true;
393
421
  this.cm.dispatch({
394
- effects: [wordWrapEffect, prosemirrorDecorationsEffect].filter(function (effect) {
422
+ effects: [wordWrapEffect, lineNumbersEffect, prosemirrorDecorationsEffect].filter(function (effect) {
395
423
  return !!effect;
396
424
  }),
397
425
  changes: changes
@@ -1,7 +1,9 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
1
2
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
3
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
4
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
5
  import { codeBlock, codeBlockWithExtendedAttributes, codeBlockWithLocalId } from '@atlaskit/adf-schema';
6
+ import { areCodeBlockLineNumbersHidden } from '@atlaskit/editor-common/code-block';
5
7
  import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
6
8
  import { CodeBlockSharedCssClassName } from '@atlaskit/editor-common/styles';
7
9
  import { fg } from '@atlaskit/platform-feature-flags';
@@ -17,6 +19,57 @@ var MATCH_NEWLINES = new RegExp('\n', 'gu');
17
19
  var getFontSize = function getFontSize() {
18
20
  return expValEquals('confluence_compact_text_format', 'isEnabled', true) || expValEquals('cc_editor_ai_content_mode', 'variant', 'test') && fg('platform_editor_content_mode_button_mvp') ? '0.875em' : '0.875rem';
19
21
  };
22
+ var getGutterBaseStyle = function getGutterBaseStyle() {
23
+ return {
24
+ backgroundColor: "var(--ds-background-neutral, #0515240F)",
25
+ position: 'relative',
26
+ flexShrink: 0,
27
+ // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
28
+ fontSize: getFontSize(),
29
+ boxSizing: 'content-box'
30
+ };
31
+ };
32
+ var getGutterPadding = function getGutterPadding(allowCodeFolding) {
33
+ return allowCodeFolding ? "var(--ds-space-100, 8px)".concat(" ", "var(--ds-space-250, 20px)", " ", "var(--ds-space-100, 8px)", " ", "var(--ds-space-075, 6px)") : "var(--ds-space-100, 8px)";
34
+ };
35
+ var getGuttersWithLineNumbers = function getGuttersWithLineNumbers(content, config) {
36
+ return ['div', {
37
+ // Based on packages/editor/editor-common/src/styles/shared/code-block.ts
38
+ // But we can't reuse that class as it adds a ::before that intefers with this approach
39
+ style: convertToInlineCss(_objectSpread(_objectSpread({}, getGutterBaseStyle()), {}, {
40
+ width: 'var(--lineNumberGutterWidth, 2rem)',
41
+ /* top and bottom | left and right */
42
+ padding: getGutterPadding(config.allowCodeFolding)
43
+ })),
44
+ contenteditable: 'false'
45
+ }, ['div', {
46
+ class: 'code-block-gutter-pseudo-element',
47
+ style: convertToInlineCss({
48
+ textAlign: 'right',
49
+ color: "var(--ds-text-subtlest, #6B6E76)",
50
+ fontFamily: "var(--ds-font-family-code, \"Atlassian Mono\", ui-monospace, Menlo, \"Segoe UI Mono\", \"Ubuntu Mono\", monospace)",
51
+ whiteSpace: 'pre-wrap'
52
+ }),
53
+ 'data-label': content
54
+ }]];
55
+ };
56
+ var getFoldOnlyGutter = function getFoldOnlyGutter() {
57
+ return ['div', {
58
+ style: convertToInlineCss(_objectSpread(_objectSpread({}, getGutterBaseStyle()), {}, {
59
+ padding: "var(--ds-space-100, 8px)".concat(" ", "var(--ds-space-150, 12px)", " ", "var(--ds-space-100, 8px)", " ", "var(--ds-space-100, 8px)")
60
+ })),
61
+ contenteditable: 'false'
62
+ }];
63
+ };
64
+ var getGutters = function getGutters(content, config, hideLineNumbers) {
65
+ if (!hideLineNumbers) {
66
+ return [getGuttersWithLineNumbers(content, config)];
67
+ }
68
+ if (config.allowCodeFolding) {
69
+ return [getFoldOnlyGutter()];
70
+ }
71
+ return [];
72
+ };
20
73
 
21
74
  // Based on: `packages/editor/editor-plugin-code-block/src/nodeviews/code-block.ts`
22
75
  var _toDOM = function toDOM(node, formattedAriaLabel, config) {
@@ -27,45 +80,26 @@ var _toDOM = function toDOM(node, formattedAriaLabel, config) {
27
80
  totalLineCount += (node.text.match(MATCH_NEWLINES) || []).length;
28
81
  }
29
82
  });
83
+ var hideLineNumbers = areCodeBlockLineNumbersHidden(node);
30
84
  var maxDigits = totalLineCount.toString().length;
31
85
  var content = node.textContent.split('\n').map(function (_, i) {
32
86
  return i + 1;
33
87
  }).join('\n');
88
+ var gutters = getGutters(content, config, hideLineNumbers);
34
89
  return ['pre', _objectSpread({
35
90
  class: codeBlockClassNames.container,
36
91
  style: "--lineNumberGutterWidth:".concat(maxDigits, "ch;"),
37
92
  'data-language': node.attrs.language || ''
38
- }, expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) && {
93
+ }, expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) && _objectSpread({
39
94
  'data-wrap': node.attrs.wrap ? 'true' : 'false'
40
- }), ['div', {
95
+ }, hideLineNumbers && {
96
+ 'data-hide-line-numbers': 'true'
97
+ })), ['div', {
41
98
  class: codeBlockClassNames.start,
42
99
  contenteditable: 'false'
43
100
  }], ['div', {
44
101
  class: codeBlockClassNames.contentWrapper
45
- }, ['div', {
46
- // Based on packages/editor/editor-common/src/styles/shared/code-block.ts
47
- // But we can't reuse that class as it adds a ::before that intefers with this approach
48
- style: convertToInlineCss({
49
- backgroundColor: "var(--ds-background-neutral, #0515240F)",
50
- position: 'relative',
51
- width: 'var(--lineNumberGutterWidth, 2rem)',
52
- /* top and bottom | left and right */
53
- padding: config.allowCodeFolding ? "var(--ds-space-100, 8px)".concat(" ", "var(--ds-space-250, 20px)", " ", "var(--ds-space-100, 8px)", " ", "var(--ds-space-075, 6px)") : "var(--ds-space-100, 8px)",
54
- flexShrink: 0,
55
- fontSize: getFontSize(),
56
- boxSizing: 'content-box'
57
- }),
58
- contenteditable: 'false'
59
- }, ['div', {
60
- class: 'code-block-gutter-pseudo-element',
61
- style: convertToInlineCss({
62
- textAlign: 'right',
63
- color: "var(--ds-text-subtlest, #6B6E76)",
64
- fontFamily: "var(--ds-font-family-code, \"Atlassian Mono\", ui-monospace, Menlo, \"Segoe UI Mono\", \"Ubuntu Mono\", monospace)",
65
- whiteSpace: 'pre-wrap'
66
- }),
67
- 'data-label': content
68
- }]], ['div', {
102
+ }].concat(_toConsumableArray(gutters), [['div', {
69
103
  class: codeBlockClassNames.content
70
104
  }, ['code', _objectSpread({
71
105
  'data-language': node.attrs.language || '',
@@ -74,7 +108,7 @@ var _toDOM = function toDOM(node, formattedAriaLabel, config) {
74
108
  'aria-label': formattedAriaLabel
75
109
  }, fg('platform_editor_adf_with_localid') && {
76
110
  'data-local-id': node.attrs.localId
77
- }), 0]]], ['div', {
111
+ }), 0]]]), ['div', {
78
112
  class: codeBlockClassNames.end,
79
113
  contenteditable: 'false'
80
114
  }]];
@@ -1,3 +1,6 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1
4
  import { EditorView as CodeMirror } from '@codemirror/view';
2
5
  import { fg } from '@atlaskit/platform-feature-flags';
3
6
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
@@ -59,12 +62,18 @@ export var cmTheme = function cmTheme(options) {
59
62
  '.cm-gutter': {
60
63
  padding: "var(--ds-space-100, 8px)"
61
64
  },
62
- '.cm-gutters': {
65
+ '.cm-gutters': _objectSpread({
63
66
  backgroundColor: "var(--ds-background-neutral, #0515240F)",
64
67
  border: 'none',
65
68
  padding: "var(--ds-space-0, 0px)",
66
69
  color: "var(--ds-text-subtlest, #6B6E76)"
67
- },
70
+ }, expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) && {
71
+ // CodeMirror defaults this to height: 100%, which can resolve against an indefinite
72
+ // parent height in content-height editor and prevent flex stretching when gutter
73
+ // content is sparse, such as fold-only gutters.
74
+ height: 'unset',
75
+ alignSelf: 'stretch'
76
+ }),
68
77
  '.cm-lineNumbers .cm-gutterElement': {
69
78
  paddingLeft: "var(--ds-space-0, 0px)",
70
79
  paddingRight: "var(--ds-space-0, 0px)",
@@ -16,6 +16,7 @@ declare class CodeBlockAdvancedNodeView implements NodeView {
16
16
  private updating;
17
17
  private view;
18
18
  private lineWrappingCompartment;
19
+ private lineNumbersCompartment;
19
20
  private languageCompartment;
20
21
  private readOnlyCompartment;
21
22
  private pmDecorationsCompartment;
@@ -43,6 +44,11 @@ declare class CodeBlockAdvancedNodeView implements NodeView {
43
44
  private updateLocalIdAttribute;
44
45
  private selectCodeBlockNode;
45
46
  private wordWrappingEnabled;
47
+ private lineNumbersHidden;
48
+ private selectCodeBlockNodeAndFocus;
49
+ private getLineNumberExtensions;
50
+ private getLineNumberVisibilityExtensions;
51
+ private getLineNumbersEffects;
46
52
  private getWordWrapEffects;
47
53
  private restoreFoldState;
48
54
  private applyContentModeTheme;
@@ -16,6 +16,7 @@ declare class CodeBlockAdvancedNodeView implements NodeView {
16
16
  private updating;
17
17
  private view;
18
18
  private lineWrappingCompartment;
19
+ private lineNumbersCompartment;
19
20
  private languageCompartment;
20
21
  private readOnlyCompartment;
21
22
  private pmDecorationsCompartment;
@@ -43,6 +44,11 @@ declare class CodeBlockAdvancedNodeView implements NodeView {
43
44
  private updateLocalIdAttribute;
44
45
  private selectCodeBlockNode;
45
46
  private wordWrappingEnabled;
47
+ private lineNumbersHidden;
48
+ private selectCodeBlockNodeAndFocus;
49
+ private getLineNumberExtensions;
50
+ private getLineNumberVisibilityExtensions;
51
+ private getLineNumbersEffects;
46
52
  private getWordWrapEffects;
47
53
  private restoreFoldState;
48
54
  private applyContentModeTheme;
package/docs/0-intro.tsx CHANGED
@@ -20,7 +20,7 @@ ${createEditorUseOnlyNotice('Editor Plugin Code Block Advanced', [
20
20
  <AtlassianInternalWarning />
21
21
  </div>
22
22
  </>
23
- )}
23
+ )}
24
24
 
25
25
  This package includes the code block advanced plugin used by \`@atlaskit/editor-core\`.
26
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-code-block-advanced",
3
- "version": "10.1.0",
3
+ "version": "10.1.1",
4
4
  "description": "CodeBlockAdvanced plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -55,7 +55,7 @@
55
55
  "codemirror-lang-elixir": "4.0.0"
56
56
  },
57
57
  "peerDependencies": {
58
- "@atlaskit/editor-common": "^114.30.0",
58
+ "@atlaskit/editor-common": "^114.32.0",
59
59
  "react": "^18.2.0",
60
60
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
61
61
  },
@@ -7,7 +7,10 @@ import type { ViewUpdate } from '@codemirror/view';
7
7
  import type { IntlShape } from 'react-intl';
8
8
 
9
9
  import { getBrowserInfo } from '@atlaskit/editor-common/browser';
10
- import { isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
10
+ import {
11
+ areCodeBlockLineNumbersHidden,
12
+ isCodeBlockWordWrapEnabled,
13
+ } from '@atlaskit/editor-common/code-block';
11
14
  import { messages as floatingToolbarMessages } from '@atlaskit/editor-common/floating-toolbar';
12
15
  import {
13
16
  blockTypeMessages,
@@ -68,6 +71,7 @@ class CodeBlockAdvancedNodeView implements NodeView {
68
71
  private updating: boolean;
69
72
  private view: EditorView;
70
73
  private lineWrappingCompartment = new Compartment();
74
+ private lineNumbersCompartment = new Compartment();
71
75
  private languageCompartment = new Compartment();
72
76
  private readOnlyCompartment = new Compartment();
73
77
  private pmDecorationsCompartment = new Compartment();
@@ -126,11 +130,6 @@ class CodeBlockAdvancedNodeView implements NodeView {
126
130
  const { formatMessage } = config.getIntl();
127
131
  const formattedAriaLabel = formatMessage(blockTypeMessages.codeblock);
128
132
 
129
- const selectNode = () => {
130
- this.selectCodeBlockNode(undefined);
131
- this.view.focus();
132
- };
133
-
134
133
  const isMacOS = getBrowserInfo().mac;
135
134
 
136
135
  this.cm = new CodeMirror({
@@ -161,16 +160,11 @@ class CodeBlockAdvancedNodeView implements NodeView {
161
160
  ),
162
161
  syntaxHighlighting(highlightStyle),
163
162
  bracketMatching(),
164
- lineNumbers({
165
- domEventHandlers: {
166
- click: () => {
167
- selectNode();
168
- return true;
169
- },
170
- },
171
- }),
172
- // Explicitly disable "sticky" positioning on line numbers to match
173
- // Renderer behaviour
163
+ expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true)
164
+ ? this.lineNumbersCompartment.of(this.getLineNumberVisibilityExtensions(node))
165
+ : this.getLineNumberExtensions(),
166
+ // Explicitly disable "sticky" positioning on all gutters to match
167
+ // Renderer behaviour.
174
168
  gutters({ fixed: false }),
175
169
  CodeMirror.updateListener.of((update) => this.forwardUpdate(update)),
176
170
  this.readOnlyCompartment.of([
@@ -207,7 +201,12 @@ class CodeBlockAdvancedNodeView implements NodeView {
207
201
  }),
208
202
  }),
209
203
  config.allowCodeFolding
210
- ? [foldGutterExtension({ selectNode, getNode: () => this.node })]
204
+ ? [
205
+ foldGutterExtension({
206
+ selectNode: this.selectCodeBlockNodeAndFocus,
207
+ getNode: () => this.node,
208
+ }),
209
+ ]
211
210
  : [],
212
211
  // With platform_editor_fix_advanced_codeblocks_crlf_patch the lineSeparatorExtension is not needed
213
212
  expValEquals('platform_editor_fix_advanced_codeblocks_crlf_patch', 'isEnabled', true)
@@ -293,6 +292,7 @@ class CodeBlockAdvancedNodeView implements NodeView {
293
292
  this.updateLanguage();
294
293
  this.updateLocalIdAttribute();
295
294
  this.wordWrappingEnabled = isCodeBlockWordWrapEnabled(node);
295
+ this.lineNumbersHidden = areCodeBlockLineNumbersHidden(node);
296
296
 
297
297
  // Restore fold state after initialization
298
298
  if (config.allowCodeFolding) {
@@ -405,6 +405,44 @@ class CodeBlockAdvancedNodeView implements NodeView {
405
405
  }
406
406
 
407
407
  private wordWrappingEnabled = false;
408
+ private lineNumbersHidden = false;
409
+
410
+ private selectCodeBlockNodeAndFocus = () => {
411
+ this.selectCodeBlockNode(undefined);
412
+ this.view.focus();
413
+ };
414
+
415
+ private getLineNumberExtensions(): Extension[] {
416
+ return [
417
+ lineNumbers({
418
+ domEventHandlers: {
419
+ click: () => {
420
+ this.selectCodeBlockNodeAndFocus();
421
+ return true;
422
+ },
423
+ },
424
+ }),
425
+ ];
426
+ }
427
+
428
+ private getLineNumberVisibilityExtensions(node: PMNode): Extension[] {
429
+ if (areCodeBlockLineNumbersHidden(node)) {
430
+ return [];
431
+ }
432
+
433
+ return this.getLineNumberExtensions();
434
+ }
435
+
436
+ private getLineNumbersEffects(node: PMNode) {
437
+ const lineNumbersHidden = areCodeBlockLineNumbersHidden(node);
438
+ if (this.lineNumbersHidden !== lineNumbersHidden) {
439
+ this.lineNumbersHidden = lineNumbersHidden;
440
+ return this.lineNumbersCompartment.reconfigure(
441
+ this.getLineNumberVisibilityExtensions(node),
442
+ );
443
+ }
444
+ return undefined;
445
+ }
408
446
 
409
447
  private getWordWrapEffects(node: PMNode) {
410
448
  if (this.wordWrappingEnabled !== isCodeBlockWordWrapEnabled(node)) {
@@ -455,11 +493,18 @@ class CodeBlockAdvancedNodeView implements NodeView {
455
493
  // Updates bundled for performance (to avoid multiple-dispatches)
456
494
  const changes = getCMSelectionChanges(curText, newText);
457
495
  const wordWrapEffect = this.getWordWrapEffects(node);
496
+ const lineNumbersEffect = expValEquals(
497
+ 'platform_editor_code_block_q4_lovability',
498
+ 'isEnabled',
499
+ true,
500
+ )
501
+ ? this.getLineNumbersEffects(node)
502
+ : undefined;
458
503
  const prosemirrorDecorationsEffect = this.getProseMirrorDecorationEffects(innerDecorations);
459
- if (changes || wordWrapEffect || prosemirrorDecorationsEffect) {
504
+ if (changes || wordWrapEffect || lineNumbersEffect || prosemirrorDecorationsEffect) {
460
505
  this.updating = true;
461
506
  this.cm.dispatch({
462
- effects: [wordWrapEffect, prosemirrorDecorationsEffect].filter(
507
+ effects: [wordWrapEffect, lineNumbersEffect, prosemirrorDecorationsEffect].filter(
463
508
  (effect): effect is StateEffect<unknown> => !!effect,
464
509
  ),
465
510
  changes,
@@ -3,6 +3,7 @@ import {
3
3
  codeBlockWithExtendedAttributes,
4
4
  codeBlockWithLocalId,
5
5
  } from '@atlaskit/adf-schema';
6
+ import { areCodeBlockLineNumbersHidden } from '@atlaskit/editor-common/code-block';
6
7
  import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
7
8
  import { CodeBlockSharedCssClassName } from '@atlaskit/editor-common/styles';
8
9
  import type { NodeSpec, DOMOutputSpec, Node } from '@atlaskit/editor-prosemirror/model';
@@ -31,6 +32,75 @@ const getFontSize = () =>
31
32
  ? '0.875em'
32
33
  : '0.875rem';
33
34
 
35
+ const getGutterBaseStyle = () => ({
36
+ backgroundColor: token('color.background.neutral'),
37
+ position: 'relative',
38
+ flexShrink: 0,
39
+ // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
40
+ fontSize: getFontSize(),
41
+ boxSizing: 'content-box',
42
+ });
43
+
44
+ const getGutterPadding = (allowCodeFolding: boolean) =>
45
+ allowCodeFolding
46
+ ? `${token('space.100')} ${token('space.250')} ${token('space.100')} ${token('space.075')}`
47
+ : token('space.100');
48
+
49
+ const getGuttersWithLineNumbers = (content: string, config: Config): DOMOutputSpec => [
50
+ 'div',
51
+ {
52
+ // Based on packages/editor/editor-common/src/styles/shared/code-block.ts
53
+ // But we can't reuse that class as it adds a ::before that intefers with this approach
54
+ style: convertToInlineCss({
55
+ ...getGutterBaseStyle(),
56
+ width: 'var(--lineNumberGutterWidth, 2rem)',
57
+ /* top and bottom | left and right */
58
+ padding: getGutterPadding(config.allowCodeFolding),
59
+ }),
60
+ contenteditable: 'false',
61
+ },
62
+ [
63
+ 'div',
64
+ {
65
+ class: 'code-block-gutter-pseudo-element',
66
+ style: convertToInlineCss({
67
+ textAlign: 'right',
68
+ color: token('color.text.subtlest'),
69
+ fontFamily: token('font.family.code'),
70
+ whiteSpace: 'pre-wrap',
71
+ }),
72
+ 'data-label': content,
73
+ },
74
+ ],
75
+ ];
76
+
77
+ const getFoldOnlyGutter = (): DOMOutputSpec => [
78
+ 'div',
79
+ {
80
+ style: convertToInlineCss({
81
+ ...getGutterBaseStyle(),
82
+ padding: `${token('space.100')} ${token('space.150')} ${token('space.100')} ${token('space.100')}`,
83
+ }),
84
+ contenteditable: 'false',
85
+ },
86
+ ];
87
+
88
+ const getGutters = (
89
+ content: string,
90
+ config: Config,
91
+ hideLineNumbers: boolean,
92
+ ): DOMOutputSpec[] => {
93
+ if (!hideLineNumbers) {
94
+ return [getGuttersWithLineNumbers(content, config)];
95
+ }
96
+
97
+ if (config.allowCodeFolding) {
98
+ return [getFoldOnlyGutter()];
99
+ }
100
+
101
+ return [];
102
+ };
103
+
34
104
  // Based on: `packages/editor/editor-plugin-code-block/src/nodeviews/code-block.ts`
35
105
  const toDOM = (node: Node, formattedAriaLabel: string, config: Config): DOMOutputSpec => {
36
106
  let totalLineCount = 1;
@@ -42,12 +112,14 @@ const toDOM = (node: Node, formattedAriaLabel: string, config: Config): DOMOutpu
42
112
  }
43
113
  });
44
114
 
115
+ const hideLineNumbers = areCodeBlockLineNumbersHidden(node);
45
116
  const maxDigits = totalLineCount.toString().length;
46
117
 
47
118
  const content = node.textContent
48
119
  .split('\n')
49
120
  .map((_, i) => i + 1)
50
121
  .join('\n');
122
+ const gutters = getGutters(content, config, hideLineNumbers);
51
123
 
52
124
  return [
53
125
  'pre',
@@ -57,6 +129,7 @@ const toDOM = (node: Node, formattedAriaLabel: string, config: Config): DOMOutpu
57
129
  'data-language': node.attrs.language || '',
58
130
  ...(expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) && {
59
131
  'data-wrap': node.attrs.wrap ? 'true' : 'false',
132
+ ...(hideLineNumbers && { 'data-hide-line-numbers': 'true' }),
60
133
  }),
61
134
  },
62
135
  ['div', { class: codeBlockClassNames.start, contenteditable: 'false' }],
@@ -65,39 +138,7 @@ const toDOM = (node: Node, formattedAriaLabel: string, config: Config): DOMOutpu
65
138
  {
66
139
  class: codeBlockClassNames.contentWrapper,
67
140
  },
68
- [
69
- 'div',
70
- {
71
- // Based on packages/editor/editor-common/src/styles/shared/code-block.ts
72
- // But we can't reuse that class as it adds a ::before that intefers with this approach
73
- style: convertToInlineCss({
74
- backgroundColor: token('color.background.neutral'),
75
- position: 'relative',
76
- width: 'var(--lineNumberGutterWidth, 2rem)',
77
- /* top and bottom | left and right */
78
- padding: config.allowCodeFolding
79
- ? `${token('space.100')} ${token('space.250')} ${token('space.100')} ${token('space.075')}`
80
- : token('space.100'),
81
- flexShrink: 0,
82
- fontSize: getFontSize(),
83
- boxSizing: 'content-box',
84
- }),
85
- contenteditable: 'false',
86
- },
87
- [
88
- 'div',
89
- {
90
- class: 'code-block-gutter-pseudo-element',
91
- style: convertToInlineCss({
92
- textAlign: 'right',
93
- color: token('color.text.subtlest'),
94
- fontFamily: token('font.family.code'),
95
- whiteSpace: 'pre-wrap',
96
- }),
97
- 'data-label': content,
98
- },
99
- ],
100
- ],
141
+ ...gutters,
101
142
  [
102
143
  'div',
103
144
  {
package/src/ui/theme.ts CHANGED
@@ -75,6 +75,13 @@ export const cmTheme = (options?: ThemeOptions): Extension =>
75
75
  border: 'none',
76
76
  padding: token('space.0'),
77
77
  color: token('color.text.subtlest'),
78
+ ...(expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) && {
79
+ // CodeMirror defaults this to height: 100%, which can resolve against an indefinite
80
+ // parent height in content-height editor and prevent flex stretching when gutter
81
+ // content is sparse, such as fold-only gutters.
82
+ height: 'unset',
83
+ alignSelf: 'stretch',
84
+ }),
78
85
  },
79
86
  '.cm-lineNumbers .cm-gutterElement': {
80
87
  paddingLeft: token('space.0'),