@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,129 @@
1
+ <!-------------------------------------------------------------------------------------------------------------------
2
+ - Tag Component
3
+ ------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <span :class="classes" :style="customColorStyles">
7
+ <span class="sk-tag-content">
8
+ <slot />
9
+ </span>
10
+ <button
11
+ v-if="removable"
12
+ type="button"
13
+ class="sk-tag-remove"
14
+ aria-label="Remove"
15
+ @click="handleRemove"
16
+ >
17
+ <svg
18
+ xmlns="http://www.w3.org/2000/svg"
19
+ width="24"
20
+ height="24"
21
+ viewBox="0 0 24 24"
22
+ fill="none"
23
+ stroke="currentColor"
24
+ stroke-width="2"
25
+ stroke-linecap="round"
26
+ stroke-linejoin="round"
27
+ >
28
+ <line x1="18" y1="6" x2="6" y2="18" />
29
+ <line x1="6" y1="6" x2="18" y2="18" />
30
+ </svg>
31
+ </button>
32
+ </span>
33
+ </template>
34
+
35
+ <!------------------------------------------------------------------------------------------------------------------->
36
+
37
+ <script setup lang="ts">
38
+ /**
39
+ * @component
40
+ * A compact label component for displaying metadata, categories, or status information.
41
+ * Supports multiple variants, sizes, and optional remove functionality.
42
+ */
43
+
44
+ import { computed, toRef } from 'vue';
45
+ import type { ComponentCustomColors, ComponentKind } from '@/types';
46
+ import type { SkTagSize, SkTagVariant } from './types';
47
+ import { useCustomColors } from '@/composables/useCustomColors';
48
+
49
+ //------------------------------------------------------------------------------------------------------------------
50
+
51
+ /**
52
+ * A compact label component for displaying metadata, categories, or status information.
53
+ * Supports multiple variants, sizes, and optional remove functionality.
54
+ *
55
+ * @example Basic tags
56
+ * ```vue
57
+ * <SkTag kind="primary">Featured</SkTag>
58
+ * <SkTag kind="success" removable @remove="handleRemove">Active</SkTag>
59
+ * ```
60
+ *
61
+ * @example Custom colored tag
62
+ * ```vue
63
+ * <SkTag
64
+ * base-color="oklch(0.75 0.2 150)"
65
+ * text-color="white"
66
+ * variant="solid"
67
+ * >
68
+ * Custom Green Tag
69
+ * </SkTag>
70
+ * ```
71
+ */
72
+ export interface SkTagComponentProps extends ComponentCustomColors
73
+ {
74
+ /** Semantic color kind for the tag */
75
+ kind ?: ComponentKind;
76
+ /** Visual variant style (solid, outline, subtle, or ghost) */
77
+ variant ?: SkTagVariant;
78
+ /** Size of the tag affecting padding and font size */
79
+ size ?: SkTagSize;
80
+ /** Whether to show a remove button that emits a 'remove' event when clicked */
81
+ removable ?: boolean;
82
+ }
83
+
84
+ //------------------------------------------------------------------------------------------------------------------
85
+
86
+ const props = withDefaults(defineProps<SkTagComponentProps>(), {
87
+ kind: 'neutral',
88
+ variant: 'solid',
89
+ size: 'md',
90
+ removable: false,
91
+ });
92
+
93
+ //------------------------------------------------------------------------------------------------------------------
94
+
95
+ const emit = defineEmits<{
96
+ remove : [];
97
+ }>();
98
+
99
+ //------------------------------------------------------------------------------------------------------------------
100
+
101
+ const classes = computed(() =>
102
+ {
103
+ return {
104
+ 'sk-tag': true,
105
+ [`sk-${ props.kind }`]: true,
106
+ [`sk-${ props.variant }`]: true,
107
+ [`sk-${ props.size }`]: true,
108
+ 'sk-removable': props.removable,
109
+ };
110
+ });
111
+
112
+ //------------------------------------------------------------------------------------------------------------------
113
+
114
+ function handleRemove() : void
115
+ {
116
+ emit('remove');
117
+ }
118
+
119
+ //------------------------------------------------------------------------------------------------------------------
120
+
121
+ // Custom color styles
122
+ const customColorStyles = useCustomColors(
123
+ 'tag',
124
+ toRef(() => props.baseColor),
125
+ toRef(() => props.textColor)
126
+ );
127
+ </script>
128
+
129
+ <!------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,15 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Tag Component Types
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ /**
6
+ * Tag variant options
7
+ */
8
+ export type SkTagVariant = 'solid' | 'outline' | 'subtle' | 'ghost';
9
+
10
+ /**
11
+ * Tag size options
12
+ */
13
+ export type SkTagSize = 'sm' | 'md' | 'lg' | 'xl';
14
+
15
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,184 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - TagsInput Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <TagsInputRoot
7
+ v-model="modelValue"
8
+ :class="wrapperClasses"
9
+ :style="customColorStyles"
10
+ :disabled="disabled"
11
+ :max="max"
12
+ :add-on-paste="addOnPaste"
13
+ >
14
+ <div :class="containerClasses">
15
+ <TagsInputItem v-for="tag in modelValue" :key="tag" :value="tag" :class="tagClasses" class="sk-tag">
16
+ <TagsInputItemText />
17
+ <TagsInputItemDelete :class="deleteClasses">
18
+ <svg
19
+ xmlns="http://www.w3.org/2000/svg"
20
+ viewBox="0 0 24 24"
21
+ fill="none"
22
+ stroke="currentColor"
23
+ stroke-width="2"
24
+ stroke-linecap="square"
25
+ stroke-linejoin="miter"
26
+ style="width: 0.875rem; height: 0.875rem;"
27
+ >
28
+ <line x1="18" y1="6" x2="6" y2="18" />
29
+ <line x1="6" y1="6" x2="18" y2="18" />
30
+ </svg>
31
+ </TagsInputItemDelete>
32
+ </TagsInputItem>
33
+
34
+ <TagsInputInput :class="inputClasses" :placeholder="placeholder" :disabled="isInputDisabled" />
35
+ </div>
36
+ </TagsInputRoot>
37
+ </template>
38
+
39
+ <!--------------------------------------------------------------------------------------------------------------------->
40
+
41
+ <style lang="scss" scoped>
42
+ // Component styles are in /src/styles/components/_tags-input.scss
43
+ </style>
44
+
45
+ <!--------------------------------------------------------------------------------------------------------------------->
46
+
47
+ <script setup lang="ts">
48
+ /**
49
+ * @component
50
+ * A multi-value tag input component powered by RekaUI.
51
+ * Add tags by typing and pressing Enter, remove with backspace or delete button.
52
+ */
53
+
54
+ import { type ComputedRef, computed, inject, toRef } from 'vue';
55
+ import {
56
+ TagsInputInput,
57
+ TagsInputItem,
58
+ TagsInputItemDelete,
59
+ TagsInputItemText,
60
+ TagsInputRoot,
61
+ } from 'reka-ui';
62
+
63
+ // Types
64
+ import type { ComponentCustomColors } from '@/types';
65
+ import type { SkTagsInputKind, SkTagsInputSize } from './types';
66
+
67
+ // Composables
68
+ import { useCustomColors } from '@/composables/useCustomColors';
69
+
70
+ //------------------------------------------------------------------------------------------------------------------
71
+
72
+ /**
73
+ * A multi-value tag input component powered by RekaUI.
74
+ */
75
+ export interface SkTagsInputComponentProps extends ComponentCustomColors
76
+ {
77
+ /** Semantic color kind for input */
78
+ kind ?: SkTagsInputKind;
79
+ /** Input size */
80
+ size ?: SkTagsInputSize;
81
+ /** Placeholder text */
82
+ placeholder ?: string;
83
+ /** Disabled state */
84
+ disabled ?: boolean;
85
+ /** Maximum number of tags */
86
+ max ?: number;
87
+ /** Add tags on paste */
88
+ addOnPaste ?: boolean;
89
+ /** Kind for tag badges (inherits from input kind if not set) */
90
+ tagKind ?: string;
91
+ /** Variant for tag badges */
92
+ tagVariant ?: 'solid' | 'outline' | 'ghost';
93
+ }
94
+
95
+ //------------------------------------------------------------------------------------------------------------------
96
+
97
+ const props = withDefaults(defineProps<SkTagsInputComponentProps>(), {
98
+ kind: undefined,
99
+ size: 'md',
100
+ placeholder: 'Add tag...',
101
+ disabled: false,
102
+ max: undefined,
103
+ addOnPaste: true,
104
+ tagKind: undefined,
105
+ tagVariant: 'solid',
106
+ });
107
+
108
+ //------------------------------------------------------------------------------------------------------------------
109
+
110
+ const modelValue = defineModel<string[]>({ default: () => [] });
111
+
112
+ //------------------------------------------------------------------------------------------------------------------
113
+
114
+ // Inject field kind
115
+ const fieldKind = inject<ComputedRef<SkTagsInputKind | undefined>>('field-kind', computed(() => undefined));
116
+
117
+ //------------------------------------------------------------------------------------------------------------------
118
+
119
+ const effectiveKind = computed(() => fieldKind.value || props.kind || 'neutral');
120
+
121
+ //------------------------------------------------------------------------------------------------------------------
122
+
123
+ const effectiveTagKind = computed(() => props.tagKind || effectiveKind.value);
124
+
125
+ //------------------------------------------------------------------------------------------------------------------
126
+
127
+ // Disable just the input field when max tags reached (still allow removing tags)
128
+ const isInputDisabled = computed(() =>
129
+ {
130
+ if(props.disabled)
131
+ {
132
+ return true;
133
+ }
134
+ if(props.max && modelValue.value.length >= props.max)
135
+ {
136
+ return true;
137
+ }
138
+ return false;
139
+ });
140
+
141
+ //------------------------------------------------------------------------------------------------------------------
142
+
143
+ const wrapperClasses = computed(() => ({
144
+ 'sk-tags-input': true,
145
+ [`sk-${ effectiveKind.value }`]: true,
146
+ [`sk-${ props.size }`]: true,
147
+ }));
148
+
149
+ //------------------------------------------------------------------------------------------------------------------
150
+
151
+ const containerClasses = computed(() => ({
152
+ 'sk-tags-input-container': true,
153
+ }));
154
+
155
+ //------------------------------------------------------------------------------------------------------------------
156
+
157
+ const tagClasses = computed(() => ({
158
+ [`sk-${ effectiveTagKind.value }`]: true,
159
+ [`sk-${ props.tagVariant }`]: true,
160
+ [`sk-${ props.size }`]: true,
161
+ }));
162
+
163
+ //------------------------------------------------------------------------------------------------------------------
164
+
165
+ const deleteClasses = computed(() => ({
166
+ 'sk-tags-input-delete': true,
167
+ }));
168
+
169
+ //------------------------------------------------------------------------------------------------------------------
170
+
171
+ const inputClasses = computed(() => ({
172
+ 'sk-tags-input-field': true,
173
+ }));
174
+
175
+ //------------------------------------------------------------------------------------------------------------------
176
+
177
+ const customColorStyles = useCustomColors(
178
+ 'tags-input',
179
+ toRef(() => props.baseColor),
180
+ toRef(() => props.textColor)
181
+ );
182
+ </script>
183
+
184
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,8 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // TagsInput Component Exports
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ export { default as SkTagsInput } from './SkTagsInput.vue';
6
+ export type { SkTagsInputKind, SkTagsInputSize } from './types';
7
+
8
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,10 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // TagsInput Component Types
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ import type { ComponentKind, ComponentSize } from '@/types';
6
+
7
+ export type SkTagsInputKind = ComponentKind;
8
+ export type SkTagsInputSize = ComponentSize;
9
+
10
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,117 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - Textarea Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <textarea
7
+ v-model="modelValue"
8
+ :class="classes"
9
+ :style="customColorStyles"
10
+ :disabled="disabled"
11
+ :readonly="readonly"
12
+ :placeholder="placeholder"
13
+ :required="required"
14
+ :name="name"
15
+ :rows="rows"
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/_textarea.scss
25
+ </style>
26
+
27
+ <!--------------------------------------------------------------------------------------------------------------------->
28
+
29
+ <script setup lang="ts">
30
+ /**
31
+ * @component
32
+ * A multiline textarea component with validation states and semantic color support.
33
+ * Supports flexible sizing and row configuration.
34
+ */
35
+
36
+ import { type ComputedRef, computed, inject, toRef } from 'vue';
37
+
38
+ // Types
39
+ import type { ComponentCustomColors } from '@/types';
40
+ import type { SkTextareaKind, SkTextareaSize } from './types';
41
+
42
+ // Composables
43
+ import { useCustomColors } from '@/composables/useCustomColors';
44
+
45
+ //------------------------------------------------------------------------------------------------------------------
46
+
47
+ /**
48
+ * A multiline textarea component with validation states and semantic color support.
49
+ */
50
+ export interface SkTextareaComponentProps extends ComponentCustomColors
51
+ {
52
+ /** Semantic color kind (useful for validation states) */
53
+ kind ?: SkTextareaKind;
54
+ /** Textarea size */
55
+ size ?: SkTextareaSize;
56
+ /** Placeholder text */
57
+ placeholder ?: string;
58
+ /** Disabled state */
59
+ disabled ?: boolean;
60
+ /** Read-only state */
61
+ readonly ?: boolean;
62
+ /** Required for form validation */
63
+ required ?: boolean;
64
+ /** Form field name */
65
+ name ?: string;
66
+ /** Number of visible text rows */
67
+ rows ?: number;
68
+ /** Autocomplete hint */
69
+ autocomplete ?: string;
70
+ }
71
+
72
+ //------------------------------------------------------------------------------------------------------------------
73
+
74
+ const props = withDefaults(defineProps<SkTextareaComponentProps>(), {
75
+ kind: undefined,
76
+ size: 'md',
77
+ placeholder: undefined,
78
+ disabled: false,
79
+ readonly: false,
80
+ required: false,
81
+ name: undefined,
82
+ rows: 4,
83
+ autocomplete: undefined,
84
+ });
85
+
86
+ //------------------------------------------------------------------------------------------------------------------
87
+
88
+ const modelValue = defineModel<string>({ default: '' });
89
+
90
+ //------------------------------------------------------------------------------------------------------------------
91
+
92
+ // Inject kind from parent SkField if available
93
+ const fieldKind = inject<ComputedRef<SkTextareaKind | 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-textarea': 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
+ 'textarea',
112
+ toRef(() => props.baseColor),
113
+ toRef(() => props.textColor)
114
+ );
115
+ </script>
116
+
117
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,8 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Textarea Component Exports
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ export { default as SkTextarea } from './SkTextarea.vue';
6
+ export type { SkTextareaKind, SkTextareaSize } from './types';
7
+
8
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,10 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Textarea Component Types
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ import type { ComponentKind, ComponentSize } from '@/types';
6
+
7
+ export type SkTextareaKind = ComponentKind;
8
+ export type SkTextareaSize = ComponentSize;
9
+
10
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,47 @@
1
+ <!----------------------------------------------------------------------------------------------------------------------
2
+ - Theme Component
3
+ --------------------------------------------------------------------------------------------------------------------->
4
+
5
+ <template>
6
+ <div :data-scheme="currentTheme">
7
+ <slot />
8
+ </div>
9
+ </template>
10
+
11
+ <!--------------------------------------------------------------------------------------------------------------------->
12
+
13
+ <script setup lang="ts">
14
+ /**
15
+ * @component
16
+ * A theme provider component that controls the color scheme for all child components.
17
+ * Wrap your application or sections in this component to apply a theme.
18
+ */
19
+
20
+ import { provide, watch } from 'vue';
21
+ import type { SkThemeComponentProps } from './types';
22
+ import { provideTheme } from './useTheme';
23
+
24
+ //------------------------------------------------------------------------------------------------------------------
25
+
26
+ const props = withDefaults(defineProps<SkThemeComponentProps>(), {
27
+ theme: 'greyscale',
28
+ });
29
+
30
+ //------------------------------------------------------------------------------------------------------------------
31
+
32
+ const { currentTheme, setTheme } = provideTheme(props.theme);
33
+
34
+ // Provide theme for components that use portals (dropdown, modal, tooltip, etc.)
35
+ provide('sk-theme', currentTheme);
36
+
37
+ // Watch for external theme prop changes
38
+ watch(() => props.theme, (newTheme) =>
39
+ {
40
+ if(newTheme)
41
+ {
42
+ setTheme(newTheme);
43
+ }
44
+ });
45
+ </script>
46
+
47
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,17 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Theme Component Types
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ export type SkThemeName = 'greyscale' | 'colorful';
6
+
7
+ /**
8
+ * A theme provider component that controls the color scheme for all child components.
9
+ * Wrap your application or sections in this component to apply a theme.
10
+ */
11
+ export interface SkThemeComponentProps
12
+ {
13
+ /** Theme name controlling the overall color scheme (greyscale or colorful) */
14
+ theme ?: SkThemeName;
15
+ }
16
+
17
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,131 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Theme Composable
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ import { type InjectionKey, type Ref, inject, provide, ref } from 'vue';
6
+ import type { SkThemeName } from './types';
7
+
8
+ //----------------------------------------------------------------------------------------------------------------------
9
+
10
+ /**
11
+ * Context object for theme management.
12
+ * Provides reactive theme state and methods to change the theme.
13
+ */
14
+ export interface ThemeContext
15
+ {
16
+ /** Reactive reference to the currently active theme */
17
+ currentTheme : Ref<SkThemeName>;
18
+ /** Function to change the active theme */
19
+ setTheme : (theme : SkThemeName) => void;
20
+ }
21
+
22
+ //----------------------------------------------------------------------------------------------------------------------
23
+
24
+ const ThemeSymbol : InjectionKey<ThemeContext> = Symbol('SkTheme');
25
+
26
+ //----------------------------------------------------------------------------------------------------------------------
27
+
28
+ /**
29
+ * Provides theme context to child components.
30
+ * Call this function at the root of your component tree (typically in SkTheme component).
31
+ *
32
+ * @param initialTheme - The initial theme to use. Defaults to 'greyscale'
33
+ * @returns ThemeContext object containing currentTheme ref and setTheme function
34
+ *
35
+ * @example Basic usage
36
+ * ```ts
37
+ * const theme = provideTheme('blue');
38
+ * ```
39
+ *
40
+ * @example Changing theme
41
+ * ```ts
42
+ * const theme = provideTheme();
43
+ * theme.setTheme('blue'); // Switch to blue theme
44
+ * ```
45
+ */
46
+ export function provideTheme(initialTheme : SkThemeName = 'greyscale') : ThemeContext
47
+ {
48
+ const currentTheme = ref<SkThemeName>(initialTheme);
49
+
50
+ const setTheme = (theme : SkThemeName) : void =>
51
+ {
52
+ currentTheme.value = theme;
53
+ };
54
+
55
+ const context : ThemeContext = {
56
+ currentTheme,
57
+ setTheme,
58
+ };
59
+
60
+ provide(ThemeSymbol, context);
61
+
62
+ return context;
63
+ }
64
+
65
+ //----------------------------------------------------------------------------------------------------------------------
66
+
67
+ /**
68
+ * Accesses the theme context in a child component.
69
+ * Must be called within a component that has an SkTheme ancestor.
70
+ *
71
+ * @returns ThemeContext object containing currentTheme ref and setTheme function
72
+ * @throws Error if called outside of an SkTheme component tree
73
+ *
74
+ * @example Get current theme
75
+ * ```vue
76
+ * <script setup>
77
+ * import { useTheme } from '@skewedaspect/sleekspace-ui';
78
+ *
79
+ * const { currentTheme } = useTheme();
80
+ * console.log(currentTheme.value); // 'greyscale', 'blue', etc.
81
+ * </script>
82
+ * ```
83
+ *
84
+ * @example Change theme
85
+ * ```vue
86
+ * <script setup>
87
+ * import { useTheme } from '@skewedaspect/sleekspace-ui';
88
+ *
89
+ * const { setTheme } = useTheme();
90
+ *
91
+ * function switchToDarkTheme() {
92
+ * setTheme('blue');
93
+ * }
94
+ * </script>
95
+ *
96
+ * <template>
97
+ * <button @click="switchToDarkTheme">Switch to Blue Theme</button>
98
+ * </template>
99
+ * ```
100
+ *
101
+ * @example Reactive theme usage
102
+ * ```vue
103
+ * <script setup>
104
+ * import { computed } from 'vue';
105
+ * import { useTheme } from '@skewedaspect/sleekspace-ui';
106
+ *
107
+ * const { currentTheme } = useTheme();
108
+ * const isDarkTheme = computed(() => currentTheme.value === 'blue');
109
+ * </script>
110
+ *
111
+ * <template>
112
+ * <div>
113
+ * Current theme: {{ currentTheme }}
114
+ * <span v-if="isDarkTheme">Dark mode active</span>
115
+ * </div>
116
+ * </template>
117
+ * ```
118
+ */
119
+ export function useTheme() : ThemeContext
120
+ {
121
+ const context = inject(ThemeSymbol);
122
+
123
+ if(!context)
124
+ {
125
+ throw new Error('useTheme must be called within an SkTheme component');
126
+ }
127
+
128
+ return context;
129
+ }
130
+
131
+ //----------------------------------------------------------------------------------------------------------------------