@sveltia/ui 0.11.1 → 0.12.1

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 (90) hide show
  1. package/package/components/button/button.svelte +4 -1
  2. package/package/components/button/button.svelte.d.ts +4 -4
  3. package/package/components/button/select-button-group.svelte.d.ts +4 -4
  4. package/package/components/button/select-button.svelte.d.ts +4 -4
  5. package/package/components/button/split-button.svelte +2 -5
  6. package/package/components/button/split-button.svelte.d.ts +4 -4
  7. package/package/components/calendar/calendar.svelte +1 -1
  8. package/package/components/checkbox/checkbox.svelte +2 -2
  9. package/package/components/checkbox/checkbox.svelte.d.ts +6 -6
  10. package/package/components/dialog/dialog.svelte +2 -2
  11. package/package/components/dialog/dialog.svelte.d.ts +2 -2
  12. package/package/components/dialog/prompt-dialog.svelte +7 -1
  13. package/package/components/dialog/prompt-dialog.svelte.d.ts +2 -0
  14. package/package/components/disclosure/disclosure.svelte +2 -2
  15. package/package/components/disclosure/disclosure.svelte.d.ts +2 -2
  16. package/package/components/drawer/drawer.svelte +2 -2
  17. package/package/components/drawer/drawer.svelte.d.ts +2 -2
  18. package/package/components/grid/grid-body.svelte +2 -2
  19. package/package/components/grid/grid.svelte.d.ts +2 -2
  20. package/package/components/icon/icon.svelte +6 -0
  21. package/package/components/listbox/listbox.svelte.d.ts +8 -8
  22. package/package/components/listbox/option-group.svelte +2 -2
  23. package/package/components/listbox/option-group.svelte.d.ts +2 -2
  24. package/package/components/menu/menu-button.svelte +0 -8
  25. package/package/components/menu/menu-button.svelte.d.ts +4 -4
  26. package/package/components/menu/menu-item-checkbox.svelte.d.ts +4 -4
  27. package/package/components/menu/menu-item-group.svelte +2 -2
  28. package/package/components/menu/menu-item-group.svelte.d.ts +2 -2
  29. package/package/components/menu/menu-item-radio.svelte.d.ts +4 -4
  30. package/package/components/menu/menu-item.svelte +1 -1
  31. package/package/components/menu/menu-item.svelte.d.ts +2 -2
  32. package/package/components/radio/radio-group.svelte.d.ts +4 -4
  33. package/package/components/radio/radio.svelte +2 -2
  34. package/package/components/radio/radio.svelte.d.ts +4 -4
  35. package/package/components/select/combobox.svelte +3 -3
  36. package/package/components/select/combobox.svelte.d.ts +4 -4
  37. package/package/components/select/select.svelte.d.ts +4 -4
  38. package/package/components/slider/slider.svelte +1 -1
  39. package/package/components/slider/slider.svelte.d.ts +8 -8
  40. package/package/components/switch/switch.svelte.d.ts +6 -6
  41. package/package/components/table/table-body.svelte +2 -2
  42. package/package/components/tabs/tab-list.svelte +1 -1
  43. package/package/components/text-editor/core.d.ts +2 -0
  44. package/package/components/text-editor/core.js +206 -0
  45. package/package/components/text-editor/index.d.ts +23 -0
  46. package/package/components/text-editor/index.js +102 -0
  47. package/package/components/text-editor/lexical-root.svelte +123 -0
  48. package/package/components/text-editor/lexical-root.svelte.d.ts +27 -0
  49. package/package/components/text-editor/text-editor.svelte +154 -0
  50. package/package/components/{text-field/markdown-editor.svelte.d.ts → text-editor/text-editor.svelte.d.ts} +16 -12
  51. package/package/components/text-editor/toolbar/editor-toolbar.svelte +150 -0
  52. package/package/components/text-editor/toolbar/editor-toolbar.svelte.d.ts +25 -0
  53. package/package/components/text-editor/toolbar/format-text-button.svelte +33 -0
  54. package/package/components/text-editor/toolbar/format-text-button.svelte.d.ts +23 -0
  55. package/package/components/text-editor/toolbar/insert-link-button.svelte +231 -0
  56. package/package/components/text-editor/toolbar/insert-link-button.svelte.d.ts +23 -0
  57. package/package/components/text-editor/toolbar/toggle-block-menu-item.svelte +83 -0
  58. package/package/components/text-editor/toolbar/toggle-block-menu-item.svelte.d.ts +23 -0
  59. package/package/components/text-field/number-input.svelte +2 -2
  60. package/package/components/text-field/number-input.svelte.d.ts +10 -10
  61. package/package/components/text-field/password-input.svelte +2 -2
  62. package/package/components/text-field/password-input.svelte.d.ts +4 -4
  63. package/package/components/text-field/search-bar.svelte +3 -3
  64. package/package/components/text-field/search-bar.svelte.d.ts +4 -4
  65. package/package/components/text-field/text-area.svelte +3 -0
  66. package/package/components/text-field/text-area.svelte.d.ts +4 -4
  67. package/package/components/text-field/text-input.svelte +2 -2
  68. package/package/components/text-field/text-input.svelte.d.ts +4 -4
  69. package/package/components/toast/toast.svelte +2 -2
  70. package/package/components/util/app-shell.svelte +56 -4
  71. package/package/components/util/modal.svelte +3 -3
  72. package/package/components/util/modal.svelte.d.ts +4 -4
  73. package/package/components/util/popup.svelte +2 -2
  74. package/package/index.d.ts +1 -2
  75. package/package/index.js +9 -4
  76. package/package/locales/en.d.ts +25 -7
  77. package/package/locales/en.js +25 -6
  78. package/package/locales/ja.d.ts +25 -7
  79. package/package/locales/ja.js +25 -6
  80. package/package/services/events.js +2 -2
  81. package/package/services/group.js +7 -6
  82. package/package/services/popup.js +2 -2
  83. package/package/styles/core.scss +51 -2
  84. package/package/styles/variables.scss +3 -1
  85. package/package/typedef.d.ts +48 -0
  86. package/package/typedef.js +36 -0
  87. package/package.json +22 -18
  88. package/package/components/text-field/markdown-editor.svelte +0 -141
  89. package/package/services/util.d.ts +0 -3
  90. package/package/services/util.js +0 -35
