@ember-eui/core 1.2.3 → 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.
Files changed (78) hide show
  1. package/CHANGELOG.md +25 -4
  2. package/README.md +1 -1
  3. package/addon/components/common.ts +13 -0
  4. package/addon/components/eui-button/index.hbs +2 -0
  5. package/addon/components/eui-button-content/index.hbs +1 -0
  6. package/addon/components/eui-button-empty/index.hbs +2 -0
  7. package/addon/components/eui-button-icon/index.hbs +2 -0
  8. package/addon/components/eui-code/index.hbs +9 -0
  9. package/addon/components/eui-code-block/index.d.ts +2 -0
  10. package/addon/components/eui-code-block/index.hbs +10 -0
  11. package/addon/components/eui-code-block-impl/code-block-controls/index.hbs +33 -0
  12. package/addon/components/eui-code-block-impl/index.hbs +111 -0
  13. package/addon/components/eui-code-block-impl/index.ts +121 -0
  14. package/addon/components/eui-combo-box/index.hbs +3 -2
  15. package/addon/components/eui-combo-box/trigger/index.hbs +118 -112
  16. package/addon/components/eui-copy/index.hbs +8 -0
  17. package/addon/components/eui-copy/index.ts +37 -0
  18. package/addon/components/eui-icon/index.hbs +37 -32
  19. package/addon/components/eui-inner-text/index.hbs +1 -0
  20. package/addon/components/eui-inner-text/index.ts +61 -0
  21. package/addon/components/eui-markdown-editor/index.hbs +63 -0
  22. package/addon/components/eui-markdown-editor/index.ts +221 -0
  23. package/addon/components/eui-markdown-editor-drop-zone/index.hbs +21 -0
  24. package/addon/components/eui-markdown-editor-drop-zone/index.ts +5 -0
  25. package/addon/components/eui-markdown-editor-footer/index.hbs +108 -0
  26. package/addon/components/eui-markdown-editor-footer/index.ts +20 -0
  27. package/addon/components/eui-markdown-editor-text-area/index.hbs +8 -0
  28. package/addon/components/eui-markdown-editor-toolbar/index.hbs +86 -0
  29. package/addon/components/eui-markdown-editor-toolbar/index.ts +97 -0
  30. package/addon/components/eui-markdown-format/index.hbs +13 -0
  31. package/addon/components/eui-markdown-format/index.ts +45 -0
  32. package/addon/components/eui-markdown-format/markdown-checkbox/index.hbs +8 -0
  33. package/addon/components/eui-markdown-format/markdown-checkbox/index.ts +28 -0
  34. package/addon/components/eui-markdown-format/markdown-code/index.hbs +3 -0
  35. package/addon/components/eui-markdown-format/markdown-code-block/index.hbs +7 -0
  36. package/addon/components/eui-markdown-format/markdown-tooltip/index.hbs +8 -0
  37. package/addon/components/markdown-checkmark-icon/index.hbs +0 -0
  38. package/addon/modifiers/get-cursor-node.ts +54 -0
  39. package/addon/modifiers/resize-observer.ts +6 -2
  40. package/addon/utils/copy-to-clipboard.ts +70 -0
  41. package/addon/utils/css-mappings/eui-code-block-impl.ts +24 -0
  42. package/addon/utils/css-mappings/index.ts +2 -0
  43. package/addon/utils/markdown/markdown-actions.ts +616 -0
  44. package/addon/utils/markdown/markdown-modes.ts +23 -0
  45. package/addon/utils/markdown/markdown-types.ts +140 -0
  46. package/addon/utils/markdown/markdown-unified-plugins.d.ts +27 -0
  47. package/addon/utils/markdown/plugins/markdown-add-components.ts +63 -0
  48. package/addon/utils/markdown/plugins/markdown-checkbox.ts +80 -0
  49. package/addon/utils/markdown/plugins/markdown-default-plugins.ts +100 -0
  50. package/addon/utils/markdown/plugins/markdown-tooltip.ts +113 -0
  51. package/addon/utils/markdown/plugins/to-dom.ts +93 -0
  52. package/app/components/eui-code/index.js +1 -0
  53. package/app/components/eui-code-block/index.js +1 -0
  54. package/app/components/eui-code-block-impl/code-block-controls/index.js +1 -0
  55. package/app/components/eui-code-block-impl/index.js +1 -0
  56. package/app/components/eui-copy/index.js +1 -0
  57. package/app/components/eui-inner-text/index.js +1 -0
  58. package/app/components/eui-markdown-editor/index.js +1 -0
  59. package/app/components/eui-markdown-editor-drop-zone/index.js +1 -0
  60. package/app/components/eui-markdown-editor-footer/index.js +1 -0
  61. package/app/components/eui-markdown-editor-text-area/index.js +1 -0
  62. package/app/components/eui-markdown-editor-toolbar/index.js +1 -0
  63. package/app/components/eui-markdown-format/index.js +1 -0
  64. package/app/components/eui-markdown-format/markdown-checkbox/index.js +1 -0
  65. package/app/components/eui-markdown-format/markdown-code/index.js +1 -0
  66. package/app/components/eui-markdown-format/markdown-code-block/index.js +1 -0
  67. package/app/components/eui-markdown-format/markdown-tooltip/index.js +1 -0
  68. package/app/modifiers/get-cursor-node.js +1 -0
  69. package/app/styles/ember-eui.scss +13 -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 +86 -0
  75. package/docs/editors/markdown-editor/base-editor.md +1 -0
  76. package/package.json +32 -6
  77. package/public/markdown-checkmark.svg +3 -0
  78. package/public/markdown-logo.svg +3 -0
