@sveltia/ui 0.11.0 → 0.12.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 (93) hide show
  1. package/package/components/button/button.svelte +4 -1
  2. package/package/components/button/button.svelte.d.ts +12 -12
  3. package/package/components/button/select-button-group.svelte.d.ts +4 -4
  4. package/package/components/button/select-button.svelte.d.ts +6 -6
  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-group.svelte.d.ts +2 -2
  9. package/package/components/checkbox/checkbox.svelte +1 -1
  10. package/package/components/checkbox/checkbox.svelte.d.ts +10 -10
  11. package/package/components/dialog/dialog.svelte +1 -1
  12. package/package/components/dialog/dialog.svelte.d.ts +2 -2
  13. package/package/components/dialog/prompt-dialog.svelte +7 -1
  14. package/package/components/dialog/prompt-dialog.svelte.d.ts +4 -2
  15. package/package/components/disclosure/disclosure.svelte +1 -1
  16. package/package/components/disclosure/disclosure.svelte.d.ts +2 -2
  17. package/package/components/drawer/drawer.svelte +1 -1
  18. package/package/components/drawer/drawer.svelte.d.ts +6 -6
  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.d.ts +2 -2
  23. package/package/components/listbox/option.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 +6 -6
  26. package/package/components/menu/menu-item-checkbox.svelte.d.ts +4 -4
  27. package/package/components/menu/menu-item-group.svelte.d.ts +2 -2
  28. package/package/components/menu/menu-item-radio.svelte.d.ts +4 -4
  29. package/package/components/menu/menu-item.svelte +1 -1
  30. package/package/components/menu/menu-item.svelte.d.ts +4 -4
  31. package/package/components/menu/menu.svelte.d.ts +2 -2
  32. package/package/components/radio/radio-group.svelte.d.ts +4 -4
  33. package/package/components/radio/radio.svelte +1 -1
  34. package/package/components/radio/radio.svelte.d.ts +6 -6
  35. package/package/components/select/combobox.svelte +2 -2
  36. package/package/components/select/combobox.svelte.d.ts +6 -6
  37. package/package/components/select/select.svelte.d.ts +6 -6
  38. package/package/components/slider/slider.svelte +13 -20
  39. package/package/components/slider/slider.svelte.d.ts +10 -12
  40. package/package/components/switch/switch.svelte.d.ts +8 -8
  41. package/package/components/tabs/tab-list.svelte +1 -1
  42. package/package/components/tabs/tab-list.svelte.d.ts +2 -2
  43. package/package/components/tabs/tab.svelte.d.ts +2 -2
  44. package/package/components/text-editor/core.d.ts +2 -0
  45. package/package/components/text-editor/core.js +206 -0
  46. package/package/components/text-editor/index.d.ts +23 -0
  47. package/package/components/text-editor/index.js +102 -0
  48. package/package/components/text-editor/lexical-root.svelte +123 -0
  49. package/package/components/text-editor/lexical-root.svelte.d.ts +27 -0
  50. package/package/components/text-editor/text-editor.svelte +154 -0
  51. package/package/components/{text-field/markdown-editor.svelte.d.ts → text-editor/text-editor.svelte.d.ts} +18 -14
  52. package/package/components/text-editor/toolbar/editor-toolbar.svelte +150 -0
  53. package/package/components/text-editor/toolbar/editor-toolbar.svelte.d.ts +25 -0
  54. package/package/components/text-editor/toolbar/format-text-button.svelte +33 -0
  55. package/package/components/text-editor/toolbar/format-text-button.svelte.d.ts +23 -0
  56. package/package/components/text-editor/toolbar/insert-link-button.svelte +231 -0
  57. package/package/components/text-editor/toolbar/insert-link-button.svelte.d.ts +23 -0
  58. package/package/components/text-editor/toolbar/toggle-block-menu-item.svelte +83 -0
  59. package/package/components/text-editor/toolbar/toggle-block-menu-item.svelte.d.ts +23 -0
  60. package/package/components/text-field/number-input.svelte +1 -1
  61. package/package/components/text-field/number-input.svelte.d.ts +12 -12
  62. package/package/components/text-field/password-input.svelte +1 -1
  63. package/package/components/text-field/password-input.svelte.d.ts +6 -6
  64. package/package/components/text-field/search-bar.svelte +2 -2
  65. package/package/components/text-field/search-bar.svelte.d.ts +6 -6
  66. package/package/components/text-field/text-area.svelte +3 -0
  67. package/package/components/text-field/text-area.svelte.d.ts +6 -6
  68. package/package/components/text-field/text-input.svelte.d.ts +8 -8
  69. package/package/components/toast/toast.svelte +2 -2
  70. package/package/components/toast/toast.svelte.d.ts +2 -2
  71. package/package/components/toolbar/toolbar.svelte.d.ts +2 -2
  72. package/package/components/util/app-shell.svelte +56 -4
  73. package/package/components/util/group.svelte.d.ts +2 -2
  74. package/package/components/util/modal.svelte +2 -2
  75. package/package/components/util/modal.svelte.d.ts +6 -6
  76. package/package/components/util/popup.svelte +2 -2
  77. package/package/components/util/popup.svelte.d.ts +6 -3
  78. package/package/index.d.ts +1 -1
  79. package/package/index.js +1 -1
  80. package/package/locales/en.d.ts +25 -7
  81. package/package/locales/en.js +25 -6
  82. package/package/locales/ja.d.ts +25 -7
  83. package/package/locales/ja.js +25 -6
  84. package/package/services/events.js +7 -5
  85. package/package/services/group.js +4 -4
  86. package/package/services/util.d.ts +1 -0
  87. package/package/services/util.js +22 -1
  88. package/package/styles/core.scss +51 -2
  89. package/package/styles/variables.scss +3 -1
  90. package/package/typedef.d.ts +48 -0
  91. package/package/typedef.js +36 -0
  92. package/package.json +26 -16
  93. package/package/components/text-field/markdown-editor.svelte +0 -141
