@atlaskit/editor-plugin-code-block-advanced 1.0.0 → 1.0.2

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 (31) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/afm-jira/tsconfig.json +36 -0
  3. package/afm-post-office/tsconfig.json +36 -0
  4. package/dist/cjs/nodeviews/codeBlockAdvanced.js +29 -4
  5. package/dist/cjs/nodeviews/codeBlockNodeWithToDOMFixed.js +42 -12
  6. package/dist/cjs/nodeviews/extensions/copyButtonDecorations.js +22 -0
  7. package/dist/cjs/ui/syntaxHighlightingTheme.js +5 -2
  8. package/dist/cjs/ui/theme.js +4 -3
  9. package/dist/es2019/nodeviews/codeBlockAdvanced.js +29 -6
  10. package/dist/es2019/nodeviews/codeBlockNodeWithToDOMFixed.js +58 -28
  11. package/dist/es2019/nodeviews/extensions/copyButtonDecorations.js +16 -0
  12. package/dist/es2019/ui/syntaxHighlightingTheme.js +5 -2
  13. package/dist/es2019/ui/theme.js +4 -3
  14. package/dist/esm/nodeviews/codeBlockAdvanced.js +31 -6
  15. package/dist/esm/nodeviews/codeBlockNodeWithToDOMFixed.js +42 -12
  16. package/dist/esm/nodeviews/extensions/copyButtonDecorations.js +16 -0
  17. package/dist/esm/ui/syntaxHighlightingTheme.js +5 -2
  18. package/dist/esm/ui/theme.js +4 -3
  19. package/dist/types/nodeviews/codeBlockAdvanced.d.ts +3 -0
  20. package/dist/types/nodeviews/extensions/copyButtonDecorations.d.ts +1 -0
  21. package/dist/types-ts4.5/nodeviews/codeBlockAdvanced.d.ts +3 -0
  22. package/dist/types-ts4.5/nodeviews/extensions/copyButtonDecorations.d.ts +1 -0
  23. package/package.json +4 -4
  24. package/src/nodeviews/codeBlockAdvanced.ts +30 -2
  25. package/src/nodeviews/codeBlockNodeWithToDOMFixed.ts +75 -30
  26. package/src/nodeviews/extensions/copyButtonDecorations.ts +15 -0
  27. package/src/nodeviews/lazyCodeBlockAdvanced.ts +0 -1
  28. package/src/ui/syntaxHighlightingTheme.ts +8 -1
  29. package/src/ui/theme.ts +2 -1
  30. package/tsconfig.app.json +53 -0
  31. package/tsconfig.dev.json +47 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @atlaskit/editor-plugin-code-block-advanced
2
2
 
