@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,764 @@
1
+ # InputEmail
2
+
3
+ A specialized email input component built with Vue 3 Composition API and TypeScript. The InputEmail component provides intelligent email validation, domain suggestions, typo detection, and visual feedback with smooth animations and accessibility features.
4
+
5
+ ## Installation/Import
6
+
7
+ ```typescript
8
+ import { InputEmail } from "@umbra-ui/core";
9
+ ```
10
+
11
+ **Dependencies:**
12
+
13
+ - Vue 3.x
14
+ - @umbra-ui/icons (for envelope, warning, and check icons)
15
+
16
+ ## Basic Usage
17
+
18
+ ```vue
19
+ <script setup lang="ts">
20
+ import { ref } from "vue";
21
+ import { InputEmail } from "@umbra-ui/core";
22
+
23
+ const email = ref("");
24
+ const isValid = ref(false);
25
+ const suggestion = ref("");
26
+
27
+ const handleEmailUpdate = (value: string) => {
28
+ console.log("Email:", value);
29
+ email.value = value;
30
+ };
31
+
32
+ const handleValidUpdate = (valid: boolean) => {
33
+ console.log("Is valid:", valid);
34
+ isValid.value = valid;
35
+ };
36
+
37
+ const handleSuggestionUpdate = (suggestedEmail: string) => {
38
+ console.log("Suggestion selected:", suggestedEmail);
39
+ suggestion.value = suggestedEmail;
40
+ };
41
+ </script>
42
+
43
+ <template>
44
+ <div>
45
+ <InputEmail
46
+ v-model:value="email"
47
+ placeholder="name@example.com"
48
+ :showSuggestions="true"
49
+ :validateOnType="true"
50
+ @update:value="handleEmailUpdate"
51
+ @update:valid="handleValidUpdate"
52
+ @update:suggestion="handleSuggestionUpdate"
53
+ />
54
+
55
+ <div v-if="suggestion" class="suggestion-info">
56
+ <p>Selected suggestion: {{ suggestion }}</p>
57
+ </div>
58
+ </div>
59
+ </template>
60
+ ```
61
+
62
+ ## Props
63
+
64
+ | Prop Name | Type | Required | Default | Description |
65
+ | ----------------- | ------------------------------------------------------------- | -------- | -------------------- | ----------------------------------------------- |
66
+ | `value` | `string` | No | `""` | The email address value |
67
+ | `placeholder` | `string` | No | `"name@example.com"` | Placeholder text displayed when empty |
68
+ | `showSuggestions` | `boolean` | No | `true` | Whether to show email domain suggestions |
69
+ | `validateOnType` | `boolean` | No | `true` | Whether to validate email while typing |
70
+ | `allowSubdomains` | `boolean` | No | `true` | Whether to allow subdomains in email validation |
71
+ | `state` | `"normal" \| "active" \| "disabled" \| "readonly" \| "error"` | No | `"normal"` | Current state of the input field |
72
+
73
+ ## Events
74
+
75
+ | Event Name | Payload Type | Description |
76
+ | ------------------- | ------------ | ------------------------------------- |
77
+ | `update:value` | `string` | Emitted when the email value changes |
78
+ | `update:valid` | `boolean` | Emitted when validation state changes |
79
+ | `update:suggestion` | `string` | Emitted when a suggestion is selected |
80
+
81
+ ## Slots
82
+
83
+ This component does not use slots.
84
+
85
+ ## Exposed Methods/Refs
86
+
87
+ This component does not expose any methods or refs.
88
+
89
+ ## Features
90
+
91
+ ### Email Validation
92
+
93
+ - **RFC 5322 Compliant**: Follows email address specification standards
94
+ - **Domain Validation**: Validates domain structure and TLD requirements
95
+ - **Length Limits**: Enforces local part (64 chars) and domain (253 chars) limits
96
+ - **Character Restrictions**: Prevents invalid characters and consecutive dots
97
+ - **TLD Validation**: Ensures top-level domain is at least 2 characters and letters only
98
+
99
+ ### Smart Suggestions
100
+
101
+ - **Common Domains**: Suggests popular email providers (Gmail, Yahoo, Outlook, etc.)
102
+ - **Typo Detection**: Detects and suggests corrections for common domain typos
103
+ - **Keyboard Navigation**: Full keyboard support for suggestion selection
104
+ - **Real-time Filtering**: Filters suggestions based on partial domain input
105
+
106
+ ### Typo Detection
107
+
108
+ The component detects common typos in popular email domains:
109
+
110
+ - `gmial.com` → `gmail.com`
111
+ - `yahooo.com` → `yahoo.com`
112
+ - `hotmial.com` → `hotmail.com`
113
+ - `outloook.com` → `outlook.com`
114
+
115
+ ## CSS Customization
116
+
117
+ The InputEmail component uses CSS custom properties for theming. It inherits from the general input theme:
118
+
119
+ ```css
120
+ /* Input colors */
121
+ --input-background-normal: #ffffff;
122
+ --input-background-filled: #f8f9fa;
123
+ --input-text-empty: #6c757d;
124
+ --input-text-filled: #212529;
125
+ --input-border: #ced4da;
126
+ --input-border-filled: #80bdff;
127
+ --input-focus-border: #007bff;
128
+ --input-placeholder: #6c757d;
129
+ --input-placeholder-filled: #adb5bd;
130
+
131
+ /* State-specific colors */
132
+ --input-disabled-bg: #e9ecef;
133
+ --input-disabled-text: #6c757d;
134
+ --input-disabled-border: #ced4da;
135
+ --input-disabled-placeholder: #adb5bd;
136
+
137
+ --input-readonly-bg: #f8f9fa;
138
+ --input-readonly-text: #495057;
139
+ --input-readonly-border: #ced4da;
140
+ --input-readonly-placeholder: #6c757d;
141
+
142
+ --input-error-bg: #f8d7da;
143
+ --input-error-text: #721c24;
144
+ --input-error-border: #dc3545;
145
+ --input-text-error: #dc3545;
146
+ ```
147
+
148
+ ## Examples
149
+
150
+ ### Basic Email Input
151
+
152
+ ```vue
153
+ <script setup lang="ts">
154
+ import { ref } from "vue";
155
+ import { InputEmail } from "@umbra-ui/core";
156
+
157
+ const email = ref("");
158
+ </script>
159
+
160
+ <template>
161
+ <div class="email-form">
162
+ <h3>Contact Information</h3>
163
+
164
+ <div class="form-group">
165
+ <label>Email Address</label>
166
+ <InputEmail
167
+ v-model:value="email"
168
+ placeholder="your.email@example.com"
169
+ :showSuggestions="true"
170
+ />
171
+ </div>
172
+ </div>
173
+ </template>
174
+
175
+ <style module>
176
+ .email-form {
177
+ max-width: 400px;
178
+ padding: 1.5rem;
179
+ border: 1px solid #e0e0e0;
180
+ border-radius: 8px;
181
+ }
182
+
183
+ .form-group {
184
+ margin-bottom: 1rem;
185
+ }
186
+
187
+ label {
188
+ display: block;
189
+ margin-bottom: 0.5rem;
190
+ font-weight: 500;
191
+ color: #333;
192
+ }
193
+ </style>
194
+ ```
195
+
196
+ ### Registration Form
197
+
198
+ ```vue
199
+ <script setup lang="ts">
200
+ import { ref, computed } from "vue";
201
+ import { InputEmail } from "@umbra-ui/core";
202
+
203
+ const formData = ref({
204
+ firstName: "",
205
+ lastName: "",
206
+ email: "",
207
+ emailValid: false,
208
+ password: "",
209
+ confirmPassword: "",
210
+ });
211
+
212
+ const canSubmit = computed(() => {
213
+ return (
214
+ formData.value.firstName &&
215
+ formData.value.lastName &&
216
+ formData.value.email &&
217
+ formData.value.emailValid &&
218
+ formData.value.password &&
219
+ formData.value.confirmPassword &&
220
+ formData.value.password === formData.value.confirmPassword
221
+ );
222
+ });
223
+
224
+ const handleSubmit = () => {
225
+ if (canSubmit.value) {
226
+ console.log("Registration data:", formData.value);
227
+ // Process registration logic here
228
+ }
229
+ };
230
+ </script>
231
+
232
+ <template>
233
+ <div class="registration-form">
234
+ <h3>Create Account</h3>
235
+
236
+ <form @submit.prevent="handleSubmit">
237
+ <div class="form-row">
238
+ <div class="form-group">
239
+ <label>First Name</label>
240
+ <input
241
+ v-model="formData.firstName"
242
+ type="text"
243
+ placeholder="John"
244
+ required
245
+ />
246
+ </div>
247
+
248
+ <div class="form-group">
249
+ <label>Last Name</label>
250
+ <input
251
+ v-model="formData.lastName"
252
+ type="text"
253
+ placeholder="Doe"
254
+ required
255
+ />
256
+ </div>
257
+ </div>
258
+
259
+ <div class="form-group">
260
+ <label>Email Address</label>
261
+ <InputEmail
262
+ v-model:value="formData.email"
263
+ @update:valid="formData.emailValid = $event"
264
+ placeholder="john.doe@example.com"
265
+ :showSuggestions="true"
266
+ :validateOnType="true"
267
+ />
268
+ </div>
269
+
270
+ <div class="form-group">
271
+ <label>Password</label>
272
+ <input
273
+ v-model="formData.password"
274
+ type="password"
275
+ placeholder="Enter your password"
276
+ required
277
+ />
278
+ </div>
279
+
280
+ <div class="form-group">
281
+ <label>Confirm Password</label>
282
+ <input
283
+ v-model="formData.confirmPassword"
284
+ type="password"
285
+ placeholder="Confirm your password"
286
+ required
287
+ />
288
+ </div>
289
+
290
+ <button type="submit" :disabled="!canSubmit">Create Account</button>
291
+ </form>
292
+ </div>
293
+ </template>
294
+
295
+ <style module>
296
+ .registration-form {
297
+ max-width: 500px;
298
+ padding: 1.5rem;
299
+ border: 1px solid #e0e0e0;
300
+ border-radius: 8px;
301
+ }
302
+
303
+ .form-row {
304
+ display: grid;
305
+ grid-template-columns: 1fr 1fr;
306
+ gap: 1rem;
307
+ }
308
+
309
+ .form-group {
310
+ margin-bottom: 1rem;
311
+ }
312
+
313
+ label {
314
+ display: block;
315
+ margin-bottom: 0.5rem;
316
+ font-weight: 500;
317
+ color: #333;
318
+ }
319
+
320
+ input {
321
+ width: 100%;
322
+ padding: 0.5rem;
323
+ border: 1px solid #ddd;
324
+ border-radius: 4px;
325
+ font-size: 1rem;
326
+ }
327
+
328
+ button {
329
+ width: 100%;
330
+ padding: 0.75rem;
331
+ background-color: #007bff;
332
+ color: white;
333
+ border: none;
334
+ border-radius: 4px;
335
+ cursor: pointer;
336
+ font-size: 1rem;
337
+ }
338
+
339
+ button:disabled {
340
+ background-color: #ccc;
341
+ cursor: not-allowed;
342
+ }
343
+ </style>
344
+ ```
345
+
346
+ ### Different States
347
+
348
+ ```vue
349
+ <script setup lang="ts">
350
+ import { ref } from "vue";
351
+ import { InputEmail } from "@umbra-ui/core";
352
+
353
+ const normalEmail = ref("");
354
+ const disabledEmail = ref("user@example.com");
355
+ const readonlyEmail = ref("admin@company.com");
356
+ const errorEmail = ref("invalid-email");
357
+ </script>
358
+
359
+ <template>
360
+ <div class="states-example">
361
+ <h3>Email Input States</h3>
362
+
363
+ <div class="state-group">
364
+ <label>Normal State</label>
365
+ <InputEmail
366
+ v-model:value="normalEmail"
367
+ placeholder="Enter your email"
368
+ state="normal"
369
+ />
370
+ </div>
371
+
372
+ <div class="state-group">
373
+ <label>Disabled State</label>
374
+ <InputEmail v-model:value="disabledEmail" state="disabled" />
375
+ </div>
376
+
377
+ <div class="state-group">
378
+ <label>Readonly State</label>
379
+ <InputEmail v-model:value="readonlyEmail" state="readonly" />
380
+ </div>
381
+
382
+ <div class="state-group">
383
+ <label>Error State (Invalid Email)</label>
384
+ <InputEmail v-model:value="errorEmail" state="normal" />
385
+ </div>
386
+ </div>
387
+ </template>
388
+
389
+ <style module>
390
+ .states-example {
391
+ max-width: 500px;
392
+ padding: 1.5rem;
393
+ border: 1px solid #e0e0e0;
394
+ border-radius: 8px;
395
+ }
396
+
397
+ .state-group {
398
+ margin-bottom: 1.5rem;
399
+ }
400
+
401
+ label {
402
+ display: block;
403
+ margin-bottom: 0.5rem;
404
+ font-weight: 500;
405
+ color: #333;
406
+ }
407
+ </style>
408
+ ```
409
+
410
+ ### Suggestion Features Demo
411
+
412
+ ```vue
413
+ <script setup lang="ts">
414
+ import { ref } from "vue";
415
+ import { InputEmail } from "@umbra-ui/core";
416
+
417
+ const email = ref("");
418
+ const selectedSuggestion = ref("");
419
+
420
+ const testEmails = ref([
421
+ "user@gmial.com", // Typo: should suggest gmail.com
422
+ "test@yahooo.com", // Typo: should suggest yahoo.com
423
+ "admin@hotmial.com", // Typo: should suggest hotmail.com
424
+ "contact@outloook.com", // Typo: should suggest outlook.com
425
+ ]);
426
+
427
+ const testEmail = (testEmail: string) => {
428
+ email.value = testEmail;
429
+ };
430
+ </script>
431
+
432
+ <template>
433
+ <div class="suggestions-demo">
434
+ <h3>Email Suggestions & Typo Detection</h3>
435
+
436
+ <div class="demo-input">
437
+ <InputEmail
438
+ v-model:value="email"
439
+ @update:suggestion="selectedSuggestion = $event"
440
+ placeholder="Try typing with typos..."
441
+ :showSuggestions="true"
442
+ :validateOnType="true"
443
+ />
444
+
445
+ <div v-if="selectedSuggestion" class="suggestion-info">
446
+ <p><strong>Selected Suggestion:</strong> {{ selectedSuggestion }}</p>
447
+ </div>
448
+ </div>
449
+
450
+ <div class="test-emails">
451
+ <h4>Test Emails with Common Typos</h4>
452
+ <div class="test-buttons">
453
+ <button
454
+ v-for="testEmail in testEmails"
455
+ :key="testEmail"
456
+ @click="testEmail(testEmail)"
457
+ class="test-button"
458
+ >
459
+ {{ testEmail }}
460
+ </button>
461
+ </div>
462
+ </div>
463
+ </div>
464
+ </template>
465
+
466
+ <style module>
467
+ .suggestions-demo {
468
+ max-width: 600px;
469
+ padding: 1.5rem;
470
+ border: 1px solid #e0e0e0;
471
+ border-radius: 8px;
472
+ }
473
+
474
+ .demo-input {
475
+ margin-bottom: 2rem;
476
+ }
477
+
478
+ .suggestion-info {
479
+ margin-top: 1rem;
480
+ padding: 1rem;
481
+ background-color: #d4edda;
482
+ border-radius: 4px;
483
+ color: #155724;
484
+ }
485
+
486
+ .test-emails h4 {
487
+ margin-bottom: 1rem;
488
+ color: #333;
489
+ }
490
+
491
+ .test-buttons {
492
+ display: grid;
493
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
494
+ gap: 0.5rem;
495
+ }
496
+
497
+ .test-button {
498
+ padding: 0.5rem;
499
+ background-color: #6c757d;
500
+ color: white;
501
+ border: none;
502
+ border-radius: 4px;
503
+ cursor: pointer;
504
+ font-size: 0.9rem;
505
+ }
506
+
507
+ .test-button:hover {
508
+ background-color: #5a6268;
509
+ }
510
+ </style>
511
+ ```
512
+
513
+ ### Newsletter Signup
514
+
515
+ ```vue
516
+ <script setup lang="ts">
517
+ import { ref, computed } from "vue";
518
+ import { InputEmail } from "@umbra-ui/core";
519
+
520
+ const email = ref("");
521
+ const isValid = ref(false);
522
+ const isSubscribed = ref(false);
523
+
524
+ const canSubscribe = computed(() => {
525
+ return email.value && isValid.value;
526
+ });
527
+
528
+ const handleSubscribe = () => {
529
+ if (canSubscribe.value) {
530
+ console.log("Subscribing:", email.value);
531
+ isSubscribed.value = true;
532
+ email.value = "";
533
+ isValid.value = false;
534
+ }
535
+ };
536
+ </script>
537
+
538
+ <template>
539
+ <div class="newsletter-signup">
540
+ <h3>Stay Updated</h3>
541
+ <p>Subscribe to our newsletter for the latest updates and news.</p>
542
+
543
+ <div v-if="!isSubscribed" class="signup-form">
544
+ <InputEmail
545
+ v-model:value="email"
546
+ @update:valid="isValid = $event"
547
+ placeholder="your.email@example.com"
548
+ :showSuggestions="true"
549
+ :validateOnType="true"
550
+ />
551
+
552
+ <button
553
+ @click="handleSubscribe"
554
+ :disabled="!canSubscribe"
555
+ class="subscribe-button"
556
+ >
557
+ Subscribe
558
+ </button>
559
+ </div>
560
+
561
+ <div v-else class="success-message">
562
+ <p>✅ Thank you for subscribing! Check your email for confirmation.</p>
563
+ </div>
564
+ </div>
565
+ </template>
566
+
567
+ <style module>
568
+ .newsletter-signup {
569
+ max-width: 400px;
570
+ padding: 1.5rem;
571
+ border: 1px solid #e0e0e0;
572
+ border-radius: 8px;
573
+ text-align: center;
574
+ }
575
+
576
+ .newsletter-signup h3 {
577
+ margin-bottom: 0.5rem;
578
+ color: #333;
579
+ }
580
+
581
+ .newsletter-signup p {
582
+ margin-bottom: 1.5rem;
583
+ color: #666;
584
+ }
585
+
586
+ .signup-form {
587
+ display: flex;
588
+ flex-direction: column;
589
+ gap: 1rem;
590
+ }
591
+
592
+ .subscribe-button {
593
+ padding: 0.75rem;
594
+ background-color: #28a745;
595
+ color: white;
596
+ border: none;
597
+ border-radius: 4px;
598
+ cursor: pointer;
599
+ font-size: 1rem;
600
+ }
601
+
602
+ .subscribe-button:disabled {
603
+ background-color: #ccc;
604
+ cursor: not-allowed;
605
+ }
606
+
607
+ .success-message {
608
+ padding: 1rem;
609
+ background-color: #d4edda;
610
+ border-radius: 4px;
611
+ color: #155724;
612
+ }
613
+ </style>
614
+ ```
615
+
616
+ ### Contact Form
617
+
618
+ ```vue
619
+ <script setup lang="ts">
620
+ import { ref, computed } from "vue";
621
+ import { InputEmail } from "@umbra-ui/core";
622
+
623
+ const contactData = ref({
624
+ name: "",
625
+ email: "",
626
+ emailValid: false,
627
+ subject: "",
628
+ message: "",
629
+ });
630
+
631
+ const canSubmit = computed(() => {
632
+ return (
633
+ contactData.value.name &&
634
+ contactData.value.email &&
635
+ contactData.value.emailValid &&
636
+ contactData.value.subject &&
637
+ contactData.value.message
638
+ );
639
+ });
640
+
641
+ const handleSubmit = () => {
642
+ if (canSubmit.value) {
643
+ console.log("Contact form submitted:", contactData.value);
644
+ // Process contact form logic here
645
+ }
646
+ };
647
+ </script>
648
+
649
+ <template>
650
+ <div class="contact-form">
651
+ <h3>Contact Us</h3>
652
+
653
+ <form @submit.prevent="handleSubmit">
654
+ <div class="form-group">
655
+ <label>Name</label>
656
+ <input
657
+ v-model="contactData.name"
658
+ type="text"
659
+ placeholder="Your full name"
660
+ required
661
+ />
662
+ </div>
663
+
664
+ <div class="form-group">
665
+ <label>Email</label>
666
+ <InputEmail
667
+ v-model:value="contactData.email"
668
+ @update:valid="contactData.emailValid = $event"
669
+ placeholder="your.email@example.com"
670
+ :showSuggestions="true"
671
+ />
672
+ </div>
673
+
674
+ <div class="form-group">
675
+ <label>Subject</label>
676
+ <input
677
+ v-model="contactData.subject"
678
+ type="text"
679
+ placeholder="What's this about?"
680
+ required
681
+ />
682
+ </div>
683
+
684
+ <div class="form-group">
685
+ <label>Message</label>
686
+ <textarea
687
+ v-model="contactData.message"
688
+ placeholder="Tell us more..."
689
+ rows="5"
690
+ required
691
+ ></textarea>
692
+ </div>
693
+
694
+ <button type="submit" :disabled="!canSubmit">Send Message</button>
695
+ </form>
696
+ </div>
697
+ </template>
698
+
699
+ <style module>
700
+ .contact-form {
701
+ max-width: 500px;
702
+ padding: 1.5rem;
703
+ border: 1px solid #e0e0e0;
704
+ border-radius: 8px;
705
+ }
706
+
707
+ .form-group {
708
+ margin-bottom: 1rem;
709
+ }
710
+
711
+ label {
712
+ display: block;
713
+ margin-bottom: 0.5rem;
714
+ font-weight: 500;
715
+ color: #333;
716
+ }
717
+
718
+ input,
719
+ textarea {
720
+ width: 100%;
721
+ padding: 0.5rem;
722
+ border: 1px solid #ddd;
723
+ border-radius: 4px;
724
+ font-size: 1rem;
725
+ font-family: inherit;
726
+ }
727
+
728
+ textarea {
729
+ resize: vertical;
730
+ min-height: 120px;
731
+ }
732
+
733
+ button {
734
+ width: 100%;
735
+ padding: 0.75rem;
736
+ background-color: #007bff;
737
+ color: white;
738
+ border: none;
739
+ border-radius: 4px;
740
+ cursor: pointer;
741
+ font-size: 1rem;
742
+ }
743
+
744
+ button:disabled {
745
+ background-color: #ccc;
746
+ cursor: not-allowed;
747
+ }
748
+ </style>
749
+ ```
750
+
751
+ ## Notes
752
+
753
+ - The component automatically converts input to lowercase for consistency
754
+ - Email validation follows RFC 5322 standards with additional domain structure checks
755
+ - Suggestions appear when the user types "@" and include common email providers
756
+ - Typo detection works for popular email domains with automatic correction suggestions
757
+ - The component includes smooth animations for suggestions dropdown and validation states
758
+ - Keyboard navigation is fully supported (Arrow keys, Enter, Escape)
759
+ - Paste operations automatically extract email addresses from common formats
760
+ - The component prevents multiple "@" symbols and removes spaces automatically
761
+ - Visual feedback includes envelope icon, validation checkmark, and error warning
762
+ - The component is fully accessible with proper ARIA attributes and keyboard navigation
763
+ - Input is optimized for mobile devices with proper input modes and font sizes
764
+ - Validation can be configured to run on every keystroke or only when appropriate