@ember-eui/core 1.2.6 → 1.3.3
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 +9 -0
- package/addon/components/common.ts +13 -0
- package/addon/components/eui-button/index.hbs +2 -0
- package/addon/components/eui-button-content/index.hbs +1 -0
- package/addon/components/eui-button-empty/index.hbs +2 -0
- package/addon/components/eui-button-icon/index.hbs +2 -0
- package/addon/components/eui-code/index.hbs +9 -0
- package/addon/components/eui-code-block/index.d.ts +2 -0
- package/addon/components/eui-code-block/index.hbs +10 -0
- package/addon/components/eui-code-block-impl/code-block-controls/index.hbs +33 -0
- package/addon/components/eui-code-block-impl/index.hbs +111 -0
- package/addon/components/eui-code-block-impl/index.ts +121 -0
- package/addon/components/eui-copy/index.hbs +8 -0
- package/addon/components/eui-copy/index.ts +37 -0
- package/addon/components/eui-icon/index.hbs +37 -32
- package/addon/components/eui-inner-text/index.hbs +1 -0
- package/addon/components/eui-inner-text/index.ts +61 -0
- package/addon/components/eui-markdown-editor/index.hbs +63 -0
- package/addon/components/eui-markdown-editor/index.ts +221 -0
- package/addon/components/eui-markdown-editor-drop-zone/index.hbs +21 -0
- package/addon/components/eui-markdown-editor-drop-zone/index.ts +5 -0
- package/addon/components/eui-markdown-editor-footer/index.hbs +108 -0
- package/addon/components/eui-markdown-editor-footer/index.ts +20 -0
- package/addon/components/eui-markdown-editor-text-area/index.hbs +8 -0
- package/addon/components/eui-markdown-editor-toolbar/index.hbs +86 -0
- package/addon/components/eui-markdown-editor-toolbar/index.ts +97 -0
- package/addon/components/eui-markdown-format/index.hbs +13 -0
- package/addon/components/eui-markdown-format/index.ts +45 -0
- package/addon/components/eui-markdown-format/markdown-checkbox/index.hbs +8 -0
- package/addon/components/eui-markdown-format/markdown-checkbox/index.ts +28 -0
- package/addon/components/eui-markdown-format/markdown-code/index.hbs +3 -0
- package/addon/components/eui-markdown-format/markdown-code-block/index.hbs +7 -0
- package/addon/components/eui-markdown-format/markdown-tooltip/index.hbs +8 -0
- package/addon/components/markdown-checkmark-icon/index.hbs +0 -0
- package/addon/modifiers/get-cursor-node.ts +54 -0
- package/addon/modifiers/resize-observer.ts +6 -2
- package/addon/utils/copy-to-clipboard.ts +70 -0
- package/addon/utils/css-mappings/eui-code-block-impl.ts +24 -0
- package/addon/utils/css-mappings/index.ts +2 -0
- package/addon/utils/markdown/markdown-actions.ts +616 -0
- package/addon/utils/markdown/markdown-modes.ts +23 -0
- package/addon/utils/markdown/markdown-types.ts +140 -0
- package/addon/utils/markdown/markdown-unified-plugins.d.ts +27 -0
- package/addon/utils/markdown/plugins/markdown-add-components.ts +63 -0
- package/addon/utils/markdown/plugins/markdown-checkbox.ts +80 -0
- package/addon/utils/markdown/plugins/markdown-default-plugins.ts +100 -0
- package/addon/utils/markdown/plugins/markdown-tooltip.ts +113 -0
- package/addon/utils/markdown/plugins/to-dom.ts +93 -0
- package/app/components/eui-code/index.js +1 -0
- package/app/components/eui-code-block/index.js +1 -0
- package/app/components/eui-code-block-impl/code-block-controls/index.js +1 -0
- package/app/components/eui-code-block-impl/index.js +1 -0
- package/app/components/eui-copy/index.js +1 -0
- package/app/components/eui-inner-text/index.js +1 -0
- package/app/components/eui-markdown-editor/index.js +1 -0
- package/app/components/eui-markdown-editor-drop-zone/index.js +1 -0
- package/app/components/eui-markdown-editor-footer/index.js +1 -0
- package/app/components/eui-markdown-editor-text-area/index.js +1 -0
- package/app/components/eui-markdown-editor-toolbar/index.js +1 -0
- package/app/components/eui-markdown-format/index.js +1 -0
- package/app/components/eui-markdown-format/markdown-checkbox/index.js +1 -0
- package/app/components/eui-markdown-format/markdown-code/index.js +1 -0
- package/app/components/eui-markdown-format/markdown-code-block/index.js +1 -0
- package/app/components/eui-markdown-format/markdown-tooltip/index.js +1 -0
- package/app/modifiers/get-cursor-node.js +1 -0
- package/app/styles/ember-eui.scss +13 -0
- package/docs/editors/code/code-block-demo/demo1.md +62 -0
- package/docs/editors/code/code-block.md +1 -0
- package/docs/editors/code/inline-demo/demo1.md +49 -0
- package/docs/editors/code/inline.md +1 -0
- package/docs/editors/markdown-editor/base-editor-demo/demo1.md +86 -0
- package/docs/editors/markdown-editor/base-editor.md +1 -0
- package/package.json +31 -5
- package/public/markdown-checkmark.svg +3 -0
- package/public/markdown-logo.svg +3 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed to Elasticsearch B.V. under one or more contributor
|
|
3
|
+
* license agreements. See the NOTICE file distributed with
|
|
4
|
+
* this work for additional information regarding copyright
|
|
5
|
+
* ownership. Elasticsearch B.V. licenses this file to you under
|
|
6
|
+
* the Apache License, Version 2.0 (the "License"); you may
|
|
7
|
+
* not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing,
|
|
13
|
+
* software distributed under the License is distributed on an
|
|
14
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
|
+
* KIND, either express or implied. See the License for the
|
|
16
|
+
* specific language governing permissions and limitations
|
|
17
|
+
* under the License.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { ComponentType, ReactNode } from 'react';
|
|
21
|
+
import { VFile } from 'vfile';
|
|
22
|
+
import { Node as UnistNode, Position as UnistPosition } from 'unist';
|
|
23
|
+
import { Parser } from 'remark-parse';
|
|
24
|
+
import { VFileMessage } from 'vfile-message';
|
|
25
|
+
import { IconType } from '../../components/eui-icon';
|
|
26
|
+
|
|
27
|
+
export interface RemarkParser {
|
|
28
|
+
Parser: typeof Parser;
|
|
29
|
+
//eslint-disable-next-line
|
|
30
|
+
tokenizeInline: Function;
|
|
31
|
+
file: VFile;
|
|
32
|
+
}
|
|
33
|
+
export interface RemarkTokenizer {
|
|
34
|
+
(
|
|
35
|
+
this: RemarkParser,
|
|
36
|
+
//eslint-disable-next-line
|
|
37
|
+
eat: Function & { now: Function },
|
|
38
|
+
value: string,
|
|
39
|
+
silent: boolean
|
|
40
|
+
): boolean | void;
|
|
41
|
+
|
|
42
|
+
locator?: (value: string, fromIndex: number) => number;
|
|
43
|
+
|
|
44
|
+
notInLink?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface RehypeNode extends EuiMarkdownAstNode {
|
|
47
|
+
[index: string]: unknown;
|
|
48
|
+
tagName: string;
|
|
49
|
+
children?: RehypeNode[];
|
|
50
|
+
value: string;
|
|
51
|
+
type: string;
|
|
52
|
+
}
|
|
53
|
+
interface RemarkRehypeHandlerCallback {
|
|
54
|
+
(
|
|
55
|
+
node: UnistPosition,
|
|
56
|
+
tagName: string,
|
|
57
|
+
props: Record<string, unknown>,
|
|
58
|
+
children: RehypeNode[]
|
|
59
|
+
): RehypeNode;
|
|
60
|
+
}
|
|
61
|
+
export interface RemarkRehypeHandler {
|
|
62
|
+
(h: RemarkRehypeHandlerCallback, node: UnistNode): RehypeNode;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface EuiMarkdownEditorUiPluginEditorProps<NodeShape> {
|
|
66
|
+
node: NodeShape | null;
|
|
67
|
+
onCancel: () => void;
|
|
68
|
+
onSave: (markdown: string, config: EuiMarkdownStringTagConfig) => void;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const isPluginWithImmediateFormatting = (
|
|
72
|
+
x: PluginWithImmediateFormatting | PluginWithDelayedFormatting<any>
|
|
73
|
+
): x is PluginWithImmediateFormatting => {
|
|
74
|
+
return x.hasOwnProperty('formatting');
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export interface PluginWithImmediateFormatting {
|
|
78
|
+
formatting: EuiMarkdownFormatting;
|
|
79
|
+
editor?: never;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface PluginWithDelayedFormatting<NodeShape> {
|
|
83
|
+
formatting?: never;
|
|
84
|
+
editor: ComponentType<EuiMarkdownEditorUiPluginEditorProps<NodeShape>>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export type EuiMarkdownEditorUiPlugin<NodeShape = any> = {
|
|
88
|
+
name: string;
|
|
89
|
+
button: {
|
|
90
|
+
label: string;
|
|
91
|
+
iconType: IconType;
|
|
92
|
+
};
|
|
93
|
+
helpText?: ReactNode;
|
|
94
|
+
} & (PluginWithImmediateFormatting | PluginWithDelayedFormatting<NodeShape>);
|
|
95
|
+
|
|
96
|
+
export interface EuiMarkdownFormatting {
|
|
97
|
+
prefix?: string;
|
|
98
|
+
suffix?: string;
|
|
99
|
+
blockPrefix?: string;
|
|
100
|
+
blockSuffix?: string;
|
|
101
|
+
multiline?: boolean;
|
|
102
|
+
replaceNext?: string;
|
|
103
|
+
prefixSpace?: boolean;
|
|
104
|
+
scanFor?: string;
|
|
105
|
+
surroundWithNewlines?: boolean;
|
|
106
|
+
orderedList?: boolean;
|
|
107
|
+
trimFirst?: boolean;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface EuiMarkdownAstNode {
|
|
111
|
+
type: string;
|
|
112
|
+
children?: EuiMarkdownAstNode[];
|
|
113
|
+
position: EuiMarkdownAstNodePosition;
|
|
114
|
+
properties: {
|
|
115
|
+
[index: string]: unknown;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export interface EuiMarkdownAstNodePosition {
|
|
119
|
+
start: { line: number; column: number; offset: number };
|
|
120
|
+
end: { line: number; column: number; offset: number };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export type EuiMarkdownParseError = string | VFileMessage | Error;
|
|
124
|
+
|
|
125
|
+
export interface EuiMarkdownDropHandler {
|
|
126
|
+
supportedFiles: string[];
|
|
127
|
+
accepts: (itemType: string) => boolean;
|
|
128
|
+
getFormattingForItem: (
|
|
129
|
+
file: File
|
|
130
|
+
) => EuiMarkdownDragAndDropResult | Promise<EuiMarkdownDragAndDropResult>;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface EuiMarkdownStringTagConfig {
|
|
134
|
+
block: boolean;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface EuiMarkdownDragAndDropResult {
|
|
138
|
+
text: string;
|
|
139
|
+
config: EuiMarkdownStringTagConfig;
|
|
140
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
3
|
+
* or more contributor license agreements. Licensed under the Elastic License
|
|
4
|
+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
5
|
+
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
6
|
+
* Side Public License, v 1.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
declare module 'remark-emoji' {
|
|
10
|
+
import { Plugin } from 'unified';
|
|
11
|
+
const RemarkEmoji: Plugin;
|
|
12
|
+
export = RemarkEmoji;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare module 'remark-highlight.js' {
|
|
16
|
+
import { Plugin } from 'unified';
|
|
17
|
+
const RemarkHighlight: Plugin;
|
|
18
|
+
export = RemarkHighlight;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
declare module 'mdast-util-to-hast/lib/all' {
|
|
22
|
+
import { Node } from 'unist';
|
|
23
|
+
import { H } from 'mdast-util-to-hast';
|
|
24
|
+
|
|
25
|
+
const all: (h: H, node: Node) => Node[];
|
|
26
|
+
export = all;
|
|
27
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { RehypeNode } from '../markdown-types';
|
|
2
|
+
|
|
3
|
+
type Visitor = (node: RehypeNode) => RehypeNode;
|
|
4
|
+
|
|
5
|
+
export const visit = (node: RehypeNode, visitor: Visitor) => {
|
|
6
|
+
node = visitor(node);
|
|
7
|
+
if (node) {
|
|
8
|
+
let children: RehypeNode[] = [];
|
|
9
|
+
if (node.children) {
|
|
10
|
+
node.children.forEach((child) => {
|
|
11
|
+
child = visit(child, visitor);
|
|
12
|
+
if (child) {
|
|
13
|
+
children.push(child);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
node.children = children;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return node;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default function MarkdownAddComponents(): (tree: RehypeNode) => void {
|
|
23
|
+
return (tree) => {
|
|
24
|
+
visit(tree, (node: RehypeNode) => {
|
|
25
|
+
if (node.tagName === 'component') {
|
|
26
|
+
node.type = 'component';
|
|
27
|
+
}
|
|
28
|
+
if (node.type === 'element' && node.tagName === 'a') {
|
|
29
|
+
node.properties.className = ['euiLink', 'euiLink--primary'];
|
|
30
|
+
}
|
|
31
|
+
if (node.type === 'element' && node.tagName === 'pre') {
|
|
32
|
+
node.tagName = 'div';
|
|
33
|
+
node.properties.className = ['euiMarkdownFormat__codeblockWrapper'];
|
|
34
|
+
}
|
|
35
|
+
if (node.type === 'element' && node.tagName === 'blockquote') {
|
|
36
|
+
node.properties.className = ['euiMarkdownFormat__blockquote'];
|
|
37
|
+
}
|
|
38
|
+
if (node.type === 'element' && node.tagName === 'table') {
|
|
39
|
+
node.properties.className = ['euiMarkdownFormat__table'];
|
|
40
|
+
}
|
|
41
|
+
if (node.type === 'element' && node.tagName === 'hr') {
|
|
42
|
+
node.type = 'component';
|
|
43
|
+
node.properties.componentName = 'eui-horizontal-rule';
|
|
44
|
+
}
|
|
45
|
+
if (node.type === 'element' && node.tagName === 'code') {
|
|
46
|
+
node.type = 'component';
|
|
47
|
+
const hasBreaks = node.children?.find((child: RehypeNode) =>
|
|
48
|
+
/\r|\n/.exec(child.value)
|
|
49
|
+
);
|
|
50
|
+
if (hasBreaks) {
|
|
51
|
+
node.properties.componentName =
|
|
52
|
+
'eui-markdown-format/markdown-code-block';
|
|
53
|
+
node.properties.fontSize = 'm';
|
|
54
|
+
node.properties.paddingSize = 's';
|
|
55
|
+
} else {
|
|
56
|
+
node.properties.componentName = 'eui-markdown-format/markdown-code';
|
|
57
|
+
node.properties.inline = true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return node;
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed to Elasticsearch B.V. under one or more contributor
|
|
3
|
+
* license agreements. See the NOTICE file distributed with
|
|
4
|
+
* this work for additional information regarding copyright
|
|
5
|
+
* ownership. Elasticsearch B.V. licenses this file to you under
|
|
6
|
+
* the Apache License, Version 2.0 (the "License"); you may
|
|
7
|
+
* not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing,
|
|
13
|
+
* software distributed under the License is distributed on an
|
|
14
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
|
+
* KIND, either express or implied. See the License for the
|
|
16
|
+
* specific language governing permissions and limitations
|
|
17
|
+
* under the License.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { RemarkTokenizer } from '../markdown-types';
|
|
21
|
+
import { Plugin } from 'unified';
|
|
22
|
+
|
|
23
|
+
interface CheckboxNodeDetails {
|
|
24
|
+
type: 'component';
|
|
25
|
+
componentName: 'eui-markdown-format/markdown-checkbox';
|
|
26
|
+
lead: string;
|
|
27
|
+
label: string;
|
|
28
|
+
isChecked: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const CheckboxParser: Plugin = function CheckboxParser() {
|
|
32
|
+
const Parser = this.Parser;
|
|
33
|
+
const tokenizers = Parser.prototype.blockTokenizers;
|
|
34
|
+
const methods = Parser.prototype.blockMethods;
|
|
35
|
+
|
|
36
|
+
const tokenizeCheckbox: RemarkTokenizer = function tokenizeCheckbox(
|
|
37
|
+
eat,
|
|
38
|
+
value,
|
|
39
|
+
silent
|
|
40
|
+
) {
|
|
41
|
+
/**
|
|
42
|
+
* optional leading whitespace & single (dash or asterisk) mix
|
|
43
|
+
* square brackets, optionally containing whitespace and `x`
|
|
44
|
+
* optional whitespace
|
|
45
|
+
* remainder of the line is consumed as the textbox label
|
|
46
|
+
*/
|
|
47
|
+
const checkboxMatch = value.match(/^(\s*[-*]\s*)?\[([\sx]*)\](.+)/);
|
|
48
|
+
if (checkboxMatch == null) return false;
|
|
49
|
+
|
|
50
|
+
if (silent) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const [match, lead = '', checkboxStatus, text] = checkboxMatch;
|
|
55
|
+
const isChecked = checkboxStatus.indexOf('x') !== -1;
|
|
56
|
+
|
|
57
|
+
const now = eat.now();
|
|
58
|
+
const offset = match.length - text.length;
|
|
59
|
+
now.column += offset;
|
|
60
|
+
now.offset += offset;
|
|
61
|
+
const children = this.tokenizeInline(text, now);
|
|
62
|
+
|
|
63
|
+
const add = eat(match);
|
|
64
|
+
|
|
65
|
+
return add({
|
|
66
|
+
type: 'component',
|
|
67
|
+
componentName: 'eui-markdown-format/markdown-checkbox',
|
|
68
|
+
lead,
|
|
69
|
+
label: text,
|
|
70
|
+
isChecked,
|
|
71
|
+
inline: true,
|
|
72
|
+
children
|
|
73
|
+
} as CheckboxNodeDetails);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
tokenizers.checkbox = tokenizeCheckbox;
|
|
77
|
+
methods.splice(methods.indexOf('list'), 0, 'checkbox'); // Run it just before default `list` plugin to inject our own idea of checkboxes.
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export { CheckboxParser as parser };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed to Elasticsearch B.V. under one or more contributor
|
|
3
|
+
* license agreements. See the NOTICE file distributed with
|
|
4
|
+
* this work for additional information regarding copyright
|
|
5
|
+
* ownership. Elasticsearch B.V. licenses this file to you under
|
|
6
|
+
* the Apache License, Version 2.0 (the "License"); you may
|
|
7
|
+
* not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing,
|
|
13
|
+
* software distributed under the License is distributed on an
|
|
14
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
|
+
* KIND, either express or implied. See the License for the
|
|
16
|
+
* specific language governing permissions and limitations
|
|
17
|
+
* under the License.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// Importing seemingly unused types from `unified` because the definitions
|
|
21
|
+
// are exported for two versions of TypeScript (3.4, 4.0) and implicit
|
|
22
|
+
// imports during eui.d.ts generation default to the incorrect version (3.4).
|
|
23
|
+
// Explicit imports here resolve the version mismatch.
|
|
24
|
+
import {
|
|
25
|
+
PluggableList,
|
|
26
|
+
// @ts-ignore See above comment
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
28
|
+
Attacher,
|
|
29
|
+
// @ts-ignore See above comment
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
31
|
+
Pluggable,
|
|
32
|
+
// @ts-ignore See above comment
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
34
|
+
Settings
|
|
35
|
+
} from 'unified';
|
|
36
|
+
import remark2Rehype from 'remark-rehype';
|
|
37
|
+
import { RehypeNode } from '../markdown-types';
|
|
38
|
+
// import * as MarkdownTooltip from './markdown_tooltip';
|
|
39
|
+
// import * as MarkdownCheckbox from './markdown_checkbox';
|
|
40
|
+
// import { markdownLinkValidator } from './markdown_link_validator';
|
|
41
|
+
// import { EuiLink } from '../../link';
|
|
42
|
+
// import { EuiCodeBlock, EuiCode } from '../../code';
|
|
43
|
+
import markdown from 'remark-parse';
|
|
44
|
+
import emoji from 'remark-emoji';
|
|
45
|
+
import all from 'mdast-util-to-hast/lib/all';
|
|
46
|
+
import { Handler } from 'mdast-util-to-hast';
|
|
47
|
+
import * as MarkdownCheckbox from '../plugins/markdown-checkbox';
|
|
48
|
+
import MarkdownAddComponents from '../plugins/markdown-add-components';
|
|
49
|
+
import breaks from 'remark-breaks';
|
|
50
|
+
import highlight from 'remark-highlight.js';
|
|
51
|
+
import * as MarkdownTooltip from '../plugins/markdown-tooltip';
|
|
52
|
+
|
|
53
|
+
export type DefaultEuiMarkdownParsingPlugins = PluggableList;
|
|
54
|
+
|
|
55
|
+
export const getDefaultEuiMarkdownParsingPlugins =
|
|
56
|
+
(): DefaultEuiMarkdownParsingPlugins => [
|
|
57
|
+
[markdown, {}],
|
|
58
|
+
[highlight, {}],
|
|
59
|
+
[emoji, { emoticon: false }],
|
|
60
|
+
//@ts-ignore
|
|
61
|
+
[breaks, {}],
|
|
62
|
+
[MarkdownTooltip.parser, {}],
|
|
63
|
+
[MarkdownCheckbox.parser, {}]
|
|
64
|
+
// [MarkdownCheckbox.parser, {}],
|
|
65
|
+
// [markdownLinkValidator, {}]
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
const unknownHandler: Handler = (h, node) => {
|
|
69
|
+
return h(node, node.type, node, all(h, node));
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const defaultParsingPlugins = getDefaultEuiMarkdownParsingPlugins();
|
|
73
|
+
|
|
74
|
+
class Compiler {
|
|
75
|
+
tree: RehypeNode | null = null;
|
|
76
|
+
constructor(tree: RehypeNode) {
|
|
77
|
+
this.tree = tree;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
compile() {
|
|
81
|
+
return this.tree;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function compiler() {
|
|
86
|
+
//@ts-expect-error
|
|
87
|
+
this.Compiler = Compiler;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const getDefaultEuiMarkdownProcessingPlugins = (): [
|
|
91
|
+
[typeof remark2Rehype, Record<string, unknown>],
|
|
92
|
+
...PluggableList // any additional are generic
|
|
93
|
+
] => [
|
|
94
|
+
[remark2Rehype, { allowDangerousHtml: true, unknownHandler }],
|
|
95
|
+
[MarkdownAddComponents, {}],
|
|
96
|
+
[compiler]
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
export const defaultProcessingPlugins =
|
|
100
|
+
getDefaultEuiMarkdownProcessingPlugins();
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { RemarkTokenizer } from '../markdown-types';
|
|
2
|
+
import { Plugin } from 'unified';
|
|
3
|
+
|
|
4
|
+
interface TooltipNodeDetails {
|
|
5
|
+
type: 'component';
|
|
6
|
+
tooltipText: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const tooltipPlugin = {
|
|
10
|
+
name: 'tooltipPlugin',
|
|
11
|
+
button: {
|
|
12
|
+
label: 'Tooltip',
|
|
13
|
+
iconType: 'editorComment'
|
|
14
|
+
},
|
|
15
|
+
formatting: {
|
|
16
|
+
prefix: '!{tooltip[',
|
|
17
|
+
suffix: ']()}',
|
|
18
|
+
trimFirst: true
|
|
19
|
+
},
|
|
20
|
+
helpText: `
|
|
21
|
+
\`\`\`md
|
|
22
|
+
!{tooltip[anchor text](helpful description)}
|
|
23
|
+
\`\`\`
|
|
24
|
+
`
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const TooltipParser: Plugin = function TooltipParser() {
|
|
28
|
+
const Parser = this.Parser;
|
|
29
|
+
const tokenizers = Parser.prototype.inlineTokenizers;
|
|
30
|
+
const methods = Parser.prototype.inlineMethods;
|
|
31
|
+
|
|
32
|
+
const tokenizeTooltip: RemarkTokenizer = function tokenizeTooltip(
|
|
33
|
+
eat,
|
|
34
|
+
value,
|
|
35
|
+
silent
|
|
36
|
+
) {
|
|
37
|
+
if (value.startsWith('!{tooltip') === false) return false;
|
|
38
|
+
|
|
39
|
+
const nextChar = value[9];
|
|
40
|
+
|
|
41
|
+
if (nextChar !== '[') return false; // this isn't actually a tooltip
|
|
42
|
+
|
|
43
|
+
let index = 9;
|
|
44
|
+
function readArg(open: string, close: string) {
|
|
45
|
+
if (value[index] !== open) throw 'Expected left bracket';
|
|
46
|
+
index++;
|
|
47
|
+
|
|
48
|
+
let body = '';
|
|
49
|
+
let openBrackets = 0;
|
|
50
|
+
|
|
51
|
+
for (; index < value.length; index++) {
|
|
52
|
+
const char = value[index];
|
|
53
|
+
|
|
54
|
+
if (char === close && openBrackets === 0) {
|
|
55
|
+
index++;
|
|
56
|
+
return body;
|
|
57
|
+
} else if (char === close) {
|
|
58
|
+
openBrackets--;
|
|
59
|
+
} else if (char === open) {
|
|
60
|
+
openBrackets++;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
body += char;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return '';
|
|
67
|
+
}
|
|
68
|
+
const tooltipAnchor = readArg('[', ']');
|
|
69
|
+
const tooltipText = readArg('(', ')');
|
|
70
|
+
|
|
71
|
+
const now = eat.now();
|
|
72
|
+
|
|
73
|
+
if (!tooltipAnchor) {
|
|
74
|
+
this.file.info('No tooltip anchor found', {
|
|
75
|
+
line: now.line,
|
|
76
|
+
column: now.column + 10
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (!tooltipText) {
|
|
80
|
+
this.file.info('No tooltip text found', {
|
|
81
|
+
line: now.line,
|
|
82
|
+
column: now.column + 12 + tooltipAnchor.length
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!tooltipText || !tooltipAnchor) return false;
|
|
87
|
+
|
|
88
|
+
if (silent) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
now.column += 10;
|
|
93
|
+
now.offset += 10;
|
|
94
|
+
const children = this.tokenizeInline(tooltipAnchor, now);
|
|
95
|
+
|
|
96
|
+
return eat(`!{tooltip[${tooltipAnchor}](${tooltipText})}`)({
|
|
97
|
+
type: 'component',
|
|
98
|
+
componentName: 'eui-markdown-format/markdown-tooltip',
|
|
99
|
+
tooltipText: tooltipText,
|
|
100
|
+
children
|
|
101
|
+
} as TooltipNodeDetails);
|
|
102
|
+
};
|
|
103
|
+
tokenizeTooltip.notInLink = true;
|
|
104
|
+
|
|
105
|
+
tokenizeTooltip.locator = (value, fromIndex) => {
|
|
106
|
+
return value.indexOf('!{tooltip', fromIndex);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
tokenizers.tooltip = tokenizeTooltip;
|
|
110
|
+
methods.splice(methods.indexOf('text'), 0, 'tooltip');
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export { tooltipPlugin as plugin, TooltipParser as parser };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { assert } from '@ember/debug';
|
|
2
|
+
import { RehypeNode } from '../markdown-types';
|
|
3
|
+
|
|
4
|
+
const attributes = ['src', 'alt', 'href', 'target'];
|
|
5
|
+
|
|
6
|
+
const createDocument = () => {
|
|
7
|
+
return document;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export interface DynamicComponent {}
|
|
11
|
+
|
|
12
|
+
export const toDOM = (tree: RehypeNode) => {
|
|
13
|
+
let document = createDocument();
|
|
14
|
+
let components: DynamicComponent[] = [];
|
|
15
|
+
|
|
16
|
+
const toElements = (parent: Node, nodes: RehypeNode[] = []) => {
|
|
17
|
+
nodes?.forEach((node) => {
|
|
18
|
+
let el = toElement(node);
|
|
19
|
+
if (el) {
|
|
20
|
+
parent.appendChild(el);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return parent;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const createElement = (
|
|
27
|
+
name: string,
|
|
28
|
+
node: RehypeNode,
|
|
29
|
+
className?: string
|
|
30
|
+
) => {
|
|
31
|
+
let element = document.createElement(name);
|
|
32
|
+
let properties = node.properties;
|
|
33
|
+
let classNames = [];
|
|
34
|
+
if (properties) {
|
|
35
|
+
if (properties.className) {
|
|
36
|
+
classNames.push(...(properties.className as string[]));
|
|
37
|
+
}
|
|
38
|
+
for (let key in properties) {
|
|
39
|
+
if (attributes.includes(key)) {
|
|
40
|
+
let value = properties[key];
|
|
41
|
+
element.setAttribute(key, value as string);
|
|
42
|
+
} else {
|
|
43
|
+
// temporary
|
|
44
|
+
if (key !== 'className') {
|
|
45
|
+
console.warn('Unmapped node property', key);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (className) {
|
|
51
|
+
classNames.push(className);
|
|
52
|
+
}
|
|
53
|
+
if (classNames.length) {
|
|
54
|
+
element.setAttribute('class', classNames.join(' '));
|
|
55
|
+
}
|
|
56
|
+
return element;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const toElement = (node: RehypeNode) => {
|
|
60
|
+
if (node) {
|
|
61
|
+
let { type } = node;
|
|
62
|
+
if (type === 'root') {
|
|
63
|
+
let element = createElement('div', node, 'root');
|
|
64
|
+
return toElements(element, node.children);
|
|
65
|
+
} else if (type === 'element') {
|
|
66
|
+
let element = createElement(node.tagName, node);
|
|
67
|
+
return toElements(element, node.children);
|
|
68
|
+
} else if (type === 'text') {
|
|
69
|
+
return document.createTextNode(node.value);
|
|
70
|
+
} else if (type === 'component') {
|
|
71
|
+
let { inline } = node.properties;
|
|
72
|
+
let element = createElement(inline ? 'span' : 'div', node, 'component');
|
|
73
|
+
let { _children, ...properties } = node.properties;
|
|
74
|
+
let content = toElements(document.createElement('span'), node.children);
|
|
75
|
+
components.push({
|
|
76
|
+
element,
|
|
77
|
+
content,
|
|
78
|
+
...properties
|
|
79
|
+
});
|
|
80
|
+
return element;
|
|
81
|
+
}
|
|
82
|
+
assert(`Unsupported node '${type}'`, false);
|
|
83
|
+
}
|
|
84
|
+
return;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
let element = toElement(tree);
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
element,
|
|
91
|
+
components
|
|
92
|
+
};
|
|
93
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-code';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-code-block';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-code-block-impl/code-block-controls';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-code-block-impl';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-copy';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-inner-text';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-markdown-editor';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-markdown-editor-drop-zone';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-markdown-editor-footer';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-markdown-editor-text-area';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-markdown-editor-toolbar';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-markdown-format';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-markdown-format/markdown-checkbox';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-markdown-format/markdown-code';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-markdown-format/markdown-code-block';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/components/eui-markdown-format/markdown-tooltip';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@ember-eui/core/modifiers/get-cursor-node';
|