@sveltia/ui 0.78.4 → 0.79.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 (181) hide show
  1. package/dist/components/alert/alert-content.svelte +51 -0
  2. package/dist/components/alert/alert-content.svelte.d.ts +39 -0
  3. package/dist/components/alert/alert.d.ts +3 -0
  4. package/dist/components/alert/alert.js +21 -0
  5. package/dist/components/alert/alert.svelte +6 -30
  6. package/dist/components/alert/infobar.svelte +7 -21
  7. package/dist/components/alert/infobar.svelte.d.ts +2 -2
  8. package/dist/components/button/button.svelte +11 -11
  9. package/dist/components/button/button.svelte.d.ts +2 -2
  10. package/dist/components/button/select-button.svelte +1 -1
  11. package/dist/components/button/select-button.svelte.d.ts +2 -2
  12. package/dist/components/button/split-button.svelte +1 -1
  13. package/dist/components/button/split-button.svelte.d.ts +3 -3
  14. package/dist/components/calendar/calendar.d.ts +2 -0
  15. package/dist/components/calendar/calendar.js +34 -0
  16. package/dist/components/calendar/calendar.svelte +49 -5
  17. package/dist/components/checkbox/checkbox.svelte +11 -4
  18. package/dist/components/checkbox/checkbox.svelte.d.ts +2 -2
  19. package/dist/components/dialog/alert-dialog.svelte +1 -1
  20. package/dist/components/dialog/alert-dialog.svelte.d.ts +2 -2
  21. package/dist/components/dialog/confirmation-dialog.svelte +1 -1
  22. package/dist/components/dialog/confirmation-dialog.svelte.d.ts +2 -2
  23. package/dist/components/dialog/dialog.svelte +8 -18
  24. package/dist/components/dialog/dialog.svelte.d.ts +2 -2
  25. package/dist/components/dialog/modal-close-button.svelte +50 -0
  26. package/dist/components/dialog/modal-close-button.svelte.d.ts +43 -0
  27. package/dist/components/dialog/prompt-dialog.svelte +1 -1
  28. package/dist/components/dialog/prompt-dialog.svelte.d.ts +4 -4
  29. package/dist/components/disclosure/disclosure.svelte +1 -1
  30. package/dist/components/drawer/drawer.svelte +12 -34
  31. package/dist/components/drawer/drawer.svelte.d.ts +1 -1
  32. package/dist/components/emoji/caret.d.ts +1 -1
  33. package/dist/components/emoji/caret.js +1 -1
  34. package/dist/components/emoji/emoji-suggestions.svelte +1 -1
  35. package/dist/components/emoji/emoji-suggestions.svelte.d.ts +3 -3
  36. package/dist/components/emoji/emoji.d.ts +2 -2
  37. package/dist/components/emoji/emoji.js +1 -1
  38. package/dist/components/emoji/position.d.ts +2 -2
  39. package/dist/components/emoji/position.js +1 -1
  40. package/dist/components/grid/grid-body.svelte +6 -2
  41. package/dist/components/grid/grid-cell.svelte +3 -9
  42. package/dist/components/grid/grid-col-header.svelte +3 -9
  43. package/dist/components/grid/grid-foot.svelte +4 -11
  44. package/dist/components/grid/grid-head.svelte +4 -11
  45. package/dist/components/grid/grid-row-header.svelte +3 -10
  46. package/dist/components/grid/grid-row.svelte +3 -16
  47. package/dist/components/listbox/listbox.svelte +1 -1
  48. package/dist/components/listbox/listbox.svelte.d.ts +1 -1
  49. package/dist/components/listbox/option.svelte +1 -1
  50. package/dist/components/listbox/option.svelte.d.ts +2 -2
  51. package/dist/components/menu/menu-button.svelte +2 -2
  52. package/dist/components/menu/menu-button.svelte.d.ts +4 -4
  53. package/dist/components/menu/menu-item-checkable.svelte +71 -0
  54. package/dist/components/menu/menu-item-checkable.svelte.d.ts +25 -0
  55. package/dist/components/menu/menu-item-checkbox.svelte +3 -36
  56. package/dist/components/menu/menu-item-checkbox.svelte.d.ts +3 -3
  57. package/dist/components/menu/menu-item-group.svelte +8 -5
  58. package/dist/components/menu/menu-item-group.svelte.d.ts +9 -1
  59. package/dist/components/menu/menu-item-radio.svelte +3 -36
  60. package/dist/components/menu/menu-item-radio.svelte.d.ts +3 -3
  61. package/dist/components/menu/menu-item.svelte +22 -6
  62. package/dist/components/menu/menu-item.svelte.d.ts +4 -4
  63. package/dist/components/radio/radio.svelte +12 -1
  64. package/dist/components/resizable-pane/resizable-handle.svelte +14 -18
  65. package/dist/components/resizable-pane/resizable-pane-group.svelte +9 -6
  66. package/dist/components/resizable-pane/resizable-pane.svelte +4 -4
  67. package/dist/components/resizable-pane/resizable-pane.svelte.d.ts +7 -6
  68. package/dist/components/resizable-pane/sizing.d.ts +5 -4
  69. package/dist/components/resizable-pane/sizing.js +84 -25
  70. package/dist/components/scroll/infinite-scroll.svelte +16 -21
  71. package/dist/components/select/combobox.svelte +43 -52
  72. package/dist/components/select/combobox.svelte.d.ts +2 -2
  73. package/dist/components/select/select-tags.svelte +7 -1
  74. package/dist/components/select/select.svelte +2 -22
  75. package/dist/components/select/select.svelte.d.ts +1 -1
  76. package/dist/components/slider/slider.d.ts +6 -0
  77. package/dist/components/slider/slider.js +55 -2
  78. package/dist/components/slider/slider.svelte +63 -32
  79. package/dist/components/table/table-cell.svelte +3 -9
  80. package/dist/components/table/table-col-header.svelte +3 -9
  81. package/dist/components/table/table-foot.svelte +4 -11
  82. package/dist/components/table/table-head.svelte +4 -11
  83. package/dist/components/table/table-part.svelte +69 -0
  84. package/dist/components/table/table-part.svelte.d.ts +48 -0
  85. package/dist/components/table/table-row-header.svelte +3 -10
  86. package/dist/components/table/table-row.svelte +3 -10
  87. package/dist/components/tabs/tab-list.svelte +12 -0
  88. package/dist/components/tabs/tab.svelte +1 -1
  89. package/dist/components/tabs/tab.svelte.d.ts +2 -2
  90. package/dist/components/text-editor/constants.d.ts +5 -5
  91. package/dist/components/text-editor/constants.js +1 -1
  92. package/dist/components/text-editor/core.d.ts +4 -5
  93. package/dist/components/text-editor/core.js +372 -285
  94. package/dist/components/text-editor/emoji-autocomplete.svelte +1 -1
  95. package/dist/components/text-editor/lexical-root.svelte +1 -1
  96. package/dist/components/text-editor/raw-markdown.d.ts +6 -33
  97. package/dist/components/text-editor/raw-markdown.js +63 -8
  98. package/dist/components/text-editor/shiki/facade.d.ts +1 -1
  99. package/dist/components/text-editor/shiki/facade.js +63 -48
  100. package/dist/components/text-editor/shiki/generated.d.ts +1 -1
  101. package/dist/components/text-editor/shiki/generated.js +1 -1
  102. package/dist/components/text-editor/shiki/highlighter.d.ts +6 -1
  103. package/dist/components/text-editor/shiki/highlighter.js +3 -4
  104. package/dist/components/text-editor/shiki/loader.d.ts +1 -1
  105. package/dist/components/text-editor/shiki/loader.js +1 -1
  106. package/dist/components/text-editor/shiki/version.d.ts +1 -1
  107. package/dist/components/text-editor/shiki/version.js +1 -1
  108. package/dist/components/text-editor/store.svelte.d.ts +1 -1
  109. package/dist/components/text-editor/store.svelte.js +5 -2
  110. package/dist/components/text-editor/text-editor.svelte +2 -2
  111. package/dist/components/text-editor/text-editor.svelte.d.ts +3 -3
  112. package/dist/components/text-editor/toolbar/code-language-switcher.svelte +24 -16
  113. package/dist/components/text-editor/toolbar/format-text-button.svelte +7 -31
  114. package/dist/components/text-editor/toolbar/format-text-button.svelte.d.ts +1 -1
  115. package/dist/components/text-editor/toolbar/insert-component.d.ts +3 -0
  116. package/dist/components/text-editor/toolbar/insert-component.js +34 -0
  117. package/dist/components/text-editor/toolbar/insert-item-button.svelte +4 -24
  118. package/dist/components/text-editor/toolbar/insert-item-button.svelte.d.ts +1 -1
  119. package/dist/components/text-editor/toolbar/insert-link-button.svelte +9 -25
  120. package/dist/components/text-editor/toolbar/insert-menu-button.svelte +4 -24
  121. package/dist/components/text-editor/toolbar/insert-menu-button.svelte.d.ts +1 -1
  122. package/dist/components/text-editor/toolbar/text-editor-toolbar.svelte +1 -1
  123. package/dist/components/text-editor/toolbar/toggle-block-menu-item.svelte +31 -35
  124. package/dist/components/text-editor/toolbar/toggle-block-menu-item.svelte.d.ts +1 -1
  125. package/dist/components/text-editor/toolbar/toolbar-wrapper.svelte +0 -10
  126. package/dist/components/text-editor/toolbar/toolbar-wrapper.svelte.d.ts +1 -11
  127. package/dist/components/text-editor/transformers/table.d.ts +0 -1
  128. package/dist/components/text-editor/transformers/table.js +1 -2
  129. package/dist/components/text-field/emoji-autocomplete.svelte +1 -1
  130. package/dist/components/text-field/masked-input.svelte +179 -0
  131. package/dist/components/text-field/masked-input.svelte.d.ts +42 -0
  132. package/dist/components/text-field/number-input.js +7 -1
  133. package/dist/components/text-field/number-input.svelte +13 -5
  134. package/dist/components/text-field/number-input.svelte.d.ts +3 -3
  135. package/dist/components/text-field/password-input.svelte +3 -116
  136. package/dist/components/text-field/password-input.svelte.d.ts +3 -3
  137. package/dist/components/text-field/search-bar.svelte +1 -1
  138. package/dist/components/text-field/search-bar.svelte.d.ts +3 -3
  139. package/dist/components/text-field/secret-input.svelte +3 -119
  140. package/dist/components/text-field/secret-input.svelte.d.ts +3 -3
  141. package/dist/components/text-field/text-area.svelte +1 -1
  142. package/dist/components/text-field/text-area.svelte.d.ts +3 -3
  143. package/dist/components/text-field/text-input.svelte +1 -1
  144. package/dist/components/text-field/text-input.svelte.d.ts +3 -3
  145. package/dist/components/toast/toast.svelte +11 -20
  146. package/dist/components/toast/toast.svelte.d.ts +1 -1
  147. package/dist/components/tree/tree-item.svelte +1 -1
  148. package/dist/components/tree/tree-item.svelte.d.ts +1 -1
  149. package/dist/components/tree/tree.svelte +1 -1
  150. package/dist/components/tree/tree.svelte.d.ts +1 -1
  151. package/dist/components/util/font-links.svelte +1 -0
  152. package/dist/components/util/modal.svelte +37 -1
  153. package/dist/components/util/modal.svelte.d.ts +1 -1
  154. package/dist/components/util/popup.svelte +2 -5
  155. package/dist/components/util/popup.svelte.d.ts +2 -2
  156. package/dist/components/util/visibility-observer.svelte +1 -0
  157. package/dist/locales/ar.yaml +1 -1
  158. package/dist/locales/sk.yaml +136 -0
  159. package/dist/services/group.svelte.d.ts +10 -1
  160. package/dist/services/group.svelte.js +361 -251
  161. package/dist/services/navigation.d.ts +19 -0
  162. package/dist/services/navigation.js +84 -0
  163. package/dist/services/popup-position.d.ts +90 -0
  164. package/dist/services/popup-position.js +275 -0
  165. package/dist/services/popup.svelte.d.ts +16 -17
  166. package/dist/services/popup.svelte.js +25 -169
  167. package/dist/services/scroll.d.ts +1 -0
  168. package/dist/services/scroll.js +17 -0
  169. package/dist/services/select.svelte.d.ts +2 -2
  170. package/dist/services/select.svelte.js +1 -1
  171. package/dist/services/text.d.ts +2 -0
  172. package/dist/services/text.js +28 -0
  173. package/dist/services/tree.svelte.d.ts +3 -11
  174. package/dist/services/tree.svelte.js +35 -77
  175. package/dist/services/type-ahead.d.ts +0 -4
  176. package/dist/services/type-ahead.js +3 -1
  177. package/dist/services/widget.d.ts +8 -0
  178. package/dist/services/widget.js +39 -0
  179. package/dist/shiki-engine.js +15 -15
  180. package/dist/styles/mixins.scss +126 -0
  181. package/package.json +24 -20