3
+ ## 1.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#105726](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/105726)
8
+ [`2eb0f22c4b065`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/2eb0f22c4b065) -
9
+ [ux] Fix toDOM implementation whitespace with 100+ lines of code
10
+ - [#103918](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/103918)
11
+ [`29844093c6ab4`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/29844093c6ab4) -
12
+ Expose new shared state for code block plugin which indicates the current node that the copy text
13
+ button is hovered for. Display highlight decorations for the copy text button in the advanced code
14
+ block plugin.
15
+ - Updated dependencies
16
+
17
+ ## 1.0.1
18
+
19
+ ### Patch Changes
20
+
21
+ - [#102828](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/102828)
22
+ [`e9e0bd7d3c706`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/e9e0bd7d3c706) -
23
+ [ux] Ensure lazy node view matches code block advanced snippet so there is no layout shift.
24
+
3
25
  ## 1.0.0
4
26
 
5
27
  ### Major Changes
@@ -0,0 +1,36 @@
1
+ {
2
+ "extends": "../../../../tsconfig.entry-points.jira.json",
3
+ "compilerOptions": {
4
+ "target": "es5",
5
+ "outDir": "../../../../../tsDist/@atlaskit__editor-plugin-code-block-advanced/app",
6
+ "rootDir": "../",
7
+ "composite": true
8
+ },
9
+ "include": [
10
+ "../src/**/*.ts",
11
+ "../src/**/*.tsx"
12
+ ],
13
+ "exclude": [
14
+ "../src/**/__tests__/*",
15
+ "../src/**/*.test.*",
16
+ "../src/**/test.*",
17
+ "../src/**/examples.*"
18
+ ],
19
+ "references": [
20
+ {
21
+ "path": "../../editor-common/afm-jira/tsconfig.json"
22
+ },
23
+ {
24
+ "path": "../../editor-plugin-code-block/afm-jira/tsconfig.json"
25
+ },
26
+ {
27
+ "path": "../../editor-plugin-editor-disabled/afm-jira/tsconfig.json"
28
+ },
29
+ {
30
+ "path": "../../editor-plugin-selection/afm-jira/tsconfig.json"
31
+ },
32
+ {
33
+ "path": "../../../design-system/tokens/afm-jira/tsconfig.json"
34
+ }
35
+ ]
36
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "extends": "../../../../tsconfig.entry-points.post-office.json",
3
+ "compilerOptions": {
4
+ "target": "es5",
5
+ "outDir": "../../../../../post-office/tsDist/@atlaskit__editor-plugin-code-block-advanced/app",
6
+ "rootDir": "../",
7
+ "composite": true
8
+ },
9
+ "include": [
10
+ "../src/**/*.ts",
11
+ "../src/**/*.tsx"
12
+ ],
13
+ "exclude": [
14
+ "../src/**/__tests__/*",
15
+ "../src/**/*.test.*",
16
+ "../src/**/test.*",
17
+ "../src/**/examples.*"
18
+ ],
19
+ "references": [
20
+ {
21
+ "path": "../../editor-common/afm-post-office/tsconfig.json"
22
+ },
23
+ {
24
+ "path": "../../editor-plugin-code-block/afm-post-office/tsconfig.json"
25
+ },
26
+ {
27
+ "path": "../../editor-plugin-editor-disabled/afm-post-office/tsconfig.json"
28
+ },
29
+ {
30
+ "path": "../../editor-plugin-selection/afm-post-office/tsconfig.json"
31
+ },
32
+ {
33
+ "path": "../../../design-system/tokens/afm-post-office/tsconfig.json"
34
+ }
35
+ ]
36
+ }
@@ -20,6 +20,7 @@ var _theme = require("../ui/theme");
20
20
  var _syncCMWithPM = require("./codemirrorSync/syncCMWithPM");
21
21
  var _updateCMSelection = require("./codemirrorSync/updateCMSelection");
22
22
  var _bidiCharWarning = require("./extensions/bidiCharWarning");
23
+ var _copyButtonDecorations = require("./extensions/copyButtonDecorations");
23
24
  var _keymap = require("./extensions/keymap");
24
25
  var _loader = require("./languages/loader");
25
26
  // Based on: https://prosemirror.net/examples/codemirror/
@@ -28,11 +29,13 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
28
29
  function CodeBlockAdvancedNodeView(node, view, getPos, config) {
29
30
  var _config$api,
30
31
  _this = this,
31
- _config$api2;
32
+ _config$api2,
33
+ _config$api3;
32
34
  (0, _classCallCheck2.default)(this, CodeBlockAdvancedNodeView);
33
35
  (0, _defineProperty2.default)(this, "lineWrappingCompartment", new _state.Compartment());
34
36
  (0, _defineProperty2.default)(this, "languageCompartment", new _state.Compartment());
35
37
  (0, _defineProperty2.default)(this, "readOnlyCompartment", new _state.Compartment());
38
+ (0, _defineProperty2.default)(this, "copyDecoCompartment", new _state.Compartment());
36
39
  (0, _defineProperty2.default)(this, "maybeTryingToReachNodeSelection", false);
37
40
  (0, _defineProperty2.default)(this, "wordWrappingEnabled", false);
38
41
  this.node = node;
@@ -48,6 +51,13 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
48
51
  this.cleanupDisabledState = (_config$api2 = config.api) === null || _config$api2 === void 0 || (_config$api2 = _config$api2.editorDisabled) === null || _config$api2 === void 0 ? void 0 : _config$api2.sharedState.onChange(function () {
49
52
  _this.updateReadonlyState();
50
53
  });
54
+ this.cleanupCopyButtonDecoration = (_config$api3 = config.api) === null || _config$api3 === void 0 || (_config$api3 = _config$api3.codeBlock) === null || _config$api3 === void 0 ? void 0 : _config$api3.sharedState.onChange(function (_ref) {
55
+ var nextSharedState = _ref.nextSharedState,
56
+ prevSharedState = _ref.prevSharedState;
57
+ if ((nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.copyButtonHoverNode) !== (prevSharedState === null || prevSharedState === void 0 ? void 0 : prevSharedState.copyButtonHoverNode)) {
58
+ _this.addCopyButtonDecoration(nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.copyButtonHoverNode);
59
+ }
60
+ });
51
61
  this.languageLoader = new _loader.LanguageLoader(function (lang) {
52
62
  _this.updating = true;
53
63
  _this.cm.dispatch({
@@ -57,13 +67,18 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
57
67
  });
58
68
  this.cm = new _view.EditorView({
59
69
  doc: this.node.textContent,
60
- extensions: [].concat((0, _toConsumableArray2.default)(config.extensions), [this.lineWrappingCompartment.of([]), this.languageCompartment.of([]), (0, _keymap.keymapExtension)({
70
+ extensions: [].concat((0, _toConsumableArray2.default)(config.extensions), [this.lineWrappingCompartment.of([]), this.languageCompartment.of([]), this.copyDecoCompartment.of([]), (0, _keymap.keymapExtension)({
61
71
  view: view,
62
72
  getPos: getPos,
63
73
  getNode: getNode,
64
74
  selectCodeBlockNode: this.selectCodeBlockNode.bind(this),
65
75
  onMaybeNodeSelection: onMaybeNodeSelection
66
- }), _theme.cmTheme, (0, _language.syntaxHighlighting)(_syntaxHighlightingTheme.highlightStyle), (0, _view.lineNumbers)(), _view.EditorView.updateListener.of(function (update) {
76
+ }), _theme.cmTheme, (0, _language.syntaxHighlighting)(_syntaxHighlightingTheme.highlightStyle), (0, _language.bracketMatching)(), (0, _view.lineNumbers)(),
77
+ // Explicitly disable "sticky" positioning on line numbers to match
78
+ // Renderer behaviour
79
+ (0, _view.gutters)({
80
+ fixed: false
81
+ }), _view.EditorView.updateListener.of(function (update) {
67
82
  return _this.forwardUpdate(update);
68
83
  }), this.readOnlyCompartment.of(_view.EditorView.editable.of(this.view.editable)), (0, _autocomplete.closeBrackets)(), _view.EditorView.editorAttributes.of({
69
84
  class: 'code-block'
@@ -81,8 +96,9 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
81
96
  return (0, _createClass2.default)(CodeBlockAdvancedNodeView, [{
82
97
  key: "destroy",
83
98
  value: function destroy() {
84
- var _this$cleanupDisabled;
99
+ var _this$cleanupDisabled, _this$cleanupCopyButt;
85
100
  (_this$cleanupDisabled = this.cleanupDisabledState) === null || _this$cleanupDisabled === void 0 || _this$cleanupDisabled.call(this);
101
+ (_this$cleanupCopyButt = this.cleanupCopyButtonDecoration) === null || _this$cleanupCopyButt === void 0 || _this$cleanupCopyButt.call(this);
86
102
  }
87
103
  }, {
88
104
  key: "forwardUpdate",
@@ -139,6 +155,15 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
139
155
  this.view.dispatch(tr);
140
156
  }
141
157
  }
158
+ }, {
159
+ key: "addCopyButtonDecoration",
160
+ value: function addCopyButtonDecoration(node) {
161
+ this.updating = true;
162
+ this.cm.dispatch({
163
+ effects: [this.copyDecoCompartment.reconfigure(node && node === this.node ? _copyButtonDecorations.copyButtonDecorations : [])]
164
+ });
165
+ this.updating = false;
166
+ }
142
167
  }, {
143
168
  key: "updateWordWrap",
144
169
  value: function updateWordWrap(node) {
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.codeBlockNodeWithFixedToDOM = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  var _adfSchema = require("@atlaskit/adf-schema");
10
+ var _lazyNodeView = require("@atlaskit/editor-common/lazy-node-view");
10
11
  var _styles = require("@atlaskit/editor-common/styles");
11
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; }
12
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; }
@@ -15,30 +16,59 @@ var codeBlockClassNames = {
15
16
  start: _styles.CodeBlockSharedCssClassName.CODEBLOCK_START,
16
17
  end: _styles.CodeBlockSharedCssClassName.CODEBLOCK_END,
17
18
  contentWrapper: _styles.CodeBlockSharedCssClassName.CODEBLOCK_CONTENT_WRAPPER,
18
- contentWrapped: _styles.CodeBlockSharedCssClassName.CODEBLOCK_CONTENT_WRAPPED,
19
- gutter: _styles.CodeBlockSharedCssClassName.CODEBLOCK_LINE_NUMBER_GUTTER,
20
- content: _styles.CodeBlockSharedCssClassName.CODEBLOCK_CONTENT,
21
- lineNumberWidget: _styles.CodeBlockSharedCssClassName.CODEBLOCK_CONTAINER_LINE_NUMBER_WIDGET
19
+ content: _styles.CodeBlockSharedCssClassName.CODEBLOCK_CONTENT
22
20
  };
21
+ var MATCH_NEWLINES = new RegExp('\n', 'gu');
23
22
 
24
- // From: `packages/editor/editor-plugin-code-block/src/nodeviews/code-block.ts`
25
- var _toDOM = function toDOM(node, contentEditable, formattedAriaLabel) {
26
- return ['div', {
27
- class: codeBlockClassNames.container
23
+ // Based on: `packages/editor/editor-plugin-code-block/src/nodeviews/code-block.ts`
24
+ var _toDOM = function toDOM(node, formattedAriaLabel) {
25
+ var totalLineCount = 1;
26
+ node.forEach(function (node) {
27
+ var text = node.text;
28
+ if (text) {
29
+ totalLineCount += (node.text.match(MATCH_NEWLINES) || []).length;
30
+ }
31
+ });
32
+ var maxDigits = totalLineCount.toString().length;
33
+ var content = node.textContent.split('\n').map(function (_, i) {
34
+ return i + 1;
35
+ }).join('\n');
36
+ return ['pre', {
37
+ class: codeBlockClassNames.container,
38
+ style: "--lineNumberGutterWidth:".concat(maxDigits, "ch;"),
39
+ 'data-language': node.attrs.language || ''
28
40
  }, ['div', {
29
41
  class: codeBlockClassNames.start,
30
42
  contenteditable: 'false'
31
43
  }], ['div', {
32
44
  class: codeBlockClassNames.contentWrapper
33
45
  }, ['div', {
34
- class: codeBlockClassNames.gutter,
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: (0, _lazyNodeView.convertToInlineCss)({
49
+ backgroundColor: "var(--ds-background-neutral, #091E420F)",
50
+ position: 'relative',
51
+ width: 'var(--lineNumberGutterWidth, 2rem)',
52
+ padding: "var(--ds-space-100, 8px)",
53
+ flexShrink: 0,
54
+ fontSize: '0.875rem',
55
+ boxSizing: 'content-box'
56
+ }),
35
57
  contenteditable: 'false'
36
- }], ['div', {
58
+ }, ['div', {
59
+ class: 'code-block-gutter-pseudo-element',
60
+ style: (0, _lazyNodeView.convertToInlineCss)({
61
+ textAlign: 'right',
62
+ color: "var(--ds-text-subtlest, #626F86)",
63
+ fontFamily: "var(--ds-font-family-code, ui-monospace, Menlo, \"Segoe UI Mono\", \"Ubuntu Mono\", monospace)",
64
+ whiteSpace: 'pre-wrap'
65
+ }),
66
+ 'data-label': content
67
+ }]], ['div', {
37
68
  class: codeBlockClassNames.content
38
69
  }, ['code', {
39
70
  'data-language': node.attrs.language || '',
40
71
  spellcheck: 'false',
41
- contenteditable: contentEditable ? 'true' : 'false',
42
72
  'data-testid': 'code-block--code',
43
73
  'aria-label': formattedAriaLabel
44
74
  }, 0]]], ['div', {
@@ -49,7 +79,7 @@ var _toDOM = function toDOM(node, contentEditable, formattedAriaLabel) {
49
79
  var codeBlockNodeWithFixedToDOM = exports.codeBlockNodeWithFixedToDOM = function codeBlockNodeWithFixedToDOM() {
50
80
  return _objectSpread(_objectSpread({}, _adfSchema.codeBlock), {}, {
51
81
  toDOM: function toDOM(node) {
52
- return _toDOM(node, false, '');
82
+ return _toDOM(node, '');
53
83
  }
54
84
  });
55
85
  };
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.copyButtonDecorations = void 0;
7
+ var _state = require("@codemirror/state");
8
+ var _view = require("@codemirror/view");
9
+ var copyButtonDecorations = exports.copyButtonDecorations = _view.EditorView.decorations.compute([], function (state) {
10
+ var allTextDecoration = _view.Decoration.mark({
11
+ attributes: {
12
+ class: 'ProseMirror-fake-text-selection'
13
+ }
14
+ });
15
+ // Create a set of decorations for the entire document
16
+ var builder = new _state.RangeSetBuilder();
17
+ for (var i = 0; i < state.doc.lines; i++) {
18
+ builder.add(state.doc.line(i + 1).from, state.doc.line(i + 1).to, allTextDecoration);
19
+ }
20
+ var decorations = builder.finish();
21
+ return decorations;
22
+ });
@@ -46,8 +46,11 @@ var highlightStyle = exports.highlightStyle = _language.HighlightStyle.define([{
46
46
  tag: [_highlight.tags.string, _highlight.tags.deleted],
47
47
  color: "var(--ds-text-accent-green, #216E4E)"
48
48
  }, {
49
- tag: [_highlight.tags.regexp, _highlight.tags.escape, _highlight.tags.special(_highlight.tags.string)],
50
- color: "var(--ds-text, #172B4D)"
49
+ tag: [_highlight.tags.special(_highlight.tags.string)],
50
+ color: "var(--ds-text-accent-green, #216E4E)"
51
+ }, {
52
+ tag: [_highlight.tags.regexp, _highlight.tags.escape],
53
+ color: "var(--ds-text-accent-teal, #206A83)"
51
54
  }, {
52
55
  tag: _highlight.tags.definition(_highlight.tags.variableName),
53
56
  color: "var(--ds-text, #172B4D)"
@@ -11,7 +11,6 @@ var cmTheme = exports.cmTheme = _view.EditorView.theme({
11
11
  padding: '0',
12
12
  marginTop: "var(--ds-space-100, 8px)",
13
13
  marginBottom: "var(--ds-space-100, 8px)",
14
- borderRadius: "var(--ds-border-radius, 4px)",
15
14
  fontSize: '0.875rem',
16
15
  // Custom syntax styling to match existing styling
17
16
  // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
@@ -37,7 +36,8 @@ var cmTheme = exports.cmTheme = _view.EditorView.theme({
37
36
  // Custom syntax styling to match existing styling
38
37
  // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
39
38
  lineHeight: 'unset',
40
- fontFamily: "var(--ds-font-family-code, ui-monospace, Menlo, \"Segoe UI Mono\", \"Ubuntu Mono\", monospace)"
39
+ fontFamily: "var(--ds-font-family-code, ui-monospace, Menlo, \"Segoe UI Mono\", \"Ubuntu Mono\", monospace)",
40
+ borderRadius: "var(--ds-border-radius, 4px)"
41
41
  },
42
42
  '&.cm-focused .cm-cursor': {
43
43
  borderLeftColor: "var(--ds-text, #172B4D)"
@@ -45,7 +45,8 @@ var cmTheme = exports.cmTheme = _view.EditorView.theme({
45
45
  '.cm-gutters': {
46
46
  backgroundColor: "var(--ds-background-neutral, #091E420F)",
47
47
  border: 'none',
48
- padding: "var(--ds-space-100, 8px)"
48
+ padding: "var(--ds-space-100, 8px)",
49
+ color: "var(--ds-text-subtlest, #626F86)"
49
50
  },
50
51
  '.cm-lineNumbers .cm-gutterElement': {
51
52
  paddingLeft: "var(--ds-space-0, 0px)",
@@ -1,8 +1,8 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  import { closeBrackets } from '@codemirror/autocomplete';
3
- import { syntaxHighlighting } from '@codemirror/language';
3
+ import { syntaxHighlighting, bracketMatching } from '@codemirror/language';
4
4
  import { Compartment, EditorSelection } from '@codemirror/state';
5
- import { EditorView as CodeMirror, lineNumbers } from '@codemirror/view';
5
+ import { EditorView as CodeMirror, lineNumbers, gutters } from '@codemirror/view';
6
6
  import { isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
7
7
  import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
8
8
  import { highlightStyle } from '../ui/syntaxHighlightingTheme';
@@ -10,16 +10,18 @@ import { cmTheme } from '../ui/theme';
10
10
  import { syncCMWithPM } from './codemirrorSync/syncCMWithPM';
11
11
  import { updateCMSelection } from './codemirrorSync/updateCMSelection';
12
12
  import { bidiCharWarningExtension } from './extensions/bidiCharWarning';
13
+ import { copyButtonDecorations } from './extensions/copyButtonDecorations';
13
14
  import { keymapExtension } from './extensions/keymap';
14
15
  import { LanguageLoader } from './languages/loader';
15
16
  // Based on: https://prosemirror.net/examples/codemirror/
16
17
  class CodeBlockAdvancedNodeView {
17
18
  // eslint-disable-next-line @typescript-eslint/max-params
18
19
  constructor(node, view, getPos, config) {
19
- var _config$api, _config$api$selection, _config$api2, _config$api2$editorDi;
20
+ var _config$api, _config$api$selection, _config$api2, _config$api2$editorDi, _config$api3, _config$api3$codeBloc;
20
21
  _defineProperty(this, "lineWrappingCompartment", new Compartment());
21
22
  _defineProperty(this, "languageCompartment", new Compartment());
22
23
  _defineProperty(this, "readOnlyCompartment", new Compartment());
24
+ _defineProperty(this, "copyDecoCompartment", new Compartment());
23
25
  _defineProperty(this, "maybeTryingToReachNodeSelection", false);
24
26
  _defineProperty(this, "wordWrappingEnabled", false);
25
27
  this.node = node;
@@ -31,6 +33,14 @@ class CodeBlockAdvancedNodeView {
31
33
  this.cleanupDisabledState = (_config$api2 = config.api) === null || _config$api2 === void 0 ? void 0 : (_config$api2$editorDi = _config$api2.editorDisabled) === null || _config$api2$editorDi === void 0 ? void 0 : _config$api2$editorDi.sharedState.onChange(() => {
32
34
  this.updateReadonlyState();
33
35
  });
36
+ this.cleanupCopyButtonDecoration = (_config$api3 = config.api) === null || _config$api3 === void 0 ? void 0 : (_config$api3$codeBloc = _config$api3.codeBlock) === null || _config$api3$codeBloc === void 0 ? void 0 : _config$api3$codeBloc.sharedState.onChange(({
37
+ nextSharedState,
38
+ prevSharedState
39
+ }) => {
40
+ if ((nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.copyButtonHoverNode) !== (prevSharedState === null || prevSharedState === void 0 ? void 0 : prevSharedState.copyButtonHoverNode)) {
41
+ this.addCopyButtonDecoration(nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.copyButtonHoverNode);
42
+ }
43
+ });
34
44
  this.languageLoader = new LanguageLoader(lang => {
35
45
  this.updating = true;
36
46
  this.cm.dispatch({
@@ -40,13 +50,18 @@ class CodeBlockAdvancedNodeView {
40
50
  });
41
51
  this.cm = new CodeMirror({
42
52
  doc: this.node.textContent,
43
- extensions: [...config.extensions, this.lineWrappingCompartment.of([]), this.languageCompartment.of([]), keymapExtension({
53
+ extensions: [...config.extensions, this.lineWrappingCompartment.of([]), this.languageCompartment.of([]), this.copyDecoCompartment.of([]), keymapExtension({
44
54
  view,
45
55
  getPos,
46
56
  getNode,
47
57
  selectCodeBlockNode: this.selectCodeBlockNode.bind(this),
48
58
  onMaybeNodeSelection
49
- }), cmTheme, syntaxHighlighting(highlightStyle), lineNumbers(), CodeMirror.updateListener.of(update => this.forwardUpdate(update)), this.readOnlyCompartment.of(CodeMirror.editable.of(this.view.editable)), closeBrackets(), CodeMirror.editorAttributes.of({
59
+ }), cmTheme, syntaxHighlighting(highlightStyle), bracketMatching(), lineNumbers(),
60
+ // Explicitly disable "sticky" positioning on line numbers to match
61
+ // Renderer behaviour
62
+ gutters({
63
+ fixed: false
64
+ }), CodeMirror.updateListener.of(update => this.forwardUpdate(update)), this.readOnlyCompartment.of(CodeMirror.editable.of(this.view.editable)), closeBrackets(), CodeMirror.editorAttributes.of({
50
65
  class: 'code-block'
51
66
  }), bidiCharWarningExtension]
52
67
  });
@@ -60,8 +75,9 @@ class CodeBlockAdvancedNodeView {
60
75
  this.updateLanguage();
61
76
  }
62
77
  destroy() {
63
- var _this$cleanupDisabled;
78
+ var _this$cleanupDisabled, _this$cleanupCopyButt;
64
79
  (_this$cleanupDisabled = this.cleanupDisabledState) === null || _this$cleanupDisabled === void 0 ? void 0 : _this$cleanupDisabled.call(this);
80
+ (_this$cleanupCopyButt = this.cleanupCopyButtonDecoration) === null || _this$cleanupCopyButt === void 0 ? void 0 : _this$cleanupCopyButt.call(this);
65
81
  }
66
82
  forwardUpdate(update) {
67
83
  var _this$getPos, _this$getPos2;
@@ -108,6 +124,13 @@ class CodeBlockAdvancedNodeView {
108
124
  this.view.dispatch(tr);
109
125
  }
110
126
  }
127
+ addCopyButtonDecoration(node) {
128
+ this.updating = true;
129
+ this.cm.dispatch({
130
+ effects: [this.copyDecoCompartment.reconfigure(node && node === this.node ? copyButtonDecorations : [])]
131
+ });
132
+ this.updating = false;
133
+ }
111
134
  updateWordWrap(node) {
112
135
  if (this.wordWrappingEnabled !== isCodeBlockWordWrapEnabled(node)) {
113
136
  this.updating = true;
@@ -1,42 +1,72 @@
1
1
  import { codeBlock } from '@atlaskit/adf-schema';
2
+ import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
2
3
  import { CodeBlockSharedCssClassName } from '@atlaskit/editor-common/styles';
3
4
  const codeBlockClassNames = {
4
5
  container: CodeBlockSharedCssClassName.CODEBLOCK_CONTAINER,
5
6
  start: CodeBlockSharedCssClassName.CODEBLOCK_START,
6
7
  end: CodeBlockSharedCssClassName.CODEBLOCK_END,
7
8
  contentWrapper: CodeBlockSharedCssClassName.CODEBLOCK_CONTENT_WRAPPER,
8
- contentWrapped: CodeBlockSharedCssClassName.CODEBLOCK_CONTENT_WRAPPED,
9
- gutter: CodeBlockSharedCssClassName.CODEBLOCK_LINE_NUMBER_GUTTER,
10
- content: CodeBlockSharedCssClassName.CODEBLOCK_CONTENT,
11
- lineNumberWidget: CodeBlockSharedCssClassName.CODEBLOCK_CONTAINER_LINE_NUMBER_WIDGET
9
+ content: CodeBlockSharedCssClassName.CODEBLOCK_CONTENT
12
10
  };
11
+ const MATCH_NEWLINES = new RegExp('\n', 'gu');
13
12
 
14
- // From: `packages/editor/editor-plugin-code-block/src/nodeviews/code-block.ts`
15
- const toDOM = (node, contentEditable, formattedAriaLabel) => ['div', {
16
- class: codeBlockClassNames.container
17
- }, ['div', {
18
- class: codeBlockClassNames.start,
19
- contenteditable: 'false'
20
- }], ['div', {
21
- class: codeBlockClassNames.contentWrapper
22
- }, ['div', {
23
- class: codeBlockClassNames.gutter,
24
- contenteditable: 'false'
25
- }], ['div', {
26
- class: codeBlockClassNames.content
27
- }, ['code', {
28
- 'data-language': node.attrs.language || '',
29
- spellcheck: 'false',
30
- contenteditable: contentEditable ? 'true' : 'false',
31
- 'data-testid': 'code-block--code',
32
- 'aria-label': formattedAriaLabel
33
- }, 0]]], ['div', {
34
- class: codeBlockClassNames.end,
35
- contenteditable: 'false'
36
- }]];
13
+ // Based on: `packages/editor/editor-plugin-code-block/src/nodeviews/code-block.ts`
14
+ const toDOM = (node, formattedAriaLabel) => {
15
+ let totalLineCount = 1;
16
+ node.forEach(node => {
17
+ const text = node.text;
18
+ if (text) {
19
+ totalLineCount += (node.text.match(MATCH_NEWLINES) || []).length;
20
+ }
21
+ });
22
+ const maxDigits = totalLineCount.toString().length;
23
+ const content = node.textContent.split('\n').map((_, i) => i + 1).join('\n');
24
+ return ['pre', {
25
+ class: codeBlockClassNames.container,
26
+ style: `--lineNumberGutterWidth:${maxDigits}ch;`,
27
+ 'data-language': node.attrs.language || ''
28
+ }, ['div', {
29
+ class: codeBlockClassNames.start,
30
+ contenteditable: 'false'
31
+ }], ['div', {
32
+ class: codeBlockClassNames.contentWrapper
33
+ }, ['div', {
34
+ // Based on packages/editor/editor-common/src/styles/shared/code-block.ts
35
+ // But we can't reuse that class as it adds a ::before that intefers with this approach
36
+ style: convertToInlineCss({
37
+ backgroundColor: "var(--ds-background-neutral, #091E420F)",
38
+ position: 'relative',
39
+ width: 'var(--lineNumberGutterWidth, 2rem)',
40
+ padding: "var(--ds-space-100, 8px)",
41
+ flexShrink: 0,
42
+ fontSize: '0.875rem',
43
+ boxSizing: 'content-box'
44
+ }),
45
+ contenteditable: 'false'
46
+ }, ['div', {
47
+ class: 'code-block-gutter-pseudo-element',
48
+ style: convertToInlineCss({
49
+ textAlign: 'right',
50
+ color: "var(--ds-text-subtlest, #626F86)",
51
+ fontFamily: "var(--ds-font-family-code, ui-monospace, Menlo, \"Segoe UI Mono\", \"Ubuntu Mono\", monospace)",
52
+ whiteSpace: 'pre-wrap'
53
+ }),
54
+ 'data-label': content
55
+ }]], ['div', {
56
+ class: codeBlockClassNames.content
57
+ }, ['code', {
58
+ 'data-language': node.attrs.language || '',
59
+ spellcheck: 'false',
60
+ 'data-testid': 'code-block--code',
61
+ 'aria-label': formattedAriaLabel
62
+ }, 0]]], ['div', {
63
+ class: codeBlockClassNames.end,
64
+ contenteditable: 'false'
65
+ }]];
66
+ };
37
67
  export const codeBlockNodeWithFixedToDOM = () => {
38
68
  return {
39
69
  ...codeBlock,
40
- toDOM: node => toDOM(node, false, '')
70
+ toDOM: node => toDOM(node, '')
41
71
  };
42
72
  };
@@ -0,0 +1,16 @@
1
+ import { RangeSetBuilder } from '@codemirror/state';
2
+ import { EditorView as CodeMirror, Decoration } from '@codemirror/view';
3
+ export const copyButtonDecorations = CodeMirror.decorations.compute([], state => {
4
+ const allTextDecoration = Decoration.mark({
5
+ attributes: {
6
+ class: 'ProseMirror-fake-text-selection'
7
+ }
8
+ });
9
+ // Create a set of decorations for the entire document
10
+ const builder = new RangeSetBuilder();
11
+ for (let i = 0; i < state.doc.lines; i++) {
12
+ builder.add(state.doc.line(i + 1).from, state.doc.line(i + 1).to, allTextDecoration);
13
+ }
14
+ const decorations = builder.finish();
15
+ return decorations;
16
+ });
@@ -40,8 +40,11 @@ export const highlightStyle = HighlightStyle.define([{
40
40
  tag: [tags.string, tags.deleted],
41
41
  color: "var(--ds-text-accent-green, #216E4E)"
42
42
  }, {
43
- tag: [tags.regexp, tags.escape, tags.special(tags.string)],
44
- color: "var(--ds-text, #172B4D)"
43
+ tag: [tags.special(tags.string)],
44
+ color: "var(--ds-text-accent-green, #216E4E)"
45
+ }, {
46
+ tag: [tags.regexp, tags.escape],
47
+ color: "var(--ds-text-accent-teal, #206A83)"
45
48
  }, {
46
49
  tag: tags.definition(tags.variableName),
47
50
  color: "var(--ds-text, #172B4D)"
@@ -5,7 +5,6 @@ export const cmTheme = CodeMirror.theme({
5
5
  padding: '0',
6
6
  marginTop: "var(--ds-space-100, 8px)",
7
7
  marginBottom: "var(--ds-space-100, 8px)",
8
- borderRadius: "var(--ds-border-radius, 4px)",
9
8
  fontSize: '0.875rem',
10
9
  // Custom syntax styling to match existing styling
11
10
  // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
@@ -31,7 +30,8 @@ export const cmTheme = CodeMirror.theme({
31
30
  // Custom syntax styling to match existing styling
32
31
  // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
33
32
  lineHeight: 'unset',
34
- fontFamily: "var(--ds-font-family-code, ui-monospace, Menlo, \"Segoe UI Mono\", \"Ubuntu Mono\", monospace)"
33
+ fontFamily: "var(--ds-font-family-code, ui-monospace, Menlo, \"Segoe UI Mono\", \"Ubuntu Mono\", monospace)",
34
+ borderRadius: "var(--ds-border-radius, 4px)"
35
35
  },
36
36
  '&.cm-focused .cm-cursor': {
37
37
  borderLeftColor: "var(--ds-text, #172B4D)"
@@ -39,7 +39,8 @@ export const cmTheme = CodeMirror.theme({
39
39
  '.cm-gutters': {
40
40
  backgroundColor: "var(--ds-background-neutral, #091E420F)",
41
41
  border: 'none',
42
- padding: "var(--ds-space-100, 8px)"
42
+ padding: "var(--ds-space-100, 8px)",
43
+ color: "var(--ds-text-subtlest, #626F86)"
43
44
  },
44
45
  '.cm-lineNumbers .cm-gutterElement': {
45
46
  paddingLeft: "var(--ds-space-0, 0px)",