@umbra.ui/core 0.1.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 (272) hide show
  1. package/dist/components/controls/Dropdown/types.d.ts +5 -0
  2. package/dist/components/controls/Dropdown/types.d.ts.map +1 -0
  3. package/dist/components/controls/Dropdown/types.js +1 -0
  4. package/dist/components/controls/SegmentedControl/types.d.ts +6 -0
  5. package/dist/components/controls/SegmentedControl/types.d.ts.map +1 -0
  6. package/dist/components/controls/SegmentedControl/types.js +1 -0
  7. package/dist/components/dialogs/Alert/types.d.ts +7 -0
  8. package/dist/components/dialogs/Alert/types.d.ts.map +1 -0
  9. package/dist/components/dialogs/Alert/types.js +1 -0
  10. package/dist/components/dialogs/Toast/types.d.ts +34 -0
  11. package/dist/components/dialogs/Toast/types.d.ts.map +1 -0
  12. package/dist/components/dialogs/Toast/types.js +10 -0
  13. package/dist/components/dialogs/Toast/useToast.d.ts +36 -0
  14. package/dist/components/dialogs/Toast/useToast.d.ts.map +1 -0
  15. package/dist/components/dialogs/Toast/useToast.js +90 -0
  16. package/dist/components/indicators/Tooltip/tooltip.d.ts +3 -0
  17. package/dist/components/indicators/Tooltip/tooltip.d.ts.map +1 -0
  18. package/dist/components/indicators/Tooltip/tooltip.js +33 -0
  19. package/dist/components/indicators/Tooltip/types.d.ts +14 -0
  20. package/dist/components/indicators/Tooltip/types.d.ts.map +1 -0
  21. package/dist/components/indicators/Tooltip/types.js +1 -0
  22. package/dist/components/indicators/Tooltip/useTooltip.d.ts +18 -0
  23. package/dist/components/indicators/Tooltip/useTooltip.d.ts.map +1 -0
  24. package/dist/components/indicators/Tooltip/useTooltip.js +57 -0
  25. package/dist/components/inputs/Tags/tag-bar-styles.d.ts +14 -0
  26. package/dist/components/inputs/Tags/tag-bar-styles.d.ts.map +1 -0
  27. package/dist/components/inputs/Tags/tag-bar-styles.js +313 -0
  28. package/dist/components/inputs/Tags/types.d.ts +93 -0
  29. package/dist/components/inputs/Tags/types.d.ts.map +1 -0
  30. package/dist/components/inputs/Tags/types.js +216 -0
  31. package/dist/components/inputs/search/types.d.ts +9 -0
  32. package/dist/components/inputs/search/types.d.ts.map +1 -0
  33. package/dist/components/inputs/search/types.js +1 -0
  34. package/dist/components/navigation/adaptive/types.d.ts +16 -0
  35. package/dist/components/navigation/adaptive/types.d.ts.map +1 -0
  36. package/dist/components/navigation/adaptive/types.js +1 -0
  37. package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts +27 -0
  38. package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts.map +1 -0
  39. package/dist/components/navigation/adaptive/useAdaptiveLayout.js +40 -0
  40. package/dist/components/navigation/adaptive/useBreakpoints.d.ts +6 -0
  41. package/dist/components/navigation/adaptive/useBreakpoints.d.ts.map +1 -0
  42. package/dist/components/navigation/adaptive/useBreakpoints.js +37 -0
  43. package/dist/components/navigation/adaptive/useContainerMonitor.d.ts +93 -0
  44. package/dist/components/navigation/adaptive/useContainerMonitor.d.ts.map +1 -0
  45. package/dist/components/navigation/adaptive/useContainerMonitor.js +145 -0
  46. package/dist/components/navigation/adaptive/useViewAnimation.d.ts +31 -0
  47. package/dist/components/navigation/adaptive/useViewAnimation.d.ts.map +1 -0
  48. package/dist/components/navigation/adaptive/useViewAnimation.js +591 -0
  49. package/dist/components/navigation/adaptive/useViewResize.d.ts +52 -0
  50. package/dist/components/navigation/adaptive/useViewResize.d.ts.map +1 -0
  51. package/dist/components/navigation/adaptive/useViewResize.js +146 -0
  52. package/dist/components/navigation/navstack/useNavigationStack.d.ts +25 -0
  53. package/dist/components/navigation/navstack/useNavigationStack.d.ts.map +1 -0
  54. package/dist/components/navigation/navstack/useNavigationStack.js +133 -0
  55. package/dist/components/navigation/slideover/useSlideoverController.d.ts +20 -0
  56. package/dist/components/navigation/slideover/useSlideoverController.d.ts.map +1 -0
  57. package/dist/components/navigation/slideover/useSlideoverController.js +267 -0
  58. package/dist/components/navigation/splitview/useSplitViewController.d.ts +20 -0
  59. package/dist/components/navigation/splitview/useSplitViewController.d.ts.map +1 -0
  60. package/dist/components/navigation/splitview/useSplitViewController.js +325 -0
  61. package/dist/components/navigation/tabcontroller/types.d.ts +21 -0
  62. package/dist/components/navigation/tabcontroller/types.d.ts.map +1 -0
  63. package/dist/components/navigation/tabcontroller/types.js +1 -0
  64. package/dist/components/navigation/tabcontroller/useTabController.d.ts +5 -0
  65. package/dist/components/navigation/tabcontroller/useTabController.d.ts.map +1 -0
  66. package/dist/components/navigation/tabcontroller/useTabController.js +10 -0
  67. package/dist/components/navigation/types.d.ts +8 -0
  68. package/dist/components/navigation/types.d.ts.map +1 -0
  69. package/dist/components/navigation/types.js +1 -0
  70. package/dist/components/pickers/CollectionPicker/types.d.ts +11 -0
  71. package/dist/components/pickers/CollectionPicker/types.d.ts.map +1 -0
  72. package/dist/components/pickers/CollectionPicker/types.js +1 -0
  73. package/dist/components/pickers/ColorPicker/colors.d.ts +13 -0
  74. package/dist/components/pickers/ColorPicker/colors.d.ts.map +1 -0
  75. package/dist/components/pickers/ColorPicker/colors.js +266 -0
  76. package/dist/components/pickers/FilePicker/types.d.ts +10 -0
  77. package/dist/components/pickers/FilePicker/types.d.ts.map +1 -0
  78. package/dist/components/pickers/FilePicker/types.js +1 -0
  79. package/dist/index.d.ts +91 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +196 -0
  82. package/dist/theme.d.ts +73 -0
  83. package/dist/theme.d.ts.map +1 -0
  84. package/dist/theme.js +279 -0
  85. package/dist/themes/blank.d.ts +7 -0
  86. package/dist/themes/blank.d.ts.map +1 -0
  87. package/dist/themes/blank.js +543 -0
  88. package/dist/themes/crimson-dark.d.ts +4 -0
  89. package/dist/themes/crimson-dark.d.ts.map +1 -0
  90. package/dist/themes/crimson-dark.js +552 -0
  91. package/dist/themes/cyan-light.d.ts +4 -0
  92. package/dist/themes/cyan-light.d.ts.map +1 -0
  93. package/dist/themes/cyan-light.js +552 -0
  94. package/dist/themes/dark.d.ts +4 -0
  95. package/dist/themes/dark.d.ts.map +1 -0
  96. package/dist/themes/dark.js +551 -0
  97. package/dist/themes/gold-dark.d.ts +4 -0
  98. package/dist/themes/gold-dark.d.ts.map +1 -0
  99. package/dist/themes/gold-dark.js +552 -0
  100. package/dist/themes/grass-dark.d.ts +4 -0
  101. package/dist/themes/grass-dark.d.ts.map +1 -0
  102. package/dist/themes/grass-dark.js +552 -0
  103. package/dist/themes/indigo.d.ts +4 -0
  104. package/dist/themes/indigo.d.ts.map +1 -0
  105. package/dist/themes/indigo.js +552 -0
  106. package/dist/themes/light.d.ts +4 -0
  107. package/dist/themes/light.d.ts.map +1 -0
  108. package/dist/themes/light.js +551 -0
  109. package/dist/themes/orange-dark.d.ts +4 -0
  110. package/dist/themes/orange-dark.d.ts.map +1 -0
  111. package/dist/themes/orange-dark.js +551 -0
  112. package/dist/themes/orange-light.d.ts +4 -0
  113. package/dist/themes/orange-light.d.ts.map +1 -0
  114. package/dist/themes/orange-light.js +551 -0
  115. package/package.json +62 -0
  116. package/src/components/controls/Button/Button.vue +417 -0
  117. package/src/components/controls/Button/README.md +348 -0
  118. package/src/components/controls/Button/theme.css +200 -0
  119. package/src/components/controls/Checkbox/Checkbox.vue +164 -0
  120. package/src/components/controls/Checkbox/README.md +441 -0
  121. package/src/components/controls/Checkbox/theme.css +36 -0
  122. package/src/components/controls/Dropdown/Dropdown.vue +476 -0
  123. package/src/components/controls/Dropdown/README.md +370 -0
  124. package/src/components/controls/Dropdown/theme.css +50 -0
  125. package/src/components/controls/Dropdown/types.ts +6 -0
  126. package/src/components/controls/IconButton/IconButton.vue +267 -0
  127. package/src/components/controls/IconButton/README.md +502 -0
  128. package/src/components/controls/IconButton/theme.css +89 -0
  129. package/src/components/controls/Radio/README.md +591 -0
  130. package/src/components/controls/Radio/Radio.vue +89 -0
  131. package/src/components/controls/Radio/theme.css +14 -0
  132. package/src/components/controls/RangeSlider/README.md +608 -0
  133. package/src/components/controls/RangeSlider/RangeSlider.vue +535 -0
  134. package/src/components/controls/RangeSlider/theme.css +80 -0
  135. package/src/components/controls/SegmentedControl/README.md +587 -0
  136. package/src/components/controls/SegmentedControl/SegmentedControl.vue +284 -0
  137. package/src/components/controls/SegmentedControl/theme.css +60 -0
  138. package/src/components/controls/SegmentedControl/types.ts +5 -0
  139. package/src/components/controls/Slider/README.md +627 -0
  140. package/src/components/controls/Slider/Slider.vue +260 -0
  141. package/src/components/controls/Slider/theme.css +74 -0
  142. package/src/components/controls/Stepper/README.md +601 -0
  143. package/src/components/controls/Stepper/Stepper.vue +103 -0
  144. package/src/components/controls/Stepper/theme.css +53 -0
  145. package/src/components/controls/Switch/README.md +667 -0
  146. package/src/components/controls/Switch/Switch.vue +127 -0
  147. package/src/components/controls/Switch/theme.css +42 -0
  148. package/src/components/dialogs/Alert/Alert.vue +218 -0
  149. package/src/components/dialogs/Alert/README.md +450 -0
  150. package/src/components/dialogs/Alert/theme.css +44 -0
  151. package/src/components/dialogs/Alert/types.ts +11 -0
  152. package/src/components/dialogs/Toast/README.md +522 -0
  153. package/src/components/dialogs/Toast/Toast.vue +296 -0
  154. package/src/components/dialogs/Toast/ToastContainer.vue +330 -0
  155. package/src/components/dialogs/Toast/theme.css +44 -0
  156. package/src/components/dialogs/Toast/types.ts +46 -0
  157. package/src/components/dialogs/Toast/useToast.ts +127 -0
  158. package/src/components/indicators/ProgressBar/ProgressBar.vue +98 -0
  159. package/src/components/indicators/ProgressBar/README.md +744 -0
  160. package/src/components/indicators/ProgressBar/theme.css +36 -0
  161. package/src/components/indicators/Tooltip/README.md +723 -0
  162. package/src/components/indicators/Tooltip/TooltipProvider.vue +142 -0
  163. package/src/components/indicators/Tooltip/theme.css +18 -0
  164. package/src/components/indicators/Tooltip/tooltip.ts +48 -0
  165. package/src/components/indicators/Tooltip/types.ts +15 -0
  166. package/src/components/indicators/Tooltip/useTooltip.ts +71 -0
  167. package/src/components/inputs/AutogrowTextView/AutogrowTextView.vue +110 -0
  168. package/src/components/inputs/AutogrowTextView/README.md +643 -0
  169. package/src/components/inputs/AutogrowTextView/theme.css +28 -0
  170. package/src/components/inputs/InputCard/InputCard.vue +600 -0
  171. package/src/components/inputs/InputCard/README.md +636 -0
  172. package/src/components/inputs/InputEmail/InputEmail.vue +698 -0
  173. package/src/components/inputs/InputEmail/README.md +764 -0
  174. package/src/components/inputs/InputNumber/InputNumber.vue +300 -0
  175. package/src/components/inputs/InputNumber/README.md +749 -0
  176. package/src/components/inputs/InputPhone/InputPhone.vue +645 -0
  177. package/src/components/inputs/InputPhone/README.md +636 -0
  178. package/src/components/inputs/InputSecure/InputSecure.vue +646 -0
  179. package/src/components/inputs/InputSecure/README.md +771 -0
  180. package/src/components/inputs/InputText/InputText.vue +225 -0
  181. package/src/components/inputs/InputText/README.md +844 -0
  182. package/src/components/inputs/OTP/OTP.vue +349 -0
  183. package/src/components/inputs/OTP/README.md +736 -0
  184. package/src/components/inputs/OTP/theme.css +50 -0
  185. package/src/components/inputs/StringCapture/README.md +718 -0
  186. package/src/components/inputs/StringCapture/StringCapture.vue +315 -0
  187. package/src/components/inputs/StringCapture/theme.css +86 -0
  188. package/src/components/inputs/Tags/README.md +897 -0
  189. package/src/components/inputs/Tags/TagBar.vue +793 -0
  190. package/src/components/inputs/Tags/TagCreation.vue +219 -0
  191. package/src/components/inputs/Tags/TagPicker.vue +380 -0
  192. package/src/components/inputs/Tags/tag-bar-styles.ts +354 -0
  193. package/src/components/inputs/Tags/theme.css +121 -0
  194. package/src/components/inputs/Tags/types.ts +346 -0
  195. package/src/components/inputs/search/README.md +759 -0
  196. package/src/components/inputs/search/SearchBar.vue +394 -0
  197. package/src/components/inputs/search/SearchResults.vue +310 -0
  198. package/src/components/inputs/search/theme.css +187 -0
  199. package/src/components/inputs/search/types.ts +8 -0
  200. package/src/components/inputs/theme.css +102 -0
  201. package/src/components/menus/ActionMenu/ActionMenu.vue +383 -0
  202. package/src/components/menus/ActionMenu/README.md +825 -0
  203. package/src/components/menus/ActionMenu/theme.css +93 -0
  204. package/src/components/models/Popover/Popover.vue +551 -0
  205. package/src/components/models/Popover/README.md +885 -0
  206. package/src/components/models/Popover/theme.css +52 -0
  207. package/src/components/models/Sheet/README.md +1159 -0
  208. package/src/components/models/Sheet/Sheet.vue +465 -0
  209. package/src/components/models/Sheet/theme.css +72 -0
  210. package/src/components/models/Sidebar/README.md +1228 -0
  211. package/src/components/models/Sidebar/Sidebar.vue +480 -0
  212. package/src/components/models/Sidebar/theme.css +90 -0
  213. package/src/components/navigation/adaptive/AdaptiveLayout.vue +779 -0
  214. package/src/components/navigation/adaptive/AdaptiveLayoutBreadcrumbs.vue +192 -0
  215. package/src/components/navigation/adaptive/AdaptiveLayoutMenuButton.vue +149 -0
  216. package/src/components/navigation/adaptive/README.md +768 -0
  217. package/src/components/navigation/adaptive/types.ts +19 -0
  218. package/src/components/navigation/adaptive/useAdaptiveLayout.ts +89 -0
  219. package/src/components/navigation/adaptive/useBreakpoints.ts +41 -0
  220. package/src/components/navigation/adaptive/useContainerMonitor.ts +214 -0
  221. package/src/components/navigation/adaptive/useViewAnimation.ts +721 -0
  222. package/src/components/navigation/adaptive/useViewResize.ts +211 -0
  223. package/src/components/navigation/navstack/NavigationStack.vue +180 -0
  224. package/src/components/navigation/navstack/README.md +994 -0
  225. package/src/components/navigation/navstack/useNavigationStack.ts +164 -0
  226. package/src/components/navigation/slideover/README.md +1275 -0
  227. package/src/components/navigation/slideover/SlideoverController.vue +287 -0
  228. package/src/components/navigation/slideover/useSlideoverController.ts +320 -0
  229. package/src/components/navigation/splitview/README.md +1115 -0
  230. package/src/components/navigation/splitview/SplitViewController.vue +176 -0
  231. package/src/components/navigation/splitview/useSplitViewController.ts +388 -0
  232. package/src/components/navigation/tabcontroller/README.md +919 -0
  233. package/src/components/navigation/tabcontroller/TabController.vue +307 -0
  234. package/src/components/navigation/tabcontroller/TabItem.vue +57 -0
  235. package/src/components/navigation/tabcontroller/types.ts +24 -0
  236. package/src/components/navigation/tabcontroller/useTabController.ts +18 -0
  237. package/src/components/navigation/theme.css +91 -0
  238. package/src/components/navigation/types.ts +7 -0
  239. package/src/components/pickers/CollectionPicker/CollectionPicker.vue +398 -0
  240. package/src/components/pickers/CollectionPicker/README.md +1115 -0
  241. package/src/components/pickers/CollectionPicker/theme.css +14 -0
  242. package/src/components/pickers/CollectionPicker/types.ts +11 -0
  243. package/src/components/pickers/ColorPicker/ColorPicker.vue +376 -0
  244. package/src/components/pickers/ColorPicker/README.md +1439 -0
  245. package/src/components/pickers/ColorPicker/colors.ts +299 -0
  246. package/src/components/pickers/ColorPicker/theme.css +32 -0
  247. package/src/components/pickers/DatePicker/DatePicker.vue +660 -0
  248. package/src/components/pickers/DatePicker/README.md +1195 -0
  249. package/src/components/pickers/DatePicker/theme.css +22 -0
  250. package/src/components/pickers/FilePicker/FilePicker.vue +534 -0
  251. package/src/components/pickers/FilePicker/README.md +1542 -0
  252. package/src/components/pickers/FilePicker/theme.css +48 -0
  253. package/src/components/pickers/FilePicker/types.ts +10 -0
  254. package/src/components/pickers/IconPicker/IconPicker.vue +327 -0
  255. package/src/components/pickers/IconPicker/README.md +1161 -0
  256. package/src/components/pickers/IconPicker/theme.css +28 -0
  257. package/src/components/pickers/theme.css +82 -0
  258. package/src/components/views/MarkdownViewer/MarkdownViewer.vue +442 -0
  259. package/src/components/views/MarkdownViewer/README.md +833 -0
  260. package/src/components/views/MarkdownViewer/theme.css +130 -0
  261. package/src/index.ts +263 -0
  262. package/src/theme.ts +378 -0
  263. package/src/themes/crimson-dark.ts +556 -0
  264. package/src/themes/cyan-light.ts +556 -0
  265. package/src/themes/dark.ts +557 -0
  266. package/src/themes/gold-dark.ts +556 -0
  267. package/src/themes/grass-dark.ts +556 -0
  268. package/src/themes/indigo.ts +556 -0
  269. package/src/themes/light.ts +557 -0
  270. package/src/themes/orange-dark.ts +557 -0
  271. package/src/themes/orange-light.ts +557 -0
  272. package/src/vue.d.ts +45 -0
