@skewedaspect/sleekspace-ui 0.2.0-beta.1

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 (266) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/dist/sleekspace-ui.css +12844 -0
  4. package/dist/sleekspace-ui.es.js +19021 -0
  5. package/dist/sleekspace-ui.umd.js +19040 -0
  6. package/docs/components/accordion.md +92 -0
  7. package/docs/components/alert.md +72 -0
  8. package/docs/components/avatar.md +69 -0
  9. package/docs/components/breadcrumbs.md +65 -0
  10. package/docs/components/button/_meta.yaml +12 -0
  11. package/docs/components/button/accessibility.md +16 -0
  12. package/docs/components/button/custom-colors.md +18 -0
  13. package/docs/components/button/icons.md +31 -0
  14. package/docs/components/button/intro.md +8 -0
  15. package/docs/components/button/kinds.md +25 -0
  16. package/docs/components/button/sizes.md +14 -0
  17. package/docs/components/button/states.md +12 -0
  18. package/docs/components/button/usage.md +23 -0
  19. package/docs/components/button/variants.md +14 -0
  20. package/docs/components/button.md +110 -0
  21. package/docs/components/card.md +87 -0
  22. package/docs/components/checkbox.md +77 -0
  23. package/docs/components/collapsible.md +71 -0
  24. package/docs/components/divider.md +62 -0
  25. package/docs/components/dropdown.md +88 -0
  26. package/docs/components/field.md +80 -0
  27. package/docs/components/group.md +41 -0
  28. package/docs/components/input.md +84 -0
  29. package/docs/components/listbox.md +82 -0
  30. package/docs/components/modal.md +101 -0
  31. package/docs/components/navbar.md +64 -0
  32. package/docs/components/number-input.md +78 -0
  33. package/docs/components/page.md +77 -0
  34. package/docs/components/pagination.md +88 -0
  35. package/docs/components/panel.md +74 -0
  36. package/docs/components/popover.md +93 -0
  37. package/docs/components/progress.md +76 -0
  38. package/docs/components/radio.md +86 -0
  39. package/docs/components/sidebar.md +74 -0
  40. package/docs/components/skeleton.md +76 -0
  41. package/docs/components/slider.md +94 -0
  42. package/docs/components/spinner.md +59 -0
  43. package/docs/components/switch.md +97 -0
  44. package/docs/components/table.md +91 -0
  45. package/docs/components/tabs.md +108 -0
  46. package/docs/components/tag.md +75 -0
  47. package/docs/components/tags-input.md +88 -0
  48. package/docs/components/textarea.md +80 -0
  49. package/docs/components/theme.md +65 -0
  50. package/docs/components/toast.md +95 -0
  51. package/docs/components/tooltip.md +90 -0
  52. package/docs/guides/custom-colors.md +84 -0
  53. package/docs/guides/design-tokens.md +105 -0
  54. package/docs/guides/getting-started.md +144 -0
  55. package/docs/guides/installation.md +62 -0
  56. package/docs/guides/theming.md +101 -0
  57. package/package.json +76 -0
  58. package/src/components/Accordion/SkAccordion.vue +133 -0
  59. package/src/components/Accordion/SkAccordionItem.vue +131 -0
  60. package/src/components/Accordion/index.ts +3 -0
  61. package/src/components/Accordion/types.ts +9 -0
  62. package/src/components/Alert/SkAlert.vue +137 -0
  63. package/src/components/Alert/types.ts +10 -0
  64. package/src/components/Avatar/SkAvatar.vue +141 -0
  65. package/src/components/Avatar/index.ts +8 -0
  66. package/src/components/Avatar/types.ts +31 -0
  67. package/src/components/Breadcrumbs/SkBreadcrumbItem.vue +76 -0
  68. package/src/components/Breadcrumbs/SkBreadcrumbSeparator.vue +38 -0
  69. package/src/components/Breadcrumbs/SkBreadcrumbs.vue +93 -0
  70. package/src/components/Breadcrumbs/index.ts +10 -0
  71. package/src/components/Breadcrumbs/types.ts +36 -0
  72. package/src/components/Button/SkButton.vue +148 -0
  73. package/src/components/Button/types.ts +21 -0
  74. package/src/components/Card/SkCard.vue +144 -0
  75. package/src/components/Card/types.ts +12 -0
  76. package/src/components/Checkbox/SkCheckbox.vue +136 -0
  77. package/src/components/Checkbox/index.ts +8 -0
  78. package/src/components/Checkbox/types.ts +10 -0
  79. package/src/components/Collapsible/SkCollapsible.vue +159 -0
  80. package/src/components/Collapsible/index.ts +2 -0
  81. package/src/components/Collapsible/types.ts +8 -0
  82. package/src/components/Divider/SkDivider.vue +63 -0
  83. package/src/components/Divider/types.ts +15 -0
  84. package/src/components/Dropdown/SkDropdown.vue +150 -0
  85. package/src/components/Dropdown/SkDropdownMenuItem.vue +58 -0
  86. package/src/components/Dropdown/SkDropdownMenuSeparator.vue +26 -0
  87. package/src/components/Dropdown/SkDropdownSubmenu.vue +107 -0
  88. package/src/components/Dropdown/index.ts +11 -0
  89. package/src/components/Dropdown/types.ts +11 -0
  90. package/src/components/Field/SkField.vue +152 -0
  91. package/src/components/Field/index.ts +8 -0
  92. package/src/components/Field/types.ts +7 -0
  93. package/src/components/Group/SkGroup.vue +52 -0
  94. package/src/components/Group/types.ts +10 -0
  95. package/src/components/Input/SkInput.vue +117 -0
  96. package/src/components/Input/index.ts +8 -0
  97. package/src/components/Input/types.ts +11 -0
  98. package/src/components/Listbox/SkListbox.vue +164 -0
  99. package/src/components/Listbox/SkListboxItem.vue +68 -0
  100. package/src/components/Listbox/SkListboxSeparator.vue +26 -0
  101. package/src/components/Listbox/index.ts +10 -0
  102. package/src/components/Listbox/types.ts +10 -0
  103. package/src/components/Modal/SkModal.vue +231 -0
  104. package/src/components/Modal/index.ts +8 -0
  105. package/src/components/Modal/types.ts +12 -0
  106. package/src/components/NavBar/SkNavBar.vue +83 -0
  107. package/src/components/NavBar/index.ts +8 -0
  108. package/src/components/NavBar/types.ts +15 -0
  109. package/src/components/NumberInput/SkNumberInput.vue +168 -0
  110. package/src/components/NumberInput/index.ts +8 -0
  111. package/src/components/NumberInput/types.ts +10 -0
  112. package/src/components/Page/SkPage.vue +94 -0
  113. package/src/components/Page/index.ts +8 -0
  114. package/src/components/Page/types.ts +21 -0
  115. package/src/components/Pagination/SkPagination.vue +185 -0
  116. package/src/components/Pagination/SkPaginationItem.vue +107 -0
  117. package/src/components/Pagination/index.ts +9 -0
  118. package/src/components/Pagination/types.ts +40 -0
  119. package/src/components/Panel/SkPanel.vue +96 -0
  120. package/src/components/Panel/types.ts +15 -0
  121. package/src/components/Popover/SkPopover.vue +185 -0
  122. package/src/components/Popover/index.ts +8 -0
  123. package/src/components/Popover/types.ts +11 -0
  124. package/src/components/Progress/SkProgress.vue +144 -0
  125. package/src/components/Progress/index.ts +8 -0
  126. package/src/components/Progress/types.ts +34 -0
  127. package/src/components/Radio/SkRadio.vue +110 -0
  128. package/src/components/Radio/SkRadioGroup.vue +92 -0
  129. package/src/components/Radio/index.ts +9 -0
  130. package/src/components/Radio/types.ts +11 -0
  131. package/src/components/Sidebar/README.md +405 -0
  132. package/src/components/Sidebar/SkSidebar.vue +88 -0
  133. package/src/components/Sidebar/SkSidebarItem.vue +58 -0
  134. package/src/components/Sidebar/SkSidebarSection.vue +40 -0
  135. package/src/components/Sidebar/types.ts +3 -0
  136. package/src/components/Skeleton/SkSkeleton.vue +171 -0
  137. package/src/components/Skeleton/index.ts +8 -0
  138. package/src/components/Skeleton/types.ts +31 -0
  139. package/src/components/Slider/SkSlider.vue +165 -0
  140. package/src/components/Slider/index.ts +8 -0
  141. package/src/components/Slider/types.ts +44 -0
  142. package/src/components/Spinner/SkSpinner.vue +105 -0
  143. package/src/components/Spinner/index.ts +8 -0
  144. package/src/components/Spinner/types.ts +28 -0
  145. package/src/components/Switch/SkSwitch.vue +215 -0
  146. package/src/components/Switch/index.ts +8 -0
  147. package/src/components/Switch/types.ts +12 -0
  148. package/src/components/Table/SkTable.vue +109 -0
  149. package/src/components/Table/index.ts +2 -0
  150. package/src/components/Table/types.ts +15 -0
  151. package/src/components/Tabs/README.md +331 -0
  152. package/src/components/Tabs/SkTab.vue +84 -0
  153. package/src/components/Tabs/SkTabList.vue +62 -0
  154. package/src/components/Tabs/SkTabPanel.vue +47 -0
  155. package/src/components/Tabs/SkTabPanels.vue +23 -0
  156. package/src/components/Tabs/SkTabs.vue +124 -0
  157. package/src/components/Tabs/types.ts +21 -0
  158. package/src/components/Tag/SkTag.vue +129 -0
  159. package/src/components/Tag/types.ts +15 -0
  160. package/src/components/TagsInput/SkTagsInput.vue +184 -0
  161. package/src/components/TagsInput/index.ts +8 -0
  162. package/src/components/TagsInput/types.ts +10 -0
  163. package/src/components/Textarea/SkTextarea.vue +117 -0
  164. package/src/components/Textarea/index.ts +8 -0
  165. package/src/components/Textarea/types.ts +10 -0
  166. package/src/components/Theme/SkTheme.vue +47 -0
  167. package/src/components/Theme/types.ts +17 -0
  168. package/src/components/Theme/useTheme.ts +131 -0
  169. package/src/components/Toast/SkToast.vue +156 -0
  170. package/src/components/Toast/SkToastProvider.vue +180 -0
  171. package/src/components/Toast/index.ts +15 -0
  172. package/src/components/Toast/types.ts +63 -0
  173. package/src/components/Toast/useToast.ts +78 -0
  174. package/src/components/Tooltip/SkTooltip.vue +162 -0
  175. package/src/components/Tooltip/SkTooltipProvider.vue +114 -0
  176. package/src/components/Tooltip/index.ts +9 -0
  177. package/src/components/Tooltip/types.ts +13 -0
  178. package/src/composables/useCustomColors.test.ts +505 -0
  179. package/src/composables/useCustomColors.ts +124 -0
  180. package/src/composables/usePortalContext.test.ts +402 -0
  181. package/src/composables/usePortalContext.ts +95 -0
  182. package/src/global.d.ts +76 -0
  183. package/src/index.ts +259 -0
  184. package/src/styles/_scrollbar.scss +100 -0
  185. package/src/styles/base/_fonts.scss +105 -0
  186. package/src/styles/base/_global.scss +47 -0
  187. package/src/styles/base/_index.scss +24 -0
  188. package/src/styles/base/_reset.scss +11 -0
  189. package/src/styles/base/_typography.scss +178 -0
  190. package/src/styles/components/_accordion.scss +250 -0
  191. package/src/styles/components/_alert.scss +239 -0
  192. package/src/styles/components/_avatar.scss +133 -0
  193. package/src/styles/components/_breadcrumbs.scss +137 -0
  194. package/src/styles/components/_button.scss +731 -0
  195. package/src/styles/components/_card.scss +141 -0
  196. package/src/styles/components/_checkbox.scss +232 -0
  197. package/src/styles/components/_collapsible.scss +158 -0
  198. package/src/styles/components/_divider.scss +121 -0
  199. package/src/styles/components/_field.scss +87 -0
  200. package/src/styles/components/_group.scss +138 -0
  201. package/src/styles/components/_index.scss +46 -0
  202. package/src/styles/components/_input.scss +205 -0
  203. package/src/styles/components/_listbox.scss +453 -0
  204. package/src/styles/components/_menu.scss +216 -0
  205. package/src/styles/components/_modal.scss +329 -0
  206. package/src/styles/components/_navbar.scss +258 -0
  207. package/src/styles/components/_number-input.scss +352 -0
  208. package/src/styles/components/_page.scss +98 -0
  209. package/src/styles/components/_pagination.scss +411 -0
  210. package/src/styles/components/_panel.scss +281 -0
  211. package/src/styles/components/_popover.scss +258 -0
  212. package/src/styles/components/_progress.scss +280 -0
  213. package/src/styles/components/_radio.scss +255 -0
  214. package/src/styles/components/_sidebar.scss +92 -0
  215. package/src/styles/components/_skeleton.scss +138 -0
  216. package/src/styles/components/_slider.scss +262 -0
  217. package/src/styles/components/_spinner.scss +331 -0
  218. package/src/styles/components/_switch.scss +370 -0
  219. package/src/styles/components/_table.scss +405 -0
  220. package/src/styles/components/_tabs.scss +486 -0
  221. package/src/styles/components/_tag.scss +425 -0
  222. package/src/styles/components/_tags-input.scss +279 -0
  223. package/src/styles/components/_textarea.scss +208 -0
  224. package/src/styles/components/_toast.scss +331 -0
  225. package/src/styles/components/_tooltip.scss +206 -0
  226. package/src/styles/fonts/Titillium_Web/OFL.txt +93 -0
  227. package/src/styles/fonts/Titillium_Web/TitilliumWeb-Black.ttf +0 -0
  228. package/src/styles/fonts/Titillium_Web/TitilliumWeb-Bold.ttf +0 -0
  229. package/src/styles/fonts/Titillium_Web/TitilliumWeb-BoldItalic.ttf +0 -0
  230. package/src/styles/fonts/Titillium_Web/TitilliumWeb-ExtraLight.ttf +0 -0
  231. package/src/styles/fonts/Titillium_Web/TitilliumWeb-ExtraLightItalic.ttf +0 -0
  232. package/src/styles/fonts/Titillium_Web/TitilliumWeb-Italic.ttf +0 -0
  233. package/src/styles/fonts/Titillium_Web/TitilliumWeb-Light.ttf +0 -0
  234. package/src/styles/fonts/Titillium_Web/TitilliumWeb-LightItalic.ttf +0 -0
  235. package/src/styles/fonts/Titillium_Web/TitilliumWeb-Regular.ttf +0 -0
  236. package/src/styles/fonts/Titillium_Web/TitilliumWeb-SemiBold.ttf +0 -0
  237. package/src/styles/fonts/Titillium_Web/TitilliumWeb-SemiBoldItalic.ttf +0 -0
  238. package/src/styles/index.scss +17 -0
  239. package/src/styles/mixins/_cut-border.scss +254 -0
  240. package/src/styles/mixins/_index.scss +7 -0
  241. package/src/styles/theme/_variables.scss +42 -0
  242. package/src/styles/themes/README.md +127 -0
  243. package/src/styles/themes/_colorful.scss +58 -0
  244. package/src/styles/themes/_greyscale.scss +58 -0
  245. package/src/styles/themes/index.scss +9 -0
  246. package/src/styles/tokens/README.md +268 -0
  247. package/src/styles/tokens/_foundation-borders.scss +26 -0
  248. package/src/styles/tokens/_foundation-colors.scss +169 -0
  249. package/src/styles/tokens/_foundation-glow.scss +36 -0
  250. package/src/styles/tokens/_foundation-radius.scss +53 -0
  251. package/src/styles/tokens/_foundation-scrollbar.scss +31 -0
  252. package/src/styles/tokens/_foundation-shadows.scss +37 -0
  253. package/src/styles/tokens/_foundation-space.scss +36 -0
  254. package/src/styles/tokens/_foundation-transitions.scss +37 -0
  255. package/src/styles/tokens/_foundation-typography.scss +58 -0
  256. package/src/styles/tokens/_semantic-color-kinds.scss +112 -0
  257. package/src/styles/tokens/_semantic-colors.scss +10 -0
  258. package/src/styles/tokens/_semantic-interactive.scss +29 -0
  259. package/src/styles/tokens/_semantic-scrollbar.scss +48 -0
  260. package/src/styles/tokens/_semantic-surfaces.scss +36 -0
  261. package/src/styles/tokens/index.scss +38 -0
  262. package/src/styles/tokens.scss +268 -0
  263. package/src/styles/utilities/_index.scss +9 -0
  264. package/src/styles/utilities/_typography.scss +121 -0
  265. package/src/types.ts +50 -0
  266. package/web-types.json +3524 -0
