intelliwaketssveltekitv25 1.0.81 → 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.
Files changed (53) hide show
  1. package/INTEGRATION.md +574 -0
  2. package/README.md +199 -45
  3. package/dist/ArrayTable.stories.js +215 -0
  4. package/dist/ArrayTable.svelte +46 -0
  5. package/dist/ArrayTable.svelte.d.ts +44 -0
  6. package/dist/DropDown.stories.d.ts +96 -0
  7. package/dist/DropDown.stories.js +192 -0
  8. package/dist/DropDown.svelte +32 -0
  9. package/dist/DropDown.svelte.d.ts +30 -0
  10. package/dist/InputNumber.stories.d.ts +122 -0
  11. package/dist/InputNumber.stories.js +186 -0
  12. package/dist/InputNumber.svelte +52 -0
  13. package/dist/InputNumber.svelte.d.ts +27 -0
  14. package/dist/Modal.stories.d.ts +114 -0
  15. package/dist/Modal.stories.js +139 -0
  16. package/dist/Modal.svelte +34 -3
  17. package/dist/Modal.svelte.d.ts +35 -3
  18. package/dist/MultiSelect.stories.js +338 -0
  19. package/dist/MultiSelect.svelte +81 -0
  20. package/dist/MultiSelect.svelte.d.ts +38 -0
  21. package/dist/Switch.stories.d.ts +81 -0
  22. package/dist/Switch.stories.js +99 -0
  23. package/dist/Switch.svelte +40 -0
  24. package/dist/Switch.svelte.d.ts +26 -0
  25. package/dist/TextArea.stories.d.ts +180 -0
  26. package/dist/TextArea.stories.js +216 -0
  27. package/dist/TextArea.svelte +32 -0
  28. package/dist/TextArea.svelte.d.ts +24 -0
  29. package/dist/app.css +1 -1
  30. package/docs/DateRangePicker.md +272 -0
  31. package/docs/DisplayHTML.md +249 -0
  32. package/docs/DropDown.md +269 -0
  33. package/docs/Functions.md +796 -0
  34. package/docs/Home.md +109 -0
  35. package/docs/Icon.md +203 -0
  36. package/docs/Importer.md +328 -0
  37. package/docs/ImporterAnalysis.md +249 -0
  38. package/docs/ImporterLoad.md +288 -0
  39. package/docs/InputNumber.md +159 -0
  40. package/docs/Integration.md +215 -0
  41. package/docs/Modal.md +207 -0
  42. package/docs/MultiSelect.md +304 -0
  43. package/docs/Paginator.md +332 -0
  44. package/docs/Search.md +364 -0
  45. package/docs/SlideDown.md +358 -0
  46. package/docs/Svelte-5-Patterns.md +364 -0
  47. package/docs/Switch.md +107 -0
  48. package/docs/TabHeader.md +333 -0
  49. package/docs/TabHref.md +370 -0
  50. package/docs/TextArea.md +118 -0
  51. package/docs/_Sidebar.md +38 -0
  52. package/llms.txt +113 -0
  53. package/package.json +7 -2
