intelliwaketssveltekitv25 1.0.80 → 1.0.82

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.
@@ -0,0 +1,338 @@
1
+ import MultiSelect from './MultiSelect.svelte';
2
+ const sampleTags = [
3
+ { id: 1, name: 'JavaScript' },
4
+ { id: 2, name: 'TypeScript' },
5
+ { id: 3, name: 'Python' },
6
+ { id: 4, name: 'Java' },
7
+ { id: 5, name: 'C++' },
8
+ { id: 6, name: 'Ruby' },
9
+ { id: 7, name: 'Go' },
10
+ { id: 8, name: 'Rust' },
11
+ { id: 9, name: 'PHP' },
12
+ { id: 10, name: 'Swift' }
13
+ ];
14
+ const groupedTags = [
15
+ { id: 1, name: 'JavaScript', header: 'Frontend' },
16
+ { id: 2, name: 'TypeScript', header: 'Frontend' },
17
+ { id: 3, name: 'React', header: 'Frontend' },
18
+ { id: 4, name: 'Vue', header: 'Frontend' },
19
+ { id: 5, name: 'Node.js', header: 'Backend' },
20
+ { id: 6, name: 'Python', header: 'Backend' },
21
+ { id: 7, name: 'Go', header: 'Backend' },
22
+ { id: 8, name: 'MySQL', header: 'Database' },
23
+ { id: 9, name: 'PostgreSQL', header: 'Database' },
24
+ { id: 10, name: 'MongoDB', header: 'Database' }
25
+ ];
26
+ const meta = {
27
+ title: 'Components/MultiSelect',
28
+ component: MultiSelect,
29
+ tags: ['autodocs'],
30
+ argTypes: {
31
+ possibles: {
32
+ control: 'object',
33
+ description: 'Array of all available items to select from',
34
+ table: {
35
+ type: { summary: 'T[]' }
36
+ }
37
+ },
38
+ selected: {
39
+ control: 'object',
40
+ description: 'Currently selected items (two-way bindable)',
41
+ table: {
42
+ type: { summary: 'T[]' },
43
+ defaultValue: { summary: '[]' }
44
+ }
45
+ },
46
+ selectedIDs: {
47
+ control: 'object',
48
+ description: 'IDs of selected items (two-way bindable, alternative to selected)',
49
+ table: {
50
+ type: { summary: '(number | string)[] | undefined' },
51
+ defaultValue: { summary: 'undefined' }
52
+ }
53
+ },
54
+ placeholder: {
55
+ control: 'text',
56
+ description: 'Placeholder text shown when no items selected',
57
+ table: {
58
+ type: { summary: 'string' },
59
+ defaultValue: { summary: '""' }
60
+ }
61
+ },
62
+ disabled: {
63
+ control: 'boolean',
64
+ description: 'Disable user interaction',
65
+ table: {
66
+ type: { summary: 'boolean' },
67
+ defaultValue: { summary: 'false' }
68
+ }
69
+ },
70
+ readonly: {
71
+ control: 'boolean',
72
+ description: 'Display in readonly mode (no interaction allowed)',
73
+ table: {
74
+ type: { summary: 'boolean' },
75
+ defaultValue: { summary: 'false' }
76
+ }
77
+ },
78
+ required: {
79
+ control: 'boolean',
80
+ description: 'Mark as required (shows invalid state if empty)',
81
+ table: {
82
+ type: { summary: 'boolean' },
83
+ defaultValue: { summary: 'false' }
84
+ }
85
+ },
86
+ isMulti: {
87
+ control: 'boolean',
88
+ description: 'Allow multiple selections (false = single-select mode)',
89
+ table: {
90
+ type: { summary: 'boolean' },
91
+ defaultValue: { summary: 'true' }
92
+ }
93
+ },
94
+ allowClearAll: {
95
+ control: 'boolean',
96
+ description: 'Show clear all button when items are selected',
97
+ table: {
98
+ type: { summary: 'boolean' },
99
+ defaultValue: { summary: 'true' }
100
+ }
101
+ },
102
+ createPrefix: {
103
+ control: 'text',
104
+ description: 'Text prefix shown before new item name in create option',
105
+ table: {
106
+ type: { summary: 'string' },
107
+ defaultValue: { summary: '"Create:"' }
108
+ }
109
+ },
110
+ autoFocus: {
111
+ control: 'boolean',
112
+ description: 'Auto-focus input on mount',
113
+ table: {
114
+ type: { summary: 'boolean' },
115
+ defaultValue: { summary: 'false' }
116
+ }
117
+ }
118
+ }
119
+ };
120
+ export default meta;
121
+ /**
122
+ * Default multi-select with no initial selection.
123
+ * Users can select multiple items from the dropdown.
124
+ */
125
+ export const Default = {
126
+ args: {
127
+ possibles: sampleTags,
128
+ selected: [],
129
+ placeholder: 'Select programming languages...'
130
+ }
131
+ };
132
+ /**
133
+ * Multi-select with pre-selected items.
134
+ * Demonstrates binding to existing selections.
135
+ */
136
+ export const PreSelected = {
137
+ args: {
138
+ possibles: sampleTags,
139
+ selected: [sampleTags[0], sampleTags[1]], // JavaScript and TypeScript
140
+ placeholder: 'Select programming languages...'
141
+ }
142
+ };
143
+ /**
144
+ * Single-select mode (isMulti=false).
145
+ * Only one item can be selected at a time - acts like a searchable dropdown.
146
+ */
147
+ export const SingleSelect = {
148
+ args: {
149
+ possibles: sampleTags,
150
+ selected: [],
151
+ isMulti: false,
152
+ placeholder: 'Select one language...'
153
+ }
154
+ };
155
+ /**
156
+ * Enable dynamic item creation with the create function.
157
+ * Type a name that doesn't exist and press Enter to create a new item.
158
+ */
159
+ export const WithCreation = {
160
+ args: {
161
+ possibles: sampleTags,
162
+ selected: [],
163
+ placeholder: 'Select or create languages...',
164
+ create: (value) => ({ id: Date.now(), name: value }),
165
+ createPrefix: 'Create new:'
166
+ }
167
+ };
168
+ /**
169
+ * Creation with validation.
170
+ * Prevents creating items that don't meet validation criteria.
171
+ */
172
+ export const WithValidation = {
173
+ args: {
174
+ possibles: sampleTags,
175
+ selected: [],
176
+ placeholder: 'Select or create (min 3 chars)...',
177
+ create: (value) => ({ id: Date.now(), name: value }),
178
+ createValid: (value) => {
179
+ if (value.length < 3) {
180
+ return 'Language name must be at least 3 characters';
181
+ }
182
+ return true;
183
+ }
184
+ }
185
+ };
186
+ /**
187
+ * Searchable dropdown with filtering.
188
+ * Type to filter the list of available items.
189
+ */
190
+ export const Searchable = {
191
+ args: {
192
+ possibles: sampleTags,
193
+ selected: [],
194
+ placeholder: 'Type to search languages...'
195
+ }
196
+ };
197
+ /**
198
+ * Grouped items with headers.
199
+ * Items are organized into sections using the headerValue function.
200
+ */
201
+ export const WithHeaders = {
202
+ args: {
203
+ possibles: groupedTags,
204
+ selected: [],
205
+ placeholder: 'Select technologies...'
206
+ }
207
+ };
208
+ /**
209
+ * Disabled state prevents all interaction.
210
+ */
211
+ export const Disabled = {
212
+ args: {
213
+ possibles: sampleTags,
214
+ selected: [sampleTags[0]],
215
+ disabled: true,
216
+ placeholder: 'Disabled...'
217
+ }
218
+ };
219
+ /**
220
+ * Readonly state displays selections but prevents changes.
221
+ */
222
+ export const Readonly = {
223
+ args: {
224
+ possibles: sampleTags,
225
+ selected: [sampleTags[0], sampleTags[1]],
226
+ readonly: true,
227
+ placeholder: 'Readonly...'
228
+ }
229
+ };
230
+ /**
231
+ * Without clear all button.
232
+ * Users must remove items individually.
233
+ */
234
+ export const NoClearAll = {
235
+ args: {
236
+ possibles: sampleTags,
237
+ selected: [sampleTags[0], sampleTags[1], sampleTags[2]],
238
+ allowClearAll: false,
239
+ placeholder: 'Select languages...'
240
+ }
241
+ };
242
+ /**
243
+ * Required field validation.
244
+ * Shows invalid state when no items are selected.
245
+ */
246
+ export const Required = {
247
+ args: {
248
+ possibles: sampleTags,
249
+ selected: [],
250
+ required: true,
251
+ placeholder: 'At least one language required'
252
+ }
253
+ };
254
+ /**
255
+ * Form integration with hidden inputs.
256
+ * Selected item IDs are submitted with the form using the name attribute.
257
+ */
258
+ export const FormIntegration = {
259
+ args: {
260
+ possibles: sampleTags,
261
+ selected: [sampleTags[0]],
262
+ name: 'languages',
263
+ placeholder: 'Select languages for form...'
264
+ }
265
+ };
266
+ /**
267
+ * Using selectedIDs for binding instead of selected array.
268
+ * Useful when working with IDs directly.
269
+ */
270
+ export const BindToIDs = {
271
+ args: {
272
+ possibles: sampleTags,
273
+ selectedIDs: [1, 2], // IDs of JavaScript and TypeScript
274
+ placeholder: 'Bound to IDs...'
275
+ }
276
+ };
277
+ /**
278
+ * Track created vs existing items.
279
+ * The created and existing bindable props separate new items from existing ones.
280
+ */
281
+ export const TrackCreated = {
282
+ args: {
283
+ possibles: sampleTags,
284
+ selected: [],
285
+ placeholder: 'Select or create languages...',
286
+ create: (value) => ({ id: Date.now(), name: value }),
287
+ createPrefix: 'Add new:'
288
+ }
289
+ };
290
+ /**
291
+ * Large dataset with many items.
292
+ * Demonstrates search performance with lots of options.
293
+ */
294
+ export const LargeDataset = {
295
+ args: {
296
+ possibles: Array.from({ length: 100 }, (_, i) => ({
297
+ id: i + 1,
298
+ name: `Language ${i + 1}`
299
+ })),
300
+ selected: [],
301
+ placeholder: 'Search 100+ items...'
302
+ }
303
+ };
304
+ /**
305
+ * Empty possibles array.
306
+ * Shows "No items found" message.
307
+ */
308
+ export const EmptyList = {
309
+ args: {
310
+ possibles: [],
311
+ selected: [],
312
+ placeholder: 'No items available...'
313
+ }
314
+ };
315
+ /**
316
+ * Auto-focus on mount.
317
+ * Input is automatically focused when component renders.
318
+ */
319
+ export const AutoFocus = {
320
+ args: {
321
+ possibles: sampleTags,
322
+ selected: [],
323
+ autoFocus: true,
324
+ placeholder: 'Auto-focused input...'
325
+ }
326
+ };
327
+ /**
328
+ * Custom styling with CSS classes.
329
+ */
330
+ export const CustomStyling = {
331
+ args: {
332
+ possibles: sampleTags,
333
+ selected: [],
334
+ placeholder: 'Custom styled...',
335
+ controlClass: 'border-2 border-primary-main',
336
+ inputClass: 'text-primary-main font-bold'
337
+ }
338
+ };
@@ -1,3 +1,43 @@
1
+ <!--
2
+ @component
3
+ Type-safe, searchable multi-select dropdown with dynamic item creation and keyboard navigation.
4
+ Replaces native <select multiple> with advanced features.
5
+
6
+ @example
7
+ ```svelte
8
+ <script lang="ts">
9
+ import { MultiSelect } from 'intelliwaketssveltekitv25';
10
+
11
+ interface Tag {
12
+ id: number;
13
+ name: string;
14
+ }
15
+
16
+ const tags: Tag[] = [
17
+ { id: 1, name: 'JavaScript' },
18
+ { id: 2, name: 'TypeScript' }
19
+ ];
20
+
21
+ let selected = $state<Tag[]>([]);
22
+ </script>
23
+
24
+ <MultiSelect possibles={tags} bind:selected={selected} placeholder="Select tags..." />
25
+ ```
26
+
27
+ @remarks
28
+ - Uses TypeScript generics for type-safe selections: <T extends TGenericMultiSelect>
29
+ - Svelte 5 $bindable runes for two-way binding (selected, selectedIDs, created, existing)
30
+ - Keyboard navigation: Arrow keys, Enter, Backspace
31
+ - Searchable with automatic filtering
32
+ - Dynamic item creation with validation
33
+ - Supports single-select mode (isMulti=false)
34
+ - Custom display and ID functions for flexible data structures
35
+ - Grouping/headers support via headerValue function
36
+
37
+ @see DropDown - For single action/selection without search
38
+ @see DropDownControl - Lower-level dropdown control (used internally)
39
+ -->
40
+
1
41
  <!--suppress JSDeprecatedSymbols -->
