@sveltia/ui 0.21.0 → 0.22.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 (174) hide show
  1. package/{package → dist}/components/button/button.svelte +1 -1
  2. package/{package → dist}/components/button/select-button-group.svelte +3 -0
  3. package/{package → dist}/components/calendar/calendar.svelte +1 -1
  4. package/{package → dist}/components/checkbox/checkbox.svelte +9 -2
  5. package/{package → dist}/components/grid/grid.svelte +1 -1
  6. package/{package → dist}/components/listbox/listbox.svelte +3 -0
  7. package/{package → dist}/components/menu/menu-button.svelte +1 -1
  8. package/{package → dist}/components/progressbar/progressbar.svelte +4 -1
  9. package/{package → dist}/components/radio/radio-group.svelte +9 -0
  10. package/{package → dist}/components/radio/radio.svelte +3 -3
  11. package/{package → dist}/components/select/combobox.svelte +6 -2
  12. package/{package → dist}/components/select/select-tags.svelte +1 -1
  13. package/{package → dist}/components/slider/slider.svelte +14 -7
  14. package/{package → dist}/components/switch/switch.svelte +4 -1
  15. package/{package → dist}/components/tabs/tab-list.svelte +1 -1
  16. package/{package → dist}/components/text-editor/core.js +79 -5
  17. package/{package → dist}/components/text-editor/index.js +6 -0
  18. package/dist/components/text-editor/lexical-root.svelte +288 -0
  19. package/{package → dist}/components/text-editor/text-editor.svelte +7 -5
  20. package/{package → dist}/components/text-editor/toolbar/toggle-block-menu-item.svelte +7 -0
  21. package/{package → dist}/components/text-field/number-input.svelte +31 -16
  22. package/{package → dist}/components/text-field/number-input.svelte.d.ts +8 -0
  23. package/{package → dist}/components/text-field/password-input.svelte +1 -0
  24. package/{package → dist}/components/text-field/password-input.svelte.d.ts +8 -0
  25. package/{package → dist}/components/text-field/search-bar.svelte +1 -0
  26. package/{package → dist}/components/text-field/search-bar.svelte.d.ts +8 -0
  27. package/{package → dist}/components/text-field/text-area.svelte +4 -4
  28. package/{package → dist}/components/text-field/text-input.svelte +7 -2
  29. package/{package → dist}/components/text-field/text-input.svelte.d.ts +13 -2
  30. package/{package → dist}/components/toast/toast.svelte +1 -1
  31. package/{package → dist}/components/toolbar/toolbar.svelte +2 -2
  32. package/{package → dist}/components/util/app-shell.svelte +6 -6
  33. package/{package → dist}/components/util/app-shell.svelte.d.ts +2 -2
  34. package/{package → dist}/components/util/popup.svelte +2 -2
  35. package/{package → dist}/locales/en.d.ts +1 -0
  36. package/{package → dist}/locales/en.js +1 -0
  37. package/{package → dist}/locales/ja.d.ts +1 -0
  38. package/{package → dist}/locales/ja.js +1 -0
  39. package/{package → dist}/styles/variables.scss +2 -2
  40. package/{package → dist}/typedefs.d.ts +1 -5
  41. package/{package → dist}/typedefs.js +14 -14
  42. package/package.json +29 -28
  43. package/package/components/text-editor/lexical-root.svelte +0 -150
  44. /package/{package → dist}/components/alert/alert.svelte +0 -0
  45. /package/{package → dist}/components/alert/alert.svelte.d.ts +0 -0
  46. /package/{package → dist}/components/button/button-group.svelte +0 -0
  47. /package/{package → dist}/components/button/button-group.svelte.d.ts +0 -0
  48. /package/{package → dist}/components/button/button.svelte.d.ts +0 -0
  49. /package/{package → dist}/components/button/select-button-group.svelte.d.ts +0 -0
  50. /package/{package → dist}/components/button/select-button.svelte +0 -0
  51. /package/{package → dist}/components/button/select-button.svelte.d.ts +0 -0
  52. /package/{package → dist}/components/button/split-button.svelte +0 -0
  53. /package/{package → dist}/components/button/split-button.svelte.d.ts +0 -0
  54. /package/{package → dist}/components/calendar/calendar.svelte.d.ts +0 -0
  55. /package/{package → dist}/components/checkbox/checkbox-group.svelte +0 -0
  56. /package/{package → dist}/components/checkbox/checkbox-group.svelte.d.ts +0 -0
  57. /package/{package → dist}/components/checkbox/checkbox.svelte.d.ts +0 -0
  58. /package/{package → dist}/components/dialog/alert-dialog.svelte +0 -0
  59. /package/{package → dist}/components/dialog/alert-dialog.svelte.d.ts +0 -0
  60. /package/{package → dist}/components/dialog/confirmation-dialog.svelte +0 -0
  61. /package/{package → dist}/components/dialog/confirmation-dialog.svelte.d.ts +0 -0
  62. /package/{package → dist}/components/dialog/dialog.svelte +0 -0
  63. /package/{package → dist}/components/dialog/dialog.svelte.d.ts +0 -0
  64. /package/{package → dist}/components/dialog/prompt-dialog.svelte +0 -0
  65. /package/{package → dist}/components/dialog/prompt-dialog.svelte.d.ts +0 -0
  66. /package/{package → dist}/components/disclosure/disclosure.svelte +0 -0
  67. /package/{package → dist}/components/disclosure/disclosure.svelte.d.ts +0 -0
  68. /package/{package → dist}/components/divider/divider.svelte +0 -0
  69. /package/{package → dist}/components/divider/divider.svelte.d.ts +0 -0
  70. /package/{package → dist}/components/divider/spacer.svelte +0 -0
  71. /package/{package → dist}/components/divider/spacer.svelte.d.ts +0 -0
  72. /package/{package → dist}/components/drawer/drawer.svelte +0 -0
  73. /package/{package → dist}/components/drawer/drawer.svelte.d.ts +0 -0
  74. /package/{package → dist}/components/grid/grid-body.svelte +0 -0
  75. /package/{package → dist}/components/grid/grid-body.svelte.d.ts +0 -0
  76. /package/{package → dist}/components/grid/grid-cell.svelte +0 -0
  77. /package/{package → dist}/components/grid/grid-cell.svelte.d.ts +0 -0
  78. /package/{package → dist}/components/grid/grid-col-header.svelte +0 -0
  79. /package/{package → dist}/components/grid/grid-col-header.svelte.d.ts +0 -0
  80. /package/{package → dist}/components/grid/grid-foot.svelte +0 -0
  81. /package/{package → dist}/components/grid/grid-foot.svelte.d.ts +0 -0
  82. /package/{package → dist}/components/grid/grid-head.svelte +0 -0
  83. /package/{package → dist}/components/grid/grid-head.svelte.d.ts +0 -0
  84. /package/{package → dist}/components/grid/grid-row-header.svelte +0 -0
  85. /package/{package → dist}/components/grid/grid-row-header.svelte.d.ts +0 -0
  86. /package/{package → dist}/components/grid/grid-row.svelte +0 -0
  87. /package/{package → dist}/components/grid/grid-row.svelte.d.ts +0 -0
  88. /package/{package → dist}/components/grid/grid.svelte.d.ts +0 -0
  89. /package/{package → dist}/components/icon/icon.svelte +0 -0
  90. /package/{package → dist}/components/icon/icon.svelte.d.ts +0 -0
  91. /package/{package → dist}/components/listbox/listbox.svelte.d.ts +0 -0
  92. /package/{package → dist}/components/listbox/option-group.svelte +0 -0
  93. /package/{package → dist}/components/listbox/option-group.svelte.d.ts +0 -0
  94. /package/{package → dist}/components/listbox/option.svelte +0 -0
  95. /package/{package → dist}/components/listbox/option.svelte.d.ts +0 -0
  96. /package/{package → dist}/components/menu/menu-button.svelte.d.ts +0 -0
  97. /package/{package → dist}/components/menu/menu-item-checkbox.svelte +0 -0
  98. /package/{package → dist}/components/menu/menu-item-checkbox.svelte.d.ts +0 -0
  99. /package/{package → dist}/components/menu/menu-item-group.svelte +0 -0
  100. /package/{package → dist}/components/menu/menu-item-group.svelte.d.ts +0 -0
  101. /package/{package → dist}/components/menu/menu-item-radio.svelte +0 -0
  102. /package/{package → dist}/components/menu/menu-item-radio.svelte.d.ts +0 -0
  103. /package/{package → dist}/components/menu/menu-item.svelte +0 -0
  104. /package/{package → dist}/components/menu/menu-item.svelte.d.ts +0 -0
  105. /package/{package → dist}/components/menu/menu.svelte +0 -0
  106. /package/{package → dist}/components/menu/menu.svelte.d.ts +0 -0
  107. /package/{package → dist}/components/progressbar/progressbar.svelte.d.ts +0 -0
  108. /package/{package → dist}/components/radio/radio-group.svelte.d.ts +0 -0
  109. /package/{package → dist}/components/radio/radio.svelte.d.ts +0 -0
  110. /package/{package → dist}/components/select/combobox.svelte.d.ts +0 -0
  111. /package/{package → dist}/components/select/select-tags.svelte.d.ts +0 -0
  112. /package/{package → dist}/components/select/select.svelte +0 -0
  113. /package/{package → dist}/components/select/select.svelte.d.ts +0 -0
  114. /package/{package → dist}/components/slider/slider.svelte.d.ts +0 -0
  115. /package/{package → dist}/components/switch/switch.svelte.d.ts +0 -0
  116. /package/{package → dist}/components/table/table-body.svelte +0 -0
  117. /package/{package → dist}/components/table/table-body.svelte.d.ts +0 -0
  118. /package/{package → dist}/components/table/table-cell.svelte +0 -0
  119. /package/{package → dist}/components/table/table-cell.svelte.d.ts +0 -0
  120. /package/{package → dist}/components/table/table-col-header.svelte +0 -0
  121. /package/{package → dist}/components/table/table-col-header.svelte.d.ts +0 -0
  122. /package/{package → dist}/components/table/table-foot.svelte +0 -0
  123. /package/{package → dist}/components/table/table-foot.svelte.d.ts +0 -0
  124. /package/{package → dist}/components/table/table-head.svelte +0 -0
  125. /package/{package → dist}/components/table/table-head.svelte.d.ts +0 -0
  126. /package/{package → dist}/components/table/table-row-header.svelte +0 -0
  127. /package/{package → dist}/components/table/table-row-header.svelte.d.ts +0 -0
  128. /package/{package → dist}/components/table/table-row.svelte +0 -0
  129. /package/{package → dist}/components/table/table-row.svelte.d.ts +0 -0
  130. /package/{package → dist}/components/table/table.svelte +0 -0
  131. /package/{package → dist}/components/table/table.svelte.d.ts +0 -0
  132. /package/{package → dist}/components/tabs/tab-box.svelte +0 -0
  133. /package/{package → dist}/components/tabs/tab-box.svelte.d.ts +0 -0
  134. /package/{package → dist}/components/tabs/tab-list.svelte.d.ts +0 -0
  135. /package/{package → dist}/components/tabs/tab-panel.svelte +0 -0
  136. /package/{package → dist}/components/tabs/tab-panel.svelte.d.ts +0 -0
  137. /package/{package → dist}/components/tabs/tab-panels.svelte +0 -0
  138. /package/{package → dist}/components/tabs/tab-panels.svelte.d.ts +0 -0
  139. /package/{package → dist}/components/tabs/tab.svelte +0 -0
  140. /package/{package → dist}/components/tabs/tab.svelte.d.ts +0 -0
  141. /package/{package → dist}/components/text-editor/core.d.ts +0 -0
  142. /package/{package → dist}/components/text-editor/index.d.ts +0 -0
  143. /package/{package → dist}/components/text-editor/lexical-root.svelte.d.ts +0 -0
  144. /package/{package → dist}/components/text-editor/text-editor.svelte.d.ts +0 -0
  145. /package/{package → dist}/components/text-editor/toolbar/editor-toolbar.svelte +0 -0
  146. /package/{package → dist}/components/text-editor/toolbar/editor-toolbar.svelte.d.ts +0 -0
  147. /package/{package → dist}/components/text-editor/toolbar/format-text-button.svelte +0 -0
  148. /package/{package → dist}/components/text-editor/toolbar/format-text-button.svelte.d.ts +0 -0
  149. /package/{package → dist}/components/text-editor/toolbar/insert-image-button.svelte +0 -0
  150. /package/{package → dist}/components/text-editor/toolbar/insert-image-button.svelte.d.ts +0 -0
  151. /package/{package → dist}/components/text-editor/toolbar/insert-link-button.svelte +0 -0
  152. /package/{package → dist}/components/text-editor/toolbar/insert-link-button.svelte.d.ts +0 -0
  153. /package/{package → dist}/components/text-editor/toolbar/insert-menu-button.svelte +0 -0
  154. /package/{package → dist}/components/text-editor/toolbar/insert-menu-button.svelte.d.ts +0 -0
  155. /package/{package → dist}/components/text-editor/toolbar/toggle-block-menu-item.svelte.d.ts +0 -0
  156. /package/{package → dist}/components/text-field/text-area.svelte.d.ts +0 -0
  157. /package/{package → dist}/components/toast/toast.svelte.d.ts +0 -0
  158. /package/{package → dist}/components/toolbar/toolbar.svelte.d.ts +0 -0
  159. /package/{package → dist}/components/util/group.svelte +0 -0
  160. /package/{package → dist}/components/util/group.svelte.d.ts +0 -0
  161. /package/{package → dist}/components/util/modal.svelte +0 -0
  162. /package/{package → dist}/components/util/modal.svelte.d.ts +0 -0
  163. /package/{package → dist}/components/util/placeholder.svelte +0 -0
  164. /package/{package → dist}/components/util/placeholder.svelte.d.ts +0 -0
  165. /package/{package → dist}/components/util/popup.svelte.d.ts +0 -0
  166. /package/{package → dist}/index.d.ts +0 -0
  167. /package/{package → dist}/index.js +0 -0
  168. /package/{package → dist}/services/events.svelte.d.ts +0 -0
  169. /package/{package → dist}/services/events.svelte.js +0 -0
  170. /package/{package → dist}/services/group.svelte.d.ts +0 -0
  171. /package/{package → dist}/services/group.svelte.js +0 -0
  172. /package/{package → dist}/services/popup.svelte.d.ts +0 -0
  173. /package/{package → dist}/services/popup.svelte.js +0 -0
  174. /package/{package → dist}/styles/core.scss +0 -0