@@ -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,45 @@
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 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
+ return unified().use(this.parsingPluginList).use(this.processingPluginList);
32
+ }
33
+
34
+ @cached
35
+ //@ts-ignore
36
+ get result() {
37
+ try {
38
+ const processed = this.processor.processSync(this.args.value);
39
+ return toDOM(processed.result as RehypeNode);
40
+ //eslint-disable-next-line
41
+ } catch (e) {
42
+ return this.args.value;
43
+ }
44
+ }
45
+ }
@@ -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>
@@ -0,0 +1,8 @@
1
+ <span>
2
+ <EuiToolTip @content={{@node.tooltipText}}>
3
+ <span>
4
+ <strong>{{@node.content}}</strong>
5
+ <EuiIcon @type="questionInCircle" class="euiMarkdownTooltip__icon" />
6
+ </span>
7
+ </EuiToolTip>
8
+ </span>
@@ -0,0 +1,54 @@
1
+ import { modifier } from 'ember-modifier';
2
+ import { EuiMarkdownAstNode } from '../utils/markdown/markdown-types';
3
+
4
+ export const getCursorNode = (
5
+ textareaRef: HTMLInputElement,
6
+ parsed: any
7
+ ): EuiMarkdownAstNode => {
8
+ const { selectionStart } = textareaRef;
9
+
10
+ let node: EuiMarkdownAstNode = parsed.result ?? parsed.contents;
11
+
12
+ //eslint-disable-next-line
13
+ outer: while (true) {
14
+ if (node.children) {
15
+ for (let i = 0; i < node.children.length; i++) {
16
+ const child = node.children[i];
17
+ if (
18
+ child.position.start.offset < (selectionStart as number) &&
19
+ (selectionStart as number) < child.position.end.offset
20
+ ) {
21
+ if (child.type === 'text') break outer; // don't dive into `text` nodes
22
+ node = child;
23
+ continue outer;
24
+ }
25
+ }
26
+ }
27
+ break;
28
+ }
29
+
30
+ return node;
31
+ };
32
+
33
+ function wrapper(
34
+ textarea: HTMLInputElement,
35
+ parsed: any,
36
+ callback: (node: EuiMarkdownAstNode) => void
37
+ ) {
38
+ const node = getCursorNode(textarea, parsed);
39
+ callback(node);
40
+ }
41
+
42
+ export default modifier(function getCursorNodeModifier(
43
+ textarea: HTMLInputElement,
44
+ [parsed, onSelectedNode]: [boolean, () => void]
45
+ ) {
46
+ const fn = wrapper.bind(null, textarea, parsed, onSelectedNode);
47
+ textarea.addEventListener('keyup', fn);
48
+ textarea.addEventListener('mouseup', fn);
49
+
50
+ return () => {
51
+ textarea.removeEventListener('keyup', fn);
52
+ textarea.removeEventListener('mouseup', fn);
53
+ };
54
+ });
@@ -3,7 +3,8 @@ import { action } from '@ember/object';
3
3
 
4
4
  // IE11 and Safari don't support the `ResizeObserver` API at the time of writing
5
5
  const hasResizeObserver =