@@ -9,10 +9,10 @@
9
9
  export default class MenuItemRadio extends SvelteComponent<{
10
10
  [x: string]: any;
11
11
  class?: string | undefined;
12
- disabled?: boolean | undefined;
13
12
  label?: string | undefined;
14
- checked?: boolean | undefined;
13
+ disabled?: boolean | undefined;
15
14
  hidden?: boolean | undefined;
15
+ checked?: boolean | undefined;
16
16
  iconName?: string | undefined;
17
17
  iconLabel?: string | undefined;
18
18
  }, {
@@ -33,10 +33,10 @@ declare const __propDef: {
33
33
  props: {
34
34
  [x: string]: any;
35
35
  class?: string | undefined;
36
- disabled?: boolean | undefined;
37
36
  label?: string | undefined;
38
- checked?: boolean | undefined;
37
+ disabled?: boolean | undefined;
39
38
  hidden?: boolean | undefined;
39
+ checked?: boolean | undefined;
40
40
  iconName?: string | undefined;
41
41
  iconLabel?: string | undefined;
42
42
  };
@@ -7,8 +7,8 @@
7
7
  import { writable } from 'svelte/store';
8
8
  import Button from '../button/button.svelte';
9
9
  import Icon from '../icon/icon.svelte';
10
- import Popup from '../util/popup.svelte';
11
10
  import Menu from './menu.svelte';
11
+ import Popup from '../util/popup.svelte';
12
12
 
13
13
  /**
14
14
  * The `class` attribute on the wrapper element.
@@ -8,8 +8,8 @@
8
8
  export default class MenuItem extends SvelteComponent<{
9
9
  [x: string]: any;
10
10
  class?: string | undefined;
11
- disabled?: boolean | undefined;
12
11
  label?: string | undefined;
12
+ disabled?: boolean | undefined;
13
13
  role?: "menuitem" | "menuitemcheckbox" | "menuitemradio" | undefined;
14
14
  hidden?: boolean | undefined;
15
15
  iconName?: string | undefined;
@@ -42,8 +42,8 @@ declare const __propDef: {
42
42
  props: {
43
43
  [x: string]: any;
44
44
  class?: string | undefined;
45
- disabled?: boolean | undefined;
46
45
  label?: string | undefined;
46
+ disabled?: boolean | undefined;
47
47
  role?: "menuitem" | "menuitemcheckbox" | "menuitemradio" | undefined;
48
48
  hidden?: boolean | undefined;
49
49
  iconName?: string | undefined;
@@ -9,12 +9,12 @@
9
9
  export default class RadioGroup extends SvelteComponent<{
10
10
  [x: string]: any;
11
11
  class?: string | undefined;
12
- disabled?: boolean | undefined;
13
12
  invalid?: boolean | undefined;
14
- required?: boolean | undefined;
13
+ disabled?: boolean | undefined;
15
14
  hidden?: boolean | undefined;
16
15
  readonly?: boolean | undefined;
17
16
  orientation?: "vertical" | "horizontal" | undefined;
17
+ required?: boolean | undefined;
18
18
  }, {
19
19
  change: CustomEvent<any>;
20
20
  } & {
@@ -31,12 +31,12 @@ declare const __propDef: {
31
31
  props: {
32
32
  [x: string]: any;
33
33
  class?: string | undefined;
34
- disabled?: boolean | undefined;
35
34
  invalid?: boolean | undefined;
36
- required?: boolean | undefined;
35
+ disabled?: boolean | undefined;
37
36
  hidden?: boolean | undefined;
38
37
  readonly?: boolean | undefined;
39
38
  orientation?: "vertical" | "horizontal" | undefined;
39
+ required?: boolean | undefined;
40
40
  };
41
41
  events: {
42
42
  change: CustomEvent<any>;
@@ -6,7 +6,7 @@
6
6
  @see https://www.w3.org/WAI/ARIA/apg/patterns/radio/
7
7
  -->
8
8
  <script>
9
- import { getRandomId } from '../../services/util';
9
+ import { generateElementId } from '@sveltia/utils/element';
10
10
  import Button from '../button/button.svelte';
11
11
 
12
12
  /**
@@ -46,7 +46,7 @@
46
46
  */
47
47
  export let label = undefined;
48
48
 
49
- const id = getRandomId('checkbox');
49
+ const id = generateElementId('checkbox');
50
50
 
51
51
  /**
52
52
  * Reference to the `Button` component.
@@ -11,11 +11,11 @@ export default class Radio extends SvelteComponent<{
11
11
  [x: string]: any;
12
12
  class?: string | undefined;
13
13
  name?: string | undefined;
14
- disabled?: boolean | undefined;
15
14
  label?: string | undefined;
16
- checked?: boolean | undefined;
15
+ disabled?: boolean | undefined;
17
16
  value?: string | undefined;
18
17
  hidden?: boolean | undefined;
18
+ checked?: boolean | undefined;
19
19
  }, {
20
20
  focus: FocusEvent;
21
21
  blur: FocusEvent;
@@ -36,11 +36,11 @@ declare const __propDef: {
36
36
  [x: string]: any;
37
37
  class?: string | undefined;
38
38
  name?: string | undefined;
39
- disabled?: boolean | undefined;
40
39
  label?: string | undefined;
41
- checked?: boolean | undefined;
40
+ disabled?: boolean | undefined;
42
41
  value?: string | undefined;
43
42
  hidden?: boolean | undefined;
43
+ checked?: boolean | undefined;
44
44
  };
45
45
  events: {
46
46
  focus: FocusEvent;
@@ -6,10 +6,10 @@
6
6
  @todo Add DOM API compatibility.
7
7
  -->
8
8
  <script>
9
+ import { generateElementId } from '@sveltia/utils/element';
9
10
  import { createEventDispatcher } from 'svelte';
10
11
  import { _ } from 'svelte-i18n';
11
12
  import { writable } from 'svelte/store';
12
- import { getRandomId } from '../../services/util';
13
13
  import Button from '../button/button.svelte';
14
14
  import Icon from '../icon/icon.svelte';
15
15
  import Listbox from '../listbox/listbox.svelte';
@@ -64,7 +64,7 @@
64
64
  export let position = 'bottom-left';
65
65
 
66
66
  const dispatch = createEventDispatcher();
67
- const id = getRandomId('combobox');
67
+ const id = generateElementId('combobox');
68
68
  const selectedSelector = '[role="option"][aria-selected="true"]';
69
69
  /** @type {HTMLElement} */
70
70
  let comboboxElement;
@@ -115,7 +115,7 @@
115
115
 
116
116
  $: {
117
117
  if (popupComponent?.content) {
118
- window.requestAnimationFrame(() => {
118
+ globalThis.requestAnimationFrame(() => {
119
119
  const selected = popupComponent?.content?.querySelector(selectedSelector);
120
120
 
121
121
  if (selected) {
@@ -10,13 +10,13 @@
10
10
  export default class Combobox extends SvelteComponent<{
11
11
  [x: string]: any;
12
12
  class?: string | undefined;
13
- disabled?: boolean | undefined;
14
13
  invalid?: boolean | undefined;
15
- required?: boolean | undefined;
14
+ disabled?: boolean | undefined;
16
15
  value?: string | number | undefined;
17
16
  position?: PopupPosition | undefined;
18
17
  hidden?: boolean | undefined;
19
18
  readonly?: boolean | undefined;
19
+ required?: boolean | undefined;
20
20
  editable?: boolean | undefined;
21
21
  }, {
22
22
  change: CustomEvent<any>;
@@ -37,13 +37,13 @@ declare const __propDef: {
37
37
  props: {
38
38
  [x: string]: any;
39
39
  class?: string | undefined;
40
- disabled?: boolean | undefined;
41
40
  invalid?: boolean | undefined;
42
- required?: boolean | undefined;
41
+ disabled?: boolean | undefined;
43
42
  value?: (string | number | undefined);
44
43
  position?: PopupPosition | undefined;
45
44
  hidden?: boolean | undefined;
46
45
  readonly?: boolean | undefined;
46
+ required?: boolean | undefined;
47
47
  editable?: boolean | undefined;
48
48
  };
49
49
  events: {
@@ -10,12 +10,12 @@
10
10
  export default class Select extends SvelteComponent<{
11
11
  [x: string]: any;
12
12
  class?: string | undefined;
13
- disabled?: boolean | undefined;
14
13
  invalid?: boolean | undefined;
15
- required?: boolean | undefined;
14
+ disabled?: boolean | undefined;
16
15
  value?: string | number | undefined;
17
16
  hidden?: boolean | undefined;
18
17
  readonly?: boolean | undefined;
18
+ required?: boolean | undefined;
19
19
  }, {
20
20
  change: CustomEvent<any>;
21
21
  } & {
@@ -32,12 +32,12 @@ declare const __propDef: {
32
32
  props: {
33
33
  [x: string]: any;
34
34
  class?: string | undefined;
35
- disabled?: boolean | undefined;
36
35
  invalid?: boolean | undefined;
37
- required?: boolean | undefined;
36
+ disabled?: boolean | undefined;
38
37
  value?: (string | number | undefined);
39
38
  hidden?: boolean | undefined;
40
39
  readonly?: boolean | undefined;
40
+ required?: boolean | undefined;
41
41
  };
42
42
  events: {
43
43
  change: CustomEvent<any>;
@@ -270,7 +270,7 @@
270
270
 
271
271
  onMount(() => {
272
272
  const observer = new ResizeObserver(() => init());
273
- const query = window.matchMedia('(pointer: coarse)');
273
+ const query = globalThis.matchMedia('(pointer: coarse)');
274
274
 
275
275
  observer.observe(/** @type {HTMLElement} */ (base));
276
276
  query.addEventListener('change', init);
@@ -12,17 +12,17 @@
12
12
  export default class Slider extends SvelteComponent<{
13
13
  [x: string]: any;
14
14
  class?: string | undefined;
15
- disabled?: boolean | undefined;
16
15
  invalid?: boolean | undefined;
17
- max?: number | undefined;
18
- min?: number | undefined;
19
- step?: number | undefined;
16
+ disabled?: boolean | undefined;
20
17
  value?: number | undefined;
21
18
  hidden?: boolean | undefined;
22
19
  readonly?: boolean | undefined;
23
20
  values?: [number, number] | undefined;
21
+ min?: number | undefined;
22
+ max?: number | undefined;
24
23
  sliderLabel?: string | undefined;
25
24
  sliderLabels?: [string, string] | undefined;
25
+ step?: number | undefined;
26
26
  optionLabels?: string[] | number[] | undefined;
27
27
  }, {
28
28
  change: CustomEvent<any>;
@@ -38,17 +38,17 @@ declare const __propDef: {
38
38
  props: {
39
39
  [x: string]: any;
40
40
  class?: string | undefined;
41
- disabled?: boolean | undefined;
42
41
  invalid?: boolean | undefined;
43
- max?: number | undefined;
44
- min?: number | undefined;
45
- step?: number | undefined;
42
+ disabled?: boolean | undefined;
46
43
  value?: number | undefined;
47
44
  hidden?: boolean | undefined;
48
45
  readonly?: boolean | undefined;
49
46
  values?: [number, number] | undefined;
47
+ min?: number | undefined;
48
+ max?: number | undefined;
50
49
  sliderLabel?: string | undefined;
51
50
  sliderLabels?: [string, string] | undefined;
51
+ step?: number | undefined;
52
52
  optionLabels?: string[] | number[] | undefined;
53
53
  };
54
54
  events: {
@@ -9,13 +9,13 @@
9
9
  export default class Switch extends SvelteComponent<{
10
10
  [x: string]: any;
11
11
  class?: string | undefined;
12
- disabled?: boolean | undefined;
13
12
  invalid?: boolean | undefined;
14
13
  label?: string | undefined;
15
- checked?: boolean | "mixed" | undefined;
16
- required?: boolean | undefined;
14
+ disabled?: boolean | undefined;
17
15
  hidden?: boolean | undefined;
18
16
  readonly?: boolean | undefined;
17
+ required?: boolean | undefined;
18
+ checked?: boolean | "mixed" | undefined;
19
19
  }, {
20
20
  change: CustomEvent<any>;
21
21
  } & {
@@ -32,13 +32,13 @@ declare const __propDef: {
32
32
  props: {
33
33
  [x: string]: any;
34
34
  class?: string | undefined;
35
- disabled?: boolean | undefined;
36
35
  invalid?: boolean | undefined;
37
36
  label?: string | undefined;
38
- checked?: boolean | "mixed" | undefined;
39
- required?: boolean | undefined;
37
+ disabled?: boolean | undefined;
40
38
  hidden?: boolean | undefined;
41
39
  readonly?: boolean | undefined;
40
+ required?: boolean | undefined;
41
+ checked?: boolean | "mixed" | undefined;
42
42
  };
43
43
  events: {
44
44
  change: CustomEvent<any>;
@@ -5,7 +5,7 @@
5
5
  @see https://w3c.github.io/aria/#rowgroup
6
6
  -->
7
7
  <script>
8
- import { getRandomId } from '../../services/util';
8
+ import { generateElementId } from '@sveltia/utils/element';
9
9
 
10
10
  /**
11
11
  * The `class` attribute on the wrapper element.
@@ -20,7 +20,7 @@
20
20
  */
21
21
  export let label = '';
22
22
 
23
- const id = getRandomId('tbody');
23
+ const id = generateElementId('tbody');
24
24
  </script>
25
25
 
26
26
  <div
@@ -51,7 +51,7 @@
51
51
  * Update the indicator position.
52
52
  */
53
53
  const updateIndicator = () => {
54
- window.requestAnimationFrame(() => {
54
+ globalThis.requestAnimationFrame(() => {
55
55
  const selected = /** @type {HTMLElement | null} */ (
56
56
  wrapper?.querySelector('[role="tab"][aria-selected="true"]')
57
57
  );
@@ -0,0 +1,2 @@
1
+ export function initEditor(): import('lexical').LexicalEditor;
2
+ export function convertMarkdown(editor: import('lexical').LexicalEditor, value: string): Promise<void>;
@@ -0,0 +1,206 @@
1
+ import { CodeHighlightNode, CodeNode } from '@lexical/code';
2
+ import { createEmptyHistoryState, registerHistory } from '@lexical/history';
3
+ import {
4
+ LinkNode,
5
+ TOGGLE_LINK_COMMAND,
6
+ $isLinkNode as isLinkNode,
7
+ toggleLink,
8
+ } from '@lexical/link';
9
+ import {
10
+ INSERT_ORDERED_LIST_COMMAND,
11
+ INSERT_UNORDERED_LIST_COMMAND,
12
+ ListItemNode,
13
+ ListNode,
14
+ insertList,
15
+ $isListItemNode as isListItemNode,
16
+ $isListNode as isListNode,
17
+ } from '@lexical/list';
18
+ import {
19
+ TRANSFORMERS,
20
+ $convertFromMarkdownString as convertFromMarkdownString,
21
+ $convertToMarkdownString as convertToMarkdownString,
22
+ } from '@lexical/markdown';
23
+ import {
24
+ HeadingNode,
25
+ QuoteNode,
26
+ $isHeadingNode as isHeadingNode,
27
+ $isQuoteNode as isQuoteNode,
28
+ registerRichText,
29
+ } from '@lexical/rich-text';
30
+ import { TableCellNode, TableNode, TableRowNode } from '@lexical/table';
31
+ import { $getNearestNodeOfType as getNearestNodeOfType } from '@lexical/utils';
32
+ import {
33
+ COMMAND_PRIORITY_NORMAL,
34
+ ElementNode,
35
+ createEditor,
36
+ $getSelection as getSelection,
37
+ $isRangeSelection as isRangeSelection,
38
+ } from 'lexical';
39
+ import { blockButtonTypes, textFormatButtonTypes } from './';
40
+
41
+ /**
42
+ * Lexical editor configuration.
43
+ * @type {import('lexical').CreateEditorArgs}
44
+ */
45
+ const editorConfig = {
46
+ namespace: 'editor',
47
+ nodes: [
48
+ HeadingNode,
49
+ QuoteNode,
50
+ LinkNode,
51
+ ListNode,
52
+ ListItemNode,
53
+ CodeNode,
54
+ CodeHighlightNode,
55
+ TableNode,
56
+ TableCellNode,
57
+ TableRowNode,
58
+ ],
59
+ theme: {
60
+ text: {
61
+ /**
62
+ * Enable bold+italic styling.
63
+ * @see https://github.com/facebook/lexical/discussions/4381
64
+ */
65
+ italic: 'italic',
66
+ },
67
+ },
68
+ };
69
+
70
+ /**
71
+ * Listen to changes on the editor.
72
+ * @param {import('lexical').LexicalEditor} editor - Editor instance.
73
+ */
74
+ const onEditorUpdate = (editor) => {
75
+ const selection = getSelection();
76
+
77
+ if (!isRangeSelection(selection)) {
78
+ return;
79
+ }
80
+
81
+ const anchor = selection.anchor.getNode();
82
+ /** @type {ElementNode | null} */
83
+ let parent = null;
84
+ /** @type {TextEditorInlineType[]} */
85
+ const selectionInlineTypes = textFormatButtonTypes.filter((type) => selection.hasFormat(type));
86
+
87
+ if (anchor.getType() !== 'root') {
88
+ parent = anchor instanceof ElementNode ? anchor : getNearestNodeOfType(anchor, ElementNode);
89
+
90
+ if (isLinkNode(parent)) {
91
+ selectionInlineTypes.push('link');
92
+ parent = getNearestNodeOfType(parent, ElementNode);
93
+ }
94
+
95
+ if (isListItemNode(parent)) {
96
+ parent = getNearestNodeOfType(parent, ListNode);
97
+ }
98
+ }
99
+
100
+ const selectionBlockType = /** @type {TextEditorBlockType} */ (
101
+ (() => {
102
+ if (!parent) {
103
+ return 'paragraph';
104
+ }
105
+
106
+ if (isHeadingNode(parent)) {
107
+ return `heading-${parent.getTag().match(/\d/)?.[0]}`;
108
+ }
109
+
110
+ if (isListNode(parent)) {
111
+ return parent.getListType() === 'bullet' ? 'bulleted-list' : 'numbered-list';
112
+ }
113
+
114
+ if (isQuoteNode(parent)) {
115
+ return 'blockquote';
116
+ }
117
+
118
+ const type = parent.getType();
119
+
120
+ if (blockButtonTypes.includes(/** @type {any} */ (type))) {
121
+ return type;
122
+ }
123
+
124
+ return 'paragraph';
125
+ })()
126
+ );
127
+
128
+ editor.getRootElement()?.dispatchEvent(
129
+ new CustomEvent('Update', {
130
+ detail: {
131
+ value: convertToMarkdownString(TRANSFORMERS),
132
+ selectionBlockType,
133
+ selectionInlineTypes,
134
+ },
135
+ }),
136
+ );
137
+ };
138
+
139
+ /**
140
+ * Initialize the Lexical editor.
141
+ * @returns {import('lexical').LexicalEditor} Editor instance.
142
+ */
143
+ export const initEditor = () => {
144
+ const editor = createEditor(editorConfig);
145
+
146
+ registerRichText(editor);
147
+ registerHistory(editor, createEmptyHistoryState(), 1000);
148
+
149
+ editor.registerCommand(
150
+ TOGGLE_LINK_COMMAND,
151
+ (payload) => {
152
+ toggleLink(typeof payload === 'string' ? payload : null);
153
+ return true;
154
+ },
155
+ COMMAND_PRIORITY_NORMAL,
156
+ );
157
+
158
+ editor.registerCommand(
159
+ INSERT_UNORDERED_LIST_COMMAND,
160
+ () => {
161
+ insertList(editor, 'bullet');
162
+ return true;
163
+ },
164
+ COMMAND_PRIORITY_NORMAL,
165
+ );
166
+
167
+ editor.registerCommand(
168
+ INSERT_ORDERED_LIST_COMMAND,
169
+ () => {
170
+ insertList(editor, 'number');
171
+ return true;
172
+ },
173
+ COMMAND_PRIORITY_NORMAL,
174
+ );
175
+
176
+ editor.registerUpdateListener(({ editorState }) => {
177
+ if (editor?.isComposing()) {
178
+ return;
179
+ }
180
+
181
+ editorState.read(() => {
182
+ onEditorUpdate(editor);
183
+ });
184
+ });
185
+
186
+ return editor;
187
+ };
188
+
189
+ /**
190
+ * Convert Markdown to Lexical nodes.
191
+ * @param {import('lexical').LexicalEditor} editor - Editor instance.
192
+ * @param {string} value - Current Markdown value.
193
+ * @returns {Promise<void>} Nothing.
194
+ * @throws {Error} Failed to convert the value to Lexical nodes.
195
+ */
196
+ export const convertMarkdown = async (editor, value) =>
197
+ new Promise((resolve, reject) => {
198
+ editor.update(() => {
199
+ try {
200
+ convertFromMarkdownString(value, TRANSFORMERS);
201
+ resolve(void 0);
202
+ } catch {
203
+ reject(new Error('Failed to convert Markdown'));
204
+ }
205
+ });
206
+ });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * List of available buttons.
3
+ * @type {{ [key: string]: { labelKey: string, icon: string, inline: boolean } }}
4
+ */
5
+ export const availableButtons: {
6
+ [key: string]: {
7
+ labelKey: string;
8
+ icon: string;
9
+ inline: boolean;
10
+ };
11
+ };
12
+ /**
13
+ * @type {TextEditorFormatType[]}
14
+ */
15
+ export const textFormatButtonTypes: TextEditorFormatType[];
16
+ /**
17
+ * @type {TextEditorInlineType[]}
18
+ */
19
+ export const inlineButtonTypes: TextEditorInlineType[];
20
+ /**
21
+ * @type {TextEditorBlockType[]}
22
+ */
23
+ export const blockButtonTypes: TextEditorBlockType[];
@@ -0,0 +1,102 @@
1
+ /**
2
+ * List of available buttons.
3
+ * @type {{ [key: string]: { labelKey: string, icon: string, inline: boolean } }}
4
+ */
5
+ export const availableButtons = {
6
+ bold: {
7
+ labelKey: 'bold',
8
+ icon: 'format_bold',
9
+ inline: true,
10
+ },
11
+ italic: {
12
+ labelKey: 'italic',
13
+ icon: 'format_italic',
14
+ inline: true,
15
+ },
16
+ code: {
17
+ labelKey: 'code',
18
+ icon: 'code',
19
+ inline: true,
20
+ },
21
+ link: {
22
+ labelKey: 'link',
23
+ icon: 'link',
24
+ inline: true,
25
+ },
26
+ paragraph: {
27
+ labelKey: 'paragraph',
28
+ icon: 'format_paragraph',
29
+ inline: false,
30
+ },
31
+ 'heading-1': {
32
+ labelKey: 'heading_1',
33
+ icon: 'format_h1',
34
+ inline: false,
35
+ },
36
+ 'heading-2': {
37
+ labelKey: 'heading_2',
38
+ icon: 'format_h2',
39
+ inline: false,
40
+ },
41
+ 'heading-3': {
42
+ labelKey: 'heading_3',
43
+ icon: 'format_h3',
44
+ inline: false,
45
+ },
46
+ 'heading-4': {
47
+ labelKey: 'heading_4',
48
+ icon: 'format_h4',
49
+ inline: false,
50
+ },
51
+ 'heading-5': {
52
+ labelKey: 'heading_5',
53
+ icon: 'format_h5',
54
+ inline: false,
55
+ },
56
+ 'heading-6': {
57
+ labelKey: 'heading_6',
58
+ icon: 'format_h6',
59
+ inline: false,
60
+ },
61
+ 'bulleted-list': {
62
+ labelKey: 'bulleted_list',
63
+ icon: 'format_list_bulleted',
64
+ inline: false,
65
+ },
66
+ 'numbered-list': {
67
+ labelKey: 'numbered_list',
68
+ icon: 'format_list_numbered',
69
+ inline: false,
70
+ },
71
+ blockquote: {
72
+ labelKey: 'blockquote',
73
+ icon: 'format_quote',
74
+ inline: false,
75
+ },
76
+ };
77
+
78
+ /**
79
+ * @type {TextEditorFormatType[]}
80
+ */
81
+ export const textFormatButtonTypes = ['bold', 'italic', 'code'];
82
+
83
+ /**
84
+ * @type {TextEditorInlineType[]}
85
+ */
86
+ export const inlineButtonTypes = [...textFormatButtonTypes, 'link'];
87
+
88
+ /**
89
+ * @type {TextEditorBlockType[]}
90
+ */
91
+ export const blockButtonTypes = [
92
+ 'paragraph',
93
+ 'heading-1',
94
+ 'heading-2',
95
+ 'heading-3',
96
+ 'heading-4',
97
+ 'heading-5',
98
+ 'heading-6',
99
+ 'bulleted-list',
100
+ 'numbered-list',
101
+ 'blockquote',
102
+ ];