@witchcraft/ui 0.0.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 (315) hide show
  1. package/README.md +236 -0
  2. package/dist/module.cjs +5 -0
  3. package/dist/module.d.mts +34 -0
  4. package/dist/module.d.ts +34 -0
  5. package/dist/module.json +9 -0
  6. package/dist/module.mjs +124 -0
  7. package/dist/runtime/assets/base.css +1 -0
  8. package/dist/runtime/assets/locales/en.json +33 -0
  9. package/dist/runtime/assets/style.css +1 -0
  10. package/dist/runtime/assets/tailwind.css +1 -0
  11. package/dist/runtime/assets/theme.css +1 -0
  12. package/dist/runtime/build/WitchcraftUiResolver.d.ts +5 -0
  13. package/dist/runtime/build/WitchcraftUiResolver.js +17 -0
  14. package/dist/runtime/build/generateTheme.d.ts +1 -0
  15. package/dist/runtime/build/generateTheme.js +14 -0
  16. package/dist/runtime/build/unpluginIconViteOptions.d.ts +2 -0
  17. package/dist/runtime/build/unpluginIconViteOptions.js +10 -0
  18. package/dist/runtime/components/Aria/Aria.vue +18 -0
  19. package/dist/runtime/components/Focus.stories.d.ts +11 -0
  20. package/dist/runtime/components/Focus.stories.js +53 -0
  21. package/dist/runtime/components/Icon/Icon.vue +39 -0
  22. package/dist/runtime/components/LibButton/LibButton.stories.d.ts +12 -0
  23. package/dist/runtime/components/LibButton/LibButton.stories.js +94 -0
  24. package/dist/runtime/components/LibButton/LibButton.vue +247 -0
  25. package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.d.ts +14 -0
  26. package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.js +29 -0
  27. package/dist/runtime/components/LibCheckbox/LibCheckbox.vue +132 -0
  28. package/dist/runtime/components/LibColorInput/LibColorInput.stories.d.ts +7 -0
  29. package/dist/runtime/components/LibColorInput/LibColorInput.stories.js +58 -0
  30. package/dist/runtime/components/LibColorInput/LibColorInput.vue +125 -0
  31. package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.d.ts +7 -0
  32. package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.js +51 -0
  33. package/dist/runtime/components/LibColorPicker/LibColorPicker.vue +448 -0
  34. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.d.ts +7 -0
  35. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.js +36 -0
  36. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue +95 -0
  37. package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.d.ts +11 -0
  38. package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.js +98 -0
  39. package/dist/runtime/components/LibDatePicker/LibDatePicker.vue +67 -0
  40. package/dist/runtime/components/LibDatePicker/LibRangeDatePicker.vue +370 -0
  41. package/dist/runtime/components/LibDatePicker/LibSingleDatePicker.vue +314 -0
  42. package/dist/runtime/components/LibDatePicker/LibTimeZonePicker.vue +27 -0
  43. package/dist/runtime/components/LibDatePicker/helpers.d.ts +25 -0
  44. package/dist/runtime/components/LibDatePicker/helpers.js +28 -0
  45. package/dist/runtime/components/LibDebug/LibDebug.stories.d.ts +9 -0
  46. package/dist/runtime/components/LibDebug/LibDebug.stories.js +46 -0
  47. package/dist/runtime/components/LibDebug/LibDebug.vue +91 -0
  48. package/dist/runtime/components/LibDevOnly/LibDevOnly.vue +53 -0
  49. package/dist/runtime/components/LibFileInput/LibFileInput.stories.d.ts +10 -0
  50. package/dist/runtime/components/LibFileInput/LibFileInput.stories.js +63 -0
  51. package/dist/runtime/components/LibFileInput/LibFileInput.vue +273 -0
  52. package/dist/runtime/components/LibInput/LibInput.stories.d.ts +33 -0
  53. package/dist/runtime/components/LibInput/LibInput.stories.js +339 -0
  54. package/dist/runtime/components/LibInput/LibInput.vue +372 -0
  55. package/dist/runtime/components/LibLabel/LibLabel.stories.d.ts +6 -0
  56. package/dist/runtime/components/LibLabel/LibLabel.stories.js +25 -0
  57. package/dist/runtime/components/LibLabel/LibLabel.vue +66 -0
  58. package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.d.ts +23 -0
  59. package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.js +60 -0
  60. package/dist/runtime/components/LibMultiValues/LibMultiValues.vue +127 -0
  61. package/dist/runtime/components/LibNotifications/LibNotification.stories.d.ts +15 -0
  62. package/dist/runtime/components/LibNotifications/LibNotification.stories.js +126 -0
  63. package/dist/runtime/components/LibNotifications/LibNotification.vue +121 -0
  64. package/dist/runtime/components/LibNotifications/LibNotifications.stories.d.ts +6 -0
  65. package/dist/runtime/components/LibNotifications/LibNotifications.stories.js +109 -0
  66. package/dist/runtime/components/LibNotifications/LibNotifications.vue +133 -0
  67. package/dist/runtime/components/LibPagination/LibPagination.stories.d.ts +6 -0
  68. package/dist/runtime/components/LibPagination/LibPagination.stories.js +40 -0
  69. package/dist/runtime/components/LibPagination/LibPagination.vue +261 -0
  70. package/dist/runtime/components/LibPalette/LibPalette.stories.d.ts +6 -0
  71. package/dist/runtime/components/LibPalette/LibPalette.stories.js +20 -0
  72. package/dist/runtime/components/LibPalette/LibPalette.vue +49 -0
  73. package/dist/runtime/components/LibPopup/LibPopup.stories.d.ts +14 -0
  74. package/dist/runtime/components/LibPopup/LibPopup.stories.js +147 -0
  75. package/dist/runtime/components/LibPopup/LibPopup.vue +441 -0
  76. package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.d.ts +10 -0
  77. package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.js +81 -0
  78. package/dist/runtime/components/LibProgressBar/LibProgressBar.vue +192 -0
  79. package/dist/runtime/components/LibRecorder/LibRecorder.stories.d.ts +19 -0
  80. package/dist/runtime/components/LibRecorder/LibRecorder.stories.js +63 -0
  81. package/dist/runtime/components/LibRecorder/LibRecorder.vue +243 -0
  82. package/dist/runtime/components/LibRoot/LibRoot.vue +126 -0
  83. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.d.ts +26 -0
  84. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.js +78 -0
  85. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.vue +148 -0
  86. package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.d.ts +27 -0
  87. package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.js +112 -0
  88. package/dist/runtime/components/LibSuggestions/LibSuggestions.vue +198 -0
  89. package/dist/runtime/components/LibTable/LibTable.stories.d.ts +16 -0
  90. package/dist/runtime/components/LibTable/LibTable.stories.js +156 -0
  91. package/dist/runtime/components/LibTable/LibTable.vue +177 -0
  92. package/dist/runtime/components/Template/NAME.vue +49 -0
  93. package/dist/runtime/components/Template/TemplateStory.d.ts +7 -0
  94. package/dist/runtime/components/Template/TemplateStory.js +22 -0
  95. package/dist/runtime/components/TestControls/TestControls.vue +19 -0
  96. package/dist/runtime/components/index.d.ts +19 -0
  97. package/dist/runtime/components/index.js +19 -0
  98. package/dist/runtime/components/reset.stories.d.ts +5 -0
  99. package/dist/runtime/components/reset.stories.js +19 -0
  100. package/dist/runtime/components/shared/props.d.ts +135 -0
  101. package/dist/runtime/components/shared/props.js +14 -0
  102. package/dist/runtime/components/shared/storyHelpers/playInput.d.ts +8 -0
  103. package/dist/runtime/components/shared/storyHelpers/playInput.js +26 -0
  104. package/dist/runtime/components/shared/storyHelpers/playSuggestions.d.ts +12 -0
  105. package/dist/runtime/components/shared/storyHelpers/playSuggestions.js +83 -0
  106. package/dist/runtime/composables/index.d.ts +11 -0
  107. package/dist/runtime/composables/index.js +11 -0
  108. package/dist/runtime/composables/useAccesibilityOutline.d.ts +41 -0
  109. package/dist/runtime/composables/useAccesibilityOutline.js +58 -0
  110. package/dist/runtime/composables/useAriaLabel.d.ts +6 -0
  111. package/dist/runtime/composables/useAriaLabel.js +15 -0
  112. package/dist/runtime/composables/useDarkMode.d.ts +38 -0
  113. package/dist/runtime/composables/useDarkMode.js +79 -0
  114. package/dist/runtime/composables/useDivideAttrs.d.ts +27 -0
  115. package/dist/runtime/composables/useDivideAttrs.js +26 -0
  116. package/dist/runtime/composables/useGlobalResizeObserver.d.ts +3 -0
  117. package/dist/runtime/composables/useGlobalResizeObserver.js +28 -0
  118. package/dist/runtime/composables/useInjectedDarkMode.d.ts +2 -0
  119. package/dist/runtime/composables/useInjectedDarkMode.js +13 -0
  120. package/dist/runtime/composables/useInjectedI18n.d.ts +2 -0
  121. package/dist/runtime/composables/useInjectedI18n.js +7 -0
  122. package/dist/runtime/composables/useInjectedLocale.d.ts +2 -0
  123. package/dist/runtime/composables/useInjectedLocale.js +21 -0
  124. package/dist/runtime/composables/useNotificationHandler.d.ts +4 -0
  125. package/dist/runtime/composables/useNotificationHandler.js +21 -0
  126. package/dist/runtime/composables/useScrollNearContainerEdges.d.ts +68 -0
  127. package/dist/runtime/composables/useScrollNearContainerEdges.js +116 -0
  128. package/dist/runtime/composables/useScrollNearContainerEdges.stories.d.ts +7 -0
  129. package/dist/runtime/composables/useScrollNearContainerEdges.stories.js +85 -0
  130. package/dist/runtime/composables/useSetupDarkMode.d.ts +12 -0
  131. package/dist/runtime/composables/useSetupDarkMode.js +4 -0
  132. package/dist/runtime/composables/useSetupI18n.d.ts +20 -0
  133. package/dist/runtime/composables/useSetupI18n.js +50 -0
  134. package/dist/runtime/composables/useSetupLocale.d.ts +9 -0
  135. package/dist/runtime/composables/useSetupLocale.js +21 -0
  136. package/dist/runtime/composables/useShowDevOnlyKey.d.ts +7 -0
  137. package/dist/runtime/composables/useShowDevOnlyKey.js +20 -0
  138. package/dist/runtime/composables/useSuggestions.d.ts +38 -0
  139. package/dist/runtime/composables/useSuggestions.js +226 -0
  140. package/dist/runtime/directives/index.d.ts +4 -0
  141. package/dist/runtime/directives/index.js +4 -0
  142. package/dist/runtime/directives/vDetectFlex.d.ts +2 -0
  143. package/dist/runtime/directives/vDetectFlex.js +109 -0
  144. package/dist/runtime/directives/vExtractRootEl.d.ts +22 -0
  145. package/dist/runtime/directives/vExtractRootEl.js +13 -0
  146. package/dist/runtime/directives/vResizableCols.d.ts +60 -0
  147. package/dist/runtime/directives/vResizableCols.js +252 -0
  148. package/dist/runtime/directives/vResizeObserver.d.ts +2 -0
  149. package/dist/runtime/directives/vResizeObserver.js +34 -0
  150. package/dist/runtime/globalResizeObserver.d.ts +5 -0
  151. package/dist/runtime/globalResizeObserver.js +5 -0
  152. package/dist/runtime/helpers/NotificationHandler.d.ts +48 -0
  153. package/dist/runtime/helpers/NotificationHandler.js +162 -0
  154. package/dist/runtime/helpers/addValue.d.ts +1 -0
  155. package/dist/runtime/helpers/addValue.js +8 -0
  156. package/dist/runtime/helpers/base64ToImg.d.ts +1 -0
  157. package/dist/runtime/helpers/base64ToImg.js +11 -0
  158. package/dist/runtime/helpers/copy.d.ts +1 -0
  159. package/dist/runtime/helpers/copy.js +10 -0
  160. package/dist/runtime/helpers/createNoonUtcDate.d.ts +7 -0
  161. package/dist/runtime/helpers/createNoonUtcDate.js +14 -0
  162. package/dist/runtime/helpers/defaultTranslationFunction.d.ts +16 -0
  163. package/dist/runtime/helpers/defaultTranslationFunction.js +14 -0
  164. package/dist/runtime/helpers/getTimeZoneList.d.ts +1 -0
  165. package/dist/runtime/helpers/getTimeZoneList.js +3 -0
  166. package/dist/runtime/helpers/hasModifiers.d.ts +1 -0
  167. package/dist/runtime/helpers/hasModifiers.js +1 -0
  168. package/dist/runtime/helpers/index.d.ts +8 -0
  169. package/dist/runtime/helpers/index.js +8 -0
  170. package/dist/runtime/helpers/readFile.d.ts +1 -0
  171. package/dist/runtime/helpers/readFile.js +13 -0
  172. package/dist/runtime/helpers/resizeObserverWrapper.d.ts +8 -0
  173. package/dist/runtime/helpers/resizeObserverWrapper.js +37 -0
  174. package/dist/runtime/helpers/storybook.d.ts +7 -0
  175. package/dist/runtime/helpers/storybook.js +42 -0
  176. package/dist/runtime/main.lib.d.ts +26 -0
  177. package/dist/runtime/main.lib.js +8 -0
  178. package/dist/runtime/nuxt/plugins/vue-plugin.d.ts +2 -0
  179. package/dist/runtime/nuxt/plugins/vue-plugin.js +12 -0
  180. package/dist/runtime/tailwind/index.d.ts +1 -0
  181. package/dist/runtime/tailwind/index.js +1 -0
  182. package/dist/runtime/tailwind/themeConvertionOpts.d.ts +2 -0
  183. package/dist/runtime/tailwind/themeConvertionOpts.js +12 -0
  184. package/dist/runtime/theme.d.ts +2 -0
  185. package/dist/runtime/theme.js +2 -0
  186. package/dist/runtime/types/index.d.ts +119 -0
  187. package/dist/runtime/types/index.js +0 -0
  188. package/dist/runtime/utils/twMerge.d.ts +10 -0
  189. package/dist/runtime/utils/twMerge.js +10 -0
  190. package/dist/runtime/vue/VueComponentsPlugin.d.ts +2 -0
  191. package/dist/runtime/vue/VueComponentsPlugin.js +10 -0
  192. package/dist/runtime/vue/registerComponents.d.ts +19 -0
  193. package/dist/runtime/vue/registerComponents.js +10 -0
  194. package/dist/runtime/vue/registerDirectives.d.ts +3 -0
  195. package/dist/runtime/vue/registerDirectives.js +9 -0
  196. package/dist/types.d.mts +7 -0
  197. package/dist/types.d.ts +7 -0
  198. package/package.json +207 -0
  199. package/src/module.ts +176 -0
  200. package/src/runtime/assets/base.css +67 -0
  201. package/src/runtime/assets/locales/en.json +33 -0
  202. package/src/runtime/assets/style.css +144 -0
  203. package/src/runtime/assets/tailwind.css +5 -0
  204. package/src/runtime/assets/theme.css +65 -0
  205. package/src/runtime/build/WitchcraftUiResolver.ts +27 -0
  206. package/src/runtime/build/generateTheme.ts +16 -0
  207. package/src/runtime/build/unpluginIconViteOptions.ts +11 -0
  208. package/src/runtime/components/Aria/Aria.vue +27 -0
  209. package/src/runtime/components/Focus.stories.ts +67 -0
  210. package/src/runtime/components/Icon/Icon.vue +39 -0
  211. package/src/runtime/components/LibButton/LibButton.stories.ts +107 -0
  212. package/src/runtime/components/LibButton/LibButton.vue +247 -0
  213. package/src/runtime/components/LibCheckbox/LibCheckbox.stories.ts +41 -0
  214. package/src/runtime/components/LibCheckbox/LibCheckbox.vue +132 -0
  215. package/src/runtime/components/LibColorInput/LibColorInput.stories.ts +69 -0
  216. package/src/runtime/components/LibColorInput/LibColorInput.vue +125 -0
  217. package/src/runtime/components/LibColorPicker/LibColorPicker.stories.ts +60 -0
  218. package/src/runtime/components/LibColorPicker/LibColorPicker.vue +448 -0
  219. package/src/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.ts +51 -0
  220. package/src/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue +95 -0
  221. package/src/runtime/components/LibDatePicker/LibDatePicker.stories.ts +114 -0
  222. package/src/runtime/components/LibDatePicker/LibDatePicker.vue +67 -0
  223. package/src/runtime/components/LibDatePicker/LibRangeDatePicker.vue +370 -0
  224. package/src/runtime/components/LibDatePicker/LibSingleDatePicker.vue +314 -0
  225. package/src/runtime/components/LibDatePicker/LibTimeZonePicker.vue +27 -0
  226. package/src/runtime/components/LibDatePicker/helpers.ts +55 -0
  227. package/src/runtime/components/LibDebug/LibDebug.stories.ts +58 -0
  228. package/src/runtime/components/LibDebug/LibDebug.vue +91 -0
  229. package/src/runtime/components/LibDevOnly/LibDevOnly.vue +53 -0
  230. package/src/runtime/components/LibFileInput/LibFileInput.stories.ts +79 -0
  231. package/src/runtime/components/LibFileInput/LibFileInput.vue +273 -0
  232. package/src/runtime/components/LibInput/LibInput.stories.ts +367 -0
  233. package/src/runtime/components/LibInput/LibInput.vue +372 -0
  234. package/src/runtime/components/LibLabel/LibLabel.stories.ts +37 -0
  235. package/src/runtime/components/LibLabel/LibLabel.vue +66 -0
  236. package/src/runtime/components/LibMultiValues/LibMultiValues.stories.ts +83 -0
  237. package/src/runtime/components/LibMultiValues/LibMultiValues.vue +127 -0
  238. package/src/runtime/components/LibNotifications/LibNotification.stories.ts +142 -0
  239. package/src/runtime/components/LibNotifications/LibNotification.vue +121 -0
  240. package/src/runtime/components/LibNotifications/LibNotifications.stories.ts +124 -0
  241. package/src/runtime/components/LibNotifications/LibNotifications.vue +133 -0
  242. package/src/runtime/components/LibPagination/LibPagination.stories.ts +53 -0
  243. package/src/runtime/components/LibPagination/LibPagination.vue +261 -0
  244. package/src/runtime/components/LibPalette/LibPalette.stories.ts +32 -0
  245. package/src/runtime/components/LibPalette/LibPalette.vue +49 -0
  246. package/src/runtime/components/LibPopup/LibPopup.stories.ts +157 -0
  247. package/src/runtime/components/LibPopup/LibPopup.vue +441 -0
  248. package/src/runtime/components/LibProgressBar/LibProgressBar.stories.ts +94 -0
  249. package/src/runtime/components/LibProgressBar/LibProgressBar.vue +192 -0
  250. package/src/runtime/components/LibRecorder/LibRecorder.stories.ts +81 -0
  251. package/src/runtime/components/LibRecorder/LibRecorder.vue +243 -0
  252. package/src/runtime/components/LibRoot/LibRoot.vue +126 -0
  253. package/src/runtime/components/LibSimpleInput/LibSimpleInput.stories.ts +98 -0
  254. package/src/runtime/components/LibSimpleInput/LibSimpleInput.vue +148 -0
  255. package/src/runtime/components/LibSuggestions/LibSuggestions.stories.ts +137 -0
  256. package/src/runtime/components/LibSuggestions/LibSuggestions.vue +198 -0
  257. package/src/runtime/components/LibTable/LibTable.stories.ts +170 -0
  258. package/src/runtime/components/LibTable/LibTable.vue +177 -0
  259. package/src/runtime/components/Template/NAME.vue +49 -0
  260. package/src/runtime/components/Template/TemplateStory.ts +38 -0
  261. package/src/runtime/components/TestControls/TestControls.vue +19 -0
  262. package/src/runtime/components/index.ts +22 -0
  263. package/src/runtime/components/reset.stories.ts +32 -0
  264. package/src/runtime/components/shared/props.ts +142 -0
  265. package/src/runtime/components/shared/storyHelpers/playInput.ts +35 -0
  266. package/src/runtime/components/shared/storyHelpers/playSuggestions.ts +105 -0
  267. package/src/runtime/composables/index.ts +13 -0
  268. package/src/runtime/composables/useAccesibilityOutline.ts +104 -0
  269. package/src/runtime/composables/useAriaLabel.ts +23 -0
  270. package/src/runtime/composables/useDarkMode.ts +146 -0
  271. package/src/runtime/composables/useDivideAttrs.ts +52 -0
  272. package/src/runtime/composables/useGlobalResizeObserver.ts +33 -0
  273. package/src/runtime/composables/useInjectedDarkMode.ts +15 -0
  274. package/src/runtime/composables/useInjectedI18n.ts +10 -0
  275. package/src/runtime/composables/useInjectedLocale.ts +24 -0
  276. package/src/runtime/composables/useNotificationHandler.ts +32 -0
  277. package/src/runtime/composables/useScrollNearContainerEdges.stories.ts +93 -0
  278. package/src/runtime/composables/useScrollNearContainerEdges.ts +205 -0
  279. package/src/runtime/composables/useSetupDarkMode.ts +14 -0
  280. package/src/runtime/composables/useSetupI18n.ts +77 -0
  281. package/src/runtime/composables/useSetupLocale.ts +32 -0
  282. package/src/runtime/composables/useShowDevOnlyKey.ts +28 -0
  283. package/src/runtime/composables/useSuggestions.ts +297 -0
  284. package/src/runtime/directives/index.ts +6 -0
  285. package/src/runtime/directives/vDetectFlex.ts +159 -0
  286. package/src/runtime/directives/vExtractRootEl.ts +38 -0
  287. package/src/runtime/directives/vResizableCols.ts +378 -0
  288. package/src/runtime/directives/vResizeObserver.ts +45 -0
  289. package/src/runtime/globalResizeObserver.ts +12 -0
  290. package/src/runtime/helpers/NotificationHandler.ts +227 -0
  291. package/src/runtime/helpers/addValue.ts +10 -0
  292. package/src/runtime/helpers/base64ToImg.ts +14 -0
  293. package/src/runtime/helpers/copy.ts +11 -0
  294. package/src/runtime/helpers/createNoonUtcDate.ts +21 -0
  295. package/src/runtime/helpers/defaultTranslationFunction.ts +33 -0
  296. package/src/runtime/helpers/getTimeZoneList.ts +4 -0
  297. package/src/runtime/helpers/hasModifiers.ts +1 -0
  298. package/src/runtime/helpers/index.ts +10 -0
  299. package/src/runtime/helpers/readFile.ts +22 -0
  300. package/src/runtime/helpers/resizeObserverWrapper.ts +45 -0
  301. package/src/runtime/helpers/storybook.ts +52 -0
  302. package/src/runtime/main.lib.ts +31 -0
  303. package/src/runtime/nuxt/plugins/vue-plugin.ts +19 -0
  304. package/src/runtime/tailwind/index.ts +3 -0
  305. package/src/runtime/tailwind/themeConvertionOpts.ts +15 -0
  306. package/src/runtime/theme.ts +5 -0
  307. package/src/runtime/types/index.ts +116 -0
  308. package/src/runtime/utils/twMerge.ts +13 -0
  309. package/src/runtime/vue/VueComponentsPlugin.ts +16 -0
  310. package/src/runtime/vue/registerComponents.ts +31 -0
  311. package/src/runtime/vue/registerDirectives.ts +12 -0
  312. package/types/components.d.ts +27 -0
  313. package/types/global.d.ts +16 -0
  314. package/types/index.d.ts +5 -0
  315. package/types/vite.d.ts +2 -0
