@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.
Files changed (179) hide show
  1. package/dist/components/checkbox/CoarCheckbox.vue.d.ts +1 -1
  2. package/dist/components/checkbox/CoarCheckbox.vue.d.ts.map +1 -1
  3. package/dist/components/code-block/CoarCodeBlock.vue.d.ts +1 -1
  4. package/dist/components/code-block/CoarCodeBlock.vue.d.ts.map +1 -1
  5. package/dist/components/data-list/CoarDataList.vue.d.ts +158 -0
  6. package/dist/components/data-list/CoarDataList.vue.d.ts.map +1 -0
  7. package/dist/components/data-list/CoarDataListToolbar.vue.d.ts +30 -0
  8. package/dist/components/data-list/CoarDataListToolbar.vue.d.ts.map +1 -0
  9. package/dist/components/data-list/data-list-builder.d.ts +288 -0
  10. package/dist/components/data-list/data-list-builder.d.ts.map +1 -0
  11. package/dist/components/data-list/index.d.ts +12 -0
  12. package/dist/components/data-list/index.d.ts.map +1 -0
  13. package/dist/components/data-list/internal/compare.d.ts +14 -0
  14. package/dist/components/data-list/internal/compare.d.ts.map +1 -0
  15. package/dist/components/data-list/internal/reorder-core.d.ts +46 -0
  16. package/dist/components/data-list/internal/reorder-core.d.ts.map +1 -0
  17. package/dist/components/data-list/internal/search.d.ts +16 -0
  18. package/dist/components/data-list/internal/search.d.ts.map +1 -0
  19. package/dist/components/data-list/internal/useDataListLines.d.ts +92 -0
  20. package/dist/components/data-list/internal/useDataListLines.d.ts.map +1 -0
  21. package/dist/components/data-list/internal/useDataListReorder.d.ts +68 -0
  22. package/dist/components/data-list/internal/useDataListReorder.d.ts.map +1 -0
  23. package/dist/components/data-list/internal/useSearchHighlight.d.ts +19 -0
  24. package/dist/components/data-list/internal/useSearchHighlight.d.ts.map +1 -0
  25. package/dist/components/data-list/types.d.ts +185 -0
  26. package/dist/components/data-list/types.d.ts.map +1 -0
  27. package/dist/components/data-list/useDataListModel.d.ts +79 -0
  28. package/dist/components/data-list/useDataListModel.d.ts.map +1 -0
  29. package/dist/components/date-time/_shared/maskito-config.d.ts +7 -2
  30. package/dist/components/date-time/_shared/maskito-config.d.ts.map +1 -1
  31. package/dist/components/date-time/_shared/time-helpers.d.ts +11 -4
  32. package/dist/components/date-time/_shared/time-helpers.d.ts.map +1 -1
  33. package/dist/components/date-time/_shared/use-date-picker-base.d.ts +1 -1
  34. package/dist/components/date-time/plain-date-picker/CoarPlainDatePicker.vue.d.ts +1 -1
  35. package/dist/components/date-time/plain-date-picker/CoarPlainDatePicker.vue.d.ts.map +1 -1
  36. package/dist/components/date-time/plain-date-time-picker/CoarPlainDateTimePicker.vue.d.ts +1 -1
  37. package/dist/components/date-time/plain-date-time-picker/CoarPlainDateTimePicker.vue.d.ts.map +1 -1
  38. package/dist/components/date-time/zoned-date-time-picker/CoarZonedDateTimePicker.vue.d.ts +1 -1
  39. package/dist/components/date-time/zoned-date-time-picker/CoarZonedDateTimePicker.vue.d.ts.map +1 -1
  40. package/dist/components/dual-listbox/CoarDualListbox.vue.d.ts +3 -0
  41. package/dist/components/dual-listbox/CoarDualListbox.vue.d.ts.map +1 -1
  42. package/dist/components/form-field/CoarFormField.vue.d.ts +1 -1
  43. package/dist/components/form-field/CoarFormField.vue.d.ts.map +1 -1
  44. package/dist/components/icon/CoarIcon.vue.d.ts +2 -2
  45. package/dist/components/icon/CoarIcon.vue.d.ts.map +1 -1
  46. package/dist/components/listbox/CoarListbox.vue.d.ts +7 -0
  47. package/dist/components/listbox/CoarListbox.vue.d.ts.map +1 -1
  48. package/dist/components/number-input/CoarNumberInput.vue.d.ts +1 -1
  49. package/dist/components/number-input/CoarNumberInput.vue.d.ts.map +1 -1
  50. package/dist/components/otp-input/CoarOtpInput.vue.d.ts +1 -1
  51. package/dist/components/otp-input/CoarOtpInput.vue.d.ts.map +1 -1
  52. package/dist/components/password-input/CoarPasswordInput.vue.d.ts +1 -1
  53. package/dist/components/password-input/CoarPasswordInput.vue.d.ts.map +1 -1
  54. package/dist/components/switch/CoarSwitch.vue.d.ts +1 -1
  55. package/dist/components/switch/CoarSwitch.vue.d.ts.map +1 -1
  56. package/dist/components/text-input/CoarTextInput.vue.d.ts +1 -1
  57. package/dist/components/text-input/CoarTextInput.vue.d.ts.map +1 -1
  58. package/dist/composables/dragRegistry.d.ts +12 -0
  59. package/dist/composables/dragRegistry.d.ts.map +1 -1
  60. package/dist/composables/index.d.ts +2 -2
  61. package/dist/composables/index.d.ts.map +1 -1
  62. package/dist/composables/useDragDrop.d.ts +62 -6
  63. package/dist/composables/useDragDrop.d.ts.map +1 -1
  64. package/dist/composables/useVirtualList.d.ts +21 -1
  65. package/dist/composables/useVirtualList.d.ts.map +1 -1
  66. package/dist/index.css +1 -1
  67. package/dist/index.d.ts +4 -2
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +4508 -2039
  70. package/package.json +5 -3
  71. package/skills/cocoar-vue-ui/SKILL.md +244 -0
  72. package/skills/cocoar-vue-ui/references/components/avatar.md +178 -0
  73. package/skills/cocoar-vue-ui/references/components/badge.md +290 -0
  74. package/skills/cocoar-vue-ui/references/components/breadcrumb.md +238 -0
  75. package/skills/cocoar-vue-ui/references/components/button.md +252 -0
  76. package/skills/cocoar-vue-ui/references/components/calendar/agenda-view.md +353 -0
  77. package/skills/cocoar-vue-ui/references/components/calendar/coar-calendar.md +1645 -0
  78. package/skills/cocoar-vue-ui/references/components/calendar/day-view.md +361 -0
  79. package/skills/cocoar-vue-ui/references/components/calendar/index.md +312 -0
  80. package/skills/cocoar-vue-ui/references/components/calendar/month-view.md +475 -0
  81. package/skills/cocoar-vue-ui/references/components/calendar/performance.md +186 -0
  82. package/skills/cocoar-vue-ui/references/components/calendar/timeline-view.md +301 -0
  83. package/skills/cocoar-vue-ui/references/components/calendar/week-view.md +382 -0
  84. package/skills/cocoar-vue-ui/references/components/calendar/work-week-view.md +145 -0
  85. package/skills/cocoar-vue-ui/references/components/calendar/year-view.md +63 -0
  86. package/skills/cocoar-vue-ui/references/components/card.md +151 -0
  87. package/skills/cocoar-vue-ui/references/components/checkbox-group.md +103 -0
  88. package/skills/cocoar-vue-ui/references/components/checkbox.md +279 -0
  89. package/skills/cocoar-vue-ui/references/components/code-block.md +241 -0
  90. package/skills/cocoar-vue-ui/references/components/context-menu.md +355 -0
  91. package/skills/cocoar-vue-ui/references/components/data-grid/checkbox.md +213 -0
  92. package/skills/cocoar-vue-ui/references/components/data-grid/date-columns.md +272 -0
  93. package/skills/cocoar-vue-ui/references/components/data-grid/editing.md +236 -0
  94. package/skills/cocoar-vue-ui/references/components/data-grid/multi-select.md +193 -0
  95. package/skills/cocoar-vue-ui/references/components/data-grid/number.md +147 -0
  96. package/skills/cocoar-vue-ui/references/components/data-grid/select.md +202 -0
  97. package/skills/cocoar-vue-ui/references/components/data-grid/text.md +127 -0
  98. package/skills/cocoar-vue-ui/references/components/data-grid.md +1225 -0
  99. package/skills/cocoar-vue-ui/references/components/data-list.md +2121 -0
  100. package/skills/cocoar-vue-ui/references/components/date-or-time-picker.md +200 -0
  101. package/skills/cocoar-vue-ui/references/components/date-picker.md +203 -0
  102. package/skills/cocoar-vue-ui/references/components/date-time-picker.md +154 -0
  103. package/skills/cocoar-vue-ui/references/components/date-views.md +212 -0
  104. package/skills/cocoar-vue-ui/references/components/dialog.md +148 -0
  105. package/skills/cocoar-vue-ui/references/components/divider.md +157 -0
  106. package/skills/cocoar-vue-ui/references/components/document-viewer/annotations.md +400 -0
  107. package/skills/cocoar-vue-ui/references/components/document-viewer/coar-document-viewer.md +327 -0
  108. package/skills/cocoar-vue-ui/references/components/document-viewer/index.md +234 -0
  109. package/skills/cocoar-vue-ui/references/components/document-viewer/toolbar.md +221 -0
  110. package/skills/cocoar-vue-ui/references/components/drag-drop.md +267 -0
  111. package/skills/cocoar-vue-ui/references/components/dual-listbox.md +449 -0
  112. package/skills/cocoar-vue-ui/references/components/file-explorer/asset-store.md +327 -0
  113. package/skills/cocoar-vue-ui/references/components/file-explorer/in-memory-store.md +176 -0
  114. package/skills/cocoar-vue-ui/references/components/file-explorer/index.md +311 -0
  115. package/skills/cocoar-vue-ui/references/components/file-explorer/use-file-explorer.md +300 -0
  116. package/skills/cocoar-vue-ui/references/components/form-field.md +1025 -0
  117. package/skills/cocoar-vue-ui/references/components/fragment-parser.md +298 -0
  118. package/skills/cocoar-vue-ui/references/components/link.md +235 -0
  119. package/skills/cocoar-vue-ui/references/components/listbox.md +575 -0
  120. package/skills/cocoar-vue-ui/references/components/map/editor.md +448 -0
  121. package/skills/cocoar-vue-ui/references/components/map/index.md +351 -0
  122. package/skills/cocoar-vue-ui/references/components/markdown-diagrams.md +210 -0
  123. package/skills/cocoar-vue-ui/references/components/markdown-editor.md +1478 -0
  124. package/skills/cocoar-vue-ui/references/components/markdown-embeds.md +387 -0
  125. package/skills/cocoar-vue-ui/references/components/markdown-form.md +447 -0
  126. package/skills/cocoar-vue-ui/references/components/markdown.md +276 -0
  127. package/skills/cocoar-vue-ui/references/components/menu.md +380 -0
  128. package/skills/cocoar-vue-ui/references/components/mermaid.md +172 -0
  129. package/skills/cocoar-vue-ui/references/components/navbar.md +147 -0
  130. package/skills/cocoar-vue-ui/references/components/note.md +96 -0
  131. package/skills/cocoar-vue-ui/references/components/notice.md +131 -0
  132. package/skills/cocoar-vue-ui/references/components/number-input.md +215 -0
  133. package/skills/cocoar-vue-ui/references/components/otp-input.md +324 -0
  134. package/skills/cocoar-vue-ui/references/components/page-builder/authoring-contract.md +271 -0
  135. package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-builder.md +476 -0
  136. package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-renderer.md +677 -0
  137. package/skills/cocoar-vue-ui/references/components/page-builder/custom-elements.md +441 -0
  138. package/skills/cocoar-vue-ui/references/components/page-builder/idp-integration.md +122 -0
  139. package/skills/cocoar-vue-ui/references/components/page-builder/index.md +573 -0
  140. package/skills/cocoar-vue-ui/references/components/pagination.md +150 -0
  141. package/skills/cocoar-vue-ui/references/components/panel-layout.md +372 -0
  142. package/skills/cocoar-vue-ui/references/components/password-input.md +175 -0
  143. package/skills/cocoar-vue-ui/references/components/popconfirm.md +186 -0
  144. package/skills/cocoar-vue-ui/references/components/popover.md +173 -0
  145. package/skills/cocoar-vue-ui/references/components/progress-bar.md +178 -0
  146. package/skills/cocoar-vue-ui/references/components/radio-group.md +225 -0
  147. package/skills/cocoar-vue-ui/references/components/script-editor.md +1271 -0
  148. package/skills/cocoar-vue-ui/references/components/segmented-control.md +238 -0
  149. package/skills/cocoar-vue-ui/references/components/select.md +463 -0
  150. package/skills/cocoar-vue-ui/references/components/sidebar.md +421 -0
  151. package/skills/cocoar-vue-ui/references/components/spinner.md +132 -0
  152. package/skills/cocoar-vue-ui/references/components/switch.md +195 -0
  153. package/skills/cocoar-vue-ui/references/components/table.md +170 -0
  154. package/skills/cocoar-vue-ui/references/components/tabs.md +382 -0
  155. package/skills/cocoar-vue-ui/references/components/tag.md +178 -0
  156. package/skills/cocoar-vue-ui/references/components/text-input.md +256 -0
  157. package/skills/cocoar-vue-ui/references/components/toast.md +160 -0
  158. package/skills/cocoar-vue-ui/references/components/tooltip.md +121 -0
  159. package/skills/cocoar-vue-ui/references/components/transitions.md +193 -0
  160. package/skills/cocoar-vue-ui/references/components/tree.md +2388 -0
  161. package/skills/cocoar-vue-ui/references/components/virtual-list.md +212 -0
  162. package/skills/cocoar-vue-ui/references/components/wizard.md +251 -0
  163. package/skills/cocoar-vue-ui/references/components/zoned-date-time-picker.md +177 -0
  164. package/skills/cocoar-vue-ui/references/foundations/colors.md +708 -0
  165. package/skills/cocoar-vue-ui/references/foundations/design-principles.md +115 -0
  166. package/skills/cocoar-vue-ui/references/foundations/icons.md +381 -0
  167. package/skills/cocoar-vue-ui/references/foundations/localization/formatting.md +530 -0
  168. package/skills/cocoar-vue-ui/references/foundations/localization/setup.md +86 -0
  169. package/skills/cocoar-vue-ui/references/foundations/localization/timezones.md +182 -0
  170. package/skills/cocoar-vue-ui/references/foundations/localization/translations.md +305 -0
  171. package/skills/cocoar-vue-ui/references/foundations/motion.md +549 -0
  172. package/skills/cocoar-vue-ui/references/foundations/spacing.md +330 -0
  173. package/skills/cocoar-vue-ui/references/foundations/theming.md +140 -0
  174. package/skills/cocoar-vue-ui/references/foundations/typography.md +206 -0
  175. package/skills/cocoar-vue-ui/references/guide/error-handling.md +162 -0
  176. package/skills/cocoar-vue-ui/references/guide/getting-started.md +119 -0
  177. package/skills/cocoar-vue-ui/references/guide/migration-page-builder-3.md +207 -0
  178. package/skills/cocoar-vue-ui/references/guide/migration.md +140 -0
  179. 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.