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

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 (110) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE.md +11 -0
  3. package/README.md +1 -0
  4. package/afm-cc/tsconfig.json +36 -0
  5. package/build/tsconfig.json +17 -0
  6. package/dist/cjs/codeBlockAdvancedPlugin.js +33 -0
  7. package/dist/cjs/codeBlockAdvancedPluginType.js +5 -0
  8. package/dist/cjs/index.js +12 -0
  9. package/dist/cjs/nodeviews/codeBlockAdvanced.js +212 -0
  10. package/dist/cjs/nodeviews/codeBlockNodeWithToDOMFixed.js +55 -0
  11. package/dist/cjs/nodeviews/codemirrorSync/syncCMWithPM.js +38 -0
  12. package/dist/cjs/nodeviews/codemirrorSync/updateCMSelection.js +36 -0
  13. package/dist/cjs/nodeviews/extensions/bidiCharWarning.js +83 -0
  14. package/dist/cjs/nodeviews/extensions/keymap/backspace.js +33 -0
  15. package/dist/cjs/nodeviews/extensions/keymap/index.js +129 -0
  16. package/dist/cjs/nodeviews/extensions/keymap/maybeEscape.js +63 -0
  17. package/dist/cjs/nodeviews/languages/languageMap.js +100 -0
  18. package/dist/cjs/nodeviews/languages/loader.js +50 -0
  19. package/dist/cjs/nodeviews/lazyCodeBlockAdvanced.js +29 -0
  20. package/dist/cjs/pm-plugins/main.js +17 -0
  21. package/dist/cjs/ui/syntaxHighlightingTheme.js +76 -0
  22. package/dist/cjs/ui/theme.js +55 -0
  23. package/dist/es2019/codeBlockAdvancedPlugin.js +26 -0
  24. package/dist/es2019/codeBlockAdvancedPluginType.js +1 -0
  25. package/dist/es2019/index.js +4 -0
  26. package/dist/es2019/nodeviews/codeBlockAdvanced.js +170 -0
  27. package/dist/es2019/nodeviews/codeBlockNodeWithToDOMFixed.js +42 -0
  28. package/dist/es2019/nodeviews/codemirrorSync/syncCMWithPM.js +35 -0
  29. package/dist/es2019/nodeviews/codemirrorSync/updateCMSelection.js +30 -0
  30. package/dist/es2019/nodeviews/extensions/bidiCharWarning.js +53 -0
  31. package/dist/es2019/nodeviews/extensions/keymap/backspace.js +28 -0
  32. package/dist/es2019/nodeviews/extensions/keymap/index.js +107 -0
  33. package/dist/es2019/nodeviews/extensions/keymap/maybeEscape.js +57 -0
  34. package/dist/es2019/nodeviews/languages/languageMap.js +82 -0
  35. package/dist/es2019/nodeviews/languages/loader.js +37 -0
  36. package/dist/es2019/nodeviews/lazyCodeBlockAdvanced.js +18 -0
  37. package/dist/es2019/pm-plugins/main.js +11 -0
  38. package/dist/es2019/ui/syntaxHighlightingTheme.js +70 -0
  39. package/dist/es2019/ui/theme.js +49 -0
  40. package/dist/esm/codeBlockAdvancedPlugin.js +27 -0
  41. package/dist/esm/codeBlockAdvancedPluginType.js +1 -0
  42. package/dist/esm/index.js +4 -0
  43. package/dist/esm/nodeviews/codeBlockAdvanced.js +205 -0
  44. package/dist/esm/nodeviews/codeBlockNodeWithToDOMFixed.js +48 -0
  45. package/dist/esm/nodeviews/codemirrorSync/syncCMWithPM.js +32 -0
  46. package/dist/esm/nodeviews/codemirrorSync/updateCMSelection.js +30 -0
  47. package/dist/esm/nodeviews/extensions/bidiCharWarning.js +77 -0
  48. package/dist/esm/nodeviews/extensions/keymap/backspace.js +27 -0
  49. package/dist/esm/nodeviews/extensions/keymap/index.js +122 -0
  50. package/dist/esm/nodeviews/extensions/keymap/maybeEscape.js +56 -0
  51. package/dist/esm/nodeviews/languages/languageMap.js +86 -0
  52. package/dist/esm/nodeviews/languages/loader.js +44 -0
  53. package/dist/esm/nodeviews/lazyCodeBlockAdvanced.js +17 -0
  54. package/dist/esm/pm-plugins/main.js +11 -0
  55. package/dist/esm/ui/syntaxHighlightingTheme.js +70 -0
  56. package/dist/esm/ui/theme.js +49 -0
  57. package/dist/types/codeBlockAdvancedPlugin.d.ts +2 -0
  58. package/dist/types/codeBlockAdvancedPluginType.d.ts +11 -0
  59. package/dist/types/index.d.ts +2 -0
  60. package/dist/types/nodeviews/codeBlockAdvanced.d.ts +38 -0
  61. package/dist/types/nodeviews/codeBlockNodeWithToDOMFixed.d.ts +2 -0
  62. package/dist/types/nodeviews/codemirrorSync/syncCMWithPM.d.ts +17 -0
  63. package/dist/types/nodeviews/codemirrorSync/updateCMSelection.d.ts +11 -0
  64. package/dist/types/nodeviews/extensions/bidiCharWarning.d.ts +8 -0
  65. package/dist/types/nodeviews/extensions/keymap/backspace.d.ts +12 -0
  66. package/dist/types/nodeviews/extensions/keymap/index.d.ts +14 -0
  67. package/dist/types/nodeviews/extensions/keymap/maybeEscape.d.ts +17 -0
  68. package/dist/types/nodeviews/languages/languageMap.d.ts +5 -0
  69. package/dist/types/nodeviews/languages/loader.d.ts +11 -0
  70. package/dist/types/nodeviews/lazyCodeBlockAdvanced.d.ts +9 -0
  71. package/dist/types/pm-plugins/main.d.ts +10 -0
  72. package/dist/types/ui/syntaxHighlightingTheme.d.ts +2 -0
  73. package/dist/types/ui/theme.d.ts +1 -0
  74. package/dist/types-ts4.5/codeBlockAdvancedPlugin.d.ts +2 -0
  75. package/dist/types-ts4.5/codeBlockAdvancedPluginType.d.ts +15 -0
  76. package/dist/types-ts4.5/index.d.ts +2 -0
  77. package/dist/types-ts4.5/nodeviews/codeBlockAdvanced.d.ts +38 -0
  78. package/dist/types-ts4.5/nodeviews/codeBlockNodeWithToDOMFixed.d.ts +2 -0
  79. package/dist/types-ts4.5/nodeviews/codemirrorSync/syncCMWithPM.d.ts +17 -0
  80. package/dist/types-ts4.5/nodeviews/codemirrorSync/updateCMSelection.d.ts +11 -0
  81. package/dist/types-ts4.5/nodeviews/extensions/bidiCharWarning.d.ts +8 -0
  82. package/dist/types-ts4.5/nodeviews/extensions/keymap/backspace.d.ts +12 -0
  83. package/dist/types-ts4.5/nodeviews/extensions/keymap/index.d.ts +14 -0
  84. package/dist/types-ts4.5/nodeviews/extensions/keymap/maybeEscape.d.ts +17 -0
  85. package/dist/types-ts4.5/nodeviews/languages/languageMap.d.ts +5 -0
  86. package/dist/types-ts4.5/nodeviews/languages/loader.d.ts +12 -0
  87. package/dist/types-ts4.5/nodeviews/lazyCodeBlockAdvanced.d.ts +9 -0
  88. package/dist/types-ts4.5/pm-plugins/main.d.ts +10 -0
  89. package/dist/types-ts4.5/ui/syntaxHighlightingTheme.d.ts +2 -0
  90. package/dist/types-ts4.5/ui/theme.d.ts +1 -0
  91. package/docs/0-intro.tsx +56 -0
  92. package/package.json +96 -0
  93. package/src/codeBlockAdvancedPlugin.tsx +25 -0
  94. package/src/codeBlockAdvancedPluginType.ts +18 -0
  95. package/src/index.ts +5 -0
  96. package/src/nodeviews/codeBlockAdvanced.ts +223 -0
  97. package/src/nodeviews/codeBlockNodeWithToDOMFixed.ts +59 -0
  98. package/src/nodeviews/codemirrorSync/syncCMWithPM.ts +40 -0
  99. package/src/nodeviews/codemirrorSync/updateCMSelection.ts +40 -0
  100. package/src/nodeviews/extensions/bidiCharWarning.ts +72 -0
  101. package/src/nodeviews/extensions/keymap/backspace.ts +47 -0
  102. package/src/nodeviews/extensions/keymap/index.ts +118 -0
  103. package/src/nodeviews/extensions/keymap/maybeEscape.ts +69 -0
  104. package/src/nodeviews/languages/languageMap.ts +91 -0
  105. package/src/nodeviews/languages/loader.ts +44 -0
  106. package/src/nodeviews/lazyCodeBlockAdvanced.ts +32 -0
  107. package/src/pm-plugins/main.ts +22 -0
  108. package/src/ui/syntaxHighlightingTheme.ts +50 -0
  109. package/src/ui/theme.ts +52 -0
  110. package/tsconfig.json +10 -0
