@cfasim-ui/components 0.7.7 → 0.8.0

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 (89) hide show
  1. package/dist/Box/Box.d.ts +7 -11
  2. package/dist/Button/Button.d.ts +7 -11
  3. package/dist/ButtonGroup/ButtonGroup.d.ts +8 -12
  4. package/dist/Container/Container.d.ts +7 -11
  5. package/dist/Expander/Expander.d.ts +12 -14
  6. package/dist/Grid/Grid.d.ts +6 -5
  7. package/dist/Hint/Hint.d.ts +2 -1
  8. package/dist/Icon/Icon.d.ts +3 -2
  9. package/dist/LightDarkToggle/LightDarkToggle.d.ts +2 -1
  10. package/dist/MultiSelect/MultiSelect.d.ts +6 -6
  11. package/dist/NumberInput/NumberInput.d.ts +13 -11
  12. package/dist/ParamEditor/ParamEditor.d.ts +3 -2
  13. package/dist/ParamEditor/ParamEditorImpl.d.ts +3 -5
  14. package/dist/{ParamEditorImpl-D0xZTyAN.js → ParamEditorImpl-CkElC6PI.js} +3075 -3041
  15. package/dist/SelectBox/SelectBox.d.ts +8 -6
  16. package/dist/{SelectBox-CByXZfaC.js → SelectBox-Df8dE2r-.js} +6 -6
  17. package/dist/SidebarLayout/SidebarLayout.d.ts +21 -20
  18. package/dist/Spinner/Spinner.d.ts +3 -2
  19. package/dist/TextInput/TextInput.d.ts +7 -5
  20. package/dist/Toggle/Toggle.d.ts +8 -6
  21. package/dist/ToggleGroup/ToggleGroup.d.ts +8 -6
  22. package/dist/_internal/FieldLabel.d.ts +2 -1
  23. package/dist/index.js +20 -20
  24. package/docs/Box.md +49 -0
  25. package/docs/Button.md +67 -0
  26. package/docs/ButtonGroup.md +64 -0
  27. package/docs/Container.md +103 -0
  28. package/docs/Expander.md +34 -0
  29. package/docs/Grid.md +170 -0
  30. package/docs/Hint.md +29 -0
  31. package/docs/Icon.md +188 -0
  32. package/docs/MultiSelect.md +143 -0
  33. package/docs/NumberInput.md +485 -0
  34. package/docs/ParamEditor.md +97 -0
  35. package/docs/SelectBox.md +182 -0
  36. package/docs/SidebarLayout.md +106 -0
  37. package/docs/Spinner.md +51 -0
  38. package/docs/TextInput.md +83 -0
  39. package/docs/Toggle.md +81 -0
  40. package/docs/ToggleGroup.md +163 -0
  41. package/docs/index.json +194 -0
  42. package/package.json +24 -20
  43. package/src/Box/Box.md +41 -0
  44. package/src/Box/Box.vue +52 -0
  45. package/src/Button/Button.md +59 -0
  46. package/src/Button/Button.vue +81 -0
  47. package/src/ButtonGroup/ButtonGroup.md +62 -0
  48. package/src/ButtonGroup/ButtonGroup.vue +91 -0
  49. package/src/Container/Container.md +99 -0
  50. package/src/Container/Container.vue +62 -0
  51. package/src/Expander/Expander.md +23 -0
  52. package/src/Expander/Expander.vue +95 -0
  53. package/src/Grid/Grid.md +175 -0
  54. package/src/Grid/Grid.vue +145 -0
  55. package/src/Hint/Hint.md +24 -0
  56. package/src/Hint/Hint.vue +83 -0
  57. package/src/Icon/Icon.md +176 -0
  58. package/src/Icon/Icon.vue +104 -0
  59. package/src/Icon/defaultIcons.ts +92 -0
  60. package/src/Icon/github.svg +1 -0
  61. package/src/Icon/registry.ts +68 -0
  62. package/src/LightDarkToggle/LightDarkToggle.vue +49 -0
  63. package/src/MultiSelect/MultiSelect.md +142 -0
  64. package/src/MultiSelect/MultiSelect.vue +279 -0
  65. package/src/NumberInput/NumberInput.md +455 -0
  66. package/src/NumberInput/NumberInput.vue +575 -0
  67. package/src/ParamEditor/ParamEditor.md +87 -0
  68. package/src/ParamEditor/ParamEditor.vue +43 -0
  69. package/src/ParamEditor/ParamEditorImpl.vue +358 -0
  70. package/src/SelectBox/SelectBox.md +169 -0
  71. package/src/SelectBox/SelectBox.vue +260 -0
  72. package/src/SidebarLayout/SidebarLayout.md +106 -0
  73. package/src/SidebarLayout/SidebarLayout.vue +468 -0
  74. package/src/Spinner/Spinner.md +45 -0
  75. package/src/Spinner/Spinner.vue +55 -0
  76. package/src/TextInput/TextInput.md +68 -0
  77. package/src/TextInput/TextInput.vue +54 -0
  78. package/src/Toggle/Toggle.md +68 -0
  79. package/src/Toggle/Toggle.vue +81 -0
  80. package/src/ToggleGroup/ToggleGroup.md +158 -0
  81. package/src/ToggleGroup/ToggleGroup.vue +138 -0
  82. package/src/_internal/FieldLabel.vue +27 -0
  83. package/src/_internal/field.ts +27 -0
  84. package/src/_internal/gap.ts +17 -0
  85. package/src/_internal/input.css +54 -0
  86. package/src/_internal/listbox.css +53 -0
  87. package/src/env.d.ts +4 -0
  88. package/src/index.ts +33 -0
  89. package/src/svg.d.ts +5 -0