6
- typeof window !== 'undefined' && typeof (window as any).ResizeObserver !== 'undefined';
6
+ typeof window !== 'undefined' &&
7
+ typeof (window as any).ResizeObserver !== 'undefined';
7
8
 
8
9
  export interface Observer {
9
10
  disconnect: () => void;
@@ -64,7 +65,10 @@ export default class ResizeObserver extends Modifier<ResizeObserverArgs> {
64
65
  let [dimension] = this.args.positional;
65
66
  const doesWidthMatter = dimension !== 'height';
66
67
  const doesHeightMatter = dimension !== 'width';
67
- if ((doesWidthMatter && width !== this.width) || (doesHeightMatter && height !== this.height)) {
68
+ if (
69
+ (doesWidthMatter && width !== this.width) ||
70
+ (doesHeightMatter && height !== this.height)
71
+ ) {
68
72
  this.width = width;
69
73
  this.height = height;
70
74
  this.args.named?.onResize({ width, height });
@@ -0,0 +1,70 @@
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
+ function createHiddenTextElement(text: string): HTMLSpanElement {
21
+ const textElement = document.createElement('span');
22
+ textElement.textContent = text;
23
+ // @ts-ignore .all is a real property - https://drafts.csswg.org/css-cascade/#all-shorthand
24
+ textElement.style.all = 'unset';
25
+ // prevents scrolling to the end of the page
26
+ textElement.style.position = 'fixed';
27
+ textElement.style.top = '0';
28
+ textElement.style.clip = 'rect(0, 0, 0, 0)';
29
+ // used to preserve spaces and line breaks
30
+ textElement.style.whiteSpace = 'pre';
31
+ // do not inherit user-select (it may be `none`)
32
+ textElement.style.webkitUserSelect = 'text';
33
+ // @ts-ignore this one doesn't appear in the TS definitions for some reason
34
+ textElement.style.MozUserSelect = 'text';
35
+ // @ts-ignore this one doesn't appear in the TS definitions for some reason
36
+ textElement.style.msUserSelect = 'text';
37
+ textElement.style.userSelect = 'text';
38
+ return textElement;
39
+ }
40
+
41
+ export function copyToClipboard(text: string): boolean {
42
+ let isCopied = true;
43
+ const range = document.createRange();
44
+ const selection = window.getSelection();
45
+ const elementToBeCopied = createHiddenTextElement(text);
46
+
47
+ document.body.appendChild(elementToBeCopied);
48
+ range.selectNode(elementToBeCopied);
49
+ if (selection) {
50
+ selection.removeAllRanges();
51
+ selection.addRange(range);
52
+ }
53
+
54
+ if (!document.execCommand('copy')) {
55
+ isCopied = false;
56
+ console.warn('Unable to copy to clipboard.');
57
+ }
58
+
59
+ if (selection) {
60
+ if (typeof selection.removeRange === 'function') {
61
+ selection.removeRange(range);
62
+ } else {
63
+ selection.removeAllRanges();
64
+ }
65
+ }
66
+
67
+ document.body.removeChild(elementToBeCopied);
68
+
69
+ return isCopied;
70
+ }
@@ -0,0 +1,24 @@
1
+ export const baseClass = 'euiCodeBlock';
2
+
3
+ export const fontSizeMapping = {
4
+ s: `${baseClass}--fontSmall`,
5
+ m: `${baseClass}--fontMedium`,
6
+ l: `${baseClass}--fontLarge`
7
+ };
8
+
9
+ export const paddingSizeMapping = {
10
+ none: '',
11
+ s: `${baseClass}--paddingSmall`,
12
+ m: `${baseClass}--paddingMedium`,
13
+ l: `${baseClass}--paddingLarge`
14
+ };
15
+
16
+ const mapping: ComponentMapping = {
17
+ base: baseClass,
18
+ properties: {
19
+ fontSize: fontSizeMapping,
20
+ paddingSize: paddingSizeMapping
21
+ }
22
+ };
23
+
24
+ export default mapping;
@@ -52,8 +52,10 @@ import EuiRangeLevels from './eui-range-levels';
52
52
  import EuiToolTip from './eui-tool-tip';
53
53
  import EuiToast from './eui-toast';
54
54
  import EuiGlobalToastList from './eui-global-toast-list';
55
+ import EuiCodeBlockImpl from './eui-code-block-impl';
55
56
 
56
57
  const mapping: Mapping = {
58
+ EuiCodeBlockImpl,
57
59
  EuiAccordion,
58
60
  EuiIcon,
59
61
  EuiModal,