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/README.md +2 -2
- package/dist/app.css +1 -1
- package/docs/DateRangePicker.md +272 -0
- package/docs/DisplayHTML.md +249 -0
- package/docs/DropDown.md +269 -0
- package/docs/Functions.md +796 -0
- package/docs/Home.md +109 -0
- package/docs/Icon.md +203 -0
- package/docs/Importer.md +328 -0
- package/docs/ImporterAnalysis.md +249 -0
- package/docs/ImporterLoad.md +288 -0
- package/docs/InputNumber.md +159 -0
- package/docs/Integration.md +215 -0
- package/docs/Modal.md +207 -0
- package/docs/MultiSelect.md +304 -0
- package/docs/Paginator.md +332 -0
- package/docs/Search.md +364 -0
- package/docs/SlideDown.md +358 -0
- package/docs/Svelte-5-Patterns.md +364 -0
- package/docs/Switch.md +107 -0
- package/docs/TabHeader.md +333 -0
- package/docs/TabHref.md +370 -0
- package/docs/TextArea.md +118 -0
- package/docs/_Sidebar.md +38 -0
- package/llms.txt +113 -0
- package/package.json +3 -2
- package/llm.txt +0 -1635
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._
|