@@ -0,0 +1,105 @@
1
+ /* eslint-disable @typescript-eslint/explicit-function-return-type */
2
+ import { expect, userEvent, within } from "@storybook/test"
3
+
4
+
5
+ export const playBasicSelect = async ({ canvasElement, args }: { canvasElement: HTMLElement, args: any }) => {
6
+ const canvas = within(canvasElement)
7
+ const input = canvas.getByLabelText(args.label ?? "", { selector: "input" })
8
+ await userEvent.type(input, "A")
9
+ await expect(canvas.queryByRole("option", { name: "A", selected: true })).toBeInTheDocument()
10
+ await userEvent.type(input, "BCDE")
11
+ // partial match
12
+ await expect(canvas.queryByRole("option", { name: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", selected: true })).toBeInTheDocument()
13
+ await userEvent.keyboard("{Enter}")
14
+
15
+ if (args.values !== undefined) {
16
+ await expect(canvas.getByTestId("model-value").textContent).toBe("")
17
+ // await expect(canvas.getByTestId("model-value")).toHaveTextContent("")
18
+ await expect(canvas.queryByRole("listbox")).not.toBeNull()
19
+ } else {
20
+ await expect(canvas.getByTestId("model-value")).toHaveTextContent("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
21
+ // await expect(canvas.getByTestId("model-value").textContent).toBe("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
22
+ // should be closed after enter
23
+ await expect(canvas.queryByRole("listbox")).toBeNull()
24
+ }
25
+ await userEvent.keyboard("{Backspace}")
26
+ await expect(canvas.queryByRole("option",{ selected: true })).toBeInTheDocument()
27
+ await userEvent.clear(input)
28
+ await userEvent.type(input, "unmatched")
29
+ if (!args.suggestionsFilter) {
30
+ await expect(canvas.queryAllByRole("option", { selected: true })).toEqual([])
31
+ }
32
+ await userEvent.clear(input)
33
+
34
+ // first match should be selected if input is empty
35
+ await expect(await canvas.findByRole("option", { name: "A", selected: true })).toBeInTheDocument()
36
+ if (args.restrictToSuggestions && args.values === undefined) {
37
+ // should still equal last selected
38
+ await expect(canvas.getByTestId("model-value").textContent).toBe("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
39
+ }
40
+
41
+ await userEvent.keyboard("{Enter}")
42
+ if (args.values === undefined) {
43
+ await expect(canvas.getByTestId("model-value").textContent).toBe("A")
44
+ }
45
+ await userEvent.clear(input)
46
+ await userEvent.keyboard("AB{Escape}")
47
+ await expect(canvas.queryByRole("listbox")).toBeNull()
48
+ if (args.values === undefined) {
49
+ if (args.restrictToSuggestions) {
50
+ await expect(canvas.getByTestId("model-value").textContent).toBe("A")
51
+ }
52
+ }
53
+ }
54
+
55
+ export const playBasicKeyboardSelect = async ({ canvasElement, args }: { canvasElement: HTMLElement , args: any }) => {
56
+ const canvas = within(canvasElement)
57
+ const input = canvas.getByLabelText(args.label ?? "", { selector: "input" })
58
+ await userEvent.clear(input)
59
+ await userEvent.type(input, "A")
60
+ await expect(canvas.queryByRole("option", { name: "A", selected: true })).toBeInTheDocument()
61
+ await userEvent.keyboard("{ArrowDown}")
62
+ await expect(canvas.queryByRole("option", { name: "AB", selected: true })).toBeInTheDocument()
63
+ await userEvent.keyboard("{ArrowUp}")
64
+ await expect(canvas.queryByRole("option", { name: "A", selected: true })).toBeInTheDocument()
65
+
66
+ // loops to last item
67
+ await userEvent.keyboard("{ArrowUp}")
68
+ await expect(canvas.queryByRole("option", { name: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", selected: true })).toBeInTheDocument()
69
+
70
+ // loops back to the first item
71
+ await userEvent.keyboard("{ArrowDown}")
72
+ await expect(canvas.queryByRole("option", { name: "A", selected: true })).toBeInTheDocument()
73
+
74
+ // goes to last
75
+ await userEvent.keyboard("{PageDown}")
76
+ await expect(canvas.queryByRole("option", { name: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", selected: true })).toBeInTheDocument()
77
+ // goes to first
78
+ await userEvent.keyboard("{PageUp}")
79
+ await expect(canvas.queryByRole("option", { name: "A", selected: true })).toBeInTheDocument()
80
+
81
+ const testOpen = async (key: string) => {
82
+ await userEvent.keyboard("{Escape}")
83
+ await expect(canvas.queryByRole("listbox")).toBeNull()
84
+ await userEvent.keyboard(`{${key}}`)
85
+ await expect(canvas.queryByRole("listbox")).toBeInTheDocument()
86
+ }
87
+ await testOpen("ArrowDown")
88
+ await testOpen("ArrowUp")
89
+ await testOpen("PageDown")
90
+ await testOpen("PageUp")
91
+ }
92
+ export const playBasicClickSelect = async ({ canvasElement, args }: { canvasElement: HTMLElement, args: any }) => {
93
+ const canvas = within(canvasElement)
94
+ const input = canvas.getByLabelText(args.label ?? "", { selector: "input" })
95
+ await userEvent.clear(input)
96
+ await userEvent.type(input, "A")
97
+ await userEvent.click(canvas.getByRole("option", { name: "AB" }))
98
+ if (args.values === undefined) {
99
+ await expect(canvas.getByTestId("model-value").textContent).toBe("AB")
100
+ await expect(canvas.queryByRole("listbox")).toBeNull()
101
+ } else {
102
+ await expect(canvas.getByTestId("values")).toHaveTextContent(/AB$/)
103
+ }
104
+ }
105
+
@@ -0,0 +1,13 @@
1
+ /* Autogenerated Index */
2
+
3
+ export { useAccesibilityOutline } from "./useAccesibilityOutline.js"
4
+ export { useAriaLabel } from "./useAriaLabel.js"
5
+ export { useDarkMode } from "./useDarkMode.js"
6
+ export { useDivideAttrs } from "./useDivideAttrs.js"
7
+ export { useGlobalResizeObserver } from "./useGlobalResizeObserver.js"
8
+ export { useInjectedDarkMode } from "./useInjectedDarkMode.js"
9
+ export { useNotificationHandler } from "./useNotificationHandler.js"
10
+ export { useScrollNearContainerEdges } from "./useScrollNearContainerEdges.js"
11
+ export { useSetupDarkMode } from "./useSetupDarkMode.js"
12
+ export { useShowDevOnlyKey } from "./useShowDevOnlyKey.js"
13
+ export { useSuggestions } from "./useSuggestions.js"
@@ -0,0 +1,104 @@
1
+ import { castType } from "@alanscodelog/utils/castType.js"
2
+ import { onBeforeUnmount, onMounted, type Ref, ref, watch } from "vue"
3
+
4
+ /**
5
+ * Returns a reactive ref that indicates whether the user presses a key *and* produced a change in focus. Used for only providing a `:focus` outline when the user is navigating via the keyboard.
6
+ *
7
+ * Can be optionally passed a reactive ref to enable/disabled the calculation (e.g. based on a user setting). This is returned back by the function in case you want to just use the control variable it auto creates. Event listeners are automatically attached/detached when this is changed.
8
+ *
9
+ * In setup:
10
+ * ```ts
11
+ * const el = ref(null)
12
+ *
13
+ * const {outline, control: outlineControl} = useAccesibilityOutline(el)
14
+ * outlineControl.value = userSettings.outlineOnlyOnNavigation
15
+ * // or
16
+ * useAccesibilityOutline(el, userSettings.outlineOnlyOnNavigation)
17
+ *
18
+ * const classes = computed(() =>( {
19
+ * // if setting is false => always outline
20
+ * outline: !userSettings.outlineOnlyOnNavigation || outline.value
21
+ * }))
22
+ *
23
+ * return {
24
+ * classes,
25
+ * el
26
+ * }
27
+ * ```
28
+ *
29
+ * In the root app component. Note it requires the element have a tabindex.
30
+ * ```html
31
+ * <div id="app" :class="classes" ref="el" tabindex="-1"></div>
32
+ * ```
33
+ *
34
+ * In style of any subcomponents we can now target `:focus` only when the user is navigating with the keyboard.
35
+ *
36
+ * ```css
37
+ * .outline button:focus {
38
+ * ....
39
+ * }
40
+ * ```
41
+ *
42
+ */
43
+ // TODO tailwind example/plugin?
44
+ export function useAccesibilityOutline(
45
+ target: Ref<HTMLElement | null>,
46
+ enable: Ref<boolean> = ref(true),
47
+ ): Record<"outline" | "control", Ref<boolean>> {
48
+ const outline = ref(false)
49
+ const awaitingFocus = ref(false)
50
+ const keydown = (_e: KeyboardEvent): void => {
51
+ awaitingFocus.value = true
52
+ setTimeout(() => {
53
+ awaitingFocus.value = false
54
+ }, 0)
55
+ }
56
+ const mousedown = (_e: MouseEvent): void => {
57
+ awaitingFocus.value = false
58
+ outline.value = false
59
+ }
60
+ const focusin = (_e: FocusEvent): void => {
61
+ if (awaitingFocus.value && enable.value) {
62
+ outline.value = true
63
+ }
64
+ }
65
+ let canAttach = false
66
+ const attach = (): void => {
67
+ if (!canAttach) return
68
+ castType<Ref<HTMLElement>>(target.value)
69
+ if (!target.value) return
70
+ target.value.addEventListener("focusin", focusin)
71
+ target.value.addEventListener("keydown", keydown)
72
+ target.value.addEventListener("mousedown", mousedown)
73
+ }
74
+ const detach = (): void => {
75
+ if (target.value) {
76
+ castType<Ref<HTMLElement>>(target.value)
77
+ target.value.removeEventListener("focusin", focusin)
78
+ target.value.removeEventListener("keydown", keydown)
79
+ target.value.removeEventListener("mousedown", mousedown)
80
+ }
81
+ }
82
+
83
+ watch(enable, (newVal, oldVal) => {
84
+ if (newVal === oldVal) return
85
+ if (newVal) {
86
+ attach()
87
+ } else {
88
+ outline.value = false
89
+ detach()
90
+ }
91
+ })
92
+
93
+ onMounted(() => {
94
+ canAttach = true
95
+ if (enable.value) {
96
+ attach()
97
+ }
98
+ })
99
+ onBeforeUnmount(() => {
100
+ canAttach = false
101
+ detach()
102
+ })
103
+ return { outline, control: enable }
104
+ }
@@ -0,0 +1,23 @@
1
+ import { computed, type ComputedRef, onMounted, ref } from "vue"
2
+
3
+ /** Returns a computed ref that creates aria-label and aria-labelledby with the correct id for labelledby. */
4
+ export const useAriaLabel = (
5
+ props: { id?: string, label?: string },
6
+ fallbackId?: string
7
+
8
+ ): ComputedRef<Record<string, string | undefined>> => {
9
+ const id = computed(() => props.id ?? fallbackId)
10
+ const labelExists = ref(false)
11
+
12
+ const aria = computed(() => ({
13
+ "aria-label": labelExists.value ? undefined : props.label,
14
+ "aria-labelledby": labelExists.value ? `label-${id.value}` : undefined,
15
+ }))
16
+
17
+ onMounted(() => {
18
+ if (id.value && document.querySelector(`#label-${id.value}`)) {
19
+ labelExists.value = true
20
+ }
21
+ })
22
+ return aria
23
+ }
@@ -0,0 +1,146 @@
1
+ import { computed, type InjectionKey, onMounted, provide, type Ref,ref, watch } from "vue"
2
+
3
+
4
+ const defaultLocalStorageKey = "prefersColorSchemeDark"
5
+ const defaultOrder = ["system", "dark", "light"] as const
6
+ /** @deprecated */
7
+ const injectionKey = Symbol("isDarkMode") as InjectionKey<Ref<boolean>>
8
+ /** @deprecated */
9
+ const manualInjectionKey = Symbol("manualDarkMode") as InjectionKey<Ref<boolean | undefined>>
10
+ const commandsInjectionKey = Symbol("darkModeCommands") as InjectionKey<DarkModeCommands>
11
+ const stateInjectionKey = Symbol("darkModeState") as InjectionKey<DarkModeState>
12
+
13
+ /**
14
+ * @deprecated Use `useSetupDarkMode` instead.
15
+ *
16
+ * A composable for setting up dark mode that automatically takes care of saving the user's preference.
17
+ *
18
+ * See the returned utilities for more details.
19
+ *
20
+ * It also provides injection keys with a ref so it can be accessed in deep nested components if needed. Alternatively you can use `useInjectedDarkMode` for ease of use.
21
+ *
22
+ * Note that this should only be called once at the root of the app.
23
+ */
24
+ export const useDarkMode = ({
25
+ useLocalStorage = true,
26
+ darkModeOrder = defaultOrder,
27
+ /** True by default, should be passed import.meta.client if using nuxt, or false when running server side. */
28
+ isClientSide = true
29
+ }: DarkModeOptions = {}): DarkModeState & DarkModeCommands => {
30
+ const systemDarkMode = ref(false)
31
+ const manualDarkMode = ref<boolean | undefined>(undefined)
32
+
33
+ if (useLocalStorage && isClientSide) {
34
+ watch(manualDarkMode, () => {
35
+ localStorage.setItem(defaultLocalStorageKey, manualDarkMode.value ? "true" : "false")
36
+ })
37
+ }
38
+
39
+ const darkMode = computed(() => manualDarkMode.value ?? systemDarkMode.value)
40
+ const darkModeState = computed(() =>
41
+ manualDarkMode.value === undefined
42
+ ? "system"
43
+ : manualDarkMode.value
44
+ ? "dark"
45
+ : "light"
46
+ )
47
+ // todo move to useinjected
48
+ function setDarkMode(value: "dark" | "light" | "system"): void {
49
+ manualDarkMode.value =
50
+ value === "dark"
51
+ ? true
52
+ : value === "light"
53
+ ? false
54
+ : undefined
55
+ }
56
+ function cycleDarkMode(): void {
57
+ const index = darkModeOrder.indexOf(darkModeState.value)
58
+
59
+ if (index === 2) {
60
+ setDarkMode(darkModeOrder[0])
61
+ } else {
62
+ setDarkMode(darkModeOrder[index + 1])
63
+ }
64
+ }
65
+
66
+ onMounted(() => {
67
+ window.matchMedia("(prefers-color-scheme: dark)")
68
+ .addEventListener("change", ({ matches }) => {
69
+ if (matches) {
70
+ systemDarkMode.value = true
71
+ } else {
72
+ systemDarkMode.value = false
73
+ }
74
+ })
75
+ if (useLocalStorage !== false) {
76
+ const key = typeof useLocalStorage === "string" ? useLocalStorage : defaultLocalStorageKey
77
+ const value = localStorage.getItem(key)
78
+
79
+ if (value === "true") {
80
+ manualDarkMode.value = true
81
+ } else if (value === "false") {
82
+ manualDarkMode.value = false
83
+ }
84
+ }
85
+ })
86
+ provide(injectionKey, darkMode)
87
+ provide(manualInjectionKey, manualDarkMode)
88
+
89
+ provide(stateInjectionKey, {
90
+ darkMode,
91
+ darkModeState,
92
+ manualDarkMode,
93
+ systemDarkMode,
94
+ })
95
+ provide(commandsInjectionKey, {
96
+ setDarkMode,
97
+ cycleDarkMode,
98
+ })
99
+
100
+ return {
101
+ darkMode,
102
+ darkModeState,
103
+ setDarkMode,
104
+ cycleDarkMode,
105
+ manualDarkMode,
106
+ systemDarkMode,
107
+ }
108
+ }
109
+ export const defaultDarkModeOrder = defaultOrder
110
+
111
+ export const isDarkModeInjectionKey = injectionKey
112
+
113
+ export const manualDarkModeInjectionKey = manualInjectionKey
114
+
115
+ export const darkModeCommandsInjectionKey = commandsInjectionKey
116
+
117
+ export const darkModeStateInjectionKey = stateInjectionKey
118
+
119
+
120
+ export type DarkModeOptions = {
121
+ /* Whether to save the manual dark mode to local storage. Uses the key "prefersColorSchemeDark" by default. You can pass a key instead of true to use that as the key instead. */
122
+ useLocalStorage?: boolean | string
123
+ /* The order of the string dark modes when using `cycleDarkMode`. Defaults to `["system", "dark", "light"]` */
124
+ darkModeOrder?: readonly ("system" | "dark" | "light")[]
125
+ /** True by default, should be passed import.meta.client if using nuxt, or false when running server side. */
126
+ isClientSide?: boolean
127
+ }
128
+
129
+
130
+ export interface DarkModeCommands {
131
+ setDarkMode: (value: "dark" | "light" | "system") => void
132
+ cycleDarkMode: () => void
133
+ }
134
+
135
+
136
+ export interface DarkModeState {
137
+ /** Whether the dark mode should be enabled or not */
138
+ darkMode: Ref<boolean>
139
+ /** The current state of the darkMode but as a string (dark, light, system) */
140
+ darkModeState: Ref<"dark" | "light" | "system">
141
+ /** The value of the manuably controllable dark mode. You can set this to true/false or undefined to allow the systemDarkMode to take priority. Alternatively use setDarkMode instead. */
142
+ manualDarkMode: Ref<boolean | undefined>
143
+ /** The value of the system dark mode. This is automatically set depending on the user's `prefer-color-scheme` and should not be set directly. */
144
+ systemDarkMode: Ref<boolean>
145
+
146
+ }
@@ -0,0 +1,52 @@
1
+ import { keys } from "@alanscodelog/utils/keys.js"
2
+ import { computed, type Ref, useAttrs } from "vue"
3
+
4
+ /**
5
+ * Allows users to more easily pass attributes to different parts of a component. Suppose a component has an input and a wrapper and you want most attributes to go to the input, but any that start with `wrapper` to go to the wrapper.
6
+ *
7
+ * You can do:
8
+ *
9
+ * ```ts
10
+ * const extraAttrs = useDivideAttrs(["wrapper"] as const)
11
+ * ```
12
+ * This will correctly remove the start of the key. So if the user passes:
13
+ * ```vue
14
+ * <your-component regular-attr wrapper-attr wrapperAttrs/>
15
+ * ```
16
+ * You will get a ref like:
17
+ *
18
+ * ```ts
19
+ * extraAttrs.value = {
20
+ * attrs: { regular-attr: true },
21
+ * wrapperAttrs: { attr: true, Attrs: true },
22
+ * }
23
+ *
24
+ * Additionally attributes are properly reactive, tough this is probably a bit expensive given they weren't meant to be reactive.
25
+ *
26
+ * Note that if using multi-word prefixes, like `inner-wrapper`, they will appear as the key `inner-wrapperAttrs` internally, but users will be able to correctly pass `inner-wrapper-prop`. Aditionally these can be passed down to deeper components, allowing easy wrapping.
27
+ * ```
28
+ */
29
+ export const useDivideAttrs = <T extends readonly string[]>(divisionKeys: T): Ref<Record<`${T[number]}Attrs` | "attrs", Record<string, any>>> => computed(() => {
30
+ const attrs: Record<string, any> = useAttrs()
31
+ const res: any = { attrs: {} }
32
+ const unseen = keys(attrs)
33
+ for (const key of divisionKeys) {
34
+ res[`${key}Attrs`] = {}
35
+ for (let i = 0; i < unseen.length; i++) {
36
+ const attrKey = unseen[i]
37
+ if (attrKey.startsWith(`${key}-`)) {
38
+ res[`${key}Attrs`][attrKey.slice(key.length + 1)] = attrs[attrKey]
39
+ unseen.splice(i, 1)
40
+ i--
41
+ } else if (attrKey.startsWith(key)) {
42
+ res[`${key}Attrs`][attrKey.slice(key.length)] = attrs[attrKey]
43
+ unseen.splice(i, 1)
44
+ i--
45
+ }
46
+ }
47
+ }
48
+ for (const attrKey of unseen) {
49
+ res.attrs[attrKey] = attrs[attrKey]
50
+ }
51
+ return res
52
+ })
@@ -0,0 +1,33 @@
1
+ import type { AnyFunction } from "@alanscodelog/utils"
2
+ import { onBeforeUnmount, onMounted, type Ref, watch } from "vue"
3
+
4
+ import { globalResizeObserver } from "../globalResizeObserver.js"
5
+
6
+
7
+ export const useGlobalResizeObserver = (el: Ref<HTMLElement | null>, cb: AnyFunction): void => {
8
+ let wasMounted = false
9
+ // in case we accidentally use it in an onMounted hook or somewhere where the element already exists
10
+ if (el.value) {
11
+ wasMounted = true
12
+ globalResizeObserver.observe(el.value, cb)
13
+ }
14
+ onMounted(() => {
15
+ watch(el, (_newval, oldval) => {
16
+ if (el.value) {
17
+ globalResizeObserver.observe(el.value, cb)
18
+ } else {
19
+ if (oldval) {
20
+ globalResizeObserver.unobserve(oldval, cb)
21
+ }
22
+ }
23
+ })
24
+ if (el.value && !wasMounted) {
25
+ globalResizeObserver.observe(el.value, cb)
26
+ }
27
+ })
28
+ onBeforeUnmount(() => {
29
+ if (el.value) {
30
+ globalResizeObserver.unobserve(el.value, cb)
31
+ }
32
+ })
33
+ }
@@ -0,0 +1,15 @@
1
+ import { inject } from "vue"
2
+
3
+ import { type DarkModeCommands, darkModeCommandsInjectionKey, type DarkModeState,darkModeStateInjectionKey } from "./useDarkMode.js"
4
+
5
+ export function useInjectedDarkMode(): DarkModeState & DarkModeCommands {
6
+ const darkModeState = inject(darkModeStateInjectionKey)
7
+ const darkModeCommands = inject(darkModeCommandsInjectionKey)
8
+ if (!darkModeState || !darkModeCommands) {
9
+ throw new Error("useInjectedDarkMode could not find provided state. Did you use useSetupDarkMode?")
10
+ }
11
+ return {
12
+ ...darkModeState,
13
+ ...darkModeCommands,
14
+ }
15
+ }
@@ -0,0 +1,10 @@
1
+ import { inject } from "vue"
2
+
3
+ import { i18nInjectionKey } from "./useSetupI18n.js"
4
+ import { type TranslationFunction } from "./useSetupI18n.js"
5
+
6
+ export function useInjectedI18n(): TranslationFunction {
7
+ const val = inject(i18nInjectionKey, undefined)
8
+ if (val === undefined) throw new Error("witchcraft/ui: i18n is not injected. See useSetupI18n.")
9
+ return val
10
+ }
@@ -0,0 +1,24 @@
1
+ import { inject } from "vue"
2
+
3
+ import { languageLocaleInjectionKey , timeLocaleInjectionKey , type useSetupLocale } from "./useSetupLocale.js"
4
+
5
+ export function useInjectedLocale(): ReturnType<typeof useSetupLocale> {
6
+ const timeLocale = inject(timeLocaleInjectionKey)
7
+ const languageLocale = inject(languageLocaleInjectionKey)
8
+ if (timeLocale === undefined || languageLocale === undefined) {
9
+ throw new Error("useInjectedLocale could not find provided state. Did you use useSetupLocale?")
10
+ }
11
+ function setLanguageLocale(value: string): void {
12
+ languageLocale!.value = value
13
+ }
14
+ function setTimeLocale(value: string): void {
15
+ timeLocale!.value = value
16
+ }
17
+ return{
18
+ timeLocale,
19
+ languageLocale,
20
+ setLanguageLocale,
21
+ setTimeLocale,
22
+ }
23
+ }
24
+
@@ -0,0 +1,32 @@
1
+ import type { NotificationHandler } from "../helpers/NotificationHandler.js"
2
+
3
+ let first = true
4
+ const configuration: {
5
+ notificationHandler: NotificationHandler
6
+ isClientSide: boolean
7
+ } = {
8
+ notificationHandler: undefined as any,
9
+ isClientSide: undefined as any
10
+ }
11
+ export const useNotificationHandler = (
12
+ handler?: NotificationHandler,
13
+ /** True by default, should be passed import.meta.client if using nuxt, or false when running server side. */
14
+ isClientSide?: boolean
15
+ ): NotificationHandler => {
16
+ const clientSide = isClientSide ?? configuration.isClientSide
17
+
18
+ if (!clientSide) return undefined as any
19
+ if (first) {
20
+ first = false
21
+ configuration.isClientSide = clientSide ?? true
22
+ if (handler) {
23
+ configuration.notificationHandler = handler
24
+ } else {
25
+ throw new Error("You must set the notification handler to use at least once before using it.")
26
+ }
27
+ } else if (handler || isClientSide) {
28
+ // eslint-disable-next-line no-console
29
+ console.warn("You can only configure useNotificationHandler once. (Note that there might be false positive during HMR).")
30
+ }
31
+ return configuration.notificationHandler
32
+ }
@@ -0,0 +1,93 @@
1
+ import type { StoryObj } from "@storybook/vue3"
2
+ import { onMounted, ref } from "vue"
3
+
4
+ import { useScrollNearContainerEdges } from "./useScrollNearContainerEdges.js"
5
+
6
+ import { twMerge } from "../utils/twMerge.js"
7
+
8
+ const meta = {
9
+ title: "Composables/ScrollNearContainerEdges",
10
+ }
11
+
12
+ export default meta
13
+ type Story = StoryObj // & StoryObj<typeof extraArgs>
14
+ // eslint-disable-next-line @typescript-eslint/naming-convention
15
+ export const Primary: Story = {
16
+ render: args => ({
17
+ setup: () => {
18
+ const containerEl = ref<HTMLElement | null>(null)
19
+ const {
20
+ resetScrollIndicator,
21
+ scrollEdges,
22
+ endScroll,
23
+ scrollIndicator,
24
+ isScrolling
25
+ } = useScrollNearContainerEdges({
26
+ containerEl,
27
+ scrollMargin: 20,
28
+ outerScrollMargin: 20,
29
+ })
30
+ const pos = ref({ x: 0, y: 0 })
31
+ onMounted(() => {
32
+ pos.value.x = containerEl.value!.getBoundingClientRect().left
33
+ pos.value.y = containerEl.value!.getBoundingClientRect().top
34
+ })
35
+ const moveDrag = (e: MouseEvent): void => {
36
+ pos.value.x = e.clientX
37
+ pos.value.y = e.clientY
38
+ scrollEdges(e.clientX, e.clientY)
39
+ }
40
+ const endDrag = (_e: MouseEvent): void => {
41
+ endScroll()
42
+ document.removeEventListener("mousemove", moveDrag)
43
+ document.removeEventListener("mouseup", endDrag)
44
+ }
45
+ const startDrag = (_e: MouseEvent): void => {
46
+ document.addEventListener("mousemove", moveDrag)
47
+ document.addEventListener("mouseup", endDrag)
48
+ }
49
+ return {
50
+ args,
51
+ containerEl,
52
+ resetScrollIndicator,
53
+ scrollEdges,
54
+ endScroll,
55
+ startDrag,
56
+ scrollIndicator,
57
+ isScrolling,
58
+ twMerge,
59
+ pos
60
+ }
61
+ },
62
+
63
+ template: `
64
+ <div>
65
+ <p>Scroll the container by dragging the red box (which represents the dragging mouse position).</p>
66
+ <p>It should drag slow, then faster as the mouse nears the edges and scroll indicators should appear on the scrolling edges.</p>
67
+ </div>
68
+ <div
69
+ :class="twMerge(
70
+ 'relative flex flex-col max-h-[300px] max-w-[300px] border-2 border-red-500',
71
+ isScrolling && 'after:content-[\\'\\'] after:absolute after:inset-0 after:border-transparent after:border-[15px]',
72
+ scrollIndicator.right && 'after:border-r-accent-500/60',
73
+ scrollIndicator.down && 'after:border-b-accent-500/60',
74
+ scrollIndicator.left && 'after:border-l-accent-500/60',
75
+ scrollIndicator.up && 'after:border-t-accent-500/60',
76
+ )"
77
+
78
+ >
79
+ <div
80
+ class="overflow-auto"
81
+ ref="containerEl"
82
+ >
83
+ <div class="h-[1000px] w-[1000px]"/>
84
+ <div
85
+ @mousedown="startDrag"
86
+ :style="\`top:\${pos.y}px; left:\${pos.x}px;\`"
87
+ class="h-[20px] w-[20px] -ml-[10px] -mt-[10px] bg-red-500 cursor-move fixed"
88
+ ></div>
89
+ </div>
90
+ </div>
91
+ `,
92
+ }),
93
+ }