@@ -0,0 +1,15 @@
1
+ import type { Extension } from '@codemirror/state';
2
+ import type { NextEditorPlugin, OptionalPlugin } from '@atlaskit/editor-common/types';
3
+ import type { CodeBlockPlugin } from '@atlaskit/editor-plugin-code-block';
4
+ import type { EditorDisabledPlugin } from '@atlaskit/editor-plugin-editor-disabled';
5
+ import type { SelectionPlugin } from '@atlaskit/editor-plugin-selection';
6
+ export type CodeBlockAdvancedPlugin = NextEditorPlugin<'codeBlockAdvanced', {
7
+ dependencies: [
8
+ CodeBlockPlugin,
9
+ SelectionPlugin,
10
+ OptionalPlugin<EditorDisabledPlugin>
11
+ ];
12
+ pluginConfiguration: {
13
+ extensions?: Extension[];
14
+ } | undefined;
15
+ }>;
@@ -0,0 +1,2 @@
1
+ export { codeBlockAdvancedPlugin } from './codeBlockAdvancedPlugin';
2
+ export type { CodeBlockAdvancedPlugin } from './codeBlockAdvancedPluginType';
@@ -0,0 +1,38 @@
1
+ import { Extension } from '@codemirror/state';
2
+ import { ViewUpdate } from '@codemirror/view';
3
+ import type { getPosHandler, getPosHandlerNode, ExtractInjectionAPI } from '@atlaskit/editor-common/types';
4
+ import { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
5
+ import type { EditorView, NodeView } from '@atlaskit/editor-prosemirror/view';
6
+ import type { CodeBlockAdvancedPlugin } from '../codeBlockAdvancedPluginType';
7
+ interface ConfigProps {
8
+ api: ExtractInjectionAPI<CodeBlockAdvancedPlugin> | undefined;
9
+ extensions: Extension[];
10
+ }
11
+ declare class CodeBlockAdvancedNodeView implements NodeView {
12
+ dom: Node;
13
+ private updating;
14
+ private view;
15
+ private lineWrappingCompartment;
16
+ private languageCompartment;
17
+ private readOnlyCompartment;
18
+ private node;
19
+ private getPos;
20
+ private cm;
21
+ private selectionAPI;
22
+ private maybeTryingToReachNodeSelection;
23
+ private cleanupDisabledState;
24
+ private languageLoader;
25
+ constructor(node: PMNode, view: EditorView, getPos: getPosHandlerNode, config: ConfigProps);
26
+ destroy(): void;
27
+ forwardUpdate(update: ViewUpdate): void;
28
+ setSelection(anchor: number, head: number): void;
29
+ private updateReadonlyState;
30
+ private updateLanguage;
31
+ private selectCodeBlockNode;
32
+ private wordWrappingEnabled;
33
+ private updateWordWrap;
34
+ update(node: PMNode): boolean;
35
+ stopEvent(e: Event): boolean;
36
+ }
37
+ export declare const getCodeBlockAdvancedNodeView: (props: ConfigProps) => (node: PMNode, view: EditorView, getPos: getPosHandler) => CodeBlockAdvancedNodeView;
38
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { NodeSpec } from '@atlaskit/editor-prosemirror/model';
2
+ export declare const codeBlockNodeWithFixedToDOM: () => NodeSpec;
@@ -0,0 +1,17 @@
1
+ import { ViewUpdate } from '@codemirror/view';
2
+ import { EditorView } from '@atlaskit/editor-prosemirror/view';
3
+ interface Props {
4
+ view: EditorView;
5
+ update: ViewUpdate;
6
+ offset: number;
7
+ }
8
+ /**
9
+ *
10
+ * Synchronises the CodeMirror update changes with the Prosemirror editor
11
+ *
12
+ * @param props.view EditorView - Prosemirror EditorView
13
+ * @param props.update ViewUpdate - CodeMirror ViewUpdate
14
+ * @param props.offset number - position where the code block starts in prosemirror
15
+ */
16
+ export declare const syncCMWithPM: ({ view, update, offset }: Props) => void;
17
+ export {};
@@ -0,0 +1,11 @@
1
+ import { TransactionSpec as CMTransactionSpec } from '@codemirror/state';
2
+ /**
3
+ *
4
+ * Compares the updated text with the current to determine the transaction to fire
5
+ * in the CodeMirror editor.
6
+ *
7
+ * @param curText string - the current CodeMirror text
8
+ * @param newText string - the new CodeMirror text
9
+ * @param updateCallback Callback to process the CodeMirror transaction
10
+ */
11
+ export declare const updateCMSelection: (curText: string, newText: string, updateCallback: (value: CMTransactionSpec) => void) => void;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Code based on warning from @atlaskit/code
3
+ */
4
+ import { ViewPlugin, ViewUpdate, DecorationSet } from '@codemirror/view';
5
+ export declare const bidiCharWarningExtension: ViewPlugin<{
6
+ placeholders: DecorationSet;
7
+ update(update: ViewUpdate): void;
8
+ }>;
@@ -0,0 +1,12 @@
1
+ import { EditorView as CodeMirror } from '@codemirror/view';
2
+ import type { getPosHandlerNode } from '@atlaskit/editor-common/types';
3
+ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
4
+ import { EditorView } from '@atlaskit/editor-prosemirror/view';
5
+ interface BackspaceProps {
6
+ view: EditorView;
7
+ cm: CodeMirror;
8
+ getPos: getPosHandlerNode;
9
+ getNode: () => PMNode;
10
+ }
11
+ export declare const backspaceKeymap: ({ cm, view, getPos, getNode }: BackspaceProps) => boolean;
12
+ export {};
@@ -0,0 +1,14 @@
1
+ import { Extension } from '@codemirror/state';
2
+ import { RelativeSelectionPos } from '@atlaskit/editor-common/selection';
3
+ import type { getPosHandlerNode } from '@atlaskit/editor-common/types';
4
+ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
5
+ import { EditorView } from '@atlaskit/editor-prosemirror/view';
6
+ interface KeymapProps {
7
+ view: EditorView;
8
+ getNode: () => PMNode;
9
+ getPos: getPosHandlerNode;
10
+ selectCodeBlockNode: (relativeSelectionPos: RelativeSelectionPos | undefined) => void;
11
+ onMaybeNodeSelection: () => void;
12
+ }
13
+ export declare const keymapExtension: ({ view, getNode, getPos, selectCodeBlockNode, onMaybeNodeSelection, }: KeymapProps) => Extension;
14
+ export {};
@@ -0,0 +1,17 @@
1
+ import { EditorView as CodeMirror } from '@codemirror/view';
2
+ import { RelativeSelectionPos } from '@atlaskit/editor-common/selection';
3
+ import type { getPosHandlerNode } from '@atlaskit/editor-common/types';
4
+ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
5
+ import { EditorView } from '@atlaskit/editor-prosemirror/view';
6
+ interface MaybeEscapeProps {
7
+ unit: 'line' | 'char';
8
+ dir: -1 | 1;
9
+ view: EditorView;
10
+ cm: CodeMirror;
11
+ getPos: getPosHandlerNode;
12
+ getNode: () => PMNode;
13
+ onMaybeNodeSelection: () => void;
14
+ selectCodeBlockNode: (relativeSelectionPos: RelativeSelectionPos | undefined) => void;
15
+ }
16
+ export declare const maybeEscapeKeymap: ({ unit, dir, view, cm, getPos, getNode, onMaybeNodeSelection, selectCodeBlockNode, }: MaybeEscapeProps) => boolean;
17
+ export {};
@@ -0,0 +1,5 @@
1
+ import { LanguageDescription } from '@codemirror/language';
2
+ import type { LanguageAlias } from '@atlaskit/code';
3
+ type LanguageAliasValue = LanguageAlias[0];
4
+ export declare const mapLanguageToCodeMirror: (language: LanguageAliasValue) => LanguageDescription | undefined;
5
+ export {};
@@ -0,0 +1,12 @@
1
+ import { LanguageSupport } from '@codemirror/language';
2
+ /**
3
+ * Manages loading the languages (for syntax highlighting, etc.)
4
+ * from CodeMirror and updating the language in the CodeMirror view
5
+ */
6
+ export declare class LanguageLoader {
7
+ private updateLanguageCompartment;
8
+ private languageName;
9
+ constructor(updateLanguageCompartment: (value: LanguageSupport | [
10
+ ]) => void);
11
+ updateLanguage(languageName: string): void;
12
+ }
@@ -0,0 +1,9 @@
1
+ import { Extension } from '@codemirror/state';
2
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
+ import type { CodeBlockAdvancedPlugin } from '../codeBlockAdvancedPluginType';
4
+ interface Props {
5
+ api: ExtractInjectionAPI<CodeBlockAdvancedPlugin> | undefined;
6
+ extensions: Extension[];
7
+ }
8
+ export declare const lazyCodeBlockView: (props: Props) => import("@atlaskit/editor-common/lazy-node-view").NodeViewConstructor;
9
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { Extension } from '@codemirror/state';
2
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
4
+ import type { CodeBlockAdvancedPlugin } from '../codeBlockAdvancedPluginType';
5
+ interface Props {
6
+ api: ExtractInjectionAPI<CodeBlockAdvancedPlugin> | undefined;
7
+ extensions: Extension[];
8
+ }
9
+ export declare const createPlugin: (props: Props) => SafePlugin<any>;
10
+ export {};
@@ -0,0 +1,2 @@
1
+ import { HighlightStyle } from '@codemirror/language';
2
+ export declare const highlightStyle: HighlightStyle;
@@ -0,0 +1 @@
1
+ export declare const cmTheme: import("@codemirror/state").Extension;
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+
3
+ import { AtlassianInternalWarning, code, md } from '@atlaskit/docs';
4
+ // eslint-disable-next-line @atlassian/tangerine/import/entry-points
5
+ import { createEditorUseOnlyNotice } from '@atlaskit/editor-common/doc-utils';
6
+ import { token } from '@atlaskit/tokens';
7
+
8
+ export default md`
9
+
10
+ ${createEditorUseOnlyNotice('Editor Plugin Code Block Advanced', [
11
+ { name: 'Editor Core', link: '/packages/editor/editor-core' },
12
+ ])}
13
+
14
+
15
+ ${
16
+ (
17
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
18
+ <div style={{ marginTop: token('space.100', '8px') }}>
19
+ <AtlassianInternalWarning />
20
+ </div>
21
+ )
22
+ }
23
+
24
+ This package includes the code block advanced plugin used by \`@atlaskit/editor-core\`.
25
+
26
+ This can be used to extend \`@atlaskit/editor-plugin-code-block\` by using a CodeMirror editor for
27
+ the nodeview to use rich functionality. Extensions can be injected via its configuration.
28
+
29
+ ## Usage
30
+ ---
31
+
32
+ The \`dependencies\`, \`configuration\`, \`state\`, \`actions\`, and \`commands\` of the plugin are defined
33
+ below:
34
+
35
+ ${code`
36
+ type CodeBlockAdvancedPlugin = NextEditorPlugin<
37
+ 'codeBlockAdvanced',
38
+ {
39
+ dependencies: [CodeBlockPlugin];
40
+ pluginConfiguration:
41
+ | {
42
+ extensions?: Extension[];
43
+ }
44
+ | undefined;
45
+ }
46
+ >;
47
+ `}
48
+
49
+
50
+ ## Support
51
+ ---
52
+ For internal Atlassian, visit the slack channel [#help-editor](https://atlassian.slack.com/archives/CFG3PSQ9E) for support or visit [go/editor-help](https://go/editor-help) to submit a bug.
53
+ ## License
54
+ ---
55
+ Please see [Atlassian Frontend - License](https://hello.atlassian.net/wiki/spaces/AF/pages/2589099144/Documentation#License) for more licensing information.
56
+ `;
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "@atlaskit/editor-plugin-code-block-advanced",
3
+ "version": "1.0.0",
4
+ "description": "CodeBlockAdvanced plugin for @atlaskit/editor-core",
5
+ "author": "Atlassian Pty Ltd",
6
+ "license": "Apache-2.0",
7
+ "publishConfig": {
8
+ "registry": "https://registry.npmjs.org/"
9
+ },
10
+ "atlassian": {
11
+ "team": "Editor: Lego",
12
+ "releaseModel": "continuous",
13
+ "singleton": true,
14
+ "runReact18": true
15
+ },
16
+ "repository": "https://bitbucket.org/atlassian/atlassian-frontend-mirror",
17
+ "main": "dist/cjs/index.js",
18
+ "module": "dist/esm/index.js",
19
+ "module:es2019": "dist/es2019/index.js",
20
+ "types": "dist/types/index.d.ts",
21
+ "typesVersions": {
22
+ ">=4.5 <4.9": {
23
+ "*": [
24
+ "dist/types-ts4.5/*",
25
+ "dist/types-ts4.5/index.d.ts"
26
+ ]
27
+ }
28
+ },
29
+ "sideEffects": false,
30
+ "atlaskit:src": "src/index.ts",
31
+ "af:exports": {
32
+ ".": "./src/index.ts"
33
+ },
34
+ "dependencies": {
35
+ "@atlaskit/adf-schema": "^46.1.0",
36
+ "@atlaskit/editor-common": "^99.1.0",
37
+ "@atlaskit/editor-plugin-code-block": "^3.5.0",
38
+ "@atlaskit/editor-plugin-editor-disabled": "^1.3.0",
39
+ "@atlaskit/editor-plugin-selection": "^1.6.0",
40
+ "@atlaskit/editor-prosemirror": "6.2.1",
41
+ "@atlaskit/tokens": "^3.0.0",
42
+ "@babel/runtime": "^7.0.0",
43
+ "@codemirror/autocomplete": "6.18.4",
44
+ "@codemirror/commands": "6.7.1",
45
+ "@codemirror/language": "6.10.8",
46
+ "@codemirror/language-data": "6.5.1",
47
+ "@codemirror/state": "6.5.1",
48
+ "@codemirror/view": "6.36.2",
49
+ "@lezer/highlight": "1.2.1",
50
+ "cm6-graphql": "0.2.0",
51
+ "codemirror-lang-elixir": "4.0.0"
52
+ },
53
+ "peerDependencies": {
54
+ "react": "^16.8.0 || ^17.0.0 || ~18.2.0"
55
+ },
56
+ "devDependencies": {
57
+ "@atlaskit/code": "^15.6.0",
58
+ "typescript": "~5.4.2"
59
+ },
60
+ "techstack": {
61
+ "@atlassian/frontend": {
62
+ "code-structure": [
63
+ "editor-plugin"
64
+ ],
65
+ "import-structure": [
66
+ "atlassian-conventions"
67
+ ],
68
+ "circular-dependencies": [
69
+ "file-and-folder-level"
70
+ ]
71
+ },
72
+ "@repo/internal": {
73
+ "dom-events": "use-bind-event-listener",
74
+ "analytics": [
75
+ "analytics-next"
76
+ ],
77
+ "design-tokens": [
78
+ "color"
79
+ ],
80
+ "theming": [
81
+ "react-context"
82
+ ],
83
+ "ui-components": [
84
+ "lite-mode"
85
+ ],
86
+ "deprecation": "no-deprecated-imports",
87
+ "styling": [
88
+ "emotion",
89
+ "emotion"
90
+ ],
91
+ "imports": [
92
+ "import-no-extraneous-disable-for-examples-and-docs"
93
+ ]
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,25 @@
1
+ import type { CodeBlockAdvancedPlugin } from './codeBlockAdvancedPluginType';
2
+ import { codeBlockNodeWithFixedToDOM } from './nodeviews/codeBlockNodeWithToDOMFixed';
3
+ import { createPlugin } from './pm-plugins/main';
4
+
5
+ export const codeBlockAdvancedPlugin: CodeBlockAdvancedPlugin = ({ api, config }) => ({
6
+ name: 'codeBlockAdvanced',
7
+
8
+ nodes() {
9
+ return [
10
+ {
11
+ name: 'codeBlock',
12
+ node: codeBlockNodeWithFixedToDOM(),
13
+ },
14
+ ];
15
+ },
16
+
17
+ pmPlugins() {
18
+ return [
19
+ {
20
+ name: 'codeBlockAdvancedPlugin',
21
+ plugin: () => createPlugin({ api, extensions: config?.extensions ?? [] }),
22
+ },
23
+ ];
24
+ },
25
+ });
@@ -0,0 +1,18 @@
1
+ import type { Extension } from '@codemirror/state';
2
+
3
+ import type { NextEditorPlugin, OptionalPlugin } from '@atlaskit/editor-common/types';
4
+ import type { CodeBlockPlugin } from '@atlaskit/editor-plugin-code-block';
5
+ import type { EditorDisabledPlugin } from '@atlaskit/editor-plugin-editor-disabled';
6
+ import type { SelectionPlugin } from '@atlaskit/editor-plugin-selection';
7
+
8
+ export type CodeBlockAdvancedPlugin = NextEditorPlugin<
9
+ 'codeBlockAdvanced',
10
+ {
11
+ dependencies: [CodeBlockPlugin, SelectionPlugin, OptionalPlugin<EditorDisabledPlugin>];
12
+ pluginConfiguration:
13
+ | {
14
+ extensions?: Extension[];
15
+ }
16
+ | undefined;
17
+ }
18
+ >;
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ /* eslint-disable @atlaskit/editor/no-re-export */
2
+ // Entry file in package.json
3
+
4
+ export { codeBlockAdvancedPlugin } from './codeBlockAdvancedPlugin';
5
+ export type { CodeBlockAdvancedPlugin } from './codeBlockAdvancedPluginType';
@@ -0,0 +1,223 @@
1
+ import { closeBrackets } from '@codemirror/autocomplete';
2
+ import { syntaxHighlighting } from '@codemirror/language';
3
+ import { Compartment, Extension, EditorSelection } from '@codemirror/state';
4
+ import { EditorView as CodeMirror, lineNumbers, ViewUpdate } from '@codemirror/view';
5
+
6
+ import { isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
7
+ import { RelativeSelectionPos } from '@atlaskit/editor-common/selection';
8
+ import type {
9
+ getPosHandler,
10
+ getPosHandlerNode,
11
+ ExtractInjectionAPI,
12
+ } from '@atlaskit/editor-common/types';
13
+ import { EditorSelectionAPI } from '@atlaskit/editor-plugin-selection';
14
+ import { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
15
+ import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
16
+ import type { EditorView, NodeView } from '@atlaskit/editor-prosemirror/view';
17
+
18
+ import type { CodeBlockAdvancedPlugin } from '../codeBlockAdvancedPluginType';
19
+ import { highlightStyle } from '../ui/syntaxHighlightingTheme';
20
+ import { cmTheme } from '../ui/theme';
21
+
22
+ import { syncCMWithPM } from './codemirrorSync/syncCMWithPM';
23
+ import { updateCMSelection } from './codemirrorSync/updateCMSelection';
24
+ import { bidiCharWarningExtension } from './extensions/bidiCharWarning';
25
+ import { keymapExtension } from './extensions/keymap';
26
+ import { LanguageLoader } from './languages/loader';
27
+
28
+ interface ConfigProps {
29
+ api: ExtractInjectionAPI<CodeBlockAdvancedPlugin> | undefined;
30
+ extensions: Extension[];
31
+ }
32
+
33
+ // Based on: https://prosemirror.net/examples/codemirror/
34
+ class CodeBlockAdvancedNodeView implements NodeView {
35
+ dom: Node;
36
+ private updating: boolean;
37
+ private view: EditorView;
38
+ private lineWrappingCompartment = new Compartment();
39
+ private languageCompartment = new Compartment();
40
+ private readOnlyCompartment = new Compartment();
41
+ private node: PMNode;
42
+ private getPos: getPosHandlerNode;
43
+ private cm: CodeMirror;
44
+ private selectionAPI: EditorSelectionAPI | undefined;
45
+ private maybeTryingToReachNodeSelection = false;
46
+ private cleanupDisabledState: (() => void) | undefined;
47
+ private languageLoader: LanguageLoader;
48
+
49
+ // eslint-disable-next-line @typescript-eslint/max-params
50
+ constructor(node: PMNode, view: EditorView, getPos: getPosHandlerNode, config: ConfigProps) {
51
+ this.node = node;
52
+ this.view = view;
53
+ this.getPos = getPos;
54
+ this.selectionAPI = config.api?.selection?.actions;
55
+ const getNode = () => this.node;
56
+ const onMaybeNodeSelection = () => (this.maybeTryingToReachNodeSelection = true);
57
+ this.cleanupDisabledState = config.api?.editorDisabled?.sharedState.onChange(() => {
58
+ this.updateReadonlyState();
59
+ });
60
+ this.languageLoader = new LanguageLoader((lang) => {
61
+ this.updating = true;
62
+ this.cm.dispatch({
63
+ effects: this.languageCompartment.reconfigure(lang),
64
+ });
65
+ this.updating = false;
66
+ });
67
+
68
+ this.cm = new CodeMirror({
69
+ doc: this.node.textContent,
70
+ extensions: [
71
+ ...config.extensions,
72
+ this.lineWrappingCompartment.of([]),
73
+ this.languageCompartment.of([]),
74
+ keymapExtension({
75
+ view,
76
+ getPos,
77
+ getNode,
78
+ selectCodeBlockNode: this.selectCodeBlockNode.bind(this),
79
+ onMaybeNodeSelection,
80
+ }),
81
+ cmTheme,
82
+ syntaxHighlighting(highlightStyle),
83
+ lineNumbers(),
84
+ CodeMirror.updateListener.of((update) => this.forwardUpdate(update)),
85
+ this.readOnlyCompartment.of(CodeMirror.editable.of(this.view.editable)),
86
+ closeBrackets(),
87
+ CodeMirror.editorAttributes.of({ class: 'code-block' }),
88
+ bidiCharWarningExtension,
89
+ ],
90
+ });
91
+
92
+ // The editor's outer node is our DOM representation
93
+ this.dom = this.cm.dom;
94
+
95
+ // This flag is used to avoid an update loop between the outer and
96
+ // inner editor
97
+ this.updating = false;
98
+ this.updateLanguage();
99
+ }
100
+
101
+ destroy() {
102
+ this.cleanupDisabledState?.();
103
+ }
104
+
105
+ forwardUpdate(update: ViewUpdate) {
106
+ if (this.updating || !this.cm.hasFocus) {
107
+ return;
108
+ }
109
+ const offset = (this.getPos?.() ?? 0) + 1;
110
+
111
+ syncCMWithPM({
112
+ view: this.view,
113
+ update,
114
+ offset,
115
+ });
116
+ }
117
+
118
+ setSelection(anchor: number, head: number) {
119
+ if (!this.maybeTryingToReachNodeSelection) {
120
+ this.cm.focus();
121
+ }
122
+ this.updating = true;
123
+ this.cm.dispatch({ selection: { anchor, head } });
124
+ this.updating = false;
125
+ }
126
+
127
+ private updateReadonlyState() {
128
+ this.updating = true;
129
+ this.cm.dispatch({
130
+ effects: this.readOnlyCompartment.reconfigure(CodeMirror.editable.of(this.view.editable)),
131
+ });
132
+ this.updating = false;
133
+ }
134
+
135
+ private updateLanguage() {
136
+ this.languageLoader.updateLanguage(this.node.attrs.language);
137
+ }
138
+
139
+ private selectCodeBlockNode(relativeSelectionPos: RelativeSelectionPos | undefined) {
140
+ const tr = this.selectionAPI?.selectNearNode({
141
+ selectionRelativeToNode: relativeSelectionPos,
142
+ selection: NodeSelection.create(this.view.state.doc, this.getPos?.() ?? 0),
143
+ })(this.view.state);
144
+ if (tr) {
145
+ this.view.dispatch(tr);
146
+ }
147
+ }
148
+
149
+ private wordWrappingEnabled = false;
150
+
151
+ private updateWordWrap(node: PMNode) {
152
+ if (this.wordWrappingEnabled !== isCodeBlockWordWrapEnabled(node)) {
153
+ this.updating = true;
154
+ this.cm.dispatch({
155
+ effects: [
156
+ this.lineWrappingCompartment.reconfigure(
157
+ isCodeBlockWordWrapEnabled(node) ? CodeMirror.lineWrapping : [],
158
+ ),
159
+ ],
160
+ });
161
+ this.updating = false;
162
+ this.wordWrappingEnabled = !this.wordWrappingEnabled;
163
+ }
164
+ }
165
+
166
+ update(node: PMNode) {
167
+ this.maybeTryingToReachNodeSelection = false;
168
+
169
+ if (node.type !== this.node.type) {
170
+ return false;
171
+ }
172
+ this.updateWordWrap(node);
173
+ this.node = node;
174
+ if (this.updating) {
175
+ return true;
176
+ }
177
+ this.updateLanguage();
178
+ const newText = node.textContent,
179
+ curText = this.cm.state.doc.toString();
180
+ updateCMSelection(curText, newText, (tr) => {
181
+ this.updating = true;
182
+ this.cm.dispatch(tr);
183
+ this.updating = false;
184
+ });
185
+ return true;
186
+ }
187
+
188
+ stopEvent(e: Event) {
189
+ if (e instanceof MouseEvent && e.type === 'mousedown') {
190
+ // !Warning: Side effect!
191
+ // CodeMirror on blur updates the dom observer with a `setTimeout(..., 10);`
192
+ // We need to select the nodeview after this has taken place to ensure
193
+ // ProseMirror takes over
194
+ // https://github.com/codemirror/view/commit/70a9a253df04a57004247b9463198c17832f92f4#diff-cb8cbffa623ff0975389e7e8c315e69d5e10345239ffe2c9b4b7986a56ad95efR720
195
+ setTimeout(() => {
196
+ // Ensure the CM selection is reset - if we have a ranged selection when we do node selection can
197
+ // cause funky behaviour
198
+ this.updating = true;
199
+ this.cm.dispatch({
200
+ selection: EditorSelection.create([EditorSelection.cursor(0)], 0),
201
+ });
202
+ this.updating = false;
203
+ this.selectCodeBlockNode(undefined);
204
+ this.view.focus();
205
+ }, 20);
206
+ }
207
+ // If we have selected the node we should not stop these events
208
+ if (
209
+ e instanceof KeyboardEvent &&
210
+ this.view.state.selection instanceof NodeSelection &&
211
+ this.view.state.selection.from === this.getPos?.()
212
+ ) {
213
+ return false;
214
+ }
215
+ return true;
216
+ }
217
+ }
218
+
219
+ export const getCodeBlockAdvancedNodeView =
220
+ (props: ConfigProps) =>
221
+ (node: PMNode, view: EditorView, getPos: getPosHandler): CodeBlockAdvancedNodeView => {
222
+ return new CodeBlockAdvancedNodeView(node, view, getPos as getPosHandlerNode, props);
223
+ };