@@ -0,0 +1,455 @@
1
+ # NumberInput
2
+
3
+ A number input field with optional slider, percent mode, and validation.
4
+
5
+ ## Examples
6
+
7
+ ### Basic
8
+
9
+ <script setup>
10
+ import { ref } from 'vue'
11
+ const days = ref(10)
12
+ const population = ref(100000)
13
+ const coverage = ref(0.5)
14
+ const r0 = ref(3.5)
15
+ const ageRange = ref([18, 65])
16
+ const coverageRange = ref([0.2, 0.8])
17
+ const minAge = ref(18)
18
+ const maxAge = ref(65)
19
+ const dayMs = 24 * 60 * 60 * 1000
20
+ const dateStart = Date.UTC(2024, 0, 1)
21
+ const dateEnd = Date.UTC(2024, 11, 31)
22
+ const dateRange = ref([Date.UTC(2024, 2, 1), Date.UTC(2024, 8, 30)])
23
+ const formatDate = (ms) =>
24
+ new Date(ms).toLocaleDateString("en-US", { month: "short", day: "numeric" })
25
+ </script>
26
+
27
+ <ComponentDemo>
28
+ <div style="width: 300px">
29
+ <NumberInput v-model="days" label="Days" placeholder="Number of days" />
30
+ </div>
31
+
32
+ <template #code>
33
+
34
+ ```vue
35
+ <script setup>
36
+ import { ref } from "vue";
37
+ const days = ref(10);
38
+ </script>
39
+
40
+ <NumberInput v-model="days" label="Days" placeholder="Number of days" />
41
+ ```
42
+
43
+ </template>
44
+ </ComponentDemo>
45
+
46
+ ### With hint and validation
47
+
48
+ <ComponentDemo>
49
+ <div style="width: 300px">
50
+ <NumberInput
51
+ v-model="population"
52
+ label="Population"
53
+ hint="Total number of individuals"
54
+ :min="1000"
55
+ :max="100000"
56
+ :step="1"
57
+ />
58
+ </div>
59
+
60
+ <template #code>
61
+
62
+ ```vue
63
+ <NumberInput
64
+ v-model="population"
65
+ label="Population"
66
+ hint="Total number of individuals"
67
+ :min="1000"
68
+ :max="100000"
69
+ :step="1"
70
+ />
71
+ ```
72
+
73
+ </template>
74
+ </ComponentDemo>
75
+
76
+ ### Percent mode
77
+
78
+ <ComponentDemo>
79
+ <div style="width: 300px">
80
+ <NumberInput
81
+ v-model="coverage"
82
+ label="Vaccination coverage"
83
+ percent
84
+ :max="1"
85
+ />
86
+ </div>
87
+
88
+ <template #code>
89
+
90
+ ```vue
91
+ <NumberInput v-model="coverage" label="Vaccination coverage" percent :max="1" />
92
+ ```
93
+
94
+ </template>
95
+ </ComponentDemo>
96
+
97
+ ### Slider
98
+
99
+ <ComponentDemo>
100
+ <div style="width: 300px">
101
+ <NumberInput
102
+ v-model="r0"
103
+ label="R0"
104
+ hint="Basic reproduction number"
105
+ :step="0.1"
106
+ :min="1"
107
+ :max="18"
108
+ slider
109
+ />
110
+ </div>
111
+
112
+ <template #code>
113
+
114
+ ```vue
115
+ <NumberInput
116
+ v-model="r0"
117
+ label="R0"
118
+ hint="Basic reproduction number"
119
+ :step="0.1"
120
+ :min="1"
121
+ :max="18"
122
+ slider
123
+ />
124
+ ```
125
+
126
+ </template>
127
+ </ComponentDemo>
128
+
129
+ ### Range slider
130
+
131
+ Bind `v-model:range` with a `[low, high]` tuple to render a two-handle
132
+ slider. Range mode is enabled automatically by the binding — there's no
133
+ explicit toggle prop.
134
+
135
+ <ComponentDemo>
136
+ <div style="width: 300px">
137
+ <NumberInput
138
+ v-model:range="ageRange"
139
+ label="Age range"
140
+ :min="0"
141
+ :max="100"
142
+ number-type="integer"
143
+ />
144
+ </div>
145
+
146
+ <template #code>
147
+
148
+ ```vue
149
+ <script setup>
150
+ import { ref } from "vue";
151
+ const ageRange = ref([18, 65]);
152
+ </script>
153
+
154
+ <NumberInput
155
+ v-model:range="ageRange"
156
+ label="Age range"
157
+ :min="0"
158
+ :max="100"
159
+ number-type="integer"
160
+ />
161
+ ```
162
+
163
+ </template>
164
+ </ComponentDemo>
165
+
166
+ ### Range slider with split bindings
167
+
168
+ When your state stores the bounds in separate refs (rather than as a tuple),
169
+ bind them directly with `v-model:lower` and `v-model:upper`. You can bind
170
+ either pair or combine them with `v-model:range` — writes from the component
171
+ go to every bound sink.
172
+
173
+ <ComponentDemo>
174
+ <div style="width: 300px">
175
+ <NumberInput
176
+ v-model:lower="minAge"
177
+ v-model:upper="maxAge"
178
+ label="Age range (split)"
179
+ :min="0"
180
+ :max="100"
181
+ number-type="integer"
182
+ />
183
+ </div>
184
+
185
+ <template #code>
186
+
187
+ ```vue
188
+ <script setup>
189
+ import { ref } from "vue";
190
+ const minAge = ref(18);
191
+ const maxAge = ref(65);
192
+ </script>
193
+
194
+ <NumberInput
195
+ v-model:lower="minAge"
196
+ v-model:upper="maxAge"
197
+ label="Age range"
198
+ :min="0"
199
+ :max="100"
200
+ number-type="integer"
201
+ />
202
+ ```
203
+
204
+ </template>
205
+ </ComponentDemo>
206
+
207
+ Range mode works with `percent` and `live` as well:
208
+
209
+ <ComponentDemo>
210
+ <div style="width: 300px">
211
+ <NumberInput
212
+ v-model:range="coverageRange"
213
+ label="Coverage range"
214
+ percent
215
+ live
216
+ :max="1"
217
+ />
218
+ </div>
219
+
220
+ <template #code>
221
+
222
+ ```vue
223
+ <NumberInput
224
+ v-model:range="coverageRange"
225
+ label="Coverage range"
226
+ percent
227
+ live
228
+ :max="1"
229
+ />
230
+ ```
231
+
232
+ </template>
233
+ </ComponentDemo>
234
+
235
+ ### Custom display format
236
+
237
+ Pass `format` to control how the value is displayed in the text input and
238
+ in slider thumb/min/max labels. Accepts a
239
+ [`NumberFormat`](../charts/data-table.md#columnconfig) — a preset name
240
+ (optionally with a `:N` digits suffix, e.g. `"percent:1"`), a printf-style
241
+ format string (`"%.2f"`), or a `(value: number) => string` function. The
242
+ internal model stays a number — only the displayed text changes.
243
+
244
+ When unset, the default formatting follows the `percent` and `decimals`
245
+ props. When set, `format` overrides both. Formats that add suffixes or
246
+ scale the value (e.g. `"percent:1"` → `"12.3%"`) may not round-trip
247
+ through the text input — pair them with `percent: true` for value scaling
248
+ and use `format` for display shaping.
249
+
250
+ The older `slider-display` prop (a `(value: number) => string` function
251
+ that only affected slider thumb/min/max labels) is **deprecated** but
252
+ still honored when `format` is unset. Prefer `format` for new code.
253
+
254
+ <ComponentDemo>
255
+ <div style="width: 300px">
256
+ <NumberInput
257
+ v-model:range="dateRange"
258
+ label="Date range"
259
+ :min="dateStart"
260
+ :max="dateEnd"
261
+ :step="dayMs"
262
+ :format="formatDate"
263
+ />
264
+ </div>
265
+
266
+ <template #code>
267
+
268
+ ```vue
269
+ <script setup>
270
+ import { ref } from "vue";
271
+ const dayMs = 24 * 60 * 60 * 1000;
272
+ const dateStart = Date.UTC(2024, 0, 1);
273
+ const dateEnd = Date.UTC(2024, 11, 31);
274
+ const dateRange = ref([Date.UTC(2024, 2, 1), Date.UTC(2024, 8, 30)]);
275
+ const formatDate = (ms) =>
276
+ new Date(ms).toLocaleDateString("en-US", { month: "short", day: "numeric" });
277
+ </script>
278
+
279
+ <NumberInput
280
+ v-model:range="dateRange"
281
+ label="Date range"
282
+ :min="dateStart"
283
+ :max="dateEnd"
284
+ :step="dayMs"
285
+ :format="formatDate"
286
+ />
287
+ ```
288
+
289
+ </template>
290
+ </ComponentDemo>
291
+
292
+ ### Live slider
293
+
294
+ With `live`, the model updates while dragging the slider thumb rather than only on release.
295
+
296
+ <ComponentDemo>
297
+ <div style="width: 300px">
298
+ <NumberInput
299
+ v-model="coverage"
300
+ label="Vaccination coverage"
301
+ percent
302
+ slider
303
+ live
304
+ :max="1"
305
+ />
306
+ </div>
307
+
308
+ <template #code>
309
+
310
+ ```vue
311
+ <NumberInput
312
+ v-model="coverage"
313
+ label="Vaccination coverage"
314
+ percent
315
+ slider
316
+ live
317
+ :max="1"
318
+ />
319
+ ```
320
+
321
+ </template>
322
+ </ComponentDemo>
323
+
324
+ ### Live input
325
+
326
+ With `live` on a regular input, the model updates as you type (debounced 300ms). Arrow keys and spinner buttons commit immediately.
327
+
328
+ <ComponentDemo>
329
+ <div style="width: 300px">
330
+ <NumberInput v-model="days" label="Days" live />
331
+ </div>
332
+
333
+ <template #code>
334
+
335
+ ```vue
336
+ <NumberInput v-model="days" label="Days" live />
337
+ ```
338
+
339
+ </template>
340
+ </ComponentDemo>
341
+
342
+ ### Integer type
343
+
344
+ With `number-type="integer"`, decimal values are truncated to whole numbers on commit. When combined with `percent`, the display value (e.g. 42%) is treated as the integer — so internal values like 0.42 are valid.
345
+
346
+ <ComponentDemo>
347
+ <div style="width: 300px">
348
+ <NumberInput v-model="days" label="Steps" number-type="integer" />
349
+ </div>
350
+
351
+ <template #code>
352
+
353
+ ```vue
354
+ <NumberInput v-model="days" label="Steps" number-type="integer" />
355
+ ```
356
+
357
+ </template>
358
+ </ComponentDemo>
359
+
360
+ ### Decimal places
361
+
362
+ Display precision is inferred from `step` (e.g. `step="0.001"` in percent mode
363
+ shows tenths of a percent). Set `decimals` explicitly to override.
364
+
365
+ <ComponentDemo>
366
+ <div style="width: 300px; display: flex; flex-direction: column; gap: 0.75em">
367
+ <NumberInput
368
+ v-model="coverage"
369
+ label="Coverage (inferred from step)"
370
+ percent
371
+ :step="0.001"
372
+ :max="1"
373
+ />
374
+ <NumberInput
375
+ v-model="r0"
376
+ label="R0 (explicit decimals)"
377
+ :decimals="3"
378
+ :min="0"
379
+ :max="18"
380
+ />
381
+ </div>
382
+
383
+ <template #code>
384
+
385
+ ```vue
386
+ <NumberInput
387
+ v-model="coverage"
388
+ label="Coverage"
389
+ percent
390
+ :step="0.001"
391
+ :max="1"
392
+ />
393
+ <NumberInput v-model="r0" label="R0" :decimals="3" :min="0" :max="18" />
394
+ ```
395
+
396
+ </template>
397
+ </ComponentDemo>
398
+
399
+ ### Required
400
+
401
+ With `required`, clearing the field shows a validation error on commit.
402
+
403
+ <ComponentDemo>
404
+ <div style="width: 300px">
405
+ <NumberInput v-model="days" label="Days" required />
406
+ </div>
407
+
408
+ <template #code>
409
+
410
+ ```vue
411
+ <NumberInput v-model="days" label="Days" required />
412
+ ```
413
+
414
+ </template>
415
+ </ComponentDemo>
416
+
417
+ Combine `required` with `live` to validate as the user types (debounced).
418
+
419
+ <ComponentDemo>
420
+ <div style="width: 300px; display: flex; flex-direction: column; gap: 0.75em">
421
+ <NumberInput v-model="days" label="Days (on blur)" required />
422
+ <NumberInput v-model="days" label="Days (live)" required live />
423
+ </div>
424
+
425
+ <template #code>
426
+
427
+ ```vue
428
+ <NumberInput v-model="days" label="Days (on blur)" required />
429
+ <NumberInput v-model="days" label="Days (live)" required live />
430
+ ```
431
+
432
+ </template>
433
+ </ComponentDemo>
434
+
435
+ ### Hidden label
436
+
437
+ Use `hide-label` to visually hide the label while keeping it available to
438
+ screen readers. Useful when a heading or surrounding context already describes
439
+ the input visually.
440
+
441
+ <ComponentDemo>
442
+ <div style="width: 300px">
443
+ <NumberInput v-model="days" label="Days" hide-label />
444
+ </div>
445
+
446
+ <template #code>
447
+
448
+ ```vue
449
+ <NumberInput v-model="days" label="Days" hide-label />
450
+ ```
451
+
452
+ </template>
453
+ </ComponentDemo>
454
+
455
+ <!--@include: ./_api/number-input.md-->