@ember-eui/core 1.2.6 → 1.4.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 (78) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/addon/components/common.ts +13 -0
  3. package/addon/components/eui-button/index.hbs +2 -0
  4. package/addon/components/eui-button-content/index.hbs +1 -0
  5. package/addon/components/eui-button-empty/index.hbs +2 -0
  6. package/addon/components/eui-button-icon/index.hbs +2 -0
  7. package/addon/components/eui-code/index.hbs +9 -0
  8. package/addon/components/eui-code-block/index.d.ts +2 -0
  9. package/addon/components/eui-code-block/index.hbs +10 -0
  10. package/addon/components/eui-code-block-impl/code-block-controls/index.hbs +33 -0
  11. package/addon/components/eui-code-block-impl/index.hbs +111 -0
  12. package/addon/components/eui-code-block-impl/index.ts +121 -0
  13. package/addon/components/eui-copy/index.hbs +8 -0
  14. package/addon/components/eui-copy/index.ts +37 -0
  15. package/addon/components/eui-icon/index.hbs +37 -32
  16. package/addon/components/eui-icon/index.ts +1 -1
  17. package/addon/components/eui-inner-text/index.hbs +1 -0
  18. package/addon/components/eui-inner-text/index.ts +61 -0
  19. package/addon/components/eui-markdown-editor/index.hbs +63 -0
  20. package/addon/components/eui-markdown-editor/index.ts +221 -0
  21. package/addon/components/eui-markdown-editor-drop-zone/index.hbs +21 -0
  22. package/addon/components/eui-markdown-editor-drop-zone/index.ts +5 -0
  23. package/addon/components/eui-markdown-editor-footer/index.hbs +108 -0
  24. package/addon/components/eui-markdown-editor-footer/index.ts +20 -0
  25. package/addon/components/eui-markdown-editor-text-area/index.hbs +8 -0
  26. package/addon/components/eui-markdown-editor-toolbar/index.hbs +86 -0
  27. package/addon/components/eui-markdown-editor-toolbar/index.ts +97 -0
  28. package/addon/components/eui-markdown-format/index.hbs +13 -0
  29. package/addon/components/eui-markdown-format/index.ts +55 -0
  30. package/addon/components/eui-markdown-format/markdown-checkbox/index.hbs +8 -0
  31. package/addon/components/eui-markdown-format/markdown-checkbox/index.ts +28 -0
  32. package/addon/components/eui-markdown-format/markdown-code/index.hbs +3 -0
  33. package/addon/components/eui-markdown-format/markdown-code-block/index.hbs +7 -0
  34. package/addon/components/eui-markdown-format/markdown-tooltip/index.hbs +8 -0
  35. package/addon/components/markdown-checkmark-icon/index.hbs +0 -0
  36. package/addon/modifiers/get-cursor-node.ts +54 -0
  37. package/addon/modifiers/resize-observer.ts +6 -2
  38. package/addon/utils/copy-to-clipboard.ts +70 -0
  39. package/addon/utils/css-mappings/eui-code-block-impl.ts +24 -0
  40. package/addon/utils/css-mappings/index.ts +2 -0
  41. package/addon/utils/markdown/markdown-actions.ts +616 -0
  42. package/addon/utils/markdown/markdown-modes.ts +23 -0
  43. package/addon/utils/markdown/markdown-types.ts +140 -0
  44. package/addon/utils/markdown/markdown-unified-plugins.d.ts +27 -0
  45. package/addon/utils/markdown/plugins/markdown-add-components.ts +63 -0
  46. package/addon/utils/markdown/plugins/markdown-checkbox.ts +80 -0
  47. package/addon/utils/markdown/plugins/markdown-default-plugins.ts +77 -0
  48. package/addon/utils/markdown/plugins/markdown-tooltip.ts +113 -0
  49. package/addon/utils/markdown/plugins/to-dom.ts +93 -0
  50. package/app/components/eui-code/index.js +1 -0
  51. package/app/components/eui-code-block/index.js +1 -0
  52. package/app/components/eui-code-block-impl/code-block-controls/index.js +1 -0
  53. package/app/components/eui-code-block-impl/index.js +1 -0
  54. package/app/components/eui-copy/index.js +1 -0
  55. package/app/components/eui-inner-text/index.js +1 -0
  56. package/app/components/eui-markdown-editor/index.js +1 -0
  57. package/app/components/eui-markdown-editor-drop-zone/index.js +1 -0
  58. package/app/components/eui-markdown-editor-footer/index.js +1 -0
  59. package/app/components/eui-markdown-editor-text-area/index.js +1 -0
  60. package/app/components/eui-markdown-editor-toolbar/index.js +1 -0
  61. package/app/components/eui-markdown-format/index.js +1 -0
  62. package/app/components/eui-markdown-format/markdown-checkbox/index.js +1 -0
  63. package/app/components/eui-markdown-format/markdown-code/index.js +1 -0
  64. package/app/components/eui-markdown-format/markdown-code-block/index.js +1 -0
  65. package/app/components/eui-markdown-format/markdown-tooltip/index.js +1 -0
  66. package/app/modifiers/get-cursor-node.js +1 -0
  67. package/app/styles/ember-eui.scss +13 -0
  68. package/app/utils/markdown/plugins/markdown-add-components.js +1 -0
  69. package/app/utils/markdown/plugins/markdown-default-plugins.js +1 -0
  70. package/docs/editors/code/code-block-demo/demo1.md +62 -0
  71. package/docs/editors/code/code-block.md +1 -0
  72. package/docs/editors/code/inline-demo/demo1.md +49 -0
  73. package/docs/editors/code/inline.md +1 -0
  74. package/docs/editors/markdown-editor/base-editor-demo/demo1.md +120 -0
  75. package/docs/editors/markdown-editor/base-editor.md +1 -0
  76. package/package.json +16 -3
  77. package/public/markdown-checkmark.svg +3 -0
  78. package/public/markdown-logo.svg +3 -0
