@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,63 @@
1
+ <!--------------------------------------------------------------------------------------------------------------------
2
+ - Divider Component
3
+ -------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <hr :class="classes" role="separator" :aria-orientation="orientation">
7
+ </template>
8
+
9
+ <!--------------------------------------------------------------------------------------------------------------------->
10
+
11
+ <script setup lang="ts">
12
+ /**
13
+ * @component
14
+ * A visual separator component for dividing content.
15
+ * Supports horizontal and vertical orientations with subtle or default styling.
16
+ */
17
+
18
+ import { computed } from 'vue';
19
+ import type { ComponentKind, ComponentSize } from '@/types';
20
+ import type { SkDividerOrientation, SkDividerVariant } from './types';
21
+
22
+ //------------------------------------------------------------------------------------------------------------------
23
+
24
+ /**
25
+ * A visual separator component for dividing content.
26
+ * Supports horizontal and vertical orientations with subtle or default styling.
27
+ */
28
+ export interface SkDividerComponentProps
29
+ {
30
+ /** Orientation of the divider line (horizontal or vertical) */
31
+ orientation ?: SkDividerOrientation;
32
+ /** Semantic color kind for the divider */
33
+ kind ?: ComponentKind;
34
+ /** Visual variant (subtle for lighter appearance) */
35
+ variant ?: SkDividerVariant;
36
+ /** Size of the divider (controls thickness and spacing) */
37
+ size ?: ComponentSize;
38
+ }
39
+
40
+ //------------------------------------------------------------------------------------------------------------------
41
+
42
+ const props = withDefaults(defineProps<SkDividerComponentProps>(), {
43
+ orientation: 'horizontal',
44
+ kind: 'neutral',
45
+ variant: undefined,
46
+ size: 'md',
47
+ });
48
+
49
+ //------------------------------------------------------------------------------------------------------------------
50
+
51
+ const classes = computed(() =>
52
+ {
53
+ return {
54
+ 'sk-divider': true,
55
+ [`sk-${ props.orientation }`]: true,
56
+ [`sk-${ props.kind }`]: true,
57
+ [`sk-${ props.size }`]: true,
58
+ 'sk-subtle': props.variant === 'subtle',
59
+ };
60
+ });
61
+ </script>
62
+
63
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,15 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Divider Component Types
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ /**
6
+ * Divider orientation options
7
+ */
8
+ export type SkDividerOrientation = 'horizontal' | 'vertical';
9
+
10
+ /**
11
+ * Divider variant options
12
+ */
13
+ export type SkDividerVariant = 'subtle';
14
+
15
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,150 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - Dropdown Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <DropdownMenuRoot>
7
+ <DropdownMenuTrigger as-child>
8
+ <slot name="trigger">
9
+ <SkButton :kind="kind">
10
+ {{ triggerText }}
11
+ <template #trailing>
12
+ <svg
13
+ xmlns="http://www.w3.org/2000/svg"
14
+ viewBox="0 0 24 24"
15
+ fill="none"
16
+ stroke="currentColor"
17
+ stroke-width="2"
18
+ stroke-linecap="square"
19
+ stroke-linejoin="miter"
20
+ style="width: 1rem; height: 1rem;"
21
+ >
22
+ <polyline :points="caretPoints" />
23
+ </svg>
24
+ </template>
25
+ </SkButton>
26
+ </slot>
27
+ </DropdownMenuTrigger>
28
+
29
+ <DropdownMenuPortal>
30
+ <DropdownMenuContent
31
+ :data-scheme="theme"
32
+ :class="classes"
33
+ :style="customColorStyles"
34
+ :side="side"
35
+ :align="align"
36
+ :side-offset="sideOffset"
37
+ >
38
+ <slot />
39
+ </DropdownMenuContent>
40
+ </DropdownMenuPortal>
41
+ </DropdownMenuRoot>
42
+ </template>
43
+
44
+ <!--------------------------------------------------------------------------------------------------------------------->
45
+
46
+ <style lang="scss" scoped>
47
+ // Component styles use shared menu styles from /src/styles/components/_menu.scss
48
+ </style>
49
+
50
+ <!--------------------------------------------------------------------------------------------------------------------->
51
+
52
+ <script setup lang="ts">
53
+ /**
54
+ * @component
55
+ * A dropdown menu component combining a trigger button and menu content powered by RekaUI.
56
+ * Use with SkMenuItem and SkMenuSeparator components.
57
+ */
58
+
59
+ import { computed, provide, toRef } from 'vue';
60
+ import {
61
+ DropdownMenuContent,
62
+ DropdownMenuPortal,
63
+ DropdownMenuRoot,
64
+ DropdownMenuTrigger,
65
+ } from 'reka-ui';
66
+
67
+ // Types
68
+ import type { ComponentCustomColors } from '@/types';
69
+ import type { SkDropdownAlign, SkDropdownKind, SkDropdownSide } from './types';
70
+
71
+ // Components
72
+ import SkButton from '../Button/SkButton.vue';
73
+
74
+ // Composables
75
+ import { useCustomColors } from '@/composables/useCustomColors';
76
+ import { usePortalContext } from '@/composables/usePortalContext';
77
+
78
+ //------------------------------------------------------------------------------------------------------------------
79
+
80
+ /**
81
+ * A dropdown menu component combining a trigger button and menu content powered by RekaUI.
82
+ */
83
+ export interface SkDropdownComponentProps extends ComponentCustomColors
84
+ {
85
+ /** Semantic color kind */
86
+ kind ?: SkDropdownKind;
87
+ /** Text for default trigger button (use trigger slot for custom trigger) */
88
+ triggerText ?: string;
89
+ /** Side of the trigger to position menu */
90
+ side ?: SkDropdownSide;
91
+ /** Alignment relative to trigger */
92
+ align ?: SkDropdownAlign;
93
+ /** Offset from the trigger in pixels */
94
+ sideOffset ?: number;
95
+ }
96
+
97
+ //------------------------------------------------------------------------------------------------------------------
98
+
99
+ const props = withDefaults(defineProps<SkDropdownComponentProps>(), {
100
+ kind: 'neutral',
101
+ triggerText: 'Menu',
102
+ side: 'bottom',
103
+ align: 'start',
104
+ sideOffset: 4,
105
+ });
106
+
107
+ //------------------------------------------------------------------------------------------------------------------
108
+
109
+ // Handle portal context (theme injection/re-provision for nested portal components)
110
+ const { theme } = usePortalContext();
111
+
112
+ // Provide kind for submenus (reactive computed so changes propagate)
113
+ provide('dropdown-kind', computed(() => props.kind));
114
+
115
+ //------------------------------------------------------------------------------------------------------------------
116
+
117
+ // Caret direction based on menu side
118
+ const caretPoints = computed(() =>
119
+ {
120
+ switch (props.side)
121
+ {
122
+ case 'top':
123
+ return '6 15 12 9 18 15'; // Point up
124
+ case 'right':
125
+ return '9 6 15 12 9 18'; // Point right
126
+ case 'left':
127
+ return '15 6 9 12 15 18'; // Point left
128
+ case 'bottom':
129
+ default:
130
+ return '6 9 12 15 18 9'; // Point down
131
+ }
132
+ });
133
+
134
+ //------------------------------------------------------------------------------------------------------------------
135
+
136
+ const classes = computed(() => ({
137
+ 'sk-dropdown-menu-content': true,
138
+ [`sk-${ props.kind }`]: true,
139
+ }));
140
+
141
+ //------------------------------------------------------------------------------------------------------------------
142
+
143
+ const customColorStyles = useCustomColors(
144
+ 'dropdown',
145
+ toRef(() => props.baseColor),
146
+ toRef(() => props.textColor)
147
+ );
148
+ </script>
149
+
150
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,58 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - MenuItem Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <DropdownMenuItem :class="classes" :disabled="disabled" @click="$emit('click', $event)">
7
+ <slot />
8
+ </DropdownMenuItem>
9
+ </template>
10
+
11
+ <!--------------------------------------------------------------------------------------------------------------------->
12
+
13
+ <style lang="scss" scoped>
14
+ // Component styles are in /src/styles/components/_menu.scss
15
+ </style>
16
+
17
+ <!--------------------------------------------------------------------------------------------------------------------->
18
+
19
+ <script setup lang="ts">
20
+ /**
21
+ * @component
22
+ * A menu item component for use within SkDropdown.
23
+ */
24
+
25
+ import { computed } from 'vue';
26
+ import { DropdownMenuItem } from 'reka-ui';
27
+
28
+ //------------------------------------------------------------------------------------------------------------------
29
+
30
+ /**
31
+ * A menu item component for use within SkDropdown.
32
+ */
33
+ export interface SkDropdownMenuItemComponentProps
34
+ {
35
+ /** Disabled state */
36
+ disabled ?: boolean;
37
+ }
38
+
39
+ //------------------------------------------------------------------------------------------------------------------
40
+
41
+ withDefaults(defineProps<SkDropdownMenuItemComponentProps>(), {
42
+ disabled: false,
43
+ });
44
+
45
+ //------------------------------------------------------------------------------------------------------------------
46
+
47
+ defineEmits<{
48
+ click : [event : Event];
49
+ }>();
50
+
51
+ //------------------------------------------------------------------------------------------------------------------
52
+
53
+ const classes = computed(() => ({
54
+ 'sk-dropdown-menu-item': true,
55
+ }));
56
+ </script>
57
+
58
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,26 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - MenuSeparator Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <DropdownMenuSeparator class="sk-menu-separator" />
7
+ </template>
8
+
9
+ <!--------------------------------------------------------------------------------------------------------------------->
10
+
11
+ <style lang="scss" scoped>
12
+ // Component styles are in /src/styles/components/_menu.scss
13
+ </style>
14
+
15
+ <!--------------------------------------------------------------------------------------------------------------------->
16
+
17
+ <script setup lang="ts">
18
+ /**
19
+ * @component
20
+ * A menu separator component for use within SkDropdown.
21
+ */
22
+
23
+ import { DropdownMenuSeparator } from 'reka-ui';
24
+ </script>
25
+
26
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,107 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - DropdownSubmenu Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <DropdownMenuSub>
7
+ <DropdownMenuSubTrigger :class="triggerClasses">
8
+ {{ triggerText }}
9
+ <svg
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ viewBox="0 0 24 24"
12
+ fill="none"
13
+ stroke="currentColor"
14
+ stroke-width="2"
15
+ stroke-linecap="square"
16
+ stroke-linejoin="miter"
17
+ class="sk-submenu-caret"
18
+ >
19
+ <polyline points="9 6 15 12 9 18" />
20
+ </svg>
21
+ </DropdownMenuSubTrigger>
22
+ <DropdownMenuPortal>
23
+ <DropdownMenuSubContent
24
+ :data-scheme="theme"
25
+ :class="contentClasses"
26
+ >
27
+ <slot />
28
+ </DropdownMenuSubContent>
29
+ </DropdownMenuPortal>
30
+ </DropdownMenuSub>
31
+ </template>
32
+
33
+ <!--------------------------------------------------------------------------------------------------------------------->
34
+
35
+ <style lang="scss" scoped>
36
+ // Component styles use shared menu styles from /src/styles/components/_menu.scss
37
+ </style>
38
+
39
+ <!--------------------------------------------------------------------------------------------------------------------->
40
+
41
+ <script setup lang="ts">
42
+ /**
43
+ * @component
44
+ * A dropdown submenu component for nested menus.
45
+ * Use with SkDropdownMenuItem components in default slot.
46
+ */
47
+
48
+ import { computed, inject } from 'vue';
49
+
50
+ // Composables
51
+ import { usePortalContext } from '@/composables/usePortalContext';
52
+ import {
53
+ DropdownMenuPortal,
54
+ DropdownMenuSub,
55
+ DropdownMenuSubContent,
56
+ DropdownMenuSubTrigger,
57
+ } from 'reka-ui';
58
+
59
+ // Types
60
+ import type { SkDropdownKind } from './types';
61
+
62
+ //------------------------------------------------------------------------------------------------------------------
63
+
64
+ /**
65
+ * A dropdown submenu component for nested menus.
66
+ */
67
+ export interface SkDropdownSubmenuComponentProps
68
+ {
69
+ /** Text for submenu trigger */
70
+ triggerText : string;
71
+ /** Semantic color kind (inherits from parent dropdown if not set) */
72
+ kind ?: SkDropdownKind;
73
+ }
74
+
75
+ //------------------------------------------------------------------------------------------------------------------
76
+
77
+ const props = withDefaults(defineProps<SkDropdownSubmenuComponentProps>(), {
78
+ kind: undefined,
79
+ });
80
+
81
+ //------------------------------------------------------------------------------------------------------------------
82
+
83
+ // Handle portal context (theme injection/re-provision for nested portal components)
84
+ const { theme } = usePortalContext();
85
+
86
+ // Inject parent dropdown kind (will be a ComputedRef)
87
+ const parentKind = inject<any>('dropdown-kind', computed(() => 'neutral'));
88
+
89
+ //------------------------------------------------------------------------------------------------------------------
90
+
91
+ const effectiveKind = computed(() => props.kind || parentKind.value || 'neutral');
92
+
93
+ //------------------------------------------------------------------------------------------------------------------
94
+
95
+ const triggerClasses = computed(() => ({
96
+ 'sk-dropdown-menu-item': true,
97
+ }));
98
+
99
+ //------------------------------------------------------------------------------------------------------------------
100
+
101
+ const contentClasses = computed(() => ({
102
+ 'sk-dropdown-menu-content': true,
103
+ [`sk-${ effectiveKind.value }`]: true,
104
+ }));
105
+ </script>
106
+
107
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,11 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Dropdown Component Exports
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ export { default as SkDropdown } from './SkDropdown.vue';
6
+ export { default as SkDropdownMenuItem } from './SkDropdownMenuItem.vue';
7
+ export { default as SkDropdownMenuSeparator } from './SkDropdownMenuSeparator.vue';
8
+ export { default as SkDropdownSubmenu } from './SkDropdownSubmenu.vue';
9
+ export type { SkDropdownAlign, SkDropdownKind, SkDropdownSide } from './types';
10
+
11
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,11 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Dropdown Component Types
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ import type { ComponentKind } from '@/types';
6
+
7
+ export type SkDropdownKind = ComponentKind;
8
+ export type SkDropdownSide = 'top' | 'right' | 'bottom' | 'left';
9
+ export type SkDropdownAlign = 'start' | 'center' | 'end';
10
+
11
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,152 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - Field Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <div :class="classes">
7
+ <label v-if="label" :for="fieldId" class="sk-field-label">
8
+ {{ label }}
9
+ <span v-if="required" class="sk-field-required">*</span>
10
+ </label>
11
+
12
+ <div class="sk-field-input-wrapper">
13
+ <slot :id="fieldId" :aria-describedby="ariaDescribedBy" :aria-invalid="ariaInvalid" :kind="effectiveKind" />
14
+ </div>
15
+
16
+ <p v-if="description && !error" :id="descriptionId" class="sk-field-description">
17
+ {{ description }}
18
+ </p>
19
+
20
+ <p v-if="error" :id="errorId" class="sk-field-error">
21
+ {{ error }}
22
+ </p>
23
+ </div>
24
+ </template>
25
+
26
+ <!--------------------------------------------------------------------------------------------------------------------->
27
+
28
+ <style lang="scss" scoped>
29
+ // Component styles are implemented in /src/styles/components/_field.scss
30
+ </style>
31
+
32
+ <!--------------------------------------------------------------------------------------------------------------------->
33
+
34
+ <script setup lang="ts">
35
+ /**
36
+ * @component
37
+ * A form field wrapper that provides label, description, and error message support.
38
+ * Automatically wires up accessibility attributes (id, aria-describedby, aria-invalid).
39
+ */
40
+
41
+ import { computed, provide } from 'vue';
42
+
43
+ // Types
44
+ import type { SkFieldLabelPosition } from './types';
45
+
46
+ //------------------------------------------------------------------------------------------------------------------
47
+
48
+ /**
49
+ * A form field wrapper that provides label, description, and error message support.
50
+ */
51
+ export interface SkFieldComponentProps
52
+ {
53
+ /** Label text for the field */
54
+ label ?: string;
55
+ /** Description/help text */
56
+ description ?: string;
57
+ /** Error message (overrides description when present) */
58
+ error ?: string;
59
+ /** Required field indicator */
60
+ required ?: boolean;
61
+ /** Label position */
62
+ labelPosition ?: SkFieldLabelPosition;
63
+ /** Custom field ID (auto-generated if not provided) */
64
+ id ?: string;
65
+ /** Validation state (true = valid, false = invalid, null/undefined = neutral) */
66
+ state ?: boolean | null;
67
+ /** Kind to use when state is true (valid) */
68
+ validKind ?: string;
69
+ /** Kind to use when state is false (invalid) */
70
+ invalidKind ?: string;
71
+ }
72
+
73
+ //------------------------------------------------------------------------------------------------------------------
74
+
75
+ const props = withDefaults(defineProps<SkFieldComponentProps>(), {
76
+ label: undefined,
77
+ description: undefined,
78
+ error: undefined,
79
+ required: false,
80
+ labelPosition: 'top',
81
+ id: undefined,
82
+ state: null,
83
+ validKind: 'success',
84
+ invalidKind: 'danger',
85
+ });
86
+
87
+ //------------------------------------------------------------------------------------------------------------------
88
+
89
+ // Generate unique ID for field
90
+ const fieldId = computed(() =>
91
+ {
92
+ return props.id || `sk-field-${ Math.random()
93
+ .toString(36)
94
+ .substr(2, 9) }`;
95
+ });
96
+
97
+ const descriptionId = computed(() => `${ fieldId.value }-description`);
98
+ const errorId = computed(() => `${ fieldId.value }-error`);
99
+
100
+ //------------------------------------------------------------------------------------------------------------------
101
+
102
+ const ariaDescribedBy = computed(() =>
103
+ {
104
+ if(props.error)
105
+ {
106
+ return errorId.value;
107
+ }
108
+ else if(props.description)
109
+ {
110
+ return descriptionId.value;
111
+ }
112
+ return undefined;
113
+ });
114
+
115
+ //------------------------------------------------------------------------------------------------------------------
116
+
117
+ const ariaInvalid = computed(() =>
118
+ {
119
+ return props.error ? 'true' : undefined;
120
+ });
121
+
122
+ //------------------------------------------------------------------------------------------------------------------
123
+
124
+ // Determine the kind to apply based on state prop
125
+ const effectiveKind = computed(() =>
126
+ {
127
+ if(props.state === true)
128
+ {
129
+ return props.validKind;
130
+ }
131
+ else if(props.state === false)
132
+ {
133
+ return props.invalidKind;
134
+ }
135
+ return undefined; // Let the input use its own kind prop
136
+ });
137
+
138
+ //------------------------------------------------------------------------------------------------------------------
139
+
140
+ // Provide kind to child inputs so they can automatically pick it up
141
+ provide('field-kind', effectiveKind);
142
+
143
+ //------------------------------------------------------------------------------------------------------------------
144
+
145
+ const classes = computed(() => ({
146
+ 'sk-field': true,
147
+ [`sk-label-${ props.labelPosition }`]: true,
148
+ 'sk-has-error': !!props.error,
149
+ }));
150
+ </script>
151
+
152
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,8 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Field Component Exports
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ export { default as SkField } from './SkField.vue';
6
+ export type { SkFieldLabelPosition } from './types';
7
+
8
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,7 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Field Component Types
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ export type SkFieldLabelPosition = 'top' | 'left';
6
+
7
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,52 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - Group Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <div :class="classes">
7
+ <slot />
8
+ </div>
9
+ </template>
10
+
11
+ <!--------------------------------------------------------------------------------------------------------------------->
12
+
13
+ <script setup lang="ts">
14
+ /**
15
+ * @component
16
+ * A layout container that groups child elements with consistent spacing.
17
+ * Automatically arranges children in horizontal or vertical orientation.
18
+ */
19
+
20
+ import { computed } from 'vue';
21
+ import type { SkGroupOrientation } from './types.ts';
22
+
23
+ //------------------------------------------------------------------------------------------------------------------
24
+
25
+ /**
26
+ * A layout container that groups child elements with consistent spacing.
27
+ * Automatically arranges children in horizontal or vertical orientation.
28
+ */
29
+ export interface SkGroupComponentProps
30
+ {
31
+ /** Orientation for arranging child elements (horizontal or vertical) */
32
+ orientation ?: SkGroupOrientation;
33
+ }
34
+
35
+ //------------------------------------------------------------------------------------------------------------------
36
+
37
+ const props = withDefaults(defineProps<SkGroupComponentProps>(), {
38
+ orientation: 'horizontal',
39
+ });
40
+
41
+ //------------------------------------------------------------------------------------------------------------------
42
+
43
+ const classes = computed(() =>
44
+ {
45
+ return {
46
+ 'sk-group': true,
47
+ [`sk-${ props.orientation }`]: true,
48
+ };
49
+ });
50
+ </script>
51
+
52
+ <!--------------------------------------------------------------------------------------------------------------------->