@streamscloud/kit 0.2.1 → 0.2.2

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 (104) hide show
  1. package/dist/styles/_input.scss +98 -0
  2. package/dist/styles/_mixins.scss +2 -2
  3. package/dist/styles/reset.css +1 -1
  4. package/dist/ui/color-picker/cmp.color-picker.svelte +3 -12
  5. package/dist/ui/color-picker/cmp.color-picker.svelte.d.ts +3 -9
  6. package/dist/ui/dialog/cmp.dialog.svelte +1 -1
  7. package/dist/ui/dropdown/cmp.dropdown-item.svelte +93 -0
  8. package/dist/ui/dropdown/cmp.dropdown-item.svelte.d.ts +32 -0
  9. package/dist/ui/dropdown/cmp.dropdown-panel.svelte +29 -0
  10. package/dist/ui/dropdown/cmp.dropdown-panel.svelte.d.ts +18 -0
  11. package/dist/ui/dropdown/cmp.dropdown.svelte +72 -7
  12. package/dist/ui/dropdown/cmp.dropdown.svelte.d.ts +3 -1
  13. package/dist/ui/dropdown/index.d.ts +2 -0
  14. package/dist/ui/dropdown/index.js +2 -0
  15. package/dist/ui/dynamic-component/cmp.dynamic-component.svelte +0 -5
  16. package/dist/ui/dynamic-component/cmp.dynamic-component.svelte.d.ts +2 -8
  17. package/dist/ui/emoji-picker/cmp.emoji-panel.svelte +186 -0
  18. package/dist/ui/emoji-picker/cmp.emoji-panel.svelte.d.ts +21 -0
  19. package/dist/ui/emoji-picker/cmp.emoji-picker.svelte +35 -0
  20. package/dist/ui/emoji-picker/cmp.emoji-picker.svelte.d.ts +15 -0
  21. package/dist/ui/emoji-picker/emoji-list.d.ts +2 -0
  22. package/dist/ui/emoji-picker/emoji-list.js +1754 -0
  23. package/dist/ui/emoji-picker/emoji-picker-localization.d.ts +5 -0
  24. package/dist/ui/emoji-picker/emoji-picker-localization.js +40 -0
  25. package/dist/ui/emoji-picker/index.d.ts +2 -0
  26. package/dist/ui/emoji-picker/index.js +2 -0
  27. package/dist/ui/emoji-picker/types.d.ts +8 -0
  28. package/dist/ui/emoji-picker/types.js +1 -0
  29. package/dist/ui/form-group/cmp.form-group-label.svelte.d.ts +1 -0
  30. package/dist/ui/form-group/cmp.form-group.svelte.d.ts +1 -0
  31. package/dist/ui/icon-text/cmp.icon-text.svelte +0 -9
  32. package/dist/ui/icon-text/cmp.icon-text.svelte.d.ts +4 -9
  33. package/dist/ui/inputs/index.d.ts +6 -0
  34. package/dist/ui/inputs/index.js +5 -0
  35. package/dist/ui/inputs/input/cmp.input-validatable.svelte +57 -0
  36. package/dist/ui/inputs/input/cmp.input-validatable.svelte.d.ts +56 -0
  37. package/dist/ui/inputs/input/cmp.input.svelte +235 -0
  38. package/dist/ui/inputs/input/cmp.input.svelte.d.ts +60 -0
  39. package/dist/ui/inputs/input/index.d.ts +2 -0
  40. package/dist/ui/inputs/input/index.js +2 -0
  41. package/dist/ui/inputs/input-emoji-picker/cmp.input-emoji-picker.svelte +44 -0
  42. package/dist/ui/inputs/input-emoji-picker/cmp.input-emoji-picker.svelte.d.ts +9 -0
  43. package/dist/ui/inputs/input-emoji-picker/index.d.ts +2 -0
  44. package/dist/ui/inputs/input-emoji-picker/index.js +2 -0
  45. package/dist/ui/inputs/input-emoji-picker/input-emoji-picker-container.d.ts +2 -0
  46. package/dist/ui/inputs/input-emoji-picker/input-emoji-picker-container.js +16 -0
  47. package/dist/ui/inputs/numeral-input/cmp.numeral-input-validatable.svelte +55 -0
  48. package/dist/ui/inputs/numeral-input/cmp.numeral-input-validatable.svelte.d.ts +62 -0
  49. package/dist/ui/inputs/numeral-input/cmp.numeral-input.svelte +248 -0
  50. package/dist/ui/inputs/numeral-input/cmp.numeral-input.svelte.d.ts +66 -0
  51. package/dist/ui/inputs/numeral-input/index.d.ts +2 -0
  52. package/dist/ui/inputs/numeral-input/index.js +2 -0
  53. package/dist/ui/inputs/pin-input/cmp.pin-input.svelte +58 -0
  54. package/dist/ui/inputs/pin-input/cmp.pin-input.svelte.d.ts +23 -0
  55. package/dist/ui/inputs/pin-input/index.d.ts +1 -0
  56. package/dist/ui/inputs/pin-input/index.js +1 -0
  57. package/dist/ui/inputs/pin-input/pin-input-generator.d.ts +27 -0
  58. package/dist/ui/inputs/pin-input/pin-input-generator.js +114 -0
  59. package/dist/ui/inputs/rich-text-input/cmp.rich-text-input.svelte +55 -0
  60. package/dist/ui/inputs/rich-text-input/cmp.rich-text-input.svelte.d.ts +43 -0
  61. package/dist/ui/inputs/rich-text-input/index.d.ts +2 -0
  62. package/dist/ui/inputs/rich-text-input/index.js +1 -0
  63. package/dist/ui/inputs/rich-text-input/rich-text-input-localization.d.ts +12 -0
  64. package/dist/ui/inputs/rich-text-input/rich-text-input-localization.js +48 -0
  65. package/dist/ui/inputs/rich-text-input/tinymce-input.svelte +250 -0
  66. package/dist/ui/inputs/rich-text-input/tinymce-input.svelte.d.ts +25 -0
  67. package/dist/ui/inputs/rich-text-input/tinymce.declarations.d.ts +7 -0
  68. package/dist/ui/inputs/rich-text-input/types.d.ts +4 -0
  69. package/dist/ui/inputs/rich-text-input/types.js +1 -0
  70. package/dist/ui/inputs/rich-text-input/validated-link-button.d.ts +3 -0
  71. package/dist/ui/inputs/rich-text-input/validated-link-button.js +78 -0
  72. package/dist/ui/inputs/textarea/cmp.textarea-validatable.svelte +35 -0
  73. package/dist/ui/inputs/textarea/cmp.textarea-validatable.svelte.d.ts +53 -0
  74. package/dist/ui/inputs/textarea/cmp.textarea.svelte +247 -0
  75. package/dist/ui/inputs/textarea/cmp.textarea.svelte.d.ts +57 -0
  76. package/dist/ui/inputs/textarea/index.d.ts +2 -0
  77. package/dist/ui/inputs/textarea/index.js +2 -0
  78. package/dist/ui/media-viewer-dialog/cmp.media-viewer-dialog.svelte.d.ts +2 -0
  79. package/dist/ui/selects/_multiselect.scss +282 -0
  80. package/dist/ui/selects/_singleselect.scss +175 -0
  81. package/dist/ui/selects/cmp.multiselect.svelte +530 -0
  82. package/dist/ui/selects/cmp.multiselect.svelte.d.ts +85 -0
  83. package/dist/ui/selects/cmp.search-multiselect.svelte +532 -0
  84. package/dist/ui/selects/cmp.search-multiselect.svelte.d.ts +67 -0
  85. package/dist/ui/selects/cmp.singleselect.svelte +381 -0
  86. package/dist/ui/selects/cmp.singleselect.svelte.d.ts +78 -0
  87. package/dist/ui/selects/index.d.ts +5 -0
  88. package/dist/ui/selects/index.js +4 -0
  89. package/dist/ui/selects/select-localization.d.ts +6 -0
  90. package/dist/ui/selects/select-localization.js +27 -0
  91. package/dist/ui/selects/types.d.ts +29 -0
  92. package/dist/ui/selects/types.js +1 -0
  93. package/dist/ui/time-ago/cmp.time-ago.svelte +0 -6
  94. package/dist/ui/time-ago/cmp.time-ago.svelte.d.ts +2 -6
  95. package/dist/ui/validatable/_validatable.scss +34 -0
  96. package/dist/ui/validatable/cmp.validatable.svelte +57 -0
  97. package/dist/ui/validatable/cmp.validatable.svelte.d.ts +49 -0
  98. package/dist/ui/validatable/cmp.validation-error.svelte +52 -0
  99. package/dist/ui/validatable/cmp.validation-error.svelte.d.ts +42 -0
  100. package/dist/ui/validatable/index.d.ts +2 -0
  101. package/dist/ui/validatable/index.js +2 -0
  102. package/package.json +31 -5
  103. package/dist/ui/color-picker/cmp.input-stub.svelte +0 -98
  104. package/dist/ui/color-picker/cmp.input-stub.svelte.d.ts +0 -40