2
42
  <script lang='ts' generics="T extends TGenericMultiSelect">
3
43
  import { DeepEqual, SearchRows } from '@solidbasisventures/intelliwaketsfoundation'
@@ -8,46 +48,87 @@
8
48
  import { type ActionArray, useActions } from './useActions'
9
49
 
10
50
  let {
51
+ /** HTML id attribute for the input element */
11
52
  id = undefined,
53
+ /** Controls dropdown visibility (two-way bindable) */
12
54
  show = $bindable(false),
55
+ /** Svelte actions array */
13
56
  use = [],
57
+ /** Array of all available items to select from */
14
58
  possibles,
59
+ /** Currently selected items (two-way bindable) */
15
60
  selected = $bindable([]),
61
+ /** IDs of selected items (two-way bindable, alternative to selected) */
16
62
  selectedIDs = $bindable(undefined),
63
+ /** Newly created items (two-way bindable, subset of selected that don't exist in possibles) */
17
64
  created = $bindable([]),
65
+ /** Existing items (two-way bindable, subset of selected that exist in possibles) */
18
66
  existing = $bindable([]),
67
+ /** Form input name for hidden inputs (enables form submission) */
19
68
  name = null,
69
+ /** Placeholder text shown when no items selected */
20
70
  placeholder = '',
71
+ /** Disable user interaction */
21
72
  disabled = false,
73
+ /** Display in readonly mode (no interaction allowed) */
22
74
  readonly = false,
75
+ /** Mark as required (shows invalid state if empty) */
23
76
  required = false,
77
+ /** Mark as invalid (shows error styling) */
24
78
  invalid = false,
79
+ /** Allow multiple selections (false = single-select mode) */
25
80
  isMulti = true,
81
+ /** Show clear all button when items are selected */
26
82
  allowClearAll = true,
83
+ /** Text prefix shown before new item name in create option */
27
84
  createPrefix = 'Create:',
85
+ /** Function to create new items from search string (enables dynamic creation) */
28
86
  create = undefined,
87
+ /** Validation function for new items (returns true or error message string) */
29
88
  createValid = undefined,
89
+ /** Tab index for keyboard navigation */
30
90
  tabindex = 0,
91
+ /** Function to extract display text from item */
31
92
  displayValue = (item: T) => item.name ?? item.id ?? '',
93
+ /** Function to extract unique identifier from item */
32
94
  idValue = (item: T) => item.id ?? displayValue(item),
95
+ /** Function to compute key for each statements (defaults to idValue) */
33
96
  keyValue = (item: T) => idValue(item),
97
+ /** Function to compute value for hidden form inputs */
34
98
  inputValue = (item: T) => idValue(item),
99
+ /** Function to extract header/group text from item (for grouping) */
35
100
  headerValue = (item: T | null | undefined) => item?.header,
101
+ /** Match dropdown width to toggle button width */
36
102
  sameSize = true,
103
+ /** Timestamp to trigger dropdown resize recalculation */
37
104
  resizeTS = 1,
105
+ /** Auto-focus input on mount */
38
106
  autoFocus = false,
107
+ /** Z-index for dropdown positioning */
39
108
  zIndex = 50,
109
+ /** Additional CSS classes for dropdown body */
40
110
  bodyClass = '',
111
+ /** Additional CSS classes for toggle button */
41
112
  toggleClass = '',
113
+ /** Additional CSS classes for dropdown control wrapper */
42
114
  controlClass = '',
115
+ /** Additional CSS classes for search input */
43
116
  inputClass = '',
117
+ /** Parent div element reference (for focus management) */
44
118
  parentDivElement = null,
119
+ /** Associate with a form by ID */
45
120
  form = undefined,
121
+ /** Callback when item is added (passes item ID) */
46
122
  onadd,
123
+ /** Callback when existing item is selected (passes item ID) */
47
124
  onselect,
125
+ /** Callback when new item is created (passes item ID) */
48
126
  oncreate,
127
+ /** Callback when selection changes (passes array of selected items) */
49
128
  onchange,
129
+ /** Callback when item is cleared (passes item ID) */
50
130
  onclear,
131
+ /** Callback when all items are cleared */
51
132
  onclearall
52
133
  }: {
53
134
  id?: string
@@ -64,6 +64,44 @@ interface $$IsomorphicComponent {
64
64
  <T extends TGenericMultiSelect>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
65
65
  z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
66
66
  }
67
+ /**
68
+ * Type-safe, searchable multi-select dropdown with dynamic item creation and keyboard navigation.
69
+ * Replaces native <select multiple> with advanced features.
70
+ *
71
+ * @example
72
+ * ```svelte
73
+ * <script lang="ts">
74
+ * import { MultiSelect } from 'intelliwaketssveltekitv25';
75
+ *
76
+ * interface Tag {
77
+ * id: number;
78
+ * name: string;
79
+ * }
80
+ *
81
+ * const tags: Tag[] = [
82
+ * { id: 1, name: 'JavaScript' },
83
+ * { id: 2, name: 'TypeScript' }
84
+ * ];
85
+ *
86
+ * let selected = $state<Tag[]>([]);
87
+ * </script>
88
+ *
89
+ * <MultiSelect possibles={tags} bind:selected={selected} placeholder="Select tags..." />
90
+ * ```
91
+ *
92
+ * @remarks
93
+ * - Uses TypeScript generics for type-safe selections: <T extends TGenericMultiSelect>
94
+ * - Svelte 5 $bindable runes for two-way binding (selected, selectedIDs, created, existing)
95
+ * - Keyboard navigation: Arrow keys, Enter, Backspace
96
+ * - Searchable with automatic filtering
97
+ * - Dynamic item creation with validation
98
+ * - Supports single-select mode (isMulti=false)
99
+ * - Custom display and ID functions for flexible data structures
100
+ * - Grouping/headers support via headerValue function
101
+ *
102
+ * @see DropDown - For single action/selection without search
103
+ * @see DropDownControl - Lower-level dropdown control (used internally)
104
+ */
67
105
  declare const MultiSelect: $$IsomorphicComponent;
68
106
  type MultiSelect<T extends TGenericMultiSelect> = InstanceType<typeof MultiSelect<T>>;
69
107
  export default MultiSelect;
@@ -0,0 +1,81 @@
1
+ import type { StoryObj } from '@storybook/svelte';
2
+ type SwitchProps = {
3
+ checked?: boolean;
4
+ disabled?: boolean;
5
+ readonly?: boolean;
6
+ name?: string;
7
+ value?: unknown;
8
+ offValue?: unknown;
9
+ displayCheckInverse?: boolean;
10
+ hidden?: boolean;
11
+ class?: string;
12
+ };
13
+ declare const meta: {
14
+ title: string;
15
+ component: import("svelte").Component<{
16
+ id?: string | undefined;
17
+ use?: import("./useActions").ActionArray;
18
+ checked?: boolean;
19
+ disabled?: boolean;
20
+ readonly?: boolean;
21
+ name?: string | undefined;
22
+ form?: string | undefined;
23
+ value?: unknown | undefined;
24
+ offValue?: unknown | undefined;
25
+ hidden?: boolean;
26
+ displayCheckInverse?: boolean;
27
+ class?: string;
28
+ oncheck?: (val: boolean) => void;
29
+ children?: import("svelte").Snippet;
30
+ }, {}, "checked">;
31
+ tags: string[];
32
+ argTypes: {
33
+ checked: {
34
+ control: "boolean";
35
+ description: string;
36
+ };
37
+ disabled: {
38
+ control: "boolean";
39
+ description: string;
40
+ };
41
+ readonly: {
42
+ control: "boolean";
43
+ description: string;
44
+ };
45
+ name: {
46
+ control: "text";
47
+ description: string;
48
+ };
49
+ value: {
50
+ control: "text";
51
+ description: string;
52
+ };
53
+ offValue: {
54
+ control: "text";
55
+ description: string;
56
+ };
57
+ displayCheckInverse: {
58
+ control: "boolean";
59
+ description: string;
60
+ };
61
+ hidden: {
62
+ control: "boolean";
63
+ description: string;
64
+ };
65
+ class: {
66
+ control: "text";
67
+ description: string;
68
+ };
69
+ };
70
+ };
71
+ export default meta;
72
+ type Story = StoryObj<SwitchProps>;
73
+ export declare const Default: Story;
74
+ export declare const Checked: Story;
75
+ export declare const Disabled: Story;
76
+ export declare const DisabledChecked: Story;
77
+ export declare const Readonly: Story;
78
+ export declare const WithFormName: Story;
79
+ export declare const WithCustomValues: Story;
80
+ export declare const DisplayInverse: Story;
81
+ export declare const DisplayInverseChecked: Story;
@@ -0,0 +1,99 @@
1
+ import Switch from './Switch.svelte';
2
+ const meta = {
3
+ title: 'Components/Switch',
4
+ component: Switch,
5
+ tags: ['autodocs'],
6
+ argTypes: {
7
+ checked: {
8
+ control: 'boolean',
9
+ description: 'Current checked state (two-way bindable)'
10
+ },
11
+ disabled: {
12
+ control: 'boolean',
13
+ description: 'Disables user interaction'
14
+ },
15
+ readonly: {
16
+ control: 'boolean',
17
+ description: 'Visual display only, no interaction'
18
+ },
19
+ name: {
20
+ control: 'text',
21
+ description: 'Form field name for submissions'
22
+ },
23
+ value: {
24
+ control: 'text',
25
+ description: 'Value to submit when checked'
26
+ },
27
+ offValue: {
28
+ control: 'text',
29
+ description: 'Value to submit when unchecked'
30
+ },
31
+ displayCheckInverse: {
32
+ control: 'boolean',
33
+ description: 'Invert visual display (useful for "disabled" semantics)'
34
+ },
35
+ hidden: {
36
+ control: 'boolean',
37
+ description: 'Hide the component'
38
+ },
39
+ class: {
40
+ control: 'text',
41
+ description: 'Additional CSS classes'
42
+ }
43
+ }
44
+ };
45
+ export default meta;
46
+ export const Default = {
47
+ args: {
48
+ checked: false
49
+ }
50
+ };
51
+ export const Checked = {
52
+ args: {
53
+ checked: true
54
+ }
55
+ };
56
+ export const Disabled = {
57
+ args: {
58
+ checked: false,
59
+ disabled: true
60
+ }
61
+ };
62
+ export const DisabledChecked = {
63
+ args: {
64
+ checked: true,
65
+ disabled: true
66
+ }
67
+ };
68
+ export const Readonly = {
69
+ args: {
70
+ checked: true,
71
+ readonly: true
72
+ }
73
+ };
74
+ export const WithFormName = {
75
+ args: {
76
+ checked: true,
77
+ name: 'agreeToTerms'
78
+ }
79
+ };
80
+ export const WithCustomValues = {
81
+ args: {
82
+ checked: true,
83
+ name: 'subscription',
84
+ value: 'premium',
85
+ offValue: 'free'
86
+ }
87
+ };
88
+ export const DisplayInverse = {
89
+ args: {
90
+ checked: false,
91
+ displayCheckInverse: true
92
+ }
93
+ };
94
+ export const DisplayInverseChecked = {
95
+ args: {
96
+ checked: true,
97
+ displayCheckInverse: true
98
+ }
99
+ };