@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,1115 @@
1
+ # CollectionPicker
2
+
3
+ A versatile collection picker component built with Vue 3 Composition API and TypeScript. The CollectionPicker provides an intuitive interface for selecting items from a collection with support for creating new items, customizable icons, and smart positioning using Floating UI.
4
+
5
+ ## Installation/Import
6
+
7
+ ```typescript
8
+ import { CollectionPicker } from "@umbra-ui/core";
9
+ import type { CollectionItem } from "@umbra-ui/core";
10
+ ```
11
+
12
+ **Dependencies:**
13
+
14
+ - Vue 3.x
15
+ - @floating-ui/vue (for positioning)
16
+ - @umbra-ui/icons (for icon support)
17
+ - @umbra-ui/core (for IconButton)
18
+
19
+ ## Basic Usage
20
+
21
+ ```vue
22
+ <script setup lang="ts">
23
+ import { ref } from "vue";
24
+ import { CollectionPicker } from "@umbra-ui/core";
25
+ import type { CollectionItem } from "@umbra-ui/core";
26
+
27
+ const items = ref<CollectionItem[]>([
28
+ { id: "1", title: "Project Alpha" },
29
+ { id: "2", title: "Project Beta" },
30
+ { id: "3", title: "Project Gamma" },
31
+ ]);
32
+
33
+ const selectedItem = ref<CollectionItem | null>(null);
34
+
35
+ const handleItemSelected = (item: CollectionItem) => {
36
+ console.log("Selected item:", item);
37
+ };
38
+
39
+ const handleItemCreate = (title: string) => {
40
+ const newItem: CollectionItem = {
41
+ id: Date.now().toString(),
42
+ title: title,
43
+ };
44
+ items.value.push(newItem);
45
+ selectedItem.value = newItem;
46
+ console.log("Created new item:", newItem);
47
+ };
48
+ </script>
49
+
50
+ <template>
51
+ <div class="app">
52
+ <h2>Select a Project</h2>
53
+
54
+ <CollectionPicker
55
+ v-model:selected-item="selectedItem"
56
+ :items="items"
57
+ button-label="Choose Project"
58
+ header-label="Select a Project"
59
+ new-item-label="Create New Project"
60
+ @item-selected="handleItemSelected"
61
+ @item-create="handleItemCreate"
62
+ />
63
+
64
+ <div v-if="selectedItem" class="selected-info">
65
+ <p>Selected: {{ selectedItem.title }}</p>
66
+ </div>
67
+ </div>
68
+ </template>
69
+
70
+ <style module>
71
+ .app {
72
+ padding: 24px;
73
+ max-width: 400px;
74
+ }
75
+
76
+ .selected-info {
77
+ margin-top: 16px;
78
+ padding: 12px;
79
+ background: #f8f9fa;
80
+ border-radius: 6px;
81
+ }
82
+ </style>
83
+ ```
84
+
85
+ ## Props
86
+
87
+ | Prop Name | Type | Required | Default | Description |
88
+ | -------------- | ------------------------ | -------- | ------------------ | --------------------------------------- |
89
+ | `items` | `CollectionItem[]` | Yes | `[]` | Array of items to display in the picker |
90
+ | `selectedItem` | `CollectionItem \| null` | No | `null` | Currently selected item |
91
+ | `loading` | `boolean` | No | `false` | Whether the picker is in loading state |
92
+ | `buttonLabel` | `string` | No | `"Select Item"` | Label for the trigger button |
93
+ | `headerLabel` | `string` | No | `"Choose an Item"` | Header text in the picker |
94
+ | `newItemLabel` | `string` | No | `"New Item"` | Label for the create new item option |
95
+ | `itemIcon` | `string` | No | `"note"` | Icon name for items |
96
+ | `newItemIcon` | `string` | No | `"circle-plus"` | Icon name for create new item |
97
+ | `allowCreate` | `boolean` | No | `true` | Whether to allow creating new items |
98
+ | `placeholder` | `string` | No | `"Enter name..."` | Placeholder text for new item input |
99
+
100
+ ## CollectionItem Interface
101
+
102
+ ```typescript
103
+ interface CollectionItem {
104
+ id: string;
105
+ title: string;
106
+ [key: string]: any; // Allow additional properties
107
+ }
108
+ ```
109
+
110
+ ### CollectionItem Properties
111
+
112
+ | Property | Type | Description |
113
+ | --------------- | -------- | ------------------------------ |
114
+ | `id` | `string` | Unique identifier for the item |
115
+ | `title` | `string` | Display text for the item |
116
+ | `[key: string]` | `any` | Additional custom properties |
117
+
118
+ ## Events
119
+
120
+ | Event Name | Payload Type | Description |
121
+ | --------------------- | ------------------------ | ------------------------------------------ |
122
+ | `item-selected` | `CollectionItem` | Emitted when an item is selected |
123
+ | `item-create` | `string` | Emitted when a new item is created (title) |
124
+ | `update:selectedItem` | `CollectionItem \| null` | Emitted when the selected item changes |
125
+
126
+ ## CSS Customization
127
+
128
+ ### Layout Variables
129
+
130
+ ```css
131
+ .collection-picker {
132
+ --picker-button-bg: #ffffff;
133
+ --picker-button-border: 1px solid #e9ecef;
134
+ --picker-button-hover-bg: #f8f9fa;
135
+ --picker-button-hover-border: 1px solid #dee2e6;
136
+ --picker-button-hover-shadow: rgba(0, 0, 0, 0.1);
137
+ --picker-button-hover-inset-shadow: rgba(255, 255, 255, 0.1);
138
+ --picker-button-selected-bg: #e3f2fd;
139
+ --picker-picker-bg: #ffffff;
140
+ --picker-picker-border: 1px solid #e9ecef;
141
+ --picker-picker-shadow: rgba(0, 0, 0, 0.1);
142
+ --picker-picker-inset-shadow: rgba(255, 255, 255, 0.1);
143
+ --picker-selection-bar-bg: #f8f9fa;
144
+ --picker-border-light: #e9ecef;
145
+ --picker-text-primary: #212529;
146
+ --picker-text-secondary: #6c757d;
147
+ --picker-bg-hover: #f8f9fa;
148
+ --picker-overlay-bg: rgba(0, 0, 0, 0.1);
149
+ }
150
+ ```
151
+
152
+ ### Container Styling
153
+
154
+ ```css
155
+ .collection-picker {
156
+ display: flex;
157
+ flex-direction: column;
158
+ align-items: start;
159
+ gap: 0.235rem;
160
+ }
161
+ ```
162
+
163
+ ### Button Styling
164
+
165
+ ```css
166
+ .collection-picker .button {
167
+ border-radius: 0.353rem;
168
+ padding: 0.588rem;
169
+ display: flex;
170
+ align-items: center;
171
+ justify-content: space-between;
172
+ cursor: default;
173
+ background-color: var(--picker-button-bg);
174
+ border: var(--picker-button-border);
175
+ transition: all 0.3s ease;
176
+ }
177
+ ```
178
+
179
+ ### Picker Styling
180
+
181
+ ```css
182
+ .collection-picker .picker {
183
+ position: absolute;
184
+ background-color: var(--picker-picker-bg);
185
+ border-radius: 0.353rem;
186
+ min-width: 18.824rem;
187
+ overflow: hidden;
188
+ z-index: 1000;
189
+ box-shadow: var(--picker-picker-shadow);
190
+ border: var(--picker-picker-border);
191
+ }
192
+ ```
193
+
194
+ ## Examples
195
+
196
+ ### Project Selector
197
+
198
+ ```vue
199
+ <script setup lang="ts">
200
+ import { ref } from "vue";
201
+ import { CollectionPicker } from "@umbra-ui/core";
202
+ import type { CollectionItem } from "@umbra-ui/core";
203
+
204
+ const projects = ref<CollectionItem[]>([
205
+ { id: "1", title: "E-commerce Platform", status: "active" },
206
+ { id: "2", title: "Mobile App", status: "development" },
207
+ { id: "3", title: "API Service", status: "completed" },
208
+ { id: "4", title: "Dashboard", status: "planning" },
209
+ ]);
210
+
211
+ const selectedProject = ref<CollectionItem | null>(null);
212
+
213
+ const handleProjectSelected = (project: CollectionItem) => {
214
+ console.log("Selected project:", project);
215
+ };
216
+
217
+ const handleProjectCreate = (title: string) => {
218
+ const newProject: CollectionItem = {
219
+ id: Date.now().toString(),
220
+ title: title,
221
+ status: "planning",
222
+ };
223
+ projects.value.push(newProject);
224
+ selectedProject.value = newProject;
225
+ console.log("Created new project:", newProject);
226
+ };
227
+ </script>
228
+
229
+ <template>
230
+ <div class="project-selector">
231
+ <div class="selector-header">
232
+ <h3>Project Management</h3>
233
+ <p>Select or create a project to work on</p>
234
+ </div>
235
+
236
+ <CollectionPicker
237
+ v-model:selected-item="selectedProject"
238
+ :items="projects"
239
+ button-label="Choose Project"
240
+ header-label="Select a Project"
241
+ new-item-label="Create New Project"
242
+ item-icon="folder"
243
+ new-item-icon="plus"
244
+ placeholder="Enter project name..."
245
+ @item-selected="handleProjectSelected"
246
+ @item-create="handleProjectCreate"
247
+ />
248
+
249
+ <div v-if="selectedProject" class="project-details">
250
+ <h4>{{ selectedProject.title }}</h4>
251
+ <p>Status: {{ selectedProject.status }}</p>
252
+ </div>
253
+ </div>
254
+ </template>
255
+
256
+ <style module>
257
+ .project-selector {
258
+ padding: 24px;
259
+ max-width: 500px;
260
+ background: #ffffff;
261
+ border-radius: 12px;
262
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
263
+ }
264
+
265
+ .selector-header {
266
+ margin-bottom: 24px;
267
+ }
268
+
269
+ .selector-header h3 {
270
+ font-size: 20px;
271
+ font-weight: 600;
272
+ color: #1a202c;
273
+ margin: 0 0 8px 0;
274
+ }
275
+
276
+ .selector-header p {
277
+ color: #718096;
278
+ margin: 0;
279
+ }
280
+
281
+ .project-details {
282
+ margin-top: 20px;
283
+ padding: 16px;
284
+ background: #f7fafc;
285
+ border-radius: 8px;
286
+ border-left: 4px solid #4299e1;
287
+ }
288
+
289
+ .project-details h4 {
290
+ font-size: 16px;
291
+ font-weight: 600;
292
+ color: #2d3748;
293
+ margin: 0 0 8px 0;
294
+ }
295
+
296
+ .project-details p {
297
+ color: #4a5568;
298
+ margin: 0;
299
+ }
300
+ </style>
301
+ ```
302
+
303
+ ### Category Picker
304
+
305
+ ```vue
306
+ <script setup lang="ts">
307
+ import { ref } from "vue";
308
+ import { CollectionPicker } from "@umbra-ui/core";
309
+ import type { CollectionItem } from "@umbra-ui/core";
310
+
311
+ const categories = ref<CollectionItem[]>([
312
+ { id: "1", title: "Technology", color: "#3b82f6", count: 15 },
313
+ { id: "2", title: "Design", color: "#8b5cf6", count: 8 },
314
+ { id: "3", title: "Business", color: "#10b981", count: 12 },
315
+ { id: "4", title: "Marketing", color: "#f59e0b", count: 6 },
316
+ ]);
317
+
318
+ const selectedCategory = ref<CollectionItem | null>(null);
319
+
320
+ const handleCategorySelected = (category: CollectionItem) => {
321
+ console.log("Selected category:", category);
322
+ };
323
+
324
+ const handleCategoryCreate = (title: string) => {
325
+ const newCategory: CollectionItem = {
326
+ id: Date.now().toString(),
327
+ title: title,
328
+ color: "#6b7280",
329
+ count: 0,
330
+ };
331
+ categories.value.push(newCategory);
332
+ selectedCategory.value = newCategory;
333
+ console.log("Created new category:", newCategory);
334
+ };
335
+ </script>
336
+
337
+ <template>
338
+ <div class="category-picker">
339
+ <div class="picker-header">
340
+ <h3>Content Categories</h3>
341
+ <p>Organize your content with categories</p>
342
+ </div>
343
+
344
+ <CollectionPicker
345
+ v-model:selected-item="selectedCategory"
346
+ :items="categories"
347
+ button-label="Select Category"
348
+ header-label="Choose a Category"
349
+ new-item-label="Add New Category"
350
+ item-icon="tag"
351
+ new-item-icon="tag-plus"
352
+ placeholder="Category name..."
353
+ @item-selected="handleCategorySelected"
354
+ @item-create="handleCategoryCreate"
355
+ />
356
+
357
+ <div v-if="selectedCategory" class="category-info">
358
+ <div class="category-header">
359
+ <div
360
+ class="category-color"
361
+ :style="{ backgroundColor: selectedCategory.color }"
362
+ />
363
+ <h4>{{ selectedCategory.title }}</h4>
364
+ </div>
365
+ <p>{{ selectedCategory.count }} items in this category</p>
366
+ </div>
367
+ </div>
368
+ </template>
369
+
370
+ <style module>
371
+ .category-picker {
372
+ padding: 24px;
373
+ max-width: 400px;
374
+ background: #ffffff;
375
+ border-radius: 12px;
376
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
377
+ }
378
+
379
+ .picker-header {
380
+ margin-bottom: 24px;
381
+ }
382
+
383
+ .picker-header h3 {
384
+ font-size: 20px;
385
+ font-weight: 600;
386
+ color: #1a202c;
387
+ margin: 0 0 8px 0;
388
+ }
389
+
390
+ .picker-header p {
391
+ color: #718096;
392
+ margin: 0;
393
+ }
394
+
395
+ .category-info {
396
+ margin-top: 20px;
397
+ padding: 16px;
398
+ background: #f7fafc;
399
+ border-radius: 8px;
400
+ }
401
+
402
+ .category-header {
403
+ display: flex;
404
+ align-items: center;
405
+ gap: 12px;
406
+ margin-bottom: 8px;
407
+ }
408
+
409
+ .category-color {
410
+ width: 16px;
411
+ height: 16px;
412
+ border-radius: 50%;
413
+ }
414
+
415
+ .category-header h4 {
416
+ font-size: 16px;
417
+ font-weight: 600;
418
+ color: #2d3748;
419
+ margin: 0;
420
+ }
421
+
422
+ .category-info p {
423
+ color: #4a5568;
424
+ margin: 0;
425
+ font-size: 14px;
426
+ }
427
+ </style>
428
+ ```
429
+
430
+ ### Team Member Selector
431
+
432
+ ```vue
433
+ <script setup lang="ts">
434
+ import { ref } from "vue";
435
+ import { CollectionPicker } from "@umbra-ui/core";
436
+ import type { CollectionItem } from "@umbra-ui/core";
437
+
438
+ const teamMembers = ref<CollectionItem[]>([
439
+ { id: "1", title: "Alice Johnson", role: "Frontend Developer", avatar: "👩‍💻" },
440
+ { id: "2", title: "Bob Smith", role: "Backend Developer", avatar: "👨‍💻" },
441
+ { id: "3", title: "Carol Davis", role: "UI/UX Designer", avatar: "👩‍🎨" },
442
+ { id: "4", title: "David Wilson", role: "Project Manager", avatar: "👨‍💼" },
443
+ ]);
444
+
445
+ const selectedMember = ref<CollectionItem | null>(null);
446
+
447
+ const handleMemberSelected = (member: CollectionItem) => {
448
+ console.log("Selected team member:", member);
449
+ };
450
+
451
+ const handleMemberCreate = (title: string) => {
452
+ const newMember: CollectionItem = {
453
+ id: Date.now().toString(),
454
+ title: title,
455
+ role: "Team Member",
456
+ avatar: "👤",
457
+ };
458
+ teamMembers.value.push(newMember);
459
+ selectedMember.value = newMember;
460
+ console.log("Added new team member:", newMember);
461
+ };
462
+ </script>
463
+
464
+ <template>
465
+ <div class="team-selector">
466
+ <div class="selector-header">
467
+ <h3>Team Assignment</h3>
468
+ <p>Assign tasks to team members</p>
469
+ </div>
470
+
471
+ <CollectionPicker
472
+ v-model:selected-item="selectedMember"
473
+ :items="teamMembers"
474
+ button-label="Assign to Team Member"
475
+ header-label="Select Team Member"
476
+ new-item-label="Add New Member"
477
+ item-icon="user"
478
+ new-item-icon="user-plus"
479
+ placeholder="Member name..."
480
+ @item-selected="handleMemberSelected"
481
+ @item-create="handleMemberCreate"
482
+ />
483
+
484
+ <div v-if="selectedMember" class="member-details">
485
+ <div class="member-header">
486
+ <span class="member-avatar">{{ selectedMember.avatar }}</span>
487
+ <div class="member-info">
488
+ <h4>{{ selectedMember.title }}</h4>
489
+ <p>{{ selectedMember.role }}</p>
490
+ </div>
491
+ </div>
492
+ </div>
493
+ </div>
494
+ </template>
495
+
496
+ <style module>
497
+ .team-selector {
498
+ padding: 24px;
499
+ max-width: 450px;
500
+ background: #ffffff;
501
+ border-radius: 12px;
502
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
503
+ }
504
+
505
+ .selector-header {
506
+ margin-bottom: 24px;
507
+ }
508
+
509
+ .selector-header h3 {
510
+ font-size: 20px;
511
+ font-weight: 600;
512
+ color: #1a202c;
513
+ margin: 0 0 8px 0;
514
+ }
515
+
516
+ .selector-header p {
517
+ color: #718096;
518
+ margin: 0;
519
+ }
520
+
521
+ .member-details {
522
+ margin-top: 20px;
523
+ padding: 16px;
524
+ background: #f7fafc;
525
+ border-radius: 8px;
526
+ border-left: 4px solid #4299e1;
527
+ }
528
+
529
+ .member-header {
530
+ display: flex;
531
+ align-items: center;
532
+ gap: 12px;
533
+ }
534
+
535
+ .member-avatar {
536
+ font-size: 24px;
537
+ width: 40px;
538
+ height: 40px;
539
+ display: flex;
540
+ align-items: center;
541
+ justify-content: center;
542
+ background: #e2e8f0;
543
+ border-radius: 50%;
544
+ }
545
+
546
+ .member-info h4 {
547
+ font-size: 16px;
548
+ font-weight: 600;
549
+ color: #2d3748;
550
+ margin: 0 0 4px 0;
551
+ }
552
+
553
+ .member-info p {
554
+ color: #4a5568;
555
+ margin: 0;
556
+ font-size: 14px;
557
+ }
558
+ </style>
559
+ ```
560
+
561
+ ### File Type Picker
562
+
563
+ ```vue
564
+ <script setup lang="ts">
565
+ import { ref } from "vue";
566
+ import { CollectionPicker } from "@umbra-ui/core";
567
+ import type { CollectionItem } from "@umbra-ui/core";
568
+
569
+ const fileTypes = ref<CollectionItem[]>([
570
+ { id: "1", title: "Documents", extension: ".doc,.docx,.pdf", icon: "📄" },
571
+ { id: "2", title: "Images", extension: ".jpg,.png,.gif", icon: "🖼️" },
572
+ { id: "3", title: "Videos", extension: ".mp4,.avi,.mov", icon: "🎥" },
573
+ { id: "4", title: "Audio", extension: ".mp3,.wav,.flac", icon: "🎵" },
574
+ { id: "5", title: "Archives", extension: ".zip,.rar,.7z", icon: "📦" },
575
+ ]);
576
+
577
+ const selectedFileType = ref<CollectionItem | null>(null);
578
+
579
+ const handleFileTypeSelected = (fileType: CollectionItem) => {
580
+ console.log("Selected file type:", fileType);
581
+ };
582
+
583
+ const handleFileTypeCreate = (title: string) => {
584
+ const newFileType: CollectionItem = {
585
+ id: Date.now().toString(),
586
+ title: title,
587
+ extension: ".*",
588
+ icon: "📁",
589
+ };
590
+ fileTypes.value.push(newFileType);
591
+ selectedFileType.value = newFileType;
592
+ console.log("Created new file type:", newFileType);
593
+ };
594
+ </script>
595
+
596
+ <template>
597
+ <div class="file-type-picker">
598
+ <div class="picker-header">
599
+ <h3>File Type Filter</h3>
600
+ <p>Filter files by type</p>
601
+ </div>
602
+
603
+ <CollectionPicker
604
+ v-model:selected-item="selectedFileType"
605
+ :items="fileTypes"
606
+ button-label="Select File Type"
607
+ header-label="Choose File Type"
608
+ new-item-label="Add Custom Type"
609
+ item-icon="file"
610
+ new-item-icon="file-plus"
611
+ placeholder="File type name..."
612
+ @item-selected="handleFileTypeSelected"
613
+ @item-create="handleFileTypeCreate"
614
+ />
615
+
616
+ <div v-if="selectedFileType" class="file-type-info">
617
+ <div class="file-type-header">
618
+ <span class="file-type-icon">{{ selectedFileType.icon }}</span>
619
+ <div class="file-type-details">
620
+ <h4>{{ selectedFileType.title }}</h4>
621
+ <p>Extensions: {{ selectedFileType.extension }}</p>
622
+ </div>
623
+ </div>
624
+ </div>
625
+ </div>
626
+ </template>
627
+
628
+ <style module>
629
+ .file-type-picker {
630
+ padding: 24px;
631
+ max-width: 400px;
632
+ background: #ffffff;
633
+ border-radius: 12px;
634
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
635
+ }
636
+
637
+ .picker-header {
638
+ margin-bottom: 24px;
639
+ }
640
+
641
+ .picker-header h3 {
642
+ font-size: 20px;
643
+ font-weight: 600;
644
+ color: #1a202c;
645
+ margin: 0 0 8px 0;
646
+ }
647
+
648
+ .picker-header p {
649
+ color: #718096;
650
+ margin: 0;
651
+ }
652
+
653
+ .file-type-info {
654
+ margin-top: 20px;
655
+ padding: 16px;
656
+ background: #f7fafc;
657
+ border-radius: 8px;
658
+ border-left: 4px solid #10b981;
659
+ }
660
+
661
+ .file-type-header {
662
+ display: flex;
663
+ align-items: center;
664
+ gap: 12px;
665
+ }
666
+
667
+ .file-type-icon {
668
+ font-size: 24px;
669
+ width: 40px;
670
+ height: 40px;
671
+ display: flex;
672
+ align-items: center;
673
+ justify-content: center;
674
+ background: #d1fae5;
675
+ border-radius: 8px;
676
+ }
677
+
678
+ .file-type-details h4 {
679
+ font-size: 16px;
680
+ font-weight: 600;
681
+ color: #2d3748;
682
+ margin: 0 0 4px 0;
683
+ }
684
+
685
+ .file-type-details p {
686
+ color: #4a5568;
687
+ margin: 0;
688
+ font-size: 14px;
689
+ }
690
+ </style>
691
+ ```
692
+
693
+ ### Loading State Example
694
+
695
+ ```vue
696
+ <script setup lang="ts">
697
+ import { ref, onMounted } from "vue";
698
+ import { CollectionPicker } from "@umbra-ui/core";
699
+ import type { CollectionItem } from "@umbra-ui/core";
700
+
701
+ const items = ref<CollectionItem[]>([]);
702
+ const selectedItem = ref<CollectionItem | null>(null);
703
+ const loading = ref(true);
704
+
705
+ // Simulate loading data
706
+ onMounted(async () => {
707
+ // Simulate API call
708
+ await new Promise((resolve) => setTimeout(resolve, 2000));
709
+
710
+ items.value = [
711
+ { id: "1", title: "Item 1" },
712
+ { id: "2", title: "Item 2" },
713
+ { id: "3", title: "Item 3" },
714
+ ];
715
+
716
+ loading.value = false;
717
+ });
718
+
719
+ const handleItemSelected = (item: CollectionItem) => {
720
+ console.log("Selected item:", item);
721
+ };
722
+
723
+ const handleItemCreate = (title: string) => {
724
+ const newItem: CollectionItem = {
725
+ id: Date.now().toString(),
726
+ title: title,
727
+ };
728
+ items.value.push(newItem);
729
+ selectedItem.value = newItem;
730
+ console.log("Created new item:", newItem);
731
+ };
732
+ </script>
733
+
734
+ <template>
735
+ <div class="loading-example">
736
+ <h3>Loading State Example</h3>
737
+
738
+ <CollectionPicker
739
+ v-model:selected-item="selectedItem"
740
+ :items="items"
741
+ :loading="loading"
742
+ button-label="Select Item"
743
+ header-label="Choose an Item"
744
+ new-item-label="Create New Item"
745
+ @item-selected="handleItemSelected"
746
+ @item-create="handleItemCreate"
747
+ />
748
+
749
+ <div v-if="loading" class="loading-message">
750
+ <p>Loading items...</p>
751
+ </div>
752
+ </div>
753
+ </template>
754
+
755
+ <style module>
756
+ .loading-example {
757
+ padding: 24px;
758
+ max-width: 400px;
759
+ }
760
+
761
+ .loading-message {
762
+ margin-top: 16px;
763
+ padding: 12px;
764
+ background: #f8f9fa;
765
+ border-radius: 6px;
766
+ text-align: center;
767
+ }
768
+
769
+ .loading-message p {
770
+ color: #6c757d;
771
+ margin: 0;
772
+ }
773
+ </style>
774
+ ```
775
+
776
+ ## Advanced Usage
777
+
778
+ ### Custom Item Properties
779
+
780
+ ```vue
781
+ <script setup lang="ts">
782
+ import { ref } from "vue";
783
+ import { CollectionPicker } from "@umbra-ui/core";
784
+ import type { CollectionItem } from "@umbra-ui/core";
785
+
786
+ // Extend the base interface for custom properties
787
+ interface CustomItem extends CollectionItem {
788
+ description: string;
789
+ priority: "low" | "medium" | "high";
790
+ tags: string[];
791
+ }
792
+
793
+ const items = ref<CustomItem[]>([
794
+ {
795
+ id: "1",
796
+ title: "Bug Fix",
797
+ description: "Fix critical authentication bug",
798
+ priority: "high",
799
+ tags: ["bug", "auth"],
800
+ },
801
+ {
802
+ id: "2",
803
+ title: "Feature Request",
804
+ description: "Add dark mode support",
805
+ priority: "medium",
806
+ tags: ["feature", "ui"],
807
+ },
808
+ {
809
+ id: "3",
810
+ title: "Documentation",
811
+ description: "Update API documentation",
812
+ priority: "low",
813
+ tags: ["docs", "api"],
814
+ },
815
+ ]);
816
+
817
+ const selectedItem = ref<CustomItem | null>(null);
818
+
819
+ const handleItemSelected = (item: CustomItem) => {
820
+ console.log("Selected item with custom properties:", item);
821
+ };
822
+
823
+ const handleItemCreate = (title: string) => {
824
+ const newItem: CustomItem = {
825
+ id: Date.now().toString(),
826
+ title: title,
827
+ description: "New item",
828
+ priority: "medium",
829
+ tags: [],
830
+ };
831
+ items.value.push(newItem);
832
+ selectedItem.value = newItem;
833
+ };
834
+ </script>
835
+
836
+ <template>
837
+ <div class="custom-properties">
838
+ <CollectionPicker
839
+ v-model:selected-item="selectedItem"
840
+ :items="items"
841
+ button-label="Select Task"
842
+ header-label="Choose a Task"
843
+ new-item-label="Create New Task"
844
+ item-icon="checklist"
845
+ new-item-icon="plus"
846
+ @item-selected="handleItemSelected"
847
+ @item-create="handleItemCreate"
848
+ />
849
+
850
+ <div v-if="selectedItem" class="item-details">
851
+ <h4>{{ selectedItem.title }}</h4>
852
+ <p>{{ selectedItem.description }}</p>
853
+ <div class="item-meta">
854
+ <span class="priority" :class="`priority-${selectedItem.priority}`">
855
+ {{ selectedItem.priority }}
856
+ </span>
857
+ <div class="tags">
858
+ <span v-for="tag in selectedItem.tags" :key="tag" class="tag">
859
+ {{ tag }}
860
+ </span>
861
+ </div>
862
+ </div>
863
+ </div>
864
+ </div>
865
+ </template>
866
+
867
+ <style module>
868
+ .custom-properties {
869
+ padding: 24px;
870
+ max-width: 500px;
871
+ }
872
+
873
+ .item-details {
874
+ margin-top: 20px;
875
+ padding: 16px;
876
+ background: #f7fafc;
877
+ border-radius: 8px;
878
+ }
879
+
880
+ .item-details h4 {
881
+ font-size: 16px;
882
+ font-weight: 600;
883
+ color: #2d3748;
884
+ margin: 0 0 8px 0;
885
+ }
886
+
887
+ .item-details p {
888
+ color: #4a5568;
889
+ margin: 0 0 12px 0;
890
+ }
891
+
892
+ .item-meta {
893
+ display: flex;
894
+ align-items: center;
895
+ gap: 12px;
896
+ }
897
+
898
+ .priority {
899
+ padding: 4px 8px;
900
+ border-radius: 4px;
901
+ font-size: 12px;
902
+ font-weight: 500;
903
+ text-transform: uppercase;
904
+ }
905
+
906
+ .priority-low {
907
+ background: #d1fae5;
908
+ color: #065f46;
909
+ }
910
+
911
+ .priority-medium {
912
+ background: #fef3c7;
913
+ color: #92400e;
914
+ }
915
+
916
+ .priority-high {
917
+ background: #fee2e2;
918
+ color: #991b1b;
919
+ }
920
+
921
+ .tags {
922
+ display: flex;
923
+ gap: 4px;
924
+ }
925
+
926
+ .tag {
927
+ padding: 2px 6px;
928
+ background: #e5e7eb;
929
+ color: #374151;
930
+ border-radius: 3px;
931
+ font-size: 11px;
932
+ }
933
+ </style>
934
+ ```
935
+
936
+ ### Integration with API
937
+
938
+ ```vue
939
+ <script setup lang="ts">
940
+ import { ref, onMounted } from "vue";
941
+ import { CollectionPicker } from "@umbra-ui/core";
942
+ import type { CollectionItem } from "@umbra-ui/core";
943
+
944
+ const items = ref<CollectionItem[]>([]);
945
+ const selectedItem = ref<CollectionItem | null>(null);
946
+ const loading = ref(false);
947
+
948
+ // Simulate API calls
949
+ const fetchItems = async () => {
950
+ loading.value = true;
951
+ try {
952
+ // Simulate API call
953
+ await new Promise((resolve) => setTimeout(resolve, 1000));
954
+ items.value = [
955
+ { id: "1", title: "API Item 1" },
956
+ { id: "2", title: "API Item 2" },
957
+ { id: "3", title: "API Item 3" },
958
+ ];
959
+ } catch (error) {
960
+ console.error("Failed to fetch items:", error);
961
+ } finally {
962
+ loading.value = false;
963
+ }
964
+ };
965
+
966
+ const createItem = async (title: string) => {
967
+ try {
968
+ // Simulate API call
969
+ await new Promise((resolve) => setTimeout(resolve, 500));
970
+ const newItem: CollectionItem = {
971
+ id: Date.now().toString(),
972
+ title: title,
973
+ };
974
+ items.value.push(newItem);
975
+ selectedItem.value = newItem;
976
+ return newItem;
977
+ } catch (error) {
978
+ console.error("Failed to create item:", error);
979
+ throw error;
980
+ }
981
+ };
982
+
983
+ const handleItemSelected = (item: CollectionItem) => {
984
+ console.log("Selected item:", item);
985
+ };
986
+
987
+ const handleItemCreate = async (title: string) => {
988
+ try {
989
+ await createItem(title);
990
+ console.log("Item created successfully");
991
+ } catch (error) {
992
+ console.error("Failed to create item");
993
+ }
994
+ };
995
+
996
+ onMounted(() => {
997
+ fetchItems();
998
+ });
999
+ </script>
1000
+
1001
+ <template>
1002
+ <div class="api-integration">
1003
+ <h3>API Integration Example</h3>
1004
+
1005
+ <CollectionPicker
1006
+ v-model:selected-item="selectedItem"
1007
+ :items="items"
1008
+ :loading="loading"
1009
+ button-label="Select Item"
1010
+ header-label="Choose an Item"
1011
+ new-item-label="Create New Item"
1012
+ @item-selected="handleItemSelected"
1013
+ @item-create="handleItemCreate"
1014
+ />
1015
+
1016
+ <div class="actions">
1017
+ <button @click="fetchItems" :disabled="loading" class="refresh-btn">
1018
+ {{ loading ? "Loading..." : "Refresh Items" }}
1019
+ </button>
1020
+ </div>
1021
+ </div>
1022
+ </template>
1023
+
1024
+ <style module>
1025
+ .api-integration {
1026
+ padding: 24px;
1027
+ max-width: 400px;
1028
+ }
1029
+
1030
+ .actions {
1031
+ margin-top: 16px;
1032
+ }
1033
+
1034
+ .refresh-btn {
1035
+ padding: 8px 16px;
1036
+ background: #007bff;
1037
+ color: white;
1038
+ border: none;
1039
+ border-radius: 6px;
1040
+ cursor: pointer;
1041
+ transition: background 0.2s ease;
1042
+ }
1043
+
1044
+ .refresh-btn:hover:not(:disabled) {
1045
+ background: #0056b3;
1046
+ }
1047
+
1048
+ .refresh-btn:disabled {
1049
+ opacity: 0.6;
1050
+ cursor: not-allowed;
1051
+ }
1052
+ </style>
1053
+ ```
1054
+
1055
+ ## Performance Considerations
1056
+
1057
+ - **Floating UI**: Smart positioning with automatic updates and cleanup
1058
+ - **Teleport**: Overlay and picker are teleported to body for proper z-index management
1059
+ - **Event Cleanup**: Proper cleanup of auto-update listeners on unmount
1060
+ - **Icon Loading**: Icons are loaded on-demand from the @umbra-ui/icons package
1061
+
1062
+ ## Accessibility
1063
+
1064
+ - **Keyboard Navigation**: Support for Enter and Escape keys in input
1065
+ - **Screen Reader Support**: Proper ARIA labels and semantic structure
1066
+ - **Focus Management**: Focus is properly managed during interactions
1067
+ - **Overlay Interaction**: Click outside to close functionality
1068
+
1069
+ ## Browser Support
1070
+
1071
+ - **Modern Browsers**: Chrome 88+, Firefox 85+, Safari 14+, Edge 88+
1072
+ - **Mobile Browsers**: iOS Safari 14+, Chrome Mobile 88+
1073
+ - **CSS Features**: Uses CSS Grid and modern layout features
1074
+ - **JavaScript**: Requires ES2020+ support
1075
+
1076
+ ## Troubleshooting
1077
+
1078
+ ### Common Issues
1079
+
1080
+ 1. **Picker not positioning correctly**: Ensure the trigger button has proper positioning context
1081
+ 2. **Items not displaying**: Check that the items array is properly formatted with id and title
1082
+ 3. **Icons not showing**: Verify icon names match those available in @umbra-ui/icons
1083
+ 4. **Overlay not closing**: Ensure the overlay click handler is properly bound
1084
+
1085
+ ### Debug Mode
1086
+
1087
+ ```vue
1088
+ <script setup lang="ts">
1089
+ import { ref, watch } from "vue";
1090
+ import { CollectionPicker } from "@umbra-ui/core";
1091
+
1092
+ const selectedItem = ref(null);
1093
+
1094
+ // Watch for changes
1095
+ watch(selectedItem, (newItem) => {
1096
+ console.log("Selected item changed:", newItem);
1097
+ });
1098
+ </script>
1099
+ ```
1100
+
1101
+ ## Migration Guide
1102
+
1103
+ ### From v1 to v2
1104
+
1105
+ - `v-model` prop is now `v-model:selected-item`
1106
+ - Event names have been updated to use kebab-case
1107
+ - Icon system has been updated to use @umbra-ui/icons
1108
+ - Floating UI integration has been improved
1109
+
1110
+ ### Breaking Changes
1111
+
1112
+ - Removed `value` prop in favor of `v-model:selected-item`
1113
+ - Changed event names from camelCase to kebab-case
1114
+ - Updated icon prop to use string names instead of components
1115
+ - Modified CSS class naming convention