@@ -0,0 +1,331 @@
1
+ # Tabs Component
2
+
3
+ A flexible, accessible tabbed interface component for organizing content into switchable panels. Built on RekaUI with keyboard navigation, ARIA support, and semantic color theming.
4
+
5
+ ## Architecture
6
+
7
+ The Tabs component is composed of five sub-components that work together:
8
+
9
+ ```
10
+ SkTabs (root container)
11
+ ├── SkTabList (tabs navigation container)
12
+ │ └── SkTab (individual tab trigger)
13
+ └── SkTabPanels (content container)
14
+ └── SkTabPanel (individual content panel)
15
+ ```
16
+
17
+ ### Component Roles
18
+
19
+ - **SkTabs**: Root container that manages state and provides context to children
20
+ - **SkTabList**: Container for tab triggers with optional orientation/placement
21
+ - **SkTab**: Individual clickable tab trigger
22
+ - **SkTabPanels**: Container for tab content panels
23
+ - **SkTabPanel**: Individual content panel (shown when corresponding tab is active)
24
+
25
+ ## Basic Usage
26
+
27
+ ```vue
28
+ <script setup>
29
+ import { ref } from 'vue';
30
+
31
+ const activeTab = ref('overview');
32
+ </script>
33
+
34
+ <template>
35
+ <SkTabs v-model="activeTab">
36
+ <SkTabList>
37
+ <SkTab name="overview">Overview</SkTab>
38
+ <SkTab name="details">Details</SkTab>
39
+ <SkTab name="settings">Settings</SkTab>
40
+ </SkTabList>
41
+
42
+ <SkTabPanels>
43
+ <SkTabPanel name="overview">
44
+ <h3>Overview</h3>
45
+ <p>Overview content goes here...</p>
46
+ </SkTabPanel>
47
+
48
+ <SkTabPanel name="details">
49
+ <h3>Details</h3>
50
+ <p>Detailed information goes here...</p>
51
+ </SkTabPanel>
52
+
53
+ <SkTabPanel name="settings">
54
+ <h3>Settings</h3>
55
+ <p>Settings configuration goes here...</p>
56
+ </SkTabPanel>
57
+ </SkTabPanels>
58
+ </SkTabs>
59
+ </template>
60
+ ```
61
+
62
+ ## Orientation
63
+
64
+ Tabs can be displayed horizontally (default) or vertically:
65
+
66
+ ```vue
67
+ <SkTabs v-model="activeTab" orientation="vertical">
68
+ <SkTabList>
69
+ <SkTab name="tab1">Tab 1</SkTab>
70
+ <SkTab name="tab2">Tab 2</SkTab>
71
+ </SkTabList>
72
+ <SkTabPanels>
73
+ <SkTabPanel name="tab1">Content 1</SkTabPanel>
74
+ <SkTabPanel name="tab2">Content 2</SkTabPanel>
75
+ </SkTabPanels>
76
+ </SkTabs>
77
+ ```
78
+
79
+ ## Placement
80
+
81
+ Control where the tab list appears relative to content:
82
+
83
+ ```vue
84
+ <!-- Horizontal tabs -->
85
+ <SkTabs v-model="activeTab" placement="start"> <!-- tabs on top (default) -->
86
+ <SkTabs v-model="activeTab" placement="end"> <!-- tabs on bottom -->
87
+
88
+ <!-- Vertical tabs -->
89
+ <SkTabs v-model="activeTab" orientation="vertical" placement="start"> <!-- tabs on left (default) -->
90
+ <SkTabs v-model="activeTab" orientation="vertical" placement="end"> <!-- tabs on right -->
91
+ ```
92
+
93
+ ## Semantic Colors
94
+
95
+ Apply semantic color themes to all tabs:
96
+
97
+ ```vue
98
+ <SkTabs v-model="activeTab" kind="primary">
99
+ <SkTabList>
100
+ <SkTab name="tab1">Tab 1</SkTab>
101
+ <SkTab name="tab2">Tab 2</SkTab>
102
+ </SkTabList>
103
+ <SkTabPanels>
104
+ <SkTabPanel name="tab1">Content 1</SkTabPanel>
105
+ <SkTabPanel name="tab2">Content 2</SkTabPanel>
106
+ </SkTabPanels>
107
+ </SkTabs>
108
+ ```
109
+
110
+ Available kinds: `neutral`, `primary`, `accent`, `info`, `success`, `warning`, `danger`
111
+
112
+ Individual tabs can override the parent kind:
113
+
114
+ ```vue
115
+ <SkTabs v-model="activeTab" kind="neutral">
116
+ <SkTabList>
117
+ <SkTab name="normal">Normal</SkTab>
118
+ <SkTab name="important" kind="warning">Important</SkTab>
119
+ </SkTabList>
120
+ <!-- ... -->
121
+ </SkTabs>
122
+ ```
123
+
124
+ ## Custom Colors
125
+
126
+ Use custom colors for complete theming control:
127
+
128
+ ```vue
129
+ <SkTabs
130
+ v-model="activeTab"
131
+ base-color="oklch(0.65 0.25 280)"
132
+ text-color="white"
133
+ >
134
+ <SkTabList>
135
+ <SkTab name="tab1">Custom Purple Tab</SkTab>
136
+ <SkTab name="tab2">Another Tab</SkTab>
137
+ </SkTabList>
138
+ <SkTabPanels>
139
+ <SkTabPanel name="tab1">Content with custom colors</SkTabPanel>
140
+ <SkTabPanel name="tab2">More content</SkTabPanel>
141
+ </SkTabPanels>
142
+ </SkTabs>
143
+ ```
144
+
145
+ ## Icons in Tabs
146
+
147
+ Add icons to tabs using the `icon` slot:
148
+
149
+ ```vue
150
+ <SkTab name="home">
151
+ <template #icon>
152
+ <FontAwesomeIcon :icon="['fas', 'home']" />
153
+ </template>
154
+ Home
155
+ </SkTab>
156
+ ```
157
+
158
+ ## Disabled Tabs
159
+
160
+ Disable specific tabs to prevent interaction:
161
+
162
+ ```vue
163
+ <SkTab name="comingSoon" :disabled="true">
164
+ Coming Soon
165
+ </SkTab>
166
+ ```
167
+
168
+ ## Flush Mode
169
+
170
+ Use negative margins to align tabs with parent container edges:
171
+
172
+ ```vue
173
+ <SkTabs v-model="activeTab" flush>
174
+ <!-- tabs will align flush with container edges -->
175
+ </SkTabs>
176
+ ```
177
+
178
+ ## Accessibility
179
+
180
+ The Tabs component follows WAI-ARIA authoring practices:
181
+
182
+ - **Keyboard Navigation**:
183
+ - `Tab`: Move focus into and out of tab list
184
+ - `Arrow Left/Right` (horizontal): Navigate between tabs
185
+ - `Arrow Up/Down` (vertical): Navigate between tabs
186
+ - `Home`: Focus first tab
187
+ - `End`: Focus last tab
188
+ - `Enter/Space`: Activate focused tab
189
+
190
+ - **ARIA Attributes**:
191
+ - `role="tablist"` on SkTabList
192
+ - `role="tab"` on SkTab
193
+ - `role="tabpanel"` on SkTabPanel
194
+ - `aria-selected` indicates active tab
195
+ - `aria-controls` links tabs to panels
196
+ - `aria-labelledby` links panels to tabs
197
+
198
+ - **Focus Management**: Active tab receives focus, inactive panels are hidden from screen readers
199
+
200
+ ## API Reference
201
+
202
+ ### SkTabs Props
203
+
204
+ | Prop | Type | Default | Description |
205
+ |------|------|---------|-------------|
206
+ | `modelValue` | `string \| number` | (required) | Currently active tab identifier |
207
+ | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Tab layout direction |
208
+ | `placement` | `'start' \| 'end'` | `'start'` | Tab list position relative to content |
209
+ | `kind` | `ComponentKind` | `undefined` | Semantic color kind for all tabs |
210
+ | `flush` | `boolean` | `false` | Use negative margins for edge alignment |
211
+ | `baseColor` | `string` | `undefined` | Custom base color (CSS color value) |
212
+ | `textColor` | `string` | `undefined` | Custom text color (CSS color value) |
213
+
214
+ ### SkTabs Events
215
+
216
+ | Event | Payload | Description |
217
+ |-------|---------|-------------|
218
+ | `update:modelValue` | `string \| number` | Emitted when active tab changes |
219
+
220
+ ### SkTab Props
221
+
222
+ | Prop | Type | Default | Description |
223
+ |------|------|---------|-------------|
224
+ | `name` | `string \| number` | (required) | Unique identifier matching SkTabPanel |
225
+ | `label` | `string` | `undefined` | Tab label text (can use default slot instead) |
226
+ | `disabled` | `boolean` | `false` | Whether tab is disabled |
227
+ | `kind` | `ComponentKind` | `undefined` | Override parent tabs kind |
228
+
229
+ ### SkTab Slots
230
+
231
+ | Slot | Description |
232
+ |------|-------------|
233
+ | `default` | Tab label content (overrides `label` prop) |
234
+ | `icon` | Icon displayed before label |
235
+
236
+ ## Best Practices
237
+
238
+ 1. **Unique Names**: Ensure each tab `name` matches exactly one panel `name`
239
+ 2. **Meaningful Labels**: Use clear, concise tab labels that describe content
240
+ 3. **Limited Tabs**: Avoid more than 5-7 tabs; consider alternative UI patterns for more
241
+ 4. **Consistent Height**: Keep tab panel content height consistent to avoid layout shifts
242
+ 5. **Loading States**: Show loading indicators when switching tabs with async content
243
+ 6. **Preserve State**: Consider using `<KeepAlive>` to preserve panel state when switching
244
+
245
+ ## Common Patterns
246
+
247
+ ### Tabs with Icons
248
+
249
+ ```vue
250
+ <SkTabList>
251
+ <SkTab name="home">
252
+ <template #icon>
253
+ <HomeIcon />
254
+ </template>
255
+ Home
256
+ </SkTab>
257
+ <SkTab name="settings">
258
+ <template #icon>
259
+ <SettingsIcon />
260
+ </template>
261
+ Settings
262
+ </SkTab>
263
+ </SkTabList>
264
+ ```
265
+
266
+ ### Conditional Tabs
267
+
268
+ ```vue
269
+ <SkTabList>
270
+ <SkTab name="public">Public</SkTab>
271
+ <SkTab v-if="isAdmin" name="admin">Admin</SkTab>
272
+ </SkTabList>
273
+
274
+ <SkTabPanels>
275
+ <SkTabPanel name="public">Public content</SkTabPanel>
276
+ <SkTabPanel v-if="isAdmin" name="admin">Admin content</SkTabPanel>
277
+ </SkTabPanels>
278
+ ```
279
+
280
+ ### Async Tab Content
281
+
282
+ ```vue
283
+ <script setup>
284
+ const activeTab = ref('overview');
285
+ const data = ref(null);
286
+ const loading = ref(false);
287
+
288
+ watch(activeTab, async (newTab) => {
289
+ loading.value = true;
290
+ data.value = await fetchTabData(newTab);
291
+ loading.value = false;
292
+ });
293
+ </script>
294
+
295
+ <template>
296
+ <SkTabs v-model="activeTab">
297
+ <SkTabList>
298
+ <SkTab name="overview">Overview</SkTab>
299
+ <SkTab name="details">Details</SkTab>
300
+ </SkTabList>
301
+
302
+ <SkTabPanels>
303
+ <SkTabPanel name="overview">
304
+ <div v-if="loading">Loading...</div>
305
+ <div v-else>{{ data }}</div>
306
+ </SkTabPanel>
307
+ <SkTabPanel name="details">
308
+ <div v-if="loading">Loading...</div>
309
+ <div v-else>{{ data }}</div>
310
+ </SkTabPanel>
311
+ </SkTabPanels>
312
+ </SkTabs>
313
+ </template>
314
+ ```
315
+
316
+ ## Styling
317
+
318
+ Tabs use CSS custom properties for theming:
319
+
320
+ ```css
321
+ .sk-tabs {
322
+ --sk-tab-color-base: /* base color for active tab indicator */
323
+ --sk-tab-fg: /* text color */
324
+ --sk-tab-padding: /* tab padding */
325
+ --sk-tab-gap: /* gap between tabs */
326
+ --sk-tab-border-width: /* active indicator height */
327
+ --sk-tab-inactive-opacity: /* opacity for inactive tabs */
328
+ }
329
+ ```
330
+
331
+ Override these in your styles or use the `baseColor`/`textColor` props for component-level customization.
@@ -0,0 +1,84 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - Tab Component (powered by RekaUI)
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <TabsTrigger
7
+ :value="String(name)"
8
+ :disabled="disabled"
9
+ :class="classes"
10
+ >
11
+ <span v-if="$slots.icon" class="sk-tab-icon">
12
+ <slot name="icon" />
13
+ </span>
14
+ <span class="sk-tab-label">
15
+ <span class="sk-tab-label-normal">
16
+ <slot>{{ label }}</slot>
17
+ </span>
18
+ <span class="sk-tab-label-bold" aria-hidden="true">
19
+ <slot>{{ label }}</slot>
20
+ </span>
21
+ </span>
22
+ </TabsTrigger>
23
+ </template>
24
+
25
+ <!--------------------------------------------------------------------------------------------------------------------->
26
+
27
+ <script setup lang="ts">
28
+ /**
29
+ * @component
30
+ * An individual tab trigger component powered by RekaUI.
31
+ * Used within SkTabList to switch between tab panels.
32
+ */
33
+
34
+ import { type ComputedRef, computed, inject } from 'vue';
35
+ import { TabsTrigger } from 'reka-ui';
36
+ import type { ComponentKind } from '@/types';
37
+
38
+ //------------------------------------------------------------------------------------------------------------------
39
+
40
+ /**
41
+ * An individual tab trigger component powered by RekaUI.
42
+ * Used within SkTabList to switch between tab panels.
43
+ */
44
+ export interface SkTabComponentProps
45
+ {
46
+ /** Unique identifier matching the corresponding SkTabPanel */
47
+ name : string | number;
48
+ /** Text label displayed in the tab (can be overridden by default slot) */
49
+ label ?: string;
50
+ /** Whether the tab is disabled and unclickable */
51
+ disabled ?: boolean;
52
+ /** Semantic color kind (overrides parent tabs kind if provided) */
53
+ kind ?: ComponentKind;
54
+ }
55
+
56
+ //------------------------------------------------------------------------------------------------------------------
57
+
58
+ const props = withDefaults(defineProps<SkTabComponentProps>(), {
59
+ label: undefined,
60
+ disabled: false,
61
+ kind: undefined,
62
+ });
63
+
64
+ //------------------------------------------------------------------------------------------------------------------
65
+
66
+ // Inject parent kind (Sleekspace-specific for theming)
67
+ const parentKind = inject<ComputedRef<ComponentKind | undefined>>('tabs-kind', computed(() => undefined));
68
+
69
+ // Use prop kind if provided, otherwise use parent kind
70
+ const kind = computed(() => props.kind ?? parentKind.value);
71
+
72
+ //------------------------------------------------------------------------------------------------------------------
73
+
74
+ const classes = computed(() =>
75
+ {
76
+ return {
77
+ 'sk-tab': true,
78
+ [`sk-${ kind.value }`]: !!kind.value,
79
+ 'sk-disabled': props.disabled,
80
+ };
81
+ });
82
+ </script>
83
+
84
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,62 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - Tab List Component (powered by RekaUI)
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <TabsList :class="classes">
7
+ <slot />
8
+ </TabsList>
9
+ </template>
10
+
11
+ <!--------------------------------------------------------------------------------------------------------------------->
12
+
13
+ <script setup lang="ts">
14
+ /**
15
+ * @component
16
+ * A container component for SkTab components powered by RekaUI.
17
+ * Arranges tabs in horizontal or vertical orientation.
18
+ */
19
+
20
+ import { computed, inject } from 'vue';
21
+ import { TabsList } from 'reka-ui';
22
+ import type { SkTabsOrientation } from './types.ts';
23
+
24
+ //------------------------------------------------------------------------------------------------------------------
25
+
26
+ /**
27
+ * A container component for SkTab components powered by RekaUI.
28
+ * Arranges tabs in horizontal or vertical orientation.
29
+ */
30
+ export interface SkTabListComponentProps
31
+ {
32
+ /** Orientation for arranging tabs (overrides parent SkTabs orientation if provided) */
33
+ orientation ?: SkTabsOrientation;
34
+ }
35
+
36
+ //------------------------------------------------------------------------------------------------------------------
37
+
38
+ const props = withDefaults(defineProps<SkTabListComponentProps>(), {
39
+ orientation: undefined,
40
+ });
41
+
42
+ //------------------------------------------------------------------------------------------------------------------
43
+
44
+ // Inject orientation from parent (if prop not provided)
45
+ // Note: RekaUI's TabsList gets orientation from TabsRoot context automatically,
46
+ // but we need it for our styling classes
47
+ const contextOrientation = inject<any>('tabs-orientation', 'horizontal');
48
+
49
+ //------------------------------------------------------------------------------------------------------------------
50
+
51
+ const effectiveOrientation = computed(() => props.orientation || contextOrientation.value);
52
+
53
+ const classes = computed(() =>
54
+ {
55
+ return {
56
+ 'sk-tab-list': true,
57
+ [`sk-${ effectiveOrientation.value }`]: true,
58
+ };
59
+ });
60
+ </script>
61
+
62
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,47 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - Tab Panel Component (powered by RekaUI)
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <TabsContent
7
+ :value="String(name)"
8
+ :force-mount="keepAlive"
9
+ class="sk-tab-panel"
10
+ >
11
+ <slot />
12
+ </TabsContent>
13
+ </template>
14
+
15
+ <!--------------------------------------------------------------------------------------------------------------------->
16
+
17
+ <script setup lang="ts">
18
+ /**
19
+ * @component
20
+ * A content panel component for displaying tab content powered by RekaUI.
21
+ * Automatically shown/hidden based on the active tab in the parent SkTabs.
22
+ */
23
+
24
+ import { TabsContent } from 'reka-ui';
25
+
26
+ //------------------------------------------------------------------------------------------------------------------
27
+
28
+ /**
29
+ * A content panel component for displaying tab content powered by RekaUI.
30
+ * Automatically shown/hidden based on the active tab in the parent SkTabs.
31
+ */
32
+ export interface SkTabPanelComponentProps
33
+ {
34
+ /** Unique identifier matching the corresponding SkTab */
35
+ name : string | number;
36
+ /** Whether to keep panel mounted in DOM even when inactive */
37
+ keepAlive ?: boolean;
38
+ }
39
+
40
+ //------------------------------------------------------------------------------------------------------------------
41
+
42
+ withDefaults(defineProps<SkTabPanelComponentProps>(), {
43
+ keepAlive: false,
44
+ });
45
+ </script>
46
+
47
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,23 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - Tab Panels Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <div class="sk-tab-panels">
7
+ <slot />
8
+ </div>
9
+ </template>
10
+
11
+ <!--------------------------------------------------------------------------------------------------------------------->
12
+
13
+ <script setup lang="ts">
14
+ /**
15
+ * @component
16
+ * A simple container component for grouping SkTabPanel components.
17
+ * Provides semantic structure for organizing tab content.
18
+ */
19
+
20
+ // No props or logic needed - just provides semantic structure
21
+ </script>
22
+
23
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,124 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - Tabs Component (powered by RekaUI)
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <TabsRoot
7
+ :model-value="modelValue"
8
+ :orientation="orientation"
9
+ :class="classes"
10
+ :style="customColorStyles"
11
+ @update:model-value="$emit('update:modelValue', $event)"
12
+ >
13
+ <slot />
14
+ </TabsRoot>
15
+ </template>
16
+
17
+ <!--------------------------------------------------------------------------------------------------------------------->
18
+
19
+ <script setup lang="ts">
20
+ /**
21
+ * @component
22
+ * A tabbed interface component for organizing content into switchable panels powered by RekaUI.
23
+ * Manages active tab state and provides context to child tab components.
24
+ */
25
+
26
+ import { computed, provide, toRef } from 'vue';
27
+ import { TabsRoot } from 'reka-ui';
28
+ import type {
29
+ SkTabsOrientation,
30
+ SkTabsPlacement,
31
+ } from './types';
32
+ import type { ComponentCustomColors, ComponentKind } from '@/types';
33
+ import { useCustomColors } from '@/composables/useCustomColors';
34
+
35
+ //------------------------------------------------------------------------------------------------------------------
36
+
37
+ /**
38
+ * A tabbed interface component for organizing content into switchable panels powered by RekaUI.
39
+ * Manages active tab state and provides context to child tab components.
40
+ *
41
+ * @example Basic tabs
42
+ * ```vue
43
+ * <SkTabs v-model="activeTab">
44
+ * <SkTabList>
45
+ * <SkTab name="overview">Overview</SkTab>
46
+ * <SkTab name="details">Details</SkTab>
47
+ * </SkTabList>
48
+ * <SkTabPanels>
49
+ * <SkTabPanel name="overview">Overview content</SkTabPanel>
50
+ * <SkTabPanel name="details">Details content</SkTabPanel>
51
+ * </SkTabPanels>
52
+ * </SkTabs>
53
+ * ```
54
+ *
55
+ * @example Custom colors
56
+ * ```vue
57
+ * <SkTabs
58
+ * v-model="activeTab"
59
+ * base-color="oklch(0.65 0.2 280)"
60
+ * text-color="white"
61
+ * >
62
+ * <!-- Tab content -->
63
+ * </SkTabs>
64
+ * ```
65
+ */
66
+ export interface SkTabsComponentProps extends ComponentCustomColors
67
+ {
68
+ /** Currently active tab identifier (matching a SkTab name) */
69
+ modelValue : string | number;
70
+ /** Orientation for tab layout (horizontal or vertical) */
71
+ orientation ?: SkTabsOrientation;
72
+ /** Placement of tabs relative to content (start, center, end) */
73
+ placement ?: SkTabsPlacement;
74
+ /** Semantic color kind for all tabs (can be overridden per tab) */
75
+ kind ?: ComponentKind;
76
+ /** Whether to use negative margins to align with parent container edges */
77
+ flush ?: boolean;
78
+ }
79
+
80
+ //------------------------------------------------------------------------------------------------------------------
81
+
82
+ const props = withDefaults(defineProps<SkTabsComponentProps>(), {
83
+ orientation: 'horizontal',
84
+ placement: 'start',
85
+ kind: undefined,
86
+ flush: false,
87
+ });
88
+
89
+ defineEmits<{
90
+ 'update:modelValue' : [value : string | number];
91
+ }>();
92
+
93
+ //------------------------------------------------------------------------------------------------------------------
94
+
95
+ // Provide our custom props to child components for styling
96
+ // (RekaUI handles its own context internally, but we need these for our CSS classes)
97
+ provide('tabs-orientation', computed(() => props.orientation));
98
+ provide('tabs-placement', computed(() => props.placement));
99
+ provide('tabs-kind', computed(() => props.kind));
100
+
101
+ //------------------------------------------------------------------------------------------------------------------
102
+
103
+ const classes = computed(() =>
104
+ {
105
+ return {
106
+ 'sk-tabs': true,
107
+ [`sk-${ props.orientation }`]: true,
108
+ [`sk-placement-${ props.placement }`]: true,
109
+ [`sk-${ props.kind }`]: !!props.kind,
110
+ 'sk-flush': props.flush,
111
+ };
112
+ });
113
+
114
+ //------------------------------------------------------------------------------------------------------------------
115
+
116
+ // Custom color styles
117
+ const customColorStyles = useCustomColors(
118
+ 'tabs',
119
+ toRef(() => props.baseColor),
120
+ toRef(() => props.textColor)
121
+ );
122
+ </script>
123
+
124
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,21 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Tabs Component Types
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ import type { SkButtonKind, SkButtonSize, SkButtonVariant } from '../Button/types';
6
+
7
+ //----------------------------------------------------------------------------------------------------------------------
8
+
9
+ // Tabs visual variant
10
+ export type SkTabsVariant = 'underline' | 'buttons';
11
+
12
+ // Tabs orientation
13
+ export type SkTabsOrientation = 'horizontal' | 'vertical';
14
+
15
+ // Tab list placement (for vertical: start=left, end=right; for horizontal: start=top, end=bottom)
16
+ export type SkTabsPlacement = 'start' | 'end';
17
+
18
+ // Re-export button types for convenience
19
+ export type { SkButtonKind, SkButtonVariant, SkButtonSize };
20
+
21
+ //----------------------------------------------------------------------------------------------------------------------