@cocoar/vue-ui 3.1.0 → 3.2.0-beta.6
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/dist/components/checkbox/CoarCheckbox.vue.d.ts +1 -1
- package/dist/components/checkbox/CoarCheckbox.vue.d.ts.map +1 -1
- package/dist/components/code-block/CoarCodeBlock.vue.d.ts +1 -1
- package/dist/components/code-block/CoarCodeBlock.vue.d.ts.map +1 -1
- package/dist/components/data-list/CoarDataList.vue.d.ts +158 -0
- package/dist/components/data-list/CoarDataList.vue.d.ts.map +1 -0
- package/dist/components/data-list/CoarDataListToolbar.vue.d.ts +30 -0
- package/dist/components/data-list/CoarDataListToolbar.vue.d.ts.map +1 -0
- package/dist/components/data-list/data-list-builder.d.ts +288 -0
- package/dist/components/data-list/data-list-builder.d.ts.map +1 -0
- package/dist/components/data-list/index.d.ts +12 -0
- package/dist/components/data-list/index.d.ts.map +1 -0
- package/dist/components/data-list/internal/compare.d.ts +14 -0
- package/dist/components/data-list/internal/compare.d.ts.map +1 -0
- package/dist/components/data-list/internal/reorder-core.d.ts +46 -0
- package/dist/components/data-list/internal/reorder-core.d.ts.map +1 -0
- package/dist/components/data-list/internal/search.d.ts +16 -0
- package/dist/components/data-list/internal/search.d.ts.map +1 -0
- package/dist/components/data-list/internal/useDataListLines.d.ts +92 -0
- package/dist/components/data-list/internal/useDataListLines.d.ts.map +1 -0
- package/dist/components/data-list/internal/useDataListReorder.d.ts +68 -0
- package/dist/components/data-list/internal/useDataListReorder.d.ts.map +1 -0
- package/dist/components/data-list/internal/useSearchHighlight.d.ts +19 -0
- package/dist/components/data-list/internal/useSearchHighlight.d.ts.map +1 -0
- package/dist/components/data-list/types.d.ts +185 -0
- package/dist/components/data-list/types.d.ts.map +1 -0
- package/dist/components/data-list/useDataListModel.d.ts +79 -0
- package/dist/components/data-list/useDataListModel.d.ts.map +1 -0
- package/dist/components/date-time/_shared/maskito-config.d.ts +7 -2
- package/dist/components/date-time/_shared/maskito-config.d.ts.map +1 -1
- package/dist/components/date-time/_shared/time-helpers.d.ts +11 -4
- package/dist/components/date-time/_shared/time-helpers.d.ts.map +1 -1
- package/dist/components/date-time/_shared/use-date-picker-base.d.ts +1 -1
- package/dist/components/date-time/plain-date-picker/CoarPlainDatePicker.vue.d.ts +1 -1
- package/dist/components/date-time/plain-date-picker/CoarPlainDatePicker.vue.d.ts.map +1 -1
- package/dist/components/date-time/plain-date-time-picker/CoarPlainDateTimePicker.vue.d.ts +1 -1
- package/dist/components/date-time/plain-date-time-picker/CoarPlainDateTimePicker.vue.d.ts.map +1 -1
- package/dist/components/date-time/zoned-date-time-picker/CoarZonedDateTimePicker.vue.d.ts +1 -1
- package/dist/components/date-time/zoned-date-time-picker/CoarZonedDateTimePicker.vue.d.ts.map +1 -1
- package/dist/components/dual-listbox/CoarDualListbox.vue.d.ts +3 -0
- package/dist/components/dual-listbox/CoarDualListbox.vue.d.ts.map +1 -1
- package/dist/components/form-field/CoarFormField.vue.d.ts +1 -1
- package/dist/components/form-field/CoarFormField.vue.d.ts.map +1 -1
- package/dist/components/icon/CoarIcon.vue.d.ts +2 -2
- package/dist/components/icon/CoarIcon.vue.d.ts.map +1 -1
- package/dist/components/listbox/CoarListbox.vue.d.ts +7 -0
- package/dist/components/listbox/CoarListbox.vue.d.ts.map +1 -1
- package/dist/components/number-input/CoarNumberInput.vue.d.ts +1 -1
- package/dist/components/number-input/CoarNumberInput.vue.d.ts.map +1 -1
- package/dist/components/otp-input/CoarOtpInput.vue.d.ts +1 -1
- package/dist/components/otp-input/CoarOtpInput.vue.d.ts.map +1 -1
- package/dist/components/password-input/CoarPasswordInput.vue.d.ts +1 -1
- package/dist/components/password-input/CoarPasswordInput.vue.d.ts.map +1 -1
- package/dist/components/switch/CoarSwitch.vue.d.ts +1 -1
- package/dist/components/switch/CoarSwitch.vue.d.ts.map +1 -1
- package/dist/components/text-input/CoarTextInput.vue.d.ts +1 -1
- package/dist/components/text-input/CoarTextInput.vue.d.ts.map +1 -1
- package/dist/composables/dragRegistry.d.ts +12 -0
- package/dist/composables/dragRegistry.d.ts.map +1 -1
- package/dist/composables/index.d.ts +2 -2
- package/dist/composables/index.d.ts.map +1 -1
- package/dist/composables/useDragDrop.d.ts +62 -6
- package/dist/composables/useDragDrop.d.ts.map +1 -1
- package/dist/composables/useVirtualList.d.ts +21 -1
- package/dist/composables/useVirtualList.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4508 -2039
- package/package.json +5 -3
- package/skills/cocoar-vue-ui/SKILL.md +244 -0
- package/skills/cocoar-vue-ui/references/components/avatar.md +178 -0
- package/skills/cocoar-vue-ui/references/components/badge.md +290 -0
- package/skills/cocoar-vue-ui/references/components/breadcrumb.md +238 -0
- package/skills/cocoar-vue-ui/references/components/button.md +252 -0
- package/skills/cocoar-vue-ui/references/components/calendar/agenda-view.md +353 -0
- package/skills/cocoar-vue-ui/references/components/calendar/coar-calendar.md +1645 -0
- package/skills/cocoar-vue-ui/references/components/calendar/day-view.md +361 -0
- package/skills/cocoar-vue-ui/references/components/calendar/index.md +312 -0
- package/skills/cocoar-vue-ui/references/components/calendar/month-view.md +475 -0
- package/skills/cocoar-vue-ui/references/components/calendar/performance.md +186 -0
- package/skills/cocoar-vue-ui/references/components/calendar/timeline-view.md +301 -0
- package/skills/cocoar-vue-ui/references/components/calendar/week-view.md +382 -0
- package/skills/cocoar-vue-ui/references/components/calendar/work-week-view.md +145 -0
- package/skills/cocoar-vue-ui/references/components/calendar/year-view.md +63 -0
- package/skills/cocoar-vue-ui/references/components/card.md +151 -0
- package/skills/cocoar-vue-ui/references/components/checkbox-group.md +103 -0
- package/skills/cocoar-vue-ui/references/components/checkbox.md +279 -0
- package/skills/cocoar-vue-ui/references/components/code-block.md +241 -0
- package/skills/cocoar-vue-ui/references/components/context-menu.md +355 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/checkbox.md +213 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/date-columns.md +272 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/editing.md +236 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/multi-select.md +193 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/number.md +147 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/select.md +202 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/text.md +127 -0
- package/skills/cocoar-vue-ui/references/components/data-grid.md +1225 -0
- package/skills/cocoar-vue-ui/references/components/data-list.md +2121 -0
- package/skills/cocoar-vue-ui/references/components/date-or-time-picker.md +200 -0
- package/skills/cocoar-vue-ui/references/components/date-picker.md +203 -0
- package/skills/cocoar-vue-ui/references/components/date-time-picker.md +154 -0
- package/skills/cocoar-vue-ui/references/components/date-views.md +212 -0
- package/skills/cocoar-vue-ui/references/components/dialog.md +148 -0
- package/skills/cocoar-vue-ui/references/components/divider.md +157 -0
- package/skills/cocoar-vue-ui/references/components/document-viewer/annotations.md +400 -0
- package/skills/cocoar-vue-ui/references/components/document-viewer/coar-document-viewer.md +327 -0
- package/skills/cocoar-vue-ui/references/components/document-viewer/index.md +234 -0
- package/skills/cocoar-vue-ui/references/components/document-viewer/toolbar.md +221 -0
- package/skills/cocoar-vue-ui/references/components/drag-drop.md +267 -0
- package/skills/cocoar-vue-ui/references/components/dual-listbox.md +449 -0
- package/skills/cocoar-vue-ui/references/components/file-explorer/asset-store.md +327 -0
- package/skills/cocoar-vue-ui/references/components/file-explorer/in-memory-store.md +176 -0
- package/skills/cocoar-vue-ui/references/components/file-explorer/index.md +311 -0
- package/skills/cocoar-vue-ui/references/components/file-explorer/use-file-explorer.md +300 -0
- package/skills/cocoar-vue-ui/references/components/form-field.md +1025 -0
- package/skills/cocoar-vue-ui/references/components/fragment-parser.md +298 -0
- package/skills/cocoar-vue-ui/references/components/link.md +235 -0
- package/skills/cocoar-vue-ui/references/components/listbox.md +575 -0
- package/skills/cocoar-vue-ui/references/components/map/editor.md +448 -0
- package/skills/cocoar-vue-ui/references/components/map/index.md +351 -0
- package/skills/cocoar-vue-ui/references/components/markdown-diagrams.md +210 -0
- package/skills/cocoar-vue-ui/references/components/markdown-editor.md +1478 -0
- package/skills/cocoar-vue-ui/references/components/markdown-embeds.md +387 -0
- package/skills/cocoar-vue-ui/references/components/markdown-form.md +447 -0
- package/skills/cocoar-vue-ui/references/components/markdown.md +276 -0
- package/skills/cocoar-vue-ui/references/components/menu.md +380 -0
- package/skills/cocoar-vue-ui/references/components/mermaid.md +172 -0
- package/skills/cocoar-vue-ui/references/components/navbar.md +147 -0
- package/skills/cocoar-vue-ui/references/components/note.md +96 -0
- package/skills/cocoar-vue-ui/references/components/notice.md +131 -0
- package/skills/cocoar-vue-ui/references/components/number-input.md +215 -0
- package/skills/cocoar-vue-ui/references/components/otp-input.md +324 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/authoring-contract.md +271 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-builder.md +476 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-renderer.md +677 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/custom-elements.md +441 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/idp-integration.md +122 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/index.md +573 -0
- package/skills/cocoar-vue-ui/references/components/pagination.md +150 -0
- package/skills/cocoar-vue-ui/references/components/panel-layout.md +372 -0
- package/skills/cocoar-vue-ui/references/components/password-input.md +175 -0
- package/skills/cocoar-vue-ui/references/components/popconfirm.md +186 -0
- package/skills/cocoar-vue-ui/references/components/popover.md +173 -0
- package/skills/cocoar-vue-ui/references/components/progress-bar.md +178 -0
- package/skills/cocoar-vue-ui/references/components/radio-group.md +225 -0
- package/skills/cocoar-vue-ui/references/components/script-editor.md +1271 -0
- package/skills/cocoar-vue-ui/references/components/segmented-control.md +238 -0
- package/skills/cocoar-vue-ui/references/components/select.md +463 -0
- package/skills/cocoar-vue-ui/references/components/sidebar.md +421 -0
- package/skills/cocoar-vue-ui/references/components/spinner.md +132 -0
- package/skills/cocoar-vue-ui/references/components/switch.md +195 -0
- package/skills/cocoar-vue-ui/references/components/table.md +170 -0
- package/skills/cocoar-vue-ui/references/components/tabs.md +382 -0
- package/skills/cocoar-vue-ui/references/components/tag.md +178 -0
- package/skills/cocoar-vue-ui/references/components/text-input.md +256 -0
- package/skills/cocoar-vue-ui/references/components/toast.md +160 -0
- package/skills/cocoar-vue-ui/references/components/tooltip.md +121 -0
- package/skills/cocoar-vue-ui/references/components/transitions.md +193 -0
- package/skills/cocoar-vue-ui/references/components/tree.md +2388 -0
- package/skills/cocoar-vue-ui/references/components/virtual-list.md +212 -0
- package/skills/cocoar-vue-ui/references/components/wizard.md +251 -0
- package/skills/cocoar-vue-ui/references/components/zoned-date-time-picker.md +177 -0
- package/skills/cocoar-vue-ui/references/foundations/colors.md +708 -0
- package/skills/cocoar-vue-ui/references/foundations/design-principles.md +115 -0
- package/skills/cocoar-vue-ui/references/foundations/icons.md +381 -0
- package/skills/cocoar-vue-ui/references/foundations/localization/formatting.md +530 -0
- package/skills/cocoar-vue-ui/references/foundations/localization/setup.md +86 -0
- package/skills/cocoar-vue-ui/references/foundations/localization/timezones.md +182 -0
- package/skills/cocoar-vue-ui/references/foundations/localization/translations.md +305 -0
- package/skills/cocoar-vue-ui/references/foundations/motion.md +549 -0
- package/skills/cocoar-vue-ui/references/foundations/spacing.md +330 -0
- package/skills/cocoar-vue-ui/references/foundations/theming.md +140 -0
- package/skills/cocoar-vue-ui/references/foundations/typography.md +206 -0
- package/skills/cocoar-vue-ui/references/guide/error-handling.md +162 -0
- package/skills/cocoar-vue-ui/references/guide/getting-started.md +119 -0
- package/skills/cocoar-vue-ui/references/guide/migration-page-builder-3.md +207 -0
- package/skills/cocoar-vue-ui/references/guide/migration.md +140 -0
- package/skills/cocoar-vue-ui/references/guide/theming.md +98 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
<!-- Generated from apps/docs/components/number-input.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
|
|
2
|
+
|
|
3
|
+
# Number Input
|
|
4
|
+
|
|
5
|
+
A purpose-built input for numeric values. It enforces min/max bounds, supports configurable step increments, and offers optional stepper buttons so users can nudge values up or down without typing.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { CoarNumberInput } from '@cocoar/vue-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Basic Usage
|
|
12
|
+
|
|
13
|
+
Bind a number with `v-model`. The component handles parsing and formatting automatically -- users can only enter valid numeric characters.
|
|
14
|
+
|
|
15
|
+
**Demo — `number-input/demos/BasicNumberInput.vue`**
|
|
16
|
+
|
|
17
|
+
```vue
|
|
18
|
+
<template>
|
|
19
|
+
<div style="display: flex; flex-direction: column; gap: 12px; max-width: 320px;">
|
|
20
|
+
<CoarFormField label="Count" hint="Whole numbers only">
|
|
21
|
+
<CoarNumberInput
|
|
22
|
+
v-model="value"
|
|
23
|
+
placeholder="Enter a number"
|
|
24
|
+
/>
|
|
25
|
+
</CoarFormField>
|
|
26
|
+
<span style="font-size: 13px; color: #64748b;">Value: {{ value ?? 'empty' }}</span>
|
|
27
|
+
</div>
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<script setup lang="ts">
|
|
31
|
+
import { ref } from 'vue';
|
|
32
|
+
import { CoarNumberInput, CoarFormField } from '@cocoar/vue-ui';
|
|
33
|
+
|
|
34
|
+
const value = ref<number | null>(null);
|
|
35
|
+
</script>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Min / Max / Step
|
|
39
|
+
|
|
40
|
+
Set boundaries with `min` and `max`, and control the increment size with `step`. Values are clamped on blur and via stepper controls.
|
|
41
|
+
|
|
42
|
+
**Demo — `number-input/demos/NumberInputMinMaxStep.vue`**
|
|
43
|
+
|
|
44
|
+
```vue
|
|
45
|
+
<template>
|
|
46
|
+
<div style="display: flex; flex-direction: column; gap: 12px; max-width: 320px;">
|
|
47
|
+
<CoarFormField label="Percentage" hint="0-100 in steps of 5">
|
|
48
|
+
<CoarNumberInput
|
|
49
|
+
v-model="percentage"
|
|
50
|
+
:min="0"
|
|
51
|
+
:max="100"
|
|
52
|
+
:step="5"
|
|
53
|
+
suffix="%"
|
|
54
|
+
/>
|
|
55
|
+
</CoarFormField>
|
|
56
|
+
<span style="font-size: 13px; color: #64748b;">Value: {{ percentage ?? 'empty' }}</span>
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<script setup lang="ts">
|
|
61
|
+
import { ref } from 'vue';
|
|
62
|
+
import { CoarNumberInput, CoarFormField } from '@cocoar/vue-ui';
|
|
63
|
+
|
|
64
|
+
const percentage = ref<number | null>(75);
|
|
65
|
+
</script>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Stepper Buttons
|
|
69
|
+
|
|
70
|
+
Show `'increment'`, `'decrement'`, or `'both'` stepper buttons, or hide them with `'none'` (the default). Useful for quantity selectors, rating inputs, and anywhere precision matters.
|
|
71
|
+
|
|
72
|
+
**Demo — `number-input/demos/NumberInputStepper.vue`**
|
|
73
|
+
|
|
74
|
+
```vue
|
|
75
|
+
<template>
|
|
76
|
+
<div style="display: flex; flex-direction: column; gap: 12px; max-width: 320px;">
|
|
77
|
+
<CoarFormField label="Quantity (both)">
|
|
78
|
+
<CoarNumberInput
|
|
79
|
+
v-model="quantity"
|
|
80
|
+
stepper-buttons="both"
|
|
81
|
+
:min="1"
|
|
82
|
+
:max="99"
|
|
83
|
+
/>
|
|
84
|
+
</CoarFormField>
|
|
85
|
+
<CoarFormField label="Price (increment only)">
|
|
86
|
+
<CoarNumberInput
|
|
87
|
+
v-model="price"
|
|
88
|
+
stepper-buttons="increment"
|
|
89
|
+
:min="0"
|
|
90
|
+
:step="0.01"
|
|
91
|
+
suffix="€"
|
|
92
|
+
/>
|
|
93
|
+
</CoarFormField>
|
|
94
|
+
</div>
|
|
95
|
+
</template>
|
|
96
|
+
|
|
97
|
+
<script setup lang="ts">
|
|
98
|
+
import { ref } from 'vue';
|
|
99
|
+
import { CoarNumberInput, CoarFormField } from '@cocoar/vue-ui';
|
|
100
|
+
|
|
101
|
+
const quantity = ref<number | null>(1);
|
|
102
|
+
const price = ref<number | null>(null);
|
|
103
|
+
</script>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## States
|
|
107
|
+
|
|
108
|
+
All the standard form states are supported: `disabled`, `readonly`, `required`, and `error`.
|
|
109
|
+
|
|
110
|
+
**Demo — `number-input/demos/NumberInputStates.vue`**
|
|
111
|
+
|
|
112
|
+
```vue
|
|
113
|
+
<template>
|
|
114
|
+
<div style="display: flex; flex-direction: column; gap: 12px; max-width: 320px;">
|
|
115
|
+
<CoarFormField label="Disabled">
|
|
116
|
+
<CoarNumberInput :model-value="42" :disabled="true" />
|
|
117
|
+
</CoarFormField>
|
|
118
|
+
<CoarFormField label="Readonly">
|
|
119
|
+
<CoarNumberInput :model-value="42" :readonly="true" />
|
|
120
|
+
</CoarFormField>
|
|
121
|
+
<CoarFormField label="Required" required>
|
|
122
|
+
<CoarNumberInput :required="true" placeholder="Required" />
|
|
123
|
+
</CoarFormField>
|
|
124
|
+
<CoarFormField label="With Error" error="Value must be between 1 and 100">
|
|
125
|
+
<CoarNumberInput />
|
|
126
|
+
</CoarFormField>
|
|
127
|
+
</div>
|
|
128
|
+
</template>
|
|
129
|
+
|
|
130
|
+
<script setup lang="ts">
|
|
131
|
+
import { CoarNumberInput, CoarFormField } from '@cocoar/vue-ui';
|
|
132
|
+
</script>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Sizes
|
|
136
|
+
|
|
137
|
+
Four size variants that align with every other Cocoar form control, so your layouts stay consistent.
|
|
138
|
+
|
|
139
|
+
**Demo — `number-input/demos/NumberInputSizes.vue`**
|
|
140
|
+
|
|
141
|
+
```vue
|
|
142
|
+
<template>
|
|
143
|
+
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px;">
|
|
144
|
+
<CoarFormField label="Extra Small">
|
|
145
|
+
<CoarNumberInput size="xs" placeholder="xs" />
|
|
146
|
+
</CoarFormField>
|
|
147
|
+
<CoarFormField label="Small">
|
|
148
|
+
<CoarNumberInput size="s" placeholder="s" />
|
|
149
|
+
</CoarFormField>
|
|
150
|
+
<CoarFormField label="Medium">
|
|
151
|
+
<CoarNumberInput size="m" placeholder="m" />
|
|
152
|
+
</CoarFormField>
|
|
153
|
+
<CoarFormField label="Large">
|
|
154
|
+
<CoarNumberInput size="l" placeholder="l" />
|
|
155
|
+
</CoarFormField>
|
|
156
|
+
</div>
|
|
157
|
+
</template>
|
|
158
|
+
|
|
159
|
+
<script setup lang="ts">
|
|
160
|
+
import { CoarNumberInput, CoarFormField } from '@cocoar/vue-ui';
|
|
161
|
+
</script>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Accessibility
|
|
165
|
+
|
|
166
|
+
### Keyboard Navigation
|
|
167
|
+
|
|
168
|
+
| Key | Action |
|
|
169
|
+
|-----|--------|
|
|
170
|
+
| `Tab` | Move focus to input |
|
|
171
|
+
| `Arrow Up` | Increment value by step |
|
|
172
|
+
| `Arrow Down` | Decrement value by step |
|
|
173
|
+
|
|
174
|
+
> **Info**
|
|
175
|
+
>
|
|
176
|
+
> Stepper buttons are keyboard accessible. Min/max bounds are enforced on blur and via stepper controls.
|
|
177
|
+
|
|
178
|
+
### Screen Reader Support
|
|
179
|
+
|
|
180
|
+
- Label text announces on focus
|
|
181
|
+
- Required state properly communicated
|
|
182
|
+
- Error messages linked via `aria-describedby`
|
|
183
|
+
- Value constraints announced through `aria-valuemin`, `aria-valuemax`
|
|
184
|
+
|
|
185
|
+
## i18n Keys
|
|
186
|
+
|
|
187
|
+
These keys can be translated via [`@cocoar/vue-localization`](../foundations/localization/translations.md).
|
|
188
|
+
|
|
189
|
+
| Key | Default (English) | Used as |
|
|
190
|
+
|-----|-------------------|---------|
|
|
191
|
+
| `coar.ui.numberInput.clear` | `'Clear'` | Clear button `aria-label` |
|
|
192
|
+
| `coar.ui.numberInput.decrease` | `'Decrease value'` | Decrement button `aria-label` |
|
|
193
|
+
| `coar.ui.numberInput.increase` | `'Increase value'` | Increment button `aria-label` |
|
|
194
|
+
|
|
195
|
+
## API
|
|
196
|
+
|
|
197
|
+
### Props
|
|
198
|
+
|
|
199
|
+
| Prop | Type | Default | Description |
|
|
200
|
+
|------|------|---------|-------------|
|
|
201
|
+
| `v-model` | `number \| null` | `null` | Current numeric value |
|
|
202
|
+
| `placeholder` | `string` | `''` | Placeholder text |
|
|
203
|
+
| `min` | `number` | `undefined` | Minimum allowed value |
|
|
204
|
+
| `max` | `number` | `undefined` | Maximum allowed value |
|
|
205
|
+
| `step` | `number` | `1` | Step increment |
|
|
206
|
+
| `decimals` | `number` | `0` | Number of decimal places |
|
|
207
|
+
| `prefix` | `string` | `''` | Prefix text |
|
|
208
|
+
| `suffix` | `string` | `''` | Suffix text (e.g. '%', 'EUR') |
|
|
209
|
+
| `stepperButtons` | `'none' \| 'increment' \| 'decrement' \| 'both'` | `'none'` | Stepper button mode |
|
|
210
|
+
| `clearable` | `boolean` | `false` | Show clear button when input has value |
|
|
211
|
+
| `size` | `'xs' \| 's' \| 'm' \| 'l'` | `'m'` | Input size |
|
|
212
|
+
| `disabled` | `boolean` | `false` | Disable the input |
|
|
213
|
+
| `readonly` | `boolean` | `false` | Make read-only |
|
|
214
|
+
| `required` | `boolean` | `false` | Mark as required |
|
|
215
|
+
| `error` | `boolean` | `false` | Error state (auto-injected from `CoarFormField`) |
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
<!-- Generated from apps/docs/components/otp-input.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
|
|
2
|
+
|
|
3
|
+
# OTP Input (New in 2.0)
|
|
4
|
+
|
|
5
|
+
The N-cell input for verification codes — 2FA / TOTP from authenticator apps, SMS one-time passwords, claim codes, short PINs. Auto-advances as the user types, jumps back on Backspace, spreads pasted codes across cells, and fires a `complete` event the moment the last cell fills so you can submit without a button click.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { CoarOtpInput, CoarFormField } from '@cocoar/vue-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Basic Usage
|
|
12
|
+
|
|
13
|
+
Wire it up with `v-model` and listen to `@complete` for auto-submit. The value is the assembled string — `"123456"` once all six cells are filled.
|
|
14
|
+
|
|
15
|
+
**Demo — `otp-input/demos/BasicOtpInput.vue`**
|
|
16
|
+
|
|
17
|
+
```vue
|
|
18
|
+
<template>
|
|
19
|
+
<div style="display: flex; flex-direction: column; gap: 12px; max-width: 360px;">
|
|
20
|
+
<CoarFormField label="Verification code" hint="Enter the 6-digit code from your authenticator app">
|
|
21
|
+
<CoarOtpInput v-model="value" auto-focus @complete="onComplete" />
|
|
22
|
+
</CoarFormField>
|
|
23
|
+
<div style="font-size: 13px; color: #64748b;">
|
|
24
|
+
<div>Value: <strong>{{ value || 'empty' }}</strong></div>
|
|
25
|
+
<div v-if="submittedValue">Auto-submitted: <strong>{{ submittedValue }}</strong></div>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<script setup lang="ts">
|
|
31
|
+
import { ref } from 'vue';
|
|
32
|
+
import { CoarOtpInput, CoarFormField } from '@cocoar/vue-ui';
|
|
33
|
+
|
|
34
|
+
const value = ref('');
|
|
35
|
+
const submittedValue = ref('');
|
|
36
|
+
|
|
37
|
+
function onComplete(code: string) {
|
|
38
|
+
submittedValue.value = code;
|
|
39
|
+
// In real apps, call your verify endpoint here.
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Length
|
|
45
|
+
|
|
46
|
+
The default 6 cells match TOTP / SMS codes (RFC 6238). For shorter PINs or longer backup codes, override with the `length` prop.
|
|
47
|
+
|
|
48
|
+
**Demo — `otp-input/demos/OtpInputLength.vue`**
|
|
49
|
+
|
|
50
|
+
```vue
|
|
51
|
+
<template>
|
|
52
|
+
<div style="display: flex; flex-direction: column; gap: 16px;">
|
|
53
|
+
<div>
|
|
54
|
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">4-digit PIN</div>
|
|
55
|
+
<CoarOtpInput v-model="pin4" :length="4" />
|
|
56
|
+
</div>
|
|
57
|
+
<div>
|
|
58
|
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">6-digit TOTP (default)</div>
|
|
59
|
+
<CoarOtpInput v-model="pin6" />
|
|
60
|
+
</div>
|
|
61
|
+
<div>
|
|
62
|
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">8-digit backup code</div>
|
|
63
|
+
<CoarOtpInput v-model="pin8" :length="8" />
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</template>
|
|
67
|
+
|
|
68
|
+
<script setup lang="ts">
|
|
69
|
+
import { ref } from 'vue';
|
|
70
|
+
import { CoarOtpInput } from '@cocoar/vue-ui';
|
|
71
|
+
|
|
72
|
+
const pin4 = ref('');
|
|
73
|
+
const pin6 = ref('');
|
|
74
|
+
const pin8 = ref('');
|
|
75
|
+
</script>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Type
|
|
79
|
+
|
|
80
|
+
`type="numeric"` (the default) rejects non-digits at the keystroke level and tells mobile browsers to open the numeric keyboard via `inputmode="numeric"`. `"alphanumeric"` accepts `[A-Za-z0-9]` for claim / recovery codes. `"text"` accepts any single character.
|
|
81
|
+
|
|
82
|
+
`mask` renders the cells as `<input type="password">` — the value is visually hidden while the keyboard interaction stays normal. Useful for PINs or sensitive codes in shared-screen contexts.
|
|
83
|
+
|
|
84
|
+
**Demo — `otp-input/demos/OtpInputTypes.vue`**
|
|
85
|
+
|
|
86
|
+
```vue
|
|
87
|
+
<template>
|
|
88
|
+
<div style="display: flex; flex-direction: column; gap: 16px;">
|
|
89
|
+
<div>
|
|
90
|
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">numeric (default) — digits only</div>
|
|
91
|
+
<CoarOtpInput v-model="numeric" type="numeric" />
|
|
92
|
+
</div>
|
|
93
|
+
<div>
|
|
94
|
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">alphanumeric — letters + digits (claim codes, recovery keys)</div>
|
|
95
|
+
<CoarOtpInput v-model="alpha" type="alphanumeric" :length="8" />
|
|
96
|
+
</div>
|
|
97
|
+
<div>
|
|
98
|
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">mask=true — visually mask digits as ●</div>
|
|
99
|
+
<CoarOtpInput v-model="masked" mask :length="4" />
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
</template>
|
|
103
|
+
|
|
104
|
+
<script setup lang="ts">
|
|
105
|
+
import { ref } from 'vue';
|
|
106
|
+
import { CoarOtpInput } from '@cocoar/vue-ui';
|
|
107
|
+
|
|
108
|
+
const numeric = ref('');
|
|
109
|
+
const alpha = ref('');
|
|
110
|
+
const masked = ref('');
|
|
111
|
+
</script>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Custom filtering: `transform` and `accept`
|
|
115
|
+
|
|
116
|
+
The built-in `type` classes (`numeric` / `alphanumeric` / `text`) cover the common cases, but real codes have quirks. Two hooks let you fine-tune per character without losing the rest of the input pipeline:
|
|
117
|
+
|
|
118
|
+
- **`transform(char) => string`** — runs FIRST. Rewrites a character before it's committed. Return a different char to substitute, return `''` to drop. Classic use: `c => c.toUpperCase()` so the user can type lowercase but the code stays canonical.
|
|
119
|
+
- **`accept(char) => boolean`** — runs AFTER `type` + `transform`. Reject characters the built-in class would otherwise allow. Classic use: block visually-ambiguous chars in printed claim codes so `O` (letter) and `0` (number) don't get confused.
|
|
120
|
+
|
|
121
|
+
Both hooks fire on every keystroke AND on every character of a pasted string — paste-spread runs through the same sanitizer, so a clipboard payload of `"abc123"` ends up as `"ABC123"` if `transform` uppercases.
|
|
122
|
+
|
|
123
|
+
**Demo — `otp-input/demos/OtpInputTransform.vue`**
|
|
124
|
+
|
|
125
|
+
```vue
|
|
126
|
+
<template>
|
|
127
|
+
<div style="display: flex; flex-direction: column; gap: 16px;">
|
|
128
|
+
<div>
|
|
129
|
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">
|
|
130
|
+
Auto-uppercase — try typing <code>abc123</code>
|
|
131
|
+
</div>
|
|
132
|
+
<CoarOtpInput
|
|
133
|
+
v-model="upper"
|
|
134
|
+
type="alphanumeric"
|
|
135
|
+
:length="6"
|
|
136
|
+
:transform="(c) => c.toUpperCase()"
|
|
137
|
+
/>
|
|
138
|
+
<div style="font-size: 12px; color: #64748b; margin-top: 6px;">
|
|
139
|
+
Value: <strong>{{ upper || 'empty' }}</strong>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<div>
|
|
144
|
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">
|
|
145
|
+
Confusable-blocking — rejects <code>O / 0 / l / 1 / I</code> (good for claim codes)
|
|
146
|
+
</div>
|
|
147
|
+
<CoarOtpInput
|
|
148
|
+
v-model="claim"
|
|
149
|
+
type="alphanumeric"
|
|
150
|
+
:length="8"
|
|
151
|
+
:transform="(c) => c.toUpperCase()"
|
|
152
|
+
:accept="(c) => !/[O0lI1]/.test(c)"
|
|
153
|
+
/>
|
|
154
|
+
<div style="font-size: 12px; color: #64748b; margin-top: 6px;">
|
|
155
|
+
Value: <strong>{{ claim || 'empty' }}</strong>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<div>
|
|
160
|
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">
|
|
161
|
+
Strip whitespace on paste — try pasting <code>1 2 3 4 5 6</code>
|
|
162
|
+
</div>
|
|
163
|
+
<CoarOtpInput
|
|
164
|
+
v-model="stripped"
|
|
165
|
+
type="numeric"
|
|
166
|
+
:transform="(c) => (/\s/.test(c) ? '' : c)"
|
|
167
|
+
/>
|
|
168
|
+
<div style="font-size: 12px; color: #64748b; margin-top: 6px;">
|
|
169
|
+
Value: <strong>{{ stripped || 'empty' }}</strong>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
</template>
|
|
174
|
+
|
|
175
|
+
<script setup lang="ts">
|
|
176
|
+
import { ref } from 'vue';
|
|
177
|
+
import { CoarOtpInput } from '@cocoar/vue-ui';
|
|
178
|
+
|
|
179
|
+
const upper = ref('');
|
|
180
|
+
const claim = ref('');
|
|
181
|
+
const stripped = ref('');
|
|
182
|
+
</script>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Validation
|
|
186
|
+
|
|
187
|
+
Drop the OTP input inside `CoarFormField` and the error state flows in automatically — the field's red ring + error message work the same as any other input. The `@complete` event is your "user finished typing" signal; verify against your backend and surface the result via `error`.
|
|
188
|
+
|
|
189
|
+
**Demo — `otp-input/demos/OtpInputValidation.vue`**
|
|
190
|
+
|
|
191
|
+
```vue
|
|
192
|
+
<template>
|
|
193
|
+
<div style="display: flex; flex-direction: column; gap: 16px; max-width: 360px;">
|
|
194
|
+
<CoarFormField
|
|
195
|
+
label="Verification code"
|
|
196
|
+
:error="error"
|
|
197
|
+
hint="Try 123456 — anything else triggers an error"
|
|
198
|
+
>
|
|
199
|
+
<CoarOtpInput v-model="value" auto-focus @complete="verify" />
|
|
200
|
+
</CoarFormField>
|
|
201
|
+
<div v-if="verified" style="font-size: 13px; color: var(--coar-text-semantic-success-bold, #16a34a);">
|
|
202
|
+
✓ Code accepted
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
</template>
|
|
206
|
+
|
|
207
|
+
<script setup lang="ts">
|
|
208
|
+
import { ref } from 'vue';
|
|
209
|
+
import { CoarOtpInput, CoarFormField } from '@cocoar/vue-ui';
|
|
210
|
+
|
|
211
|
+
const value = ref('');
|
|
212
|
+
const error = ref('');
|
|
213
|
+
const verified = ref(false);
|
|
214
|
+
|
|
215
|
+
function verify(code: string) {
|
|
216
|
+
if (code === '123456') {
|
|
217
|
+
error.value = '';
|
|
218
|
+
verified.value = true;
|
|
219
|
+
} else {
|
|
220
|
+
error.value = 'Invalid code. Try 123456.';
|
|
221
|
+
verified.value = false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
</script>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Sizes
|
|
228
|
+
|
|
229
|
+
Four sizes match the rest of the form-input family (`CoarTextInput`, `CoarNumberInput`, etc.) — `xs` / `s` / `m` (default) / `l`. Cell width tracks the size token, so the OTP input lines up vertically with neighbouring inputs in a form.
|
|
230
|
+
|
|
231
|
+
**Demo — `otp-input/demos/OtpInputSizes.vue`**
|
|
232
|
+
|
|
233
|
+
```vue
|
|
234
|
+
<template>
|
|
235
|
+
<div style="display: flex; flex-direction: column; gap: 16px;">
|
|
236
|
+
<div>
|
|
237
|
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">xs</div>
|
|
238
|
+
<CoarOtpInput v-model="xs" size="xs" />
|
|
239
|
+
</div>
|
|
240
|
+
<div>
|
|
241
|
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">s</div>
|
|
242
|
+
<CoarOtpInput v-model="s" size="s" />
|
|
243
|
+
</div>
|
|
244
|
+
<div>
|
|
245
|
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">m (default)</div>
|
|
246
|
+
<CoarOtpInput v-model="m" size="m" />
|
|
247
|
+
</div>
|
|
248
|
+
<div>
|
|
249
|
+
<div style="font-size: 12px; color: #64748b; margin-bottom: 6px;">l</div>
|
|
250
|
+
<CoarOtpInput v-model="l" size="l" />
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
</template>
|
|
254
|
+
|
|
255
|
+
<script setup lang="ts">
|
|
256
|
+
import { ref } from 'vue';
|
|
257
|
+
import { CoarOtpInput } from '@cocoar/vue-ui';
|
|
258
|
+
|
|
259
|
+
const xs = ref('');
|
|
260
|
+
const s = ref('');
|
|
261
|
+
const m = ref('');
|
|
262
|
+
const l = ref('');
|
|
263
|
+
</script>
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Behavior
|
|
267
|
+
|
|
268
|
+
| Interaction | Result |
|
|
269
|
+
|---|---|
|
|
270
|
+
| Type a character in cell `i` | Cell fills, focus auto-advances to `i + 1`. |
|
|
271
|
+
| Backspace on a filled cell | Clears the cell (stays put). |
|
|
272
|
+
| Backspace on an empty cell | Jumps to `i − 1` and clears it. |
|
|
273
|
+
| Delete on a filled cell | Clears the cell (stays put). |
|
|
274
|
+
| Arrow Left / Right | Moves focus between cells. |
|
|
275
|
+
| Home / End | First / last cell. |
|
|
276
|
+
| Type into a filled cell | Replaces its content (selection ensures overwrite). |
|
|
277
|
+
| Paste `"123456"` in cell 0 | Spreads across cells 0–5. Strips chars that don't match `type`. |
|
|
278
|
+
| Paste a 6-char code in cell 2 | Spreads from cell 2 onward, stopping at the last cell. |
|
|
279
|
+
| All cells filled | Fires `@complete` with the assembled string. |
|
|
280
|
+
| Tab | Moves focus *out* of the group from any cell — the entire OTP input is one tab-stop in practice. |
|
|
281
|
+
|
|
282
|
+
### Mobile SMS autofill
|
|
283
|
+
|
|
284
|
+
The first cell carries `autocomplete="one-time-code"` by default, so iOS and Android offer the SMS autofill chip when a verification text arrives. Override via the `autocomplete` prop if your app uses a different signal (`autocomplete="off"` to opt out entirely).
|
|
285
|
+
|
|
286
|
+
## API
|
|
287
|
+
|
|
288
|
+
### Props
|
|
289
|
+
|
|
290
|
+
| Prop | Type | Default | Description |
|
|
291
|
+
|---|---|---|---|
|
|
292
|
+
| `modelValue` (`v-model`) | `string` | `''` | The assembled code. Partial fills work — `"12"` means cells 0–1 are filled, the rest empty. |
|
|
293
|
+
| `length` | `number` | `6` | Number of cells. |
|
|
294
|
+
| `type` | `'numeric' \| 'alphanumeric' \| 'text'` | `'numeric'` | Character class accepted per cell. |
|
|
295
|
+
| `mask` | `boolean` | `false` | Render cells as `type="password"`. |
|
|
296
|
+
| `autoFocus` | `boolean` | `false` | Focus the first cell on mount. |
|
|
297
|
+
| `size` | `'xs' \| 's' \| 'm' \| 'l'` | `'m'` | Cell size — matches the form-input family. |
|
|
298
|
+
| `disabled` | `boolean` | `false` | Disable all cells. |
|
|
299
|
+
| `readonly` | `boolean` | `false` | All cells read-only. |
|
|
300
|
+
| `required` | `boolean` | `false` | Marks the group as required (picked up by `CoarFormField`). |
|
|
301
|
+
| `error` | `boolean` | `false` | Error state. Auto-injected from `CoarFormField`. |
|
|
302
|
+
| `placeholder` | `string` | `''` | Single-char placeholder shown in empty cells. |
|
|
303
|
+
| `id` | `string` | _auto_ | HTML `id` for the first cell (and aria reference target). |
|
|
304
|
+
| `name` | `string` | `''` | HTML `name` prefix — each cell gets `${name}-${i}`. |
|
|
305
|
+
| `autocomplete` | `string` | `'one-time-code'` | First cell's `autocomplete` value. |
|
|
306
|
+
| `transform` | `(char: string) => string` | _none_ | Rewrite a character before commit. Return `''` to drop. Runs before `type` + `accept`. |
|
|
307
|
+
| `accept` | `(char: string) => boolean` | _none_ | Per-character accept predicate ANDed with `type`. Return `false` to reject. |
|
|
308
|
+
|
|
309
|
+
### Events
|
|
310
|
+
|
|
311
|
+
| Event | Payload | Notes |
|
|
312
|
+
|---|---|---|
|
|
313
|
+
| `update:modelValue` | `string` | Standard `v-model` emit. |
|
|
314
|
+
| `complete` | `string` | All cells filled — assembled string. Wire to your verify call. |
|
|
315
|
+
| `focused` | `FocusEvent` | A cell gained focus. |
|
|
316
|
+
| `blurred` | `FocusEvent` | A cell lost focus. |
|
|
317
|
+
|
|
318
|
+
## Accessibility
|
|
319
|
+
|
|
320
|
+
- The component is a `role="group"` with `aria-label="Verification code, N digits"`.
|
|
321
|
+
- Each cell is a real `<input>` with `aria-label="Digit i of N"` so screen readers announce position.
|
|
322
|
+
- `aria-invalid` propagates to every cell when the error state is set.
|
|
323
|
+
- Cell focus is keyboard-driven (Tab into the first cell, arrows / auto-advance inside, Tab out at any cell).
|
|
324
|
+
- Mobile screen readers respect the per-cell input semantics — the SMS-autofill chip on iOS Safari also targets the first cell correctly.
|