@@ -0,0 +1,381 @@
1
+ <script lang="ts" generics="T">import { Icon } from '../icon';
2
+ import { SelectLocalization } from './select-localization';
3
+ import IconAdd from '@fluentui/svg-icons/icons/add_16_filled.svg?raw';
4
+ import IconChevronDown from '@fluentui/svg-icons/icons/chevron_down_20_regular.svg?raw';
5
+ import Fuse from 'fuse.js';
6
+ import Select from 'svelte-select';
7
+ let { value = null, options = [], placeholder = '', disabled = false, loading = false, creatable = null, allowReset = false, groupHeaderSelectable = false, on, icon, optionSnippet, selectionSnippet } = $props();
8
+ const loc = new SelectLocalization();
9
+ let listOpen = $state(false);
10
+ let filterText = $state('');
11
+ const floatingConfig = { strategy: 'absolute' };
12
+ const flattenGroupedOptions = (opts) => {
13
+ const result = [];
14
+ for (const opt of opts) {
15
+ if ('options' in opt) {
16
+ for (const child of opt.options) {
17
+ result.push({ label: child.label, value: child.value, group: opt.label });
18
+ }
19
+ }
20
+ else {
21
+ result.push({ label: opt.label, value: opt.value });
22
+ }
23
+ }
24
+ return result;
25
+ };
26
+ const flatOptions = $derived(flattenGroupedOptions(options));
27
+ let selectValue = $state.raw(null);
28
+ $effect(() => {
29
+ const existent = flatOptions.find((x) => x.value === value);
30
+ if (existent) {
31
+ selectValue = {
32
+ label: existent.label,
33
+ value: existent.value,
34
+ $isCreated: false,
35
+ group: existent.group
36
+ };
37
+ }
38
+ else {
39
+ selectValue = null;
40
+ }
41
+ });
42
+ const generateOptions = (includeReset = true) => {
43
+ const generated = flatOptions.map((x) => ({
44
+ label: x.label,
45
+ value: x.value,
46
+ $isCreated: false,
47
+ group: x.group
48
+ }));
49
+ if (allowReset && includeReset) {
50
+ return [
51
+ {
52
+ label: placeholder || '-',
53
+ value: undefined,
54
+ $isCreated: false,
55
+ $isResetOption: true
56
+ },
57
+ ...generated
58
+ ];
59
+ }
60
+ return generated;
61
+ };
62
+ const groupBy = (item) => item.group;
63
+ let optionItems = $state.raw([]);
64
+ $effect(() => {
65
+ let generated = generateOptions();
66
+ if (!listOpen) {
67
+ generated = generated.filter((x) => !x.$isCreated);
68
+ }
69
+ optionItems = generated;
70
+ });
71
+ const onSelectChange = (item) => {
72
+ if (item.$isResetOption) {
73
+ on?.change?.(null);
74
+ return;
75
+ }
76
+ if (item.groupHeader) {
77
+ const group = options.find((opt) => 'options' in opt && opt.label === item.label);
78
+ if (group?.value !== undefined) {
79
+ on?.change?.(group.value);
80
+ }
81
+ return;
82
+ }
83
+ if (item.$isCreated === true) {
84
+ on?.create?.(item.value);
85
+ if (selectValue) {
86
+ const val = selectValue;
87
+ selectValue = null;
88
+ selectValue = val;
89
+ }
90
+ else {
91
+ selectValue = null;
92
+ }
93
+ }
94
+ else {
95
+ on?.change?.(item.value);
96
+ }
97
+ };
98
+ const itemFilter = (label, query) => {
99
+ if (!query) {
100
+ return true;
101
+ }
102
+ const fuse = new Fuse([label]);
103
+ const result = fuse.search(query);
104
+ return result.length > 0;
105
+ };
106
+ const onSelectFilter = (itemsFiltered) => {
107
+ if (!creatable || loading) {
108
+ return;
109
+ }
110
+ if (!creatable.validateFn(filterText)) {
111
+ return;
112
+ }
113
+ if (selectValue?.value === filterText) {
114
+ return;
115
+ }
116
+ const exactMatch = itemsFiltered.find((x) => x.label.toLowerCase() === filterText.toLowerCase());
117
+ if (!exactMatch) {
118
+ const isExistentOption = (opt) => opt.$isCreated === false && !opt.$isResetOption;
119
+ const allExistingOptions = optionItems.filter(isExistentOption);
120
+ const newOption = { value: filterText, label: filterText, $isCreated: true };
121
+ optionItems = [
122
+ newOption,
123
+ ...allExistingOptions.map((x) => ({
124
+ label: x.label,
125
+ value: x.value,
126
+ $isCreated: false,
127
+ group: flatOptions.find((f) => f.value === x.value)?.group
128
+ }))
129
+ ];
130
+ }
131
+ else if (!exactMatch.$isCreated) {
132
+ if (optionItems.some((x) => x.$isCreated)) {
133
+ optionItems = optionItems.filter((x) => !x.$isCreated);
134
+ }
135
+ }
136
+ };
137
+ </script>
138
+
139
+ <div class="select" class:select--disabled={disabled} class:select--loading={loading}>
140
+ <Select
141
+ containerStyles="font-size: 1em;"
142
+ value={selectValue}
143
+ items={optionItems}
144
+ disabled={disabled}
145
+ floatingConfig={floatingConfig}
146
+ placeholder={placeholder}
147
+ bind:loading={loading}
148
+ clearable={false}
149
+ bind:listOpen={listOpen}
150
+ listOffset={2}
151
+ showChevron={!loading}
152
+ itemFilter={itemFilter}
153
+ groupBy={groupBy}
154
+ groupHeaderSelectable={groupHeaderSelectable}
155
+ bind:filterText={filterText}
156
+ inputAttributes={{ title: selectValue?.label ?? placeholder ?? '' }}
157
+ on:change={({ detail }) => onSelectChange(detail)}
158
+ on:filter={({ detail }) => onSelectFilter(detail)}>
159
+ <div slot="item" let:item class="select__option" title={item.label} class:select__option--faded={item.$isResetOption}>
160
+ {#if optionSnippet}
161
+ {@render optionSnippet({ item })}
162
+ {:else}
163
+ {#if item.$isCreated}
164
+ <Icon src={IconAdd} />
165
+ {/if}
166
+ {item.label}
167
+ {/if}
168
+ </div>
169
+ <div class="select__selection" slot="selection" let:selection>
170
+ <span class="select__selection-text">
171
+ {#if selectionSnippet}
172
+ {@render selectionSnippet({ selection })}
173
+ {:else}
174
+ {selection.label}
175
+ {/if}
176
+ </span>
177
+ </div>
178
+ <span slot="prepend" class="select__icon select__icon--prepend">
179
+ {#if icon}
180
+ {@render icon()}
181
+ {/if}
182
+ </span>
183
+ <span slot="chevron-icon" class="select__icon">
184
+ <Icon src={IconChevronDown} />
185
+ </span>
186
+ <svelte:fragment slot="empty">
187
+ <div class="select__no-options">{loc.noMatch}</div>
188
+ </svelte:fragment>
189
+ </Select>
190
+ </div>
191
+
192
+ <!--
193
+ @component
194
+ Single-value select dropdown built on svelte-select with fuzzy search. Supports groups, item creation, and reset option.
195
+
196
+ ### CSS Custom Properties
197
+ | Property | Description | Default |
198
+ |---|---|---|
199
+ | `--sc-kit--singleselect--root--font-size` | Root font size | `1rem` |
200
+ | `--sc-kit--singleselect--height` | Control height | `2em` |
201
+ | `--sc-kit--singleselect--width` | Control width | `100%` |
202
+ | `--sc-kit--singleselect--padding-block` | Vertical padding | `0.25em` |
203
+ | `--sc-kit--singleselect--padding-inline` | Horizontal padding | `0.5em` |
204
+ | `--sc-kit--singleselect--background` | Background color | `light-dark(white, gray-900)` |
205
+ | `--sc-kit--singleselect--background--disabled` | Disabled background | `light-dark(neutral-50, neutral-800)` |
206
+ | `--sc-kit--singleselect--border-color` | Border color | `light-dark(neutral-300, neutral-600)` |
207
+ | `--sc-kit--singleselect--border-radius` | Border radius | `0.25em` |
208
+ | `--sc-kit--singleselect--text--font-size` | Text font size | `0.875em` |
209
+ | `--sc-kit--singleselect--text--color` | Text color | `light-dark(gray-800, white)` |
210
+ | `--sc-kit--singleselect--placeholder--color` | Placeholder color | border-color |
211
+ | `--sc-kit--singleselect--icon--color` | Icon color | border-color |
212
+ | `--sc-kit--singleselect--options--max-height` | Options list max height | `20em` |
213
+ | `--sc-kit--singleselect--item--active--background` | Active item background | `light-dark(neutral-50, neutral-700)` |
214
+ | `--sc-kit--singleselect--item--hover--background` | Item hover background | `light-dark(gray-100, gray-800)` |
215
+ | `--sc-kit--singleselect--group-header--color` | Group header color | placeholder-color |
216
+ | `--sc-kit--singleselect--group-header--font-weight` | Group header font weight | `500` |
217
+ | `--sc-kit--singleselect--group-item--padding-left` | Group item left padding | `1em` |
218
+ -->
219
+
220
+ <style>.select {
221
+ --_singleselect--root--font-size: var(--sc-kit--singleselect--root--font-size, 1rem);
222
+ --_singleselect--height: var(--sc-kit--singleselect--height, 2em);
223
+ --_singleselect--width: var(--sc-kit--singleselect--width, 100%);
224
+ --_singleselect--background: var(--sc-kit--singleselect--background, light-dark(#ffffff, #1c1c1c));
225
+ --_singleselect--background--disabled: var(
226
+ --sc-kit--singleselect--background--disabled,
227
+ light-dark(#f9fafb, #1f2937)
228
+ );
229
+ --_singleselect--border-color: var(--sc-kit--singleselect--border-color, light-dark(#d1d5db, #4b5563));
230
+ --_singleselect--border-radius: var(--sc-kit--singleselect--border-radius, 0.25em);
231
+ --_singleselect--text--font-size: var(--sc-kit--singleselect--text--font-size, 0.875em);
232
+ --_singleselect--text--color: var(--sc-kit--singleselect--text--color, light-dark(#2e2e2e, #ffffff));
233
+ --_singleselect--placeholder--color: var(--sc-kit--singleselect--placeholder--color, var(--_singleselect--border-color));
234
+ --_singleselect--icon--color: var(--sc-kit--singleselect--icon--color, var(--_singleselect--border-color));
235
+ --_singleselect--padding-inline: var(--sc-kit--singleselect--padding-inline, 0.5em);
236
+ --_singleselect--padding-block: var(--sc-kit--singleselect--padding-block, 0.25em);
237
+ --_singleselect--options--max-height: var(--sc-kit--singleselect--options--max-height, 20em);
238
+ --_singleselect--item--hover--background: var(
239
+ --sc-kit--singleselect--item--hover--background,
240
+ light-dark(#f2f2f2, #2e2e2e)
241
+ );
242
+ --_singleselect--item--active--background: var(
243
+ --sc-kit--singleselect--item--active--background,
244
+ light-dark(#f9fafb, #374151)
245
+ );
246
+ --_singleselect--group-header--color: var(--sc-kit--singleselect--group-header--color, var(--_singleselect--placeholder--color));
247
+ --_singleselect--group-header--font-weight: var(--sc-kit--singleselect--group-header--font-weight, 500);
248
+ --_singleselect--group-item--padding-left: var(--sc-kit--singleselect--group-item--padding-left, 1em);
249
+ --background: var(--_singleselect--background);
250
+ --border: 1px solid var(--_singleselect--border-color);
251
+ --border-focused: var(--border);
252
+ --border-hover: var(--border);
253
+ --border-radius: var(--_singleselect--border-radius);
254
+ --border-radius-focused: var(--border-radius);
255
+ --box-sizing: border-box;
256
+ --chevron-background: transparent;
257
+ --chevron-border: transparent;
258
+ --chevron-color: transparent;
259
+ --chevron-height: auto;
260
+ --chevron-pointer-events: none;
261
+ --chevron-width: auto;
262
+ --disabled-background: var(--_singleselect--background--disabled);
263
+ --disabled-border-color: var(--_singleselect--border-color);
264
+ --disabled-color: var(--_singleselect--text--color);
265
+ --disabled-placeholder-color: var(--placeholder-color);
266
+ --disabled-placeholder-opacity: var(--placeholder-opacity);
267
+ --font-size: var(--_singleselect--text--font-size);
268
+ --height: var(--_singleselect--height);
269
+ --icons-color: var(--_singleselect--icon--color);
270
+ --indicators-bottom: auto;
271
+ --indicators-position: static;
272
+ --indicators-right: auto;
273
+ --indicators-top: auto;
274
+ --input--color: var(--_singleselect--text--color);
275
+ --input-left: 0;
276
+ --input-letter-spacing: 1;
277
+ --input-margin: 0;
278
+ --input-padding: 0 var(--_singleselect--padding-inline) 0 0;
279
+ --item-active-background: var(--_singleselect--item--active--background);
280
+ --item-color: var(--_singleselect--text--color);
281
+ --item-first-border-radius: 0;
282
+ --item-height: auto;
283
+ --item-hover-bg: var(--_singleselect--item--hover--background);
284
+ --item-hover-color: var(--_singleselect--text--color);
285
+ --item-is-active-bg: var(--_singleselect--item--active--background);
286
+ --item-is-active-color: var(--_singleselect--text--color);
287
+ --item-is-not-selectable-color: var(--_singleselect--group-header--color);
288
+ --item-line-height: 1;
289
+ --item-padding: var(--_singleselect--padding-block) var(--_singleselect--padding-inline);
290
+ --item-transition: auto;
291
+ --list-background: var(--background);
292
+ --list-border: var(--border);
293
+ --list-border-radius: var(--border-radius);
294
+ --list-max-height: var(--_singleselect--options--max-height);
295
+ --list-position: absolute;
296
+ --list-shadow: none;
297
+ --list-z-index: 2;
298
+ --loading--margin: 0;
299
+ --loading-color: var(--icons-color);
300
+ --loading-height: max-content;
301
+ --loading-width: max-content;
302
+ --margin: 0;
303
+ --max-height: var(--height);
304
+ --padding: 0 var(--_singleselect--padding-inline) 0 0;
305
+ --placeholder-color: var(--_singleselect--placeholder--color);
306
+ --placeholder-opacity: 0.8;
307
+ --selected-item-color: auto;
308
+ --selected-item-overflow: auto;
309
+ --selected-item-padding: auto;
310
+ --spinner-color: var(--icons-color);
311
+ --spinner-height: var(--_singleselect--text--font-size);
312
+ --spinner-width: var(--_singleselect--text--font-size);
313
+ --value-container-overflow: hidden;
314
+ --value-container-padding: 0;
315
+ --width: var(--_singleselect--width);
316
+ --group-title-color: var(--_singleselect--group-header--color);
317
+ --group-title-font-weight: var(--_singleselect--group-header--font-weight);
318
+ --group-title-font-size: var(--_singleselect--text--font-size);
319
+ --group-title-padding: var(--_singleselect--padding-block) var(--_singleselect--padding-inline);
320
+ --group-item-padding-left: var(--_singleselect--group-item--padding-left);
321
+ font-size: var(--_singleselect--root--font-size);
322
+ width: var(--_singleselect--width);
323
+ position: relative;
324
+ }
325
+ .select__icon {
326
+ --sc-kit--icon--color: var(--_singleselect--icon--color);
327
+ --sc-kit--icon--size: 1.25em;
328
+ display: flex;
329
+ align-items: center;
330
+ }
331
+ .select__icon--prepend {
332
+ padding: 0 var(--_singleselect--padding-inline);
333
+ }
334
+ :global(.select__icon--prepend:not(:has(*))) {
335
+ padding-right: 0 !important;
336
+ }
337
+ .select__option {
338
+ font-size: var(--_singleselect--text--font-size);
339
+ }
340
+ .select__option--faded {
341
+ color: var(--_singleselect--placeholder--color);
342
+ opacity: 0.5;
343
+ }
344
+ .select__selection {
345
+ width: 100%;
346
+ min-width: 100%;
347
+ max-width: 100%;
348
+ height: 100%;
349
+ min-height: 100%;
350
+ max-height: 100%;
351
+ display: flex;
352
+ align-items: center;
353
+ min-width: 0;
354
+ }
355
+ .select__selection-text {
356
+ text-overflow: ellipsis;
357
+ max-width: 100%;
358
+ white-space: nowrap;
359
+ overflow: hidden;
360
+ }
361
+ .select__no-options {
362
+ color: var(--_singleselect--placeholder--color);
363
+ padding: var(--_singleselect--padding-block) var(--_singleselect--padding-inline);
364
+ }
365
+ .select--disabled {
366
+ cursor: default;
367
+ pointer-events: none;
368
+ }
369
+ .select--loading {
370
+ pointer-events: none;
371
+ }
372
+ .select--loading::after {
373
+ content: "";
374
+ position: absolute;
375
+ top: 0;
376
+ left: 0;
377
+ width: 100%;
378
+ height: 100%;
379
+ background: light-dark(hsl(0, 0%, 97%), hsl(0, 0%, 3%));
380
+ opacity: 0.5;
381
+ }</style>
@@ -0,0 +1,78 @@
1
+ import type { SelectCreateItemSettings, SelectOption, SelectOptionGroup } from './types';
2
+ import type { Snippet } from 'svelte';
3
+ declare function $$render<T>(): {
4
+ props: {
5
+ value?: T | null;
6
+ options?: (SelectOption<T> | SelectOptionGroup<T>)[];
7
+ placeholder?: string;
8
+ disabled?: boolean;
9
+ loading?: boolean;
10
+ /** Settings for creating new items in the dropdown */
11
+ creatable?: SelectCreateItemSettings | null;
12
+ /** Adds a reset option at the top of the list to clear the value */
13
+ allowReset?: boolean;
14
+ /** Allow clicking group headers to select them */
15
+ groupHeaderSelectable?: boolean;
16
+ on?: {
17
+ change?: (value: T | null) => void;
18
+ create?: (label: string) => void;
19
+ };
20
+ /** Left icon snippet */
21
+ icon?: Snippet;
22
+ /** Custom option rendering */
23
+ optionSnippet?: Snippet<[{
24
+ item: SelectOption<T>;
25
+ }]>;
26
+ /** Custom selection rendering */
27
+ selectionSnippet?: Snippet<[{
28
+ selection: SelectOption<T>;
29
+ }]>;
30
+ };
31
+ exports: {};
32
+ bindings: "";
33
+ slots: {};
34
+ events: {};
35
+ };
36
+ declare class __sveltets_Render<T> {
37
+ props(): ReturnType<typeof $$render<T>>['props'];
38
+ events(): ReturnType<typeof $$render<T>>['events'];
39
+ slots(): ReturnType<typeof $$render<T>>['slots'];
40
+ bindings(): "";
41
+ exports(): {};
42
+ }
43
+ interface $$IsomorphicComponent {
44
+ new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
45
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
46
+ } & ReturnType<__sveltets_Render<T>['exports']>;
47
+ <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
48
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
49
+ }
50
+ /**
51
+ * Single-value select dropdown built on svelte-select with fuzzy search. Supports groups, item creation, and reset option.
52
+ *
53
+ * ### CSS Custom Properties
54
+ * | Property | Description | Default |
55
+ * |---|---|---|
56
+ * | `--sc-kit--singleselect--root--font-size` | Root font size | `1rem` |
57
+ * | `--sc-kit--singleselect--height` | Control height | `2em` |
58
+ * | `--sc-kit--singleselect--width` | Control width | `100%` |
59
+ * | `--sc-kit--singleselect--padding-block` | Vertical padding | `0.25em` |
60
+ * | `--sc-kit--singleselect--padding-inline` | Horizontal padding | `0.5em` |
61
+ * | `--sc-kit--singleselect--background` | Background color | `light-dark(white, gray-900)` |
62
+ * | `--sc-kit--singleselect--background--disabled` | Disabled background | `light-dark(neutral-50, neutral-800)` |
63
+ * | `--sc-kit--singleselect--border-color` | Border color | `light-dark(neutral-300, neutral-600)` |
64
+ * | `--sc-kit--singleselect--border-radius` | Border radius | `0.25em` |
65
+ * | `--sc-kit--singleselect--text--font-size` | Text font size | `0.875em` |
66
+ * | `--sc-kit--singleselect--text--color` | Text color | `light-dark(gray-800, white)` |
67
+ * | `--sc-kit--singleselect--placeholder--color` | Placeholder color | border-color |
68
+ * | `--sc-kit--singleselect--icon--color` | Icon color | border-color |
69
+ * | `--sc-kit--singleselect--options--max-height` | Options list max height | `20em` |
70
+ * | `--sc-kit--singleselect--item--active--background` | Active item background | `light-dark(neutral-50, neutral-700)` |
71
+ * | `--sc-kit--singleselect--item--hover--background` | Item hover background | `light-dark(gray-100, gray-800)` |
72
+ * | `--sc-kit--singleselect--group-header--color` | Group header color | placeholder-color |
73
+ * | `--sc-kit--singleselect--group-header--font-weight` | Group header font weight | `500` |
74
+ * | `--sc-kit--singleselect--group-item--padding-left` | Group item left padding | `1em` |
75
+ */
76
+ declare const Cmp: $$IsomorphicComponent;
77
+ type Cmp<T> = InstanceType<typeof Cmp<T>>;
78
+ export default Cmp;
@@ -0,0 +1,5 @@
1
+ export { default as Multiselect } from './cmp.multiselect.svelte';
2
+ export { default as SearchMultiselect } from './cmp.search-multiselect.svelte';
3
+ export { default as Singleselect } from './cmp.singleselect.svelte';
4
+ export { SelectLocalization } from './select-localization';
5
+ export type { SelectCreateItemSettings, SelectOption, SelectOptionGroup } from './types';
@@ -0,0 +1,4 @@
1
+ export { default as Multiselect } from './cmp.multiselect.svelte';
2
+ export { default as SearchMultiselect } from './cmp.search-multiselect.svelte';
3
+ export { default as Singleselect } from './cmp.singleselect.svelte';
4
+ export { SelectLocalization } from './select-localization';
@@ -0,0 +1,6 @@
1
+ export declare class SelectLocalization {
2
+ get empty(): string;
3
+ get noMatch(): string;
4
+ get createLabel(): (value: string) => string;
5
+ get nMore(): (count: number) => string;
6
+ }
@@ -0,0 +1,27 @@
1
+ import { AppLocale } from '../../core/locale';
2
+ const loc = {
3
+ empty: { en: 'No options', no: 'Ingen alternativer' },
4
+ noMatch: { en: 'No options found', no: 'Ingen alternativer funnet' },
5
+ createLabel: {
6
+ en: (value) => `Create "${value}"`,
7
+ no: (value) => `Opprett "${value}"`
8
+ },
9
+ nMore: {
10
+ en: (count) => `+${count} more`,
11
+ no: (count) => `+${count} til`
12
+ }
13
+ };
14
+ export class SelectLocalization {
15
+ get empty() {
16
+ return loc.empty[AppLocale.current];
17
+ }
18
+ get noMatch() {
19
+ return loc.noMatch[AppLocale.current];
20
+ }
21
+ get createLabel() {
22
+ return loc.createLabel[AppLocale.current];
23
+ }
24
+ get nMore() {
25
+ return loc.nMore[AppLocale.current];
26
+ }
27
+ }
@@ -0,0 +1,29 @@
1
+ export type SelectOption<T = string> = {
2
+ label: string;
3
+ value: T;
4
+ };
5
+ export type SelectOptionGroup<T = string> = {
6
+ label: string;
7
+ /** Value emitted when the group header is selected (requires groupHeaderSelectable) */
8
+ value?: T;
9
+ options: SelectOption<T>[];
10
+ };
11
+ export type SelectCreateItemSettings = {
12
+ /** Validates whether the typed value can be created as a new item */
13
+ validateFn: (value: string) => boolean;
14
+ };
15
+ export type SelectOptionItem<T> = SelectCreatedOptionItem | SelectExistentOptionItem<T>;
16
+ export type SelectCreatedOptionItem = {
17
+ $isCreated: true;
18
+ $isResetOption?: boolean;
19
+ label: string;
20
+ value: string;
21
+ group?: string;
22
+ };
23
+ export type SelectExistentOptionItem<T> = {
24
+ $isCreated: false;
25
+ $isResetOption?: boolean;
26
+ label: string;
27
+ value: T;
28
+ group?: string;
29
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -71,10 +71,4 @@ const disableTimeout = () => {
71
71
  @component
72
72
  Displays a human-readable relative time string (e.g. "5 minutes ago") that auto-updates.
73
73
  Falls back to an absolute date after the threshold is exceeded.
74
-
75
- ### Props
76
- | Prop | Type | Default | Description |
77
- |---|---|---|---|
78
- | `date` | `Date \| string \| null` | `null` | The date to display relative to now |
79
- | `thresholdMinutes` | `number` | `2880` (2 days) | Minutes after which absolute date is shown instead |
80
74
  -->
@@ -1,16 +1,12 @@
1
1
  type Props = {
2
+ /** Date to display relative to now */
2
3
  date: Date | string | null;
4
+ /** Minutes after which absolute date format is used @default 2880 */
3
5
  thresholdMinutes?: number;
4
6
  };
5
7
  /**
6
8
  * Displays a human-readable relative time string (e.g. "5 minutes ago") that auto-updates.
7
9
  * Falls back to an absolute date after the threshold is exceeded.
8
- *
9
- * ### Props
10
- * | Prop | Type | Default | Description |
11
- * |---|---|---|---|
12
- * | `date` | `Date \| string \| null` | `null` | The date to display relative to now |
13
- * | `thresholdMinutes` | `number` | `2880` (2 days) | Minutes after which absolute date is shown instead |
14
10
  */
15
11
  declare const Cmp: import("svelte").Component<Props, {}, "">;
16
12
  type Cmp = ReturnType<typeof Cmp>;
@@ -0,0 +1,34 @@
1
+ @use 'styles/input';
2
+ @use 'styles/colors';
3
+
4
+ @mixin validatable() {
5
+ --_validatable--error--color: var(--sc-kit--validatable--error--color, #{colors.$color-destructive-500});
6
+ --_validatable--error--position: var(--sc-kit--validatable--error--position, absolute);
7
+ --_validatable--error--left: var(--sc-kit--validatable--error--left, 0);
8
+ --_validatable--error--right: var(--sc-kit--validatable--error--right, 0);
9
+ --_validatable--margin-bottom: var(--sc-kit--validatable--margin-bottom, 1.1em);
10
+ --_validatable--margin-right: var(--sc-kit--validatable--margin-right, 0);
11
+ --_validatable--display: var(--sc-kit--validatable--display, block);
12
+ --_validatable--width: var(--sc-kit--validatable--width, auto);
13
+
14
+ position: relative;
15
+ margin-bottom: var(--_validatable--margin-bottom);
16
+ margin-right: var(--_validatable--margin-right);
17
+ display: var(--_validatable--display);
18
+ width: var(--_validatable--width);
19
+
20
+ &--errored {
21
+ @include input.input-accented(var(--_validatable--error--color));
22
+ }
23
+
24
+ &__error {
25
+ position: var(--_validatable--error--position);
26
+ top: calc(100% + 0.1em);
27
+ left: var(--_validatable--error--left);
28
+ right: var(--_validatable--error--right);
29
+ display: block;
30
+ color: var(--_validatable--error--color);
31
+ font-size: 0.7rem;
32
+ font-weight: 400;
33
+ }
34
+ }
@@ -0,0 +1,57 @@
1
+ <script lang="ts" generics="T extends Record<string, unknown>">let { name, handler, disableTouchedTracking = false, children } = $props();
2
+ const showErrors = $derived(handler.errors[name] && (disableTouchedTracking || handler.touched[name]));
3
+ export {};
4
+ </script>
5
+
6
+ <div class="validatable" class:validatable--errored={showErrors}>
7
+ {@render children()}
8
+ {#if showErrors}
9
+ <small class="validatable__error">{handler.errors[name]}</small>
10
+ {/if}
11
+ </div>
12
+
13
+ <!--
14
+ @component
15
+ Wraps a form field and displays validation errors from a FormValidationHandler.
16
+
17
+ ### CSS Custom Properties
18
+ | Property | Description | Default |
19
+ |---|---|---|
20
+ | `--sc-kit--validatable--error--color` | Error text and accent color | destructive-500 |
21
+ | `--sc-kit--validatable--error--position` | Error message positioning | `absolute` |
22
+ | `--sc-kit--validatable--error--left` | Error left offset | `0` |
23
+ | `--sc-kit--validatable--error--right` | Error right offset | `0` |
24
+ | `--sc-kit--validatable--margin-bottom` | Bottom margin for spacing | `1.1em` |
25
+ | `--sc-kit--validatable--margin-right` | Right margin for spacing | `0` |
26
+ | `--sc-kit--validatable--display` | Display mode | `block` |
27
+ | `--sc-kit--validatable--width` | Container width | `auto` |
28
+ -->
29
+
30
+ <style>.validatable {
31
+ --_validatable--error--color: var(--sc-kit--validatable--error--color, #e71d36);
32
+ --_validatable--error--position: var(--sc-kit--validatable--error--position, absolute);
33
+ --_validatable--error--left: var(--sc-kit--validatable--error--left, 0);
34
+ --_validatable--error--right: var(--sc-kit--validatable--error--right, 0);
35
+ --_validatable--margin-bottom: var(--sc-kit--validatable--margin-bottom, 1.1em);
36
+ --_validatable--margin-right: var(--sc-kit--validatable--margin-right, 0);
37
+ --_validatable--display: var(--sc-kit--validatable--display, block);
38
+ --_validatable--width: var(--sc-kit--validatable--width, auto);
39
+ position: relative;
40
+ margin-bottom: var(--_validatable--margin-bottom);
41
+ margin-right: var(--_validatable--margin-right);
42
+ display: var(--_validatable--display);
43
+ width: var(--_validatable--width);
44
+ }
45
+ .validatable--errored {
46
+ --_input--explicit-shadow-color: var(--_validatable--error--color);
47
+ }
48
+ .validatable__error {
49
+ position: var(--_validatable--error--position);
50
+ top: calc(100% + 0.1em);
51
+ left: var(--_validatable--error--left);
52
+ right: var(--_validatable--error--right);
53
+ display: block;
54
+ color: var(--_validatable--error--color);
55
+ font-size: 0.7rem;
56
+ font-weight: 400;
57
+ }</style>