@@ -45,7 +45,7 @@
45
45
  <button
46
46
  bind:this={element}
47
47
  {...restProps}
48
- class="sui button {variant ?? ''} {size} {className}"
48
+ class="sui button {variant} {size} {className}"
49
49
  class:iconic
50
50
  class:pill
51
51
  class:flex
@@ -82,6 +82,9 @@
82
82
  border-top-right-radius: 4px !important;
83
83
  border-bottom-right-radius: 4px !important;
84
84
  }
85
+ .select-button-group[aria-invalid=true] :global(button) {
86
+ border-color: var(--sui-error-border-color);
87
+ }
85
88
  .select-button-group :global(button[aria-checked="true"]) {
86
89
  color: var(--sui-highlight-foreground-color);
87
90
  background-color: var(--sui-selected-background-color);
@@ -11,7 +11,7 @@
11
11
 
12
12
  /**
13
13
  * @typedef {object} Props
14
- * @property {string | undefined} [value] - Date.
14
+ * @property {string} [value] - Date.
15
15
  */
16
16
 
17
17
  /**
@@ -19,7 +19,7 @@
19
19
  * `aria-invalid` attribute.
20
20
  * @property {boolean | 'mixed'} [checked] - Whether to check the widget. An alias of the
21
21
  * `aria-checked` attribute.
22
- * @property {string | undefined} [label] - Text label displayed next to the checkbox.
22
+ * @property {string} [label] - Text label displayed next to the checkbox.
23
23
  * @property {string} [aria-label] - `aria-label` attribute.
24
24
  * @property {import('svelte').Snippet} [checkIcon] - Check icon slot content.
25
25
  */
@@ -88,7 +88,7 @@
88
88
  {disabled}
89
89
  {readonly}
90
90
  {required}
91
- {invalid}
91
+ aria-invalid={invalid}
92
92
  aria-checked={checked}
93
93
  aria-label={ariaLabel || undefined}
94
94
  aria-labelledby={ariaLabel ? undefined : `${id}-label`}
@@ -174,6 +174,13 @@
174
174
  .checkbox :global(button[aria-checked="false"]) {
175
175
  color: transparent;
176
176
  }
177
+ .checkbox :global(button[aria-invalid="true"]) {
178
+ border-color: var(--sui-error-border-color);
179
+ color: var(--sui-error-foreground-color);
180
+ }
181
+ .checkbox :global(button[aria-checked="true"][aria-invalid="true"]) {
182
+ background-color: var(--sui-error-background-color);
183
+ }
177
184
  .checkbox label {
178
185
  cursor: inherit;
179
186
  }
@@ -13,7 +13,7 @@
13
13
  * @property {boolean} [selected] - Whether to allow selecting more than one `<GridRow>` and/or
14
14
  * `<GridCell>`. An alias of the `aria-multiselectable` attribute.
15
15
  * @property {boolean} [clickToSelect] - Whether to select a row by clicking on it.
16
- * @property {HTMLElement | undefined} [element] - A reference to the wrapper element.
16
+ * @property {HTMLElement} [element] - A reference to the wrapper element.
17
17
  * @property {import('svelte').Snippet} [children] - Primary slot content.
18
18
  * @property {(event: CustomEvent) => void} [onChange] - Custom `Change` event handler.
19
19
  */
@@ -102,6 +102,9 @@
102
102
  margin: 4px;
103
103
  background-color: var(--sui-control-border-color);
104
104
  }
