@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,10 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Group Component Types
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ /**
6
+ * Group orientation options
7
+ */
8
+ export type SkGroupOrientation = 'horizontal' | 'vertical';
9
+
10
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,117 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - Input Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <input
7
+ v-model="modelValue"
8
+ :type="type"
9
+ :class="classes"
10
+ :style="customColorStyles"
11
+ :disabled="disabled"
12
+ :readonly="readonly"
13
+ :placeholder="placeholder"
14
+ :required="required"
15
+ :name="name"
16
+ :autocomplete="autocomplete"
17
+ v-bind="$attrs"
18
+ >
19
+ </template>
20
+
21
+ <!--------------------------------------------------------------------------------------------------------------------->
22
+
23
+ <style lang="scss" scoped>
24
+ // Component styles are implemented in /src/styles/components/_input.scss
25
+ </style>
26
+
27
+ <!--------------------------------------------------------------------------------------------------------------------->
28
+
29
+ <script setup lang="ts">
30
+ /**
31
+ * @component
32
+ * A text input component with validation states and semantic color support.
33
+ * Supports various input types and flexible sizing.
34
+ */
35
+
36
+ import { type ComputedRef, computed, inject, toRef } from 'vue';
37
+
38
+ // Types
39
+ import type { ComponentCustomColors } from '@/types';
40
+ import type { SkInputKind, SkInputSize, SkInputType } from './types';
41
+
42
+ // Composables
43
+ import { useCustomColors } from '@/composables/useCustomColors';
44
+
45
+ //------------------------------------------------------------------------------------------------------------------
46
+
47
+ /**
48
+ * A text input component with validation states and semantic color support.
49
+ */
50
+ export interface SkInputComponentProps extends ComponentCustomColors
51
+ {
52
+ /** Input type */
53
+ type ?: SkInputType;
54
+ /** Semantic color kind (useful for validation states) */
55
+ kind ?: SkInputKind;
56
+ /** Input size */
57
+ size ?: SkInputSize;
58
+ /** Placeholder text */
59
+ placeholder ?: string;
60
+ /** Disabled state */
61
+ disabled ?: boolean;
62
+ /** Read-only state */
63
+ readonly ?: boolean;
64
+ /** Required for form validation */
65
+ required ?: boolean;
66
+ /** Form field name */
67
+ name ?: string;
68
+ /** Autocomplete hint */
69
+ autocomplete ?: string;
70
+ }
71
+
72
+ //------------------------------------------------------------------------------------------------------------------
73
+
74
+ const props = withDefaults(defineProps<SkInputComponentProps>(), {
75
+ type: 'text',
76
+ kind: undefined,
77
+ size: 'md',
78
+ placeholder: undefined,
79
+ disabled: false,
80
+ readonly: false,
81
+ required: false,
82
+ name: undefined,
83
+ autocomplete: undefined,
84
+ });
85
+
86
+ //------------------------------------------------------------------------------------------------------------------
87
+
88
+ const modelValue = defineModel<string | number>({ default: '' });
89
+
90
+ //------------------------------------------------------------------------------------------------------------------
91
+
92
+ // Inject kind from parent SkField if available
93
+ const fieldKind = inject<ComputedRef<SkInputKind | undefined>>('field-kind', computed(() => undefined));
94
+
95
+ //------------------------------------------------------------------------------------------------------------------
96
+
97
+ const effectiveKind = computed(() => fieldKind.value || props.kind || 'neutral');
98
+
99
+ //------------------------------------------------------------------------------------------------------------------
100
+
101
+ const classes = computed(() => ({
102
+ 'sk-input': true,
103
+ [`sk-${ effectiveKind.value }`]: true,
104
+ [`sk-${ props.size }`]: true,
105
+ 'sk-readonly': props.readonly,
106
+ }));
107
+
108
+ //------------------------------------------------------------------------------------------------------------------
109
+
110
+ const customColorStyles = useCustomColors(
111
+ 'input',
112
+ toRef(() => props.baseColor),
113
+ toRef(() => props.textColor)
114
+ );
115
+ </script>
116
+
117
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,8 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Input Component Exports
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ export { default as SkInput } from './SkInput.vue';
6
+ export type { SkInputKind, SkInputSize, SkInputType } from './types';
7
+
8
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,11 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Input Component Types
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ import type { ComponentKind, ComponentSize } from '@/types';
6
+
7
+ export type SkInputKind = ComponentKind;
8
+ export type SkInputSize = ComponentSize;
9
+ export type SkInputType = 'text' | 'email' | 'password' | 'url' | 'tel' | 'search' | 'number';
10
+
11
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,164 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - Listbox Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <ComboboxRoot v-model="modelValue" :disabled="disabled" :class="wrapperClasses" :style="customColorStyles">
7
+ <ComboboxAnchor :class="anchorClasses">
8
+ <ComboboxInput
9
+ :class="inputClasses"
10
+ :placeholder="placeholder"
11
+ />
12
+ <ComboboxTrigger :class="triggerClasses">
13
+ <svg
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ viewBox="0 0 24 24"
16
+ fill="none"
17
+ stroke="currentColor"
18
+ stroke-width="2"
19
+ stroke-linecap="square"
20
+ stroke-linejoin="miter"
21
+ style="width: 1rem; height: 1rem;"
22
+ >
23
+ <polyline points="6 9 12 15 18 9" />
24
+ </svg>
25
+ </ComboboxTrigger>
26
+ </ComboboxAnchor>
27
+
28
+ <ComboboxPortal>
29
+ <ComboboxContent
30
+ :data-scheme="theme"
31
+ :class="contentClasses"
32
+ :style="customColorStyles"
33
+ position="popper"
34
+ side="bottom"
35
+ align="start"
36
+ :side-offset="4"
37
+ >
38
+ <ComboboxViewport>
39
+ <slot />
40
+ </ComboboxViewport>
41
+ </ComboboxContent>
42
+ </ComboboxPortal>
43
+ </ComboboxRoot>
44
+ </template>
45
+
46
+ <!--------------------------------------------------------------------------------------------------------------------->
47
+
48
+ <style lang="scss" scoped>
49
+ // Component styles are in /src/styles/components/_listbox.scss
50
+ </style>
51
+
52
+ <!--------------------------------------------------------------------------------------------------------------------->
53
+
54
+ <script setup lang="ts">
55
+ /**
56
+ * @component
57
+ * A searchable listbox component for selecting from predefined options.
58
+ * Use with SkListboxItem components.
59
+ */
60
+
61
+ import { type ComputedRef, computed, inject, toRef } from 'vue';
62
+ import {
63
+ ComboboxAnchor,
64
+ ComboboxContent,
65
+ ComboboxInput,
66
+ ComboboxPortal,
67
+ ComboboxRoot,
68
+ ComboboxTrigger,
69
+ ComboboxViewport,
70
+ } from 'reka-ui';
71
+
72
+ // Types
73
+ import type { ComponentCustomColors } from '@/types';
74
+ import type { SkListboxKind, SkListboxSize } from './types';
75
+
76
+ // Composables
77
+ import { useCustomColors } from '@/composables/useCustomColors';
78
+ import { usePortalContext } from '@/composables/usePortalContext';
79
+
80
+ //------------------------------------------------------------------------------------------------------------------
81
+
82
+ /**
83
+ * A searchable listbox component for selecting from predefined options.
84
+ */
85
+ export interface SkListboxComponentProps extends ComponentCustomColors
86
+ {
87
+ /** Semantic color kind */
88
+ kind ?: SkListboxKind;
89
+ /** Input size */
90
+ size ?: SkListboxSize;
91
+ /** Placeholder text */
92
+ placeholder ?: string;
93
+ /** Disabled state */
94
+ disabled ?: boolean;
95
+ }
96
+
97
+ //------------------------------------------------------------------------------------------------------------------
98
+
99
+ const props = withDefaults(defineProps<SkListboxComponentProps>(), {
100
+ kind: undefined,
101
+ size: 'md',
102
+ placeholder: 'Search...',
103
+ disabled: false,
104
+ });
105
+
106
+ //------------------------------------------------------------------------------------------------------------------
107
+
108
+ const modelValue = defineModel<string | string[]>();
109
+
110
+ //------------------------------------------------------------------------------------------------------------------
111
+
112
+ // Handle portal context (theme injection/re-provision for nested portal components)
113
+ const { theme } = usePortalContext();
114
+
115
+ // Inject field kind from parent SkField
116
+ const fieldKind = inject<ComputedRef<SkListboxKind | undefined>>('field-kind', computed(() => undefined));
117
+
118
+ //------------------------------------------------------------------------------------------------------------------
119
+
120
+ const effectiveKind = computed(() => fieldKind.value || props.kind || 'neutral');
121
+
122
+ //------------------------------------------------------------------------------------------------------------------
123
+
124
+ const wrapperClasses = computed(() => ({
125
+ 'sk-listbox': true,
126
+ [`sk-${ effectiveKind.value }`]: true,
127
+ [`sk-${ props.size }`]: true,
128
+ }));
129
+
130
+ //------------------------------------------------------------------------------------------------------------------
131
+
132
+ const anchorClasses = computed(() => ({
133
+ 'sk-listbox-anchor': true,
134
+ }));
135
+
136
+ //------------------------------------------------------------------------------------------------------------------
137
+
138
+ const inputClasses = computed(() => ({
139
+ 'sk-listbox-input': true,
140
+ }));
141
+
142
+ //------------------------------------------------------------------------------------------------------------------
143
+
144
+ const triggerClasses = computed(() => ({
145
+ 'sk-listbox-trigger': true,
146
+ }));
147
+
148
+ //------------------------------------------------------------------------------------------------------------------
149
+
150
+ const contentClasses = computed(() => ({
151
+ 'sk-listbox-content': true,
152
+ [`sk-${ effectiveKind.value }`]: true,
153
+ }));
154
+
155
+ //------------------------------------------------------------------------------------------------------------------
156
+
157
+ const customColorStyles = useCustomColors(
158
+ 'listbox',
159
+ toRef(() => props.baseColor),
160
+ toRef(() => props.textColor)
161
+ );
162
+ </script>
163
+
164
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,68 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - ListboxItem Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <ComboboxItem :class="classes" :value="value" :disabled="disabled">
7
+ <slot />
8
+ <ComboboxItemIndicator class="sk-listbox-item-indicator">
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="3"
15
+ stroke-linecap="square"
16
+ stroke-linejoin="miter"
17
+ style="width: 1rem; height: 1rem;"
18
+ >
19
+ <polyline points="20 6 9 17 4 12" />
20
+ </svg>
21
+ </ComboboxItemIndicator>
22
+ </ComboboxItem>
23
+ </template>
24
+
25
+ <!--------------------------------------------------------------------------------------------------------------------->
26
+
27
+ <style lang="scss" scoped>
28
+ // Component styles are in /src/styles/components/_listbox.scss
29
+ </style>
30
+
31
+ <!--------------------------------------------------------------------------------------------------------------------->
32
+
33
+ <script setup lang="ts">
34
+ /**
35
+ * @component
36
+ * A listbox item for use within SkListbox.
37
+ */
38
+
39
+ import { computed } from 'vue';
40
+ import { ComboboxItem, ComboboxItemIndicator } from 'reka-ui';
41
+
42
+ //------------------------------------------------------------------------------------------------------------------
43
+
44
+ /**
45
+ * A listbox item for use within SkListbox.
46
+ */
47
+ export interface SkListboxItemComponentProps
48
+ {
49
+ /** Value for this item */
50
+ value : string | number | object;
51
+ /** Disabled state */
52
+ disabled ?: boolean;
53
+ }
54
+
55
+ //------------------------------------------------------------------------------------------------------------------
56
+
57
+ withDefaults(defineProps<SkListboxItemComponentProps>(), {
58
+ disabled: false,
59
+ });
60
+
61
+ //------------------------------------------------------------------------------------------------------------------
62
+
63
+ const classes = computed(() => ({
64
+ 'sk-listbox-item': true,
65
+ }));
66
+ </script>
67
+
68
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,26 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - ListboxSeparator Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <ComboboxSeparator class="sk-listbox-separator" />
7
+ </template>
8
+
9
+ <!--------------------------------------------------------------------------------------------------------------------->
10
+
11
+ <style lang="scss" scoped>
12
+ // Component styles are in /src/styles/components/_listbox.scss
13
+ </style>
14
+
15
+ <!--------------------------------------------------------------------------------------------------------------------->
16
+
17
+ <script setup lang="ts">
18
+ /**
19
+ * @component
20
+ * A listbox separator for use within SkListbox.
21
+ */
22
+
23
+ import { ComboboxSeparator } from 'reka-ui';
24
+ </script>
25
+
26
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,10 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Listbox Component Exports
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ export { default as SkListbox } from './SkListbox.vue';
6
+ export { default as SkListboxItem } from './SkListboxItem.vue';
7
+ export { default as SkListboxSeparator } from './SkListboxSeparator.vue';
8
+ export type { SkListboxKind, SkListboxSize } from './types';
9
+
10
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,10 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Listbox Component Types
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ import type { ComponentKind, ComponentSize } from '@/types';
6
+
7
+ export type SkListboxKind = ComponentKind;
8
+ export type SkListboxSize = ComponentSize;
9
+
10
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,231 @@
1
+ <template>
2
+ <DialogRoot v-model:open="isOpen">
3
+ <DialogTrigger v-if="$slots.trigger || triggerText" as-child>
4
+ <slot name="trigger">
5
+ <SkButton :kind="kind">
6
+ {{ triggerText }}
7
+ </SkButton>
8
+ </slot>
9
+ </DialogTrigger>
10
+ <DialogPortal>
11
+ <DialogOverlay :class="overlayClasses" :data-scheme="theme" />
12
+ <DialogContent
13
+ :class="contentClasses"
14
+ :style="customColorStyles"
15
+ :data-scheme="theme"
16
+ @escape-key-down="handleEscapeKey"
17
+ @pointer-down-outside="handleOverlayClick"
18
+ @interact-outside="handleOverlayClick"
19
+ >
20
+ <div v-if="$slots.title || title" class="sk-modal-header">
21
+ <DialogTitle class="sk-modal-title">
22
+ <slot name="title" :close="close">
23
+ {{ title }}
24
+ </slot>
25
+ </DialogTitle>
26
+ <DialogClose as-child>
27
+ <SkButton
28
+ :kind="kind"
29
+ :base-color="baseColor"
30
+ :text-color="textColor"
31
+ variant="outline"
32
+ size="sm"
33
+ class="sk-modal-close"
34
+ aria-label="Close"
35
+ >
36
+
37
+ </SkButton>
38
+ </DialogClose>
39
+ </div>
40
+ <div class="sk-modal-body">
41
+ <slot :close="close" />
42
+ </div>
43
+ <div v-if="$slots.footer" class="sk-modal-footer">
44
+ <slot name="footer" :close="close" />
45
+ </div>
46
+ </DialogContent>
47
+ </DialogPortal>
48
+ </DialogRoot>
49
+ </template>
50
+
51
+ <!--------------------------------------------------------------------------------------------------------------------->
52
+
53
+ <style lang="scss" scoped>
54
+ // Modal styles are implemented in /src/styles/components/_modal.scss
55
+ </style>
56
+
57
+ <!--------------------------------------------------------------------------------------------------------------------->
58
+
59
+ <script setup lang="ts">
60
+ /**
61
+ * @component
62
+ * Modal dialog component for displaying content in an overlay
63
+ */
64
+
65
+ import { computed, ref, toRef, watch } from 'vue';
66
+ import {
67
+ DialogClose,
68
+ DialogContent,
69
+ DialogOverlay,
70
+ DialogPortal,
71
+ DialogRoot,
72
+ DialogTitle,
73
+ DialogTrigger,
74
+ } from 'reka-ui';
75
+
76
+ // Types
77
+ import type { ComponentCustomColors, ComponentKind, ComponentSize } from '@/types';
78
+
79
+ // Composables
80
+ import { useCustomColors } from '@/composables/useCustomColors';
81
+ import { usePortalContext } from '@/composables/usePortalContext';
82
+
83
+ // Components
84
+ import SkButton from '../Button/SkButton.vue';
85
+
86
+ //------------------------------------------------------------------------------------------------------------------
87
+
88
+ /**
89
+ * Modal dialog component for displaying content in an overlay
90
+ *
91
+ * @example Basic usage with footer close button
92
+ * ```vue
93
+ * <SkModal title="Confirm Action" trigger-text="Open">
94
+ * <p>Are you sure?</p>
95
+ * <template #footer="{ close }">
96
+ * <SkButton @click="close">Cancel</SkButton>
97
+ * <SkButton kind="primary" @click="doAction(); close()">Confirm</SkButton>
98
+ * </template>
99
+ * </SkModal>
100
+ * ```
101
+ *
102
+ * @example Prevent escape/overlay dismissal
103
+ * ```vue
104
+ * <SkModal
105
+ * title="Important Form"
106
+ * no-close-on-escape
107
+ * no-close-on-overlay
108
+ * >
109
+ * <!-- User must use buttons to close -->
110
+ * </SkModal>
111
+ * ```
112
+ */
113
+ export interface SkModalComponentProps extends ComponentCustomColors
114
+ {
115
+ /** Semantic color kind for the modal */
116
+ kind ?: ComponentKind;
117
+ /** Size of the modal (width) */
118
+ size ?: ComponentSize;
119
+ /** Title text displayed in the header */
120
+ title ?: string;
121
+ /** Text for the default trigger button */
122
+ triggerText ?: string;
123
+ /** Whether the modal is open (v-model:open) */
124
+ open ?: boolean;
125
+ /** Whether pressing Escape closes the modal (default: true) */
126
+ closeOnEscape ?: boolean;
127
+ /** Whether clicking the overlay closes the modal (default: true) */
128
+ closeOnOverlay ?: boolean;
129
+ /** Prevent closing on Escape key (alternative to :close-on-escape="false") */
130
+ noCloseOnEscape ?: boolean;
131
+ /** Prevent closing on overlay click (alternative to :close-on-overlay="false") */
132
+ noCloseOnOverlay ?: boolean;
133
+ }
134
+
135
+ //------------------------------------------------------------------------------------------------------------------
136
+
137
+ const props = withDefaults(defineProps<SkModalComponentProps>(), {
138
+ kind: 'neutral',
139
+ size: 'md',
140
+ title: undefined,
141
+ triggerText: undefined,
142
+ open: false,
143
+ closeOnEscape: true,
144
+ closeOnOverlay: true,
145
+ noCloseOnEscape: false,
146
+ noCloseOnOverlay: false,
147
+ });
148
+
149
+ const emit = defineEmits<{
150
+ 'update:open' : [ value : boolean ];
151
+ }>();
152
+
153
+ //------------------------------------------------------------------------------------------------------------------
154
+
155
+ // Handle portal context (theme injection/re-provision for nested portal components)
156
+ const { theme } = usePortalContext();
157
+
158
+ //------------------------------------------------------------------------------------------------------------------
159
+
160
+ const isOpen = ref(props.open);
161
+
162
+ watch(() => props.open, (newValue) =>
163
+ {
164
+ isOpen.value = newValue;
165
+ });
166
+
167
+ watch(isOpen, (newValue) =>
168
+ {
169
+ emit('update:open', newValue);
170
+ });
171
+
172
+ //------------------------------------------------------------------------------------------------------------------
173
+
174
+ /**
175
+ * Close the modal programmatically.
176
+ * This function is exposed to all slots via slot props.
177
+ */
178
+ function close() : void
179
+ {
180
+ isOpen.value = false;
181
+ }
182
+
183
+ /**
184
+ * Handle escape key press - prevent if closeOnEscape is false or noCloseOnEscape is true
185
+ */
186
+ function handleEscapeKey(event : Event) : void
187
+ {
188
+ if(!props.closeOnEscape || props.noCloseOnEscape)
189
+ {
190
+ event.preventDefault();
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Handle overlay/outside click - prevent if closeOnOverlay is false or noCloseOnOverlay is true
196
+ */
197
+ function handleOverlayClick(event : Event) : void
198
+ {
199
+ if(!props.closeOnOverlay || props.noCloseOnOverlay)
200
+ {
201
+ event.preventDefault();
202
+ }
203
+ }
204
+
205
+ //------------------------------------------------------------------------------------------------------------------
206
+
207
+ const overlayClasses = computed(() => ({
208
+ 'sk-modal-overlay': true,
209
+ }));
210
+
211
+ const contentClasses = computed(() => ({
212
+ 'sk-modal-content': true,
213
+ [`sk-${ props.kind }`]: true,
214
+ [`sk-${ props.size }`]: true,
215
+ }));
216
+
217
+ //------------------------------------------------------------------------------------------------------------------
218
+
219
+ const customColorStyles = useCustomColors(
220
+ 'modal',
221
+ toRef(() => props.baseColor),
222
+ toRef(() => props.textColor)
223
+ );
224
+
225
+ //------------------------------------------------------------------------------------------------------------------
226
+
227
+ // Expose close function for external use via template ref
228
+ defineExpose({ close });
229
+ </script>
230
+
231
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,8 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Modal Component Exports
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ export { default as SkModal } from './SkModal.vue';
6
+ export type { SkModalKind, SkModalSize } from './types';
7
+
8
+ //----------------------------------------------------------------------------------------------------------------------