@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,897 @@
1
+ # Tags Components
2
+
3
+ A comprehensive tag management system built with Vue 3 Composition API and TypeScript. The Tags components provide a powerful interface for creating, selecting, and managing tags with advanced features like real-time search, keyboard navigation, custom styling, and multiple overflow modes.
4
+
5
+ ## Installation/Import
6
+
7
+ ```typescript
8
+ import { TagBar, TagPicker, TagCreation } from "@umbra-ui/core";
9
+ import type { TagItem, TagStyleConfig } from "@umbra-ui/core";
10
+ ```
11
+
12
+ **Dependencies:**
13
+
14
+ - Vue 3.x
15
+ - @umbra-ui/core (for IconButton and ColorPicker components)
16
+ - @umbra-ui/colors (for color schemes)
17
+ - @floating-ui/vue (for positioning)
18
+ - gsap (for animations)
19
+ - tinycolor2 (for color manipulation)
20
+
21
+ ## Basic Usage
22
+
23
+ ```vue
24
+ <script setup lang="ts">
25
+ import { ref } from "vue";
26
+ import { TagBar } from "@umbra-ui/core";
27
+ import type { TagItem } from "@umbra-ui/core";
28
+
29
+ const allTags = ref<TagItem[]>([
30
+ { id: "1", title: "Vue.js" },
31
+ { id: "2", title: "TypeScript" },
32
+ { id: "3", title: "Frontend" },
33
+ ]);
34
+
35
+ const selectedTags = ref<TagItem[]>([]);
36
+ const query = ref("");
37
+ const matchIndex = ref(-1);
38
+
39
+ const handleTagSelect = (tag: TagItem) => {
40
+ selectedTags.value.push(tag);
41
+ };
42
+
43
+ const handleTagRemove = (tag: TagItem) => {
44
+ const index = selectedTags.value.findIndex((t) => t.id === tag.id);
45
+ if (index > -1) {
46
+ selectedTags.value.splice(index, 1);
47
+ }
48
+ };
49
+
50
+ const handleTagCreate = (title: string) => {
51
+ const newTag: TagItem = {
52
+ id: Date.now().toString(),
53
+ title: title.trim(),
54
+ };
55
+ allTags.value.push(newTag);
56
+ selectedTags.value.push(newTag);
57
+ };
58
+ </script>
59
+
60
+ <template>
61
+ <div>
62
+ <TagBar
63
+ :all-tags="allTags"
64
+ :selected-tags="selectedTags"
65
+ v-model:query="query"
66
+ v-model:match-index="matchIndex"
67
+ placeholder="Add tags..."
68
+ overflow="fixed"
69
+ :allow-editing="true"
70
+ @tag-select="handleTagSelect"
71
+ @tag-remove="handleTagRemove"
72
+ @tag-create="handleTagCreate"
73
+ />
74
+ </div>
75
+ </template>
76
+ ```
77
+
78
+ ## Components
79
+
80
+ ### TagBar
81
+
82
+ The main tag management component with input field and tag display.
83
+
84
+ #### Props
85
+
86
+ | Prop Name | Type | Required | Default | Description |
87
+ | -------------- | ----------------------------- | -------- | ------------ | -------------------------------------------- |
88
+ | `allTags` | `TagItem[]` | No | `[]` | Array of all available tags |
89
+ | `selectedTags` | `TagItem[]` | No | `[]` | Array of currently selected tags |
90
+ | `query` | `string` | No | `""` | Current search query |
91
+ | `matchIndex` | `number` | No | `-1` | Index of currently highlighted match |
92
+ | `placeholder` | `string` | No | `"ADD TAGS"` | Placeholder text for the input field |
93
+ | `overflow` | `"full" \| "fixed" \| "list"` | No | `"fixed"` | How tags overflow when they exceed container |
94
+ | `allowEditing` | `boolean` | No | `true` | Whether tags can be edited/removed |
95
+
96
+ #### Events
97
+
98
+ | Event Name | Payload Type | Description |
99
+ | ------------------- | ------------ | ---------------------------------------- |
100
+ | `update:query` | `string` | Emitted when the search query changes |
101
+ | `update:matchIndex` | `number` | Emitted when the match index changes |
102
+ | `tag-create` | `string` | Emitted when a new tag should be created |
103
+ | `tag-select` | `TagItem` | Emitted when a tag is selected |
104
+ | `tag-remove` | `TagItem` | Emitted when a tag is removed |
105
+ | `tag-reorder` | `TagItem[]` | Emitted when tags are reordered |
106
+
107
+ ### TagPicker
108
+
109
+ The dropdown picker component for selecting tags (used internally by TagBar).
110
+
111
+ #### Props
112
+
113
+ | Prop Name | Type | Required | Description |
114
+ | -------------- | ----------- | -------- | ------------------------------------ |
115
+ | `allTags` | `TagItem[]` | Yes | Array of all available tags |
116
+ | `selectedTags` | `TagItem[]` | Yes | Array of currently selected tags |
117
+ | `query` | `string` | Yes | Current search query |
118
+ | `matchIndex` | `number` | Yes | Index of currently highlighted match |
119
+ | `canCreateTag` | `boolean` | No | Whether a new tag can be created |
120
+
121
+ #### Events
122
+
123
+ | Event Name | Payload Type | Description |
124
+ | ------------------- | ------------ | ---------------------------------------- |
125
+ | `tag-select` | `TagItem` | Emitted when a tag is selected |
126
+ | `tag-create` | `string` | Emitted when a new tag should be created |
127
+ | `update:query` | `string` | Emitted when the search query changes |
128
+ | `update:matchIndex` | `number` | Emitted when the match index changes |
129
+ | `quit` | `void` | Emitted when the picker should be closed |
130
+
131
+ ### TagCreation
132
+
133
+ A component for creating new tags with color selection.
134
+
135
+ #### Props
136
+
137
+ | Prop Name | Type | Required | Default | Description |
138
+ | ---------------- | ---------- | -------- | ------- | ------------------------------------------- |
139
+ | `containerID` | `string` | Yes | - | Unique ID for the container |
140
+ | `initialColor` | `Color` | No | Gray | Initial color for the new tag |
141
+ | `existingTitles` | `string[]` | No | `[]` | Array of existing tag titles for validation |
142
+
143
+ #### Events
144
+
145
+ | Event Name | Payload Type | Description |
146
+ | ---------- | --------------- | -------------------------------------------- |
147
+ | `onCreate` | `string, Color` | Emitted when a tag is created (title, color) |
148
+
149
+ ## TagItem Interface
150
+
151
+ ```typescript
152
+ interface TagItem {
153
+ id: string;
154
+ title: string;
155
+ style?: TagStyleConfig;
156
+ }
157
+ ```
158
+
159
+ ## TagStyleConfig Interface
160
+
161
+ ```typescript
162
+ interface TagStyleConfig {
163
+ // Direct CSS properties for full control
164
+ backgroundColor?: string;
165
+ color?: string;
166
+ border?: string;
167
+ borderRadius?: string;
168
+ padding?: string;
169
+ fontSize?: string;
170
+ fontWeight?: string;
171
+ boxShadow?: string;
172
+
173
+ // Optional hover state
174
+ hover?: {
175
+ backgroundColor?: string;
176
+ color?: string;
177
+ border?: string;
178
+ transform?: string;
179
+ boxShadow?: string;
180
+ };
181
+
182
+ // Helper properties for convenience
183
+ size?: "sm" | "md" | "lg";
184
+ colorScheme?: string; // Radix color name or hex
185
+ }
186
+ ```
187
+
188
+ ## CSS Customization
189
+
190
+ The Tags components use CSS custom properties for theming and customization:
191
+
192
+ ### TagBar Variables
193
+
194
+ ```css
195
+ /* TagBar Container */
196
+ --tagbar-bg: var(--tagbar-background);
197
+ --tagbar-border: var(--tagbar-border-color);
198
+ --tagbar-text: var(--tagbar-text-color);
199
+
200
+ /* TagBar Field */
201
+ --tagbar-field-bg: var(--tagbar-field-background);
202
+ --tagbar-field-text: var(--tagbar-field-text-color);
203
+
204
+ /* TagBar List */
205
+ --tagbar-list-border: var(--tagbar-list-border-color);
206
+ ```
207
+
208
+ ### TagPicker Variables
209
+
210
+ ```css
211
+ /* TagPicker Container */
212
+ --tagpicker-container-bg: var(--tagpicker-container-background);
213
+ --tagpicker-container-shadow: var(--tagpicker-container-shadow-color);
214
+ --tagpicker-container-inset-shadow: var(
215
+ --tagpicker-container-inset-shadow-color
216
+ );
217
+
218
+ /* TagPicker Subheader */
219
+ --tagpicker-subheader-bg: var(--tagpicker-subheader-background);
220
+ --tagpicker-subheader-border: var(--tagpicker-subheader-border-color);
221
+ --tagpicker-subheader-text: var(--tagpicker-subheader-text-color);
222
+ --tagpicker-subheader-label: var(--tagpicker-subheader-label-color);
223
+
224
+ /* TagPicker Tags */
225
+ --tagpicker-tag-border: var(--tagpicker-tag-border-color);
226
+ --tagpicker-tag-text: var(--tagpicker-tag-text-color);
227
+ --tagpicker-tag-hover-bg: var(--tagpicker-tag-hover-background);
228
+ --tagpicker-tag-selected-bg: var(--tagpicker-tag-selected-background);
229
+
230
+ /* TagPicker Create */
231
+ --tagpicker-create-bg: var(--tagpicker-create-background);
232
+ --tagpicker-create-hover-bg: var(--tagpicker-create-hover-background);
233
+ --tagpicker-create-selected-bg: var(--tagpicker-create-selected-background);
234
+ --tagpicker-create-border: var(--tagpicker-create-border-color);
235
+ --tagpicker-create-text: var(--tagpicker-create-text-color);
236
+ --tagpicker-create-error-text: var(--tagpicker-create-error-text-color);
237
+
238
+ /* TagPicker Empty State */
239
+ --tagpicker-empty-text: var(--tagpicker-empty-text-color);
240
+ ```
241
+
242
+ ## Key Features
243
+
244
+ ### Tag Management
245
+
246
+ - **Real-time Search**: Filter tags as you type with instant results
247
+ - **Keyboard Navigation**: Full keyboard support with arrow keys and Enter
248
+ - **Tag Creation**: Create new tags on-the-fly with custom colors
249
+ - **Tag Removal**: Click tags to remove them from selection
250
+ - **Duplicate Prevention**: Prevents adding duplicate tags
251
+
252
+ ### Overflow Modes
253
+
254
+ - **Full**: Horizontal scroll with hidden scrollbar
255
+ - **Fixed**: Tags wrap to multiple lines
256
+ - **List**: Each tag on its own row with borders
257
+
258
+ ### Styling System
259
+
260
+ - **Custom Styles**: Full CSS property control for each tag
261
+ - **Color Schemes**: Support for Radix colors and custom hex colors
262
+ - **Size Presets**: Small, medium, and large size options
263
+ - **Hover Effects**: Customizable hover states
264
+ - **Theme Support**: Light and dark mode compatibility
265
+
266
+ ### User Experience
267
+
268
+ - **Smooth Animations**: GSAP-powered transitions and animations
269
+ - **Floating Positioning**: Smart positioning using Floating UI
270
+ - **Responsive Design**: Adapts to different screen sizes
271
+ - **Accessibility**: Full keyboard navigation and screen reader support
272
+
273
+ ## Examples
274
+
275
+ ### Basic Tag Management
276
+
277
+ ```vue
278
+ <script setup lang="ts">
279
+ import { ref } from "vue";
280
+ import { TagBar } from "@umbra-ui/core";
281
+ import type { TagItem } from "@umbra-ui/core";
282
+
283
+ const allTags = ref<TagItem[]>([
284
+ { id: "1", title: "JavaScript" },
285
+ { id: "2", title: "Vue.js" },
286
+ { id: "3", title: "TypeScript" },
287
+ { id: "4", title: "Frontend" },
288
+ { id: "5", title: "Backend" },
289
+ { id: "6", title: "Full Stack" },
290
+ ]);
291
+
292
+ const selectedTags = ref<TagItem[]>([]);
293
+ const query = ref("");
294
+ const matchIndex = ref(-1);
295
+
296
+ const handleTagSelect = (tag: TagItem) => {
297
+ selectedTags.value.push(tag);
298
+ };
299
+
300
+ const handleTagRemove = (tag: TagItem) => {
301
+ const index = selectedTags.value.findIndex((t) => t.id === tag.id);
302
+ if (index > -1) {
303
+ selectedTags.value.splice(index, 1);
304
+ }
305
+ };
306
+
307
+ const handleTagCreate = (title: string) => {
308
+ const newTag: TagItem = {
309
+ id: Date.now().toString(),
310
+ title: title.trim(),
311
+ };
312
+ allTags.value.push(newTag);
313
+ selectedTags.value.push(newTag);
314
+ };
315
+ </script>
316
+
317
+ <template>
318
+ <div class="basic-tags">
319
+ <h3>Basic Tag Management</h3>
320
+
321
+ <TagBar
322
+ :all-tags="allTags"
323
+ :selected-tags="selectedTags"
324
+ v-model:query="query"
325
+ v-model:match-index="matchIndex"
326
+ placeholder="Add skills..."
327
+ overflow="fixed"
328
+ :allow-editing="true"
329
+ @tag-select="handleTagSelect"
330
+ @tag-remove="handleTagRemove"
331
+ @tag-create="handleTagCreate"
332
+ />
333
+
334
+ <div v-if="selectedTags.length > 0" class="selected-tags">
335
+ <h4>Selected Tags ({{ selectedTags.length }})</h4>
336
+ <ul>
337
+ <li v-for="tag in selectedTags" :key="tag.id">
338
+ {{ tag.title }}
339
+ </li>
340
+ </ul>
341
+ </div>
342
+ </div>
343
+ </template>
344
+
345
+ <style module>
346
+ .basic-tags {
347
+ max-width: 600px;
348
+ padding: 2rem;
349
+ border: 1px solid #e0e0e0;
350
+ border-radius: 0.5rem;
351
+ }
352
+
353
+ .selected-tags {
354
+ margin-top: 1.5rem;
355
+ padding: 1rem;
356
+ background-color: #f8f9fa;
357
+ border-radius: 0.25rem;
358
+ }
359
+
360
+ .selected-tags h4 {
361
+ margin: 0 0 0.5rem 0;
362
+ color: #333;
363
+ }
364
+
365
+ .selected-tags ul {
366
+ margin: 0;
367
+ padding-left: 1.5rem;
368
+ }
369
+
370
+ .selected-tags li {
371
+ margin-bottom: 0.25rem;
372
+ color: #666;
373
+ }
374
+ </style>
375
+ ```
376
+
377
+ ### Styled Tags with Custom Colors
378
+
379
+ ```vue
380
+ <script setup lang="ts">
381
+ import { ref } from "vue";
382
+ import { TagBar, createStyledTag } from "@umbra-ui/core";
383
+ import type { TagItem, TagStyleConfig } from "@umbra-ui/core";
384
+
385
+ const allTags = ref<TagItem[]>([
386
+ createStyledTag("1", "Frontend", { colorScheme: "blue", size: "md" }),
387
+ createStyledTag("2", "Backend", { colorScheme: "green", size: "md" }),
388
+ createStyledTag("3", "Database", { colorScheme: "orange", size: "md" }),
389
+ createStyledTag("4", "DevOps", { colorScheme: "purple", size: "md" }),
390
+ createStyledTag("5", "UI/UX", { colorScheme: "pink", size: "md" }),
391
+ createStyledTag("6", "Mobile", { colorScheme: "cyan", size: "md" }),
392
+ ]);
393
+
394
+ const selectedTags = ref<TagItem[]>([]);
395
+ const query = ref("");
396
+ const matchIndex = ref(-1);
397
+
398
+ const handleTagSelect = (tag: TagItem) => {
399
+ selectedTags.value.push(tag);
400
+ };
401
+
402
+ const handleTagRemove = (tag: TagItem) => {
403
+ const index = selectedTags.value.findIndex((t) => t.id === tag.id);
404
+ if (index > -1) {
405
+ selectedTags.value.splice(index, 1);
406
+ }
407
+ };
408
+
409
+ const handleTagCreate = (title: string) => {
410
+ const newTag = createStyledTag(Date.now().toString(), title.trim(), {
411
+ colorScheme: "gray",
412
+ size: "md",
413
+ });
414
+ allTags.value.push(newTag);
415
+ selectedTags.value.push(newTag);
416
+ };
417
+ </script>
418
+
419
+ <template>
420
+ <div class="styled-tags">
421
+ <h3>Styled Tags with Custom Colors</h3>
422
+
423
+ <TagBar
424
+ :all-tags="allTags"
425
+ :selected-tags="selectedTags"
426
+ v-model:query="query"
427
+ v-model:match-index="matchIndex"
428
+ placeholder="Add technology tags..."
429
+ overflow="full"
430
+ :allow-editing="true"
431
+ @tag-select="handleTagSelect"
432
+ @tag-remove="handleTagRemove"
433
+ @tag-create="handleTagCreate"
434
+ />
435
+
436
+ <div class="tag-info">
437
+ <p>Available tags: {{ allTags.length }}</p>
438
+ <p>Selected tags: {{ selectedTags.length }}</p>
439
+ </div>
440
+ </div>
441
+ </template>
442
+
443
+ <style module>
444
+ .styled-tags {
445
+ max-width: 600px;
446
+ padding: 2rem;
447
+ border: 1px solid #e0e0e0;
448
+ border-radius: 0.5rem;
449
+ }
450
+
451
+ .tag-info {
452
+ margin-top: 1rem;
453
+ display: flex;
454
+ gap: 2rem;
455
+ color: #666;
456
+ font-size: 0.875rem;
457
+ }
458
+ </style>
459
+ ```
460
+
461
+ ### Form Integration
462
+
463
+ ```vue
464
+ <script setup lang="ts">
465
+ import { ref, computed } from "vue";
466
+ import { TagBar } from "@umbra-ui/core";
467
+ import type { TagItem } from "@umbra-ui/core";
468
+
469
+ interface ProjectForm {
470
+ title: string;
471
+ description: string;
472
+ tags: TagItem[];
473
+ }
474
+
475
+ const form = ref<ProjectForm>({
476
+ title: "",
477
+ description: "",
478
+ tags: [],
479
+ });
480
+
481
+ const allTags = ref<TagItem[]>([
482
+ { id: "1", title: "Web Development" },
483
+ { id: "2", title: "Mobile App" },
484
+ { id: "3", title: "API" },
485
+ { id: "4", title: "Database" },
486
+ { id: "5", title: "UI/UX" },
487
+ { id: "6", title: "Testing" },
488
+ ]);
489
+
490
+ const query = ref("");
491
+ const matchIndex = ref(-1);
492
+
493
+ const isFormValid = computed(() => {
494
+ return (
495
+ form.value.title && form.value.description && form.value.tags.length > 0
496
+ );
497
+ });
498
+
499
+ const handleTagSelect = (tag: TagItem) => {
500
+ form.value.tags.push(tag);
501
+ };
502
+
503
+ const handleTagRemove = (tag: TagItem) => {
504
+ const index = form.value.tags.findIndex((t) => t.id === tag.id);
505
+ if (index > -1) {
506
+ form.value.tags.splice(index, 1);
507
+ }
508
+ };
509
+
510
+ const handleTagCreate = (title: string) => {
511
+ const newTag: TagItem = {
512
+ id: Date.now().toString(),
513
+ title: title.trim(),
514
+ };
515
+ allTags.value.push(newTag);
516
+ form.value.tags.push(newTag);
517
+ };
518
+
519
+ const handleSubmit = () => {
520
+ if (isFormValid.value) {
521
+ console.log("Project created:", form.value);
522
+ // Handle form submission
523
+ }
524
+ };
525
+ </script>
526
+
527
+ <template>
528
+ <div class="form-integration">
529
+ <h3>Create New Project</h3>
530
+
531
+ <form @submit.prevent="handleSubmit">
532
+ <div class="form-group">
533
+ <label>Project Title *</label>
534
+ <input
535
+ v-model="form.title"
536
+ type="text"
537
+ placeholder="Enter project title"
538
+ required
539
+ />
540
+ </div>
541
+
542
+ <div class="form-group">
543
+ <label>Description *</label>
544
+ <textarea
545
+ v-model="form.description"
546
+ placeholder="Enter project description"
547
+ rows="4"
548
+ required
549
+ ></textarea>
550
+ </div>
551
+
552
+ <div class="form-group">
553
+ <label>Tags *</label>
554
+ <TagBar
555
+ :all-tags="allTags"
556
+ :selected-tags="form.tags"
557
+ v-model:query="query"
558
+ v-model:match-index="matchIndex"
559
+ placeholder="Add project tags..."
560
+ overflow="fixed"
561
+ :allow-editing="true"
562
+ @tag-select="handleTagSelect"
563
+ @tag-remove="handleTagRemove"
564
+ @tag-create="handleTagCreate"
565
+ />
566
+ <p class="help-text">Add at least one tag to categorize your project</p>
567
+ </div>
568
+
569
+ <button type="submit" :disabled="!isFormValid" class="submit-button">
570
+ Create Project
571
+ </button>
572
+ </form>
573
+ </div>
574
+ </template>
575
+
576
+ <style module>
577
+ .form-integration {
578
+ max-width: 600px;
579
+ padding: 2rem;
580
+ border: 1px solid #e0e0e0;
581
+ border-radius: 0.5rem;
582
+ }
583
+
584
+ .form-group {
585
+ margin-bottom: 1.5rem;
586
+ }
587
+
588
+ .form-group label {
589
+ display: block;
590
+ margin-bottom: 0.5rem;
591
+ font-weight: 500;
592
+ color: #333;
593
+ }
594
+
595
+ .form-group input,
596
+ .form-group textarea {
597
+ width: 100%;
598
+ padding: 0.75rem;
599
+ border: 1px solid #ddd;
600
+ border-radius: 0.25rem;
601
+ font-size: 1rem;
602
+ font-family: inherit;
603
+ }
604
+
605
+ .form-group input:focus,
606
+ .form-group textarea:focus {
607
+ outline: none;
608
+ border-color: #007bff;
609
+ box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
610
+ }
611
+
612
+ .help-text {
613
+ margin-top: 0.5rem;
614
+ color: #666;
615
+ font-size: 0.875rem;
616
+ }
617
+
618
+ .submit-button {
619
+ width: 100%;
620
+ padding: 0.75rem;
621
+ background-color: #007bff;
622
+ color: white;
623
+ border: none;
624
+ border-radius: 0.25rem;
625
+ font-size: 1rem;
626
+ cursor: pointer;
627
+ transition: background-color 0.2s;
628
+ }
629
+
630
+ .submit-button:hover:not(:disabled) {
631
+ background-color: #0056b3;
632
+ }
633
+
634
+ .submit-button:disabled {
635
+ background-color: #6c757d;
636
+ cursor: not-allowed;
637
+ }
638
+ </style>
639
+ ```
640
+
641
+ ### Different Overflow Modes
642
+
643
+ ```vue
644
+ <script setup lang="ts">
645
+ import { ref } from "vue";
646
+ import { TagBar } from "@umbra-ui/core";
647
+ import type { TagItem } from "@umbra-ui/core";
648
+
649
+ const allTags = ref<TagItem[]>([
650
+ { id: "1", title: "JavaScript" },
651
+ { id: "2", title: "TypeScript" },
652
+ { id: "3", title: "Vue.js" },
653
+ { id: "4", title: "React" },
654
+ { id: "5", title: "Angular" },
655
+ { id: "6", title: "Node.js" },
656
+ { id: "7", title: "Python" },
657
+ { id: "8", title: "Java" },
658
+ { id: "9", title: "C#" },
659
+ { id: "10", title: "Go" },
660
+ ]);
661
+
662
+ const selectedTags = ref<TagItem[]>([
663
+ { id: "1", title: "JavaScript" },
664
+ { id: "2", title: "TypeScript" },
665
+ { id: "3", title: "Vue.js" },
666
+ { id: "4", title: "React" },
667
+ { id: "5", title: "Node.js" },
668
+ ]);
669
+
670
+ const query = ref("");
671
+ const matchIndex = ref(-1);
672
+
673
+ const handleTagSelect = (tag: TagItem) => {
674
+ selectedTags.value.push(tag);
675
+ };
676
+
677
+ const handleTagRemove = (tag: TagItem) => {
678
+ const index = selectedTags.value.findIndex((t) => t.id === tag.id);
679
+ if (index > -1) {
680
+ selectedTags.value.splice(index, 1);
681
+ }
682
+ };
683
+
684
+ const handleTagCreate = (title: string) => {
685
+ const newTag: TagItem = {
686
+ id: Date.now().toString(),
687
+ title: title.trim(),
688
+ };
689
+ allTags.value.push(newTag);
690
+ selectedTags.value.push(newTag);
691
+ };
692
+ </script>
693
+
694
+ <template>
695
+ <div class="overflow-modes">
696
+ <h3>Different Overflow Modes</h3>
697
+
698
+ <div class="mode-section">
699
+ <h4>Full Mode (Horizontal Scroll)</h4>
700
+ <TagBar
701
+ :all-tags="allTags"
702
+ :selected-tags="selectedTags"
703
+ v-model:query="query"
704
+ v-model:match-index="matchIndex"
705
+ placeholder="Add tags..."
706
+ overflow="full"
707
+ :allow-editing="true"
708
+ @tag-select="handleTagSelect"
709
+ @tag-remove="handleTagRemove"
710
+ @tag-create="handleTagCreate"
711
+ />
712
+ </div>
713
+
714
+ <div class="mode-section">
715
+ <h4>Fixed Mode (Wrap Tags)</h4>
716
+ <TagBar
717
+ :all-tags="allTags"
718
+ :selected-tags="selectedTags"
719
+ v-model:query="query"
720
+ v-model:match-index="matchIndex"
721
+ placeholder="Add tags..."
722
+ overflow="fixed"
723
+ :allow-editing="true"
724
+ @tag-select="handleTagSelect"
725
+ @tag-remove="handleTagRemove"
726
+ @tag-create="handleTagCreate"
727
+ />
728
+ </div>
729
+
730
+ <div class="mode-section">
731
+ <h4>List Mode (Vertical List)</h4>
732
+ <TagBar
733
+ :all-tags="allTags"
734
+ :selected-tags="selectedTags"
735
+ v-model:query="query"
736
+ v-model:match-index="matchIndex"
737
+ placeholder="Add tags..."
738
+ overflow="list"
739
+ :allow-editing="true"
740
+ @tag-select="handleTagSelect"
741
+ @tag-remove="handleTagRemove"
742
+ @tag-create="handleTagCreate"
743
+ />
744
+ </div>
745
+ </div>
746
+ </template>
747
+
748
+ <style module>
749
+ .overflow-modes {
750
+ max-width: 800px;
751
+ padding: 2rem;
752
+ border: 1px solid #e0e0e0;
753
+ border-radius: 0.5rem;
754
+ }
755
+
756
+ .mode-section {
757
+ margin-bottom: 2rem;
758
+ padding: 1rem;
759
+ border: 1px solid #f0f0f0;
760
+ border-radius: 0.25rem;
761
+ }
762
+
763
+ .mode-section h4 {
764
+ margin: 0 0 1rem 0;
765
+ color: #333;
766
+ }
767
+ </style>
768
+ ```
769
+
770
+ ### Custom Styling
771
+
772
+ ```vue
773
+ <script setup lang="ts">
774
+ import { ref } from "vue";
775
+ import { TagBar, createStyledTag } from "@umbra-ui/core";
776
+ import type { TagItem, TagStyleConfig } from "@umbra-ui/core";
777
+
778
+ const customStyle: TagStyleConfig = {
779
+ backgroundColor: "#e3f2fd",
780
+ color: "#1976d2",
781
+ border: "2px solid #2196f3",
782
+ borderRadius: "20px",
783
+ padding: "0.5rem 1rem",
784
+ fontSize: "0.875rem",
785
+ fontWeight: "600",
786
+ hover: {
787
+ backgroundColor: "#bbdefb",
788
+ transform: "scale(1.05)",
789
+ },
790
+ };
791
+
792
+ const allTags = ref<TagItem[]>([
793
+ createStyledTag("1", "Custom Style", customStyle),
794
+ createStyledTag("2", "Another Tag", customStyle),
795
+ createStyledTag("3", "Styled Tag", customStyle),
796
+ ]);
797
+
798
+ const selectedTags = ref<TagItem[]>([]);
799
+ const query = ref("");
800
+ const matchIndex = ref(-1);
801
+
802
+ const handleTagSelect = (tag: TagItem) => {
803
+ selectedTags.value.push(tag);
804
+ };
805
+
806
+ const handleTagRemove = (tag: TagItem) => {
807
+ const index = selectedTags.value.findIndex((t) => t.id === tag.id);
808
+ if (index > -1) {
809
+ selectedTags.value.splice(index, 1);
810
+ }
811
+ };
812
+
813
+ const handleTagCreate = (title: string) => {
814
+ const newTag = createStyledTag(
815
+ Date.now().toString(),
816
+ title.trim(),
817
+ customStyle
818
+ );
819
+ allTags.value.push(newTag);
820
+ selectedTags.value.push(newTag);
821
+ };
822
+ </script>
823
+
824
+ <template>
825
+ <div class="custom-styling">
826
+ <h3>Custom Styled Tags</h3>
827
+
828
+ <TagBar
829
+ :all-tags="allTags"
830
+ :selected-tags="selectedTags"
831
+ v-model:query="query"
832
+ v-model:match-index="matchIndex"
833
+ placeholder="Add custom tags..."
834
+ overflow="fixed"
835
+ :allow-editing="true"
836
+ @tag-select="handleTagSelect"
837
+ @tag-remove="handleTagRemove"
838
+ @tag-create="handleTagCreate"
839
+ />
840
+
841
+ <div class="style-info">
842
+ <h4>Custom Style Properties:</h4>
843
+ <ul>
844
+ <li>Background: Light blue with transparency</li>
845
+ <li>Border: 2px solid blue</li>
846
+ <li>Border radius: 20px (pill shape)</li>
847
+ <li>Hover: Scale effect and darker background</li>
848
+ </ul>
849
+ </div>
850
+ </div>
851
+ </template>
852
+
853
+ <style module>
854
+ .custom-styling {
855
+ max-width: 600px;
856
+ padding: 2rem;
857
+ border: 1px solid #e0e0e0;
858
+ border-radius: 0.5rem;
859
+ }
860
+
861
+ .style-info {
862
+ margin-top: 1.5rem;
863
+ padding: 1rem;
864
+ background-color: #f8f9fa;
865
+ border-radius: 0.25rem;
866
+ }
867
+
868
+ .style-info h4 {
869
+ margin: 0 0 0.5rem 0;
870
+ color: #333;
871
+ }
872
+
873
+ .style-info ul {
874
+ margin: 0;
875
+ padding-left: 1.5rem;
876
+ }
877
+
878
+ .style-info li {
879
+ margin-bottom: 0.25rem;
880
+ color: #666;
881
+ }
882
+ </style>
883
+ ```
884
+
885
+ ## Technical Notes
886
+
887
+ - Tags components provide a comprehensive tag management system with advanced features
888
+ - Real-time search filters tags as you type with instant results
889
+ - Keyboard navigation includes arrow keys, Enter, and Escape for full control
890
+ - Multiple overflow modes handle different layout requirements
891
+ - Custom styling system supports both Radix colors and custom CSS properties
892
+ - Floating UI provides smart positioning for the tag picker
893
+ - GSAP animations create smooth transitions and visual feedback
894
+ - ResizeObserver tracks container changes for responsive behavior
895
+ - TypeScript interfaces ensure type safety for all tag operations
896
+ - Accessibility features include keyboard navigation and screen reader support
897
+ - Color picker integration allows custom tag colors during creation