105
+ [role=listbox][aria-invalid=true] {
106
+ border-color: var(--sui-error-border-color);
107
+ }
105
108
  [role=listbox]:global(.tabs) {
106
109
  padding: 0;
107
110
  border-width: 0 1px 0 0;
@@ -10,7 +10,7 @@
10
10
 
11
11
  /**
12
12
  * @typedef {object} Props
13
- * @property {HTMLElement | undefined} [popupPositionBaseElement] - The base element of
13
+ * @property {HTMLElement} [popupPositionBaseElement] - The base element of
14
14
  * {@link popupPosition}. If omitted, this will be {@link buttonComponent}.
15
15
  */
16
16
 
@@ -42,9 +42,12 @@
42
42
 
43
43
  <style>.progressbar {
44
44
  overflow: hidden;
45
+ border-width: var(--sui-progressbar-border-width, 1px);
46
+ border-style: var(--sui-progressbar-border-style, solid);
47
+ border-color: var(--sui-progressbar-border-color, var(--sui-control-border-color));
45
48
  border-radius: var(--sui-progressbar-border-radius, 16px);
46
49
  width: var(--sui-progressbar-width, 240px);
47
- height: var(--sui-progressbar-height, 8px);
50
+ height: var(--sui-progressbar-height, 10px);
48
51
  background-color: var(--sui-progressbar-background-color, var(--sui-secondary-background-color));
49
52
  }
50
53
  .progressbar div {
@@ -86,6 +86,15 @@
86
86
  gap: 8px;
87
87
  }
88
88
  }