@@ -0,0 +1,221 @@
1
+ import Component from '@glimmer/component';
2
+ import { action } from '@ember/object';
3
+ import { cached, tracked } from '@glimmer/tracking';
4
+ import { argOrDefaultDecorator as argOrDefault } from '../../helpers/arg-or-default';
5
+ import MarkdownActions from '../../utils/markdown/markdown-actions';
6
+ import {
7
+ MODE_EDITING,
8
+ MODE_VIEWING
9
+ } from '../../utils/markdown/markdown-modes';
10
+ import {
11
+ defaultParsingPlugins,
12
+ defaultProcessingPlugins
13
+ } from '../../utils/markdown/plugins/markdown-default-plugins';
14
+ import { uniqueId } from '../../helpers/unique-id';
15
+ import unified from 'unified';
16
+ import * as MarkdownTooltipPlugin from '../../utils/markdown/plugins/markdown-tooltip';
17
+ import {
18
+ EuiMarkdownEditorUiPlugin,
19
+ EuiMarkdownAstNodePosition,
20
+ EuiMarkdownAstNode
21
+ } from '../../utils/markdown/markdown-types';
22
+ import { Processor } from 'unified';
23
+
24
+ export interface EuiMarkdownEditorArgs {
25
+ initialViewMode?: string;
26
+ editorId?: string;
27
+ uiPlugins: EuiMarkdownEditorUiPlugin[];
28
+ value: string;
29
+ onChange: (str: string) => void;
30
+ onParse: (
31
+ parseError: string | null,
32
+ parsed: { messages: string[]; ast: EuiMarkdownAstNode }
33
+ ) => void;
34
+ }
35
+
36
+ // function isNewLine(char: string | undefined): boolean {
37
+ // if (char == null) return true;
38
+ // return !!char.match(/[\r\n]/);
39
+ // }
40
+ // function padWithNewlinesIfNeeded(textarea: HTMLTextAreaElement, text: string) {
41
+ // const selectionStart = textarea.selectionStart;
42
+ // const selectionEnd = textarea.selectionEnd;
43
+
44
+ // // block parsing requires two leading new lines and none trailing, but we add an extra trailing line for readability
45
+ // const isPrevNewLine = isNewLine(textarea.value[selectionStart - 1]);
46
+ // const isPrevPrevNewLine = isNewLine(textarea.value[selectionStart - 2]);
47
+ // const isNextNewLine = isNewLine(textarea.value[selectionEnd]);
48
+
49
+ // // pad text with newlines as needed
50
+ // text = `${isPrevNewLine ? '' : '\n'}${isPrevPrevNewLine ? '' : '\n'}${text}${
51
+ // isNextNewLine ? '' : '\n'
52
+ // }`;
53
+ // return text;
54
+ // }
55
+
56
+ export default class EuiMarkdownEditorComponent extends Component<EuiMarkdownEditorArgs> {
57
+ // Defaults
58
+ @argOrDefault(defaultParsingPlugins)
59
+ declare parsingPluginList: typeof defaultParsingPlugins;
60
+
61
+ @argOrDefault(250) declare height: number | string;
62
+ @argOrDefault(500) declare maxHeight: number | string;
63
+ @argOrDefault(true) declare autoExpandPreview: boolean;
64
+
65
+ @argOrDefault(defaultProcessingPlugins)
66
+ declare processingPluginList: typeof defaultProcessingPlugins;
67
+
68
+ @tracked selectedNode: Node | null = null;
69
+ @tracked editorId = this.args.editorId ?? uniqueId();
70
+ @tracked viewMode = this.args.initialViewMode || MODE_EDITING;
71
+ @tracked textareaRef: HTMLTextAreaElement | null = null;
72
+ @tracked previewRef: HTMLDivElement | null = null;
73
+ @tracked editorToolbarRef: HTMLDivElement | null = null;
74
+ @tracked currentHeight: number | string = 250;
75
+ @tracked editorFooterHeight: number = 0;
76
+ @tracked editorToolbarHeight: number = 0;
77
+
78
+ markdownActions: MarkdownActions | null = null;
79
+
80
+ get toolbarPlugins() {
81
+ return [MarkdownTooltipPlugin.plugin, ...(this.args.uiPlugins || [])];
82
+ }
83
+
84
+ constructor(owner: unknown, args: EuiMarkdownEditorArgs) {
85
+ super(owner, args);
86
+ this.markdownActions = new MarkdownActions(
87
+ this.editorId,
88
+ this.toolbarPlugins
89
+ );
90
+ this.currentHeight = this.height;
91
+ }
92
+
93
+ get previewHeight() {
94
+ if (this.height === 'full') {
95
+ return `calc(100% - ${this.editorFooterHeight}px)`;
96
+ }
97
+ return `${this.currentHeight}px`;
98
+ }
99
+
100
+ get textAreaHeight() {
101
+ return this.height === 'full'
102
+ ? '100%'
103
+ : `calc(${(this.height as number) - this.editorFooterHeight}px)`;
104
+ }
105
+
106
+ get textAreaMaxHeight() {
107
+ return this.height !== 'full'
108
+ ? `${(this.maxHeight as number) - this.editorFooterHeight}px`
109
+ : '';
110
+ }
111
+
112
+ get editorToggleContainerHeight() {
113
+ return `calc(100% - ${this.editorToolbarHeight}px)`;
114
+ }
115
+
116
+ @action
117
+ onResize() {
118
+ if (this.textareaRef && this.isEditing && this.height !== 'full') {
119
+ const resizedTextareaHeight =
120
+ this.textareaRef.offsetHeight + this.editorFooterHeight;
121
+
122
+ this.currentHeight = resizedTextareaHeight;
123
+ }
124
+ }
125
+
126
+ @action
127
+ updateCurrentHeight() {
128
+ let { isPreviewing, autoExpandPreview, height, previewRef, currentHeight } =
129
+ this;
130
+ if (isPreviewing && autoExpandPreview && height !== 'full' && previewRef) {
131
+ if (previewRef.scrollHeight > currentHeight) {
132
+ // scrollHeight does not include the border or margin
133
+ // so we ask for the computed value for those,
134
+ // which is always in pixels because getComputedValue
135
+ // returns the resolved values
136
+ const elementComputedStyle = window.getComputedStyle(previewRef);
137
+ const borderWidth =
138
+ parseFloat(elementComputedStyle.borderTopWidth) +
139
+ parseFloat(elementComputedStyle.borderBottomWidth);
140
+ const marginWidth =
141
+ parseFloat(elementComputedStyle.marginTop) +
142
+ parseFloat(elementComputedStyle.marginBottom);
143
+
144
+ // then add an extra pixel for safety and because the scrollHeight value is rounded
145
+ const extraHeight = borderWidth + marginWidth + 1;
146
+
147
+ this.currentHeight = previewRef.scrollHeight + extraHeight;
148
+ }
149
+ }
150
+ }
151
+
152
+ @action
153
+ setTextAreaRef(ref: HTMLTextAreaElement) {
154
+ this.textareaRef = ref;
155
+ }
156
+
157
+ @action
158
+ setEditorToolbarRef(ref: HTMLDivElement) {
159
+ this.editorToolbarRef = ref;
160
+ this.editorToolbarHeight = ref.offsetHeight;
161
+ }
162
+
163
+ @action
164
+ replaceNode(position: EuiMarkdownAstNodePosition, next: string) {
165
+ let value = this.args.value;
166
+ const leading = value.substr(0, position.start.offset);
167
+ const trailing = value.substr(position.end.offset);
168
+ this.args.onChange?.(`${leading}${next}${trailing}`);
169
+ }
170
+
171
+ get isEditing() {
172
+ return this.viewMode === MODE_EDITING;
173
+ }
174
+
175
+ get isPreviewing() {
176
+ return this.viewMode === MODE_VIEWING;
177
+ }
178
+
179
+ @action
180
+ setViewMode() {
181
+ this.viewMode = this.isPreviewing ? MODE_EDITING : MODE_VIEWING;
182
+ }
183
+
184
+ @cached
185
+ get parser() {
186
+ const Compiler = (tree: any) => {
187
+ return tree;
188
+ };
189
+
190
+ function identityCompiler(this: Processor) {
191
+ this.Compiler = Compiler;
192
+ }
193
+ return unified().use(this.parsingPluginList).use(identityCompiler);
194
+ }
195
+
196
+ @cached
197
+ get parsed() {
198
+ try {
199
+ const parsed = this.parser.processSync(this.args.value);
200
+ return [parsed, null];
201
+ } catch (e) {
202
+ return [null, e];
203
+ }
204
+ }
205
+
206
+ @action
207
+ onParse() {
208
+ if (this.args.onParse) {
209
+ const [parsed, parseError] = this.parsed;
210
+ const onParse = this.args.onParse;
211
+ const messages = parsed ? parsed.messages : [];
212
+ const ast = parsed ? parsed.result ?? parsed.contents : null;
213
+ onParse(parseError, { messages, ast });
214
+ }
215
+ }
216
+
217
+ @action
218
+ setSelectedNode(node: Node) {
219
+ this.selectedNode = node;
220
+ }
221
+ }
@@ -0,0 +1,21 @@
1
+ <div
2
+ class={{class-names
3
+ "euiMarkdownEditorDropZone"
4
+ (if this.isDragging "euiMarkdownEditorDropZone--isDragging")
5
+ (if @hasUnacceptedItems "euiMarkdownEditorDropZone--hasError")
6
+ (if this.isDraggingError "euiMarkdownEditorDropZone--isDraggingError")
7
+ }}
8
+ >
9
+ {{yield}}
10
+ <EuiMarkdownEditorFooter
11
+ @uiPlugins={{@uiPlugins}}
12
+ {{!-- openFiles={() => {
13
+ setHasUnacceptedItems(false);
14
+ open();
15
+ }} --}}
16
+ @isUploadingFiles={{this.isUploadingFiles}}
17
+ @hasUnacceptedItems={{@hasUnacceptedItems}}
18
+ {{! dropHandlers={dropHandlers} }}
19
+ @errors={{@errors}}
20
+ />
21
+ </div>
@@ -0,0 +1,5 @@
1
+ import Component from '@glimmer/component';
2
+
3
+ export interface EuiMarkdownEditorDropZoneArgs {}
4
+
5
+ export default class EuiMarkdownEditorDropZoneComponent extends Component<EuiMarkdownEditorDropZoneArgs> {}
@@ -0,0 +1,108 @@
1
+ <div class="euiMarkdownEditorFooter">
2
+ <div class="euiMarkdownEditorFooter__actions">
3
+
4
+ {{#if @isUploadingFiles}}
5
+ {{! pending implementation}}
6
+ <EuiButtonIcon
7
+ @iconType={{component "eui-loading-spinner"}}
8
+ {{! aria-label={ariaLabels.uploadingFiles} }}
9
+ />
10
+ {{/if}}
11
+ {{#if (and @errors @errors.length)}}
12
+ <EuiPopover
13
+ @isOpen={{this.isPopoverOpen}}
14
+ @closePopover={{set this "isPopoverOpen" false}}
15
+ >
16
+ <:button>
17
+ <EuiButtonEmpty
18
+ @iconType="crossInACircleFilled"
19
+ @size="s"
20
+ @color="danger"
21
+ {{! aria-label={ariaLabels.showSyntaxErrors} }}
22
+ {{on "click" (set this "isPopoverOpen" (not this.isPopoverOpen))}}
23
+ >
24
+ {{@errors.length}}
25
+ </EuiButtonEmpty>
26
+ </:button>
27
+ </EuiPopover>
28
+ {{/if}}
29
+ </div>
30
+ <EuiButtonIcon
31
+ class="euiMarkdownEditorFooter__help"
32
+ @iconType={{this.markdownLogo}}
33
+ @color="text"
34
+ @useSvg={{true}}
35
+ {{! aria-label={ariaLabels.showMarkdownHelp} }}
36
+ {{on "click" (set this "isShowingHelp" (not this.isShowingHelp))}}
37
+ />
38
+
39
+ {{#if this.isShowingHelp}}
40
+ <EuiOverlayMask>
41
+ <EuiModal @onClose={{set this "isShowingHelp" false}}>
42
+ <EuiModalHeader>
43
+ <EuiTitle>
44
+ <h3>
45
+ Syntax Help
46
+ {{! <EuiI18n
47
+ token="euiMarkdownEditorFooter.syntaxTitle"
48
+ default="Syntax help"
49
+ /> }}
50
+ </h3>
51
+ </EuiTitle>
52
+ </EuiModalHeader>
53
+ <EuiModalBody>
54
+
55
+ <EuiText>
56
+ <p>The editor uses</p>
57
+ <a
58
+ href="https://github.github.com/gfm/"
59
+ target="_blank"
60
+ rel="noreferrer noopener"
61
+ >
62
+ Github flavored markdown
63
+ </a>
64
+ <p>You can also utilize these additional syntax plugins to add rich
65
+ content to yoru text.</p>
66
+
67
+ {{! <EuiI18n
68
+ tokens={[
69
+ 'euiMarkdownEditorFooter.descriptionPrefix',
70
+ 'euiMarkdownEditorFooter.descriptionSuffix',
71
+ ]}
72
+ defaults={[
73
+ 'This editor uses',
74
+ 'You can also utilize these additional syntax plugins to add rich content to your text.',
75
+ ]}>
76
+ {([descriptionPrefix, descriptionSuffix]: ReactChild[]) => (
77
+ <p>
78
+ {descriptionPrefix}{' '}
79
+ <a
80
+ href="https://github.github.com/gfm/"
81
+ target="_blank">
82
+ Github flavored markdown
83
+ </a>
84
+ . {descriptionSuffix}
85
+ </p>
86
+ )}
87
+ </EuiI18n> }}
88
+ </EuiText>
89
+ <EuiHorizontalRule />
90
+ {{#each @uiPlugins as |uiPlugin|}}
91
+ {{#if uiPlugin.helpText}}
92
+ <EuiTitle size="xxs">
93
+ <p>
94
+ <strong>{{uiPlugin.name}}</strong>
95
+ </p>
96
+ </EuiTitle>
97
+ <EuiSpacer size="s" />
98
+ <EuiMarkdownFormat @value={{uiPlugin.helpText}} />
99
+ <EuiSpacer size="l" />
100
+
101
+ {{/if}}
102
+ {{/each}}
103
+ </EuiModalBody>
104
+ </EuiModal>
105
+ </EuiOverlayMask>
106
+
107
+ {{/if}}
108
+ </div>
@@ -0,0 +1,20 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { getOwner } from '@ember/application';
4
+
5
+ export interface EuiMarkdownEditorFooterArgs {}
6
+
7
+ export default class EuiMarkdownEditorFooterComponent extends Component<EuiMarkdownEditorFooterArgs> {
8
+ @tracked isPopoverOpen = false;
9
+ @tracked isShowingHelp = false;
10
+
11
+ get svgPath() {
12
+ const config = getOwner(this).resolveRegistration('config:environment');
13
+ const svgPath = config?.['@ember-eui/core']?.svgPath || 'svg/';
14
+ return svgPath;
15
+ }
16
+
17
+ get markdownLogo() {
18
+ return `${this.svgPath}markdown-logo`;
19
+ }
20
+ }
@@ -0,0 +1,8 @@
1
+ <textarea
2
+ class="euiMarkdownEditorTextArea"
3
+ rows="6"
4
+ ...attributes
5
+ {{style (hash height=@height maxHeight=@maxHeight)}}
6
+ >
7
+ {{yield}}
8
+ </textarea>
@@ -0,0 +1,86 @@
1
+ <div class="euiMarkdownEditorToolbar">
2
+ <div class="euiMarkdownEditorToolbar__buttons">
3
+ {{#each this.boldItalicsButtons as |item|}}
4
+ <EuiToolTip @content={{item.label}} @delay="long">
5
+ <EuiButtonIcon
6
+ @color="text"
7
+ {{on "click" (fn this.handleMdButtonClick item.id)}}
8
+ @iconType={{item.iconType}}
9
+ aria-label={{item.label}}
10
+ @isDisabled={{this.isPreviewing}}
11
+ />
12
+ </EuiToolTip>
13
+
14
+ {{/each}}
15
+ <span className="euiMarkdownEditorToolbar__divider"></span>
16
+ {{#each this.listButtons as |item|}}
17
+ <EuiToolTip @content={{item.label}} @delay="long">
18
+ <EuiButtonIcon
19
+ @color="text"
20
+ {{on "click" (fn this.handleMdButtonClick item.id)}}
21
+ @iconType={{item.iconType}}
22
+ aria-label={{item.label}}
23
+ @useSvg={{item.useSvg}}
24
+ @isDisabled={{this.isPreviewing}}
25
+ />
26
+ </EuiToolTip>
27
+
28
+ {{/each}}
29
+ <span className="euiMarkdownEditorToolbar__divider"></span>
30
+ {{#each this.quoteCodeLinkButtons as |item|}}
31
+ <EuiToolTip @content={{item.label}} @delay="long">
32
+ <EuiButtonIcon
33
+ @color="text"
34
+ {{on "click" (fn this.handleMdButtonClick item.id)}}
35
+ @iconType={{item.iconType}}
36
+ aria-label={{item.label}}
37
+ @isDisabled={{this.isPreviewing}}
38
+ />
39
+ </EuiToolTip>
40
+
41
+ {{/each}}
42
+ {{#if (gte this.uiPlugins.length 0)}}
43
+ <span className="euiMarkdownEditorToolbar__divider"></span>
44
+ {{#each this.uiPlugins as |plugin|}}
45
+ {{#let
46
+ (and @selectedNode (eq @selectedNode.type plugin.name))
47
+ as |isSelectedNodeType|
48
+ }}
49
+ <EuiToolTip @content={{plugin.button.label}} @delay="long">
50
+ <EuiButtonIcon
51
+ @color="text"
52
+ {{style
53
+ (if isSelectedNodeType (hash background="rgba(0, 0, 0, 0.15)"))
54
+ }}
55
+ {{on "click" (fn this.handleMdButtonClick plugin.name)}}
56
+ @iconType={{plugin.button.iconType}}
57
+ aria-label={{plugin.button.label}}
58
+ @isDisabled={{this.isPreviewing}}
59
+ />
60
+ </EuiToolTip>
61
+ {{/let}}
62
+ {{/each}}
63
+ {{/if}}
64
+ </div>
65
+
66
+ {{#if this.isPreviewing}}
67
+ <EuiButtonEmpty
68
+ @iconType="editorCodeBlock"
69
+ @color="text"
70
+ @size="s"
71
+ {{on "click" @onClickPreview}}
72
+ >
73
+ Editor
74
+ </EuiButtonEmpty>
75
+
76
+ {{else}}
77
+ <EuiButtonEmpty
78
+ @iconType="eye"
79
+ @color="text"
80
+ @size="s"
81
+ {{on "click" @onClickPreview}}
82
+ >
83
+ Preview
84
+ </EuiButtonEmpty>
85
+ {{/if}}
86
+ </div>
@@ -0,0 +1,97 @@
1
+ import Component from '@glimmer/component';
2
+ import { action } from '@ember/object';
3
+ import type MarkdownActions from '../../utils/markdown/markdown-actions';
4
+ import { MODE_VIEWING } from '../../utils/markdown/markdown-modes';
5
+ import { cached } from '@glimmer/tracking';
6
+ import { getOwner } from '@ember/application';
7
+ import { Plugin } from 'unified';
8
+
9
+ export interface EuiMarkdownEditorToolbarArgs {
10
+ viewMode?: string;
11
+ markdownActions: MarkdownActions;
12
+ uiPlugins: Plugin[];
13
+ openPluginEditor?: (actionResult: ReturnType<MarkdownActions['do']>) => void;
14
+ }
15
+
16
+ export default class EuiMarkdownEditorToolbarComponent extends Component<EuiMarkdownEditorToolbarArgs> {
17
+ boldItalicButtons = [
18
+ {
19
+ id: 'mdBold',
20
+ label: 'Bold',
21
+ name: 'bold',
22
+ iconType: 'editorBold'
23
+ },
24
+ {
25
+ id: 'mdItalic',
26
+ label: 'Italic',
27
+ name: 'italic',
28
+ iconType: 'editorItalic'
29
+ }
30
+ ];
31
+
32
+ get svgPath() {
33
+ const config = getOwner(this).resolveRegistration('config:environment');
34
+ const svgPath = config?.['@ember-eui/core']?.svgPath || 'svg/';
35
+ return svgPath;
36
+ }
37
+
38
+ @cached
39
+ get listButtons() {
40
+ return [
41
+ {
42
+ id: 'mdUl',
43
+ label: 'Unordered list',
44
+ name: 'ul',
45
+ iconType: 'editorUnorderedList'
46
+ },
47
+ {
48
+ id: 'mdOl',
49
+ label: 'Ordered list',
50
+ name: 'ol',
51
+ iconType: 'editorOrderedList'
52
+ },
53
+ {
54
+ id: 'mdTl',
55
+ label: 'Task list',
56
+ name: 'tl',
57
+ useSvg: true,
58
+ iconType: `${this.svgPath}markdown-checkmark`
59
+ }
60
+ ];
61
+ }
62
+
63
+ quoteCodeLinkButtons = [
64
+ {
65
+ id: 'mdQuote',
66
+ label: 'Quote',
67
+ name: 'quote',
68
+ iconType: 'quote'
69
+ },
70
+ {
71
+ id: 'mdCode',
72
+ label: 'Code',
73
+ name: 'code',
74
+ iconType: 'editorCodeBlock'
75
+ },
76
+ {
77
+ id: 'mdLink',
78
+ label: 'Link',
79
+ name: 'link',
80
+ iconType: 'editorLink'
81
+ }
82
+ ];
83
+
84
+ get uiPlugins() {
85
+ return this.args.uiPlugins || [];
86
+ }
87
+
88
+ get isPreviewing() {
89
+ return this.args.viewMode === MODE_VIEWING;
90
+ }
91
+
92
+ @action
93
+ handleMdButtonClick(mdButtonId: string) {
94
+ const actionResult = this.args.markdownActions.do(mdButtonId);
95
+ if (actionResult !== true) this.args.openPluginEditor?.(actionResult);
96
+ }
97
+ }
@@ -0,0 +1,13 @@
1
+ <div class="euiMarkdownFormat">
2
+ {{this.result.element}}
3
+ {{#each this.result.components as |CompNode|}}
4
+ {{#in-element CompNode.element}}
5
+ {{#let (component CompNode.componentName) as |DynamicComponent|}}
6
+ <DynamicComponent
7
+ @replaceNode={{optional @replaceNode}}
8
+ @node={{CompNode}}
9
+ />
10
+ {{/let}}
11
+ {{/in-element}}
12
+ {{/each}}
13
+ </div>
@@ -0,0 +1,55 @@
1
+ import Component from '@glimmer/component';
2
+ import type MarkdownActions from '../../utils/markdown/markdown-actions';
3
+ import {
4
+ defaultParsingPlugins,
5
+ defaultProcessingPlugins
6
+ } from '../../utils/markdown/plugins/markdown-default-plugins';
7
+ import { cached } from '@glimmer/tracking';
8
+ import unified, { Processor } from 'unified';
9
+ import { toDOM } from '../../utils/markdown/plugins/to-dom';
10
+ import type { RehypeNode } from '../../utils/markdown/markdown-types';
11
+
12
+ export interface EuiMarkdownEditorToolbarArgs {
13
+ parsingPluginList?: typeof defaultParsingPlugins;
14
+ processingPluginList?: typeof defaultProcessingPlugins;
15
+ viewMode?: string;
16
+ markdownActions: MarkdownActions;
17
+ value: string;
18
+ }
19
+
20
+ export default class EuiMarkdownEditorToolbarComponent extends Component<EuiMarkdownEditorToolbarArgs> {
21
+ get parsingPluginList() {
22
+ return this.args.parsingPluginList || defaultParsingPlugins;
23
+ }
24
+
25
+ get processingPluginList() {
26
+ return this.args.processingPluginList || defaultProcessingPlugins;
27
+ }
28
+
29
+ @cached
30
+ get processor() {
31
+ const Compiler = (tree: any) => {
32
+ return tree;
33
+ };
34
+
35
+ function identityCompiler(this: Processor) {
36
+ this.Compiler = Compiler;
37
+ }
38
+ return unified()
39
+ .use(this.parsingPluginList)
40
+ .use(this.processingPluginList)
41
+ .use(identityCompiler);
42
+ }
43
+
44
+ @cached
45
+ //@ts-ignore
46
+ get result() {
47
+ try {
48
+ const processed = this.processor.processSync(this.args.value);
49
+ return toDOM(processed.result as RehypeNode);
50
+ //eslint-disable-next-line
51
+ } catch (e) {
52
+ return this.args.value;
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,8 @@
1
+ <EuiCheckbox
2
+ @checked={{@node.isChecked}}
3
+ {{on "change" this.handleChange}}
4
+ >
5
+ <:label>
6
+ {{@node.content}}
7
+ </:label>
8
+ </EuiCheckbox>
@@ -0,0 +1,28 @@
1
+ import Component from '@glimmer/component';
2
+ import { action } from '@ember/object';
3
+
4
+ interface Position {
5
+ start: Record<string, unknown>;
6
+ end: Record<string, unknown>;
7
+ }
8
+ export interface EuiMarkdownFormatMarkdownCheckboxArgs {
9
+ replaceNode(position: Position, str: string): void;
10
+ node: {
11
+ position: Position;
12
+ lead: string;
13
+ isChecked: boolean;
14
+ label: string;
15
+ };
16
+ }
17
+
18
+ export default class EuiMarkdownFormatMarkdownCheckboxComponent extends Component<EuiMarkdownFormatMarkdownCheckboxArgs> {
19
+ @action
20
+ handleChange() {
21
+ const { position, lead, isChecked, label } = this.args.node;
22
+
23
+ this.args.replaceNode(
24
+ position,
25
+ `${lead}[${isChecked ? ' ' : 'x'}]${label}`
26
+ );
27
+ }
28
+ }
@@ -0,0 +1,3 @@
1
+ <EuiCode>
2
+ {{@node.content}}
3
+ </EuiCode>
@@ -0,0 +1,7 @@
1
+ <EuiCodeBlock
2
+ @paddingSize={{@node.paddingSize}}
3
+ @fontSize={{@node.fontSize}}
4
+ @isCopyable={{true}}
5
+ >
6
+ {{@node.content}}
7
+ </EuiCodeBlock>