@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.
- package/README.md +236 -0
- package/dist/module.cjs +5 -0
- package/dist/module.d.mts +34 -0
- package/dist/module.d.ts +34 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +124 -0
- package/dist/runtime/assets/base.css +1 -0
- package/dist/runtime/assets/locales/en.json +33 -0
- package/dist/runtime/assets/style.css +1 -0
- package/dist/runtime/assets/tailwind.css +1 -0
- package/dist/runtime/assets/theme.css +1 -0
- package/dist/runtime/build/WitchcraftUiResolver.d.ts +5 -0
- package/dist/runtime/build/WitchcraftUiResolver.js +17 -0
- package/dist/runtime/build/generateTheme.d.ts +1 -0
- package/dist/runtime/build/generateTheme.js +14 -0
- package/dist/runtime/build/unpluginIconViteOptions.d.ts +2 -0
- package/dist/runtime/build/unpluginIconViteOptions.js +10 -0
- package/dist/runtime/components/Aria/Aria.vue +18 -0
- package/dist/runtime/components/Focus.stories.d.ts +11 -0
- package/dist/runtime/components/Focus.stories.js +53 -0
- package/dist/runtime/components/Icon/Icon.vue +39 -0
- package/dist/runtime/components/LibButton/LibButton.stories.d.ts +12 -0
- package/dist/runtime/components/LibButton/LibButton.stories.js +94 -0
- package/dist/runtime/components/LibButton/LibButton.vue +247 -0
- package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.d.ts +14 -0
- package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.js +29 -0
- package/dist/runtime/components/LibCheckbox/LibCheckbox.vue +132 -0
- package/dist/runtime/components/LibColorInput/LibColorInput.stories.d.ts +7 -0
- package/dist/runtime/components/LibColorInput/LibColorInput.stories.js +58 -0
- package/dist/runtime/components/LibColorInput/LibColorInput.vue +125 -0
- package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.d.ts +7 -0
- package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.js +51 -0
- package/dist/runtime/components/LibColorPicker/LibColorPicker.vue +448 -0
- package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.d.ts +7 -0
- package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.js +36 -0
- package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue +95 -0
- package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.d.ts +11 -0
- package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.js +98 -0
- package/dist/runtime/components/LibDatePicker/LibDatePicker.vue +67 -0
- package/dist/runtime/components/LibDatePicker/LibRangeDatePicker.vue +370 -0
- package/dist/runtime/components/LibDatePicker/LibSingleDatePicker.vue +314 -0
- package/dist/runtime/components/LibDatePicker/LibTimeZonePicker.vue +27 -0
- package/dist/runtime/components/LibDatePicker/helpers.d.ts +25 -0
- package/dist/runtime/components/LibDatePicker/helpers.js +28 -0
- package/dist/runtime/components/LibDebug/LibDebug.stories.d.ts +9 -0
- package/dist/runtime/components/LibDebug/LibDebug.stories.js +46 -0
- package/dist/runtime/components/LibDebug/LibDebug.vue +91 -0
- package/dist/runtime/components/LibDevOnly/LibDevOnly.vue +53 -0
- package/dist/runtime/components/LibFileInput/LibFileInput.stories.d.ts +10 -0
- package/dist/runtime/components/LibFileInput/LibFileInput.stories.js +63 -0
- package/dist/runtime/components/LibFileInput/LibFileInput.vue +273 -0
- package/dist/runtime/components/LibInput/LibInput.stories.d.ts +33 -0
- package/dist/runtime/components/LibInput/LibInput.stories.js +339 -0
- package/dist/runtime/components/LibInput/LibInput.vue +372 -0
- package/dist/runtime/components/LibLabel/LibLabel.stories.d.ts +6 -0
- package/dist/runtime/components/LibLabel/LibLabel.stories.js +25 -0
- package/dist/runtime/components/LibLabel/LibLabel.vue +66 -0
- package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.d.ts +23 -0
- package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.js +60 -0
- package/dist/runtime/components/LibMultiValues/LibMultiValues.vue +127 -0
- package/dist/runtime/components/LibNotifications/LibNotification.stories.d.ts +15 -0
- package/dist/runtime/components/LibNotifications/LibNotification.stories.js +126 -0
- package/dist/runtime/components/LibNotifications/LibNotification.vue +121 -0
- package/dist/runtime/components/LibNotifications/LibNotifications.stories.d.ts +6 -0
- package/dist/runtime/components/LibNotifications/LibNotifications.stories.js +109 -0
- package/dist/runtime/components/LibNotifications/LibNotifications.vue +133 -0
- package/dist/runtime/components/LibPagination/LibPagination.stories.d.ts +6 -0
- package/dist/runtime/components/LibPagination/LibPagination.stories.js +40 -0
- package/dist/runtime/components/LibPagination/LibPagination.vue +261 -0
- package/dist/runtime/components/LibPalette/LibPalette.stories.d.ts +6 -0
- package/dist/runtime/components/LibPalette/LibPalette.stories.js +20 -0
- package/dist/runtime/components/LibPalette/LibPalette.vue +49 -0
- package/dist/runtime/components/LibPopup/LibPopup.stories.d.ts +14 -0
- package/dist/runtime/components/LibPopup/LibPopup.stories.js +147 -0
- package/dist/runtime/components/LibPopup/LibPopup.vue +441 -0
- package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.d.ts +10 -0
- package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.js +81 -0
- package/dist/runtime/components/LibProgressBar/LibProgressBar.vue +192 -0
- package/dist/runtime/components/LibRecorder/LibRecorder.stories.d.ts +19 -0
- package/dist/runtime/components/LibRecorder/LibRecorder.stories.js +63 -0
- package/dist/runtime/components/LibRecorder/LibRecorder.vue +243 -0
- package/dist/runtime/components/LibRoot/LibRoot.vue +126 -0
- package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.d.ts +26 -0
- package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.js +78 -0
- package/dist/runtime/components/LibSimpleInput/LibSimpleInput.vue +148 -0
- package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.d.ts +27 -0
- package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.js +112 -0
- package/dist/runtime/components/LibSuggestions/LibSuggestions.vue +198 -0
- package/dist/runtime/components/LibTable/LibTable.stories.d.ts +16 -0
- package/dist/runtime/components/LibTable/LibTable.stories.js +156 -0
- package/dist/runtime/components/LibTable/LibTable.vue +177 -0
- package/dist/runtime/components/Template/NAME.vue +49 -0
- package/dist/runtime/components/Template/TemplateStory.d.ts +7 -0
- package/dist/runtime/components/Template/TemplateStory.js +22 -0
- package/dist/runtime/components/TestControls/TestControls.vue +19 -0
- package/dist/runtime/components/index.d.ts +19 -0
- package/dist/runtime/components/index.js +19 -0
- package/dist/runtime/components/reset.stories.d.ts +5 -0
- package/dist/runtime/components/reset.stories.js +19 -0
- package/dist/runtime/components/shared/props.d.ts +135 -0
- package/dist/runtime/components/shared/props.js +14 -0
- package/dist/runtime/components/shared/storyHelpers/playInput.d.ts +8 -0
- package/dist/runtime/components/shared/storyHelpers/playInput.js +26 -0
- package/dist/runtime/components/shared/storyHelpers/playSuggestions.d.ts +12 -0
- package/dist/runtime/components/shared/storyHelpers/playSuggestions.js +83 -0
- package/dist/runtime/composables/index.d.ts +11 -0
- package/dist/runtime/composables/index.js +11 -0
- package/dist/runtime/composables/useAccesibilityOutline.d.ts +41 -0
- package/dist/runtime/composables/useAccesibilityOutline.js +58 -0
- package/dist/runtime/composables/useAriaLabel.d.ts +6 -0
- package/dist/runtime/composables/useAriaLabel.js +15 -0
- package/dist/runtime/composables/useDarkMode.d.ts +38 -0
- package/dist/runtime/composables/useDarkMode.js +79 -0
- package/dist/runtime/composables/useDivideAttrs.d.ts +27 -0
- package/dist/runtime/composables/useDivideAttrs.js +26 -0
- package/dist/runtime/composables/useGlobalResizeObserver.d.ts +3 -0
- package/dist/runtime/composables/useGlobalResizeObserver.js +28 -0
- package/dist/runtime/composables/useInjectedDarkMode.d.ts +2 -0
- package/dist/runtime/composables/useInjectedDarkMode.js +13 -0
- package/dist/runtime/composables/useInjectedI18n.d.ts +2 -0
- package/dist/runtime/composables/useInjectedI18n.js +7 -0
- package/dist/runtime/composables/useInjectedLocale.d.ts +2 -0
- package/dist/runtime/composables/useInjectedLocale.js +21 -0
- package/dist/runtime/composables/useNotificationHandler.d.ts +4 -0
- package/dist/runtime/composables/useNotificationHandler.js +21 -0
- package/dist/runtime/composables/useScrollNearContainerEdges.d.ts +68 -0
- package/dist/runtime/composables/useScrollNearContainerEdges.js +116 -0
- package/dist/runtime/composables/useScrollNearContainerEdges.stories.d.ts +7 -0
- package/dist/runtime/composables/useScrollNearContainerEdges.stories.js +85 -0
- package/dist/runtime/composables/useSetupDarkMode.d.ts +12 -0
- package/dist/runtime/composables/useSetupDarkMode.js +4 -0
- package/dist/runtime/composables/useSetupI18n.d.ts +20 -0
- package/dist/runtime/composables/useSetupI18n.js +50 -0
- package/dist/runtime/composables/useSetupLocale.d.ts +9 -0
- package/dist/runtime/composables/useSetupLocale.js +21 -0
- package/dist/runtime/composables/useShowDevOnlyKey.d.ts +7 -0
- package/dist/runtime/composables/useShowDevOnlyKey.js +20 -0
- package/dist/runtime/composables/useSuggestions.d.ts +38 -0
- package/dist/runtime/composables/useSuggestions.js +226 -0
- package/dist/runtime/directives/index.d.ts +4 -0
- package/dist/runtime/directives/index.js +4 -0
- package/dist/runtime/directives/vDetectFlex.d.ts +2 -0
- package/dist/runtime/directives/vDetectFlex.js +109 -0
- package/dist/runtime/directives/vExtractRootEl.d.ts +22 -0
- package/dist/runtime/directives/vExtractRootEl.js +13 -0
- package/dist/runtime/directives/vResizableCols.d.ts +60 -0
- package/dist/runtime/directives/vResizableCols.js +252 -0
- package/dist/runtime/directives/vResizeObserver.d.ts +2 -0
- package/dist/runtime/directives/vResizeObserver.js +34 -0
- package/dist/runtime/globalResizeObserver.d.ts +5 -0
- package/dist/runtime/globalResizeObserver.js +5 -0
- package/dist/runtime/helpers/NotificationHandler.d.ts +48 -0
- package/dist/runtime/helpers/NotificationHandler.js +162 -0
- package/dist/runtime/helpers/addValue.d.ts +1 -0
- package/dist/runtime/helpers/addValue.js +8 -0
- package/dist/runtime/helpers/base64ToImg.d.ts +1 -0
- package/dist/runtime/helpers/base64ToImg.js +11 -0
- package/dist/runtime/helpers/copy.d.ts +1 -0
- package/dist/runtime/helpers/copy.js +10 -0
- package/dist/runtime/helpers/createNoonUtcDate.d.ts +7 -0
- package/dist/runtime/helpers/createNoonUtcDate.js +14 -0
- package/dist/runtime/helpers/defaultTranslationFunction.d.ts +16 -0
- package/dist/runtime/helpers/defaultTranslationFunction.js +14 -0
- package/dist/runtime/helpers/getTimeZoneList.d.ts +1 -0
- package/dist/runtime/helpers/getTimeZoneList.js +3 -0
- package/dist/runtime/helpers/hasModifiers.d.ts +1 -0
- package/dist/runtime/helpers/hasModifiers.js +1 -0
- package/dist/runtime/helpers/index.d.ts +8 -0
- package/dist/runtime/helpers/index.js +8 -0
- package/dist/runtime/helpers/readFile.d.ts +1 -0
- package/dist/runtime/helpers/readFile.js +13 -0
- package/dist/runtime/helpers/resizeObserverWrapper.d.ts +8 -0
- package/dist/runtime/helpers/resizeObserverWrapper.js +37 -0
- package/dist/runtime/helpers/storybook.d.ts +7 -0
- package/dist/runtime/helpers/storybook.js +42 -0
- package/dist/runtime/main.lib.d.ts +26 -0
- package/dist/runtime/main.lib.js +8 -0
- package/dist/runtime/nuxt/plugins/vue-plugin.d.ts +2 -0
- package/dist/runtime/nuxt/plugins/vue-plugin.js +12 -0
- package/dist/runtime/tailwind/index.d.ts +1 -0
- package/dist/runtime/tailwind/index.js +1 -0
- package/dist/runtime/tailwind/themeConvertionOpts.d.ts +2 -0
- package/dist/runtime/tailwind/themeConvertionOpts.js +12 -0
- package/dist/runtime/theme.d.ts +2 -0
- package/dist/runtime/theme.js +2 -0
- package/dist/runtime/types/index.d.ts +119 -0
- package/dist/runtime/types/index.js +0 -0
- package/dist/runtime/utils/twMerge.d.ts +10 -0
- package/dist/runtime/utils/twMerge.js +10 -0
- package/dist/runtime/vue/VueComponentsPlugin.d.ts +2 -0
- package/dist/runtime/vue/VueComponentsPlugin.js +10 -0
- package/dist/runtime/vue/registerComponents.d.ts +19 -0
- package/dist/runtime/vue/registerComponents.js +10 -0
- package/dist/runtime/vue/registerDirectives.d.ts +3 -0
- package/dist/runtime/vue/registerDirectives.js +9 -0
- package/dist/types.d.mts +7 -0
- package/dist/types.d.ts +7 -0
- package/package.json +207 -0
- package/src/module.ts +176 -0
- package/src/runtime/assets/base.css +67 -0
- package/src/runtime/assets/locales/en.json +33 -0
- package/src/runtime/assets/style.css +144 -0
- package/src/runtime/assets/tailwind.css +5 -0
- package/src/runtime/assets/theme.css +65 -0
- package/src/runtime/build/WitchcraftUiResolver.ts +27 -0
- package/src/runtime/build/generateTheme.ts +16 -0
- package/src/runtime/build/unpluginIconViteOptions.ts +11 -0
- package/src/runtime/components/Aria/Aria.vue +27 -0
- package/src/runtime/components/Focus.stories.ts +67 -0
- package/src/runtime/components/Icon/Icon.vue +39 -0
- package/src/runtime/components/LibButton/LibButton.stories.ts +107 -0
- package/src/runtime/components/LibButton/LibButton.vue +247 -0
- package/src/runtime/components/LibCheckbox/LibCheckbox.stories.ts +41 -0
- package/src/runtime/components/LibCheckbox/LibCheckbox.vue +132 -0
- package/src/runtime/components/LibColorInput/LibColorInput.stories.ts +69 -0
- package/src/runtime/components/LibColorInput/LibColorInput.vue +125 -0
- package/src/runtime/components/LibColorPicker/LibColorPicker.stories.ts +60 -0
- package/src/runtime/components/LibColorPicker/LibColorPicker.vue +448 -0
- package/src/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.ts +51 -0
- package/src/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue +95 -0
- package/src/runtime/components/LibDatePicker/LibDatePicker.stories.ts +114 -0
- package/src/runtime/components/LibDatePicker/LibDatePicker.vue +67 -0
- package/src/runtime/components/LibDatePicker/LibRangeDatePicker.vue +370 -0
- package/src/runtime/components/LibDatePicker/LibSingleDatePicker.vue +314 -0
- package/src/runtime/components/LibDatePicker/LibTimeZonePicker.vue +27 -0
- package/src/runtime/components/LibDatePicker/helpers.ts +55 -0
- package/src/runtime/components/LibDebug/LibDebug.stories.ts +58 -0
- package/src/runtime/components/LibDebug/LibDebug.vue +91 -0
- package/src/runtime/components/LibDevOnly/LibDevOnly.vue +53 -0
- package/src/runtime/components/LibFileInput/LibFileInput.stories.ts +79 -0
- package/src/runtime/components/LibFileInput/LibFileInput.vue +273 -0
- package/src/runtime/components/LibInput/LibInput.stories.ts +367 -0
- package/src/runtime/components/LibInput/LibInput.vue +372 -0
- package/src/runtime/components/LibLabel/LibLabel.stories.ts +37 -0
- package/src/runtime/components/LibLabel/LibLabel.vue +66 -0
- package/src/runtime/components/LibMultiValues/LibMultiValues.stories.ts +83 -0
- package/src/runtime/components/LibMultiValues/LibMultiValues.vue +127 -0
- package/src/runtime/components/LibNotifications/LibNotification.stories.ts +142 -0
- package/src/runtime/components/LibNotifications/LibNotification.vue +121 -0
- package/src/runtime/components/LibNotifications/LibNotifications.stories.ts +124 -0
- package/src/runtime/components/LibNotifications/LibNotifications.vue +133 -0
- package/src/runtime/components/LibPagination/LibPagination.stories.ts +53 -0
- package/src/runtime/components/LibPagination/LibPagination.vue +261 -0
- package/src/runtime/components/LibPalette/LibPalette.stories.ts +32 -0
- package/src/runtime/components/LibPalette/LibPalette.vue +49 -0
- package/src/runtime/components/LibPopup/LibPopup.stories.ts +157 -0
- package/src/runtime/components/LibPopup/LibPopup.vue +441 -0
- package/src/runtime/components/LibProgressBar/LibProgressBar.stories.ts +94 -0
- package/src/runtime/components/LibProgressBar/LibProgressBar.vue +192 -0
- package/src/runtime/components/LibRecorder/LibRecorder.stories.ts +81 -0
- package/src/runtime/components/LibRecorder/LibRecorder.vue +243 -0
- package/src/runtime/components/LibRoot/LibRoot.vue +126 -0
- package/src/runtime/components/LibSimpleInput/LibSimpleInput.stories.ts +98 -0
- package/src/runtime/components/LibSimpleInput/LibSimpleInput.vue +148 -0
- package/src/runtime/components/LibSuggestions/LibSuggestions.stories.ts +137 -0
- package/src/runtime/components/LibSuggestions/LibSuggestions.vue +198 -0
- package/src/runtime/components/LibTable/LibTable.stories.ts +170 -0
- package/src/runtime/components/LibTable/LibTable.vue +177 -0
- package/src/runtime/components/Template/NAME.vue +49 -0
- package/src/runtime/components/Template/TemplateStory.ts +38 -0
- package/src/runtime/components/TestControls/TestControls.vue +19 -0
- package/src/runtime/components/index.ts +22 -0
- package/src/runtime/components/reset.stories.ts +32 -0
- package/src/runtime/components/shared/props.ts +142 -0
- package/src/runtime/components/shared/storyHelpers/playInput.ts +35 -0
- package/src/runtime/components/shared/storyHelpers/playSuggestions.ts +105 -0
- package/src/runtime/composables/index.ts +13 -0
- package/src/runtime/composables/useAccesibilityOutline.ts +104 -0
- package/src/runtime/composables/useAriaLabel.ts +23 -0
- package/src/runtime/composables/useDarkMode.ts +146 -0
- package/src/runtime/composables/useDivideAttrs.ts +52 -0
- package/src/runtime/composables/useGlobalResizeObserver.ts +33 -0
- package/src/runtime/composables/useInjectedDarkMode.ts +15 -0
- package/src/runtime/composables/useInjectedI18n.ts +10 -0
- package/src/runtime/composables/useInjectedLocale.ts +24 -0
- package/src/runtime/composables/useNotificationHandler.ts +32 -0
- package/src/runtime/composables/useScrollNearContainerEdges.stories.ts +93 -0
- package/src/runtime/composables/useScrollNearContainerEdges.ts +205 -0
- package/src/runtime/composables/useSetupDarkMode.ts +14 -0
- package/src/runtime/composables/useSetupI18n.ts +77 -0
- package/src/runtime/composables/useSetupLocale.ts +32 -0
- package/src/runtime/composables/useShowDevOnlyKey.ts +28 -0
- package/src/runtime/composables/useSuggestions.ts +297 -0
- package/src/runtime/directives/index.ts +6 -0
- package/src/runtime/directives/vDetectFlex.ts +159 -0
- package/src/runtime/directives/vExtractRootEl.ts +38 -0
- package/src/runtime/directives/vResizableCols.ts +378 -0
- package/src/runtime/directives/vResizeObserver.ts +45 -0
- package/src/runtime/globalResizeObserver.ts +12 -0
- package/src/runtime/helpers/NotificationHandler.ts +227 -0
- package/src/runtime/helpers/addValue.ts +10 -0
- package/src/runtime/helpers/base64ToImg.ts +14 -0
- package/src/runtime/helpers/copy.ts +11 -0
- package/src/runtime/helpers/createNoonUtcDate.ts +21 -0
- package/src/runtime/helpers/defaultTranslationFunction.ts +33 -0
- package/src/runtime/helpers/getTimeZoneList.ts +4 -0
- package/src/runtime/helpers/hasModifiers.ts +1 -0
- package/src/runtime/helpers/index.ts +10 -0
- package/src/runtime/helpers/readFile.ts +22 -0
- package/src/runtime/helpers/resizeObserverWrapper.ts +45 -0
- package/src/runtime/helpers/storybook.ts +52 -0
- package/src/runtime/main.lib.ts +31 -0
- package/src/runtime/nuxt/plugins/vue-plugin.ts +19 -0
- package/src/runtime/tailwind/index.ts +3 -0
- package/src/runtime/tailwind/themeConvertionOpts.ts +15 -0
- package/src/runtime/theme.ts +5 -0
- package/src/runtime/types/index.ts +116 -0
- package/src/runtime/utils/twMerge.ts +13 -0
- package/src/runtime/vue/VueComponentsPlugin.ts +16 -0
- package/src/runtime/vue/registerComponents.ts +31 -0
- package/src/runtime/vue/registerDirectives.ts +12 -0
- package/types/components.d.ts +27 -0
- package/types/global.d.ts +16 -0
- package/types/index.d.ts +5 -0
- package/types/vite.d.ts +2 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { reactive, ref } from "vue";
|
|
2
|
+
export const useScrollNearContainerEdges = ({
|
|
3
|
+
containerEl,
|
|
4
|
+
scrollMargin = 10,
|
|
5
|
+
outerScrollMargin,
|
|
6
|
+
fastPixelMultiplier = 4,
|
|
7
|
+
fastPixelAmount,
|
|
8
|
+
useTimer = true,
|
|
9
|
+
timerInterval = 1
|
|
10
|
+
}) => {
|
|
11
|
+
fastPixelMultiplier = fastPixelAmount !== void 0 ? fastPixelAmount * 2 : fastPixelMultiplier;
|
|
12
|
+
const scrollIndicator = reactive({ left: false, right: false, down: false, up: false });
|
|
13
|
+
const isScrolling = ref(false);
|
|
14
|
+
const resetScrollIndicator = () => {
|
|
15
|
+
scrollIndicator.right = false;
|
|
16
|
+
scrollIndicator.left = false;
|
|
17
|
+
scrollIndicator.up = false;
|
|
18
|
+
scrollIndicator.down = false;
|
|
19
|
+
isScrolling.value = false;
|
|
20
|
+
};
|
|
21
|
+
let timer;
|
|
22
|
+
const scrollContainerRelative = (x, y) => {
|
|
23
|
+
const el = containerEl.value;
|
|
24
|
+
if (!el) return;
|
|
25
|
+
const leftSpace = el.scrollLeft;
|
|
26
|
+
const topSpace = el.scrollTop;
|
|
27
|
+
el.scroll(leftSpace + x, topSpace + y);
|
|
28
|
+
};
|
|
29
|
+
const move = { x: 0, y: 0 };
|
|
30
|
+
const resetMove = () => {
|
|
31
|
+
move.x = 0;
|
|
32
|
+
move.y = 0;
|
|
33
|
+
};
|
|
34
|
+
const m = scrollMargin;
|
|
35
|
+
const M = outerScrollMargin ?? 0;
|
|
36
|
+
const tryScrollContainer = (x, y) => {
|
|
37
|
+
const el = containerEl.value;
|
|
38
|
+
if (!el) return;
|
|
39
|
+
const box = el.getBoundingClientRect();
|
|
40
|
+
const leftLimit = box.x;
|
|
41
|
+
const rightLimit = box.x + box.width;
|
|
42
|
+
const topLimit = box.y;
|
|
43
|
+
const bottomLimit = box.y + box.height;
|
|
44
|
+
const leftLeftLimit = leftLimit - M;
|
|
45
|
+
const leftRightLimit = leftLimit + m;
|
|
46
|
+
const rightLeftLimit = rightLimit - M;
|
|
47
|
+
const rightRightLimit = rightLimit + m;
|
|
48
|
+
const topTopLimit = topLimit - M;
|
|
49
|
+
const topBottomLimit = topLimit + m;
|
|
50
|
+
const bottomTopLimit = bottomLimit - m;
|
|
51
|
+
const bottomBottomLimit = bottomLimit + M;
|
|
52
|
+
const t = m + M;
|
|
53
|
+
resetScrollIndicator();
|
|
54
|
+
resetMove();
|
|
55
|
+
if (x > leftLeftLimit && x < leftRightLimit) {
|
|
56
|
+
const leftSpace = el.scrollLeft;
|
|
57
|
+
if (leftSpace > 0) {
|
|
58
|
+
const edgeOffset = (leftLimit + m - x) / t;
|
|
59
|
+
move.x = -edgeOffset * fastPixelMultiplier;
|
|
60
|
+
}
|
|
61
|
+
} else if (x > rightLeftLimit && x < rightRightLimit) {
|
|
62
|
+
const rightSpace = el.scrollWidth - el.scrollLeft - Math.round(box.width);
|
|
63
|
+
if (rightSpace > 0) {
|
|
64
|
+
const edgeOffset = (x - (rightLimit - m)) / t;
|
|
65
|
+
move.x = edgeOffset * fastPixelMultiplier;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (y > topTopLimit && y < topBottomLimit) {
|
|
69
|
+
const topSpace = el.scrollTop;
|
|
70
|
+
if (topSpace > 0) {
|
|
71
|
+
const edgeOffset = (topLimit + m - y) / t;
|
|
72
|
+
move.y = -edgeOffset * fastPixelMultiplier;
|
|
73
|
+
}
|
|
74
|
+
} else if (y > bottomTopLimit && y < bottomBottomLimit) {
|
|
75
|
+
const bottomSpace = el.scrollHeight - el.scrollTop - Math.round(box.height);
|
|
76
|
+
if (bottomSpace > 0) {
|
|
77
|
+
const edgeOffset = (y - (bottomLimit - m)) / t;
|
|
78
|
+
move.y = edgeOffset * fastPixelMultiplier;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (move.x !== 0 || move.y !== 0) {
|
|
82
|
+
isScrolling.value = true;
|
|
83
|
+
scrollIndicator.right = move.x > 0;
|
|
84
|
+
scrollIndicator.left = move.x < 0;
|
|
85
|
+
scrollIndicator.up = move.y < 0;
|
|
86
|
+
scrollIndicator.down = move.y > 0;
|
|
87
|
+
scrollContainerRelative(move.x, move.y);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const clearScrollInterval = () => {
|
|
91
|
+
clearInterval(timer);
|
|
92
|
+
};
|
|
93
|
+
const scrollEdges = (clientX, clientY, overrideUseTimer) => {
|
|
94
|
+
clearInterval(timer);
|
|
95
|
+
tryScrollContainer(clientX, clientY);
|
|
96
|
+
if (overrideUseTimer ? overrideUseTimer : useTimer) {
|
|
97
|
+
timer = setInterval(() => {
|
|
98
|
+
tryScrollContainer(clientX, clientY);
|
|
99
|
+
}, timerInterval);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const endScroll = () => {
|
|
103
|
+
clearScrollInterval();
|
|
104
|
+
resetScrollIndicator();
|
|
105
|
+
resetMove();
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
scrollEdges,
|
|
109
|
+
scrollIndicator,
|
|
110
|
+
resetScrollIndicator,
|
|
111
|
+
clearScrollInterval,
|
|
112
|
+
isScrolling,
|
|
113
|
+
endScroll
|
|
114
|
+
/* resetMove does not need to be returned since the user cannot call the timer interval manually and the scrollContainer function resets it before starting. */
|
|
115
|
+
};
|
|
116
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { onMounted, ref } from "vue";
|
|
2
|
+
import { useScrollNearContainerEdges } from "./useScrollNearContainerEdges.js";
|
|
3
|
+
import { twMerge } from "../utils/twMerge.js";
|
|
4
|
+
const meta = {
|
|
5
|
+
title: "Composables/ScrollNearContainerEdges"
|
|
6
|
+
};
|
|
7
|
+
export default meta;
|
|
8
|
+
export const Primary = {
|
|
9
|
+
render: (args) => ({
|
|
10
|
+
setup: () => {
|
|
11
|
+
const containerEl = ref(null);
|
|
12
|
+
const {
|
|
13
|
+
resetScrollIndicator,
|
|
14
|
+
scrollEdges,
|
|
15
|
+
endScroll,
|
|
16
|
+
scrollIndicator,
|
|
17
|
+
isScrolling
|
|
18
|
+
} = useScrollNearContainerEdges({
|
|
19
|
+
containerEl,
|
|
20
|
+
scrollMargin: 20,
|
|
21
|
+
outerScrollMargin: 20
|
|
22
|
+
});
|
|
23
|
+
const pos = ref({ x: 0, y: 0 });
|
|
24
|
+
onMounted(() => {
|
|
25
|
+
pos.value.x = containerEl.value.getBoundingClientRect().left;
|
|
26
|
+
pos.value.y = containerEl.value.getBoundingClientRect().top;
|
|
27
|
+
});
|
|
28
|
+
const moveDrag = (e) => {
|
|
29
|
+
pos.value.x = e.clientX;
|
|
30
|
+
pos.value.y = e.clientY;
|
|
31
|
+
scrollEdges(e.clientX, e.clientY);
|
|
32
|
+
};
|
|
33
|
+
const endDrag = (_e) => {
|
|
34
|
+
endScroll();
|
|
35
|
+
document.removeEventListener("mousemove", moveDrag);
|
|
36
|
+
document.removeEventListener("mouseup", endDrag);
|
|
37
|
+
};
|
|
38
|
+
const startDrag = (_e) => {
|
|
39
|
+
document.addEventListener("mousemove", moveDrag);
|
|
40
|
+
document.addEventListener("mouseup", endDrag);
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
args,
|
|
44
|
+
containerEl,
|
|
45
|
+
resetScrollIndicator,
|
|
46
|
+
scrollEdges,
|
|
47
|
+
endScroll,
|
|
48
|
+
startDrag,
|
|
49
|
+
scrollIndicator,
|
|
50
|
+
isScrolling,
|
|
51
|
+
twMerge,
|
|
52
|
+
pos
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
template: `
|
|
56
|
+
<div>
|
|
57
|
+
<p>Scroll the container by dragging the red box (which represents the dragging mouse position).</p>
|
|
58
|
+
<p>It should drag slow, then faster as the mouse nears the edges and scroll indicators should appear on the scrolling edges.</p>
|
|
59
|
+
</div>
|
|
60
|
+
<div
|
|
61
|
+
:class="twMerge(
|
|
62
|
+
'relative flex flex-col max-h-[300px] max-w-[300px] border-2 border-red-500',
|
|
63
|
+
isScrolling && 'after:content-[\\'\\'] after:absolute after:inset-0 after:border-transparent after:border-[15px]',
|
|
64
|
+
scrollIndicator.right && 'after:border-r-accent-500/60',
|
|
65
|
+
scrollIndicator.down && 'after:border-b-accent-500/60',
|
|
66
|
+
scrollIndicator.left && 'after:border-l-accent-500/60',
|
|
67
|
+
scrollIndicator.up && 'after:border-t-accent-500/60',
|
|
68
|
+
)"
|
|
69
|
+
|
|
70
|
+
>
|
|
71
|
+
<div
|
|
72
|
+
class="overflow-auto"
|
|
73
|
+
ref="containerEl"
|
|
74
|
+
>
|
|
75
|
+
<div class="h-[1000px] w-[1000px]"/>
|
|
76
|
+
<div
|
|
77
|
+
@mousedown="startDrag"
|
|
78
|
+
:style="\`top:\${pos.y}px; left:\${pos.x}px;\`"
|
|
79
|
+
class="h-[20px] w-[20px] -ml-[10px] -mt-[10px] bg-red-500 cursor-move fixed"
|
|
80
|
+
></div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
`
|
|
84
|
+
})
|
|
85
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useDarkMode } from "./useDarkMode.js.js";
|
|
2
|
+
/**
|
|
3
|
+
* A composable for setting up dark mode that automatically takes care of saving the user's preference.
|
|
4
|
+
*
|
|
5
|
+
* See the returned utilities for more details.
|
|
6
|
+
*
|
|
7
|
+
* Use it's twin, `useInjectedDarkMode` for accessing the injected state and commands in components
|
|
8
|
+
*
|
|
9
|
+
* Note that this should only be called once at the root of the app.
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
12
|
+
export declare function useSetupDarkMode(...args: Parameters<typeof useDarkMode>): ReturnType<typeof useDarkMode>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type InjectionKey, type Ref } from "vue";
|
|
2
|
+
export type TranslationFunction = (key: string, replacements?: Record<string, any>) => string;
|
|
3
|
+
/**
|
|
4
|
+
* A composable for providing a translation function + messages for the library. Note the Root component already takes care of setting this up with defaults, disable it via it's `useBuiltinTranslations` option.
|
|
5
|
+
*
|
|
6
|
+
* Should be called only once. You can choose to await it or not (see the `useDummyMessageSetWhileLoading` option).
|
|
7
|
+
*
|
|
8
|
+
* A default function is available, see {@link defaultTranslationFunction}.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useSetupI18n({ locale, useBuiltinTranslations, useDummyMessageSetWhileLoading, translationFunction, }: {
|
|
11
|
+
locale: Ref<string>;
|
|
12
|
+
/** Will asynchronously load the built-in translations for the current locale (watching and updating if needed). If you don't use this, you'll need to provide a custom translation function. */
|
|
13
|
+
useBuiltinTranslations?: boolean;
|
|
14
|
+
/** To avoid having to wrap the component in a Suspense component because of the await on `useSetupI18n`, we can provide a dummy message proxy that just returns empty text until the messages are loaded. */
|
|
15
|
+
useDummyMessageSetWhileLoading?: boolean;
|
|
16
|
+
/** A custom translation function. The default requires the `useBuiltinTranslations` option to be true. */
|
|
17
|
+
translationFunction?: TranslationFunction;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
export declare const i18nInjectionKey: InjectionKey<TranslationFunction>;
|
|
20
|
+
export declare const translationMessagesInjectionKey: InjectionKey<Ref<Record<string, any>, Record<string, any>>>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
provide,
|
|
3
|
+
ref,
|
|
4
|
+
watch
|
|
5
|
+
} from "vue";
|
|
6
|
+
import { defaultTranslationFunction } from "../helpers/defaultTranslationFunction.js";
|
|
7
|
+
const _i18nInjectionKey = Symbol("witchcraftUiI18n");
|
|
8
|
+
const _translationMessagesInjectionKey = Symbol("witchcraftUiI18nMessages");
|
|
9
|
+
const messagesGlob = import.meta.glob("../assets/locales/*.json");
|
|
10
|
+
const loaded = {};
|
|
11
|
+
const dummyLibraryMessages = new Proxy({}, {
|
|
12
|
+
get() {
|
|
13
|
+
return "...";
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
const dummyMessageSet = new Proxy({}, {
|
|
17
|
+
get(_, key) {
|
|
18
|
+
if (key === "witchcraft-ui") {
|
|
19
|
+
return dummyLibraryMessages;
|
|
20
|
+
} else return void 0;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
export async function useSetupI18n({
|
|
24
|
+
locale,
|
|
25
|
+
useBuiltinTranslations = false,
|
|
26
|
+
useDummyMessageSetWhileLoading = true,
|
|
27
|
+
translationFunction = defaultTranslationFunction
|
|
28
|
+
}) {
|
|
29
|
+
provide(_i18nInjectionKey, translationFunction);
|
|
30
|
+
if (useBuiltinTranslations) {
|
|
31
|
+
const messages = ref(useDummyMessageSetWhileLoading ? dummyMessageSet : {});
|
|
32
|
+
provide(_translationMessagesInjectionKey, messages);
|
|
33
|
+
async function loadMessageSet(l) {
|
|
34
|
+
const isLoaded = loaded[l];
|
|
35
|
+
if (isLoaded) {
|
|
36
|
+
messages.value = loaded[l];
|
|
37
|
+
} else {
|
|
38
|
+
const newMessages = (await messagesGlob[`../assets/locales/${l}.json`]()).default;
|
|
39
|
+
loaded[l] = newMessages;
|
|
40
|
+
messages.value = newMessages;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
void loadMessageSet(locale.value);
|
|
44
|
+
watch(locale, async () => {
|
|
45
|
+
void loadMessageSet(locale.value);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export const i18nInjectionKey = _i18nInjectionKey;
|
|
50
|
+
export const translationMessagesInjectionKey = _translationMessagesInjectionKey;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type InjectionKey, type Ref } from "vue";
|
|
2
|
+
export declare const languageLocaleInjectionKey: InjectionKey<Ref<string>>;
|
|
3
|
+
export declare const timeLocaleInjectionKey: InjectionKey<Ref<string>>;
|
|
4
|
+
export declare function useSetupLocale(): {
|
|
5
|
+
languageLocale: Ref<string>;
|
|
6
|
+
timeLocale: Ref<string>;
|
|
7
|
+
setLanguageLocale: (value: string) => void;
|
|
8
|
+
setTimeLocale: (value: string) => void;
|
|
9
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { provide, ref } from "vue";
|
|
2
|
+
export const languageLocaleInjectionKey = Symbol("witchcraftUiLanguageLocale");
|
|
3
|
+
export const timeLocaleInjectionKey = Symbol("witchcraftUiTimeLocale");
|
|
4
|
+
export function useSetupLocale() {
|
|
5
|
+
const languageLocale = ref("en");
|
|
6
|
+
const timeLocale = ref("en-GB");
|
|
7
|
+
function setLanguageLocale(value) {
|
|
8
|
+
languageLocale.value = value;
|
|
9
|
+
}
|
|
10
|
+
function setTimeLocale(value) {
|
|
11
|
+
timeLocale.value = value;
|
|
12
|
+
}
|
|
13
|
+
provide(languageLocaleInjectionKey, languageLocale);
|
|
14
|
+
provide(timeLocaleInjectionKey, timeLocale);
|
|
15
|
+
return {
|
|
16
|
+
languageLocale,
|
|
17
|
+
timeLocale,
|
|
18
|
+
setLanguageLocale,
|
|
19
|
+
setTimeLocale
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* For nuxt only.
|
|
3
|
+
*
|
|
4
|
+
* Communicates with the dev only component to show/hide it depending on a keypress (single key, no modifiers, `F1` by default). *
|
|
5
|
+
*/
|
|
6
|
+
export declare function useShowDevOnlyKey(key?: string): void;
|
|
7
|
+
export declare const showDevOnlyInjectionKey: symbol;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { onBeforeUnmount, onMounted, provide, ref } from "vue";
|
|
2
|
+
const injectionKey = Symbol("showDevOnly");
|
|
3
|
+
export function useShowDevOnlyKey(key = "F1") {
|
|
4
|
+
if (!import.meta.dev) return;
|
|
5
|
+
const showDevOnly = ref(false);
|
|
6
|
+
provide(injectionKey, showDevOnly);
|
|
7
|
+
const listener = (e) => {
|
|
8
|
+
if (e.key === key && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
9
|
+
showDevOnly.value = !showDevOnly.value;
|
|
10
|
+
e.preventDefault();
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
onMounted(() => {
|
|
14
|
+
document.addEventListener("keydown", listener);
|
|
15
|
+
});
|
|
16
|
+
onBeforeUnmount(() => {
|
|
17
|
+
document.removeEventListener("keydown", listener);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export const showDevOnlyInjectionKey = injectionKey;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type Ref } from "vue";
|
|
2
|
+
import { type SuggestionsEmits, type SuggestionsOptions } from "../components/shared/props.js.js";
|
|
3
|
+
/**
|
|
4
|
+
* The logic for the suggestions component.
|
|
5
|
+
*
|
|
6
|
+
* Note that while object suggestions are supported, the `suggestionLabel` prop is required and $inputModel and $modelValue will still be string values (as returned by the suggestionLabel function).
|
|
7
|
+
*/
|
|
8
|
+
export declare function useSuggestions<TSuggestion>($inputValue: Ref<string>, $modelValue: Ref<string>, emit: SuggestionsEmits, opts: SuggestionsOptions<TSuggestion>, debug?: boolean): {
|
|
9
|
+
list: import("vue").ComputedRef<any[] | undefined>;
|
|
10
|
+
filtered: import("vue").ComputedRef<any[] | undefined>;
|
|
11
|
+
active: Ref<number, number>;
|
|
12
|
+
available: import("vue").ComputedRef<boolean>;
|
|
13
|
+
moreThanOneAvailable: import("vue").ComputedRef<boolean>;
|
|
14
|
+
hasExactlyMatching: import("vue").ComputedRef<TSuggestion | undefined>;
|
|
15
|
+
/** Whether there is a valid suggestion that can be submitted. If `restrictToSuggestions` is true, this will be true if isValid is true, otherwise this is considered to be true if suggestions are available. */
|
|
16
|
+
hasValidSuggestion: import("vue").ComputedRef<boolean>;
|
|
17
|
+
openable: import("vue").ComputedRef<boolean | undefined>;
|
|
18
|
+
getLabel: (item: any) => string;
|
|
19
|
+
isOpen: Ref<boolean, boolean>;
|
|
20
|
+
open: () => void;
|
|
21
|
+
close: () => void;
|
|
22
|
+
enterSelected: () => void;
|
|
23
|
+
enterSuggestion: (num: number) => void;
|
|
24
|
+
toggle: () => void;
|
|
25
|
+
cancel: () => void;
|
|
26
|
+
select: (num: number) => void;
|
|
27
|
+
prev: () => void;
|
|
28
|
+
next: () => void;
|
|
29
|
+
first: () => void;
|
|
30
|
+
last: () => void;
|
|
31
|
+
};
|
|
32
|
+
export declare function useSuggestionsInputAria(id: Ref<string>, isOpen: Ref<boolean>, activeSuggestion: Ref<number>, suggestions: Ref<any | undefined>): import("vue").ComputedRef<{
|
|
33
|
+
"aria-autocomplete": "both" | undefined;
|
|
34
|
+
"aria-controls": string | undefined;
|
|
35
|
+
role: string | undefined;
|
|
36
|
+
"aria-expanded": boolean | undefined;
|
|
37
|
+
"aria-activedescendant": string | undefined;
|
|
38
|
+
}>;
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { isBlank } from "@alanscodelog/utils/isBlank.js";
|
|
2
|
+
import { isObject } from "@alanscodelog/utils/isObject.js";
|
|
3
|
+
import { computed, ref, toRaw, watch } from "vue";
|
|
4
|
+
export function useSuggestions($inputValue, $modelValue, emit, opts, debug = false) {
|
|
5
|
+
if (typeof opts.suggestions?.[0] === "object" && !opts.suggestionLabel && !opts.suggestionsFilter) {
|
|
6
|
+
throw new Error("`suggestionLabel` or `suggestionsFilter` must be passed if suggestions are objects.");
|
|
7
|
+
}
|
|
8
|
+
const isOpen = ref(false);
|
|
9
|
+
const activeSuggestion = ref(-1);
|
|
10
|
+
watch(isOpen, (val) => {
|
|
11
|
+
emit("update:isOpen", val);
|
|
12
|
+
});
|
|
13
|
+
watch(activeSuggestion, (val) => {
|
|
14
|
+
emit("update:activeSuggestion", val);
|
|
15
|
+
});
|
|
16
|
+
const suggestionKey = (item) => {
|
|
17
|
+
if (isObject(item)) {
|
|
18
|
+
if (opts.suggestionLabel) {
|
|
19
|
+
return opts.suggestionLabel(item);
|
|
20
|
+
}
|
|
21
|
+
throw new Error("`suggestionLabel` must be passed if suggestions are objects.");
|
|
22
|
+
}
|
|
23
|
+
return item;
|
|
24
|
+
};
|
|
25
|
+
const getSuggestionLabel = (item) => opts.suggestionLabel?.(item) ?? suggestionKey(item) ?? "";
|
|
26
|
+
const defaultSuggestionsFilter = (input, items) => input === "" ? [...items] : items.filter((item) => getSuggestionLabel(item).toLowerCase().includes(input.toLowerCase()));
|
|
27
|
+
const suggestionsFilter = computed(() => opts.suggestionsFilter ?? defaultSuggestionsFilter);
|
|
28
|
+
const suggestionsList = computed(() => {
|
|
29
|
+
if (opts.suggestions) {
|
|
30
|
+
const res = suggestionsFilter.value($inputValue.value, opts.suggestions);
|
|
31
|
+
return res;
|
|
32
|
+
}
|
|
33
|
+
return void 0;
|
|
34
|
+
});
|
|
35
|
+
const suggestionAvailable = computed(() => (suggestionsList.value?.length ?? 0) > 0);
|
|
36
|
+
const moreThanOneSuggestionAvailable = computed(() => (suggestionsList.value?.length ?? 0) > 1);
|
|
37
|
+
const exactlyMatchingSuggestion = computed(() => opts.suggestions?.find((suggestion) => $inputValue.value === getSuggestionLabel(suggestion)));
|
|
38
|
+
const isValidSuggestion = computed(() => !opts.restrictToSuggestions && opts.isValid || suggestionAvailable.value);
|
|
39
|
+
const openable = computed(
|
|
40
|
+
() => opts.canOpen && (isBlank($inputValue.value) && opts.allowOpenEmpty || suggestionAvailable.value)
|
|
41
|
+
);
|
|
42
|
+
const filteredSuggestions = computed(() => {
|
|
43
|
+
if (opts.suggestions) {
|
|
44
|
+
const res = suggestionAvailable.value ? suggestionsList.value : opts.suggestions;
|
|
45
|
+
if (opts.restrictToSuggestions && !isValidSuggestion.value) return res;
|
|
46
|
+
if (opts.preventDuplicateValues && opts.values) {
|
|
47
|
+
return res.filter((suggestion) => !opts.values.includes(suggestionKey(suggestion)));
|
|
48
|
+
}
|
|
49
|
+
return res;
|
|
50
|
+
}
|
|
51
|
+
return void 0;
|
|
52
|
+
});
|
|
53
|
+
const closeSuggestions = () => {
|
|
54
|
+
if (debug) console.log("closeSuggestions");
|
|
55
|
+
isOpen.value = false;
|
|
56
|
+
activeSuggestion.value = -1;
|
|
57
|
+
};
|
|
58
|
+
const openSuggestions = () => {
|
|
59
|
+
if (debug) console.log("openSuggestions", { openable: openable.value });
|
|
60
|
+
if (!openable.value) return;
|
|
61
|
+
if (activeSuggestion.value === -1) {
|
|
62
|
+
if (exactlyMatchingSuggestion.value) {
|
|
63
|
+
activeSuggestion.value = suggestionsList.value?.indexOf(exactlyMatchingSuggestion.value) ?? -1;
|
|
64
|
+
} else {
|
|
65
|
+
activeSuggestion.value = 0;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
isOpen.value = true;
|
|
69
|
+
};
|
|
70
|
+
function enterSuggestion(num) {
|
|
71
|
+
if (num < -1 || num > (filteredSuggestions.value?.length ?? 0)) return;
|
|
72
|
+
if (debug) console.log("enterSuggestion", num);
|
|
73
|
+
if (filteredSuggestions.value === void 0) return;
|
|
74
|
+
const suggestion = filteredSuggestions.value[num];
|
|
75
|
+
const val = suggestionKey(suggestion);
|
|
76
|
+
$modelValue.value = val;
|
|
77
|
+
$inputValue.value = getSuggestionLabel(suggestion);
|
|
78
|
+
closeSuggestions();
|
|
79
|
+
emit("submit", val, toRaw(suggestion));
|
|
80
|
+
}
|
|
81
|
+
const enterSelected = () => {
|
|
82
|
+
if (activeSuggestion.value === -1) {
|
|
83
|
+
if (!opts.restrictToSuggestions) {
|
|
84
|
+
if (debug) console.log("enterSelected, unrestricted, emitting submit");
|
|
85
|
+
emit("submit", $inputValue.value);
|
|
86
|
+
} else {
|
|
87
|
+
if (debug) console.log("enterSelected, no active suggestion, ignoring");
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (debug) console.log("enterSelected");
|
|
92
|
+
enterSuggestion(activeSuggestion.value);
|
|
93
|
+
};
|
|
94
|
+
const selectSuggestion = (num) => {
|
|
95
|
+
if (debug) console.log("selectSuggestion", num);
|
|
96
|
+
if (num >= -1) {
|
|
97
|
+
activeSuggestion.value = num;
|
|
98
|
+
}
|
|
99
|
+
if (num === Infinity && (filteredSuggestions.value?.length ?? 0) > 0) {
|
|
100
|
+
activeSuggestion.value = filteredSuggestions.value.length - 1;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const toggleSuggestions = () => {
|
|
104
|
+
isOpen.value ? closeSuggestions() : openSuggestions();
|
|
105
|
+
};
|
|
106
|
+
const prevSuggestion = () => {
|
|
107
|
+
if (!filteredSuggestions.value) return;
|
|
108
|
+
if (activeSuggestion.value > 0) {
|
|
109
|
+
activeSuggestion.value--;
|
|
110
|
+
} else if (filteredSuggestions.value) {
|
|
111
|
+
activeSuggestion.value = filteredSuggestions.value.length - 1;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const nextSuggestion = () => {
|
|
115
|
+
if (!filteredSuggestions.value) return;
|
|
116
|
+
if (activeSuggestion.value >= filteredSuggestions.value.length - 1) {
|
|
117
|
+
activeSuggestion.value = 0;
|
|
118
|
+
} else {
|
|
119
|
+
activeSuggestion.value++;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const firstSuggestion = () => {
|
|
123
|
+
selectSuggestion(0);
|
|
124
|
+
};
|
|
125
|
+
const lastSuggestion = () => {
|
|
126
|
+
selectSuggestion(Infinity);
|
|
127
|
+
};
|
|
128
|
+
const cancel = () => {
|
|
129
|
+
if (debug) console.log("cancel");
|
|
130
|
+
$inputValue.value = getSuggestionLabel($modelValue.value);
|
|
131
|
+
closeSuggestions();
|
|
132
|
+
};
|
|
133
|
+
watch(() => opts.canOpen, (val) => {
|
|
134
|
+
if (!val) {
|
|
135
|
+
if (debug) console.log("canOpen changed to false, closing suggestions");
|
|
136
|
+
closeSuggestions();
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
watch(openable, (val) => {
|
|
140
|
+
if (!val) {
|
|
141
|
+
if (debug) console.log("openable changed to false, closing suggestions");
|
|
142
|
+
closeSuggestions();
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
watch(isValidSuggestion, () => {
|
|
146
|
+
if (!isValidSuggestion.value) {
|
|
147
|
+
if (debug) console.log("isValidSuggestion changed to false, opening suggestions");
|
|
148
|
+
openSuggestions();
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
watch($modelValue, () => {
|
|
152
|
+
$inputValue.value = getSuggestionLabel($modelValue.value);
|
|
153
|
+
if (debug) console.log("modelValue changed");
|
|
154
|
+
});
|
|
155
|
+
const defaultSuggestionSelector = (suggestions, input) => {
|
|
156
|
+
if (input.length === 0) return 0;
|
|
157
|
+
let longestMatch;
|
|
158
|
+
let ii = -1;
|
|
159
|
+
for (let i = 0; i < suggestions.length; i++) {
|
|
160
|
+
const suggestion = suggestions[i];
|
|
161
|
+
const label = getSuggestionLabel(suggestion);
|
|
162
|
+
const labelPart = label.slice(0, input.length);
|
|
163
|
+
if (labelPart === input) {
|
|
164
|
+
if (label.length > (longestMatch?.[0]?.length ?? 0)) {
|
|
165
|
+
longestMatch = label;
|
|
166
|
+
ii = i;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return ii;
|
|
171
|
+
};
|
|
172
|
+
watch($inputValue, () => {
|
|
173
|
+
if (debug) console.log("input changed:", $inputValue.value, "modelValue:", $modelValue.value);
|
|
174
|
+
if (getSuggestionLabel($modelValue.value) === $inputValue.value) return;
|
|
175
|
+
if (suggestionAvailable.value) {
|
|
176
|
+
if (debug) console.log("input changed, suggestion available, opening suggestions");
|
|
177
|
+
openSuggestions();
|
|
178
|
+
}
|
|
179
|
+
if (!opts.restrictToSuggestions) {
|
|
180
|
+
if (debug) console.log("input changed, unrestricted, setting modelValue");
|
|
181
|
+
$modelValue.value = $inputValue.value;
|
|
182
|
+
}
|
|
183
|
+
if (exactlyMatchingSuggestion.value && suggestionsList.value) {
|
|
184
|
+
if (debug) console.log("input changed, exactly matching, setting activeSuggestion");
|
|
185
|
+
selectSuggestion(suggestionsList.value.indexOf(exactlyMatchingSuggestion.value));
|
|
186
|
+
} else {
|
|
187
|
+
if (debug) console.log("input changed, not exactly matching, finding longest match");
|
|
188
|
+
const i = opts.suggestionSelector?.(filteredSuggestions.value ?? [], $inputValue.value) ?? defaultSuggestionSelector(filteredSuggestions.value ?? [], $inputValue.value);
|
|
189
|
+
selectSuggestion(i);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
return {
|
|
193
|
+
list: suggestionsList,
|
|
194
|
+
filtered: filteredSuggestions,
|
|
195
|
+
active: activeSuggestion,
|
|
196
|
+
available: suggestionAvailable,
|
|
197
|
+
moreThanOneAvailable: moreThanOneSuggestionAvailable,
|
|
198
|
+
hasExactlyMatching: exactlyMatchingSuggestion,
|
|
199
|
+
/** Whether there is a valid suggestion that can be submitted. If `restrictToSuggestions` is true, this will be true if isValid is true, otherwise this is considered to be true if suggestions are available. */
|
|
200
|
+
hasValidSuggestion: isValidSuggestion,
|
|
201
|
+
openable,
|
|
202
|
+
getLabel: getSuggestionLabel,
|
|
203
|
+
isOpen,
|
|
204
|
+
open: openSuggestions,
|
|
205
|
+
close: closeSuggestions,
|
|
206
|
+
enterSelected,
|
|
207
|
+
enterSuggestion,
|
|
208
|
+
toggle: toggleSuggestions,
|
|
209
|
+
cancel,
|
|
210
|
+
select: selectSuggestion,
|
|
211
|
+
prev: prevSuggestion,
|
|
212
|
+
next: nextSuggestion,
|
|
213
|
+
first: firstSuggestion,
|
|
214
|
+
last: lastSuggestion
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
export function useSuggestionsInputAria(id, isOpen, activeSuggestion, suggestions) {
|
|
218
|
+
const ariaInputProps = computed(() => ({
|
|
219
|
+
"aria-autocomplete": suggestions !== void 0 ? "both" : void 0,
|
|
220
|
+
"aria-controls": suggestions !== void 0 ? `suggestions-${id.value}` : void 0,
|
|
221
|
+
role: suggestions ? "combobox" : void 0,
|
|
222
|
+
"aria-expanded": suggestions !== void 0 ? isOpen.value : void 0,
|
|
223
|
+
"aria-activedescendant": isOpen.value ? `suggestion-${id.value}-${activeSuggestion.value}` : void 0
|
|
224
|
+
}));
|
|
225
|
+
return ariaInputProps;
|
|
226
|
+
}
|