@@ -0,0 +1,34 @@
1
+ import { $createParagraphNode as createParagraphNode, $insertNodes as insertNodes } from 'lexical';
2
+ import { insertComponent } from '../raw-markdown.js';
3
+
4
+ /**
5
+ * @import { TextEditorComponent, TextEditorStore } from '../../../typedefs.js';
6
+ */
7
+
8
+ /**
9
+ * Insert a new instance of the given editor component into the editor: its Markdown in the plain
10
+ * text mode, or its node in the rich text mode.
11
+ * @param {TextEditorStore} editorStore Editor store.
12
+ * @param {TextEditorComponent} component Editor component.
13
+ */
14
+ export const insertEditorComponent = (editorStore, component) => {
15
+ const { textArea, useRichText } = editorStore;
16
+
17
+ // Insert the component’s Markdown in the plain text mode
18
+ if (!useRichText) {
19
+ // The toolbar is only enabled while the `<textarea>` is there
20
+ /* v8 ignore else */
21
+ if (textArea) {
22
+ insertComponent(textArea, component);
23
+ }
24
+
25
+ return;
26
+ }
27
+
28
+ const { createNode } = component;
29
+
30
+ editorStore.editor?.update(() => {
31
+ // Add an additional paragraph for easier editing
32
+ insertNodes([createNode(), createParagraphNode()]);
33
+ });
34
+ };
@@ -1,15 +1,11 @@
1
1
  <script>