@@ -0,0 +1,249 @@
1
+ # ImporterAnalysis Component
2
+
3
+ **Purpose:** CSV validation, column mapping, and error reporting phase of import workflow
4
+
5
+ **When to Use:**
6
+ - Rarely used directly (use **Importer** instead)
7
+ - Advanced use cases requiring custom import flow
8
+ - When you need granular control over validation display
9
+
10
+ ## Overview
11
+
12
+ ImporterAnalysis is the second phase of the **Importer** component. It displays CSV data in a table format with:
13
+ - Column header mapping (manual remapping if alternateNames provided)
14
+ - Row-by-row validation with error/warning highlighting
15
+ - Filter by errors or warnings
16
+ - Import/Clear actions
17
+
18
+ **Note:** Most applications should use the parent **Importer** component instead of ImporterAnalysis directly.
19
+
20
+ ## Key Props
21
+
22
+ - `definition: TDataImportProcessorDefinition<T>` (required) - Import column definitions
23
+ - `alternateNames?: Record<string, string[]>` ($bindable) - Column name mappings
24
+ - `csvData?: string | null` ($bindable) - CSV content
25
+ - `arrayData?: string[][] | null` ($bindable) - Array of arrays format
26
+ - `onprocess?: (results: TDataImportProcessorResult<T>[]) => Promise<boolean>` - Process validated rows
27
+
28
+ ## Features
29
+
30
+ ### Error/Warning Filtering
31
+ - Red "Errors" button - Shows rows with validation errors
32
+ - Yellow "Warnings" button - Shows rows with warnings
33
+ - Click to toggle filter, shows count
34
+
35
+ ### Column Remapping
36
+ When `alternateNames` is bound, users can:
37
+ - Click column header dropdown
38
+ - Select target column from definition
39
+ - Reset mapping
40
+ - System remembers alternate names for future imports
41
+
42
+ ### Data Preview
43
+ - Table view with all columns
44
+ - Missing required columns highlighted in red
45
+ - Error/warning messages shown in cells
46
+ - Text alignment based on data type
47
+
48
+ ## Usage Examples
49
+
50
+ ### Direct Usage (Advanced)
51
+ ```svelte
52
+ <script>
53
+ import { ImporterAnalysis } from 'intelliwaketssveltekitv25';
54
+
55
+ const definition = {
56
+ columns: {
57
+ 'Name': { required: true },
58
+ 'Email': { required: true }
59
+ }
60
+ };
61
+
62
+ let csvData = $state('Name,Email\nJohn,john@example.com');
63
+ let alternateNames = $state<Record<string, string[]> | null>({});
64
+
65
+ async function processData(validRows) {
66
+ console.log('Processing', validRows);
67
+ return true;
68
+ }
69
+ </script>
70
+
71
+ <ImporterAnalysis
72
+ {definition}
73
+ bind:alternateNames
74
+ bind:csvData
75
+ onprocess={processData}
76
+ />
77
+ ```
78
+
79
+ ### With Array Data
80
+ ```svelte
81
+ <script>
82
+ let arrayData = $state([
83
+ ['Name', 'Email'],
84
+ ['John', 'john@example.com'],
85
+ ['Jane', 'jane@example.com']
86
+ ]);
87
+ </script>
88
+
89
+ <ImporterAnalysis
90
+ {definition}
91
+ bind:arrayData
92
+ onprocess={processData}
93
+ />
94
+ ```
95
+
96
+ ## Validation Display
97
+
98
+ ### Error Cells (Red Background)
99
+ - Invalid data
100
+ - Missing required column
101
+ - Failed custom validation
102
+
103
+ ### Warning Cells (Yellow Background)
104
+ - Non-critical issues
105
+ - Data transformations applied
106
+
107
+ ### Gray Cells
108
+ - Unmapped columns (not in definition)
109
+
110
+ ### Normal Cells
111
+ - Valid data
112
+
113
+ ## Column Header Mapping
114
+
115
+ Headers show:
116
+ 1. **Mapped column name** (from definition) - Bold
117
+ 2. **Original CSV header** (if different) - Normal weight
118
+
119
+ Example:
120
+ ```
121
+ Email Address ← Definition column (bold)
122
+ email_addr ← CSV header (normal)
123
+ ```
124
+
125
+ ### Manual Remapping
126
+ If alternateNames is bound:
127
+ 1. Click column header dropdown
128
+ 2. Select correct target column
129
+ 3. Mapping is saved in alternateNames
130
+ 4. Future imports remember the mapping
131
+
132
+ ## Actions
133
+
134
+ ### Import Button
135
+ - Disabled if validation errors exist
136
+ - Calls `onprocess` with valid rows only
137
+ - Clears data if `onprocess` returns true
138
+
139
+ ### Clear Button
140
+ - Resets csvData/arrayData to null
141
+ - Returns to ImporterLoad phase (if using Importer)
142
+
143
+ ## DataImportProcessor
144
+
145
+ The component uses `DataImportProcessor` from `@solidbasisventures/intelliwaketsfoundation`:
146
+ ```typescript
147
+ const processor = new DataImportProcessor(definition.columns, {
148
+ alternateNames: alternateNames ?? {}
149
+ });
150
+ processor.populateFromCSV(csvData);
151
+ // or
152
+ processor.populateFromArray(arrayData);
153
+
154
+ // Access results:
155
+ processor.allErrors // All error messages
156
+ processor.allWarnings // All warning messages
157
+ processor.validRows // Rows passing validation
158
+ processor.analysisRows // All rows with metadata
159
+ processor.isValid // True if no errors
160
+ ```
161
+
162
+ ## Common Patterns
163
+
164
+ ### Custom Import Flow
165
+ ```svelte
166
+ <script>
167
+ let step = $state<'upload' | 'analyze' | 'complete'>('upload');
168
+ let csvData = $state(null);
169
+ </script>
170
+
171
+ {#if step === 'upload'}
172
+ <ImporterLoad bind:csvData {definition} />
173
+ <button onclick={() => step = 'analyze'}>
174
+ Analyze
175
+ </button>
176
+ {:else if step === 'analyze'}
177
+ <ImporterAnalysis
178
+ bind:csvData
179
+ {definition}
180
+ onprocess={async (rows) => {
181
+ await import(rows);
182
+ step = 'complete';
183
+ return true;
184
+ }}
185
+ />
186
+ {:else}
187
+ <div>Import complete!</div>
188
+ {/if}
189
+ ```
190
+
191
+ ### Programmatic Validation
192
+ ```svelte
193
+ <script>
194
+ import { DataImportProcessor } from '@solidbasisventures/intelliwaketsfoundation';
195
+
196
+ function validateCSV(csv: string) {
197
+ const processor = new DataImportProcessor(definition.columns);
198
+ processor.populateFromCSV(csv);
199
+
200
+ if (!processor.isValid) {
201
+ console.error('Validation failed:', processor.allErrors);
202
+ return false;
203
+ }
204
+
205
+ return processor.validRows;
206
+ }
207
+ </script>
208
+ ```
209
+
210
+ ## Common Mistakes
211
+
212
+ - ❌ Using ImporterAnalysis without providing csvData or arrayData
213
+ ✅ Correct: Ensure data is bound and populated
214
+
215
+ - ❌ Not providing `onprocess` callback
216
+ ✅ Correct: Always provide onprocess to handle validated rows
217
+
218
+ - ❌ Forgetting that `onprocess` should return boolean
219
+ ✅ Correct: Return true to clear, false to keep data
220
+
221
+ - ❌ Using this component when Importer would suffice
222
+ ✅ Correct: Use Importer for standard workflows
223
+
224
+ ## Related Components
225
+
226
+ - **Importer** - Complete import workflow (recommended)
227
+ - **ImporterLoad** - File upload and template download phase
228
+ - **DropDown** - Used for column mapping dropdown
229
+ - **DataImportProcessor** - Core validation logic
230
+
231
+ ## Props Reference
232
+
233
+ | Prop | Type | Default | Description |
234
+ |------|------|---------|-------------|
235
+ | `definition` | `TDataImportProcessorDefinition<T>` | (required) | Column definitions |
236
+ | `alternateNames` | `Record<string, string[]>` | `null` | Column mappings ($bindable) |
237
+ | `csvData` | `string \| null` | `null` | CSV content ($bindable) |
238
+ | `arrayData` | `string[][] \| null` | `null` | Array format ($bindable) |
239
+ | `onprocess` | `(rows) => Promise<boolean>` | - | Process valid rows |
240
+
241
+ ## Styling
242
+
243
+ Uses standard table classes:
244
+ - `table` - Base table styles
245
+ - `tableBordered` - Cell borders
246
+ - `tableSticky` - Sticky header
247
+ - `data-color-light="danger"` - Error highlighting
248
+ - `data-color-light="warning"` - Warning highlighting
249
+ - `data-color-light="gray"` - Unmapped columns
@@ -0,0 +1,288 @@
1
+ # ImporterLoad Component
2
+
3
+ **Purpose:** File upload and CSV template download phase of import workflow
4
+
5
+ **When to Use:**
6
+ - Rarely used directly (use **Importer** instead)
7
+ - Advanced use cases requiring custom import UI
8
+ - When building multi-step import wizards
9
+
10
+ ## Overview
11
+
12
+ ImporterLoad is the first phase of the **Importer** component. It provides:
13
+ - CSV file upload via button or drag-and-drop
14
+ - Download empty template
15
+ - Download template with sample data
16
+ - Download current data as template
17
+
18
+ **Note:** Most applications should use the parent **Importer** component instead of ImporterLoad directly.
19
+
20
+ ## Key Props
21
+
22
+ - `definition: TDataImportProcessorDefinition<T>` (required) - Import column definitions
23
+ - `csvData?: string | null` ($bindable) - CSV content (set when file uploaded)
24
+ - `description?: Snippet` - Custom description/instructions
25
+ - `currentData?: object[]` - Existing data for "Download Current Data" option
26
+ - `templateName?: string` (default: 'Template') - Filename prefix for downloads
27
+ - `fileAccept?: string` (default: '.csv') - Accepted file types
28
+
29
+ ## Features
30
+
31
+ ### File Upload
32
+ - **Button upload** - Click "Import CSV" button to select file
33
+ - **Drag-and-drop** - Drag CSV file onto component area
34
+ - Visual feedback on drag (blue background)
35
+ - File content stored in `csvData` binding
36
+
37
+ ### Template Downloads
38
+ Three template download options:
39
+
40
+ 1. **Download Empty Template**
41
+ - CSV with just column headers
42
+ - Filename: `{templateName}_YYYY-MM-DD_HH-mm-ss.csv`
43
+
44
+ 2. **Download with Sample Data**
45
+ - Headers + description row + sample data row
46
+ - Only shown if columns have `description` or `sampleData`
47
+
48
+ 3. **Download Current Data**
49
+ - Current data exported as CSV template
50
+ - Only shown if `currentData` prop provided
51
+ - Helps users see expected format
52
+
53
+ ## Usage Examples
54
+
55
+ ### Direct Usage (Advanced)
56
+ ```svelte
57
+ <script>
58
+ import { ImporterLoad } from 'intelliwaketssveltekitv25';
59
+
60
+ const definition = {
61
+ descriptionHTML: '<p>Upload CSV with user data</p>',
62
+ columns: {
63
+ 'Name': {
64
+ required: true,
65
+ description: 'Full name',
66
+ sampleData: 'John Doe'
67
+ },
68
+ 'Email': {
69
+ required: true,
70
+ description: 'Email address',
71
+ sampleData: 'john@example.com'
72
+ }
73
+ }
74
+ };
75
+
76
+ let csvData = $state<string | null>(null);
77
+ </script>
78
+
79
+ <!-- Upload phase -->
80
+ {#if csvData === null}
81
+ <ImporterLoad
82
+ {definition}
83
+ bind:csvData
84
+ />
85
+ {:else}
86
+ <!-- Process csvData or show ImporterAnalysis -->
87
+ {/if}
88
+ ```
89
+
90
+ ### With Custom Description
91
+ ```svelte
92
+ <ImporterLoad
93
+ {definition}
94
+ bind:csvData
95
+ >
96
+ {#snippet description()}
97
+ <div class="alert alert-info">
98
+ <h4>Before uploading:</h4>
99
+ <ul>
100
+ <li>Ensure email addresses are valid</li>
101
+ <li>Names should be in "First Last" format</li>
102
+ <li>Maximum 500 rows per import</li>
103
+ </ul>
104
+ </div>
105
+ {/snippet}
106
+ </ImporterLoad>
107
+ ```
108
+
109
+ ### With Current Data Download
110
+ ```svelte
111
+ <script>
112
+ let existingUsers = [
113
+ { Name: 'John Doe', Email: 'john@example.com', Age: 30 },
114
+ { Name: 'Jane Smith', Email: 'jane@example.com', Age: 28 }
115
+ ];
116
+ </script>
117
+
118
+ <ImporterLoad
119
+ {definition}
120
+ bind:csvData
121
+ currentData={existingUsers}
122
+ templateName="Users"
123
+ />
124
+ <!-- Users can download existing data as reference -->
125
+ ```
126
+
127
+ ### Custom File Types
128
+ ```svelte
129
+ <ImporterLoad
130
+ {definition}
131
+ bind:csvData
132
+ fileAccept=".csv,.txt"
133
+ />
134
+ ```
135
+
136
+ ## Template Generation
137
+
138
+ ### Empty Template
139
+ ```csv
140
+ Name,Email,Age
141
+ ```
142
+
143
+ ### With Sample Data
144
+ ```csv
145
+ Name,Email,Age
146
+ Full name,Email address,User age
147
+ John Doe,john@example.com,25
148
+ ```
149
+
150
+ ### Current Data
151
+ ```csv
152
+ Name,Email,Age
153
+ John Doe,john@example.com,30
154
+ Jane Smith,jane@example.com,28
155
+ ```
156
+
157
+ ## Drag-and-Drop
158
+
159
+ Visual feedback during drag:
160
+ - Component background turns blue (`bg-blue-50`)
161
+ - Drop zone covers entire component
162
+ - Accepts single file only
163
+ - File content immediately loaded into `csvData`
164
+
165
+ ## Column Definition Display
166
+
167
+ The component shows a table with:
168
+ - **Header row:** Column names from definition
169
+ - **Description row:** If any column has `description` (optional)
170
+ - **Sample row:** If any column has `sampleData` (optional)
171
+
172
+ ## Common Patterns
173
+
174
+ ### Multi-Step Import
175
+ ```svelte
176
+ <script>
177
+ let csvData = $state(null);
178
+ let step = $state<'upload' | 'validate'>('upload');
179
+ </script>
180
+
181
+ {#if step === 'upload'}
182
+ <ImporterLoad
183
+ {definition}
184
+ bind:csvData
185
+ />
186
+ <button
187
+ disabled={!csvData}
188
+ onclick={() => step = 'validate'}
189
+ >
190
+ Next
191
+ </button>
192
+ {:else}
193
+ <ImporterAnalysis
194
+ {definition}
195
+ bind:csvData
196
+ onprocess={handleImport}
197
+ />
198
+ {/if}
199
+ ```
200
+
201
+ ### With Progress Indicator
202
+ ```svelte
203
+ <script>
204
+ let uploading = $state(false);
205
+
206
+ $effect(() => {
207
+ if (csvData !== null) {
208
+ uploading = false;
209
+ }
210
+ });
211
+ </script>
212
+
213
+ {#if uploading}
214
+ <div>Processing file...</div>
215
+ {/if}
216
+
217
+ <ImporterLoad
218
+ {definition}
219
+ bind:csvData
220
+ />
221
+ ```
222
+
223
+ ### Reset Upload
224
+ ```svelte
225
+ <script>
226
+ let csvData = $state(null);
227
+ </script>
228
+
229
+ <ImporterLoad {definition} bind:csvData />
230
+
231
+ {#if csvData}
232
+ <button onclick={() => csvData = null}>
233
+ Reset
234
+ </button>
235
+ {/if}
236
+ ```
237
+
238
+ ## Common Mistakes
239
+
240
+ - ❌ Not binding `csvData` prop
241
+ ✅ Correct: Use `bind:csvData` for two-way binding
242
+
243
+ - ❌ Not checking if csvData exists before processing
244
+ ✅ Correct: Check `if (csvData !== null)` before analysis
245
+
246
+ - ❌ Using complex objects in `currentData` that don't match definition
247
+ ✅ Correct: Ensure currentData keys match column definitions
248
+
249
+ - ❌ Not providing sample data for complex formats
250
+ ✅ Correct: Add `sampleData` to help users understand format
251
+
252
+ ## Related Components
253
+
254
+ - **Importer** - Complete import workflow (recommended)
255
+ - **ImporterAnalysis** - Validation and processing phase
256
+ - **DropDown** - Used for template download options
257
+ - **DisplayHTML** - Renders definition.descriptionHTML
258
+
259
+ ## Props Reference
260
+
261
+ | Prop | Type | Default | Description |
262
+ |------|------|---------|-------------|
263
+ | `definition` | `TDataImportProcessorDefinition<T>` | (required) | Column definitions |
264
+ | `csvData` | `string \| null` | `null` | CSV content ($bindable) |
265
+ | `description` | `Snippet` | - | Custom instructions |
266
+ | `currentData` | `object[]` | - | Data for template download |
267
+ | `templateName` | `string` | `'Template'` | Download filename prefix |
268
+ | `fileAccept` | `string` | `'.csv'` | Accepted file extensions |
269
+
270
+ ## Utility Functions
271
+
272
+ Uses these functions from the library:
273
+ - **DataToCSVExport(filename, data)** - Generate and download CSV
274
+ - **YYYY_MM_DD_HH_mm_ss(date)** - Format timestamp for filename
275
+
276
+ ## Styling
277
+
278
+ - Drag-and-drop zone: `bg-blue-50` on dragover
279
+ - Upload button: Standard button styles with upload icon (SVG)
280
+ - Table: Uses `table`, `tableBordered`, `tableSticky` classes
281
+ - Icons: Inline SVG for upload/download icons
282
+
283
+ ## Accessibility
284
+
285
+ - File input hidden, triggered by button click
286
+ - Drag-and-drop zone marked with `role="region"` and `aria-label`
287
+ - Upload button has descriptive SVG icon
288
+ - All interactive elements keyboard accessible
@@ -0,0 +1,159 @@
1
+ # InputNumber Component
2
+
3
+ **Replaces:** `<input type="number">` for ALL numeric inputs
4
+
5
+ **Purpose:** Formatted numeric input with automatic currency, percentage, and decimal handling
6
+
7
+ **When to Use:**
8
+ - Currency amounts (prices, costs, payments)
9
+ - Percentages (tax rates, discounts, progress)
10
+ - Decimal numbers (measurements, weights, quantities)
11
+ - Integer counts with min/max constraints
12
+ - Any numeric data entry where formatting matters
13
+
14
+ ## Key Props
15
+
16
+ - `value?: number | null` ($bindable) - Current numeric value, use `bind:value`
17
+ - `currency?: boolean` - Format as currency (adds $ prefix, 2 decimal places)
18
+ - `percent?: boolean` - Format as percentage (adds % suffix, stores as decimal 0-1, displays as 0-100)
19
+ - `fixedDecimals?: number` - Force exact number of decimal places
20
+ - `minDecimals?: number` - Minimum decimal places to show
21
+ - `maxDecimals?: number` - Maximum decimal places allowed
22
+ - `min?: number` - Minimum allowed value (enforced on input)
23
+ - `max?: number` - Maximum allowed value (enforced on input)
24
+ - `allowNegative?: boolean` - Allow negative numbers (default: false)
25
+ - `zeroBlank?: boolean` - Display empty string instead of 0
26
+ - `zeroDash?: boolean` - Display "-" instead of 0
27
+ - `nullBlank?: boolean` - Display empty string for null values
28
+ - `nullDash?: boolean` - Display "-" for null values
29
+ - `prefix?: string` - Custom prefix (overrides currency $)
30
+ - `suffix?: string` - Custom suffix (overrides percent %)
31
+ - `delayChange?: boolean | number | 'blur'` - Delay before updating bound value
32
+ - `true`: 1500ms delay
33
+ - `number`: Custom milliseconds delay
34
+ - `'blur'`: Update only on blur event
35
+ - `widthNumbers?: number` - Set input width based on number of digits
36
+ - `class?: string` - Additional CSS classes for wrapper div
37
+ - `inputClass?: string` - CSS classes for the input element itself
38
+ - `onchange?: (value: number | null) => void` - Callback when value changes
39
+ - Standard HTML input props: `disabled`, `readonly`, `required`, `name`, `placeholder`, `id`, etc.
40
+
41
+ **TypeScript Type:** `TInputNumberAttributes` (extends standard input attributes)
42
+
43
+ ## Usage Examples
44
+
45
+ ```svelte
46
+ <script>
47
+ import { InputNumber } from 'intelliwaketssveltekitv25';
48
+ let price = $state(29.99);
49
+ let taxRate = $state(0.08); // 8% stored as 0.08, displays as 8
50
+ let quantity = $state(1);
51
+ let weight = $state(null);
52
+ </script>
53
+
54
+ <!-- Currency input -->
55
+ <label>
56
+ Price:
57
+ <InputNumber bind:value={price} currency required />
58
+ </label>
59
+ <!-- Displays: $29.99 -->
60
+
61
+ <!-- Percentage input -->
62
+ <label>
63
+ Tax Rate:
64
+ <InputNumber bind:value={taxRate} percent />
65
+ </label>
66
+ <!-- Displays: 8% (user enters 8, stored as 0.08) -->
67
+
68
+ <!-- Integer quantity with constraints -->
69
+ <label>
70
+ Quantity:
71
+ <InputNumber bind:value={quantity} fixedDecimals={0} min={1} max={999} />
72
+ </label>
73
+
74
+ <!-- Decimal with custom suffix -->
75
+ <label>
76
+ Weight:
77
+ <InputNumber bind:value={weight} suffix="kg" maxDecimals={2} zeroBlank />
78
+ </label>
79
+
80
+ <!-- With delayed change (for expensive calculations) -->
81
+ <InputNumber
82
+ bind:value={searchAmount}
83
+ currency
84
+ delayChange={true}
85
+ placeholder="Filter by amount..."
86
+ />
87
+ <!-- Value updates 1.5 seconds after user stops typing -->
88
+
89
+ <!-- Update only on blur -->
90
+ <InputNumber
91
+ bind:value={finalTotal}
92
+ currency
93
+ delayChange="blur"
94
+ />
95
+
96
+ <!-- Readonly display -->
97
+ <InputNumber value={calculatedTotal} currency readonly />
98
+
99
+ <!-- Allow negative numbers -->
100
+ <InputNumber
101
+ bind:value={profitLoss}
102
+ currency
103
+ allowNegative
104
+ zeroDash
105
+ />
106
+
107
+ <!-- Width based on digit count -->
108
+ <InputNumber
109
+ bind:value={zipCode}
110
+ fixedDecimals={0}
111
+ widthNumbers={5}
112
+ />
113
+
114
+ <!-- With change handler -->
115
+ <InputNumber
116
+ bind:value={discount}
117
+ percent
118
+ onchange={(val) => {
119
+ console.log('Discount changed to:', val);
120
+ recalculateTotal();
121
+ }}
122
+ />
123
+ ```
124
+
125
+ ## Common Mistakes
126
+
127
+ - ❌ Using `<input type="number">` for currency: `<input type="number" step="0.01">`
128
+ ✅ Correct: `<InputNumber currency bind:value={amount} />`
129
+
130
+ - ❌ Storing percentages as whole numbers (8) instead of decimals (0.08)
131
+ ✅ Correct: Store as decimal (0.08), use `percent` prop to display as 8%
132
+
133
+ - ❌ Not using `bind:value`: `<InputNumber value={x} />`
134
+ ✅ Correct: `<InputNumber bind:value={x} />` (for two-way binding)
135
+
136
+ - ❌ Expecting immediate updates without considering `delayChange`
137
+ ✅ Correct: Use `delayChange="blur"` or `delayChange={false}` for immediate updates
138
+
139
+ - ❌ Using both `currency` and `percent` props together
140
+ ✅ Correct: Use only one formatting option at a time
141
+
142
+ ## Props Combinations
143
+
144
+ - **Currency:** `currency` (auto-adds $ prefix, 2 decimals)
145
+ - **Percentage:** `percent` (auto-adds % suffix, multiplies display by 100)
146
+ - **Integer:** `fixedDecimals={0}`
147
+ - **Range validation:** `min={x} max={y}`
148
+ - **Performance optimization:** `delayChange={true}` or `delayChange={500}` (ms) or `delayChange="blur"`
149
+ - **Zero handling:** `zeroBlank` or `zeroDash`
150
+ - **Null handling:** `nullBlank` or `nullDash`
151
+
152
+ ## Related Components
153
+
154
+ - `InputNumberScroll` - Numeric input with scroll wheel adjustment support
155
+ - `NumberFormat` - Display-only formatted number component
156
+
157
+ ## Storybook
158
+
159
+ See `Components/InputNumber` stories