@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,370 @@
1
+ # Dropdown
2
+
3
+ A fully-featured dropdown component built with Vue 3 Composition API and TypeScript. The Dropdown component provides a customizable select interface with keyboard navigation, accessibility features, and smooth animations.
4
+
5
+ ## Installation/Import
6
+
7
+ ```typescript
8
+ import { Dropdown } from "@umbra-ui/core";
9
+ import type { DropdownItem } from "@umbra-ui/core";
10
+ ```
11
+
12
+ **Dependencies:**
13
+
14
+ - Vue 3.x
15
+ - @umbra-ui/icons (for chevron icon)
16
+ - @umbra-ui/core (Button component)
17
+
18
+ ## Basic Usage
19
+
20
+ ```vue
21
+ <script setup lang="ts">
22
+ import { ref } from "vue";
23
+ import { Dropdown } from "@umbra-ui/core";
24
+ import type { DropdownItem } from "@umbra-ui/core";
25
+
26
+ const selectedItem = ref<DropdownItem | null>(null);
27
+
28
+ const dropdownItems: DropdownItem[] = [
29
+ { id: "1", title: "Option 1" },
30
+ { id: "2", title: "Option 2" },
31
+ { id: "3", title: "Option 3" },
32
+ ];
33
+
34
+ const handleSelectionChange = (item: DropdownItem | null) => {
35
+ console.log("Selected item:", item);
36
+ selectedItem.value = item;
37
+ };
38
+ </script>
39
+
40
+ <template>
41
+ <Dropdown
42
+ :items="dropdownItems"
43
+ v-model="selectedItem"
44
+ placeholder="Choose an option"
45
+ @change="handleSelectionChange"
46
+ />
47
+ </template>
48
+ ```
49
+
50
+ ## Props
51
+
52
+ | Prop Name | Type | Required | Default | Description |
53
+ | ------------- | ---------------------- | -------- | ------------------------------------------------------------------------------------- | -------------------------------------------- |
54
+ | `items` | `DropdownItem[]` | Yes | `[{ id: "1", title: "One" }, { id: "2", title: "Two" }, { id: "3", title: "Three" }]` | Array of dropdown items to display |
55
+ | `modelValue` | `DropdownItem \| null` | No | `null` | Currently selected item (v-model support) |
56
+ | `showOverlay` | `boolean` | No | `true` | Whether to show background overlay when open |
57
+ | `placeholder` | `string` | No | `"Select an option"` | Placeholder text when no item is selected |
58
+
59
+ ### DropdownItem Interface
60
+
61
+ ```typescript
62
+ interface DropdownItem {
63
+ id: string | number;
64
+ title: string;
65
+ subtitle?: string;
66
+ disabled?: boolean;
67
+ }
68
+ ```
69
+
70
+ ## Events
71
+
72
+ | Event Name | Payload Type | Description |
73
+ | ------------------- | ---------------------- | ------------------------------------------- |
74
+ | `update:modelValue` | `DropdownItem \| null` | Emitted when selection changes (v-model) |
75
+ | `change` | `DropdownItem \| null` | Emitted when selection changes (additional) |
76
+
77
+ ### Event Examples
78
+
79
+ ```vue
80
+ <script setup lang="ts">
81
+ import { ref } from "vue";
82
+ import { Dropdown } from "@umbra-ui/core";
83
+ import type { DropdownItem } from "@umbra-ui/core";
84
+
85
+ const selectedItem = ref<DropdownItem | null>(null);
86
+
87
+ const handleModelValueUpdate = (item: DropdownItem | null) => {
88
+ console.log("Model value updated:", item);
89
+ selectedItem.value = item;
90
+ };
91
+
92
+ const handleChange = (item: DropdownItem | null) => {
93
+ console.log("Selection changed:", item);
94
+ };
95
+ </script>
96
+
97
+ <template>
98
+ <Dropdown
99
+ :items="dropdownItems"
100
+ v-model="selectedItem"
101
+ @update:model-value="handleModelValueUpdate"
102
+ @change="handleChange"
103
+ />
104
+ </template>
105
+ ```
106
+
107
+ ## Slots
108
+
109
+ This component does not use slots. All content is controlled via props.
110
+
111
+ ## Exposed Methods/Refs
112
+
113
+ This component does not expose any methods or refs via `defineExpose`.
114
+
115
+ ## CSS Customization
116
+
117
+ The Dropdown component uses CSS custom properties that can be overridden to customize the appearance:
118
+
119
+ ### Color Variables
120
+
121
+ ```css
122
+ /* Dropdown popover colors */
123
+ --dropdown-popover-bg: #ffffff;
124
+ --dropdown-popover-border: 1px solid rgba(0, 0, 0, 0.1);
125
+ --dropdown-shadow-dark: transparent;
126
+ --dropdown-shadow-light: rgba(255, 255, 255, 0.7);
127
+
128
+ /* Dropdown item colors */
129
+ --dropdown-item-border: rgba(0, 0, 0, 0.08);
130
+ --dropdown-item-hover-bg: #f0f2f4;
131
+ --dropdown-item-focused-bg: rgba(0, 0, 0, 0.04);
132
+ --dropdown-item-selected-bg: rgba(0, 144, 255, 0.1);
133
+ --dropdown-item-selected-hover-bg: rgba(0, 144, 255, 0.15);
134
+ --dropdown-item-subtitle: #60646c;
135
+
136
+ /* Icon colors */
137
+ --dropdown-icon-color: #1a1d23;
138
+ --dropdown-icon-color-default: #1a1d23;
139
+ --dropdown-icon-color-secondary: #60646c;
140
+
141
+ /* Overlay color */
142
+ --dropdown-overlay-bg: rgba(0, 0, 0, 0.1);
143
+ ```
144
+
145
+ ### Custom Styling Example
146
+
147
+ ```vue
148
+ <template>
149
+ <Dropdown :items="items" v-model="selectedItem" class="custom-dropdown" />
150
+ </template>
151
+
152
+ <style>
153
+ .custom-dropdown {
154
+ --dropdown-item-selected-bg: #ff6b6b;
155
+ --dropdown-item-selected-hover-bg: #ff5252;
156
+ --dropdown-popover-bg: #f8f9fa;
157
+ }
158
+ </style>
159
+ ```
160
+
161
+ ## Examples
162
+
163
+ ### Basic Dropdown
164
+
165
+ ```vue
166
+ <script setup lang="ts">
167
+ import { ref } from "vue";
168
+ import { Dropdown } from "@umbra-ui/core";
169
+ import type { DropdownItem } from "@umbra-ui/core";
170
+
171
+ const selectedItem = ref<DropdownItem | null>(null);
172
+
173
+ const items: DropdownItem[] = [
174
+ { id: "apple", title: "Apple" },
175
+ { id: "banana", title: "Banana" },
176
+ { id: "cherry", title: "Cherry" },
177
+ { id: "date", title: "Date" },
178
+ ];
179
+ </script>
180
+
181
+ <template>
182
+ <Dropdown
183
+ :items="items"
184
+ v-model="selectedItem"
185
+ placeholder="Select a fruit"
186
+ />
187
+ </template>
188
+ ```
189
+
190
+ ### Dropdown with Subtitles
191
+
192
+ ```vue
193
+ <script setup lang="ts">
194
+ import { ref } from "vue";
195
+ import { Dropdown } from "@umbra-ui/core";
196
+ import type { DropdownItem } from "@umbra-ui/core";
197
+
198
+ const selectedUser = ref<DropdownItem | null>(null);
199
+
200
+ const users: DropdownItem[] = [
201
+ { id: "1", title: "John Doe", subtitle: "Software Engineer" },
202
+ { id: "2", title: "Jane Smith", subtitle: "Product Manager" },
203
+ { id: "3", title: "Bob Johnson", subtitle: "Designer" },
204
+ { id: "4", title: "Alice Brown", subtitle: "Marketing Lead" },
205
+ ];
206
+ </script>
207
+
208
+ <template>
209
+ <Dropdown
210
+ :items="users"
211
+ v-model="selectedUser"
212
+ placeholder="Select a team member"
213
+ />
214
+ </template>
215
+ ```
216
+
217
+ ### Dropdown with Disabled Items
218
+
219
+ ```vue
220
+ <script setup lang="ts">
221
+ import { ref } from "vue";
222
+ import { Dropdown } from "@umbra-ui/core";
223
+ import type { DropdownItem } from "@umbra-ui/core";
224
+
225
+ const selectedPlan = ref<DropdownItem | null>(null);
226
+
227
+ const plans: DropdownItem[] = [
228
+ { id: "free", title: "Free Plan", subtitle: "Basic features" },
229
+ { id: "pro", title: "Pro Plan", subtitle: "Advanced features" },
230
+ {
231
+ id: "enterprise",
232
+ title: "Enterprise Plan",
233
+ subtitle: "All features",
234
+ disabled: true,
235
+ },
236
+ ];
237
+ </script>
238
+
239
+ <template>
240
+ <Dropdown :items="plans" v-model="selectedPlan" placeholder="Choose a plan" />
241
+ </template>
242
+ ```
243
+
244
+ ### Form Integration
245
+
246
+ ```vue
247
+ <script setup lang="ts">
248
+ import { ref } from "vue";
249
+ import { Dropdown } from "@umbra-ui/core";
250
+ import type { DropdownItem } from "@umbra-ui/core";
251
+
252
+ interface FormData {
253
+ country: DropdownItem | null;
254
+ city: DropdownItem | null;
255
+ language: DropdownItem | null;
256
+ }
257
+
258
+ const formData = ref<FormData>({
259
+ country: null,
260
+ city: null,
261
+ language: null,
262
+ });
263
+
264
+ const countries: DropdownItem[] = [
265
+ { id: "us", title: "United States" },
266
+ { id: "ca", title: "Canada" },
267
+ { id: "uk", title: "United Kingdom" },
268
+ { id: "de", title: "Germany" },
269
+ ];
270
+
271
+ const cities: DropdownItem[] = [
272
+ { id: "nyc", title: "New York" },
273
+ { id: "la", title: "Los Angeles" },
274
+ { id: "chicago", title: "Chicago" },
275
+ ];
276
+
277
+ const languages: DropdownItem[] = [
278
+ { id: "en", title: "English" },
279
+ { id: "es", title: "Spanish" },
280
+ { id: "fr", title: "French" },
281
+ { id: "de", title: "German" },
282
+ ];
283
+
284
+ const submitForm = () => {
285
+ if (!formData.value.country || !formData.value.language) {
286
+ alert("Please fill in all required fields");
287
+ return;
288
+ }
289
+
290
+ console.log("Form submitted:", formData.value);
291
+ };
292
+ </script>
293
+
294
+ <template>
295
+ <form class="form-example" @submit.prevent="submitForm">
296
+ <div class="form-group">
297
+ <label>Country *</label>
298
+ <Dropdown
299
+ :items="countries"
300
+ v-model="formData.country"
301
+ placeholder="Select country"
302
+ />
303
+ </div>
304
+
305
+ <div class="form-group">
306
+ <label>City</label>
307
+ <Dropdown
308
+ :items="cities"
309
+ v-model="formData.city"
310
+ placeholder="Select city"
311
+ />
312
+ </div>
313
+
314
+ <div class="form-group">
315
+ <label>Language *</label>
316
+ <Dropdown
317
+ :items="languages"
318
+ v-model="formData.language"
319
+ placeholder="Select language"
320
+ />
321
+ </div>
322
+
323
+ <button type="submit">Submit</button>
324
+ </form>
325
+ </template>
326
+
327
+ <style module>
328
+ .form-example {
329
+ display: flex;
330
+ flex-direction: column;
331
+ gap: 1rem;
332
+ max-width: 400px;
333
+ }
334
+
335
+ .form-group {
336
+ display: flex;
337
+ flex-direction: column;
338
+ gap: 0.5rem;
339
+ }
340
+ </style>
341
+ ```
342
+
343
+ ## Keyboard Navigation
344
+
345
+ The Dropdown component supports full keyboard navigation:
346
+
347
+ - **Enter/Space/Arrow Down**: Open dropdown when closed
348
+ - **Arrow Down**: Focus next item
349
+ - **Arrow Up**: Focus previous item
350
+ - **Enter**: Select focused item
351
+ - **Escape**: Close dropdown
352
+
353
+ ## Accessibility Features
354
+
355
+ - Full ARIA support with proper roles (`combobox`, `listbox`, `option`)
356
+ - Keyboard navigation support
357
+ - Screen reader friendly
358
+ - Focus management
359
+ - Proper labeling and descriptions
360
+
361
+ ## Notes
362
+
363
+ - The dropdown automatically positions itself above or below the button based on available space
364
+ - Global overlay system prevents multiple dropdowns from interfering with each other
365
+ - Smooth animations for opening/closing with proper transitions
366
+ - Responsive positioning that adjusts to window resize and scroll events
367
+ - Support for both light and dark themes
368
+ - The component uses a shared overlay system across all instances for better performance
369
+ - Items can be disabled by setting the `disabled` property to `true`
370
+ - The dropdown supports both simple titles and titles with subtitles
@@ -0,0 +1,50 @@
1
+ /* Light theme - semantic naming for dropdown properties */
2
+ :root {
3
+ /* Dropdown popover colors */
4
+ --dropdown-popover-bg: #ffffff;
5
+ --dropdown-popover-border: 1px solid rgba(0, 0, 0, 0.1);
6
+ --dropdown-shadow-dark: transparent;
7
+ --dropdown-shadow-light: rgba(255, 255, 255, 0.7);
8
+
9
+ /* Dropdown item colors */
10
+ --dropdown-item-border: rgba(0, 0, 0, 0.08);
11
+ --dropdown-item-hover-bg: #f0f2f4;
12
+ --dropdown-item-focused-bg: rgba(0, 0, 0, 0.04);
13
+ --dropdown-item-selected-bg: rgba(0, 144, 255, 0.1);
14
+ --dropdown-item-selected-hover-bg: rgba(0, 144, 255, 0.15);
15
+ --dropdown-item-subtitle: #60646c;
16
+
17
+ /* Icon colors - default and secondary styles */
18
+ --dropdown-icon-color: #1a1d23;
19
+ --dropdown-icon-color-default: #1a1d23;
20
+ --dropdown-icon-color-secondary: #60646c;
21
+
22
+ /* Overlay color */
23
+ --dropdown-overlay-bg: rgba(0, 0, 0, 0.1);
24
+ }
25
+
26
+ /* Dark theme */
27
+ .dark,
28
+ .dark-theme {
29
+ /* Dropdown popover colors */
30
+ --dropdown-popover-bg: #484848;
31
+ --dropdown-popover-border: none;
32
+ --dropdown-shadow-dark: rgba(0, 0, 0, 0.21);
33
+ --dropdown-shadow-light: rgba(255, 255, 255, 0.1);
34
+
35
+ /* Dropdown item colors */
36
+ --dropdown-item-border: rgba(255, 255, 255, 0.15);
37
+ --dropdown-item-hover-bg: #222222;
38
+ --dropdown-item-focused-bg: rgba(255, 255, 255, 0.05);
39
+ --dropdown-item-selected-bg: rgba(255, 255, 255, 0.15);
40
+ --dropdown-item-selected-hover-bg: rgba(255, 255, 255, 0.25);
41
+ --dropdown-item-subtitle: #b4b4b4;
42
+
43
+ /* Icon colors - keeping default and secondary styles */
44
+ --dropdown-icon-color: #eeeeee;
45
+ --dropdown-icon-color-default: #eeeeee;
46
+ --dropdown-icon-color-secondary: #60646c;
47
+
48
+ /* Overlay color */
49
+ --dropdown-overlay-bg: rgba(0, 0, 0, 0.5);
50
+ }
@@ -0,0 +1,6 @@
1
+ import { ControlItem } from "../SegmentedControl/types";
2
+
3
+ // Updated DropdownItem interface with required id
4
+ export interface DropdownItem extends ControlItem {
5
+ id: string | number;
6
+ }
@@ -0,0 +1,267 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+ import { CircleAnimOutlineIcon, icons, type IconKey } from "@umbra-ui/icons";
4
+ import type { TooltipConfig } from "../../indicators/Tooltip/types";
5
+ import "./theme.css";
6
+
7
+ interface Props {
8
+ iconName?: IconKey;
9
+ buttonType?: "round" | "square" | "plain";
10
+ buttonStyle?: "primary" | "secondary" | "tertiary" | "quaternary";
11
+ state?: "normal" | "active" | "disabled";
12
+ buttonSize?: number;
13
+ tooltip?: string | TooltipConfig;
14
+ }
15
+
16
+ const props = withDefaults(defineProps<Props>(), {
17
+ iconName: "heart",
18
+ buttonType: "round",
19
+ buttonStyle: "primary",
20
+ state: "normal",
21
+ buttonSize: 16,
22
+ });
23
+
24
+ const emit = defineEmits(["update:state", "click"]);
25
+
26
+ const handleClick = (event: MouseEvent) => {
27
+ emit("click", event);
28
+ };
29
+
30
+ const buttonColor = computed(() => {
31
+ switch (props.buttonStyle) {
32
+ case "primary":
33
+ return "var(--iconbutton-primary-bg)";
34
+ case "secondary":
35
+ return "var(--iconbutton-secondary-bg)";
36
+ case "tertiary":
37
+ return "var(--iconbutton-tertiary-bg)";
38
+ case "quaternary":
39
+ return "var(--iconbutton-quaternary-bg)";
40
+ }
41
+ });
42
+
43
+ const buttonHoverColor = computed(() => {
44
+ switch (props.buttonStyle) {
45
+ case "primary":
46
+ return "var(--iconbutton-primary-hover-bg)";
47
+ case "secondary":
48
+ return "var(--iconbutton-secondary-hover-bg)";
49
+ case "tertiary":
50
+ return "var(--iconbutton-tertiary-hover-bg)";
51
+ case "quaternary":
52
+ return "var(--iconbutton-quaternary-hover-bg)";
53
+ }
54
+ });
55
+
56
+ const buttonColorWithOpacity = computed(() => {
57
+ return `color-mix(in srgb, var(--button-color) 20%, transparent)`;
58
+ });
59
+
60
+ const iconColor = computed(() => {
61
+ // All predefined styles use white
62
+ return "var(--iconbutton-icon-color)";
63
+ });
64
+
65
+ const IconComponent = computed(() => {
66
+ if (!props.iconName) return null;
67
+ return icons[props.iconName as keyof typeof icons] || null;
68
+ });
69
+ </script>
70
+
71
+ <template>
72
+ <div
73
+ v-tooltip="tooltip"
74
+ @click="handleClick"
75
+ :class="[
76
+ $style.container,
77
+ $style[buttonType!],
78
+ $style[buttonStyle!],
79
+ $style[state!],
80
+ ]"
81
+ :style="{
82
+ '--button-color': buttonColor,
83
+ '--button-hover-color': buttonHoverColor,
84
+ '--button-color-opacity': buttonColorWithOpacity,
85
+ '--button-size': `${buttonSize}px`,
86
+ '--icon-color': iconColor,
87
+ }"
88
+ >
89
+ <component v-if="IconComponent" :is="IconComponent" :class="$style.icon" />
90
+ <div :class="$style.animated" v-if="state === 'active'">
91
+ <CircleAnimOutlineIcon />
92
+ </div>
93
+ </div>
94
+ </template>
95
+
96
+ <style module>
97
+ .container {
98
+ display: flex;
99
+ align-items: center;
100
+ justify-content: center;
101
+ background-color: var(--button-color);
102
+ padding: 0.5rem;
103
+ transition: 0.3s ease-in-out transform, 0.3s ease-in-out background-color,
104
+ 0.3s ease-in-out box-shadow, 0.3s ease-in-out border, 0.3s ease-in-out color,
105
+ 0.3s ease-in-out opacity;
106
+ will-change: transform;
107
+ width: fit-content;
108
+ height: fit-content;
109
+ cursor: pointer;
110
+ }
111
+
112
+ .container:hover {
113
+ transform: scale(1.05);
114
+ }
115
+ .container:active {
116
+ transform: scale(1);
117
+ }
118
+
119
+ .icon {
120
+ width: var(--button-size);
121
+ height: var(--button-size);
122
+ color: var(--icon-color);
123
+ }
124
+ .round {
125
+ border-radius: 50%;
126
+ }
127
+ .square {
128
+ border-radius: 0.353rem;
129
+ padding: 0.5rem;
130
+ }
131
+ .plain {
132
+ border-radius: 0;
133
+ padding: 0;
134
+ color: var(--button-color);
135
+ background-color: transparent;
136
+ }
137
+ .plain .icon {
138
+ color: var(--button-color);
139
+ }
140
+ .plain:hover {
141
+ transform: scale(1.15);
142
+ }
143
+ .plain:active {
144
+ transform: scale(1);
145
+ }
146
+ .plain.primary {
147
+ background-color: transparent;
148
+ color: var(--iconbutton-plain-primary);
149
+ box-shadow: none;
150
+ }
151
+ .plain.primary:hover {
152
+ background-color: transparent;
153
+ box-shadow: none;
154
+ }
155
+ .plain.secondary {
156
+ background-color: transparent;
157
+ color: var(--iconbutton-plain-secondary);
158
+ border: none;
159
+ }
160
+ .plain.secondary:hover {
161
+ background-color: transparent;
162
+ box-shadow: none;
163
+ border: none;
164
+ }
165
+ .plain.secondary .icon {
166
+ color: var(--iconbutton-plain-secondary);
167
+ }
168
+ .plain.tertiary .icon {
169
+ color: var(--iconbutton-plain-tertiary);
170
+ }
171
+ .plain.quaternary .icon {
172
+ color: var(--iconbutton-plain-quaternary);
173
+ }
174
+ .plain.tertiary {
175
+ background-color: transparent;
176
+ color: var(--iconbutton-plain-tertiary);
177
+ border: none;
178
+ box-shadow: none;
179
+ }
180
+ .plain.tertiary:hover {
181
+ background-color: transparent;
182
+ box-shadow: none;
183
+ border: none;
184
+ }
185
+ .plain.quaternary {
186
+ background-color: transparent;
187
+ color: var(--iconbutton-plain-quaternary);
188
+ border: none;
189
+ }
190
+ .plain.quaternary:hover {
191
+ background-color: transparent;
192
+ box-shadow: none;
193
+ border: none;
194
+ }
195
+ .primary {
196
+ background-color: var(--iconbutton-primary-bg);
197
+ box-shadow: inset 0 0 0 1px var(--iconbutton-primary-border);
198
+ color: var(--iconbutton-icon-primary-color);
199
+ }
200
+ .primary.round .icon {
201
+ color: var(--iconbutton-icon-primary-color);
202
+ }
203
+ .primary.square .icon {
204
+ color: var(--iconbutton-icon-primary-color);
205
+ }
206
+ .primary:hover {
207
+ background-color: var(--button-hover-color);
208
+ box-shadow: inset 0 0 0 1px var(--iconbutton-primary-hover-border);
209
+ }
210
+ .secondary {
211
+ background-color: var(--iconbutton-secondary-bg);
212
+ border: 1px solid var(--iconbutton-secondary-border);
213
+ }
214
+ .secondary:hover {
215
+ background-color: var(--button-hover-color);
216
+ border: 1px solid var(--iconbutton-secondary-hover-border);
217
+ }
218
+ .tertiary {
219
+ background-color: var(--iconbutton-tertiary-bg);
220
+ border: 1px solid var(--iconbutton-tertiary-border);
221
+ }
222
+ .tertiary:hover {
223
+ background-color: var(--iconbutton-tertiary-hover-bg);
224
+ border: 1px solid var(--iconbutton-tertiary-hover-border);
225
+ }
226
+ .quaternary {
227
+ background-color: var(--iconbutton-quaternary-bg);
228
+ border: 1px solid var(--iconbutton-quaternary-border);
229
+ }
230
+ .quaternary:hover {
231
+ background-color: var(--iconbutton-quaternary-hover-bg);
232
+ border: 1px solid var(--iconbutton-quaternary-hover-border);
233
+ }
234
+
235
+ .active {
236
+ opacity: var(--iconbutton-active-opacity);
237
+ cursor: pointer;
238
+ pointer-events: none;
239
+ }
240
+ .plain.active {
241
+ padding: 0.5rem;
242
+ }
243
+
244
+ .disabled {
245
+ opacity: var(--iconbutton-disabled-opacity);
246
+ cursor: not-allowed;
247
+ pointer-events: none;
248
+ filter: grayscale(100%);
249
+ }
250
+
251
+ .animated {
252
+ position: absolute;
253
+ top: 0;
254
+ left: 0;
255
+ bottom: 0;
256
+ right: 0;
257
+ border-radius: inherit;
258
+ display: flex;
259
+ align-items: center;
260
+ justify-content: center;
261
+ overflow: visible;
262
+ }
263
+ .animated svg {
264
+ width: 90%;
265
+ height: 90%;
266
+ }
267
+ </style>