@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,159 @@
|
|
|
1
|
+
import { castType } from "@alanscodelog/utils/castType.js"
|
|
2
|
+
import { last } from "@alanscodelog/utils/last.js"
|
|
3
|
+
import { throttle } from "@alanscodelog/utils/throttle.js"
|
|
4
|
+
import { unreachable } from "@alanscodelog/utils/unreachable.js"
|
|
5
|
+
import type { Directive } from "vue"
|
|
6
|
+
|
|
7
|
+
import { globalResizeObserver } from "../globalResizeObserver.js"
|
|
8
|
+
import type { ResizeCallback } from "../types/index.js"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const observer = globalResizeObserver
|
|
12
|
+
/**
|
|
13
|
+
* Directive for detecting flex wrap on element. It will bind a resize-observer to the element to detect when it's children have wrapped and add a .wrapped class when they are.
|
|
14
|
+
*
|
|
15
|
+
* The directive throttles the observer callback by 50ms by default and ignored children elements with the `.detect-flex-ignore` selector, both are configurable.
|
|
16
|
+
*
|
|
17
|
+
* If you only want the listener attached sometimes you can pass `{condition:yourCondition}`, this option is reactive.
|
|
18
|
+
*
|
|
19
|
+
* By default it detects row wrapping, pass `vertical:true` for column wrapping.
|
|
20
|
+
* ```vue
|
|
21
|
+
* <!--parent-->
|
|
22
|
+
* <div v-detect-flex="{vertical: false, condition: yourCondition, ignoreSelector: `detect-flex-ignore`, throttle: 500}">
|
|
23
|
+
* <div><div/> <!--child-->
|
|
24
|
+
* <div><div/> <!--child-->
|
|
25
|
+
* </div>
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* This just checks the first child element is below the last element, so it might not work in some cases, but for most purposes works fine.
|
|
29
|
+
*
|
|
30
|
+
*/
|
|
31
|
+
type PrivateState = {
|
|
32
|
+
lastCondition: boolean
|
|
33
|
+
lastThrottleTime: number
|
|
34
|
+
callback?: typeof callback
|
|
35
|
+
vertical: boolean
|
|
36
|
+
ignoreSelector: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const callbacks: Record<number, { count: number, callback: typeof callback }> = {}
|
|
40
|
+
const elMap = new WeakMap<HTMLElement, PrivateState>()
|
|
41
|
+
|
|
42
|
+
function getOrCreateCallback(throttleTime: number): ResizeCallback {
|
|
43
|
+
if (callbacks[throttleTime]) {
|
|
44
|
+
callbacks[throttleTime].count++
|
|
45
|
+
} else {
|
|
46
|
+
callbacks[throttleTime] = { count: 1, callback: throttle(callback, throttleTime) }
|
|
47
|
+
}
|
|
48
|
+
return callbacks[throttleTime].callback
|
|
49
|
+
}
|
|
50
|
+
function removeCallback(throttleTime: number): void {
|
|
51
|
+
if (callbacks[throttleTime]) {
|
|
52
|
+
callbacks[throttleTime].count--
|
|
53
|
+
if (callbacks[throttleTime].count === 0) delete callbacks[throttleTime]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function callback(_rect: DOMRectReadOnly, el: Element): void {
|
|
58
|
+
const _ = elMap.get(el as HTMLElement)
|
|
59
|
+
if (!_) {unreachable()}
|
|
60
|
+
const pos = _.vertical ? "x" : "y"
|
|
61
|
+
const dimension = _.vertical ? "width" : "height"
|
|
62
|
+
|
|
63
|
+
castType<HTMLElement>(el)
|
|
64
|
+
|
|
65
|
+
const filteredChildren = Array.from(el.children).filter(child => _.ignoreSelector && !child.matches(_.ignoreSelector))
|
|
66
|
+
const firstChild = filteredChildren[0]
|
|
67
|
+
const lastChild = last(filteredChildren)
|
|
68
|
+
|
|
69
|
+
if (firstChild === undefined || firstChild === lastChild) {
|
|
70
|
+
// eslint-disable-next-line no-console
|
|
71
|
+
console.warn("detect-flex directive detected there are less than two child elements.")
|
|
72
|
+
// eslint-disable-next-line no-console
|
|
73
|
+
console.warn(el)
|
|
74
|
+
el.classList.remove("wrapped")
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const firstRect = firstChild.getBoundingClientRect()
|
|
79
|
+
const lastRect = lastChild.getBoundingClientRect()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
// should work even if the flex items are different heights
|
|
83
|
+
// only exceptions i think are if the element aligns itself below another element somehow
|
|
84
|
+
// rounded to nearest 10th since getBoundingClientRect can have rounding errors
|
|
85
|
+
if (Math.round(10 * (firstRect[pos] + firstRect[dimension] - lastRect[pos])) * 10 <= 0) {
|
|
86
|
+
el.classList.add("wrapped")
|
|
87
|
+
} else {
|
|
88
|
+
el.classList.remove("wrapped")
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
export const vDetectFlex: Directive = {
|
|
94
|
+
mounted(el: HTMLElement, { value: { condition = true, vertical = false, throttleTime = 50, ignoreSelector = ".detect-flex-ignore" } = {} }: DetectFlexOptions) {
|
|
95
|
+
const _: PrivateState = {
|
|
96
|
+
vertical,
|
|
97
|
+
lastCondition: condition,
|
|
98
|
+
lastThrottleTime: throttleTime,
|
|
99
|
+
ignoreSelector,
|
|
100
|
+
}
|
|
101
|
+
elMap.set(el, _)
|
|
102
|
+
if (condition) {
|
|
103
|
+
_.callback = getOrCreateCallback(throttleTime)
|
|
104
|
+
observer.observe(el, _.callback)
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
updated(el: HTMLElement, { value: { condition = true, vertical = false, throttleTime = 50, ignoreSelector = ".detect-flex-ignore" } = {} }: DetectFlexOptions) {
|
|
108
|
+
const _ = elMap.get(el)
|
|
109
|
+
if (!_) {unreachable()}
|
|
110
|
+
|
|
111
|
+
_.vertical = vertical
|
|
112
|
+
_.ignoreSelector = ignoreSelector
|
|
113
|
+
if (throttleTime !== _.lastThrottleTime) {
|
|
114
|
+
if (condition && _.lastCondition) {
|
|
115
|
+
if (!_.callback) unreachable()
|
|
116
|
+
observer.unobserve(el, _.callback)
|
|
117
|
+
removeCallback(_.lastThrottleTime)
|
|
118
|
+
_.callback = getOrCreateCallback(throttleTime)
|
|
119
|
+
observer.observe(el, _.callback)
|
|
120
|
+
}
|
|
121
|
+
_.lastThrottleTime = throttleTime
|
|
122
|
+
}
|
|
123
|
+
if (condition !== _.lastCondition) {
|
|
124
|
+
_.lastCondition = condition
|
|
125
|
+
if (condition) {
|
|
126
|
+
_.callback = getOrCreateCallback(throttleTime)
|
|
127
|
+
observer.observe(el, _.callback)
|
|
128
|
+
} else {
|
|
129
|
+
if (!_.callback) unreachable()
|
|
130
|
+
observer.unobserve(el, _.callback)
|
|
131
|
+
removeCallback(throttleTime)
|
|
132
|
+
_.callback = undefined
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
unmounted(el: HTMLElement, { value: { vertical = false, throttleTime = 50, ignoreSelector = ".detect-flex-ignore" } = {} }: DetectFlexOptions) {
|
|
137
|
+
const _ = elMap.get(el)
|
|
138
|
+
if (!_) {unreachable()}
|
|
139
|
+
_.vertical = vertical
|
|
140
|
+
_.ignoreSelector = ignoreSelector
|
|
141
|
+
_.lastThrottleTime = throttleTime
|
|
142
|
+
if (_.lastCondition) {
|
|
143
|
+
if (!_.callback) unreachable()
|
|
144
|
+
observer.unobserve(el, _.callback)
|
|
145
|
+
_.callback = undefined
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
getSSRProps() {
|
|
149
|
+
return {}
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
type DetectFlexOptions = {
|
|
153
|
+
value: {
|
|
154
|
+
condition?: boolean
|
|
155
|
+
vertical?: boolean
|
|
156
|
+
throttleTime?: number
|
|
157
|
+
ignoreSelector?: string
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Directive } from "vue"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Vue 3 no longer allows extracting the root element from a component.
|
|
5
|
+
*
|
|
6
|
+
* This allows us to extract it via a callback.
|
|
7
|
+
*
|
|
8
|
+
* Note the callback will be called on mount/unmount to keep the value up to date and make it null if the element disappears.
|
|
9
|
+
*
|
|
10
|
+
* One can create a ref:
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { vExtractRootEl } from "@witchcraft/ui/directives/vExtractRootEl.js"
|
|
13
|
+
* const el = ref<HTMLElement|null>(null)
|
|
14
|
+
*
|
|
15
|
+
* ```
|
|
16
|
+
* Then in the template
|
|
17
|
+
* ```vue
|
|
18
|
+
* <SomeComponent v-extract-root-el="_ => el = _" />
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Currently only tested with single root elements.
|
|
22
|
+
*/
|
|
23
|
+
export const vExtractRootEl: Directive = {
|
|
24
|
+
// @ts-expect-error for registering properly without doing complicated case conversion
|
|
25
|
+
directiveName: "extract-root-el",
|
|
26
|
+
mounted(el: HTMLElement, { value: callback }: Options) {
|
|
27
|
+
callback(el)
|
|
28
|
+
},
|
|
29
|
+
unmounted(_el: HTMLElement, { value: callback }: Options) {
|
|
30
|
+
callback(null)
|
|
31
|
+
},
|
|
32
|
+
getSSRProps() {
|
|
33
|
+
return {}
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
type Options = {
|
|
37
|
+
value: (el: HTMLElement | null) => void
|
|
38
|
+
}
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-use-before-define */
|
|
2
|
+
import { castType } from "@alanscodelog/utils/castType.js"
|
|
3
|
+
import { override } from "@alanscodelog/utils/override.js"
|
|
4
|
+
import { throttle } from "@alanscodelog/utils/throttle.js"
|
|
5
|
+
import { unreachable } from "@alanscodelog/utils/unreachable.js"
|
|
6
|
+
import type { Directive, Ref } from "vue"
|
|
7
|
+
|
|
8
|
+
import { globalResizeObserver } from "../globalResizeObserver.js"
|
|
9
|
+
import type { ResizableOptions, ResizeCallback } from "../types/index.js"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
const observer = globalResizeObserver
|
|
13
|
+
type Data = {
|
|
14
|
+
margin: number
|
|
15
|
+
fitWidth: boolean
|
|
16
|
+
colCount: number
|
|
17
|
+
grips: Map<HTMLElement, number>
|
|
18
|
+
isDragging: boolean
|
|
19
|
+
pointerDownHandler: (e: PointerEvent) => void
|
|
20
|
+
pointerUpHandler: (e: PointerEvent) => void
|
|
21
|
+
pointerLeaveHandler: (e: PointerEvent) => void
|
|
22
|
+
pointerMoveHandler: (e: PointerEvent) => void
|
|
23
|
+
target?: HTMLElement
|
|
24
|
+
offset?: number
|
|
25
|
+
widths: Ref<string[]>
|
|
26
|
+
selector: string
|
|
27
|
+
}
|
|
28
|
+
const elMap = new WeakMap<HTMLElement, Data>()
|
|
29
|
+
type RawOpts = { value: Partial<ResizableOptions> }
|
|
30
|
+
|
|
31
|
+
type ResizableElement = HTMLElement
|
|
32
|
+
|
|
33
|
+
const defaultOpts: Omit<ResizableOptions, "colCount" | "widths" | "selector"> = {
|
|
34
|
+
fitWidth: true,
|
|
35
|
+
margin: "dynamic",
|
|
36
|
+
enabled: true,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const callback: ResizeCallback = (_rect: DOMRectReadOnly, el: Element): void => {
|
|
40
|
+
setColWidths(el as ResizableElement)
|
|
41
|
+
positionGrips(el as ResizableElement)
|
|
42
|
+
}
|
|
43
|
+
const throttledCallback = throttle(callback)
|
|
44
|
+
/**
|
|
45
|
+
* Allow a table like element to be resized along it's columns.
|
|
46
|
+
*
|
|
47
|
+
* ```vue
|
|
48
|
+
* <template>
|
|
49
|
+
* <div v-resizable-cols="opts">
|
|
50
|
+
* <!---->
|
|
51
|
+
* </div>
|
|
52
|
+
* </template>
|
|
53
|
+
* <script setup>
|
|
54
|
+
* import {vResizeCols} from "@witchcraft/ui/directives/vResizableCols.js"
|
|
55
|
+
* </script>
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* This assumes the following:
|
|
59
|
+
* - The `.grip` element the directive adds for each column is styled with at least some width.
|
|
60
|
+
* - The containing element must not have any borders. Use a wrapper if you need them.
|
|
61
|
+
*
|
|
62
|
+
* This will set the following styles on the elements:
|
|
63
|
+
*
|
|
64
|
+
* ```css
|
|
65
|
+
* el {
|
|
66
|
+
* min-width: [opts.minWidth * col #] // only if needed, see margin and fitWidth options
|
|
67
|
+
* min-width: min-content; // if fitWidth: false
|
|
68
|
+
* .grip {
|
|
69
|
+
* position: absolute;
|
|
70
|
+
* top: 0;
|
|
71
|
+
* bottom: 0;
|
|
72
|
+
* cursor: col-resize;
|
|
73
|
+
* }
|
|
74
|
+
* [cells] {
|
|
75
|
+
* none
|
|
76
|
+
* }
|
|
77
|
+
* }
|
|
78
|
+
* ```
|
|
79
|
+
* Note that they aren't removed if the directive is disabled.
|
|
80
|
+
*
|
|
81
|
+
* It does NOT set the widths on the cells. It used to, but for maximum flexibility a ref with an array should be passed to be populated by the widths calculated.
|
|
82
|
+
*
|
|
83
|
+
* Additionally the following are suggested:
|
|
84
|
+
* - If fitWidth is true, `overflow: hidden` should be set on the column elements to avoid glitches when dragging the last column near the right edge.
|
|
85
|
+
* - The root element should have `overflow-x:scroll` even if `fitWidth` is true, since there is some minimum space (margin+grip * col) the element will always occupy.
|
|
86
|
+
*
|
|
87
|
+
* The directive also adds a class after the initial setup `resizable-cols-setup`. This is useful to set initial column widths, for example, using flexboxes, then removing those styles when the element is setup. You can also check if the passed widths array is still of 0 length.
|
|
88
|
+
*
|
|
89
|
+
* ```css
|
|
90
|
+
* el:not(.resizable-cols-setup) {
|
|
91
|
+
* initial styles
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* You can prevent columns from being resized by adding the class `no-resize`. When a column cannot be moved, the `resizable-cols-error` class is added to the element.
|
|
96
|
+
*
|
|
97
|
+
* Also note the `.grip` element added is added to the root element. This is so you can have `overflow:hidden` on cells if you want without the grip getting hidden. But this does mean that if you're styling the cells using `:last-child`, to, for example, target table rows, won't work, you'll need `:last-of-type`.
|
|
98
|
+
*
|
|
99
|
+
* # Options
|
|
100
|
+
* See {@link ResizableOptions}
|
|
101
|
+
*/
|
|
102
|
+
export const vResizableCols: Directive = {
|
|
103
|
+
mounted(el: ResizableElement, { value: opts = {} }: RawOpts) {
|
|
104
|
+
const options = override({ ...defaultOpts }, opts) as ResizableOptions
|
|
105
|
+
|
|
106
|
+
if (options.enabled) {
|
|
107
|
+
setupColumns(el, options)
|
|
108
|
+
observer.observe(el, throttledCallback)
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
updated(el: ResizableElement, { value: opts = {} }: RawOpts) {
|
|
112
|
+
const options = override({ ...defaultOpts }, opts) as ResizableOptions
|
|
113
|
+
const info = el && getElInfo(el)
|
|
114
|
+
const hasGrips = el && elMap.get(el)!.grips
|
|
115
|
+
// todo, we should probably check by name
|
|
116
|
+
const colsNotEqual = (info && info.colCount !== options.colCount)
|
|
117
|
+
if ((hasGrips && !options.enabled) || colsNotEqual) {
|
|
118
|
+
teardownColumns(el)
|
|
119
|
+
observer.unobserve(el, throttledCallback)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if ((!hasGrips && options.enabled) || colsNotEqual) {
|
|
123
|
+
setupColumns(el, options)
|
|
124
|
+
observer.observe(el, throttledCallback)
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
unmounted(el: ResizableElement) {
|
|
128
|
+
const hasGrips = elMap.has(el) && elMap.get(el)!.grips
|
|
129
|
+
if (hasGrips) {
|
|
130
|
+
teardownColumns(el)
|
|
131
|
+
globalResizeObserver.unobserve(el, throttledCallback)
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
getSSRProps() {
|
|
135
|
+
return {}
|
|
136
|
+
},
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
const setWidth = (col: HTMLElement, amountInPx: number, el: ResizableElement): void => {
|
|
141
|
+
const $el = getElInfo(el)
|
|
142
|
+
const width = Math.max($el.margin, amountInPx)
|
|
143
|
+
|
|
144
|
+
const index = getColEls(el).findIndex(_ => col === _)
|
|
145
|
+
if ($el.fitWidth) {
|
|
146
|
+
$el.widths.value[index] = `${width / getBox(el).width * 100}%`
|
|
147
|
+
} else {
|
|
148
|
+
$el.widths.value[index] = `${width}px`
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
const getBox = (el: Element): { x: number, width: number } => {
|
|
154
|
+
const rect = el.getBoundingClientRect()
|
|
155
|
+
// the numbers need to be rounded or else the columns will start to shift
|
|
156
|
+
// rounding rect.width is bettwe than just using clientWidth which does not include the scrollbar
|
|
157
|
+
return { x: Math.round(rect.x), width: Math.round(rect.width) }
|
|
158
|
+
}
|
|
159
|
+
const getCols = (el: ResizableElement): { col: HTMLElement | null, colNext: HTMLElement | null } => {
|
|
160
|
+
const $el = getElInfo(el)
|
|
161
|
+
if (!$el.target) unreachable()
|
|
162
|
+
let col = getColEls(el)[$el.grips.get($el.target!)!]
|
|
163
|
+
|
|
164
|
+
if (!col) unreachable()
|
|
165
|
+
while (col?.classList.contains("no-resize")) {
|
|
166
|
+
col = col?.previousElementSibling as HTMLElement ?? null
|
|
167
|
+
}
|
|
168
|
+
let colNext = (col?.nextElementSibling as HTMLElement) ?? null
|
|
169
|
+
if ($el.fitWidth) {
|
|
170
|
+
while (colNext?.classList.contains("no-resize")) {
|
|
171
|
+
colNext = colNext?.nextElementSibling as HTMLElement ?? null
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return { col, colNext }
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const createPointerDownHandler = (el: ResizableElement) => (e: PointerEvent) => {
|
|
178
|
+
const $el = getElInfo(el)
|
|
179
|
+
if (!$el.isDragging) {
|
|
180
|
+
castType<HTMLElement>(e.target)
|
|
181
|
+
$el.target = e.target
|
|
182
|
+
$el.isDragging = true
|
|
183
|
+
e.preventDefault()
|
|
184
|
+
|
|
185
|
+
// in case any errors happen, we want the pointer up to still be called
|
|
186
|
+
document.addEventListener("pointerup", $el.pointerUpHandler)
|
|
187
|
+
|
|
188
|
+
const { col, colNext } = getCols(el)
|
|
189
|
+
if (col === null || colNext === null) {
|
|
190
|
+
el.classList.add("resizable-cols-error")
|
|
191
|
+
} else {
|
|
192
|
+
document.addEventListener("pointermove", $el.pointerMoveHandler)
|
|
193
|
+
const box = getBox(col!)
|
|
194
|
+
if (box) {
|
|
195
|
+
$el.offset = e.pageX - (box.x + box.width)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const createPointerMoveHandler = (el: ResizableElement) => (e: PointerEvent) => {
|
|
201
|
+
const $el = getElInfo(el)
|
|
202
|
+
if ($el.isDragging) {
|
|
203
|
+
e.preventDefault()
|
|
204
|
+
|
|
205
|
+
const { col, colNext } = getCols(el)
|
|
206
|
+
|
|
207
|
+
if (col !== null) {
|
|
208
|
+
const leftBox = getBox(col)
|
|
209
|
+
|
|
210
|
+
const oldWidth = leftBox.width
|
|
211
|
+
const leftBound = leftBox.x
|
|
212
|
+
const rightBox = colNext ? getBox(colNext) : getBox(el)
|
|
213
|
+
|
|
214
|
+
const rightBound = rightBox.x + rightBox.width
|
|
215
|
+
const margin = $el.margin
|
|
216
|
+
const pos = e.pageX - $el.offset!
|
|
217
|
+
|
|
218
|
+
if ($el.fitWidth) {
|
|
219
|
+
if (pos > (leftBound + margin) && pos < (rightBound - margin)) {
|
|
220
|
+
const newWidth = pos - leftBound
|
|
221
|
+
const diff = oldWidth - newWidth
|
|
222
|
+
|
|
223
|
+
if (rightBox.width + diff < margin) {
|
|
224
|
+
el.classList.add("resizable-cols-error")
|
|
225
|
+
return
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
setWidth(col, newWidth, el)
|
|
230
|
+
setWidth(colNext!, rightBox.width + diff, el)
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
if (pos > leftBound + margin) {
|
|
234
|
+
const newWidth = pos - leftBound
|
|
235
|
+
setWidth(col, newWidth, el)
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
positionGrips(el)
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const createPointerUpHandler = (el: ResizableElement) => (e: PointerEvent) => {
|
|
245
|
+
const $el = getElInfo(el)
|
|
246
|
+
if ($el.isDragging) {
|
|
247
|
+
e.preventDefault()
|
|
248
|
+
$el.isDragging = false
|
|
249
|
+
el.classList.remove("resizable-cols-error")
|
|
250
|
+
$el.offset = 0
|
|
251
|
+
delete $el.target
|
|
252
|
+
document.removeEventListener("pointermove", $el.pointerMoveHandler)
|
|
253
|
+
document.removeEventListener("pointerup", $el.pointerUpHandler)
|
|
254
|
+
// unfortunately does not work with iframes in storybook but otherwise does work
|
|
255
|
+
document.removeEventListener("pointerleave", $el.pointerLeaveHandler)
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const createGrip = (): HTMLElement => {
|
|
260
|
+
const grip = document.createElement("div")
|
|
261
|
+
grip.style.position = "absolute"
|
|
262
|
+
grip.style.cursor = "col-resize"
|
|
263
|
+
grip.style.top = "0"
|
|
264
|
+
grip.style.bottom = "0"
|
|
265
|
+
grip.classList.add("grip")
|
|
266
|
+
return grip
|
|
267
|
+
}
|
|
268
|
+
const removeGrips = (el: HTMLElement): void => {
|
|
269
|
+
const grips = Array.from(el.querySelectorAll(".grip") ?? [])
|
|
270
|
+
for (const grip of grips) {
|
|
271
|
+
el.removeChild(grip)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const getTestGripSize = (el: ResizableElement): number => {
|
|
275
|
+
const testGrip = createGrip()
|
|
276
|
+
el.appendChild(testGrip)
|
|
277
|
+
const dynamicMinWidth = getBox(testGrip).width * 3
|
|
278
|
+
el.removeChild(testGrip)
|
|
279
|
+
return dynamicMinWidth
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const getElInfo = (el: ResizableElement): Data => {
|
|
283
|
+
const $el = elMap.get(el)
|
|
284
|
+
if (!$el) unreachable("El went missing.")
|
|
285
|
+
return $el
|
|
286
|
+
}
|
|
287
|
+
const getColEls = (el: ResizableElement): HTMLElement[] => {
|
|
288
|
+
const $el = elMap.get(el)
|
|
289
|
+
if (!$el) unreachable("El went missing.")
|
|
290
|
+
return [...el.querySelectorAll(`:scope ${$el.selector ? $el.selector : "tr > td"}`)] as any
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const setupColumns = (el: ResizableElement, opts: ResizableOptions): void => {
|
|
294
|
+
const gripWidth = getTestGripSize(el)
|
|
295
|
+
const $el: Data = {
|
|
296
|
+
grips: new Map(),
|
|
297
|
+
isDragging: false,
|
|
298
|
+
pointerDownHandler: createPointerDownHandler(el),
|
|
299
|
+
pointerMoveHandler: createPointerMoveHandler(el),
|
|
300
|
+
pointerUpHandler: createPointerUpHandler(el),
|
|
301
|
+
pointerLeaveHandler: createPointerUpHandler(el),
|
|
302
|
+
fitWidth: opts.fitWidth,
|
|
303
|
+
margin: opts.margin === "dynamic" ? gripWidth : opts.margin,
|
|
304
|
+
colCount: opts.colCount,
|
|
305
|
+
widths: opts.widths,
|
|
306
|
+
selector: opts.selector,
|
|
307
|
+
}
|
|
308
|
+
elMap.set(el, $el)
|
|
309
|
+
const els = getColEls(el)
|
|
310
|
+
|
|
311
|
+
const headers = els.slice(0, opts.colCount)
|
|
312
|
+
|
|
313
|
+
setColWidths(el, headers)
|
|
314
|
+
el.style.width = $el.fitWidth ? "" : "min-content"
|
|
315
|
+
const len = opts.colCount
|
|
316
|
+
for (let i = 0; i < len; i++) {
|
|
317
|
+
if (opts.fitWidth && i === len - 1) continue
|
|
318
|
+
|
|
319
|
+
const grip: HTMLElement = createGrip()
|
|
320
|
+
grip.addEventListener("pointerdown", $el.pointerDownHandler)
|
|
321
|
+
el.appendChild(grip)
|
|
322
|
+
$el.grips.set(grip, i)
|
|
323
|
+
}
|
|
324
|
+
positionGrips(el)
|
|
325
|
+
el.classList.add("resizable-cols-setup")
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const positionGrips = (el: ResizableElement): void => {
|
|
329
|
+
let xPos = 0
|
|
330
|
+
const $el = getElInfo(el)
|
|
331
|
+
for (const grip of $el.grips.keys()) {
|
|
332
|
+
const col = $el.grips.get(grip)!
|
|
333
|
+
const colBox = getBox(getColEls(el)[col])
|
|
334
|
+
const gripBox = getBox(grip)
|
|
335
|
+
|
|
336
|
+
grip.style.left = `${xPos + colBox.width - (gripBox.width / 2)}px`
|
|
337
|
+
xPos += colBox.width
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const setColWidths = (el: ResizableElement, children?: Element[]): void => {
|
|
342
|
+
const $el = getElInfo(el)
|
|
343
|
+
const header = children ?? getColEls(el).slice(0, $el.colCount)
|
|
344
|
+
const len = $el.colCount
|
|
345
|
+
let width = 0
|
|
346
|
+
const minTotalWidth = len * $el.margin
|
|
347
|
+
for (let i = 0; i < len; i++) {
|
|
348
|
+
const col = header[i]
|
|
349
|
+
castType<HTMLElement>(col)
|
|
350
|
+
/**
|
|
351
|
+
* only works if parent table does NOT use `box-sizing:border-box` and either has no border or does `width: calc(100% - BORDERWIDTH*2)`
|
|
352
|
+
*/
|
|
353
|
+
const colBox = getBox(col)
|
|
354
|
+
|
|
355
|
+
setWidth(col, colBox.width, el)
|
|
356
|
+
width += getBox(col).width
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (width < minTotalWidth) {
|
|
360
|
+
el.style.minWidth = `${minTotalWidth}px`
|
|
361
|
+
} else {
|
|
362
|
+
el.style.minWidth = ""
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const teardownColumns = (el: ResizableElement): void => {
|
|
367
|
+
const $el = getElInfo(el)
|
|
368
|
+
|
|
369
|
+
el.removeEventListener("pointerdown", $el.pointerDownHandler)
|
|
370
|
+
document.removeEventListener("pointermove", $el.pointerMoveHandler)
|
|
371
|
+
document.removeEventListener("pointerup", $el.pointerUpHandler)
|
|
372
|
+
for (const key of Object.keys($el)) {
|
|
373
|
+
delete $el[key as keyof typeof $el]
|
|
374
|
+
}
|
|
375
|
+
elMap.delete(el)
|
|
376
|
+
el.classList.remove("resizable-cols-setup")
|
|
377
|
+
removeGrips(el)
|
|
378
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Directive } from "vue"
|
|
2
|
+
|
|
3
|
+
import { globalResizeObserver } from "../globalResizeObserver.js"
|
|
4
|
+
import type { ResizeCallback } from "../types/index.js"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const observer = globalResizeObserver
|
|
8
|
+
const lastCondition = Symbol("lastCondition")
|
|
9
|
+
const checkCallback = (cb: any): void => {
|
|
10
|
+
if (cb === undefined) {
|
|
11
|
+
throw new Error("No callback function passed to resize observer directive.")
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export const vResizeObserver: Directive = {
|
|
15
|
+
mounted(el: HTMLElement, { value: { condition = true, callback } }: Options) {
|
|
16
|
+
if (condition) {
|
|
17
|
+
observer.observe(el, callback)
|
|
18
|
+
}
|
|
19
|
+
checkCallback(callback)
|
|
20
|
+
},
|
|
21
|
+
updated(el: HTMLElement, { value: { condition = true, callback } }: Options) {
|
|
22
|
+
if (condition !== (el as any)[lastCondition]) {
|
|
23
|
+
(el as any)[lastCondition] = condition
|
|
24
|
+
if (condition) {
|
|
25
|
+
observer.observe(el, callback)
|
|
26
|
+
} else {
|
|
27
|
+
observer.unobserve(el, callback)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
checkCallback(callback)
|
|
31
|
+
},
|
|
32
|
+
unmounted(el: HTMLElement, { value: { callback } }: Options) {
|
|
33
|
+
observer.unobserve(el, callback)
|
|
34
|
+
delete (el as any)[lastCondition]
|
|
35
|
+
},
|
|
36
|
+
getSSRProps() {
|
|
37
|
+
return {}
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
type Options = {
|
|
41
|
+
value: {
|
|
42
|
+
condition?: boolean
|
|
43
|
+
callback: ResizeCallback
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is not inside helpers to avoid having it get dragged in by an import of /helpers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ResizeObserverWrapper } from "./helpers/resizeObserverWrapper.js"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
if (typeof ResizeObserver === "undefined") {
|
|
9
|
+
// eslint-disable-next-line no-console
|
|
10
|
+
console.warn("You are using a directive that uses a ResizeObserver or are importing something that uses this resize observer in a context (e.g. the server) where ResizeObserver does not exist.")
|
|
11
|
+
}
|
|
12
|
+
export const globalResizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserverWrapper() : {} as ResizeObserverWrapper
|