@@ -0,0 +1,736 @@
1
+ # OTP
2
+
3
+ A One-Time Password (OTP) input component built with Vue 3 Composition API and TypeScript. The OTP component provides a secure, user-friendly interface for entering verification codes with automatic focus management, paste support, keyboard navigation, and accessibility features.
4
+
5
+ ## Installation/Import
6
+
7
+ ```typescript
8
+ import { OTP } from "@umbra-ui/core";
9
+ ```
10
+
11
+ **Dependencies:**
12
+
13
+ - Vue 3.x
14
+
15
+ ## Basic Usage
16
+
17
+ ```vue
18
+ <script setup lang="ts">
19
+ import { ref } from "vue";
20
+ import { OTP } from "@umbra-ui/core";
21
+
22
+ const otpCode = ref("");
23
+
24
+ const handleOTPUpdate = (value: string) => {
25
+ console.log("OTP Code:", value);
26
+ otpCode.value = value;
27
+ };
28
+
29
+ const handleOTPComplete = (value: string) => {
30
+ console.log("OTP Complete:", value);
31
+ // Handle OTP verification
32
+ };
33
+ </script>
34
+
35
+ <template>
36
+ <div>
37
+ <OTP
38
+ v-model="otpCode"
39
+ :length="6"
40
+ :auto-focus="true"
41
+ :auto-submit="true"
42
+ @complete="handleOTPComplete"
43
+ />
44
+ </div>
45
+ </template>
46
+ ```
47
+
48
+ ## Props
49
+
50
+ | Prop Name | Type | Required | Default | Description |
51
+ | ------------ | --------- | -------- | ------- | ---------------------------------------------------------- |
52
+ | `modelValue` | `string` | No | `""` | The OTP code value |
53
+ | `length` | `number` | No | `6` | Number of OTP digits |
54
+ | `disabled` | `boolean` | No | `false` | Whether the OTP input is disabled |
55
+ | `error` | `string` | No | `""` | Error message to display |
56
+ | `loading` | `boolean` | No | `false` | Whether the OTP is in loading state |
57
+ | `autoFocus` | `boolean` | No | `true` | Whether to auto-focus the first input on mount |
58
+ | `autoSubmit` | `boolean` | No | `true` | Whether to emit complete event when all digits are entered |
59
+
60
+ ## Events
61
+
62
+ | Event Name | Payload Type | Description |
63
+ | ------------------- | ------------ | ----------------------------------------------------------- |
64
+ | `update:modelValue` | `string` | Emitted when the OTP value changes |
65
+ | `complete` | `string` | Emitted when all digits are entered (if autoSubmit is true) |
66
+ | `change` | `string` | Emitted when the OTP value changes |
67
+ | `focus` | `void` | Emitted when any input receives focus |
68
+ | `blur` | `void` | Emitted when any input loses focus |
69
+
70
+ ## Slots
71
+
72
+ This component does not provide any slots.
73
+
74
+ ## Exposed Methods/Refs
75
+
76
+ The OTP component exposes the following methods via template refs:
77
+
78
+ | Method Name | Parameters | Description |
79
+ | ----------- | ---------- | ------------------------------------------------- |
80
+ | `focus` | `()` | Focuses the first input field |
81
+ | `clear` | `()` | Clears all input fields and focuses the first one |
82
+
83
+ ### Example Usage
84
+
85
+ ```vue
86
+ <script setup lang="ts">
87
+ import { ref } from "vue";
88
+ import { OTP } from "@umbra-ui/core";
89
+
90
+ const otpRef = ref();
91
+
92
+ const clearOTP = () => {
93
+ otpRef.value?.clear();
94
+ };
95
+
96
+ const focusOTP = () => {
97
+ otpRef.value?.focus();
98
+ };
99
+ </script>
100
+
101
+ <template>
102
+ <div>
103
+ <OTP ref="otpRef" v-model="otpCode" />
104
+ <button @click="clearOTP">Clear</button>
105
+ <button @click="focusOTP">Focus</button>
106
+ </div>
107
+ </template>
108
+ ```
109
+
110
+ ## CSS Customization
111
+
112
+ The OTP component uses CSS custom properties for theming and customization:
113
+
114
+ ### OTP Pin Variables
115
+
116
+ ```css
117
+ /* Pin Background Colors */
118
+ --otp-pin-empty-bg: var(--otp-pin-empty-background);
119
+ --otp-pin-filled-bg: var(--otp-pin-filled-background);
120
+
121
+ /* Pin Text Colors */
122
+ --otp-pin-empty-text: var(--otp-pin-empty-text-color);
123
+ --otp-pin-filled-text: var(--otp-pin-filled-text-color);
124
+
125
+ /* Pin Border Colors */
126
+ --otp-pin-border: var(--otp-pin-border-color);
127
+ --otp-filled-border: var(--otp-filled-border-color);
128
+
129
+ /* Focus Colors */
130
+ --otp-focus-border: var(--otp-focus-border-color);
131
+
132
+ /* Error Colors */
133
+ --otp-error-border: var(--otp-error-border-color);
134
+ --otp-error-text: var(--otp-error-text-color);
135
+
136
+ /* Loading Colors */
137
+ --otp-loading-text: var(--otp-loading-text-color);
138
+ ```
139
+
140
+ ## Key Features
141
+
142
+ ### Input Management
143
+
144
+ - **Automatic Focus**: Auto-focuses the first input on mount
145
+ - **Smart Navigation**: Automatically moves to the next field when a digit is entered
146
+ - **Backspace Handling**: Moves to the previous field when backspace is pressed on an empty field
147
+ - **Arrow Key Navigation**: Left/right arrow keys move between fields
148
+ - **Delete Key**: Clears all fields from the current position
149
+
150
+ ### Paste Support
151
+
152
+ - **Paste Detection**: Automatically detects and handles pasted OTP codes
153
+ - **Smart Distribution**: Distributes pasted digits across available fields
154
+ - **Focus Management**: Focuses the next empty field after pasting
155
+
156
+ ### Validation & States
157
+
158
+ - **Digit-Only Input**: Only accepts numeric digits (0-9)
159
+ - **Error States**: Visual error indication with custom error messages
160
+ - **Loading States**: Loading indicator with disabled interaction
161
+ - **Disabled States**: Non-interactive state with visual feedback
162
+
163
+ ### Accessibility
164
+
165
+ - **ARIA Labels**: Proper labeling for screen readers
166
+ - **Keyboard Navigation**: Full keyboard support
167
+ - **Focus Management**: Clear focus indicators
168
+ - **Error Announcements**: Error messages are announced to screen readers
169
+
170
+ ## Examples
171
+
172
+ ### Basic OTP Input
173
+
174
+ ```vue
175
+ <script setup lang="ts">
176
+ import { ref } from "vue";
177
+ import { OTP } from "@umbra-ui/core";
178
+
179
+ const otpCode = ref("");
180
+ const isComplete = ref(false);
181
+
182
+ const handleOTPComplete = (value: string) => {
183
+ isComplete.value = true;
184
+ console.log("OTP Complete:", value);
185
+ };
186
+
187
+ const handleOTPChange = (value: string) => {
188
+ isComplete.value = false;
189
+ console.log("OTP Changed:", value);
190
+ };
191
+ </script>
192
+
193
+ <template>
194
+ <div class="otp-form">
195
+ <h3>Enter Verification Code</h3>
196
+
197
+ <div class="otp-container">
198
+ <OTP
199
+ v-model="otpCode"
200
+ :length="6"
201
+ :auto-focus="true"
202
+ :auto-submit="true"
203
+ @complete="handleOTPComplete"
204
+ @change="handleOTPChange"
205
+ />
206
+ </div>
207
+
208
+ <div class="otp-status">
209
+ <p v-if="isComplete" class="success">Code entered successfully!</p>
210
+ <p v-else class="instruction">
211
+ Enter the 6-digit code sent to your phone
212
+ </p>
213
+ </div>
214
+ </div>
215
+ </template>
216
+
217
+ <style module>
218
+ .otp-form {
219
+ max-width: 400px;
220
+ padding: 2rem;
221
+ border: 1px solid #e0e0e0;
222
+ border-radius: 0.5rem;
223
+ text-align: center;
224
+ }
225
+
226
+ .otp-container {
227
+ margin: 2rem 0;
228
+ }
229
+
230
+ .otp-status {
231
+ margin-top: 1rem;
232
+ }
233
+
234
+ .success {
235
+ color: #28a745;
236
+ font-weight: 500;
237
+ }
238
+
239
+ .instruction {
240
+ color: #666;
241
+ font-size: 0.875rem;
242
+ }
243
+ </style>
244
+ ```
245
+
246
+ ### OTP with Error Handling
247
+
248
+ ```vue
249
+ <script setup lang="ts">
250
+ import { ref, computed } from "vue";
251
+ import { OTP } from "@umbra-ui/core";
252
+
253
+ const otpCode = ref("");
254
+ const error = ref("");
255
+ const isLoading = ref(false);
256
+ const attempts = ref(0);
257
+
258
+ const isComplete = computed(() => {
259
+ return otpCode.value.length === 6;
260
+ });
261
+
262
+ const handleOTPComplete = async (value: string) => {
263
+ isLoading.value = true;
264
+ error.value = "";
265
+
266
+ try {
267
+ // Simulate API call
268
+ await new Promise((resolve) => setTimeout(resolve, 2000));
269
+
270
+ // Simulate verification failure
271
+ if (value !== "123456") {
272
+ attempts.value++;
273
+ error.value = `Invalid code. ${3 - attempts.value} attempts remaining.`;
274
+ otpCode.value = "";
275
+
276
+ if (attempts.value >= 3) {
277
+ error.value = "Too many attempts. Please request a new code.";
278
+ }
279
+ } else {
280
+ error.value = "";
281
+ console.log("Verification successful!");
282
+ }
283
+ } catch (err) {
284
+ error.value = "Verification failed. Please try again.";
285
+ } finally {
286
+ isLoading.value = false;
287
+ }
288
+ };
289
+
290
+ const handleOTPChange = () => {
291
+ error.value = "";
292
+ };
293
+ </script>
294
+
295
+ <template>
296
+ <div class="otp-verification">
297
+ <h3>Verify Your Account</h3>
298
+
299
+ <div class="otp-container">
300
+ <OTP
301
+ v-model="otpCode"
302
+ :length="6"
303
+ :error="error"
304
+ :loading="isLoading"
305
+ :auto-focus="true"
306
+ :auto-submit="true"
307
+ @complete="handleOTPComplete"
308
+ @change="handleOTPChange"
309
+ />
310
+ </div>
311
+
312
+ <div class="verification-status">
313
+ <p v-if="isLoading" class="loading">Verifying code...</p>
314
+ <p v-else-if="error" class="error">{{ error }}</p>
315
+ <p v-else class="instruction">Enter the 6-digit verification code</p>
316
+ </div>
317
+ </div>
318
+ </template>
319
+
320
+ <style module>
321
+ .otp-verification {
322
+ max-width: 400px;
323
+ padding: 2rem;
324
+ border: 1px solid #e0e0e0;
325
+ border-radius: 0.5rem;
326
+ text-align: center;
327
+ }
328
+
329
+ .otp-container {
330
+ margin: 2rem 0;
331
+ }
332
+
333
+ .verification-status {
334
+ margin-top: 1rem;
335
+ min-height: 1.5rem;
336
+ }
337
+
338
+ .loading {
339
+ color: #007bff;
340
+ font-weight: 500;
341
+ }
342
+
343
+ .error {
344
+ color: #dc3545;
345
+ font-weight: 500;
346
+ }
347
+
348
+ .instruction {
349
+ color: #666;
350
+ font-size: 0.875rem;
351
+ }
352
+ </style>
353
+ ```
354
+
355
+ ### Custom Length OTP
356
+
357
+ ```vue
358
+ <script setup lang="ts">
359
+ import { ref } from "vue";
360
+ import { OTP } from "@umbra-ui/core";
361
+
362
+ const otpCode = ref("");
363
+ const otpLength = ref(4);
364
+
365
+ const handleOTPComplete = (value: string) => {
366
+ console.log(`${otpLength.value}-digit OTP Complete:`, value);
367
+ };
368
+
369
+ const changeLength = (length: number) => {
370
+ otpLength.value = length;
371
+ otpCode.value = "";
372
+ };
373
+ </script>
374
+
375
+ <template>
376
+ <div class="custom-otp">
377
+ <h3>Custom Length OTP</h3>
378
+
379
+ <div class="length-selector">
380
+ <label>OTP Length:</label>
381
+ <div class="length-buttons">
382
+ <button
383
+ v-for="length in [4, 6, 8]"
384
+ :key="length"
385
+ @click="changeLength(length)"
386
+ :class="{ active: otpLength === length }"
387
+ class="length-btn"
388
+ >
389
+ {{ length }} digits
390
+ </button>
391
+ </div>
392
+ </div>
393
+
394
+ <div class="otp-container">
395
+ <OTP
396
+ v-model="otpCode"
397
+ :length="otpLength"
398
+ :auto-focus="true"
399
+ :auto-submit="true"
400
+ @complete="handleOTPComplete"
401
+ />
402
+ </div>
403
+
404
+ <div class="otp-info">
405
+ <p>Enter the {{ otpLength }}-digit code</p>
406
+ </div>
407
+ </div>
408
+ </template>
409
+
410
+ <style module>
411
+ .custom-otp {
412
+ max-width: 500px;
413
+ padding: 2rem;
414
+ border: 1px solid #e0e0e0;
415
+ border-radius: 0.5rem;
416
+ text-align: center;
417
+ }
418
+
419
+ .length-selector {
420
+ margin-bottom: 2rem;
421
+ }
422
+
423
+ .length-selector label {
424
+ display: block;
425
+ margin-bottom: 1rem;
426
+ font-weight: 500;
427
+ color: #333;
428
+ }
429
+
430
+ .length-buttons {
431
+ display: flex;
432
+ gap: 0.5rem;
433
+ justify-content: center;
434
+ }
435
+
436
+ .length-btn {
437
+ padding: 0.5rem 1rem;
438
+ border: 1px solid #ddd;
439
+ background-color: #fff;
440
+ border-radius: 0.25rem;
441
+ cursor: pointer;
442
+ transition: all 0.2s;
443
+ }
444
+
445
+ .length-btn:hover {
446
+ background-color: #f8f9fa;
447
+ }
448
+
449
+ .length-btn.active {
450
+ background-color: #007bff;
451
+ color: white;
452
+ border-color: #007bff;
453
+ }
454
+
455
+ .otp-container {
456
+ margin: 2rem 0;
457
+ }
458
+
459
+ .otp-info {
460
+ margin-top: 1rem;
461
+ }
462
+
463
+ .otp-info p {
464
+ color: #666;
465
+ font-size: 0.875rem;
466
+ }
467
+ </style>
468
+ ```
469
+
470
+ ### OTP with Resend Functionality
471
+
472
+ ```vue
473
+ <script setup lang="ts">
474
+ import { ref, computed } from "vue";
475
+ import { OTP } from "@umbra-ui/core";
476
+
477
+ const otpCode = ref("");
478
+ const isResending = ref(false);
479
+ const resendCooldown = ref(0);
480
+ const resendCount = ref(0);
481
+
482
+ const canResend = computed(() => {
483
+ return resendCooldown.value === 0 && !isResending.value;
484
+ });
485
+
486
+ const handleOTPComplete = (value: string) => {
487
+ console.log("OTP Complete:", value);
488
+ };
489
+
490
+ const resendOTP = async () => {
491
+ if (!canResend.value) return;
492
+
493
+ isResending.value = true;
494
+ resendCount.value++;
495
+
496
+ try {
497
+ // Simulate API call
498
+ await new Promise((resolve) => setTimeout(resolve, 1000));
499
+ console.log("OTP resent successfully");
500
+
501
+ // Start cooldown
502
+ resendCooldown.value = 30;
503
+ const interval = setInterval(() => {
504
+ resendCooldown.value--;
505
+ if (resendCooldown.value === 0) {
506
+ clearInterval(interval);
507
+ }
508
+ }, 1000);
509
+ } catch (err) {
510
+ console.error("Failed to resend OTP");
511
+ } finally {
512
+ isResending.value = false;
513
+ }
514
+ };
515
+ </script>
516
+
517
+ <template>
518
+ <div class="otp-with-resend">
519
+ <h3>Two-Factor Authentication</h3>
520
+
521
+ <div class="otp-container">
522
+ <OTP
523
+ v-model="otpCode"
524
+ :length="6"
525
+ :auto-focus="true"
526
+ :auto-submit="true"
527
+ @complete="handleOTPComplete"
528
+ />
529
+ </div>
530
+
531
+ <div class="resend-section">
532
+ <p class="instruction">Enter the 6-digit code sent to your phone</p>
533
+
534
+ <div class="resend-actions">
535
+ <button @click="resendOTP" :disabled="!canResend" class="resend-btn">
536
+ <span v-if="isResending">Sending...</span>
537
+ <span v-else-if="resendCooldown > 0"
538
+ >Resend in {{ resendCooldown }}s</span
539
+ >
540
+ <span v-else>Resend Code</span>
541
+ </button>
542
+
543
+ <p v-if="resendCount > 0" class="resend-count">
544
+ Resent {{ resendCount }} time{{ resendCount > 1 ? "s" : "" }}
545
+ </p>
546
+ </div>
547
+ </div>
548
+ </div>
549
+ </template>
550
+
551
+ <style module>
552
+ .otp-with-resend {
553
+ max-width: 400px;
554
+ padding: 2rem;
555
+ border: 1px solid #e0e0e0;
556
+ border-radius: 0.5rem;
557
+ text-align: center;
558
+ }
559
+
560
+ .otp-container {
561
+ margin: 2rem 0;
562
+ }
563
+
564
+ .resend-section {
565
+ margin-top: 1rem;
566
+ }
567
+
568
+ .instruction {
569
+ color: #666;
570
+ font-size: 0.875rem;
571
+ margin-bottom: 1rem;
572
+ }
573
+
574
+ .resend-actions {
575
+ display: flex;
576
+ flex-direction: column;
577
+ gap: 0.5rem;
578
+ align-items: center;
579
+ }
580
+
581
+ .resend-btn {
582
+ padding: 0.5rem 1rem;
583
+ background-color: #007bff;
584
+ color: white;
585
+ border: none;
586
+ border-radius: 0.25rem;
587
+ cursor: pointer;
588
+ font-size: 0.875rem;
589
+ transition: background-color 0.2s;
590
+ }
591
+
592
+ .resend-btn:hover:not(:disabled) {
593
+ background-color: #0056b3;
594
+ }
595
+
596
+ .resend-btn:disabled {
597
+ background-color: #6c757d;
598
+ cursor: not-allowed;
599
+ }
600
+
601
+ .resend-count {
602
+ color: #666;
603
+ font-size: 0.75rem;
604
+ margin: 0;
605
+ }
606
+ </style>
607
+ ```
608
+
609
+ ### OTP with Manual Submit
610
+
611
+ ```vue
612
+ <script setup lang="ts">
613
+ import { ref, computed } from "vue";
614
+ import { OTP } from "@umbra-ui/core";
615
+
616
+ const otpCode = ref("");
617
+ const isVerifying = ref(false);
618
+ const error = ref("");
619
+
620
+ const isComplete = computed(() => {
621
+ return otpCode.value.length === 6;
622
+ });
623
+
624
+ const handleOTPChange = () => {
625
+ error.value = "";
626
+ };
627
+
628
+ const verifyOTP = async () => {
629
+ if (!isComplete.value) return;
630
+
631
+ isVerifying.value = true;
632
+ error.value = "";
633
+
634
+ try {
635
+ // Simulate API call
636
+ await new Promise((resolve) => setTimeout(resolve, 2000));
637
+
638
+ if (otpCode.value === "123456") {
639
+ console.log("Verification successful!");
640
+ } else {
641
+ error.value = "Invalid verification code";
642
+ }
643
+ } catch (err) {
644
+ error.value = "Verification failed. Please try again.";
645
+ } finally {
646
+ isVerifying.value = false;
647
+ }
648
+ };
649
+ </script>
650
+
651
+ <template>
652
+ <div class="manual-submit-otp">
653
+ <h3>Manual Submit OTP</h3>
654
+
655
+ <div class="otp-container">
656
+ <OTP
657
+ v-model="otpCode"
658
+ :length="6"
659
+ :error="error"
660
+ :auto-submit="false"
661
+ @change="handleOTPChange"
662
+ />
663
+ </div>
664
+
665
+ <div class="submit-section">
666
+ <button
667
+ @click="verifyOTP"
668
+ :disabled="!isComplete || isVerifying"
669
+ class="verify-btn"
670
+ >
671
+ <span v-if="isVerifying">Verifying...</span>
672
+ <span v-else>Verify Code</span>
673
+ </button>
674
+
675
+ <p v-if="error" class="error-message">{{ error }}</p>
676
+ </div>
677
+ </div>
678
+ </template>
679
+
680
+ <style module>
681
+ .manual-submit-otp {
682
+ max-width: 400px;
683
+ padding: 2rem;
684
+ border: 1px solid #e0e0e0;
685
+ border-radius: 0.5rem;
686
+ text-align: center;
687
+ }
688
+
689
+ .otp-container {
690
+ margin: 2rem 0;
691
+ }
692
+
693
+ .submit-section {
694
+ margin-top: 1rem;
695
+ }
696
+
697
+ .verify-btn {
698
+ padding: 0.75rem 2rem;
699
+ background-color: #28a745;
700
+ color: white;
701
+ border: none;
702
+ border-radius: 0.25rem;
703
+ cursor: pointer;
704
+ font-size: 1rem;
705
+ transition: background-color 0.2s;
706
+ }
707
+
708
+ .verify-btn:hover:not(:disabled) {
709
+ background-color: #218838;
710
+ }
711
+
712
+ .verify-btn:disabled {
713
+ background-color: #6c757d;
714
+ cursor: not-allowed;
715
+ }
716
+
717
+ .error-message {
718
+ color: #dc3545;
719
+ font-size: 0.875rem;
720
+ margin-top: 0.5rem;
721
+ }
722
+ </style>
723
+ ```
724
+
725
+ ## Technical Notes
726
+
727
+ - OTP component provides secure, accessible input for verification codes
728
+ - Automatic focus management moves between fields as digits are entered
729
+ - Paste support automatically distributes pasted digits across fields
730
+ - Keyboard navigation includes arrow keys, backspace, and delete functionality
731
+ - Error states provide visual feedback with custom error messages
732
+ - Loading states disable interaction during verification
733
+ - Accessibility features include ARIA labels and screen reader support
734
+ - Responsive design adapts to mobile devices with appropriate sizing
735
+ - CSS custom properties enable easy theming for light and dark modes
736
+ - Exposed methods allow programmatic control of focus and clearing