2
- import {
3
- $createParagraphNode as createParagraphNode,
4
- $insertNodes as insertNodes,
5
- } from 'lexical';
6
2
  import { getContext } from 'svelte';
7
3
  import Button from '../../button/button.svelte';
8
4
  import Icon from '../../icon/icon.svelte';
9
- import { insertComponent } from '../raw-markdown.js';
5
+ import { insertEditorComponent } from './insert-component.js';
10
6
 
11
7
  /**
12
- * @import { TextEditorComponent, TextEditorStore } from '../../../typedefs';
8
+ * @import { TextEditorComponent, TextEditorStore } from '../../../typedefs.js';
13
9
  */
14
10
 
15
11
  /**
@@ -27,7 +23,7 @@
27
23
  /** @type {TextEditorStore} */
28
24
  const editorStore = getContext('editorStore');
29
25
 
30
- const { label, icon, createNode } = $derived(component);
26
+ const { label, icon } = $derived(component);
31
27
  </script>
32
28
 
33
29
  <Button
@@ -37,23 +33,7 @@
37
33
  aria-label={label}
38
34
  aria-controls={editorStore.controlId}
39
35
  onclick={() => {
40
- const { textArea, useRichText } = editorStore;
41
-
42
- // Insert the component’s Markdown in the plain text mode
43
- if (!useRichText) {
44
- // The button is only enabled while the `<textarea>` is there
45
- /* v8 ignore else */
46
- if (textArea) {
47
- insertComponent(textArea, component);
48
- }
49
-
50
- return;
51
- }
52
-
53
- editorStore.editor?.update(() => {
54
- // Add an additional paragraph for easier editing
55
- insertNodes([createNode(), createParagraphNode()]);
56
- });
36
+ insertEditorComponent(editorStore, component);
57
37
  }}
