@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,156 @@
1
+ <template>
2
+ <ToastRoot
3
+ :class="classes"
4
+ :duration="duration"
5
+ @update:open="onOpenChange"
6
+ >
7
+ <!-- Icon -->
8
+ <div class="sk-toast-icon">
9
+ <svg
10
+ v-if="kind === 'info'"
11
+ viewBox="0 0 24 24"
12
+ fill="none"
13
+ stroke="currentColor"
14
+ stroke-width="2"
15
+ >
16
+ <circle cx="12" cy="12" r="10" />
17
+ <line x1="12" y1="16" x2="12" y2="12" />
18
+ <circle cx="12" cy="8" r="0.5" fill="currentColor" />
19
+ </svg>
20
+ <svg
21
+ v-else-if="kind === 'success'"
22
+ viewBox="0 0 24 24"
23
+ fill="none"
24
+ stroke="currentColor"
25
+ stroke-width="2"
26
+ >
27
+ <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
28
+ <polyline points="22 4 12 14.01 9 11.01" />
29
+ </svg>
30
+ <svg
31
+ v-else-if="kind === 'warning'"
32
+ viewBox="0 0 24 24"
33
+ fill="none"
34
+ stroke="currentColor"
35
+ stroke-width="2"
36
+ >
37
+ <path
38
+ d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"
39
+ />
40
+ <line x1="12" y1="9" x2="12" y2="13" />
41
+ <circle cx="12" cy="17" r="0.5" fill="currentColor" />
42
+ </svg>
43
+ <svg
44
+ v-else-if="kind === 'danger'"
45
+ viewBox="0 0 24 24"
46
+ fill="none"
47
+ stroke="currentColor"
48
+ stroke-width="2"
49
+ >
50
+ <circle cx="12" cy="12" r="10" />
51
+ <line x1="15" y1="9" x2="9" y2="15" />
52
+ <line x1="9" y1="9" x2="15" y2="15" />
53
+ </svg>
54
+ </div>
55
+
56
+ <!-- Content -->
57
+ <div class="sk-toast-content">
58
+ <ToastTitle v-if="title" class="sk-toast-title">
59
+ {{ title }}
60
+ </ToastTitle>
61
+ <ToastDescription class="sk-toast-description">
62
+ {{ message }}
63
+ </ToastDescription>
64
+ </div>
65
+
66
+ <!-- Close button -->
67
+ <ToastClose v-if="closable" class="sk-toast-close" aria-label="Close">
68
+ <svg
69
+ xmlns="http://www.w3.org/2000/svg"
70
+ width="16"
71
+ height="16"
72
+ viewBox="0 0 24 24"
73
+ fill="none"
74
+ stroke="currentColor"
75
+ stroke-width="2"
76
+ stroke-linecap="round"
77
+ stroke-linejoin="round"
78
+ >
79
+ <line x1="18" y1="6" x2="6" y2="18" />
80
+ <line x1="6" y1="6" x2="18" y2="18" />
81
+ </svg>
82
+ </ToastClose>
83
+ </ToastRoot>
84
+ </template>
85
+
86
+ <!--------------------------------------------------------------------------------------------------------------------->
87
+
88
+ <style lang="scss" scoped>
89
+ // Toast styles are implemented in /src/styles/components/_toast.scss
90
+ </style>
91
+
92
+ <!--------------------------------------------------------------------------------------------------------------------->
93
+
94
+ <script setup lang="ts">
95
+ /**
96
+ * @component
97
+ * Internal toast component used by SkToastProvider.
98
+ * Not exported directly - use useToast() to create toasts.
99
+ */
100
+
101
+ import { computed } from 'vue';
102
+ import {
103
+ ToastClose,
104
+ ToastDescription,
105
+ ToastRoot,
106
+ ToastTitle,
107
+ } from 'reka-ui';
108
+
109
+ // Types
110
+ import type { SkToastKind } from './types';
111
+
112
+ //------------------------------------------------------------------------------------------------------------------
113
+
114
+ interface SkToastProps
115
+ {
116
+ /** Toast ID for tracking */
117
+ id : string;
118
+ /** Semantic kind */
119
+ kind : SkToastKind;
120
+ /** Optional title */
121
+ title ?: string;
122
+ /** Toast message */
123
+ message : string;
124
+ /** Duration in ms (0 = no auto-dismiss) */
125
+ duration ?: number;
126
+ /** Whether to show close button */
127
+ closable : boolean;
128
+ }
129
+
130
+ //------------------------------------------------------------------------------------------------------------------
131
+
132
+ const props = defineProps<SkToastProps>();
133
+
134
+ const emit = defineEmits<{
135
+ dismiss : [ id : string ];
136
+ }>();
137
+
138
+ //------------------------------------------------------------------------------------------------------------------
139
+
140
+ const classes = computed(() => ({
141
+ 'sk-toast': true,
142
+ [`sk-${ props.kind }`]: true,
143
+ }));
144
+
145
+ //------------------------------------------------------------------------------------------------------------------
146
+
147
+ function onOpenChange(open : boolean) : void
148
+ {
149
+ if(!open)
150
+ {
151
+ emit('dismiss', props.id);
152
+ }
153
+ }
154
+ </script>
155
+
156
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,180 @@
1
+ <template>
2
+ <ToastProvider
3
+ :duration="duration"
4
+ :swipe-direction="swipeDirection"
5
+ :swipe-threshold="swipeThreshold"
6
+ >
7
+ <slot />
8
+ <ToastViewport
9
+ :class="viewportClasses"
10
+ :data-scheme="theme"
11
+ :hotkey="hotkey"
12
+ >
13
+ <SkToast
14
+ v-for="toast in toasts"
15
+ :id="toast.id"
16
+ :key="toast.id"
17
+ :kind="toast.kind"
18
+ :title="toast.title"
19
+ :message="toast.message"
20
+ :duration="toast.duration"
21
+ :closable="toast.closable"
22
+ @dismiss="dismissToast"
23
+ />
24
+ </ToastViewport>
25
+ </ToastProvider>
26
+ </template>
27
+
28
+ <!--------------------------------------------------------------------------------------------------------------------->
29
+
30
+ <style lang="scss" scoped>
31
+ // Toast viewport styles are implemented in /src/styles/components/_toast.scss
32
+ </style>
33
+
34
+ <!--------------------------------------------------------------------------------------------------------------------->
35
+
36
+ <script setup lang="ts">
37
+ /**
38
+ * @component
39
+ * Toast provider and viewport combined.
40
+ *
41
+ * Wrap your app (or a section) with this component to enable toasts.
42
+ * Use the useToast() composable to show toasts from anywhere in the tree.
43
+ */
44
+
45
+ import { computed, provide, ref } from 'vue';
46
+ import { ToastProvider, ToastViewport } from 'reka-ui';
47
+
48
+ // Types
49
+ import type { SkToastPosition, SkToastSwipeDirection, ToastAPI, ToastOptions, ToastState } from './types';
50
+
51
+ // Components
52
+ import SkToast from './SkToast.vue';
53
+
54
+ // Composables
55
+ import { usePortalContext } from '@/composables/usePortalContext';
56
+ import { TOAST_INJECTION_KEY } from './useToast';
57
+
58
+ //------------------------------------------------------------------------------------------------------------------
59
+
60
+ /**
61
+ * Toast provider that manages and displays toast notifications.
62
+ *
63
+ * Wrap your app with this component to enable toasts. Use useToast() composable
64
+ * to show notifications from anywhere in the tree.
65
+ *
66
+ * @see useToast - Composable for showing toasts
67
+ */
68
+ export interface SkToastProviderComponentProps
69
+ {
70
+ /**
71
+ * Preset position for the viewport. If omitted, position via CSS/classes.
72
+ */
73
+ position ?: SkToastPosition;
74
+
75
+ /**
76
+ * Default duration (ms) before auto-dismiss.
77
+ * @default 5000
78
+ */
79
+ duration ?: number;
80
+
81
+ /**
82
+ * Direction to swipe to dismiss.
83
+ * @default 'right'
84
+ */
85
+ swipeDirection ?: SkToastSwipeDirection;
86
+
87
+ /**
88
+ * Distance (px) to swipe before dismissing.
89
+ * @default 50
90
+ */
91
+ swipeThreshold ?: number;
92
+
93
+ /**
94
+ * Keyboard shortcut to focus toasts.
95
+ * @default ['F8']
96
+ */
97
+ hotkey ?: string[];
98
+ }
99
+
100
+ //------------------------------------------------------------------------------------------------------------------
101
+
102
+ const props = withDefaults(defineProps<SkToastProviderComponentProps>(), {
103
+ position: undefined,
104
+ duration: 5000,
105
+ swipeDirection: 'right',
106
+ swipeThreshold: 50,
107
+ hotkey: () => [ 'F8' ],
108
+ });
109
+
110
+ //------------------------------------------------------------------------------------------------------------------
111
+
112
+ // Handle portal context (theme injection/re-provision for nested portal components)
113
+ const { theme } = usePortalContext();
114
+
115
+ //------------------------------------------------------------------------------------------------------------------
116
+ // Toast State Management
117
+ //------------------------------------------------------------------------------------------------------------------
118
+
119
+ const toasts = ref<ToastState[]>([]);
120
+ let toastCounter = 0;
121
+
122
+ function generateId() : string
123
+ {
124
+ return `toast-${ ++toastCounter }-${ Date.now() }`;
125
+ }
126
+
127
+ function addToast(options : ToastOptions) : string
128
+ {
129
+ const id = options.id ?? generateId();
130
+
131
+ const toast : ToastState = {
132
+ id,
133
+ kind: options.kind ?? 'info',
134
+ title: options.title ?? '',
135
+ message: options.message,
136
+ duration: options.duration,
137
+ closable: options.closable ?? true,
138
+ };
139
+
140
+ toasts.value.push(toast);
141
+ return id;
142
+ }
143
+
144
+ function dismissToast(id : string) : void
145
+ {
146
+ const index = toasts.value.findIndex((item) => item.id === id);
147
+ if(index !== -1)
148
+ {
149
+ toasts.value.splice(index, 1);
150
+ }
151
+ }
152
+
153
+ function dismissAllToasts() : void
154
+ {
155
+ toasts.value = [];
156
+ }
157
+
158
+ //------------------------------------------------------------------------------------------------------------------
159
+ // Provide Toast API
160
+ //------------------------------------------------------------------------------------------------------------------
161
+
162
+ const toastAPI : ToastAPI = {
163
+ add: addToast,
164
+ dismiss: dismissToast,
165
+ dismissAll: dismissAllToasts,
166
+ };
167
+
168
+ provide(TOAST_INJECTION_KEY, toastAPI);
169
+
170
+ //------------------------------------------------------------------------------------------------------------------
171
+ // Viewport Classes
172
+ //------------------------------------------------------------------------------------------------------------------
173
+
174
+ const viewportClasses = computed(() => ({
175
+ 'sk-toast-viewport': true,
176
+ [`sk-${ props.position }`]: props.position !== undefined,
177
+ }));
178
+ </script>
179
+
180
+ <!--------------------------------------------------------------------------------------------------------------------->
@@ -0,0 +1,15 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Toast Component Exports
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ export { default as SkToastProvider } from './SkToastProvider.vue';
6
+ export { useToast } from './useToast';
7
+ export type {
8
+ SkToastKind,
9
+ SkToastPosition,
10
+ SkToastSwipeDirection,
11
+ ToastAPI,
12
+ ToastOptions,
13
+ } from './types';
14
+
15
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,63 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Toast Types
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ /** Toast semantic kinds (subset of ComponentKind for notifications) */
6
+ export type SkToastKind = 'info' | 'success' | 'warning' | 'danger';
7
+
8
+ /** Toast viewport position presets */
9
+ export type SkToastPosition
10
+ = 'top-left'
11
+ | 'top-center'
12
+ | 'top-right'
13
+ | 'bottom-left'
14
+ | 'bottom-center'
15
+ | 'bottom-right';
16
+
17
+ /** Swipe direction for dismissing toasts */
18
+ export type SkToastSwipeDirection = 'right' | 'left' | 'up' | 'down';
19
+
20
+ //----------------------------------------------------------------------------------------------------------------------
21
+ // Toast Options (for useToast composable)
22
+ //----------------------------------------------------------------------------------------------------------------------
23
+
24
+ /** Options for creating a toast */
25
+ export interface ToastOptions
26
+ {
27
+ /** Unique ID for the toast. Auto-generated if not provided */
28
+ id ?: string;
29
+ /** Semantic kind (default: 'info') */
30
+ kind ?: SkToastKind;
31
+ /** Optional heading text */
32
+ title ?: string;
33
+ /** Toast message content (required) */
34
+ message : string;
35
+ /** Duration in ms before auto-dismiss. Use 0 for no auto-dismiss */
36
+ duration ?: number;
37
+ /** Whether to show close button (default: true) */
38
+ closable ?: boolean;
39
+ }
40
+
41
+ /** Internal toast state */
42
+ export interface ToastState extends Required<Omit<ToastOptions, 'duration'>>
43
+ {
44
+ /** Duration can be undefined to use provider default */
45
+ duration ?: number;
46
+ }
47
+
48
+ //----------------------------------------------------------------------------------------------------------------------
49
+ // Toast API (returned by useToast)
50
+ //----------------------------------------------------------------------------------------------------------------------
51
+
52
+ /** Toast management API */
53
+ export interface ToastAPI
54
+ {
55
+ /** Add a new toast and return its ID */
56
+ add : (options : ToastOptions) => string;
57
+ /** Dismiss a specific toast by ID */
58
+ dismiss : (id : string) => void;
59
+ /** Dismiss all active toasts */
60
+ dismissAll : () => void;
61
+ }
62
+
63
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,78 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Toast Composable
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ import { inject } from 'vue';
6
+
7
+ // Types
8
+ import type { ToastAPI, ToastOptions } from './types';
9
+
10
+ //----------------------------------------------------------------------------------------------------------------------
11
+ // Injection Key
12
+ //----------------------------------------------------------------------------------------------------------------------
13
+
14
+ export const TOAST_INJECTION_KEY = Symbol.for('sk-toast-provider');
15
+
16
+ //----------------------------------------------------------------------------------------------------------------------
17
+ // useToast Composable
18
+ //----------------------------------------------------------------------------------------------------------------------
19
+
20
+ /**
21
+ * Get the toast API for showing notifications.
22
+ *
23
+ * Must be used within a component tree that contains SkToastProvider.
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * import { useToast } from '@skewedaspect/sleekspace-ui';
28
+ *
29
+ * const toast = useToast();
30
+ *
31
+ * // Show a success toast
32
+ * toast.add({
33
+ * kind: 'success',
34
+ * title: 'Saved!',
35
+ * message: 'Your changes have been saved.'
36
+ * });
37
+ *
38
+ * // Show an error toast that doesn't auto-dismiss
39
+ * toast.add({
40
+ * kind: 'danger',
41
+ * title: 'Error',
42
+ * message: 'Something went wrong.',
43
+ * duration: 0
44
+ * });
45
+ *
46
+ * // Dismiss all toasts
47
+ * toast.dismissAll();
48
+ * ```
49
+ */
50
+ export function useToast() : ToastAPI
51
+ {
52
+ const api = inject<ToastAPI>(TOAST_INJECTION_KEY);
53
+
54
+ if(!api)
55
+ {
56
+ // Return a no-op API with warnings
57
+ console.warn('[SkToast] useToast() must be used within SkToastProvider');
58
+ return {
59
+ add: (_options : ToastOptions) =>
60
+ {
61
+ console.warn('[SkToast] Cannot add toast - no provider found');
62
+ return '';
63
+ },
64
+ dismiss: () =>
65
+ {
66
+ console.warn('[SkToast] Cannot dismiss toast - no provider found');
67
+ },
68
+ dismissAll: () =>
69
+ {
70
+ console.warn('[SkToast] Cannot dismiss toasts - no provider found');
71
+ },
72
+ };
73
+ }
74
+
75
+ return api;
76
+ }
77
+
78
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,162 @@
1
+ <template>
2
+ <!-- When inside SkTooltipProvider, skip creating our own provider -->
3
+ <TooltipProvider v-if="!hasProvider" :delay-duration="delayDuration">
4
+ <TooltipRoot>
5
+ <TooltipTrigger as-child>
6
+ <slot name="trigger" />
7
+ </TooltipTrigger>
8
+ <TooltipPortal>
9
+ <TooltipContent
10
+ :class="contentClasses"
11
+ :style="customColorStyles"
12
+ :data-scheme="theme"
13
+ :side="side"
14
+ :align="align"
15
+ :side-offset="sideOffset"
16
+ >
17
+ <slot />
18
+ <TooltipArrow v-if="showArrow" class="sk-tooltip-arrow" />
19
+ </TooltipContent>
20
+ </TooltipPortal>
21
+ </TooltipRoot>
22
+ </TooltipProvider>
23
+
24
+ <!-- When inside SkTooltipProvider, use shared provider context -->
25
+ <TooltipRoot v-else>
26
+ <TooltipTrigger as-child>
27
+ <slot name="trigger" />
28
+ </TooltipTrigger>
29
+ <TooltipPortal>
30
+ <TooltipContent
31
+ :class="contentClasses"
32
+ :style="customColorStyles"
33
+ :data-scheme="theme"
34
+ :side="side"
35
+ :align="align"
36
+ :side-offset="sideOffset"
37
+ >
38
+ <slot />
39
+ <TooltipArrow v-if="showArrow" class="sk-tooltip-arrow" />
40
+ </TooltipContent>
41
+ </TooltipPortal>
42
+ </TooltipRoot>
43
+ </template>
44
+
45
+ <!--------------------------------------------------------------------------------------------------------------------->
46
+
47
+ <style lang="scss" scoped>
48
+ // Tooltip styles are implemented in /src/styles/components/_tooltip.scss
49
+ </style>
50
+
51
+ <!--------------------------------------------------------------------------------------------------------------------->
52
+
53
+ <script setup lang="ts">
54
+ /**
55
+ * @component
56
+ * Tooltip component for displaying hover hints
57
+ */
58
+
59
+ import { computed, inject, toRef } from 'vue';
60
+ import {
61
+ TooltipArrow,
62
+ TooltipContent,
63
+ TooltipPortal,
64
+ TooltipProvider,
65
+ TooltipRoot,
66
+ TooltipTrigger,
67
+ } from 'reka-ui';
68
+
69
+ // Types
70
+ import type { ComponentCustomColors, ComponentKind } from '@/types';
71
+ import type { SkTooltipSide } from './types';
72
+
73
+ // Composables
74
+ import { useCustomColors } from '@/composables/useCustomColors';
75
+ import { usePortalContext } from '@/composables/usePortalContext';
76
+
77
+ //------------------------------------------------------------------------------------------------------------------
78
+
79
+ /**
80
+ * Tooltip component for displaying hover hints.
81
+ *
82
+ * Works in two modes:
83
+ * - **Standalone**: Each tooltip manages its own timing (default)
84
+ * - **With Provider**: Wrap tooltips in SkTooltipProvider for coordinated behavior
85
+ *
86
+ * The provider enables "skip delay" - moving quickly between tooltips shows them instantly.
87
+ *
88
+ * @example Standalone (works out of the box)
89
+ * ```vue
90
+ * <SkTooltip>
91
+ * <template #trigger><SkButton>Hover me</SkButton></template>
92
+ * Tooltip content
93
+ * </SkTooltip>
94
+ * ```
95
+ *
96
+ * @example With provider (coordinated tooltips)
97
+ * ```vue
98
+ * <SkTooltipProvider :delay-duration="300">
99
+ * <SkTooltip>...</SkTooltip>
100
+ * <SkTooltip>...</SkTooltip>
101
+ * </SkTooltipProvider>
102
+ * ```
103
+ */
104
+ export interface SkTooltipComponentProps extends ComponentCustomColors
105
+ {
106
+ /** Semantic color kind */
107
+ kind ?: ComponentKind;
108
+ /** Visual variant */
109
+ variant ?: 'solid' | 'outline';
110
+ /** Which side of the trigger to show the tooltip */
111
+ side ?: SkTooltipSide;
112
+ /** Alignment along the side */
113
+ align ?: 'start' | 'center' | 'end';
114
+ /** Offset from the trigger in pixels */
115
+ sideOffset ?: number;
116
+ /**
117
+ * Delay before showing tooltip (ms). Only used in standalone mode.
118
+ * When inside SkTooltipProvider, the provider's delayDuration is used instead.
119
+ */
120
+ delayDuration ?: number;
121
+ /** Whether to show the arrow pointing to the trigger */
122
+ showArrow ?: boolean;
123
+ }
124
+
125
+ //------------------------------------------------------------------------------------------------------------------
126
+
127
+ const props = withDefaults(defineProps<SkTooltipComponentProps>(), {
128
+ kind: 'neutral',
129
+ variant: 'solid',
130
+ side: 'top',
131
+ align: 'center',
132
+ sideOffset: 5,
133
+ delayDuration: 400,
134
+ showArrow: true,
135
+ });
136
+
137
+ //------------------------------------------------------------------------------------------------------------------
138
+
139
+ // Check if we're inside an SkTooltipProvider
140
+ const hasProvider = inject('sk-tooltip-provider', false);
141
+
142
+ // Handle portal context (theme injection/re-provision for nested portal components)
143
+ const { theme } = usePortalContext();
144
+
145
+ //------------------------------------------------------------------------------------------------------------------
146
+
147
+ const contentClasses = computed(() => ({
148
+ 'sk-tooltip-content': true,
149
+ [`sk-${ props.kind }`]: true,
150
+ [`sk-${ props.variant }`]: true,
151
+ }));
152
+
153
+ //------------------------------------------------------------------------------------------------------------------
154
+
155
+ const customColorStyles = useCustomColors(
156
+ 'tooltip',
157
+ toRef(() => props.baseColor),
158
+ toRef(() => props.textColor)
159
+ );
160
+ </script>
161
+
162
+ <!--------------------------------------------------------------------------------------------------------------------->