intelliwaketssveltekitv25 1.0.82 → 1.0.83

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.
package/llm.txt DELETED
@@ -1,1635 +0,0 @@
1
- # IntelliWakeTSSvelteKitV2.5 - LLM Component Guide
2
-
3
- **Version:** 1.0.81
4
- **Technologies:** Svelte 5 | TypeScript | Tailwind CSS v4
5
- **Package:** `intelliwaketssveltekitv25`
6
-
7
- ## Library Overview
8
-
9
- This is a professional SvelteKit component library providing 41 reusable UI components and 17 utility modules. Built with modern Svelte 5 features (runes, snippets, generics) and optimized for TypeScript developers building data-driven applications.
10
-
11
- **Key Features:**
12
- - Svelte 5 runes (`$state`, `$derived`, `$effect`, `$bindable`)
13
- - TypeScript generics for type-safe data handling
14
- - Tailwind CSS v4 with custom theme integration
15
- - Comprehensive form controls with two-way binding
16
- - Performance-optimized data display components
17
- - Responsive layout patterns
18
-
19
- ---
20
-
21
- ## 🚨 CRITICAL: Native HTML Replacement Map
22
-
23
- **IMPORTANT FOR AI ASSISTANTS**: Before writing native HTML elements or standard UI patterns, check this table for library replacements. Always prefer library components over native HTML.
24
-
25
- | User Request | ❌ Do Not Use | ✅ Use Instead | Import Statement |
26
- |--------------|---------------|----------------|------------------|
27
- | Checkbox, toggle switch, on/off control | `<input type="checkbox">` | **Switch** | `import { Switch } from 'intelliwaketssveltekitv25'` |
28
- | Numeric input, currency, percentage, decimals | `<input type="number">` | **InputNumber** | `import { InputNumber } from 'intelliwaketssveltekitv25'` |
29
- | Modal dialog, popup, overlay | `<dialog>` or custom div overlay | **Modal** | `import { Modal } from 'intelliwaketssveltekitv25'` |
30
- | Dropdown menu, select replacement | `<select>` | **DropDown** | `import { DropDown } from 'intelliwaketssveltekitv25'` |
31
- | Data table, grid display | `<table>` with manual code | **ArrayTable** | `import { ArrayTable } from 'intelliwaketssveltekitv25'` |
32
- | Multi-line text input | `<textarea>` | **TextArea** | `import { TextArea } from 'intelliwaketssveltekitv25'` |
33
- | Multi-select, tags, categories | `<select multiple>` or custom | **MultiSelect** | `import { MultiSelect } from 'intelliwaketssveltekitv25'` |
34
-
35
- ---
36
-
37
- ## Component Documentation
38
-
39
- ### Switch
40
-
41
- **Replaces:** `<input type="checkbox">` for ALL toggle switches and boolean controls
42
- **Purpose:** Custom styled toggle switch with smooth animations, accessibility, and two-way data binding
43
- **When to Use:**
44
- - Feature toggles (enable/disable settings)
45
- - Boolean preferences (notifications on/off)
46
- - Any on/off state in settings or forms
47
- - **NOT for multiple selections** (use CheckBox component for that)
48
-
49
- **Key Props:**
50
-
51
- - `checked?: boolean` ($bindable) - Current checked state, use `bind:checked` for two-way binding
52
- - `disabled?: boolean` (default: false) - Disables user interaction, grays out the switch
53
- - `readonly?: boolean` (default: false) - Visual display only, no interaction allowed
54
- - `name?: string` - Form field name for HTML form submissions
55
- - `value?: unknown` - Value to submit when checked (default: boolean checked state)
56
- - `offValue?: unknown` - Value to submit when unchecked (default: undefined)
57
- - `displayCheckInverse?: boolean` - Inverts visual display (useful for "disabled" semantics)
58
- - `hidden?: boolean` - Hides the component
59
- - `class?: string` - Additional CSS classes for the wrapper
60
- - `oncheck?: (val: boolean) => void` - Callback fired when checked state changes
61
- - `use?: ActionArray` - Svelte actions array
62
- - `id?: string` - HTML id attribute
63
- - `form?: string` - Associate with a specific form by ID
64
-
65
- **Snippets:**
66
- - `children?: Snippet` - Label content displayed to the right of the switch
67
-
68
- **Usage Examples:**
69
-
70
- ```svelte
71
- <!-- Basic toggle -->
72
- <script>
73
- import { Switch } from 'intelliwaketssveltekitv25';
74
- let notificationsEnabled = $state(false);
75
- </script>
76
-
77
- <Switch bind:checked={notificationsEnabled}>
78
- Enable Email Notifications
79
- </Switch>
80
-
81
- <!-- In a form with name attribute -->
82
- <form method="POST">
83
- <Switch name="agreeToTerms" bind:checked={agreedToTerms}>
84
- I agree to the terms and conditions
85
- </Switch>
86
- <button type="submit">Submit</button>
87
- </form>
88
-
89
- <!-- Disabled state -->
90
- <Switch checked={true} disabled>
91
- Premium Feature (Upgrade Required)
92
- </Switch>
93
-
94
- <!-- With oncheck callback -->
95
- <Switch
96
- bind:checked={darkModeEnabled}
97
- oncheck={(isChecked) => {
98
- console.log('Dark mode:', isChecked);
99
- // Apply theme changes
100
- }}
101
- >
102
- Dark Mode
103
- </Switch>
104
-
105
- <!-- Custom value submission -->
106
- <Switch
107
- name="subscription"
108
- bind:checked={isSubscribed}
109
- value="premium"
110
- offValue="free"
111
- >
112
- Premium Subscription
113
- </Switch>
114
-
115
- <!-- Display inverse (show as "on" when feature is disabled) -->
116
- <Switch bind:checked={disableTracking} displayCheckInverse>
117
- Disable Tracking
118
- </Switch>
119
- ```
120
-
121
- **Common Mistakes:**
122
-
123
- - ❌ Using `value` prop for binding: `<Switch bind:value={x}>`
124
- ✅ Correct: `<Switch bind:checked={x}>`
125
-
126
- - ❌ Forgetting `bind:` directive: `<Switch checked={x}>`
127
- ✅ Correct: `<Switch bind:checked={x}>` (for two-way binding)
128
-
129
- - ❌ Wrapping in `<label>`: `<label><Switch /></label>`
130
- ✅ Correct: `<Switch>Label Text</Switch>` (uses children snippet internally)
131
-
132
- - ❌ Using Switch for multiple selections from a list
133
- ✅ Correct: Use `CheckBox` component for multi-select scenarios
134
-
135
- **Related Components:**
136
- - `CheckBox` - For custom checkbox styling (not toggle appearance)
137
- - `SwitchDateNull` - Toggle that sets/clears a date value
138
-
139
- **Storybook:** See `Components/Switch` stories for interactive examples
140
-
141
- ---
142
-
143
- ### InputNumber
144
-
145
- **Replaces:** `<input type="number">` for ALL numeric inputs
146
- **Purpose:** Formatted numeric input with automatic currency, percentage, and decimal handling
147
- **When to Use:**
148
- - Currency amounts (prices, costs, payments)
149
- - Percentages (tax rates, discounts, progress)
150
- - Decimal numbers (measurements, weights, quantities)
151
- - Integer counts with min/max constraints
152
- - Any numeric data entry where formatting matters
153
-
154
- **Key Props:**
155
-
156
- - `value?: number | null` ($bindable) - Current numeric value, use `bind:value`
157
- - `currency?: boolean` - Format as currency (adds $ prefix, 2 decimal places)
158
- - `percent?: boolean` - Format as percentage (adds % suffix, stores as decimal 0-1, displays as 0-100)
159
- - `fixedDecimals?: number` - Force exact number of decimal places
160
- - `minDecimals?: number` - Minimum decimal places to show
161
- - `maxDecimals?: number` - Maximum decimal places allowed
162
- - `min?: number` - Minimum allowed value (enforced on input)
163
- - `max?: number` - Maximum allowed value (enforced on input)
164
- - `allowNegative?: boolean` - Allow negative numbers (default: false)
165
- - `zeroBlank?: boolean` - Display empty string instead of 0
166
- - `zeroDash?: boolean` - Display "-" instead of 0
167
- - `nullBlank?: boolean` - Display empty string for null values
168
- - `nullDash?: boolean` - Display "-" for null values
169
- - `prefix?: string` - Custom prefix (overrides currency $)
170
- - `suffix?: string` - Custom suffix (overrides percent %)
171
- - `delayChange?: boolean | number | 'blur'` - Delay before updating bound value
172
- - `true`: 1500ms delay
173
- - `number`: Custom milliseconds delay
174
- - `'blur'`: Update only on blur event
175
- - `widthNumbers?: number` - Set input width based on number of digits
176
- - `class?: string` - Additional CSS classes for wrapper div
177
- - `inputClass?: string` - CSS classes for the input element itself
178
- - `onchange?: (value: number | null) => void` - Callback when value changes
179
- - Standard HTML input props: `disabled`, `readonly`, `required`, `name`, `placeholder`, `id`, etc.
180
-
181
- **TypeScript Type:** `TInputNumberAttributes` (extends standard input attributes)
182
-
183
- **Usage Examples:**
184
-
185
- ```svelte
186
- <script>
187
- import { InputNumber } from 'intelliwaketssveltekitv25';
188
- let price = $state(29.99);
189
- let taxRate = $state(0.08); // 8% stored as 0.08, displays as 8
190
- let quantity = $state(1);
191
- let weight = $state(null);
192
- </script>
193
-
194
- <!-- Currency input -->
195
- <label>
196
- Price:
197
- <InputNumber bind:value={price} currency required />
198
- </label>
199
- <!-- Displays: $29.99 -->
200
-
201
- <!-- Percentage input -->
202
- <label>
203
- Tax Rate:
204
- <InputNumber bind:value={taxRate} percent />
205
- </label>
206
- <!-- Displays: 8% (user enters 8, stored as 0.08) -->
207
-
208
- <!-- Integer quantity with constraints -->
209
- <label>
210
- Quantity:
211
- <InputNumber bind:value={quantity} fixedDecimals={0} min={1} max={999} />
212
- </label>
213
-
214
- <!-- Decimal with custom suffix -->
215
- <label>
216
- Weight:
217
- <InputNumber bind:value={weight} suffix="kg" maxDecimals={2} zeroBlank />
218
- </label>
219
-
220
- <!-- With delayed change (for expensive calculations) -->
221
- <InputNumber
222
- bind:value={searchAmount}
223
- currency
224
- delayChange={true}
225
- placeholder="Filter by amount..."
226
- />
227
- <!-- Value updates 1.5 seconds after user stops typing -->
228
-
229
- <!-- Update only on blur -->
230
- <InputNumber
231
- bind:value={finalTotal}
232
- currency
233
- delayChange="blur"
234
- />
235
-
236
- <!-- Readonly display -->
237
- <InputNumber value={calculatedTotal} currency readonly />
238
-
239
- <!-- Allow negative numbers -->
240
- <InputNumber
241
- bind:value={profitLoss}
242
- currency
243
- allowNegative
244
- zeroDash
245
- />
246
-
247
- <!-- Width based on digit count -->
248
- <InputNumber
249
- bind:value={zipCode}
250
- fixedDecimals={0}
251
- widthNumbers={5}
252
- />
253
-
254
- <!-- With change handler -->
255
- <InputNumber
256
- bind:value={discount}
257
- percent
258
- onchange={(val) => {
259
- console.log('Discount changed to:', val);
260
- recalculateTotal();
261
- }}
262
- />
263
- ```
264
-
265
- **Common Mistakes:**
266
-
267
- - ❌ Using `<input type="number">` for currency: `<input type="number" step="0.01">`
268
- ✅ Correct: `<InputNumber currency bind:value={amount} />`
269
-
270
- - ❌ Storing percentages as whole numbers (8) instead of decimals (0.08)
271
- ✅ Correct: Store as decimal (0.08), use `percent` prop to display as 8%
272
-
273
- - ❌ Not using `bind:value`: `<InputNumber value={x} />`
274
- ✅ Correct: `<InputNumber bind:value={x} />` (for two-way binding)
275
-
276
- - ❌ Expecting immediate updates without considering `delayChange`
277
- ✅ Correct: Use `delayChange="blur"` or `delayChange={false}` for immediate updates
278
-
279
- - ❌ Using both `currency` and `percent` props together
280
- ✅ Correct: Use only one formatting option at a time
281
-
282
- **Props Combinations:**
283
-
284
- - **Currency:** `currency` (auto-adds $ prefix, 2 decimals)
285
- - **Percentage:** `percent` (auto-adds % suffix, multiplies display by 100)
286
- - **Integer:** `fixedDecimals={0}`
287
- - **Range validation:** `min={x} max={y}`
288
- - **Performance optimization:** `delayChange={true}` or `delayChange={500}` (ms) or `delayChange="blur"`
289
- - **Zero handling:** `zeroBlank` or `zeroDash`
290
- - **Null handling:** `nullBlank` or `nullDash`
291
-
292
- **Related Components:**
293
- - `InputNumberScroll` - Numeric input with scroll wheel adjustment support
294
- - `NumberFormat` - Display-only formatted number component
295
-
296
- **Storybook:** See `Components/InputNumber` stories
297
-
298
- ---
299
-
300
- ### Modal
301
-
302
- **Replaces:** Native `<dialog>` element or custom div overlays with manual JavaScript
303
- **Purpose:** Full-featured modal dialog with draggable header, keyboard shortcuts, and flexible content slots
304
- **When to Use:**
305
- - Confirmation dialogs (delete, save, cancel operations)
306
- - Forms that need to overlay the main content
307
- - Multi-step workflows in a focused view
308
- - Detail views that shouldn't navigate away from current page
309
- - Any overlay content that requires user interaction before proceeding
310
-
311
- **Key Props:**
312
-
313
- - `show: unknown` ($bindable) - Control visibility: value equal to `noShowValue` hides modal, any other value shows it
314
- - `noShowValue?: unknown` (default: false) - The value to compare against `show` to determine if modal should be hidden
315
- - `forceNoShow?: boolean` - Force modal to be hidden regardless of `show` value
316
- - `width?: string` (default: '40em') - Modal width (CSS value like '40em', '500px', '80%')
317
- - `cancelButton?: string | false` (default: 'Cancel') - Cancel button text, or `false` to hide
318
- - `okButton?: string | false` (default: 'OK') - OK button text, or `false` to hide
319
- - `okDisabled?: boolean` - Disable the OK button
320
- - `okColor?: TDefaultColorPalate | null` - Color theme for OK button
321
- - `okFAProps?: IFAProps` - FontAwesome icon props for OK button
322
- - `okType?: 'submit' | 'button'` (default: 'button') - Button type for form integration
323
- - `okActionNotOnEnter?: boolean` - Prevent Enter key from triggering OK action
324
- - `noCloseOnOK?: boolean` (default: true) - Keep modal open after OK click (useful for form validation)
325
- - `overflowY?: 'auto' | 'visible' | 'hidden'` (default: 'auto') - Body overflow behavior
326
- - `disable?: boolean` - Disable all interactions (shows activity overlay)
327
- - `marginForStickyHeader?: boolean` - Add margin to body for sticky header support
328
- - `okButtonWrap?: boolean` - Allow OK/Cancel button text to wrap
329
- - `borderFooter?: boolean` (default: true) - Show border above footer
330
- - `class?: string` - Additional CSS classes for dialog element
331
- - `color?: TDefaultColorPalate | null` - Overall color theme
332
- - `classHeader?: string` - CSS classes for header section
333
- - `classBody?: string` - CSS classes for body section
334
- - `classFooter?: string` - CSS classes for footer section
335
- - `classButton?: string` - CSS classes for OK button
336
- - `onOK?: () => void` - Callback when OK button clicked (synchronous)
337
- - `onOKPromise?: () => Promise<unknown>` - Async callback for OK button (awaits promise before closing)
338
- - `onCancel?: () => void` - Callback when Cancel button clicked or modal dismissed
339
- - `onClose?: () => void` - Callback when modal closes (any reason)
340
-
341
- **Snippets:**
342
- - `header?: Snippet` - Header content (displays in colored bar with close button)
343
- - `body?: Snippet` - Main body content
344
- - `leftFooter?: Snippet` - Content in footer left section
345
- - `centerFooter?: Snippet` - Content in footer center section
346
- - `rightFooter?: Snippet` - Content in footer right section
347
-
348
- **Special Features:**
349
- - **Draggable:** Click and drag the header to reposition the modal
350
- - **Keyboard shortcuts:** Enter key triggers OK, Escape key cancels
351
- - **Activity overlay:** Automatically disables interaction when `disable` is true
352
- - **Backdrop click:** Clicking outside modal closes it (triggers cancel action)
353
-
354
- **Usage Examples:**
355
-
356
- ```svelte
357
- <script>
358
- import { Modal } from 'intelliwaketssveltekitv25';
359
- let showConfirmDelete = $state(false);
360
- let showEditForm = $state(null); // null = hidden, object = shown with data
361
- let isProcessing = $state(false);
362
- </script>
363
-
364
- <!-- Simple confirmation dialog -->
365
- <Modal
366
- bind:show={showConfirmDelete}
367
- width="30em"
368
- okButton="Delete"
369
- cancelButton="Cancel"
370
- onOK={() => {
371
- performDelete();
372
- showConfirmDelete = false;
373
- }}
374
- >
375
- {#snippet header()}
376
- Confirm Deletion
377
- {/snippet}
378
- {#snippet body()}
379
- Are you sure you want to delete this item? This action cannot be undone.
380
- {/snippet}
381
- </Modal>
382
-
383
- <!-- Form in modal with validation -->
384
- <Modal
385
- bind:show={showEditForm}
386
- width="50em"
387
- okButton="Save Changes"
388
- okType="submit"
389
- noCloseOnOK={true}
390
- onOKPromise={async () => {
391
- // Validate and save
392
- const result = await saveForm(showEditForm);
393
- if (result.success) {
394
- showEditForm = null; // Close on success
395
- } else {
396
- // Stay open on validation failure
397
- throw new Error(result.error);
398
- }
399
- }}
400
- >
401
- {#snippet header()}
402
- Edit User Profile
403
- {/snippet}
404
- {#snippet body()}
405
- <form id="editForm">
406
- <!-- Form fields here -->
407
- <input type="text" name="name" value={showEditForm?.name} />
408
- <input type="email" name="email" value={showEditForm?.email} />
409
- </form>
410
- {/snippet}
411
- </Modal>
412
-
413
- <!-- Modal with custom footer content -->
414
- <Modal
415
- bind:show={showDetails}
416
- okButton={false}
417
- cancelButton="Close"
418
- >
419
- {#snippet header()}
420
- Item Details
421
- {/snippet}
422
- {#snippet body()}
423
- <p>Detailed information here...</p>
424
- {/snippet}
425
- {#snippet leftFooter()}
426
- <button type="button" onclick={() => printDetails()}>
427
- Print
428
- </button>
429
- {/snippet}
430
- {#snippet rightFooter()}
431
- <button type="button" onclick={() => exportDetails()}>
432
- Export
433
- </button>
434
- {/snippet}
435
- </Modal>
436
-
437
- <!-- Modal with activity overlay during async operation -->
438
- <Modal
439
- bind:show={showImport}
440
- disable={isProcessing}
441
- okButton="Import Data"
442
- onOKPromise={async () => {
443
- isProcessing = true;
444
- try {
445
- await importData();
446
- showImport = false;
447
- } finally {
448
- isProcessing = false;
449
- }
450
- }}
451
- >
452
- {#snippet header()}
453
- Import Data
454
- {#snippet}
455
- {#snippet body()}
456
- <input type="file" accept=".csv" />
457
- {/snippet}
458
- </Modal>
459
-
460
- <!-- Modal with custom width and no buttons -->
461
- <Modal
462
- bind:show={showPreview}
463
- width="90%"
464
- okButton={false}
465
- cancelButton={false}
466
- onClose={() => {
467
- // Cleanup when modal closes
468
- }}
469
- >
470
- {#snippet header()}
471
- Preview
472
- {/snippet}
473
- {#snippet body()}
474
- <img src={previewUrl} alt="Preview" />
475
- {/snippet}
476
- </Modal>
477
-
478
- <!-- Using noShowValue for object-based visibility -->
479
- <Modal
480
- bind:show={selectedUser}
481
- noShowValue={null}
482
- okButton="Save"
483
- >
484
- {#snippet header()}
485
- Edit {selectedUser?.name}
486
- {/snippet}
487
- {#snippet body()}
488
- <!-- Edit form -->
489
- {/snippet}
490
- </Modal>
491
- <!-- To show: selectedUser = {name: 'John', ...} -->
492
- <!-- To hide: selectedUser = null -->
493
- ```
494
-
495
- **Common Mistakes:**
496
-
497
- - ❌ Not binding `show` prop: `<Modal show={x}>`
498
- ✅ Correct: `<Modal bind:show={x}>` (for two-way binding)
499
-
500
- - ❌ Unclear `noShowValue` usage: `show={item}` with `noShowValue={null}` but forgetting to set `item = null` to close
501
- ✅ Correct: Always set `show = noShowValue` to close the modal
502
-
503
- - ❌ Using `noCloseOnOK={false}` with `onOKPromise` without handling errors
504
- ✅ Correct: Use `noCloseOnOK={true}` and manually close in promise, or handle all errors
505
-
506
- - ❌ Forgetting to prevent Enter key when using forms: Modal submits unexpectedly
507
- ✅ Correct: Use `okActionNotOnEnter={true}` or `okType="submit"` with proper form handling
508
-
509
- - ❌ Not using `onOKPromise` for async operations, causing modal to close immediately
510
- ✅ Correct: Use `onOKPromise` for async operations, not `onOK`
511
-
512
- **Related Components:**
513
- - `ModalFormAction` - Specialized modal for SvelteKit form actions
514
- - `ModalPromptControl` - Modal with prompt/confirmation patterns
515
- - `ActivityOverlay` - Loading overlay (used internally by Modal)
516
-
517
- **Storybook:** See `Components/Modal` stories
518
-
519
- ---
520
-
521
- ### DropDown
522
-
523
- **Replaces:** `<select>` elements and custom dropdown menus
524
- **Purpose:** Rich dropdown menu with keyboard navigation, icons, search, and action handling
525
- **When to Use:**
526
- - Action menus (context menus, toolbar dropdowns)
527
- - Navigation dropdowns with links
528
- - Replacing `<select>` when you need icons, dividers, or complex items
529
- - Any menu that needs better UX than native `<select>`
530
-
531
- **Key Props:**
532
-
533
- - `show?: boolean` ($bindable) - Control dropdown open/closed state
534
- - `position?: TDropDownControlPosition` (default: null) - Menu position relative to button
535
- - `ddActions?: IDDAction[]` (default: []) - Array of menu items/actions (see IDDAction interface below)
536
- - `noCaret?: boolean` - Hide the dropdown arrow icon
537
- - `buttonTitle?: string | null` - Button text (if not using `button` snippet)
538
- - `buttonClass?: string` - CSS classes for the button
539
- - `controlClass?: string` - CSS classes for the dropdown wrapper
540
- - `toggleClass?: string` - CSS classes for the toggle container
541
- - `inputControl?: boolean` - Style button as input control
542
- - `fullBlock?: boolean` - Make button full width
543
- - `bodyClass?: string` - CSS classes for dropdown body/menu
544
- - `sameSize?: boolean` - Make dropdown menu same width as button
545
- - `zIndex?: number` (default: 40) - Z-index for dropdown positioning
546
- - `disabled?: boolean` - Disable the dropdown
547
- - `hidden?: boolean` - Hide the dropdown
548
- - `hideEmptyDDActions?: boolean` - Auto-hide if no actions provided
549
- - `verbose?: boolean` - Enable console logging for debugging
550
- - `dataColor?: TDefaultColorPalate` - Color theme for button
551
- - `clientWidth?: number` ($bindable) - Width of the button element
552
-
553
- **Snippets:**
554
- - `button?: Snippet` - Custom button content (overrides `buttonTitle`)
555
- - `actions?: Snippet` - Custom menu content (in addition to or instead of `ddActions`)
556
-
557
- **IDDAction Interface** (menu items):
558
-
559
- ```typescript
560
- interface IDDAction {
561
- title?: string // Display text
562
- key?: string | number // Unique key for item
563
- divider?: boolean // Render as divider line
564
- header?: boolean // Render as header text (bold, no click)
565
- dividerGroup?: string // Auto-add divider when group changes
566
- headerGroup?: string // Auto-add header when group changes
567
- active?: boolean // Highlight as active/selected
568
- disabled?: boolean // Disable interaction
569
- hidden?: boolean // Hide from menu
570
- indented?: boolean // Indent item (for hierarchy)
571
-
572
- // Actions
573
- action?: () => void // Click handler
574
- href?: string // Navigation URL
575
- hrefReplace?: boolean // Use replaceState navigation
576
- hrefDownload?: string // Download URL
577
- hrefDownloadFilename?: string // Filename for download
578
-
579
- // Visual
580
- faProps?: IFAProps // FontAwesome icon
581
- imageHref?: string // Image URL for icon
582
-
583
- // Alternate action (right side button)
584
- alternateAction?: () => void // Right-side button action
585
- alternateTitle?: string // Right-side button text
586
- alternateFAProps?: IFAProps // Right-side button icon
587
- alternateNoClose?: boolean // Keep menu open after alternate action
588
-
589
- // Behavior
590
- noCloseMenu?: boolean // Keep menu open after action
591
- }
592
- ```
593
-
594
- **Keyboard Navigation:**
595
- - **Arrow Down:** Open menu / Move to next item
596
- - **Arrow Up:** Move to previous item
597
- - **Enter:** Execute selected item action
598
- - **Tab:** Close menu
599
- - **Type letter:** Jump to first item starting with that letter
600
-
601
- **Usage Examples:**
602
-
603
- ```svelte
604
- <script>
605
- import { DropDown } from 'intelliwaketssveltekitv25';
606
- import { faEdit, faTrash, faCopy } from '@fortawesome/free-solid-svg-icons';
607
-
608
- let showMenu = $state(false);
609
- let selectedOption = $state('option1');
610
-
611
- const actions = [
612
- {
613
- title: 'Edit',
614
- faProps: { icon: faEdit },
615
- action: () => editItem()
616
- },
617
- {
618
- title: 'Duplicate',
619
- faProps: { icon: faCopy },
620
- action: () => duplicateItem()
621
- },
622
- { divider: true },
623
- {
624
- title: 'Delete',
625
- faProps: { icon: faTrash },
626
- action: () => deleteItem()
627
- }
628
- ];
629
- </script>
630
-
631
- <!-- Simple action menu -->
632
- <DropDown
633
- bind:show={showMenu}
634
- buttonTitle="Actions"
635
- ddActions={actions}
636
- />
637
-
638
- <!-- As select replacement with active indicator -->
639
- <DropDown
640
- bind:show={showOptions}
641
- buttonTitle={selectedOption}
642
- ddActions={[
643
- {
644
- title: 'Option 1',
645
- active: selectedOption === 'option1',
646
- action: () => selectedOption = 'option1'
647
- },
648
- {
649
- title: 'Option 2',
650
- active: selectedOption === 'option2',
651
- action: () => selectedOption = 'option2'
652
- },
653
- {
654
- title: 'Option 3',
655
- active: selectedOption === 'option3',
656
- action: () => selectedOption = 'option3'
657
- }
658
- ]}
659
- inputControl
660
- />
661
-
662
- <!-- With navigation links -->
663
- <DropDown
664
- buttonTitle="Navigate"
665
- ddActions={[
666
- { title: 'Dashboard', href: '/dashboard' },
667
- { title: 'Settings', href: '/settings' },
668
- { divider: true },
669
- { title: 'Logout', href: '/logout', hrefReplace: true }
670
- ]}
671
- />
672
-
673
- <!-- With grouped items -->
674
- <DropDown
675
- buttonTitle="Options"
676
- ddActions={[
677
- { title: 'File Operations', header: true },
678
- { title: 'Open', action: () => open() },
679
- { title: 'Save', action: () => save() },
680
- { divider: true },
681
- { title: 'Edit Operations', header: true },
682
- { title: 'Cut', action: () => cut() },
683
- { title: 'Copy', action: () => copy() },
684
- { title: 'Paste', action: () => paste() }
685
- ]}
686
- />
687
-
688
- <!-- With auto-grouping by headerGroup -->
689
- <DropDown
690
- buttonTitle="Grouped"
691
- ddActions={[
692
- { title: 'Item 1', headerGroup: 'Group A', action: () => {} },
693
- { title: 'Item 2', headerGroup: 'Group A', action: () => {} },
694
- { title: 'Item 3', headerGroup: 'Group B', action: () => {} },
695
- { title: 'Item 4', headerGroup: 'Group B', action: () => {} }
696
- ]}
697
- />
698
- <!-- Automatically adds headers "Group A" and "Group B" -->
699
-
700
- <!-- Custom button content -->
701
- <DropDown bind:show={showCustom} ddActions={actions}>
702
- {#snippet button()}
703
- <Icon icon={faEllipsisV} />
704
- More Options
705
- {/snippet}
706
- </DropDown>
707
-
708
- <!-- Full width dropdown -->
709
- <DropDown
710
- buttonTitle="Select Option"
711
- ddActions={options}
712
- fullBlock
713
- sameSize
714
- inputControl
715
- />
716
-
717
- <!-- With disabled items -->
718
- <DropDown
719
- buttonTitle="Actions"
720
- ddActions={[
721
- { title: 'Available Action', action: () => {} },
722
- { title: 'Coming Soon', disabled: true },
723
- { title: 'Premium Only', disabled: true }
724
- ]}
725
- />
726
-
727
- <!-- With alternate actions (two buttons per row) -->
728
- <DropDown
729
- buttonTitle="Files"
730
- ddActions={[
731
- {
732
- title: 'document.pdf',
733
- action: () => openFile('document.pdf'),
734
- alternateAction: () => downloadFile('document.pdf'),
735
- alternateFAProps: { icon: faDownload }
736
- }
737
- ]}
738
- />
739
-
740
- <!-- Download action -->
741
- <DropDown
742
- buttonTitle="Export"
743
- ddActions={[
744
- {
745
- title: 'Export as CSV',
746
- hrefDownload: '/api/export?format=csv',
747
- hrefDownloadFilename: 'data.csv'
748
- },
749
- {
750
- title: 'Export as PDF',
751
- hrefDownload: '/api/export?format=pdf',
752
- hrefDownloadFilename: 'data.pdf'
753
- }
754
- ]}
755
- />
756
- ```
757
-
758
- **Common Mistakes:**
759
-
760
- - ❌ Not providing `action`, `href`, or `hrefDownload` for menu items
761
- ✅ Correct: Every menu item (except dividers/headers) needs an action
762
-
763
- - ❌ Using DropDown when MultiSelect is more appropriate
764
- ✅ Correct: Use `MultiSelect` for selecting multiple options, `DropDown` for single actions/selections
765
-
766
- - ❌ Forgetting to handle menu close in custom `noCloseMenu` actions
767
- ✅ Correct: Manually set `show = false` when using `noCloseMenu: true`
768
-
769
- - ❌ Not using `bind:show` for controlled dropdowns
770
- ✅ Correct: `<DropDown bind:show={showMenu}>` to control open/close state
771
-
772
- - ❌ Using complex objects as `key` without providing unique string/number keys
773
- ✅ Correct: Always provide `key` prop for array items
774
-
775
- **Related Components:**
776
- - `DropDownControl` - Lower-level dropdown control (used internally by DropDown)
777
- - `MultiSelect` - For selecting multiple options from a list
778
- - `Importer` - Specialized dropdown for file imports
779
-
780
- **Storybook:** See `Components/DropDown` stories
781
-
782
- ---
783
-
784
- ### ArrayTable
785
-
786
- **Replaces:** Manual `<table>` implementations with sorting, formatting, and event handling
787
- **Purpose:** Type-safe, sortable data table with automatic formatting, custom cell rendering, and row/column interactions
788
- **When to Use:**
789
- - Displaying arrays of data objects
790
- - Sortable tables with column headers
791
- - Tables with computed values or custom formatting
792
- - Data grids with row click actions
793
- - Reports and dashboards with tabular data
794
-
795
- **Key Props:**
796
-
797
- - `arrayData: T[] | null` - Array of data objects (generic type T)
798
- - `arrayStructure: IArrayStructure<T>` - Column definitions and table configuration (see interface below)
799
- - `bordered?: boolean` - Add borders to table cells
800
- - `scrollable?: boolean` - Make table sticky-header scrollable
801
- - `class?: string` - Additional CSS classes for table element
802
- - `minWidth?: string` - Minimum table width (CSS value)
803
- - `hideCosts?: boolean` - Hide columns marked as costs
804
- - `tableRef?: HTMLTableElement` ($bindable) - Reference to the table DOM element
805
-
806
- **TypeScript:** Uses generics `<T extends Record<string, any>>` for type safety
807
-
808
- **IArrayStructure Interface:**
809
-
810
- ```typescript
811
- interface IArrayStructure<T> {
812
- columns: IArrayColumn<T>[] // Column definitions
813
- sortable?: boolean // Enable column header sorting
814
- defaultSortColumn?: keyof T // Initial sort column
815
- defaultSortAscending?: boolean // Initial sort direction
816
- minColSize?: string // Minimum column size class
817
- emptyMessage?: string | false // Message when no data (default: "No data available")
818
- rowClick?: (row: T) => void // Row click handler
819
- }
820
-
821
- interface IArrayColumn<T> {
822
- fieldName: keyof T // Data field name
823
- title?: string // Column header (auto-generated from fieldName if not provided)
824
- hidden?: boolean // Hide column
825
- doNotSort?: boolean // Disable sorting for this column
826
- isACost?: boolean // Mark as cost (hideable via hideCosts prop)
827
- size?: string // Column size class (td-sm, td-md, td-lg, etc.)
828
-
829
- // Formatting
830
- type?: 'currency' | 'percent' | 'date' | 'datetime' | 'boolean' | 'number'
831
- decimals?: number // Decimal places for numbers
832
- align?: 'left' | 'center' | 'right' // Text alignment (auto-detects for currency/numbers)
833
-
834
- // Custom rendering
835
- compute?: (value: any, row: T) => any // Transform value before display
836
- format?: (value: any, row: T) => string // Custom display formatting
837
- onclick?: (row: T, event: MouseEvent) => void // Cell click handler
838
-
839
- // Footer
840
- sum?: boolean // Show sum in footer
841
- average?: boolean // Show average in footer
842
- count?: boolean // Show count in footer
843
- }
844
- ```
845
-
846
- **Features:**
847
- - **Auto-formatting:** Currency, percentages, dates automatically formatted based on `type`
848
- - **Sorting:** Click column headers to sort (ascending/descending toggle)
849
- - **Type-safe:** TypeScript generic ensures column field names match data object keys
850
- - **Computed values:** Transform data before display with `compute` function
851
- - **Footer totals:** Automatic sums, averages, and counts
852
- - **Empty state:** Customizable message when no data
853
-
854
- **Usage Examples:**
855
-
856
- ```svelte
857
- <script lang="ts">
858
- import { ArrayTable } from 'intelliwaketssveltekitv25';
859
-
860
- interface User {
861
- id: number;
862
- name: string;
863
- email: string;
864
- role: string;
865
- salary: number;
866
- active: boolean;
867
- }
868
-
869
- let users: User[] = $state([
870
- { id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin', salary: 75000, active: true },
871
- { id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User', salary: 60000, active: true },
872
- { id: 3, name: 'Bob Johnson', email: 'bob@example.com', role: 'User', salary: 55000, active: false }
873
- ]);
874
-
875
- const userTableStructure: IArrayStructure<User> = {
876
- columns: [
877
- { fieldName: 'id', title: 'ID', size: 'sm' },
878
- { fieldName: 'name', title: 'Name' },
879
- { fieldName: 'email', title: 'Email' },
880
- { fieldName: 'role', title: 'Role' },
881
- {
882
- fieldName: 'salary',
883
- title: 'Salary',
884
- type: 'currency',
885
- sum: true
886
- },
887
- {
888
- fieldName: 'active',
889
- title: 'Status',
890
- compute: (val) => val ? 'Active' : 'Inactive'
891
- }
892
- ],
893
- sortable: true,
894
- defaultSortColumn: 'name',
895
- defaultSortAscending: true,
896
- rowClick: (user) => {
897
- console.log('Clicked user:', user.name);
898
- // Navigate or open modal
899
- }
900
- };
901
- </script>
902
-
903
- <ArrayTable
904
- arrayData={users}
905
- arrayStructure={userTableStructure}
906
- bordered
907
- />
908
-
909
- <!-- Simple table without row click -->
910
- <ArrayTable
911
- arrayData={products}
912
- arrayStructure={{
913
- columns: [
914
- { fieldName: 'name', title: 'Product' },
915
- { fieldName: 'price', type: 'currency' },
916
- { fieldName: 'stock', title: 'In Stock' }
917
- ],
918
- sortable: true
919
- }}
920
- />
921
-
922
- <!-- With custom formatting and computed columns -->
923
- <script>
924
- interface Sale {
925
- date: string;
926
- amount: number;
927
- taxRate: number;
928
- }
929
-
930
- const salesStructure: IArrayStructure<Sale> = {
931
- columns: [
932
- {
933
- fieldName: 'date',
934
- title: 'Date',
935
- type: 'date'
936
- },
937
- {
938
- fieldName: 'amount',
939
- title: 'Subtotal',
940
- type: 'currency'
941
- },
942
- {
943
- fieldName: 'taxRate',
944
- title: 'Tax Rate',
945
- type: 'percent'
946
- },
947
- {
948
- fieldName: 'amount', // Reuse field for computed column
949
- title: 'Tax Amount',
950
- type: 'currency',
951
- compute: (amount, row) => amount * row.taxRate
952
- },
953
- {
954
- fieldName: 'amount',
955
- title: 'Total',
956
- type: 'currency',
957
- compute: (amount, row) => amount * (1 + row.taxRate),
958
- sum: true // Show total in footer
959
- }
960
- ],
961
- sortable: true
962
- };
963
- </script>
964
-
965
- <ArrayTable
966
- arrayData={sales}
967
- arrayStructure={salesStructure}
968
- />
969
-
970
- <!-- Empty state -->
971
- <ArrayTable
972
- arrayData={[]}
973
- arrayStructure={{
974
- columns: [
975
- { fieldName: 'name' },
976
- { fieldName: 'value' }
977
- ],
978
- emptyMessage: 'No items found. Add your first item to get started.'
979
- }}
980
- />
981
-
982
- <!-- Scrollable table with sticky header -->
983
- <ArrayTable
984
- arrayData={largeDataset}
985
- arrayStructure={structureDef}
986
- scrollable
987
- class="max-h-96"
988
- />
989
-
990
- <!-- With cell click handlers -->
991
- <script>
992
- const tableStructure: IArrayStructure<Item> = {
993
- columns: [
994
- { fieldName: 'name' },
995
- {
996
- fieldName: 'status',
997
- onclick: (row, event) => {
998
- event.stopPropagation(); // Prevent row click
999
- toggleStatus(row);
1000
- }
1001
- }
1002
- ],
1003
- rowClick: (row) => viewDetails(row)
1004
- };
1005
- </script>
1006
-
1007
- <!-- Hide cost columns conditionally -->
1008
- <ArrayTable
1009
- arrayData={budgetItems}
1010
- arrayStructure={{
1011
- columns: [
1012
- { fieldName: 'description' },
1013
- { fieldName: 'quantity' },
1014
- { fieldName: 'unitCost', type: 'currency', isACost: true },
1015
- { fieldName: 'totalCost', type: 'currency', isACost: true, sum: true }
1016
- ]
1017
- }}
1018
- hideCosts={!showCosts}
1019
- />
1020
- ```
1021
-
1022
- **Common Mistakes:**
1023
-
1024
- - ❌ Not providing generic type: `arrayStructure: IArrayStructure`
1025
- ✅ Correct: `arrayStructure: IArrayStructure<User>` (provides type safety)
1026
-
1027
- - ❌ Using wrong field names in column definitions (no TypeScript error if not using generics)
1028
- ✅ Correct: Use TypeScript generics to catch field name typos at compile time
1029
-
1030
- - ❌ Forgetting to set `sum: true` or `average: true` for footer totals
1031
- ✅ Correct: Add `sum: true` to columns where you want footer totals
1032
-
1033
- - ❌ Not handling `null` or `undefined` in `compute` functions
1034
- ✅ Correct: Add null checks in compute functions: `compute: (val) => val ?? 'N/A'`
1035
-
1036
- - ❌ Using `rowClick` and cell `onclick` without `stopPropagation`
1037
- ✅ Correct: Cell onclick handlers should call `event.stopPropagation()` to prevent row click
1038
-
1039
- **Related Components:**
1040
- - `VirtualTable` - For very large datasets (10,000+ rows) with virtual scrolling
1041
- - `ArrayFunctions` - Utility functions for array/table operations (imported automatically)
1042
-
1043
- **Storybook:** See `Components/ArrayTable` stories
1044
-
1045
- ---
1046
-
1047
- ### TextArea
1048
-
1049
- **Replaces:** Native `<textarea>` elements
1050
- **Purpose:** Auto-resizing textarea with automatic height adjustment and readonly display mode
1051
- **When to Use:**
1052
- - Multi-line text input (comments, descriptions, notes)
1053
- - Forms requiring paragraph-length text entry
1054
- - Any textarea that should grow/shrink with content
1055
- - Readonly text display that preserves formatting
1056
-
1057
- **Key Props:**
1058
-
1059
- - `value: string | null` ($bindable) - Current text value, use `bind:value` for two-way binding
1060
- - `readonly?: boolean` - Display as readonly (renders as DisplayHTML instead of textarea)
1061
- - `propagateEnter?: boolean` (default: false) - Allow Enter key to propagate (useful in forms)
1062
- - `use?: ActionArray` - Svelte actions array
1063
- - Standard HTML textarea attributes: `placeholder`, `disabled`, `required`, `maxlength`, `rows`, `cols`, `name`, `class`, etc.
1064
-
1065
- **Features:**
1066
- - **Auto-grow**: Automatically adjusts height to fit content using `autoGrow` action
1067
- - **Readonly mode**: Displays as HTML when readonly (preserves formatting, line breaks)
1068
- - **Enter key control**: Prevents Enter key propagation by default (prevents form submission)
1069
- - **Full textarea API**: Supports all standard HTML textarea attributes
1070
-
1071
- **Usage Examples:**
1072
-
1073
- ```svelte
1074
- <script>
1075
- import { TextArea } from 'intelliwaketssveltekitv25';
1076
- let comment = $state('');
1077
- let description = $state('Product description here...');
1078
- </script>
1079
-
1080
- <!-- Basic auto-resizing textarea -->
1081
- <label>
1082
- Comment:
1083
- <TextArea bind:value={comment} placeholder="Enter your comment..." />
1084
- </label>
1085
-
1086
- <!-- With max length -->
1087
- <TextArea
1088
- bind:value={description}
1089
- maxlength={500}
1090
- placeholder="Describe the product..."
1091
- required
1092
- />
1093
-
1094
- <!-- Readonly display -->
1095
- <TextArea value={savedComment} readonly />
1096
-
1097
- <!-- With Enter key propagation (for inline editing) -->
1098
- <TextArea
1099
- bind:value={note}
1100
- propagateEnter={true}
1101
- placeholder="Press Enter to submit"
1102
- />
1103
-
1104
- <!-- In a form -->
1105
- <form method="POST">
1106
- <TextArea
1107
- name="feedback"
1108
- bind:value={feedback}
1109
- placeholder="Your feedback..."
1110
- required
1111
- />
1112
- <button type="submit">Submit</button>
1113
- </form>
1114
-
1115
- <!-- With custom styling -->
1116
- <TextArea
1117
- bind:value={text}
1118
- class="border-2 border-blue-500 rounded-lg p-4"
1119
- placeholder="Styled textarea..."
1120
- />
1121
-
1122
- <!-- Disabled state -->
1123
- <TextArea value={existingText} disabled />
1124
-
1125
- <!-- With rows (initial height) -->
1126
- <TextArea
1127
- bind:value={longText}
1128
- rows={10}
1129
- placeholder="Start with 10 rows..."
1130
- />
1131
- ```
1132
-
1133
- **Common Mistakes:**
1134
-
1135
- - ❌ Using native `<textarea>` without auto-grow: `<textarea bind:value={x}>`
1136
- ✅ Correct: `<TextArea bind:value={x} />` (auto-grows automatically)
1137
-
1138
- - ❌ Not using `bind:value`: `<TextArea value={x} />`
1139
- ✅ Correct: `<TextArea bind:value={x} />` (for two-way binding)
1140
-
1141
- - ❌ Expecting readonly to show a textarea: `<TextArea value={x} readonly />`
1142
- ✅ Note: readonly mode displays as formatted HTML, not a textarea
1143
-
1144
- - ❌ Form submitting on Enter key when you don't want it to
1145
- ✅ Correct: Default behavior prevents Enter propagation; use `propagateEnter={true}` if you want form submission on Enter
1146
-
1147
- **Props Details:**
1148
-
1149
- - **Auto-grow behavior**: Height automatically adjusts as you type, no scrolling needed
1150
- - **Readonly rendering**: Uses `DisplayHTML` component to show formatted text with line breaks preserved
1151
- - **Enter key**: By default, Enter key is stopped from propagating to prevent accidental form submissions
1152
-
1153
- **Related Components:**
1154
- - `DisplayHTML` - Used internally for readonly display
1155
- - `InputNumber` - For single-line numeric inputs
1156
- - `MultiSelect` - For selecting from predefined options
1157
-
1158
- **Storybook:** See `Components/TextArea` stories
1159
-
1160
- ---
1161
-
1162
- ### MultiSelect
1163
-
1164
- **Replaces:** Multiple `<select multiple>` and custom multi-select implementations
1165
- **Purpose:** Type-safe, searchable multi-select dropdown with dynamic item creation and keyboard navigation
1166
- **When to Use:**
1167
- - Selecting multiple items from a list (tags, categories, assignees)
1168
- - Searchable selection with many options
1169
- - Dynamic item creation (creating new tags on the fly)
1170
- - Single-select with search (set `isMulti={false}`)
1171
- - Type-safe selections with TypeScript generics
1172
-
1173
- **Key Props:**
1174
-
1175
- - `possibles: T[]` - Array of available items to select from (required)
1176
- - `selected?: T[]` ($bindable) - Currently selected items array
1177
- - `selectedIDs?: (number | string)[]` ($bindable) - Selected item IDs (alternative to selected)
1178
- - `created?: T[]` ($bindable) - Items that were created (not in possibles)
1179
- - `existing?: T[]` ($bindable) - Items that exist in possibles
1180
- - `isMulti?: boolean` (default: true) - Allow multiple selections or single select
1181
- - `allowClearAll?: boolean` (default: true) - Show clear all button
1182
- - `create?: (value: string) => T | null` - Function to create new items from search text
1183
- - `createValid?: (value: string) => boolean | string` - Validate new item creation (return string for error message)
1184
- - `createPrefix?: string` (default: 'Create:') - Prefix text for create option
1185
- - `displayValue?: (item: T) => string | number` - How to display items (default: item.name or item.id)
1186
- - `idValue?: (item: T) => any` - How to get unique ID from items (default: item.id)
1187
- - `keyValue?: (item: T) => any` - Key for Svelte each blocks (default: same as idValue)
1188
- - `inputValue?: (item: T) => any` - Value for hidden form inputs (default: same as idValue)
1189
- - `headerValue?: (item: T) => string | null` - Extract header/category from items for grouping
1190
- - `show?: boolean` ($bindable) - Control dropdown open/closed state
1191
- - `placeholder?: string` - Input placeholder text
1192
- - `disabled?: boolean` - Disable all interactions
1193
- - `readonly?: boolean` - Display only, no interaction
1194
- - `required?: boolean` - Mark as required field
1195
- - `invalid?: boolean` - Show invalid state
1196
- - `autoFocus?: boolean` - Auto-focus input on mount
1197
- - `name?: string` - Form field name (creates hidden inputs for each selected item)
1198
- - `form?: string` - Associate with form by ID
1199
- - Callback props: `onadd`, `onselect`, `oncreate`, `onchange`, `onclear`, `onclearall`
1200
-
1201
- **TypeScript:** Uses generics `<T extends TGenericMultiSelect>` for type safety
1202
-
1203
- **TGenericMultiSelect Interface:**
1204
- ```typescript
1205
- interface TGenericMultiSelect {
1206
- id?: string | number;
1207
- name?: string;
1208
- header?: string; // For grouping
1209
- [key: string]: any; // Additional properties
1210
- }
1211
- ```
1212
-
1213
- **Keyboard Navigation:**
1214
- - **Arrow Down/Up**: Navigate dropdown options
1215
- - **Enter**: Select highlighted option or create new item
1216
- - **Backspace**: Remove last selected item (when search is empty)
1217
- - **Type**: Filter options by search
1218
-
1219
- **Usage Examples:**
1220
-
1221
- ```svelte
1222
- <script lang="ts">
1223
- import { MultiSelect } from 'intelliwaketssveltekitv25';
1224
-
1225
- interface Tag {
1226
- id: number;
1227
- name: string;
1228
- }
1229
-
1230
- const availableTags: Tag[] = [
1231
- { id: 1, name: 'JavaScript' },
1232
- { id: 2, name: 'TypeScript' },
1233
- { id: 3, name: 'Svelte' }
1234
- ];
1235
-
1236
- let selectedTags = $state<Tag[]>([]);
1237
- </script>
1238
-
1239
- <!-- Basic multi-select -->
1240
- <MultiSelect
1241
- possibles={availableTags}
1242
- bind:selected={selectedTags}
1243
- placeholder="Select tags..."
1244
- />
1245
-
1246
- <!-- With dynamic item creation -->
1247
- <MultiSelect
1248
- possibles={availableTags}
1249
- bind:selected={selectedTags}
1250
- placeholder="Select or create tags..."
1251
- create={(name) => ({
1252
- id: Date.now(),
1253
- name: name
1254
- })}
1255
- />
1256
-
1257
- <!-- With creation validation -->
1258
- <MultiSelect
1259
- possibles={availableTags}
1260
- bind:selected={selectedTags}
1261
- create={(name) => ({ id: Date.now(), name })}
1262
- createValid={(name) => {
1263
- if (name.length < 3) return 'Tag must be at least 3 characters';
1264
- if (availableTags.some(t => t.name.toLowerCase() === name.toLowerCase())) {
1265
- return 'Tag already exists';
1266
- }
1267
- return true;
1268
- }}
1269
- />
1270
-
1271
- <!-- Single select mode -->
1272
- <MultiSelect
1273
- possibles={availableTags}
1274
- bind:selected={selectedTags}
1275
- isMulti={false}
1276
- placeholder="Select one..."
1277
- />
1278
-
1279
- <!-- With selected IDs binding -->
1280
- <script>
1281
- let selectedTagIDs = $state<number[]>([1, 3]);
1282
- </script>
1283
-
1284
- <MultiSelect
1285
- possibles={availableTags}
1286
- bind:selectedIDs={selectedTagIDs}
1287
- placeholder="Select tags..."
1288
- />
1289
-
1290
- <!-- With custom display function -->
1291
- <script>
1292
- interface User {
1293
- id: number;
1294
- firstName: string;
1295
- lastName: string;
1296
- email: string;
1297
- }
1298
-
1299
- const users: User[] = [
1300
- { id: 1, firstName: 'John', lastName: 'Doe', email: 'john@example.com' },
1301
- { id: 2, firstName: 'Jane', lastName: 'Smith', email: 'jane@example.com' }
1302
- ];
1303
-
1304
- let assignees = $state<User[]>([]);
1305
- </script>
1306
-
1307
- <MultiSelect
1308
- possibles={users}
1309
- bind:selected={assignees}
1310
- displayValue={(user) => `${user.firstName} ${user.lastName}`}
1311
- placeholder="Assign to..."
1312
- />
1313
-
1314
- <!-- With grouping/headers -->
1315
- <script>
1316
- interface Item {
1317
- id: number;
1318
- name: string;
1319
- category: string;
1320
- }
1321
-
1322
- const items: Item[] = [
1323
- { id: 1, name: 'Apple', category: 'Fruits' },
1324
- { id: 2, name: 'Banana', category: 'Fruits' },
1325
- { id: 3, name: 'Carrot', category: 'Vegetables' },
1326
- { id: 4, name: 'Lettuce', category: 'Vegetables' }
1327
- ];
1328
- </script>
1329
-
1330
- <MultiSelect
1331
- possibles={items}
1332
- bind:selected={selectedItems}
1333
- headerValue={(item) => item.category}
1334
- placeholder="Select items..."
1335
- />
1336
-
1337
- <!-- In a form -->
1338
- <form method="POST">
1339
- <MultiSelect
1340
- name="tags"
1341
- possibles={availableTags}
1342
- bind:selected={selectedTags}
1343
- required
1344
- placeholder="Select at least one tag..."
1345
- />
1346
- <button type="submit">Submit</button>
1347
- </form>
1348
-
1349
- <!-- With callbacks -->
1350
- <MultiSelect
1351
- possibles={availableTags}
1352
- bind:selected={selectedTags}
1353
- onadd={(id) => console.log('Added:', id)}
1354
- onselect={(id) => console.log('Selected existing:', id)}
1355
- oncreate={(id) => console.log('Created new:', id)}
1356
- onchange={(items) => console.log('Selection changed:', items)}
1357
- onclear={(id) => console.log('Removed:', id)}
1358
- onclearall={() => console.log('Cleared all')}
1359
- />
1360
-
1361
- <!-- Readonly/disabled -->
1362
- <MultiSelect
1363
- possibles={availableTags}
1364
- selected={[availableTags[0], availableTags[2]]}
1365
- readonly
1366
- />
1367
-
1368
- <MultiSelect
1369
- possibles={availableTags}
1370
- bind:selected={selectedTags}
1371
- disabled
1372
- />
1373
-
1374
- <!-- Without clear all button -->
1375
- <MultiSelect
1376
- possibles={availableTags}
1377
- bind:selected={selectedTags}
1378
- allowClearAll={false}
1379
- />
1380
- ```
1381
-
1382
- **Common Mistakes:**
1383
-
1384
- - ❌ Not providing `possibles` array: `<MultiSelect bind:selected={x} />`
1385
- ✅ Correct: `<MultiSelect possibles={items} bind:selected={x} />`
1386
-
1387
- - ❌ Binding to non-array for multi-select: `bind:selected={singleItem}`
1388
- ✅ Correct: `bind:selected={arrayOfItems}` (always an array, even for single select)
1389
-
1390
- - ❌ Not using TypeScript generics: `possibles: any[]`
1391
- ✅ Correct: `possibles: Tag[]` with `interface Tag extends TGenericMultiSelect`
1392
-
1393
- - ❌ Forgetting id or name in data objects: `possibles={[{label: 'Item'}]}`
1394
- ✅ Correct: `possibles={[{id: 1, name: 'Item'}]}` or provide custom `idValue` and `displayValue` functions
1395
-
1396
- - ❌ Using create without validation when it can fail
1397
- ✅ Correct: Use `createValid` to validate and show error messages
1398
-
1399
- - ❌ Not handling created vs existing items separately
1400
- ✅ Correct: Use `bind:created` and `bind:existing` to differentiate
1401
-
1402
- **Advanced Features:**
1403
-
1404
- **1. Dynamic Item Creation:**
1405
- ```svelte
1406
- <MultiSelect
1407
- possibles={tags}
1408
- bind:selected={selectedTags}
1409
- bind:created={newlyCreatedTags}
1410
- bind:existing={existingSelectedTags}
1411
- create={(name) => ({ id: Date.now(), name })}
1412
- createPrefix="Add new:"
1413
- oncreate={(id) => {
1414
- // Save new tag to backend
1415
- saveNewTag(id);
1416
- }}
1417
- />
1418
- ```
1419
-
1420
- **2. Custom Value Functions:**
1421
- ```svelte
1422
- <script>
1423
- interface ComplexItem {
1424
- uuid: string;
1425
- displayName: string;
1426
- sortOrder: number;
1427
- }
1428
- </script>
1429
-
1430
- <MultiSelect
1431
- possibles={complexItems}
1432
- bind:selected={selectedItems}
1433
- idValue={(item) => item.uuid}
1434
- displayValue={(item) => item.displayName}
1435
- keyValue={(item) => item.uuid}
1436
- inputValue={(item) => item.uuid}
1437
- />
1438
- ```
1439
-
1440
- **3. Grouped Options:**
1441
- ```svelte
1442
- <MultiSelect
1443
- possibles={groupedItems}
1444
- bind:selected={selectedItems}
1445
- headerValue={(item) => item.category}
1446
- />
1447
- <!-- Automatically adds category headers when category changes -->
1448
- ```
1449
-
1450
- **Related Components:**
1451
- - `DropDown` - For single action/selection without search
1452
- - `DropDownControl` - Lower-level dropdown control (used internally)
1453
- - `DisplayHTML` - Used to render item text
1454
-
1455
- **Storybook:** See `Components/MultiSelect` stories
1456
-
1457
- ---
1458
-
1459
- ## Component Categories
1460
-
1461
- ### Form Controls
1462
-
1463
- These components replace native HTML form elements with enhanced features, validation, and styling:
1464
-
1465
- - **Switch** - Toggle switches for boolean values
1466
- - **InputNumber** - Numeric inputs with formatting
1467
- - **CheckBox** - Custom checkboxes and radio buttons (not in Phase 1 docs)
1468
- - **TextArea** - Auto-resizing text areas (not in Phase 1 docs)
1469
- - **DropDown** - Replacement for `<select>` with rich features
1470
- - **MultiSelect** - Multiple selection from lists (not in Phase 1 docs)
1471
-
1472
- ### Layout & Navigation
1473
-
1474
- Components for structuring application layout and navigation:
1475
-
1476
- - **Modal** - Dialog overlays
1477
- - **MasterDetailLayout** - Responsive master-detail pattern (not in Phase 1 docs)
1478
- - **TabHeader**, **TabHref** - Tab navigation (not in Phase 1 docs)
1479
- - **BlockNav** - Block-style navigation (not in Phase 1 docs)
1480
-
1481
- ### Data Display
1482
-
1483
- Components for presenting data to users:
1484
-
1485
- - **ArrayTable** - Sortable data tables
1486
- - **VirtualList**, **VirtualTable** - Performance-optimized large datasets (not in Phase 1 docs)
1487
- - **Calendar**, **DateRangePicker** - Date selection (not in Phase 1 docs)
1488
- - **Paginator** - Pagination controls (not in Phase 1 docs)
1489
-
1490
- ### Visual & Feedback
1491
-
1492
- Components for visual elements and user feedback:
1493
-
1494
- - **Icon** - FontAwesome icon wrapper (not in Phase 1 docs)
1495
- - **ActivityOverlay** - Loading overlays (used by Modal, not standalone)
1496
- - **MessageBoxes** - Toast notifications (not in Phase 1 docs)
1497
-
1498
- ### Utilities
1499
-
1500
- Helper modules and functions:
1501
-
1502
- - **Functions**, **FunctionsBrowser**, **FunctionsServer** - Utility functions
1503
- - **PathAnalyzer** - Route parsing and navigation (not in Phase 1 docs)
1504
- - **ArrayFunctions** - Array/table data helpers
1505
-
1506
- ---
1507
-
1508
- ## Integration Requirements
1509
-
1510
- ### Required Peer Dependencies
1511
-
1512
- ```json
1513
- {
1514
- "@solidbasisventures/intelliwaketsfoundation": "^5.13.57",
1515
- "@sveltejs/kit": "^2.49.2",
1516
- "svelte": "^5.46.1"
1517
- }
1518
- ```
1519
-
1520
- ### CSS Import (Required)
1521
-
1522
- ```typescript
1523
- // In your root +layout.svelte or app.css
1524
- import 'intelliwaketssveltekitv25/dist/app.css';
1525
- ```
1526
-
1527
- ### Tailwind Configuration (Required)
1528
-
1529
- Your project MUST define these custom Tailwind colors in your `tailwind.config.js`:
1530
-
1531
- ```javascript
1532
- theme: {
1533
- extend: {
1534
- colors: {
1535
- primary: {
1536
- main: '#your-color',
1537
- face: '#your-color',
1538
- hover: '#your-color',
1539
- light: '#your-color',
1540
- selected: '#your-color'
1541
- },
1542
- secondary: {
1543
- main: '#your-color',
1544
- light: '#your-color'
1545
- }
1546
- }
1547
- }
1548
- }
1549
- ```
1550
-
1551
- You must also define these custom classes:
1552
- - `.mdMasterHR` - Horizontal rule styling for MasterDetailLayout master header
1553
- - `.mdDetailHR` - Horizontal rule styling for MasterDetailLayout detail header
1554
-
1555
- ---
1556
-
1557
- ## Svelte 5 Patterns Used in This Library
1558
-
1559
- ### Runes
1560
-
1561
- This library extensively uses Svelte 5 runes:
1562
-
1563
- - **`$state()`** - Reactive local state
1564
- - **`$derived()`** - Computed values that update automatically
1565
- - **`$effect()`** - Side effects that run when dependencies change
1566
- - **`$bindable()`** - Two-way binding for component props
1567
- - **`$props()`** - Component props declaration
1568
-
1569
- ### Snippets
1570
-
1571
- Many components use Svelte 5's Snippet type for flexible content projection:
1572
-
1573
- ```typescript
1574
- import { type Snippet } from 'svelte';
1575
-
1576
- // Usage in component props
1577
- {
1578
- header?: Snippet,
1579
- body?: Snippet<[dataType, index]>
1580
- }
1581
-
1582
- // Rendering snippets
1583
- {#if header}
1584
- {@render header()}
1585
- {/if}
1586
- ```
1587
-
1588
- ### TypeScript Generics
1589
-
1590
- Components like `ArrayTable` use TypeScript generics for type safety:
1591
-
1592
- ```svelte
1593
- <script lang="ts" generics="T extends Record<string, any>">
1594
- let {
1595
- arrayData,
1596
- arrayStructure
1597
- }: {
1598
- arrayData: T[],
1599
- arrayStructure: IArrayStructure<T>
1600
- } = $props()
1601
- </script>
1602
- ```
1603
-
1604
- ---
1605
-
1606
- ## Phase 2 Components (Coming Soon)
1607
-
1608
- The following components will be documented in Phase 2:
1609
-
1610
- - **CheckBox** - Custom checkbox with flexible indicator styling
1611
- - **TextArea** - Auto-resizing textarea
1612
- - **MultiSelect** - Multi-select dropdown
1613
- - **VirtualList** - High-performance list for large datasets
1614
- - **MasterDetailLayout** - Complex responsive layout pattern
1615
-
1616
- ---
1617
-
1618
- ## Support & Documentation
1619
-
1620
- - **Full Project Documentation:** See `CLAUDE.md` in the package root
1621
- - **Integration Guide:** See `INTEGRATION.md` in the package root
1622
- - **Storybook:** Run `pnpm storybook` in the package directory for interactive component demos
1623
- - **GitHub Issues:** Report bugs or request features at the package repository
1624
-
1625
- ---
1626
-
1627
- ## Version History
1628
-
1629
- **Current Version:** 1.0.81 (Phase 1 Documentation)
1630
-
1631
- This documentation covers Phase 1 components. Additional components will be documented in future updates.
1632
-
1633
- ---
1634
-
1635
- _This documentation is optimized for LLM consumption. For human-readable tutorials and guides, see the Storybook documentation._