@@ -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;
15
13
  hidden?: boolean | undefined;
14
+ disabled?: 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;
39
37
  hidden?: boolean | undefined;
38
+ disabled?: 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,10 +8,10 @@
8
8
  export default class MenuItem extends SvelteComponent<{
9
9
  [x: string]: any;
10
10
  class?: string | undefined;
11
- disabled?: boolean | undefined;
12
- label?: string | undefined;
13
11
  role?: "menuitem" | "menuitemcheckbox" | "menuitemradio" | undefined;
12
+ label?: string | undefined;
14
13
  hidden?: boolean | undefined;
14
+ disabled?: boolean | undefined;
15
15
  iconName?: string | undefined;
16
16
  iconLabel?: string | undefined;
17
17
  }, {
@@ -42,10 +42,10 @@ declare const __propDef: {
42
42
  props: {
43
43
  [x: string]: any;
44
44
  class?: string | undefined;
45
- disabled?: boolean | undefined;
46
- label?: string | undefined;
47
45
  role?: "menuitem" | "menuitemcheckbox" | "menuitemradio" | undefined;
46
+ label?: string | undefined;
48
47
  hidden?: boolean | undefined;
48
+ disabled?: boolean | undefined;
49
49
  iconName?: string | undefined;
50
50
  iconLabel?: string | undefined;
51
51
  };
@@ -9,8 +9,8 @@
9
9
  export default class Menu extends SvelteComponent<{
10
10
  [x: string]: any;
11
11
  class?: string | undefined;
12
- disabled?: boolean | undefined;
13
12
  hidden?: boolean | undefined;
13
+ disabled?: boolean | undefined;
14
14
  }, {
15
15
  change: CustomEvent<any>;
16
16
  } & {
@@ -27,8 +27,8 @@ declare const __propDef: {
27
27
  props: {
28
28
  [x: string]: any;
29
29
  class?: string | undefined;
30
- disabled?: boolean | undefined;
31
30
  hidden?: boolean | undefined;
31
+ disabled?: boolean | undefined;
32
32
  };
33
33
  events: {
34
34
  change: CustomEvent<any>;
@@ -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;
15
13
  hidden?: boolean | undefined;
14
+ disabled?: 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;
37
35
  hidden?: boolean | undefined;
36
+ disabled?: 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,8 +6,8 @@
6
6
  @see https://www.w3.org/WAI/ARIA/apg/patterns/radio/
7
7
  -->
8
8
  <script>
9
- import { getRandomId } from '../../services/util';
10
9
  import Button from '../button/button.svelte';
10
+ import { getRandomId } from '../../services/util';
11
11
 
12
12
  /**
13
13
  * The `class` attribute on the wrapper element.
@@ -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;
17
- value?: string | undefined;
18
15
  hidden?: boolean | undefined;
16
+ disabled?: boolean | undefined;
17
+ value?: string | 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;
42
- value?: string | undefined;
43
40
  hidden?: boolean | undefined;
41
+ disabled?: boolean | undefined;
42
+ value?: string | undefined;
43
+ checked?: boolean | undefined;
44
44
  };
45
45
  events: {
46
46
  focus: FocusEvent;
@@ -9,13 +9,13 @@
9
9
  import { createEventDispatcher } from 'svelte';
10
10
  import { _ } from 'svelte-i18n';
11
11
  import { writable } from 'svelte/store';
12
- import { getRandomId } from '../../services/util';
13
12
  import Button from '../button/button.svelte';
14
13
  import Icon from '../icon/icon.svelte';
15
14
  import Listbox from '../listbox/listbox.svelte';
16
15
  import SearchBar from '../text-field/search-bar.svelte';
17
16
  import TextInput from '../text-field/text-input.svelte';
18
17
  import Popup from '../util/popup.svelte';
18
+ import { getRandomId } from '../../services/util';
19
19
 
20
20
  /**
21
21
  * The `class` attribute on the wrapper element.
@@ -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;
16
- value?: string | number | undefined;
17
14
  position?: PopupPosition | undefined;
18
15
  hidden?: boolean | undefined;
16
+ disabled?: boolean | undefined;
17
+ value?: string | number | 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;
43
- value?: (string | number | undefined);
44
41
  position?: PopupPosition | undefined;
45
42
  hidden?: boolean | undefined;
43
+ disabled?: boolean | undefined;
44
+ value?: (string | number | 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;
16
- value?: string | number | undefined;
17
14
  hidden?: boolean | undefined;
15
+ disabled?: boolean | undefined;
16
+ value?: string | number | 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;
38
- value?: (string | number | undefined);
39
36
  hidden?: boolean | undefined;
37
+ disabled?: boolean | undefined;
38
+ value?: (string | number | undefined);
40
39
  readonly?: boolean | undefined;
40
+ required?: boolean | undefined;
41
41
  };
42
42
  events: {
43
43
  change: CustomEvent<any>;
@@ -172,6 +172,8 @@
172
172
  return;
173
173
  }
174
174
 
175
+ event.stopPropagation();
176
+
175
177
  moveThumb(startX + (screenX - startScreenX));
176
178
  };
177
179
 
@@ -186,6 +188,13 @@
186
188
  return;
187
189
  }
188
190
 
191
+ event.stopPropagation();
192
+
193
+ // Handle a click on the bars
194
+ if (/** @type {HTMLElement} */ (event.target).matches('.base-bar, .slider-bar')) {
195
+ moveThumb(/** @type {any} */ (event).layerX);
196
+ }
197
+
189
198
  // Reset everything
190
199
  dragging = false;
191
200
  startX = 0;
@@ -211,6 +220,8 @@
211
220
  return;
212
221
  }
213
222
 
223
+ event.stopPropagation();
224
+
214
225
  dragging = true;
215
226
  startX = clientX - /** @type {HTMLElement} */ (base).getBoundingClientRect().x;
216
227
  startScreenX = screenX;
@@ -222,18 +233,6 @@
222
233
  document.addEventListener('pointercancel', onPointerUp);
223
234
  };
224
235
 
225
- /**
226
- * Handle the `click` event fired on the slider.
227
- * @param {MouseEvent} event - `click` event.
228
- */
229
- const onClick = (event) => {
230
- if (disabled || readonly || multiThumb || dragging) {
231
- return;
232
- }
233
-
234
- moveThumb(/** @type {any} */ (event).layerX);
235
- };
236
-
237
236
  /**
238
237
  * Update the thumb position and fire the `change` event when the value is changed.
239
238
  */
@@ -271,7 +270,7 @@
271
270
 
272
271
  onMount(() => {
273
272
  const observer = new ResizeObserver(() => init());
274
- const query = window.matchMedia('(pointer: coarse)');
273
+ const query = globalThis.matchMedia('(pointer: coarse)');
275
274
 
276
275
  observer.observe(/** @type {HTMLElement} */ (base));
277
276
  query.addEventListener('change', init);
@@ -303,14 +302,8 @@
303
302
  class:readonly
304
303
  hidden={hidden || undefined}
305
304
  {...$$restProps}
306
- on:click|preventDefault|stopPropagation
307
305
  >
308
- <div
309
- role="none"
310
- class="base"
311
- bind:this={base}
312
- on:click|preventDefault|stopPropagation={(event) => onClick(event)}
313
- >
306
+ <div role="none" class="base" bind:this={base} on:pointerdown={(event) => onPointerDown(event)}>
314
307
  <div role="none" class="base-bar" />
315
308
  <div
316
309
  class="slider-bar"
@@ -12,20 +12,19 @@
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;
20
- value?: number | undefined;
21
16
  hidden?: boolean | undefined;
17
+ disabled?: boolean | undefined;
18
+ value?: number | 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
- click: MouseEvent;
29
28
  change: CustomEvent<any>;
30
29
  } & {
31
30
  [evt: string]: CustomEvent<any>;
@@ -39,21 +38,20 @@ declare const __propDef: {
39
38
  props: {
40
39
  [x: string]: any;
41
40
  class?: string | undefined;
42
- disabled?: boolean | undefined;
43
41
  invalid?: boolean | undefined;
44
- max?: number | undefined;
45
- min?: number | undefined;
46
- step?: number | undefined;
47
- value?: number | undefined;
48
42
  hidden?: boolean | undefined;
43
+ disabled?: boolean | undefined;
44
+ value?: number | undefined;
49
45
  readonly?: boolean | undefined;
50
46
  values?: [number, number] | undefined;
47
+ min?: number | undefined;
48
+ max?: number | undefined;
51
49
  sliderLabel?: string | undefined;
52
50
  sliderLabels?: [string, string] | undefined;
51
+ step?: number | undefined;
53
52
  optionLabels?: string[] | number[] | undefined;
54
53
  };
55
54
  events: {
56
- click: MouseEvent;
57
55
  change: CustomEvent<any>;
58
56
  } & {
59
57
  [evt: string]: CustomEvent<any>;
@@ -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
- invalid?: boolean | undefined;
14
12
  label?: string | undefined;
15
- checked?: boolean | "mixed" | undefined;
16
- required?: boolean | undefined;
13
+ invalid?: boolean | undefined;
17
14
  hidden?: boolean | undefined;
15
+ disabled?: 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
- invalid?: boolean | undefined;
37
35
  label?: string | undefined;
38
- checked?: boolean | "mixed" | undefined;
39
- required?: boolean | undefined;
36
+ invalid?: boolean | undefined;
40
37
  hidden?: boolean | undefined;
38
+ disabled?: 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>;
@@ -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
  );
@@ -10,8 +10,8 @@ export default class TabList extends SvelteComponent<{
10
10
  [x: string]: any;
11
11
  class?: string | undefined;
12
12
  name?: string | undefined;
13
- disabled?: boolean | undefined;
14
13
  hidden?: boolean | undefined;
14
+ disabled?: boolean | undefined;
15
15
  orientation?: "vertical" | "horizontal" | undefined;
16
16
  }, {
17
17
  change: CustomEvent<any>;
@@ -30,8 +30,8 @@ declare const __propDef: {
30
30
  [x: string]: any;
31
31
  class?: string | undefined;
32
32
  name?: string | undefined;
33
- disabled?: boolean | undefined;
34
33
  hidden?: boolean | undefined;
34
+ disabled?: boolean | undefined;
35
35
  orientation?: "vertical" | "horizontal" | undefined;
36
36
  };
37
37
  events: {
@@ -9,8 +9,8 @@
9
9
  export default class Tab extends SvelteComponent<{
10
10
  [x: string]: any;
11
11
  class?: string | undefined;
12
- disabled?: boolean | undefined;
13
12
  hidden?: boolean | undefined;
13
+ disabled?: boolean | undefined;
14
14
  selected?: boolean | undefined;
15
15
  }, {
16
16
  focus: FocusEvent;
@@ -37,8 +37,8 @@ declare const __propDef: {
37
37
  props: {
38
38
  [x: string]: any;
39
39
  class?: string | undefined;
40
- disabled?: boolean | undefined;
41
40
  hidden?: boolean | undefined;
41
+ disabled?: boolean | undefined;
42
42
  selected?: boolean | undefined;
43
43
  };
44
44
  events: {
@@ -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
+ });