@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,919 @@
1
+ # TabController
2
+
3
+ A flexible and feature-rich tab navigation component built with Vue 3 Composition API and TypeScript. The TabController provides an intuitive tabbed interface with support for icons, badges, keyboard navigation, and customizable layouts, perfect for organizing content into distinct sections.
4
+
5
+ ## Installation/Import
6
+
7
+ ```typescript
8
+ import { TabController, TabItem, useTabController } from "@umbra-ui/core";
9
+ import type { Tab, TabPosition, TabControllerContext } from "@umbra-ui/core";
10
+ ```
11
+
12
+ **Dependencies:**
13
+
14
+ - Vue 3.x
15
+ - @umbra-ui/icons (for icon support)
16
+
17
+ ## Basic Usage
18
+
19
+ ```vue
20
+ <script setup lang="ts">
21
+ import { ref } from "vue";
22
+ import { TabController, TabItem } from "@umbra-ui/core";
23
+ import HomeView from "./HomeView.vue";
24
+ import ProfileView from "./ProfileView.vue";
25
+ import SettingsView from "./SettingsView.vue";
26
+
27
+ const activeTab = ref("home");
28
+
29
+ const handleTabChange = (tabId: string) => {
30
+ console.log("Tab changed to:", tabId);
31
+ };
32
+ </script>
33
+
34
+ <template>
35
+ <div class="app">
36
+ <TabController
37
+ v-model="activeTab"
38
+ position="top"
39
+ layout="row"
40
+ @change="handleTabChange"
41
+ >
42
+ <TabItem id="home" label="Home" icon="home">
43
+ <HomeView />
44
+ </TabItem>
45
+
46
+ <TabItem id="profile" label="Profile" icon="user">
47
+ <ProfileView />
48
+ </TabItem>
49
+
50
+ <TabItem id="settings" label="Settings" icon="settings">
51
+ <SettingsView />
52
+ </TabItem>
53
+ </TabController>
54
+ </div>
55
+ </template>
56
+
57
+ <style module>
58
+ .app {
59
+ height: 100vh;
60
+ display: flex;
61
+ flex-direction: column;
62
+ }
63
+ </style>
64
+ ```
65
+
66
+ ## Components
67
+
68
+ ### TabController
69
+
70
+ The main container component that manages tab state and provides the tab bar interface.
71
+
72
+ #### Props
73
+
74
+ | Prop Name | Type | Required | Default | Description |
75
+ | -------------------- | ------------------- | -------- | ----------- | ------------------------------------------ |
76
+ | `modelValue` | `string` | No | `""` | The ID of the currently active tab |
77
+ | `position` | `TabPosition` | No | `"bottom"` | Position of the tab bar: "top" or "bottom" |
78
+ | `layout` | `"row" \| "column"` | No | `"column"` | Layout direction for tab items |
79
+ | `barColor` | `string` | No | `"#111111"` | Background color for the tab bar |
80
+ | `tabItemActiveColor` | `string` | No | `"#0090ff"` | Active tab item color |
81
+
82
+ #### Events
83
+
84
+ | Event Name | Payload Type | Description |
85
+ | ------------------- | ------------ | ----------------------------------- |
86
+ | `update:modelValue` | `string` | Emitted when the active tab changes |
87
+ | `change` | `string` | Emitted when a tab is selected |
88
+
89
+ #### Slots
90
+
91
+ | Slot Name | Description |
92
+ | --------- | ------------------ |
93
+ | `default` | TabItem components |
94
+
95
+ ### TabItem
96
+
97
+ Individual tab component that represents a single tab and its content.
98
+
99
+ #### Props
100
+
101
+ | Prop Name | Type | Required | Default | Description |
102
+ | ---------- | ------------------ | -------- | ------- | ------------------------------- |
103
+ | `id` | `string` | Yes | - | Unique identifier for the tab |
104
+ | `label` | `string` | Yes | - | Display text for the tab |
105
+ | `icon` | `string` | No | - | Icon name from @umbra-ui/icons |
106
+ | `badge` | `string \| number` | No | - | Badge text or number to display |
107
+ | `disabled` | `boolean` | No | `false` | Whether the tab is disabled |
108
+
109
+ #### Slots
110
+
111
+ | Slot Name | Description |
112
+ | --------- | ----------------------------------------- |
113
+ | `default` | Content to display when the tab is active |
114
+
115
+ ## Types
116
+
117
+ ### Tab Interface
118
+
119
+ ```typescript
120
+ interface Tab {
121
+ id: string;
122
+ label: string;
123
+ icon?: string;
124
+ badge?: string | number;
125
+ disabled?: boolean;
126
+ }
127
+ ```
128
+
129
+ ### TabPosition Type
130
+
131
+ ```typescript
132
+ type TabPosition = "top" | "bottom";
133
+ ```
134
+
135
+ ### TabControllerContext Interface
136
+
137
+ ```typescript
138
+ interface TabControllerContext {
139
+ tabs: Ref<Tab[]>;
140
+ activeTab: Ref<string>;
141
+ registerTab: (tab: Tab) => void;
142
+ unregisterTab: (id: string) => void;
143
+ setActiveTab: (id: string) => void;
144
+ goToTab: (index: number) => void;
145
+ nextTab: () => void;
146
+ previousTab: () => void;
147
+ animated: boolean;
148
+ }
149
+ ```
150
+
151
+ ## useTabController Composable
152
+
153
+ The `useTabController` composable provides access to the tab controller context and can be used within TabItem components or child components.
154
+
155
+ ```typescript
156
+ import { useTabController } from "@umbra-ui/core";
157
+
158
+ const {
159
+ tabs,
160
+ activeTab,
161
+ registerTab,
162
+ unregisterTab,
163
+ setActiveTab,
164
+ goToTab,
165
+ nextTab,
166
+ previousTab,
167
+ animated,
168
+ } = useTabController();
169
+ ```
170
+
171
+ ### Composable Returns
172
+
173
+ | Property | Type | Description |
174
+ | --------------- | ------------------------- | ------------------------------------- |
175
+ | `tabs` | `Ref<Tab[]>` | Reactive array of all registered tabs |
176
+ | `activeTab` | `Ref<string>` | ID of the currently active tab |
177
+ | `registerTab` | `(tab: Tab) => void` | Register a new tab |
178
+ | `unregisterTab` | `(id: string) => void` | Unregister a tab |
179
+ | `setActiveTab` | `(id: string) => void` | Set the active tab |
180
+ | `goToTab` | `(index: number) => void` | Navigate to tab by index |
181
+ | `nextTab` | `() => void` | Navigate to the next tab |
182
+ | `previousTab` | `() => void` | Navigate to the previous tab |
183
+ | `animated` | `boolean` | Whether animations are enabled |
184
+
185
+ ## CSS Customization
186
+
187
+ ### Layout Variables
188
+
189
+ ```css
190
+ .tab-controller {
191
+ --tabcontroller-container-bg: #ffffff;
192
+ --tabcontroller-bar-bg: #f8f9fa;
193
+ --tabcontroller-bar-border: #e9ecef;
194
+ --tabcontroller-tab-text: #495057;
195
+ --tabcontroller-tab-active-text: #007bff;
196
+ --tabcontroller-tab-hover-bg: #e9ecef;
197
+ --tabcontroller-tab-disabled-opacity: 0.5;
198
+ --tabcontroller-badge-bg: #dc3545;
199
+ --tabcontroller-badge-text: #ffffff;
200
+ }
201
+ ```
202
+
203
+ ### Container Styling
204
+
205
+ ```css
206
+ .tab-controller {
207
+ display: flex;
208
+ flex-direction: column;
209
+ height: 100%;
210
+ background: var(--tabcontroller-container-bg);
211
+ overflow: hidden;
212
+ }
213
+ ```
214
+
215
+ ### Tab Bar Styling
216
+
217
+ ```css
218
+ .tab-controller .tabBar {
219
+ display: flex;
220
+ background: var(--tabcontroller-bar-bg);
221
+ border-top: 1px solid var(--tabcontroller-bar-border);
222
+ padding: 0.353rem;
223
+ }
224
+
225
+ .tab-controller .tabBar--column {
226
+ gap: 0.353rem;
227
+ }
228
+
229
+ .tab-controller .tabBar--row {
230
+ gap: 0.5rem;
231
+ }
232
+ ```
233
+
234
+ ### Tab Item Styling
235
+
236
+ ```css
237
+ .tab-controller .tabItem {
238
+ flex: 1;
239
+ display: flex;
240
+ align-items: center;
241
+ justify-content: center;
242
+ padding: 8px 4px;
243
+ background: none;
244
+ border: none;
245
+ cursor: pointer;
246
+ transition: all 0.2s ease;
247
+ color: var(--tabcontroller-tab-text);
248
+ border-radius: 0.353rem;
249
+ font-size: 12px;
250
+ }
251
+
252
+ .tab-controller .tabItem--active {
253
+ color: var(--tabcontroller-tab-active-text);
254
+ }
255
+
256
+ .tab-controller .tabItem--disabled {
257
+ opacity: var(--tabcontroller-tab-disabled-opacity);
258
+ cursor: not-allowed;
259
+ }
260
+ ```
261
+
262
+ ## Examples
263
+
264
+ ### Mobile App Navigation
265
+
266
+ ```vue
267
+ <script setup lang="ts">
268
+ import { ref } from "vue";
269
+ import { TabController, TabItem } from "@umbra-ui/core";
270
+ import HomeScreen from "./HomeScreen.vue";
271
+ import SearchScreen from "./SearchScreen.vue";
272
+ import ProfileScreen from "./ProfileScreen.vue";
273
+ import NotificationsScreen from "./NotificationsScreen.vue";
274
+
275
+ const activeTab = ref("home");
276
+
277
+ const handleTabChange = (tabId: string) => {
278
+ console.log("Navigated to:", tabId);
279
+ };
280
+ </script>
281
+
282
+ <template>
283
+ <div class="mobile-app">
284
+ <TabController
285
+ v-model="activeTab"
286
+ position="bottom"
287
+ layout="column"
288
+ @change="handleTabChange"
289
+ >
290
+ <TabItem id="home" label="Home" icon="home">
291
+ <HomeScreen />
292
+ </TabItem>
293
+
294
+ <TabItem id="search" label="Search" icon="search">
295
+ <SearchScreen />
296
+ </TabItem>
297
+
298
+ <TabItem id="notifications" label="Notifications" icon="bell" :badge="5">
299
+ <NotificationsScreen />
300
+ </TabItem>
301
+
302
+ <TabItem id="profile" label="Profile" icon="user">
303
+ <ProfileScreen />
304
+ </TabItem>
305
+ </TabController>
306
+ </div>
307
+ </template>
308
+
309
+ <style module>
310
+ .mobile-app {
311
+ height: 100vh;
312
+ display: flex;
313
+ flex-direction: column;
314
+ background: #f8f9fa;
315
+ }
316
+ </style>
317
+ ```
318
+
319
+ ### Desktop Application Tabs
320
+
321
+ ```vue
322
+ <script setup lang="ts">
323
+ import { ref } from "vue";
324
+ import { TabController, TabItem } from "@umbra-ui/core";
325
+ import DashboardView from "./DashboardView.vue";
326
+ import AnalyticsView from "./AnalyticsView.vue";
327
+ import ReportsView from "./ReportsView.vue";
328
+ import SettingsView from "./SettingsView.vue";
329
+
330
+ const activeTab = ref("dashboard");
331
+
332
+ const handleTabChange = (tabId: string) => {
333
+ console.log("Tab changed to:", tabId);
334
+ };
335
+ </script>
336
+
337
+ <template>
338
+ <div class="desktop-app">
339
+ <header class="app-header">
340
+ <h1 class="app-title">My Application</h1>
341
+ </header>
342
+
343
+ <TabController
344
+ v-model="activeTab"
345
+ position="top"
346
+ layout="row"
347
+ @change="handleTabChange"
348
+ >
349
+ <TabItem id="dashboard" label="Dashboard" icon="dashboard">
350
+ <DashboardView />
351
+ </TabItem>
352
+
353
+ <TabItem id="analytics" label="Analytics" icon="chart">
354
+ <AnalyticsView />
355
+ </TabItem>
356
+
357
+ <TabItem id="reports" label="Reports" icon="file">
358
+ <ReportsView />
359
+ </TabItem>
360
+
361
+ <TabItem id="settings" label="Settings" icon="settings">
362
+ <SettingsView />
363
+ </TabItem>
364
+ </TabController>
365
+ </div>
366
+ </template>
367
+
368
+ <style module>
369
+ .desktop-app {
370
+ height: 100vh;
371
+ display: flex;
372
+ flex-direction: column;
373
+ background: #ffffff;
374
+ }
375
+
376
+ .app-header {
377
+ padding: 16px 24px;
378
+ background: #f8f9fa;
379
+ border-bottom: 1px solid #e9ecef;
380
+ }
381
+
382
+ .app-title {
383
+ font-size: 24px;
384
+ font-weight: 600;
385
+ color: #212529;
386
+ margin: 0;
387
+ }
388
+ </style>
389
+ ```
390
+
391
+ ### Settings Panel with Disabled Tabs
392
+
393
+ ```vue
394
+ <script setup lang="ts">
395
+ import { ref } from "vue";
396
+ import { TabController, TabItem } from "@umbra-ui/core";
397
+ import GeneralSettings from "./GeneralSettings.vue";
398
+ import AppearanceSettings from "./AppearanceSettings.vue";
399
+ import PrivacySettings from "./PrivacySettings.vue";
400
+ import AdvancedSettings from "./AdvancedSettings.vue";
401
+
402
+ const activeTab = ref("general");
403
+ const isProUser = ref(false);
404
+
405
+ const handleTabChange = (tabId: string) => {
406
+ console.log("Settings tab changed to:", tabId);
407
+ };
408
+ </script>
409
+
410
+ <template>
411
+ <div class="settings-panel">
412
+ <div class="settings-header">
413
+ <h2 class="settings-title">Settings</h2>
414
+ <p class="settings-subtitle">Configure your application preferences</p>
415
+ </div>
416
+
417
+ <TabController
418
+ v-model="activeTab"
419
+ position="top"
420
+ layout="row"
421
+ @change="handleTabChange"
422
+ >
423
+ <TabItem id="general" label="General" icon="settings">
424
+ <GeneralSettings />
425
+ </TabItem>
426
+
427
+ <TabItem id="appearance" label="Appearance" icon="palette">
428
+ <AppearanceSettings />
429
+ </TabItem>
430
+
431
+ <TabItem
432
+ id="privacy"
433
+ label="Privacy"
434
+ icon="shield"
435
+ :disabled="!isProUser"
436
+ :badge="!isProUser ? 'Pro' : undefined"
437
+ >
438
+ <PrivacySettings />
439
+ </TabItem>
440
+
441
+ <TabItem
442
+ id="advanced"
443
+ label="Advanced"
444
+ icon="gear"
445
+ :disabled="!isProUser"
446
+ :badge="!isProUser ? 'Pro' : undefined"
447
+ >
448
+ <AdvancedSettings />
449
+ </TabItem>
450
+ </TabController>
451
+
452
+ <div class="settings-footer">
453
+ <button v-if="!isProUser" @click="isProUser = true" class="upgrade-btn">
454
+ Upgrade to Pro
455
+ </button>
456
+ </div>
457
+ </div>
458
+ </template>
459
+
460
+ <style module>
461
+ .settings-panel {
462
+ height: 100vh;
463
+ display: flex;
464
+ flex-direction: column;
465
+ background: #f8f9fa;
466
+ }
467
+
468
+ .settings-header {
469
+ padding: 24px;
470
+ background: white;
471
+ border-bottom: 1px solid #e9ecef;
472
+ }
473
+
474
+ .settings-title {
475
+ font-size: 28px;
476
+ font-weight: 700;
477
+ color: #1a202c;
478
+ margin: 0 0 8px 0;
479
+ }
480
+
481
+ .settings-subtitle {
482
+ font-size: 16px;
483
+ color: #718096;
484
+ margin: 0;
485
+ }
486
+
487
+ .settings-footer {
488
+ padding: 16px 24px;
489
+ background: white;
490
+ border-top: 1px solid #e9ecef;
491
+ }
492
+
493
+ .upgrade-btn {
494
+ padding: 12px 24px;
495
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
496
+ color: white;
497
+ border: none;
498
+ border-radius: 8px;
499
+ font-weight: 600;
500
+ cursor: pointer;
501
+ transition: all 0.2s ease;
502
+ }
503
+
504
+ .upgrade-btn:hover {
505
+ transform: translateY(-1px);
506
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
507
+ }
508
+ </style>
509
+ ```
510
+
511
+ ### Dynamic Tab Management
512
+
513
+ ```vue
514
+ <script setup lang="ts">
515
+ import { ref } from "vue";
516
+ import { TabController, TabItem, useTabController } from "@umbra-ui/core";
517
+ import DynamicView from "./DynamicView.vue";
518
+
519
+ const activeTab = ref("tab1");
520
+ const tabCounter = ref(2);
521
+
522
+ const tabs = ref([
523
+ { id: "tab1", label: "Tab 1", icon: "home" },
524
+ { id: "tab2", label: "Tab 2", icon: "user" },
525
+ ]);
526
+
527
+ const addTab = () => {
528
+ const newTab = {
529
+ id: `tab${tabCounter.value}`,
530
+ label: `Tab ${tabCounter.value}`,
531
+ icon: "plus",
532
+ };
533
+ tabs.value.push(newTab);
534
+ activeTab.value = newTab.id;
535
+ tabCounter.value++;
536
+ };
537
+
538
+ const removeTab = (tabId: string) => {
539
+ if (tabs.value.length > 1) {
540
+ const index = tabs.value.findIndex((tab) => tab.id === tabId);
541
+ if (index > -1) {
542
+ tabs.value.splice(index, 1);
543
+ if (activeTab.value === tabId) {
544
+ activeTab.value = tabs.value[Math.max(0, index - 1)].id;
545
+ }
546
+ }
547
+ }
548
+ };
549
+
550
+ const handleTabChange = (tabId: string) => {
551
+ console.log("Tab changed to:", tabId);
552
+ };
553
+ </script>
554
+
555
+ <template>
556
+ <div class="dynamic-tabs">
557
+ <div class="tab-controls">
558
+ <button @click="addTab" class="control-btn add">Add Tab</button>
559
+ <button
560
+ v-for="tab in tabs"
561
+ :key="tab.id"
562
+ @click="removeTab(tab.id)"
563
+ :disabled="tabs.length <= 1"
564
+ class="control-btn remove"
565
+ >
566
+ Remove {{ tab.label }}
567
+ </button>
568
+ </div>
569
+
570
+ <TabController
571
+ v-model="activeTab"
572
+ position="top"
573
+ layout="row"
574
+ @change="handleTabChange"
575
+ >
576
+ <TabItem
577
+ v-for="tab in tabs"
578
+ :key="tab.id"
579
+ :id="tab.id"
580
+ :label="tab.label"
581
+ :icon="tab.icon"
582
+ >
583
+ <DynamicView :tab-id="tab.id" />
584
+ </TabItem>
585
+ </TabController>
586
+ </div>
587
+ </template>
588
+
589
+ <style module>
590
+ .dynamic-tabs {
591
+ height: 100vh;
592
+ display: flex;
593
+ flex-direction: column;
594
+ background: #f8f9fa;
595
+ }
596
+
597
+ .tab-controls {
598
+ display: flex;
599
+ gap: 8px;
600
+ padding: 16px;
601
+ background: white;
602
+ border-bottom: 1px solid #e9ecef;
603
+ flex-wrap: wrap;
604
+ }
605
+
606
+ .control-btn {
607
+ padding: 8px 16px;
608
+ border: 1px solid #dee2e6;
609
+ border-radius: 6px;
610
+ cursor: pointer;
611
+ font-size: 14px;
612
+ transition: all 0.2s ease;
613
+ }
614
+
615
+ .control-btn.add {
616
+ background: #28a745;
617
+ color: white;
618
+ border-color: #28a745;
619
+ }
620
+
621
+ .control-btn.add:hover {
622
+ background: #218838;
623
+ border-color: #1e7e34;
624
+ }
625
+
626
+ .control-btn.remove {
627
+ background: #dc3545;
628
+ color: white;
629
+ border-color: #dc3545;
630
+ }
631
+
632
+ .control-btn.remove:hover:not(:disabled) {
633
+ background: #c82333;
634
+ border-color: #bd2130;
635
+ }
636
+
637
+ .control-btn:disabled {
638
+ opacity: 0.5;
639
+ cursor: not-allowed;
640
+ }
641
+ </style>
642
+ ```
643
+
644
+ ### Custom Tab Content with Navigation
645
+
646
+ ```vue
647
+ <script setup lang="ts">
648
+ import { ref } from "vue";
649
+ import { TabController, TabItem, useTabController } from "@umbra-ui/core";
650
+ import CustomView from "./CustomView.vue";
651
+
652
+ const activeTab = ref("view1");
653
+
654
+ const handleTabChange = (tabId: string) => {
655
+ console.log("Tab changed to:", tabId);
656
+ };
657
+ </script>
658
+
659
+ <template>
660
+ <div class="custom-tabs">
661
+ <TabController
662
+ v-model="activeTab"
663
+ position="top"
664
+ layout="row"
665
+ @change="handleTabChange"
666
+ >
667
+ <TabItem id="view1" label="View 1" icon="eye">
668
+ <CustomView
669
+ title="First View"
670
+ :can-navigate="true"
671
+ @navigate="activeTab = 'view2'"
672
+ />
673
+ </TabItem>
674
+
675
+ <TabItem id="view2" label="View 2" icon="eye">
676
+ <CustomView
677
+ title="Second View"
678
+ :can-navigate="true"
679
+ @navigate="activeTab = 'view3'"
680
+ />
681
+ </TabItem>
682
+
683
+ <TabItem id="view3" label="View 3" icon="eye">
684
+ <CustomView title="Third View" :can-navigate="false" />
685
+ </TabItem>
686
+ </TabController>
687
+ </div>
688
+ </template>
689
+
690
+ <style module>
691
+ .custom-tabs {
692
+ height: 100vh;
693
+ display: flex;
694
+ flex-direction: column;
695
+ background: #ffffff;
696
+ }
697
+ </style>
698
+ ```
699
+
700
+ ## Advanced Usage
701
+
702
+ ### Programmatic Tab Control
703
+
704
+ ```vue
705
+ <script setup lang="ts">
706
+ import { ref } from "vue";
707
+ import { TabController, TabItem, useTabController } from "@umbra-ui/core";
708
+
709
+ const activeTab = ref("tab1");
710
+ const tabControllerRef = ref();
711
+
712
+ // Access tab controller methods
713
+ const nextTab = () => {
714
+ // This would need to be implemented in the TabController component
715
+ console.log("Navigate to next tab");
716
+ };
717
+
718
+ const previousTab = () => {
719
+ console.log("Navigate to previous tab");
720
+ };
721
+
722
+ const goToTab = (index: number) => {
723
+ console.log("Go to tab index:", index);
724
+ };
725
+ </script>
726
+
727
+ <template>
728
+ <div class="programmatic-tabs">
729
+ <div class="tab-navigation">
730
+ <button @click="nextTab" class="nav-btn">Next Tab</button>
731
+ <button @click="previousTab" class="nav-btn">Previous Tab</button>
732
+ <button @click="goToTab(0)" class="nav-btn">Go to Tab 1</button>
733
+ <button @click="goToTab(1)" class="nav-btn">Go to Tab 2</button>
734
+ </div>
735
+
736
+ <TabController
737
+ ref="tabControllerRef"
738
+ v-model="activeTab"
739
+ position="top"
740
+ layout="row"
741
+ >
742
+ <TabItem id="tab1" label="Tab 1" icon="home">
743
+ <div class="tab-content">Content for Tab 1</div>
744
+ </TabItem>
745
+
746
+ <TabItem id="tab2" label="Tab 2" icon="user">
747
+ <div class="tab-content">Content for Tab 2</div>
748
+ </TabItem>
749
+ </TabController>
750
+ </div>
751
+ </template>
752
+
753
+ <style module>
754
+ .programmatic-tabs {
755
+ height: 100vh;
756
+ display: flex;
757
+ flex-direction: column;
758
+ }
759
+
760
+ .tab-navigation {
761
+ display: flex;
762
+ gap: 8px;
763
+ padding: 16px;
764
+ background: #f8f9fa;
765
+ border-bottom: 1px solid #e9ecef;
766
+ }
767
+
768
+ .nav-btn {
769
+ padding: 8px 16px;
770
+ background: #007bff;
771
+ color: white;
772
+ border: none;
773
+ border-radius: 6px;
774
+ cursor: pointer;
775
+ font-size: 14px;
776
+ transition: all 0.2s ease;
777
+ }
778
+
779
+ .nav-btn:hover {
780
+ background: #0056b3;
781
+ }
782
+
783
+ .tab-content {
784
+ padding: 24px;
785
+ font-size: 16px;
786
+ color: #495057;
787
+ }
788
+ </style>
789
+ ```
790
+
791
+ ### Integration with Router
792
+
793
+ ```vue
794
+ <script setup lang="ts">
795
+ import { ref, watch } from "vue";
796
+ import { useRoute, useRouter } from "vue-router";
797
+ import { TabController, TabItem } from "@umbra-ui/core";
798
+
799
+ const route = useRoute();
800
+ const router = useRouter();
801
+ const activeTab = ref("home");
802
+
803
+ const tabs = [
804
+ { id: "home", label: "Home", icon: "home", route: "/" },
805
+ { id: "about", label: "About", icon: "info", route: "/about" },
806
+ { id: "contact", label: "Contact", icon: "mail", route: "/contact" },
807
+ ];
808
+
809
+ // Sync with router
810
+ watch(
811
+ () => route.path,
812
+ (newPath) => {
813
+ const tab = tabs.find((t) => t.route === newPath);
814
+ if (tab) {
815
+ activeTab.value = tab.id;
816
+ }
817
+ },
818
+ { immediate: true }
819
+ );
820
+
821
+ const handleTabChange = (tabId: string) => {
822
+ const tab = tabs.find((t) => t.id === tabId);
823
+ if (tab) {
824
+ router.push(tab.route);
825
+ }
826
+ };
827
+ </script>
828
+
829
+ <template>
830
+ <div class="routed-tabs">
831
+ <TabController
832
+ v-model="activeTab"
833
+ position="top"
834
+ layout="row"
835
+ @change="handleTabChange"
836
+ >
837
+ <TabItem
838
+ v-for="tab in tabs"
839
+ :key="tab.id"
840
+ :id="tab.id"
841
+ :label="tab.label"
842
+ :icon="tab.icon"
843
+ >
844
+ <router-view />
845
+ </TabItem>
846
+ </TabController>
847
+ </div>
848
+ </template>
849
+
850
+ <style module>
851
+ .routed-tabs {
852
+ height: 100vh;
853
+ display: flex;
854
+ flex-direction: column;
855
+ }
856
+ </style>
857
+ ```
858
+
859
+ ## Performance Considerations
860
+
861
+ - **Component Registration**: Tabs are automatically registered and unregistered when mounted/unmounted
862
+ - **Reactive Updates**: Tab properties are watched and updated reactively
863
+ - **Memory Management**: Proper cleanup when tabs are removed
864
+ - **Icon Loading**: Icons are loaded on-demand from the @umbra-ui/icons package
865
+
866
+ ## Accessibility
867
+
868
+ - **Keyboard Navigation**: Support for arrow keys and tab navigation
869
+ - **Screen Reader Support**: Proper ARIA labels and roles
870
+ - **Focus Management**: Focus is maintained during tab changes
871
+ - **Disabled State**: Proper handling of disabled tabs
872
+
873
+ ## Browser Support
874
+
875
+ - **Modern Browsers**: Chrome 88+, Firefox 85+, Safari 14+, Edge 88+
876
+ - **Mobile Browsers**: iOS Safari 14+, Chrome Mobile 88+
877
+ - **CSS Features**: Uses CSS Grid and modern layout features
878
+ - **JavaScript**: Requires ES2020+ support
879
+
880
+ ## Troubleshooting
881
+
882
+ ### Common Issues
883
+
884
+ 1. **Tabs not displaying**: Ensure TabItem components are properly nested within TabController
885
+ 2. **Icons not showing**: Verify icon names match those available in @umbra-ui/icons
886
+ 3. **Active tab not updating**: Check that the modelValue prop is properly bound
887
+ 4. **Content not showing**: Ensure TabItem components have content in their default slot
888
+
889
+ ### Debug Mode
890
+
891
+ ```vue
892
+ <script setup lang="ts">
893
+ import { ref, watch } from "vue";
894
+ import { TabController, TabItem, useTabController } from "@umbra-ui/core";
895
+
896
+ const activeTab = ref("tab1");
897
+
898
+ // Watch for tab changes
899
+ watch(activeTab, (newTab) => {
900
+ console.log("Active tab changed to:", newTab);
901
+ });
902
+ </script>
903
+ ```
904
+
905
+ ## Migration Guide
906
+
907
+ ### From v1 to v2
908
+
909
+ - `v-model` prop is now `modelValue`
910
+ - `position` prop now supports "top" and "bottom" values
911
+ - `layout` prop now supports "row" and "column" values
912
+ - Icon system has been updated to use @umbra-ui/icons
913
+
914
+ ### Breaking Changes
915
+
916
+ - Removed `activeTab` prop in favor of `modelValue`
917
+ - Changed event names from `tab-change` to `change`
918
+ - Updated CSS class naming convention
919
+ - Modified icon prop to use string names instead of components