58
38
  >
59
39
  {#snippet startIcon()}
@@ -15,4 +15,4 @@ type Props = {
15
15
  */
16
16
  component: TextEditorComponent;
17
17
  };
18
- import type { TextEditorComponent } from '../../../typedefs';
18
+ import type { TextEditorComponent } from '../../../typedefs.js';
@@ -24,14 +24,14 @@
24
24
  import { AVAILABLE_BUTTONS } from '../constants.js';
25
25
  import { focusEditor, isSafeLinkURL } from '../core.js';
26
26
  import {
27
- applyRawTextEdit,
27
+ editRawText,
28
28
  getRawTextState,
29
29
  insertLink,
30
- isRawTextEditable,
30
+ registerRawTextShortcut,
31
31
  } from '../raw-markdown.js';
32
32
 
33
33
  /**
34
- * @import { TextEditorStore } from '../../../typedefs';
34
+ * @import { TextEditorStore } from '../../../typedefs.js';
35
35
  * @import { RangeSelection } from 'lexical';
36
36
  */
37
37
 
@@ -169,12 +169,8 @@
169
169
  /* v8 ignore else */
170
170
  if (textArea) {
171
171
  if (event.detail.returnValue !== 'cancel') {
172
- applyRawTextEdit(
173
- textArea,
174
- insertLink(getRawTextState(textArea), {
175
- url: anchorURL.trim(),
176
- text: hasAnchor ? undefined : anchorText,
177
- }),
172
+ editRawText(textArea, (state) =>
173
+ insertLink(state, { url: anchorURL.trim(), text: hasAnchor ? undefined : anchorText }),
178
174
  );
179
175
  } else {
180
176
  textArea.focus();
@@ -249,22 +245,10 @@
249
245
  return undefined;
250
246
  }
251
247
 
252
- /**
253
- * Handle the keyboard shortcut in the plain text mode.
254
- * @param {KeyboardEvent} event `keydown` event.
255
- */
256
- const onKeyDown = (event) => {
257
- if (isRawTextEditable(textArea) && matchesShortcuts(event, isMac() ? 'Meta+K' : 'Ctrl+K')) {
258
- event.preventDefault();
259
- onButtonClick();
260
- }
261
- };
262
-
263
- textArea.addEventListener('keydown', onKeyDown);
264
-
265
- return () => {
266
- textArea.removeEventListener('keydown', onKeyDown);
267
- };
248
+ // Handle the keyboard shortcut in the plain text mode
249
+ return registerRawTextShortcut(textArea, 'K', () => {
250
+ onButtonClick();
251
+ });
268
252
  });
269
253
 
270
254
  $effect(() => {
@@ -1,18 +1,14 @@
1
1
  <script>
2
2
  import { _ } from '@sveltia/i18n';
3
- import {
4
- $createParagraphNode as createParagraphNode,
5
- $insertNodes as insertNodes,
6
- } from 'lexical';
7
3
  import { getContext } from 'svelte';
8
4
  import Icon from '../../icon/icon.svelte';
9
5
  import MenuButton from '../../menu/menu-button.svelte';
10
6
  import MenuItem from '../../menu/menu-item.svelte';
11
7
  import Menu from '../../menu/menu.svelte';
12
- import { insertComponent } from '../raw-markdown.js';
8
+ import { insertEditorComponent } from './insert-component.js';
13
9
 
14
10
  /**
15
- * @import { TextEditorComponent, TextEditorStore } from '../../../typedefs';
11
+ * @import { TextEditorComponent, TextEditorStore } from '../../../typedefs.js';
16
12
  */
17
13
 
18
14
  /**
@@ -38,27 +34,11 @@
38
34
  {#snippet popup()}
39
35
  <Menu>
40
36
  {#each components as component (component.id)}
41
- {@const { label, icon, createNode } = component}
37
+ {@const { label, icon } = component}
42
38
  <MenuItem
43
39
  {label}
44
40
  onclick={() => {
45
- const { textArea, useRichText } = editorStore;
46
-
47
- // Insert the component’s Markdown in the plain text mode
48
- if (!useRichText) {
49
- // The item is only clickable while the `<textarea>` is there
50
- /* v8 ignore else */
51
- if (textArea) {
52
- insertComponent(textArea, component);
53
- }
54
-
55
- return;
56
- }
57
-
58
- editorStore.editor?.update(() => {
59
- // Add an additional paragraph for easier editing
60
- insertNodes([createNode(), createParagraphNode()]);
61
- });
41
+ insertEditorComponent(editorStore, component);
62
42
  }}