89
+ .radio-group[aria-invalid=true] :global(button) {
90
+ border-color: var(--sui-error-border-color);
91
+ }
92
+ .radio-group[aria-invalid=true] :global(button[aria-checked="true"]) {
93
+ border-color: var(--sui-error-border-color);
94
+ }
95
+ .radio-group[aria-invalid=true] :global(button[aria-checked="true"]::before) {
96
+ background-color: var(--sui-error-border-color);
97
+ }
89
98
 
90
99
  .inner {
91
100
  display: contents;
@@ -17,9 +17,9 @@
17
17
  * attribute.
18
18
  * @property {boolean} [checked] - Whether to check the widget. An alias of the `aria-checked`
19
19
  * attribute.
20
- * @property {string | undefined} [name] - The `name` attribute on the `<button>` element.
21
- * @property {string | undefined} [value] - The `value` attribute on the `<button>` element.
22
- * @property {string | undefined} [label] - Text label displayed next to the checkbox.
20
+ * @property {string} [name] - The `name` attribute on the `<button>` element.
21
+ * @property {string} [value] - The `value` attribute on the `<button>` element.
22
+ * @property {string} [label] - Text label displayed next to the checkbox.
23
23
  * @property {import('svelte').Snippet} [children] - Primary slot content.
24
24
  * @property {import('svelte').Snippet} [default] - Default slot content.
25
25
  * @property {(event: CustomEvent) => void} [onChange] - Custom `Change` event handler.
@@ -122,8 +122,9 @@
122
122
  aria-hidden={hidden}
123
123
  aria-disabled={disabled}
124
124
  aria-readonly={readonly}
125
+ aria-required={required}
126
+ aria-invalid={invalid}
125
127
  aria-haspopup="listbox"
126
- aria-activedescendant="selected-option"
127
128
  >
128
129
  <div role="none" class="label">
129
130
  {value !== undefined ? label : $_('_sui.combobox.select_an_option')}
@@ -144,7 +145,6 @@
144
145
  aria-controls="{id}-popup"
145
146
  aria-expanded={isPopupOpen}
146
147
  aria-haspopup="listbox"
147
- aria-activedescendant="selected-option"
148
148
  />
149
149
  {/if}
150
150
  <Button
@@ -282,6 +282,10 @@
282
282
  .combobox div[role=combobox]:hover, .combobox div[role=combobox]:focus {
283
283
  background-color: var(--sui-hover-background-color);
284
284
  }
285
+ .combobox div[role=combobox][aria-invalid=true] {
286
+ border-color: var(--sui-error-border-color);
287
+ background-color: var(--sui-error-background-color);
288
+ }
285
289
  .combobox div[role=combobox] .label {
286
290
  display: block;
287
291
  overflow: hidden;
@@ -10,7 +10,7 @@
10
10
  * @property {{ label: string, value: string, searchValue?: string }[]} options - Available
11
11
  * options.
12
12
  * @property {string[]} [values] - Selected option values.
13
- * @property {number | undefined} [max] - Maximum number of selectable options.
13
+ * @property {number} [max] - Maximum number of selectable options.
14
14
  * @property {string} [class] - The `class` attribute on the wrapper element.
15
15
  * @property {boolean} [hidden] - Whether to hide the widget.
16
16
  * @property {boolean} [disabled] - Whether to disable the widget. An alias of the `aria-disabled`
@@ -16,8 +16,8 @@
16
16
  * @property {number} [min] - Minimum allowed value. An alias of the `aria-valuemin` attribute.
17
17
  * @property {number} [max] - Maximum allowed value. An alias of the `aria-valuemax` attribute.
18
18
  * @property {string} [sliderLabel] - `aria-label` on the slider.
19
- * @property {[number, number] | undefined} [values] - Value list for a multi-thumb slider.
20
- * @property {[string, string] | undefined} [sliderLabels] - `aria-label` on a multi-thumb slider.
19
+ * @property {[number, number]} [values] - Value list for a multi-thumb slider.
20
+ * @property {[string, string]} [sliderLabels] - `aria-label` on a multi-thumb slider.
21
21
  * @property {number} [step] - Step option like `<input type="range">`.
22
22
  * @property {(string[] | number[])} [optionLabels] - Visible labels on the slider.
23
23
  * @property {boolean} [flex] - Make the text input container flexible.
@@ -304,6 +304,7 @@
304
304
  class="sui slider {className}"
305
305
  class:disabled
306
306
  class:readonly
307
+ class:invalid
307
308
  {hidden}
308
309
  >
309
310
  <div bind:this={base} role="none" class="base" onpointerdown={(event) => onPointerDown(event)}>
@@ -316,7 +317,7 @@
316
317
  <div
317
318
  role="slider"
318
319
  tabindex={disabled ? -1 : 0}
319
- aria-label={multiThumb ? sliderLabels?.[0] || '' : sliderLabel}
320
+ aria-label={multiThumb ? sliderLabels?.[0] : sliderLabel}
320
321
  aria-hidden={hidden}
321
322
  aria-disabled={disabled}
322
323
  aria-readonly={readonly}
@@ -332,7 +333,7 @@
332
333
  <div
333
334
  role="slider"
334
335
  tabindex={disabled ? -1 : 0}
335
- aria-label={sliderLabels?.[1] || ''}
336
+ aria-label={sliderLabels?.[1]}
336
337
  aria-hidden={hidden}
337
338
  aria-disabled={disabled}
338
339
  aria-readonly={readonly}
@@ -363,7 +364,7 @@
363
364
  position: relative;
364
365
  display: inline-block;
365
366
  margin: var(--sui-focus-ring-width);
366
- padding: var(--sui-checkbox-height) calc(var(--sui-checkbox-height) / 2);
367
+ padding: 4px 6px;
367
368
  touch-action: none;
368
369
  }
369
370
  .slider:hover .base-bar {
@@ -375,7 +376,7 @@
375
376
 
376
377
  .base {
377
378
  position: relative;
378
- width: var(--sui-slider-base-width, calc(var(--sui-checkbox-height) * 10));
379
+ width: var(--sui-slider-base-width, 240px);
379
380
  height: calc(var(--sui-checkbox-height) / 2);
380
381
  cursor: pointer;
381
382
  }
@@ -385,7 +386,7 @@
385
386
  border-style: solid;
386
387
  border-color: var(--sui-control-border-color);
387
388
  border-radius: var(--sui-checkbox-height);
388
- background-color: var(--sui-button-background-color);
389
+ background-color: var(--sui-slider-background-color, var(--sui-secondary-background-color));
389
390
  transition: all 200ms;
390
391
  width: 100%;
391
392
  height: 100%;
@@ -398,6 +399,9 @@
398
399
  border-radius: var(--sui-checkbox-height);
399
400
  background-color: var(--sui-primary-accent-color-light);
400
401
  }
402
+ .invalid .slider-bar {
403
+ background-color: var(--sui-error-border-color);
404
+ }
401
405
 
402
406
  [role=slider] {
403
407
  position: absolute;
@@ -410,6 +414,9 @@
410
414
  cursor: pointer;
411
415
  transform: translate(calc((var(--sui-checkbox-height) / 2 - 1px) * -1), calc((var(--sui-checkbox-height) / 4 - 1px) * -1));
412
416
  }
417
+ .invalid [role=slider] {
418
+ border-color: var(--sui-error-border-color);
419
+ }
413
420
 
414
421
  .label {
415
422
  position: absolute;
@@ -7,7 +7,7 @@
7
7
  <script>
8
8
  /**
9
9
  * @typedef {object} Props
10
- * @property {string | undefined} [label] - Text label displayed next to the switch.
10
+ * @property {string} [label] - Text label displayed next to the switch.
11
11
  * @property {string} [class] - The `class` attribute on the wrapper element.
12
12
  * @property {boolean} [hidden] - Whether to hide the widget.
13
13
  * @property {boolean} [disabled] - Whether to disable the widget. An alias of the `aria-disabled`
@@ -90,6 +90,9 @@
90
90
  -webkit-user-select: none;
91
91
  user-select: none;
92
92
  }
93
+ button[aria-invalid=true] span {
94
+ background-color: var(--sui-error-border-color) !important;
95
+ }
93
96
  button:hover[aria-checked=false] span {
94
97
  background-color: var(--sui-hover-background-color);
95
98
  }
@@ -16,7 +16,7 @@
16
16
  * attribute.
17
17
  * @property {'horizontal' | 'vertical'} [orientation] - Orientation of the widget. An alias of
18
18
  * the `aria-orientation` attribute.
19
- * @property {string | undefined} [name] - The `data-name` attribute on the wrapper element.
19
+ * @property {string} [name] - The `data-name` attribute on the wrapper element.
20
20
  * @property {import('svelte').Snippet} [children] - Primary slot content.
21
21
  * @property {(event: CustomEvent) => void} [onChange] - Custom `Change` event handler.
22
22
  */
@@ -1,4 +1,10 @@
1
- import { CodeHighlightNode, CodeNode } from '@lexical/code';
1
+ import {
2
+ CodeHighlightNode,
3
+ CodeNode,
4
+ $isCodeHighlightNode as isCodeHighlightNode,
5
+ $isCodeNode as isCodeNode,
6
+ registerCodeHighlighting,
7
+ } from '@lexical/code';
2
8
  import { registerDragonSupport } from '@lexical/dragon';
3
9
  import { createEmptyHistoryState, registerHistory } from '@lexical/history';
4
10
  import {
@@ -31,6 +37,7 @@ import {
31
37
  } from '@lexical/rich-text';
32
38
  import { TableCellNode, TableNode, TableRowNode } from '@lexical/table';
33
39
  import { $getNearestNodeOfType as getNearestNodeOfType } from '@lexical/utils';
40
+ import { sleep } from '@sveltia/utils/misc';
34
41
  import {
35
42
  COMMAND_PRIORITY_NORMAL,
36
43
  ElementNode,
@@ -41,6 +48,7 @@ import {
41
48
  $getSelection as getSelection,
42
49
  $isRangeSelection as isRangeSelection,
43
50
  } from 'lexical';
51
+ import prismComponents from 'prismjs/components';
44
52
  import { blockButtonTypes, textFormatButtonTypes } from '.';
45
53
 
46
54
  const allTransformers = [...TRANSFORMERS];
@@ -76,6 +84,40 @@ const editorConfig = {
76
84
  listitem: 'nested',
77
85
  },
78
86
  },
87
+ code: 'code-block',
88
+ // https://github.com/facebook/lexical/blob/main/packages/lexical-website/docs/getting-started/theming.md
89
+ codeHighlight: {
90
+ atrule: 'token atrule',
91
+ attr: 'token attr',
92
+ boolean: 'token boolean',
93
+ builtin: 'token builtin',
94
+ cdata: 'token cdata',
95
+ char: 'token char',
96
+ class: 'token class',
97
+ 'class-name': 'token class-name',
98
+ comment: 'token comment',
99
+ constant: 'token constant',
100
+ deleted: 'token deleted',
101
+ doctype: 'token doctype',
102
+ entity: 'token entity',
103
+ function: 'token function',
104
+ important: 'token important',
105
+ inserted: 'token inserted',
106
+ keyword: 'token keyword',
107
+ namespace: 'token namespace',
108
+ number: 'token number',
109
+ operator: 'token operator',
110
+ prolog: 'token prolog',
111
+ property: 'token property',
112
+ punctuation: 'token punctuation',
113
+ regex: 'token regex',
114
+ selector: 'token selector',
115
+ string: 'token string',
116
+ symbol: 'token symbol',
117
+ tag: 'token tag',
118
+ url: 'token url',
119
+ variable: 'token variable',
120
+ },
79
121
  },
80
122
  };
81
123
 
@@ -128,6 +170,10 @@ const getSelectionTypes = () => {
128
170
  return 'blockquote';
129
171
  }
130
172
 
173
+ if (isCodeNode(parent) || isCodeHighlightNode(parent)) {
174
+ return 'code-block';
175
+ }
176
+
131
177
  const type = parent.getType();
132
178
 
133
179
  if (blockButtonTypes.includes(/** @type {any} */ (type))) {
@@ -180,6 +226,13 @@ export const initEditor = ({ components } = {}) => {
180
226
  registerDragonSupport(editor);
181
227
  registerHistory(editor, createEmptyHistoryState(), 1000);
182
228
 
229
+ registerCodeHighlighting(editor, {
230
+ defaultLanguage: 'plain',
231
+ // eslint-disable-next-line jsdoc/require-jsdoc
232
+ tokenize: (code, language = 'plain') =>
233
+ window.Prism.tokenize(code, window.Prism.languages[language] ?? window.Prism.languages.plain),
234
+ });
235
+
183
236
  editor.registerCommand(
184
237
  TOGGLE_LINK_COMMAND,
185
238
  (payload) => {
@@ -270,8 +323,24 @@ export const initEditor = ({ components } = {}) => {
270
323
  * @returns {Promise<void>} Nothing.
271
324
  * @throws {Error} Failed to convert the value to Lexical nodes.
272
325
  */
273
- export const convertMarkdown = async (editor, value) =>
274
- new Promise((resolve, reject) => {
326
+ export const convertMarkdown = async (editor, value) => {
327
+ // Load Prism language support on demand; the `loadLanguages` Prism utility method cannot be used
328
+ await Promise.all(
329
+ [...value.matchAll(/^```(?<lang>.+?)\n/gm)].map(async ({ groups: { lang } = {} }) => {
330
+ if (!(lang in window.Prism.languages) && lang in prismComponents.languages) {
331
+ try {
332
+ await import(
333
+ // eslint-disable-next-line jsdoc/no-bad-blocks
334
+ /* @vite-ignore */ `https://unpkg.com/prismjs@1.29.0/components/prism-${lang}.min.js`
335
+ );
336
+ } catch {
337
+ //
338
+ }
339
+ }
340
+ }),
341
+ );
342
+
343
+ return new Promise((resolve, reject) => {
275
344
  editor.update(() => {
276
345
  try {
277
346
  convertFromMarkdownString(value, allTransformers);
@@ -281,15 +350,20 @@ export const convertMarkdown = async (editor, value) =>
281
350
  }
282
351
  });
283
352
  });
353
+ };
284
354
 
285
355
  /**
286
356
  * Move focus to the editor so the user can start editing immediately.
287
357
  * @param {import('lexical').LexicalEditor} editor - Editor instance.
288
358
  * @returns {Promise<void>} Nothing.
289
359
  */
290
- export const focusEditor = async (editor) =>
291
- new Promise((resolve) => {
360
+ export const focusEditor = async (editor) => {
361
+ await sleep(100);
362
+ editor.getRootElement()?.focus();
363
+
364
+ return new Promise((resolve) => {
292
365
  editor.focus(() => {
293
366
  resolve(undefined);
294
367
  });
295
368
  });
369
+ };
@@ -73,6 +73,11 @@ export const availableButtons = {
73
73
  icon: 'format_quote',
74
74
  inline: false,
75
75
  },
76
+ 'code-block': {
77
+ labelKey: 'code_block',
78
+ icon: 'code_blocks',
79
+ inline: false,
80
+ },
76
81
  };
77
82
  /**
78
83
  * @type {import('../../typedefs').TextEditorFormatType[]}
@@ -96,4 +101,5 @@ export const blockButtonTypes = [
96
101
  'bulleted-list',
97
102
  'numbered-list',
98
103
  'blockquote',
104
+ 'code-block',
99
105
  ];