@atlaskit/editor-plugin-code-block-advanced 3.0.7 → 3.1.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.
- package/CHANGELOG.md +12 -0
- package/dist/cjs/codeBlockAdvancedPlugin.js +6 -2
- package/dist/cjs/nodeviews/codeBlockAdvanced.js +12 -4
- package/dist/cjs/nodeviews/codeBlockNodeWithToDOMFixed.js +5 -4
- package/dist/cjs/nodeviews/extensions/foldGutter.js +100 -0
- package/dist/cjs/ui/theme.js +31 -1
- package/dist/es2019/codeBlockAdvancedPlugin.js +6 -2
- package/dist/es2019/nodeviews/codeBlockAdvanced.js +13 -5
- package/dist/es2019/nodeviews/codeBlockNodeWithToDOMFixed.js +5 -4
- package/dist/es2019/nodeviews/extensions/foldGutter.js +97 -0
- package/dist/es2019/ui/theme.js +30 -0
- package/dist/esm/codeBlockAdvancedPlugin.js +6 -2
- package/dist/esm/nodeviews/codeBlockAdvanced.js +13 -5
- package/dist/esm/nodeviews/codeBlockNodeWithToDOMFixed.js +5 -4
- package/dist/esm/nodeviews/extensions/foldGutter.js +94 -0
- package/dist/esm/ui/theme.js +30 -0
- package/dist/types/codeBlockAdvancedPluginType.d.ts +5 -3
- package/dist/types/index.d.ts +1 -1
- package/dist/types/nodeviews/codeBlockAdvanced.d.ts +2 -1
- package/dist/types/nodeviews/codeBlockNodeWithToDOMFixed.d.ts +5 -1
- package/dist/types/nodeviews/extensions/foldGutter.d.ts +3 -0
- package/dist/types/nodeviews/lazyCodeBlockAdvanced.d.ts +1 -0
- package/dist/types/pm-plugins/main.d.ts +1 -0
- package/dist/types/ui/theme.d.ts +1 -0
- package/dist/types-ts4.5/codeBlockAdvancedPluginType.d.ts +5 -3
- package/dist/types-ts4.5/index.d.ts +1 -1
- package/dist/types-ts4.5/nodeviews/codeBlockAdvanced.d.ts +2 -1
- package/dist/types-ts4.5/nodeviews/codeBlockNodeWithToDOMFixed.d.ts +5 -1
- package/dist/types-ts4.5/nodeviews/extensions/foldGutter.d.ts +3 -0
- package/dist/types-ts4.5/nodeviews/lazyCodeBlockAdvanced.d.ts +1 -0
- package/dist/types-ts4.5/pm-plugins/main.d.ts +1 -0
- package/dist/types-ts4.5/ui/theme.d.ts +1 -0
- package/package.json +4 -5
- package/src/codeBlockAdvancedPlugin.tsx +7 -2
- package/src/codeBlockAdvancedPluginType.ts +6 -5
- package/src/index.ts +4 -1
- package/src/nodeviews/codeBlockAdvanced.ts +13 -4
- package/src/nodeviews/codeBlockNodeWithToDOMFixed.ts +11 -4
- package/src/nodeviews/extensions/foldGutter.ts +128 -0
- package/src/nodeviews/lazyCodeBlockAdvanced.ts +1 -0
- package/src/pm-plugins/main.ts +1 -0
- package/src/ui/theme.ts +31 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { foldGutter, codeFolding } from '@codemirror/language';
|
|
2
|
+
import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
|
|
3
|
+
import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
|
|
4
|
+
// Based on platform/packages/design-system/icon/svgs/utility/add.svg
|
|
5
|
+
var chevronDown = ['http://www.w3.org/2000/svg svg', {
|
|
6
|
+
width: '12',
|
|
7
|
+
height: '12',
|
|
8
|
+
fill: 'none',
|
|
9
|
+
viewBox: '0 0 16 16',
|
|
10
|
+
style: 'pointer-events: none;'
|
|
11
|
+
}, ['http://www.w3.org/2000/svg path', {
|
|
12
|
+
fill: 'currentcolor',
|
|
13
|
+
'fill-rule': 'evenodd',
|
|
14
|
+
d: 'm14.53 6.03-6 6a.75.75 0 0 1-1.004.052l-.056-.052-6-6 1.06-1.06L8 10.44l5.47-5.47z',
|
|
15
|
+
'clip-rule': 'evenodd',
|
|
16
|
+
style: 'pointer-events: none;'
|
|
17
|
+
}]];
|
|
18
|
+
var chevronRight = ['http://www.w3.org/2000/svg svg', {
|
|
19
|
+
width: '12',
|
|
20
|
+
height: '12',
|
|
21
|
+
fill: 'none',
|
|
22
|
+
viewBox: '0 0 16 16',
|
|
23
|
+
style: 'pointer-events: none;'
|
|
24
|
+
}, ['http://www.w3.org/2000/svg path', {
|
|
25
|
+
fill: 'currentcolor',
|
|
26
|
+
'fill-rule': 'evenodd',
|
|
27
|
+
d: 'm8.28 1.47 6 6a.75.75 0 0 1 .052 1.004l-.052.056-6 6-1.06-1.06L12.69 8 7.22 2.53z',
|
|
28
|
+
'clip-rule': 'evenodd',
|
|
29
|
+
style: 'pointer-events: none;'
|
|
30
|
+
}]];
|
|
31
|
+
export function foldGutterExtension(_ref) {
|
|
32
|
+
var selectNode = _ref.selectNode;
|
|
33
|
+
return [foldGutter({
|
|
34
|
+
domEventHandlers: {
|
|
35
|
+
click: function click(_view, _, event) {
|
|
36
|
+
// If we're trying to click the button, don't select
|
|
37
|
+
if (event.target instanceof HTMLButtonElement && event.target.getAttribute('data-marker-dom-element')) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
selectNode();
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
markerDOM: function markerDOM(open) {
|
|
45
|
+
var _DOMSerializer$render = DOMSerializer.renderSpec(document, chevronDown),
|
|
46
|
+
downElement = _DOMSerializer$render.dom;
|
|
47
|
+
var _DOMSerializer$render2 = DOMSerializer.renderSpec(document, chevronRight),
|
|
48
|
+
rightElement = _DOMSerializer$render2.dom;
|
|
49
|
+
var htmlElement = document.createElement('button');
|
|
50
|
+
htmlElement.setAttribute('data-marker-dom-element', 'true');
|
|
51
|
+
htmlElement.setAttribute('data-testid', "code-block-fold-button-".concat(open ? 'open' : 'closed'));
|
|
52
|
+
htmlElement.setAttribute('style', convertToInlineCss({
|
|
53
|
+
background: 'none',
|
|
54
|
+
color: 'inherit',
|
|
55
|
+
border: 'none',
|
|
56
|
+
padding: 0,
|
|
57
|
+
paddingRight: "var(--ds-space-050, 4px)",
|
|
58
|
+
font: 'inherit',
|
|
59
|
+
outline: 'inherit',
|
|
60
|
+
cursor: 'pointer'
|
|
61
|
+
}));
|
|
62
|
+
if (open) {
|
|
63
|
+
if (downElement) {
|
|
64
|
+
htmlElement.appendChild(downElement);
|
|
65
|
+
} else {
|
|
66
|
+
// Fallback - never called
|
|
67
|
+
htmlElement.textContent = '⌄';
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
if (rightElement) {
|
|
71
|
+
htmlElement.appendChild(rightElement);
|
|
72
|
+
} else {
|
|
73
|
+
// Fallback - never called
|
|
74
|
+
htmlElement.textContent = '>';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return htmlElement;
|
|
78
|
+
}
|
|
79
|
+
}), codeFolding({
|
|
80
|
+
placeholderDOM: function placeholderDOM(view, onclick, prepared) {
|
|
81
|
+
var htmlElement = document.createElement('button');
|
|
82
|
+
htmlElement.setAttribute('data-marker-dom-element', 'true');
|
|
83
|
+
htmlElement.setAttribute('style', convertToInlineCss({
|
|
84
|
+
color: 'inherit',
|
|
85
|
+
font: 'inherit',
|
|
86
|
+
cursor: 'pointer'
|
|
87
|
+
}));
|
|
88
|
+
htmlElement.textContent = '…';
|
|
89
|
+
htmlElement.className = 'cm-foldPlaceholder';
|
|
90
|
+
htmlElement.onclick = onclick;
|
|
91
|
+
return htmlElement;
|
|
92
|
+
}
|
|
93
|
+
})];
|
|
94
|
+
}
|
package/dist/esm/ui/theme.js
CHANGED
|
@@ -68,6 +68,36 @@ export var cmTheme = CodeMirror.theme({
|
|
|
68
68
|
minHeight: lineHeight
|
|
69
69
|
}
|
|
70
70
|
});
|
|
71
|
+
export var codeFoldingTheme = CodeMirror.theme({
|
|
72
|
+
'.cm-gutter': {
|
|
73
|
+
paddingLeft: "var(--ds-space-075, 6px)",
|
|
74
|
+
paddingTop: "var(--ds-space-100, 8px)",
|
|
75
|
+
paddingBottom: "var(--ds-space-100, 8px)",
|
|
76
|
+
paddingRight: "var(--ds-space-0, 0px)"
|
|
77
|
+
},
|
|
78
|
+
'.cm-foldGutter': {
|
|
79
|
+
paddingLeft: "var(--ds-space-050, 4px)"
|
|
80
|
+
},
|
|
81
|
+
'.cm-gutterElement:has([data-marker-dom-element="true"])': {
|
|
82
|
+
color: "var(--ds-icon-subtle, #626F86)"
|
|
83
|
+
},
|
|
84
|
+
'.cm-gutterElement:has([data-marker-dom-element="true"]):hover': {
|
|
85
|
+
color: "var(--ds-text-accent-gray-bolder, #091E42)"
|
|
86
|
+
},
|
|
87
|
+
'.cm-foldPlaceholder': {
|
|
88
|
+
// To give spacing between lines
|
|
89
|
+
height: '20px',
|
|
90
|
+
backgroundColor: "var(--ds-background-accent-gray-subtlest, #F1F2F4)",
|
|
91
|
+
border: 'none',
|
|
92
|
+
color: "var(--ds-text, #172B4D)",
|
|
93
|
+
outline: "1px solid ".concat("var(--ds-border-accent-gray, #758195)"),
|
|
94
|
+
paddingLeft: "var(--ds-space-025, 2px)",
|
|
95
|
+
paddingRight: "var(--ds-space-025, 2px)"
|
|
96
|
+
},
|
|
97
|
+
'.cm-foldPlaceholder:hover': {
|
|
98
|
+
backgroundColor: "var(--ds-background-accent-gray-subtlest-hovered, #DCDFE4)"
|
|
99
|
+
}
|
|
100
|
+
});
|
|
71
101
|
|
|
72
102
|
/**
|
|
73
103
|
* Copied directly from `packages/editor/editor-shared-styles/src/overflow-shadow/overflow-shadow.ts`
|
|
@@ -13,7 +13,9 @@ export type CodeBlockAdvancedPlugin = NextEditorPlugin<'codeBlockAdvanced', {
|
|
|
13
13
|
OptionalPlugin<SelectionMarkerPlugin>,
|
|
14
14
|
OptionalPlugin<FindReplacePlugin>
|
|
15
15
|
];
|
|
16
|
-
pluginConfiguration:
|
|
17
|
-
extensions?: Extension[];
|
|
18
|
-
} | undefined;
|
|
16
|
+
pluginConfiguration: CodeBlockAdvancedPluginOptions | undefined;
|
|
19
17
|
}>;
|
|
18
|
+
export type CodeBlockAdvancedPluginOptions = {
|
|
19
|
+
extensions?: Extension[];
|
|
20
|
+
allowCodeFolding?: boolean;
|
|
21
|
+
};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { codeBlockAdvancedPlugin } from './codeBlockAdvancedPlugin';
|
|
2
|
-
export type { CodeBlockAdvancedPlugin } from './codeBlockAdvancedPluginType';
|
|
2
|
+
export type { CodeBlockAdvancedPlugin, CodeBlockAdvancedPluginOptions, } from './codeBlockAdvancedPluginType';
|
|
@@ -5,10 +5,11 @@ import type { getPosHandler, getPosHandlerNode, ExtractInjectionAPI } from '@atl
|
|
|
5
5
|
import { type Node as PMNode } from '@atlaskit/editor-prosemirror/model';
|
|
6
6
|
import type { Decoration, DecorationSource, EditorView, NodeView } from '@atlaskit/editor-prosemirror/view';
|
|
7
7
|
import type { CodeBlockAdvancedPlugin } from '../codeBlockAdvancedPluginType';
|
|
8
|
-
interface ConfigProps {
|
|
8
|
+
export interface ConfigProps {
|
|
9
9
|
api: ExtractInjectionAPI<CodeBlockAdvancedPlugin> | undefined;
|
|
10
10
|
extensions: Extension[];
|
|
11
11
|
getIntl: () => IntlShape;
|
|
12
|
+
allowCodeFolding: boolean;
|
|
12
13
|
}
|
|
13
14
|
declare class CodeBlockAdvancedNodeView implements NodeView {
|
|
14
15
|
dom: Node;
|
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
import type { NodeSpec } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
-
|
|
2
|
+
interface Config {
|
|
3
|
+
allowCodeFolding: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare const codeBlockNodeWithFixedToDOM: (config: Config) => NodeSpec;
|
|
6
|
+
export {};
|
|
@@ -6,6 +6,7 @@ interface Props {
|
|
|
6
6
|
api: ExtractInjectionAPI<CodeBlockAdvancedPlugin> | undefined;
|
|
7
7
|
extensions: Extension[];
|
|
8
8
|
getIntl: () => IntlShape;
|
|
9
|
+
allowCodeFolding: boolean;
|
|
9
10
|
}
|
|
10
11
|
export declare const lazyCodeBlockView: (props: Props) => import("@atlaskit/editor-common/lazy-node-view").NodeViewConstructor;
|
|
11
12
|
export {};
|
package/dist/types/ui/theme.d.ts
CHANGED
|
@@ -13,7 +13,9 @@ export type CodeBlockAdvancedPlugin = NextEditorPlugin<'codeBlockAdvanced', {
|
|
|
13
13
|
OptionalPlugin<SelectionMarkerPlugin>,
|
|
14
14
|
OptionalPlugin<FindReplacePlugin>
|
|
15
15
|
];
|
|
16
|
-
pluginConfiguration:
|
|
17
|
-
extensions?: Extension[];
|
|
18
|
-
} | undefined;
|
|
16
|
+
pluginConfiguration: CodeBlockAdvancedPluginOptions | undefined;
|
|
19
17
|
}>;
|
|
18
|
+
export type CodeBlockAdvancedPluginOptions = {
|
|
19
|
+
extensions?: Extension[];
|
|
20
|
+
allowCodeFolding?: boolean;
|
|
21
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { codeBlockAdvancedPlugin } from './codeBlockAdvancedPlugin';
|
|
2
|
-
export type { CodeBlockAdvancedPlugin } from './codeBlockAdvancedPluginType';
|
|
2
|
+
export type { CodeBlockAdvancedPlugin, CodeBlockAdvancedPluginOptions, } from './codeBlockAdvancedPluginType';
|
|
@@ -5,10 +5,11 @@ import type { getPosHandler, getPosHandlerNode, ExtractInjectionAPI } from '@atl
|
|
|
5
5
|
import { type Node as PMNode } from '@atlaskit/editor-prosemirror/model';
|
|
6
6
|
import type { Decoration, DecorationSource, EditorView, NodeView } from '@atlaskit/editor-prosemirror/view';
|
|
7
7
|
import type { CodeBlockAdvancedPlugin } from '../codeBlockAdvancedPluginType';
|
|
8
|
-
interface ConfigProps {
|
|
8
|
+
export interface ConfigProps {
|
|
9
9
|
api: ExtractInjectionAPI<CodeBlockAdvancedPlugin> | undefined;
|
|
10
10
|
extensions: Extension[];
|
|
11
11
|
getIntl: () => IntlShape;
|
|
12
|
+
allowCodeFolding: boolean;
|
|
12
13
|
}
|
|
13
14
|
declare class CodeBlockAdvancedNodeView implements NodeView {
|
|
14
15
|
dom: Node;
|
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
import type { NodeSpec } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
-
|
|
2
|
+
interface Config {
|
|
3
|
+
allowCodeFolding: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare const codeBlockNodeWithFixedToDOM: (config: Config) => NodeSpec;
|
|
6
|
+
export {};
|
|
@@ -6,6 +6,7 @@ interface Props {
|
|
|
6
6
|
api: ExtractInjectionAPI<CodeBlockAdvancedPlugin> | undefined;
|
|
7
7
|
extensions: Extension[];
|
|
8
8
|
getIntl: () => IntlShape;
|
|
9
|
+
allowCodeFolding: boolean;
|
|
9
10
|
}
|
|
10
11
|
export declare const lazyCodeBlockView: (props: Props) => import("@atlaskit/editor-common/lazy-node-view").NodeViewConstructor;
|
|
11
12
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-code-block-advanced",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "CodeBlockAdvanced plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@atlaskit/editor-plugin-selection-marker": "^3.0.0",
|
|
40
40
|
"@atlaskit/editor-prosemirror": "7.0.0",
|
|
41
41
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
42
|
-
"@atlaskit/tmp-editor-statsig": "^9.
|
|
42
|
+
"@atlaskit/tmp-editor-statsig": "^9.27.0",
|
|
43
43
|
"@atlaskit/tokens": "^6.0.0",
|
|
44
44
|
"@babel/runtime": "^7.0.0",
|
|
45
45
|
"@codemirror/autocomplete": "6.18.4",
|
|
@@ -54,12 +54,11 @@
|
|
|
54
54
|
"codemirror-lang-elixir": "4.0.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@atlaskit/editor-common": "^107.
|
|
57
|
+
"@atlaskit/editor-common": "^107.20.0",
|
|
58
58
|
"react": "^18.2.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@atlaskit/code": "^17.2.0"
|
|
62
|
-
"typescript": "~5.4.2"
|
|
61
|
+
"@atlaskit/code": "^17.2.0"
|
|
63
62
|
},
|
|
64
63
|
"techstack": {
|
|
65
64
|
"@atlassian/frontend": {
|
|
@@ -9,7 +9,7 @@ export const codeBlockAdvancedPlugin: CodeBlockAdvancedPlugin = ({ api, config }
|
|
|
9
9
|
return [
|
|
10
10
|
{
|
|
11
11
|
name: 'codeBlock',
|
|
12
|
-
node: codeBlockNodeWithFixedToDOM(),
|
|
12
|
+
node: codeBlockNodeWithFixedToDOM({ allowCodeFolding: config?.allowCodeFolding ?? false }),
|
|
13
13
|
},
|
|
14
14
|
];
|
|
15
15
|
},
|
|
@@ -19,7 +19,12 @@ export const codeBlockAdvancedPlugin: CodeBlockAdvancedPlugin = ({ api, config }
|
|
|
19
19
|
{
|
|
20
20
|
name: 'codeBlockAdvancedPlugin',
|
|
21
21
|
plugin: ({ getIntl }) =>
|
|
22
|
-
createPlugin({
|
|
22
|
+
createPlugin({
|
|
23
|
+
api,
|
|
24
|
+
extensions: config?.extensions ?? [],
|
|
25
|
+
allowCodeFolding: config?.allowCodeFolding ?? false,
|
|
26
|
+
getIntl
|
|
27
|
+
}),
|
|
23
28
|
},
|
|
24
29
|
];
|
|
25
30
|
},
|
|
@@ -17,10 +17,11 @@ export type CodeBlockAdvancedPlugin = NextEditorPlugin<
|
|
|
17
17
|
OptionalPlugin<SelectionMarkerPlugin>,
|
|
18
18
|
OptionalPlugin<FindReplacePlugin>,
|
|
19
19
|
];
|
|
20
|
-
pluginConfiguration:
|
|
21
|
-
| {
|
|
22
|
-
extensions?: Extension[];
|
|
23
|
-
}
|
|
24
|
-
| undefined;
|
|
20
|
+
pluginConfiguration: CodeBlockAdvancedPluginOptions | undefined;
|
|
25
21
|
}
|
|
26
22
|
>;
|
|
23
|
+
|
|
24
|
+
export type CodeBlockAdvancedPluginOptions = {
|
|
25
|
+
extensions?: Extension[];
|
|
26
|
+
allowCodeFolding?: boolean;
|
|
27
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -2,4 +2,7 @@
|
|
|
2
2
|
// Entry file in package.json
|
|
3
3
|
|
|
4
4
|
export { codeBlockAdvancedPlugin } from './codeBlockAdvancedPlugin';
|
|
5
|
-
export type {
|
|
5
|
+
export type {
|
|
6
|
+
CodeBlockAdvancedPlugin,
|
|
7
|
+
CodeBlockAdvancedPluginOptions,
|
|
8
|
+
} from './codeBlockAdvancedPluginType';
|
|
@@ -33,21 +33,23 @@ import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equ
|
|
|
33
33
|
|
|
34
34
|
import type { CodeBlockAdvancedPlugin } from '../codeBlockAdvancedPluginType';
|
|
35
35
|
import { highlightStyle } from '../ui/syntaxHighlightingTheme';
|
|
36
|
-
import { cmTheme } from '../ui/theme';
|
|
36
|
+
import { cmTheme, codeFoldingTheme } from '../ui/theme';
|
|
37
37
|
|
|
38
38
|
import { syncCMWithPM } from './codemirrorSync/syncCMWithPM';
|
|
39
39
|
import { getCMSelectionChanges } from './codemirrorSync/updateCMSelection';
|
|
40
40
|
import { firstCodeBlockInDocument } from './extensions/firstCodeBlockInDocument';
|
|
41
|
+
import { foldGutterExtension } from './extensions/foldGutter';
|
|
41
42
|
import { keymapExtension } from './extensions/keymap';
|
|
42
43
|
import { manageSelectionMarker } from './extensions/manageSelectionMarker';
|
|
43
44
|
import { prosemirrorDecorationPlugin } from './extensions/prosemirrorDecorations';
|
|
44
45
|
import { tripleClickSelectAllExtension } from './extensions/tripleClickExtension';
|
|
45
46
|
import { LanguageLoader } from './languages/loader';
|
|
46
47
|
|
|
47
|
-
interface ConfigProps {
|
|
48
|
+
export interface ConfigProps {
|
|
48
49
|
api: ExtractInjectionAPI<CodeBlockAdvancedPlugin> | undefined;
|
|
49
50
|
extensions: Extension[];
|
|
50
51
|
getIntl: () => IntlShape;
|
|
52
|
+
allowCodeFolding: boolean;
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
// Based on: https://prosemirror.net/examples/codemirror/
|
|
@@ -94,6 +96,11 @@ class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
94
96
|
const { formatMessage } = config.getIntl();
|
|
95
97
|
const formattedAriaLabel = formatMessage(blockTypeMessages.codeblock);
|
|
96
98
|
|
|
99
|
+
const selectNode = () => {
|
|
100
|
+
this.selectCodeBlockNode(undefined);
|
|
101
|
+
this.view.focus();
|
|
102
|
+
};
|
|
103
|
+
|
|
97
104
|
this.cm = new CodeMirror({
|
|
98
105
|
doc: this.node.textContent,
|
|
99
106
|
extensions: [
|
|
@@ -111,14 +118,15 @@ class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
111
118
|
onMaybeNodeSelection,
|
|
112
119
|
customFindReplace: Boolean(config.api?.findReplace),
|
|
113
120
|
}),
|
|
121
|
+
// Goes before cmTheme to override styles
|
|
122
|
+
config.allowCodeFolding ? [codeFoldingTheme] : [],
|
|
114
123
|
cmTheme,
|
|
115
124
|
syntaxHighlighting(highlightStyle),
|
|
116
125
|
bracketMatching(),
|
|
117
126
|
lineNumbers({
|
|
118
127
|
domEventHandlers: {
|
|
119
128
|
click: () => {
|
|
120
|
-
|
|
121
|
-
this.view.focus();
|
|
129
|
+
selectNode();
|
|
122
130
|
return true;
|
|
123
131
|
},
|
|
124
132
|
},
|
|
@@ -138,6 +146,7 @@ class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
138
146
|
tripleClickSelectAllExtension(),
|
|
139
147
|
firstCodeBlockInDocument(getPos),
|
|
140
148
|
CodeMirror.contentAttributes.of({ 'aria-label': formattedAriaLabel }),
|
|
149
|
+
config.allowCodeFolding ? [foldGutterExtension({ selectNode })] : [],
|
|
141
150
|
],
|
|
142
151
|
});
|
|
143
152
|
|
|
@@ -4,6 +4,10 @@ import { CodeBlockSharedCssClassName } from '@atlaskit/editor-common/styles';
|
|
|
4
4
|
import type { NodeSpec, DOMOutputSpec, Node } from '@atlaskit/editor-prosemirror/model';
|
|
5
5
|
import { token } from '@atlaskit/tokens';
|
|
6
6
|
|
|
7
|
+
interface Config {
|
|
8
|
+
allowCodeFolding: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
7
11
|
const codeBlockClassNames = {
|
|
8
12
|
container: CodeBlockSharedCssClassName.CODEBLOCK_CONTAINER,
|
|
9
13
|
start: CodeBlockSharedCssClassName.CODEBLOCK_START,
|
|
@@ -15,7 +19,7 @@ const codeBlockClassNames = {
|
|
|
15
19
|
const MATCH_NEWLINES = new RegExp('\n', 'gu');
|
|
16
20
|
|
|
17
21
|
// Based on: `packages/editor/editor-plugin-code-block/src/nodeviews/code-block.ts`
|
|
18
|
-
const toDOM = (node: Node, formattedAriaLabel: string): DOMOutputSpec => {
|
|
22
|
+
const toDOM = (node: Node, formattedAriaLabel: string, config: Config): DOMOutputSpec => {
|
|
19
23
|
let totalLineCount = 1;
|
|
20
24
|
|
|
21
25
|
node.forEach((node) => {
|
|
@@ -54,7 +58,10 @@ const toDOM = (node: Node, formattedAriaLabel: string): DOMOutputSpec => {
|
|
|
54
58
|
backgroundColor: token('color.background.neutral'),
|
|
55
59
|
position: 'relative',
|
|
56
60
|
width: 'var(--lineNumberGutterWidth, 2rem)',
|
|
57
|
-
|
|
61
|
+
/* top and bottom | left and right */
|
|
62
|
+
padding: config.allowCodeFolding
|
|
63
|
+
? `${token('space.100')} ${token('space.250')} ${token('space.100')} ${token('space.075')}`
|
|
64
|
+
: token('space.100'),
|
|
58
65
|
flexShrink: 0,
|
|
59
66
|
fontSize: '0.875rem',
|
|
60
67
|
boxSizing: 'content-box',
|
|
@@ -96,9 +103,9 @@ const toDOM = (node: Node, formattedAriaLabel: string): DOMOutputSpec => {
|
|
|
96
103
|
];
|
|
97
104
|
};
|
|
98
105
|
|
|
99
|
-
export const codeBlockNodeWithFixedToDOM = (): NodeSpec => {
|
|
106
|
+
export const codeBlockNodeWithFixedToDOM = (config: Config): NodeSpec => {
|
|
100
107
|
return {
|
|
101
108
|
...codeBlock,
|
|
102
|
-
toDOM: (node) => toDOM(node, ''),
|
|
109
|
+
toDOM: (node) => toDOM(node, '', config),
|
|
103
110
|
};
|
|
104
111
|
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { foldGutter, codeFolding } from '@codemirror/language';
|
|
2
|
+
|
|
3
|
+
import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
|
|
4
|
+
import type { DOMOutputSpec } from '@atlaskit/editor-prosemirror/model';
|
|
5
|
+
import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
|
|
6
|
+
import { token } from '@atlaskit/tokens';
|
|
7
|
+
|
|
8
|
+
// Based on platform/packages/design-system/icon/svgs/utility/add.svg
|
|
9
|
+
const chevronDown: DOMOutputSpec = [
|
|
10
|
+
'http://www.w3.org/2000/svg svg',
|
|
11
|
+
{
|
|
12
|
+
width: '12',
|
|
13
|
+
height: '12',
|
|
14
|
+
fill: 'none',
|
|
15
|
+
viewBox: '0 0 16 16',
|
|
16
|
+
style: 'pointer-events: none;',
|
|
17
|
+
},
|
|
18
|
+
[
|
|
19
|
+
'http://www.w3.org/2000/svg path',
|
|
20
|
+
{
|
|
21
|
+
fill: 'currentcolor',
|
|
22
|
+
'fill-rule': 'evenodd',
|
|
23
|
+
d: 'm14.53 6.03-6 6a.75.75 0 0 1-1.004.052l-.056-.052-6-6 1.06-1.06L8 10.44l5.47-5.47z',
|
|
24
|
+
'clip-rule': 'evenodd',
|
|
25
|
+
style: 'pointer-events: none;',
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const chevronRight: DOMOutputSpec = [
|
|
31
|
+
'http://www.w3.org/2000/svg svg',
|
|
32
|
+
{
|
|
33
|
+
width: '12',
|
|
34
|
+
height: '12',
|
|
35
|
+
fill: 'none',
|
|
36
|
+
viewBox: '0 0 16 16',
|
|
37
|
+
style: 'pointer-events: none;',
|
|
38
|
+
},
|
|
39
|
+
[
|
|
40
|
+
'http://www.w3.org/2000/svg path',
|
|
41
|
+
{
|
|
42
|
+
fill: 'currentcolor',
|
|
43
|
+
'fill-rule': 'evenodd',
|
|
44
|
+
d: 'm8.28 1.47 6 6a.75.75 0 0 1 .052 1.004l-.052.056-6 6-1.06-1.06L12.69 8 7.22 2.53z',
|
|
45
|
+
'clip-rule': 'evenodd',
|
|
46
|
+
style: 'pointer-events: none;',
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
export function foldGutterExtension({ selectNode }: { selectNode: () => void }) {
|
|
52
|
+
return [
|
|
53
|
+
foldGutter({
|
|
54
|
+
domEventHandlers: {
|
|
55
|
+
click: (_view, _, event) => {
|
|
56
|
+
// If we're trying to click the button, don't select
|
|
57
|
+
if (
|
|
58
|
+
event.target instanceof HTMLButtonElement &&
|
|
59
|
+
event.target.getAttribute('data-marker-dom-element')
|
|
60
|
+
) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
selectNode();
|
|
64
|
+
return false;
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
markerDOM: (open) => {
|
|
68
|
+
const { dom: downElement } = DOMSerializer.renderSpec(document, chevronDown);
|
|
69
|
+
const { dom: rightElement } = DOMSerializer.renderSpec(document, chevronRight);
|
|
70
|
+
const htmlElement = document.createElement('button');
|
|
71
|
+
htmlElement.setAttribute('data-marker-dom-element', 'true');
|
|
72
|
+
htmlElement.setAttribute(
|
|
73
|
+
'data-testid',
|
|
74
|
+
`code-block-fold-button-${open ? 'open' : 'closed'}`,
|
|
75
|
+
);
|
|
76
|
+
htmlElement.setAttribute(
|
|
77
|
+
'style',
|
|
78
|
+
convertToInlineCss({
|
|
79
|
+
background: 'none',
|
|
80
|
+
color: 'inherit',
|
|
81
|
+
border: 'none',
|
|
82
|
+
padding: 0,
|
|
83
|
+
paddingRight: token('space.050'),
|
|
84
|
+
font: 'inherit',
|
|
85
|
+
outline: 'inherit',
|
|
86
|
+
cursor: 'pointer',
|
|
87
|
+
}),
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (open) {
|
|
91
|
+
if (downElement) {
|
|
92
|
+
htmlElement.appendChild(downElement);
|
|
93
|
+
} else {
|
|
94
|
+
// Fallback - never called
|
|
95
|
+
htmlElement.textContent = '⌄';
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
if (rightElement) {
|
|
99
|
+
htmlElement.appendChild(rightElement);
|
|
100
|
+
} else {
|
|
101
|
+
// Fallback - never called
|
|
102
|
+
htmlElement.textContent = '>';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return htmlElement;
|
|
107
|
+
},
|
|
108
|
+
}),
|
|
109
|
+
codeFolding({
|
|
110
|
+
placeholderDOM(view, onclick, prepared) {
|
|
111
|
+
const htmlElement = document.createElement('button');
|
|
112
|
+
htmlElement.setAttribute('data-marker-dom-element', 'true');
|
|
113
|
+
htmlElement.setAttribute(
|
|
114
|
+
'style',
|
|
115
|
+
convertToInlineCss({
|
|
116
|
+
color: 'inherit',
|
|
117
|
+
font: 'inherit',
|
|
118
|
+
cursor: 'pointer',
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
htmlElement.textContent = '…';
|
|
122
|
+
htmlElement.className = 'cm-foldPlaceholder';
|
|
123
|
+
htmlElement.onclick = onclick;
|
|
124
|
+
return htmlElement;
|
|
125
|
+
},
|
|
126
|
+
}),
|
|
127
|
+
];
|
|
128
|
+
}
|
package/src/pm-plugins/main.ts
CHANGED
package/src/ui/theme.ts
CHANGED
|
@@ -73,6 +73,37 @@ export const cmTheme = CodeMirror.theme({
|
|
|
73
73
|
},
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
export const codeFoldingTheme = CodeMirror.theme({
|
|
77
|
+
'.cm-gutter': {
|
|
78
|
+
paddingLeft: token('space.075'),
|
|
79
|
+
paddingTop: token('space.100'),
|
|
80
|
+
paddingBottom: token('space.100'),
|
|
81
|
+
paddingRight: token('space.0'),
|
|
82
|
+
},
|
|
83
|
+
'.cm-foldGutter': {
|
|
84
|
+
paddingLeft: token('space.050'),
|
|
85
|
+
},
|
|
86
|
+
'.cm-gutterElement:has([data-marker-dom-element="true"])': {
|
|
87
|
+
color: token('color.icon.subtle'),
|
|
88
|
+
},
|
|
89
|
+
'.cm-gutterElement:has([data-marker-dom-element="true"]):hover': {
|
|
90
|
+
color: token('color.text.accent.gray.bolder'),
|
|
91
|
+
},
|
|
92
|
+
'.cm-foldPlaceholder': {
|
|
93
|
+
// To give spacing between lines
|
|
94
|
+
height: '20px',
|
|
95
|
+
backgroundColor: token('color.background.accent.gray.subtlest'),
|
|
96
|
+
border: 'none',
|
|
97
|
+
color: token('color.text'),
|
|
98
|
+
outline: `1px solid ${token('color.border.accent.gray')}`,
|
|
99
|
+
paddingLeft: token('space.025'),
|
|
100
|
+
paddingRight: token('space.025'),
|
|
101
|
+
},
|
|
102
|
+
'.cm-foldPlaceholder:hover': {
|
|
103
|
+
backgroundColor: token('color.background.accent.gray.subtlest.hovered'),
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
76
107
|
/**
|
|
77
108
|
* Copied directly from `packages/editor/editor-shared-styles/src/overflow-shadow/overflow-shadow.ts`
|
|
78
109
|
* `CodeMirror` does not support emotion styling so this has been re-created.
|