63
43
  >
64
44
  {#snippet startIcon()}
@@ -15,4 +15,4 @@ type Props = {
15
15
  */
16
16
  components: TextEditorComponent[];
17
17
  };
18
- import type { TextEditorComponent } from '../../../typedefs';
18
+ import type { TextEditorComponent } from '../../../typedefs.js';
@@ -19,7 +19,7 @@
19
19
  import ToolbarWrapper from './toolbar-wrapper.svelte';
20
20
 
21
21
  /**
22
- * @import { TextEditorBlockType, TextEditorInlineType, TextEditorStore } from '../../../typedefs';
22
+ * @import { TextEditorBlockType, TextEditorInlineType, TextEditorStore } from '../../../typedefs.js';
23
23
  */
24
24
 
25
25
  /**
@@ -16,13 +16,34 @@
16
16
  import MenuItemCheckbox from '../../menu/menu-item-checkbox.svelte';
17
17
  import { AVAILABLE_BUTTONS } from '../constants.js';
18
18
  import { focusEditor } from '../core.js';
19
- import { applyRawTextEdit, getRawTextState, setBlockType } from '../raw-markdown.js';
19
+ import { editRawText, setBlockType } from '../raw-markdown.js';
20
20
 
21
21
  /**
22
- * @import { TextEditorBlockType, TextEditorStore } from '../../../typedefs';
22
+ * @import { TextEditorBlockType, TextEditorStore } from '../../../typedefs.js';
23
23
  * @import { HeadingTagType } from '@lexical/rich-text';
24
+ * @import { ElementNode, LexicalCommand } from 'lexical';
24
25
  */
25
26
 
27
+ /**
28
+ * Node factories for the block types applied with `$setBlocksType()`, except headings, whose
29
+ * level is parsed from the type.
30
+ * @type {Record<string, () => ElementNode>}
31
+ */
32
+ const NODE_FACTORIES = {
33
+ paragraph: createParagraphNode,
34
+ blockquote: createQuoteNode,
35
+ 'code-block': createCodeNode,
36
+ };
37
+
38
+ /**
39
+ * Commands for the list block types, which are toggled by the list plugin instead.
40
+ * @type {Record<string, LexicalCommand<void>>}
41
+ */
42
+ const LIST_COMMANDS = {
43
+ 'bulleted-list': INSERT_UNORDERED_LIST_COMMAND,
44
+ 'numbered-list': INSERT_ORDERED_LIST_COMMAND,
45
+ };
46
+
26
47
  /**
27
48
  * @typedef {object} Props
28
49
  * @property {TextEditorBlockType} type Button type.
@@ -46,13 +67,8 @@
46
67
  */
47
68
  const changeBlockType = async () => {
48
69
  if (!editorStore.useRichText) {
49
- const { textArea } = editorStore;
50
-
51
70
  // The item is only clickable while the `<textarea>` is there
52
- /* v8 ignore else */
53
- if (textArea) {
54
- applyRawTextEdit(textArea, setBlockType(getRawTextState(textArea), type));
55
- }
71
+ editRawText(editorStore.textArea, (state) => setBlockType(state, type));
56
72
 
57
73
  return;
58
74
  }
@@ -67,38 +83,18 @@
67
83
 
68
84
  const [, headingLevel] = type.match(/^heading-(\d)$/) ?? [];
69
85
 
70
- if (headingLevel) {
71
- editorStore.editor.update(() => {
72
- setBlocksType(getSelection(), () =>
73
- createHeadingNode(/** @type {HeadingTagType} */ (`h${headingLevel}`)),
74
- );
75
- });
76
- }
86
+ const createNode = headingLevel
87
+ ? () => createHeadingNode(/** @type {HeadingTagType} */ (`h${headingLevel}`))
88
+ : NODE_FACTORIES[type];
77
89
 
78
- if (type === 'paragraph') {
90
+ if (createNode) {
79
91
  editorStore.editor.update(() => {
80
- setBlocksType(getSelection(), () => createParagraphNode());
92
+ setBlocksType(getSelection(), createNode);
81
93
  });
82
94
  }
83
95
 
84
- if (type === 'bulleted-list') {
85
- editorStore.editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);
86
- }
87
-
88
- if (type === 'numbered-list') {
89
- editorStore.editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);
90
- }
91
-
92
- if (type === 'blockquote') {
93
- editorStore.editor.update(() => {
94
- setBlocksType(getSelection(), () => createQuoteNode());
95
- });
96
- }
97
-
98
- if (type === 'code-block') {
99
- editorStore.editor.update(() => {
100
- setBlocksType(getSelection(), () => createCodeNode());
101
- });
96
+ if (type in LIST_COMMANDS) {
97
+ editorStore.editor.dispatchCommand(LIST_COMMANDS[type], undefined);
102
98
  }
103
99
  };
104
100
  </script>
@@ -15,4 +15,4 @@ type Props = {
15
15
  */
16
16
  type: TextEditorBlockType;
17
17
  };
18
- import type { TextEditorBlockType } from '../../../typedefs';
18
+ import type { TextEditorBlockType } from '../../../typedefs.js';
@@ -9,8 +9,6 @@
9
9
  * @typedef {object} Props
10
10
  * @property {boolean} [disabled] Whether to disable the widget. An alias of the `aria-disabled`
11
11
  * attribute.
12
- * @property {boolean} [readonly] Whether to make the widget read-only. An alias of the
13
- * `aria-readonly` attribute.
14
12
  * @property {Snippet} [children] Primary slot content.
15
13
  */
16
14
 
@@ -19,8 +17,6 @@
19
17
  */
20
18
  let {
21
19
  /* eslint-disable prefer-const */
22
- code = $bindable(''),
23
- lang = $bindable('plain'),
24
20
  disabled = false,
25
21
  children,
26
22
  ...restProps
@@ -56,12 +52,6 @@
56
52
  min-height: 40px;
57
53
  background-color: var(--sui-tertiary-background-color);
58
54
  }
59
- @media (width < 768px) {
60
- .wrapper :global([role=toolbar]) {
61
- flex-wrap: wrap;
62
- height: auto;
63
- }
64
- }
65
55
  .wrapper :global(.sui.menu-button) {
66
56
  padding: 0 4px;
67
57
  }
@@ -9,27 +9,17 @@ declare const ToolbarWrapper: import("svelte").Component<{
9
9
  * attribute.
10
10
  */
11
11
  disabled?: boolean | undefined;
12
- /**
13
- * Whether to make the widget read-only. An alias of the
14
- * `aria-readonly` attribute.
15
- */
16
- readonly?: boolean | undefined;
17
12
  /**
18
13
  * Primary slot content.
19
14
  */
20
15
  children?: Snippet<[]> | undefined;
21
- } & Record<string, any>, {}, "code" | "lang">;
16
+ } & Record<string, any>, {}, "">;
22
17
  type Props = {
23
18
  /**
24
19
  * Whether to disable the widget. An alias of the `aria-disabled`
25
20
  * attribute.
26
21
  */
27
22
  disabled?: boolean | undefined;
28
- /**
29
- * Whether to make the widget read-only. An alias of the
30
- * `aria-readonly` attribute.
31
- */
32
- readonly?: boolean | undefined;
33
23
  /**
34
24
  * Primary slot content.
35
25
  */
@@ -1,5 +1,4 @@
1
1
  export function getTableColumnsSize(table: TableNode): number;
2
- export function createTableCell(textContent: string): TableCellNode;
3
2
  export function mapToTableCells(textContent: string): TableCellNode[] | null;
4
3
  /**
5
4
  * @type {ElementTransformer}
@@ -44,11 +44,10 @@ export const getTableColumnsSize = (table) => {
44
44
 
45
45
  /**
46
46
  * Creates a table cell with the given text content.
47
- * @internal
48
47
  * @param {string} textContent
49
48
  * @returns {TableCellNode}
50
49
  */
51
- export const createTableCell = (textContent) => {
50
+ const createTableCell = (textContent) => {
52
51
  textContent = textContent.replace(/\\n/g, '\n');
53
52
 
54
53
  const cell = createTableCellNode(TableCellHeaderStates.NO_STATUS);
@@ -11,7 +11,7 @@
11
11
  import EmojiSuggestions from '../emoji/emoji-suggestions.svelte';
12
12
 
13
13
  /**
14
- * @import { EmojiEntry, EmojiTrigger } from '../../typedefs';
14
+ * @import { EmojiEntry, EmojiTrigger } from '../../typedefs.js';
15
15
  */
16
16
 
17
17
  /**
@@ -0,0 +1,179 @@
1
+ <!--
2
+ @component
3
+ Internal base of `<PasswordInput>` and `<SecretInput>`: a text field whose value is masked, with a
4
+ Show/Hide button.
5
+ -->
6
+ <script>
7
+ import { _ } from '@sveltia/i18n';
8
+ import Button from '../button/button.svelte';
9
+ import Icon from '../icon/icon.svelte';
10
+ import TextInput from './text-input.svelte';
11
+
12
+ /**
13
+ * @import { Snippet } from 'svelte';
14
+ * @import { CommonEventHandlers, InputEventHandlers, TextInputProps } from '../../typedefs.js';
15
+ */
16
+
17
+ /**
18
+ * @typedef {object} Props
19
+ * @property {'type' | 'css'} mask How to mask the value: `type` uses `type="password"`, while
20
+ * `css` uses `-webkit-text-security` so password managers don’t prompt to save the value.
21
+ * @property {string} [value] Input value.
22
+ * @property {Snippet} [visibilityIcon] Visibility icon slot content.
23
+ */
24
+
25
+ /**
26
+ * @type {TextInputProps & CommonEventHandlers & InputEventHandlers & Props & Record<string, any>}
27
+ */
28
+ let {
29
+ /* eslint-disable prefer-const */
30
+ mask,
31
+ value = $bindable(),
32
+ flex = false,
33
+ monospace = true,
34
+ class: className,
35
+ hidden = false,
36
+ disabled = false,
37
+ readonly = false,
38
+ required = false,
39
+ invalid = false,
40
+ // Not rendered, but kept out of `restProps` so it isn’t spread onto the `<input>`
41
+ children,
42
+ visibilityIcon,
43
+ ...restProps
44
+ /* eslint-enable prefer-const */
45
+ } = $props();
46
+
47
+ const id = $props.id();
48
+
49
+ /**
50
+ * Reference to the `<input>` element.
51
+ * @type {HTMLInputElement | undefined}
52
+ */
53
+ let inputElement = $state();
54
+ let show = $state(false);
55
+
56
+ const labels = $derived(
57
+ mask === 'type'
58
+ ? {
59
+ show: '_sui.password_input.show_password',
60
+ hide: '_sui.password_input.hide_password',
61
+ }
62
+ : {
63
+ show: '_sui.secret_input.show_secret',
64
+ hide: '_sui.secret_input.hide_secret',
65
+ },
66
+ );
67
+
68
+ $effect(() => {
69
+ if (mask === 'type') {
70
+ inputElement?.setAttribute('type', show ? 'text' : 'password');
71
+ }
72
+ });
73
+ </script>
74
+
75
+ <div
76
+ role="none"
77
+ class="sui {mask === 'type' ? 'password-input' : 'secret-input'} {className}"
78
+ class:flex
79
+ class:disabled
80
+ class:readonly
81
+ class:show={mask === 'css' && show}
82
+ {hidden}
83
+ >
84
+ <!-- With the `css` mask, the field is masked with CSS rather than `type="password"`, so opt out
85
+ of the features that would remember the secret, like autofill history and the keyboard’s learned
86
+ words -->
87
+ <TextInput
88
+ dir="ltr"
89
+ bind:element={inputElement}
90
+ {...mask === 'css' ? { autocomplete: 'off', autocapitalize: 'off', autocorrect: 'off' } : {}}
91
+ {...restProps}
92
+ {id}
93
+ bind:value
94
+ {...mask === 'type' ? { type: 'password' } : {}}
95
+ spellcheck="false"
96
+ {flex}
97
+ {monospace}
98
+ {hidden}
99
+ {disabled}
100
+ {readonly}
101
+ {required}
102
+ {invalid}
103
+ />
104
+ <Button
105
+ iconic
106
+ disabled={disabled || readonly}
107
+ pressed={show}
108
+ aria-label={_(show ? labels.hide : labels.show)}
109
+ aria-controls={id}
110
+ onclick={() => {
111
+ show = !show;
112
+ }}
113
+ >
114
+ {#snippet startIcon()}
115
+ {#if visibilityIcon}
116
+ {@render visibilityIcon()}
117
+ {:else}
118
+ <Icon name={show ? 'visibility_off' : 'visibility'} />
119
+ {/if}
120
+ {/snippet}
121
+ </Button>
122
+ </div>
123
+
124
+ <style>.password-input,
125
+ .secret-input {
126
+ display: inline-flex;
127
+ align-items: center;
128
+ margin: var(--sui-focus-ring-width);
129
+ min-width: var(--sui-textbox-singleline-min-width);
130
+ }
131
+ .password-input.flex:not([hidden]),
132
+ .secret-input.flex:not([hidden]) {
133
+ display: inline-flex;
134
+ width: -moz-available;
135
+ width: -webkit-fill-available;
136
+ width: stretch;
137
+ min-width: 0;
138
+ }
139
+ .password-input :global(.text-input),
140
+ .secret-input :global(.text-input) {
141
+ flex: auto;
142
+ margin: 0 !important;
143
+ width: 0;
144
+ min-width: 0 !important;
145
+ }
146
+ .password-input :global(input),
147
+ .secret-input :global(input) {
148
+ border-start-end-radius: 0;
149
+ border-end-end-radius: 0;
150
+ }
151
+ .password-input :global(button),
152
+ .secret-input :global(button) {
153
+ margin-block: 0;
154
+ margin-inline-end: 0;
155
+ flex: none;
156
+ margin-inline-start: -1px;
157
+ border-width: 1px;
158
+ border-color: var(--sui-textbox-border-color);
159
+ width: var(--sui-textbox-height);
160
+ aspect-ratio: 1/1;
161
+ }
162
+ .password-input :global(button:last-child),
163
+ .secret-input :global(button:last-child) {
164
+ border-start-start-radius: 0;
165
+ border-start-end-radius: 4px;
166
+ border-end-end-radius: 4px;
167
+ border-end-start-radius: 0;
168
+ }
169
+ .password-input :global(button) :global(.icon),
170
+ .secret-input :global(button) :global(.icon) {
171
+ font-size: var(--sui-font-size-xx-large);
172
+ }
173
+
174
+ .secret-input.show :global(input) {
175
+ -webkit-text-security: none;
176
+ }
177
+ .secret-input :global(input) {
178
+ -webkit-text-security: disc;
179
+ }</style>
@@ -0,0 +1,42 @@
1
+ export default MaskedInput;
2
+ type MaskedInput = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<TextInputProps & KeyboardEventHandlers & MouseEventHandlers & PointerEventHandlers & FocusEventHandlers & DragEventHandlers & InputEventHandlers & Props & Record<string, any>>): void;
5
+ };
6
+ /**
7
+ * Internal base of `<PasswordInput>` and `<SecretInput>`: a text field whose value is masked, with a
8
+ * Show/Hide button.
9
+ */
10
+ declare const MaskedInput: import("svelte").Component<TextInputProps & import("../../typedefs.js").KeyboardEventHandlers & import("../../typedefs.js").MouseEventHandlers & import("../../typedefs.js").PointerEventHandlers & import("../../typedefs.js").FocusEventHandlers & import("../../typedefs.js").DragEventHandlers & InputEventHandlers & {
11
+ /**
12
+ * How to mask the value: `type` uses `type="password"`, while
13
+ * `css` uses `-webkit-text-security` so password managers don’t prompt to save the value.
14
+ */
15
+ mask: "type" | "css";
16
+ /**
17
+ * Input value.
18
+ */
19
+ value?: string | undefined;
20
+ /**
21
+ * Visibility icon slot content.
22
+ */
23
+ visibilityIcon?: Snippet<[]> | undefined;
24
+ } & Record<string, any>, {}, "value">;
25
+ type Props = {
26
+ /**
27
+ * How to mask the value: `type` uses `type="password"`, while
28
+ * `css` uses `-webkit-text-security` so password managers don’t prompt to save the value.
29
+ */
30
+ mask: "type" | "css";
31
+ /**
32
+ * Input value.
33
+ */
34
+ value?: string | undefined;
35
+ /**
36
+ * Visibility icon slot content.
37
+ */
38
+ visibilityIcon?: Snippet<[]> | undefined;
39
+ };
40
+ import type { TextInputProps } from '../../typedefs.js';
41
+ import type { InputEventHandlers } from '../../typedefs.js';
42
+ import type { Snippet } from 'svelte';
@@ -9,7 +9,13 @@
9
9
  * @param {number} step Step value.
10
10
  * @returns {number} Number of fraction digits, `0` for an integer step.
11
11
  */
12
- export const getMaximumFractionDigits = (step) => String(step).split('.')[1]?.length || 0;
12
+ export const getMaximumFractionDigits = (step) => {
13
+ // A small step like `0.0000001` is stringified in exponent notation as `1e-7`
14
+ const [mantissa, exponent = '0'] = String(step).toLowerCase().split('e');
15
+ const digits = (mantissa.split('.')[1]?.length ?? 0) - Number(exponent);
16
+
17
+ return Math.max(digits, 0);
18
+ };
13
19
 
14
20
  /**
15
21
  * Parse the text entered in the field.