@witchcraft/ui 0.0.1 → 0.1.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 +18 -28
- package/dist/module.d.mts +3 -1
- package/dist/module.json +3 -3
- package/dist/module.mjs +21 -12
- package/dist/runtime/assets/base.css +1 -1
- package/dist/runtime/assets/locales/en.json +2 -2
- package/dist/runtime/assets/tailwind.css +1 -1
- package/dist/runtime/assets/utils.css +1 -0
- package/dist/runtime/build/WitchcraftUiResolver.js +1 -1
- package/dist/runtime/components/Aria/Aria.vue +5 -9
- package/dist/runtime/components/Aria/Aria.vue.d.ts +5 -0
- package/dist/runtime/components/Icon/Icon.vue +12 -28
- package/dist/runtime/components/Icon/Icon.vue.d.ts +21 -0
- package/dist/runtime/components/LibButton/LibButton.vue +93 -117
- package/dist/runtime/components/LibButton/LibButton.vue.d.ts +36 -0
- package/dist/runtime/components/LibCheckbox/LibCheckbox.vue +53 -76
- package/dist/runtime/components/LibCheckbox/LibCheckbox.vue.d.ts +42 -0
- package/dist/runtime/components/LibColorInput/LibColorInput.vue +131 -101
- package/dist/runtime/components/LibColorInput/LibColorInput.vue.d.ts +63 -0
- package/dist/runtime/components/LibColorPicker/LibColorPicker.vue +326 -296
- package/dist/runtime/components/LibColorPicker/LibColorPicker.vue.d.ts +61 -0
- package/dist/runtime/components/LibColorPicker/utils/safeConvertToHsva.d.ts +2 -0
- package/dist/runtime/components/LibColorPicker/utils/safeConvertToHsva.js +18 -0
- package/dist/runtime/components/LibColorPicker/utils/safeConvertToRgba.d.ts +2 -0
- package/dist/runtime/components/LibColorPicker/utils/safeConvertToRgba.js +17 -0
- package/dist/runtime/components/LibColorPicker/utils/toLowPrecisionRgbaString.d.ts +2 -0
- package/dist/runtime/components/LibColorPicker/utils/toLowPrecisionRgbaString.js +8 -0
- package/dist/runtime/components/LibColorPicker/utils/truncate.d.ts +1 -0
- package/dist/runtime/components/LibColorPicker/utils/truncate.js +5 -0
- package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue +42 -64
- package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue.d.ts +22 -0
- package/dist/runtime/components/LibDatePicker/LibDatePicker.vue +20 -54
- package/dist/runtime/components/LibDatePicker/LibDatePicker.vue.d.ts +40 -0
- package/dist/runtime/components/LibDatePicker/LibRangeDatePicker.vue +205 -173
- package/dist/runtime/components/LibDatePicker/LibRangeDatePicker.vue.d.ts +34 -0
- package/dist/runtime/components/LibDatePicker/LibSingleDatePicker.vue +215 -164
- package/dist/runtime/components/LibDatePicker/LibSingleDatePicker.vue.d.ts +34 -0
- package/dist/runtime/components/LibDatePicker/LibTimeZonePicker.vue +9 -10
- package/dist/runtime/components/LibDatePicker/LibTimeZonePicker.vue.d.ts +22 -0
- package/dist/runtime/components/LibDebug/LibDebug.vue +47 -65
- package/dist/runtime/components/LibDebug/LibDebug.vue.d.ts +32 -0
- package/dist/runtime/components/LibDevOnly/LibDevOnly.vue +19 -34
- package/dist/runtime/components/LibDevOnly/LibDevOnly.vue.d.ts +22 -0
- package/dist/runtime/components/LibFileInput/LibFileInput.vue +155 -173
- package/dist/runtime/components/LibFileInput/LibFileInput.vue.d.ts +43 -0
- package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.vue +352 -0
- package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.vue.d.ts +165 -0
- package/dist/runtime/components/LibLabel/LibLabel.vue +30 -46
- package/dist/runtime/components/LibLabel/LibLabel.vue.d.ts +27 -0
- package/dist/runtime/components/LibMultiValues/LibMultiValues.vue +50 -66
- package/dist/runtime/components/LibMultiValues/LibMultiValues.vue.d.ts +29 -0
- package/dist/runtime/components/LibNotifications/LibNotification.vue +48 -56
- package/dist/runtime/components/LibNotifications/LibNotification.vue.d.ts +17 -0
- package/dist/runtime/components/LibNotifications/LibNotifications.vue +71 -83
- package/dist/runtime/components/LibNotifications/LibNotifications.vue.d.ts +13 -0
- package/dist/runtime/components/LibPagination/LibPagination.vue +86 -131
- package/dist/runtime/components/LibPagination/LibPagination.vue.d.ts +104 -0
- package/dist/runtime/components/LibPalette/LibPalette.vue +23 -26
- package/dist/runtime/components/LibPalette/LibPalette.vue.d.ts +14 -0
- package/dist/runtime/components/LibPopup/LibPopup.vue +326 -400
- package/dist/runtime/components/LibPopup/LibPopup.vue.d.ts +46 -0
- package/dist/runtime/components/LibProgressBar/LibProgressBar.vue +73 -93
- package/dist/runtime/components/LibProgressBar/LibProgressBar.vue.d.ts +41 -0
- package/dist/runtime/components/LibRecorder/LibRecorder.vue +134 -179
- package/dist/runtime/components/LibRecorder/LibRecorder.vue.d.ts +77 -0
- package/dist/runtime/components/LibRoot/LibRoot.vue +75 -89
- package/dist/runtime/components/LibRoot/LibRoot.vue.d.ts +41 -0
- package/dist/runtime/components/LibSimpleInput/LibSimpleInput.vue +51 -82
- package/dist/runtime/components/LibSimpleInput/LibSimpleInput.vue.d.ts +35 -0
- package/dist/runtime/components/LibSuggestions/LibSuggestions.vue +147 -164
- package/dist/runtime/components/LibSuggestions/LibSuggestions.vue.d.ts +94 -0
- package/dist/runtime/components/LibTable/LibTable.vue +69 -106
- package/dist/runtime/components/LibTable/LibTable.vue.d.ts +45 -0
- package/dist/runtime/components/Template/NAME.vue +15 -36
- package/dist/runtime/components/Template/NAME.vue.d.ts +17 -0
- package/dist/runtime/components/TestControls/TestControls.vue +7 -10
- package/dist/runtime/components/TestControls/TestControls.vue.d.ts +5 -0
- package/dist/runtime/components/index.d.ts +12 -11
- package/dist/runtime/components/index.js +12 -11
- package/dist/runtime/components/shared/props.d.ts +81 -16
- package/dist/runtime/components/shared/storyHelpers/playInput.js +5 -5
- package/dist/runtime/components/shared/storyHelpers/playSuggestions.js +15 -11
- package/dist/runtime/composables/index.d.ts +5 -0
- package/dist/runtime/composables/index.js +5 -0
- package/dist/runtime/composables/useDivideAttrs.js +1 -0
- package/dist/runtime/composables/useDragWithThreshold.d.ts +71 -0
- package/dist/runtime/composables/useDragWithThreshold.js +40 -0
- package/dist/runtime/composables/usePreHydrationValue.d.ts +12 -0
- package/dist/runtime/composables/usePreHydrationValue.js +15 -0
- package/dist/runtime/composables/useSetupI18n.d.ts +2 -0
- package/dist/runtime/composables/useSetupI18n.js +5 -1
- package/dist/runtime/composables/useSuggestions.d.ts +7 -5
- package/dist/runtime/composables/useSuggestions.js +94 -57
- package/dist/runtime/directives/vResizableCols.js +92 -84
- package/dist/runtime/helpers/NotificationHandler.d.ts +5 -0
- package/dist/runtime/helpers/index.d.ts +3 -1
- package/dist/runtime/helpers/index.js +3 -1
- package/dist/runtime/types/index.d.ts +6 -0
- package/dist/runtime/utils/notifyIfError.d.ts +14 -0
- package/dist/runtime/utils/notifyIfError.js +29 -0
- package/dist/types.d.mts +2 -6
- package/package.json +27 -29
- package/src/module.ts +31 -12
- package/src/runtime/assets/base.css +10 -1
- package/src/runtime/assets/locales/en.json +2 -2
- package/src/runtime/assets/tailwind.css +1 -1
- package/src/runtime/assets/{style.css → utils.css} +86 -4
- package/src/runtime/build/WitchcraftUiResolver.ts +1 -1
- package/src/runtime/components/Focus.stories.ts +3 -2
- package/src/runtime/components/Icon/Icon.vue +10 -6
- package/src/runtime/components/LibButton/LibButton.vue +41 -47
- package/src/runtime/components/LibCheckbox/LibCheckbox.vue +7 -4
- package/src/runtime/components/LibColorInput/LibColorInput.vue +111 -37
- package/src/runtime/components/LibColorPicker/LibColorPicker.stories.ts +25 -4
- package/src/runtime/components/LibColorPicker/LibColorPicker.vue +242 -131
- package/src/runtime/components/LibColorPicker/utils/safeConvertToHsva.ts +24 -0
- package/src/runtime/components/LibColorPicker/utils/safeConvertToRgba.ts +23 -0
- package/src/runtime/components/LibColorPicker/utils/toLowPrecisionRgbaString.ts +13 -0
- package/src/runtime/components/LibColorPicker/utils/truncate.ts +6 -0
- package/src/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.ts +1 -1
- package/src/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue +11 -9
- package/src/runtime/components/LibDatePicker/LibDatePicker.vue +4 -17
- package/src/runtime/components/LibDatePicker/LibRangeDatePicker.vue +192 -131
- package/src/runtime/components/LibDatePicker/LibSingleDatePicker.vue +183 -115
- package/src/runtime/components/LibDatePicker/LibTimeZonePicker.vue +3 -3
- package/src/runtime/components/LibDebug/LibDebug.vue +15 -5
- package/src/runtime/components/LibDevOnly/LibDevOnly.vue +1 -3
- package/src/runtime/components/LibFileInput/LibFileInput.vue +54 -29
- package/src/runtime/components/{LibInput/LibInput.stories.ts → LibInputDeprecated/LibInputDeprecated.stories.ts} +64 -19
- package/{dist/runtime/components/LibInput/LibInput.vue → src/runtime/components/LibInputDeprecated/LibInputDeprecated.vue} +40 -34
- package/src/runtime/components/LibLabel/LibLabel.vue +2 -2
- package/src/runtime/components/LibMultiValues/LibMultiValues.stories.ts +5 -4
- package/src/runtime/components/LibMultiValues/LibMultiValues.vue +11 -13
- package/src/runtime/components/LibNotifications/LibNotification.vue +19 -11
- package/src/runtime/components/LibNotifications/LibNotifications.stories.ts +2 -2
- package/src/runtime/components/LibNotifications/LibNotifications.vue +20 -12
- package/src/runtime/components/LibPagination/LibPagination.stories.ts +2 -2
- package/src/runtime/components/LibPagination/LibPagination.vue +19 -20
- package/src/runtime/components/LibPalette/LibPalette.vue +3 -3
- package/src/runtime/components/LibPopup/LibPopup.stories.ts +2 -2
- package/src/runtime/components/LibPopup/LibPopup.vue +30 -67
- package/src/runtime/components/LibProgressBar/LibProgressBar.vue +3 -2
- package/src/runtime/components/LibRecorder/LibRecorder.vue +2 -3
- package/src/runtime/components/LibRoot/LibRoot.vue +14 -1
- package/src/runtime/components/LibSimpleInput/LibSimpleInput.stories.ts +1 -1
- package/src/runtime/components/LibSimpleInput/LibSimpleInput.vue +5 -8
- package/src/runtime/components/LibSuggestions/LibSuggestions.vue +42 -26
- package/src/runtime/components/LibTable/LibTable.vue +8 -9
- package/src/runtime/components/Scrolling.stories.ts +58 -0
- package/src/runtime/components/Template/NAME.vue +1 -1
- package/src/runtime/components/TestControls/TestControls.vue +1 -1
- package/src/runtime/components/index.ts +12 -12
- package/src/runtime/components/shared/props.ts +82 -19
- package/src/runtime/components/shared/storyHelpers/playInput.ts +6 -5
- package/src/runtime/components/shared/storyHelpers/playSuggestions.ts +25 -11
- package/src/runtime/composables/index.ts +5 -0
- package/src/runtime/composables/useDarkMode.ts +2 -2
- package/src/runtime/composables/useDivideAttrs.ts +1 -0
- package/src/runtime/composables/useDragWithThreshold.ts +108 -0
- package/src/runtime/composables/usePreHydrationValue.ts +30 -0
- package/src/runtime/composables/useSetupI18n.ts +8 -2
- package/src/runtime/composables/useSuggestions.ts +92 -45
- package/src/runtime/directives/vResizableCols.ts +82 -74
- package/src/runtime/helpers/NotificationHandler.ts +5 -0
- package/src/runtime/helpers/index.ts +3 -1
- package/src/runtime/types/index.ts +5 -0
- package/src/runtime/utils/notifyIfError.ts +45 -0
- package/dist/module.cjs +0 -5
- package/dist/module.d.ts +0 -34
- package/dist/runtime/assets/style.css +0 -1
- package/dist/runtime/components/Focus.stories.d.ts +0 -11
- package/dist/runtime/components/Focus.stories.js +0 -53
- package/dist/runtime/components/LibButton/LibButton.stories.d.ts +0 -12
- package/dist/runtime/components/LibButton/LibButton.stories.js +0 -94
- package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.d.ts +0 -14
- package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.js +0 -29
- package/dist/runtime/components/LibColorInput/LibColorInput.stories.d.ts +0 -7
- package/dist/runtime/components/LibColorInput/LibColorInput.stories.js +0 -58
- package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.d.ts +0 -7
- package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.js +0 -51
- package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.d.ts +0 -7
- package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.js +0 -36
- package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.d.ts +0 -11
- package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.js +0 -98
- package/dist/runtime/components/LibDebug/LibDebug.stories.d.ts +0 -9
- package/dist/runtime/components/LibDebug/LibDebug.stories.js +0 -46
- package/dist/runtime/components/LibFileInput/LibFileInput.stories.d.ts +0 -10
- package/dist/runtime/components/LibFileInput/LibFileInput.stories.js +0 -63
- package/dist/runtime/components/LibInput/LibInput.stories.d.ts +0 -33
- package/dist/runtime/components/LibInput/LibInput.stories.js +0 -339
- package/dist/runtime/components/LibLabel/LibLabel.stories.d.ts +0 -6
- package/dist/runtime/components/LibLabel/LibLabel.stories.js +0 -25
- package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.d.ts +0 -23
- package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.js +0 -60
- package/dist/runtime/components/LibNotifications/LibNotification.stories.d.ts +0 -15
- package/dist/runtime/components/LibNotifications/LibNotification.stories.js +0 -126
- package/dist/runtime/components/LibNotifications/LibNotifications.stories.d.ts +0 -6
- package/dist/runtime/components/LibNotifications/LibNotifications.stories.js +0 -109
- package/dist/runtime/components/LibPagination/LibPagination.stories.d.ts +0 -6
- package/dist/runtime/components/LibPagination/LibPagination.stories.js +0 -40
- package/dist/runtime/components/LibPalette/LibPalette.stories.d.ts +0 -6
- package/dist/runtime/components/LibPalette/LibPalette.stories.js +0 -20
- package/dist/runtime/components/LibPopup/LibPopup.stories.d.ts +0 -14
- package/dist/runtime/components/LibPopup/LibPopup.stories.js +0 -147
- package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.d.ts +0 -10
- package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.js +0 -81
- package/dist/runtime/components/LibRecorder/LibRecorder.stories.d.ts +0 -19
- package/dist/runtime/components/LibRecorder/LibRecorder.stories.js +0 -63
- package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.d.ts +0 -26
- package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.js +0 -78
- package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.d.ts +0 -27
- package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.js +0 -112
- package/dist/runtime/components/LibTable/LibTable.stories.d.ts +0 -16
- package/dist/runtime/components/LibTable/LibTable.stories.js +0 -156
- package/dist/runtime/components/reset.stories.d.ts +0 -5
- package/dist/runtime/components/reset.stories.js +0 -19
- package/dist/runtime/composables/useScrollNearContainerEdges.stories.d.ts +0 -7
- package/dist/runtime/composables/useScrollNearContainerEdges.stories.js +0 -85
- package/dist/runtime/helpers/addValue.d.ts +0 -1
- package/dist/runtime/helpers/addValue.js +0 -8
- package/dist/types.d.ts +0 -7
- package/src/runtime/components/LibInput/LibInput.vue +0 -372
- package/src/runtime/helpers/addValue.ts +0 -10
- /package/src/runtime/components/{reset.stories.ts → Reset.stories.ts} +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { type Ref, ref } from "vue"
|
|
2
|
+
|
|
3
|
+
import type { Point } from "../types/index.js"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A composable for dragging items only after a certain threshold of movement has been reached.
|
|
8
|
+
*
|
|
9
|
+
* What to do with the actual pointer coordinates is up to you.
|
|
10
|
+
*
|
|
11
|
+
* The is compatible with the `useScrollNearContainerEdges` composable as well.
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* const {
|
|
15
|
+
* pointerCoords,
|
|
16
|
+
* passedDragThreshold,
|
|
17
|
+
* startDragThresholdCheck,
|
|
18
|
+
* endDragThresholdCheck,
|
|
19
|
+
* checkDragThreshold,
|
|
20
|
+
* } = useDragWithThreshold({ threshold: ref(5) })
|
|
21
|
+
*
|
|
22
|
+
* function grabPointerDown(e: PointerEvent): void {
|
|
23
|
+
* startDragThresholdCheck(e)
|
|
24
|
+
* e.preventDefault()
|
|
25
|
+
*
|
|
26
|
+
* document.addEventListener("pointermove", grabPointerMove)
|
|
27
|
+
* document.addEventListener("pointerup", grabPointerUp)
|
|
28
|
+
* document.addEventListener("keyup", escapeDrag)
|
|
29
|
+
* }
|
|
30
|
+
* function grabPointerMove(e: PointerEvent): void {
|
|
31
|
+
* e.preventDefault()
|
|
32
|
+
* checkDragThreshold(e)
|
|
33
|
+
* if (passedDragThreshold.value) {
|
|
34
|
+
*
|
|
35
|
+
* }
|
|
36
|
+
* }
|
|
37
|
+
* function grabPointerUp(e: PointerEvent): void {
|
|
38
|
+
* if (passedDragThreshold.value) {
|
|
39
|
+
* // drag
|
|
40
|
+
* } else {
|
|
41
|
+
* // handleAsClick(e)
|
|
42
|
+
* }
|
|
43
|
+
* stopDrag()
|
|
44
|
+
* }
|
|
45
|
+
*
|
|
46
|
+
* function stopDrag(): void {
|
|
47
|
+
* endDragThresholdCheck()
|
|
48
|
+
* document.removeEventListener("keyup", escapeDrag)
|
|
49
|
+
* document.removeEventListener("pointermove", grabPointerMove)
|
|
50
|
+
* document.removeEventListener("pointerup", grabPointerUp)
|
|
51
|
+
* }
|
|
52
|
+
*
|
|
53
|
+
* function escapeDrag(e: KeyboardEvent): void {
|
|
54
|
+
* if (e.code === "Escape") stopDrag()
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export const useDragWithThreshold = ({
|
|
59
|
+
initialOffset = ref({ x: 0, y: 0 }),
|
|
60
|
+
pointerCoords = ref({ x: 0, y: 0 }),
|
|
61
|
+
threshold = ref(10),
|
|
62
|
+
}: {
|
|
63
|
+
initialOffset?: Ref<Point | undefined>
|
|
64
|
+
pointerCoords?: Ref<Point | undefined>
|
|
65
|
+
threshold?: Ref<number>
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
67
|
+
} = {}) => {
|
|
68
|
+
const passedDragThreshold = ref(false)
|
|
69
|
+
function getDistance(p1: Point, p2: Point): number {
|
|
70
|
+
const xDiff = p2.x - p1.x
|
|
71
|
+
const yDiff = p2.y - p1.y
|
|
72
|
+
|
|
73
|
+
return Math.sqrt((xDiff * xDiff) + (yDiff * yDiff))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function getEventCoords(e: { clientX: number, clientY: number }): Point {
|
|
77
|
+
return { x: e.clientX, y: e.clientY }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function checkDragThreshold(e: PointerEvent): void {
|
|
81
|
+
pointerCoords.value = getEventCoords(e)
|
|
82
|
+
// don't allow it to be reset to false
|
|
83
|
+
passedDragThreshold.value ||=
|
|
84
|
+
initialOffset.value !== undefined &&
|
|
85
|
+
getDistance(initialOffset.value, pointerCoords.value) >= threshold.value
|
|
86
|
+
}
|
|
87
|
+
function startDragThresholdCheck(e: PointerEvent): void {
|
|
88
|
+
passedDragThreshold.value = false
|
|
89
|
+
initialOffset.value = getEventCoords(e)
|
|
90
|
+
pointerCoords.value = getEventCoords(e)
|
|
91
|
+
}
|
|
92
|
+
function endDragThresholdCheck(): void {
|
|
93
|
+
passedDragThreshold.value = false
|
|
94
|
+
initialOffset.value = undefined
|
|
95
|
+
pointerCoords.value = undefined
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
initialOffset,
|
|
99
|
+
pointerCoords,
|
|
100
|
+
threshold,
|
|
101
|
+
passedDragThreshold,
|
|
102
|
+
getEventCoords,
|
|
103
|
+
checkDragThreshold,
|
|
104
|
+
startDragThresholdCheck,
|
|
105
|
+
endDragThresholdCheck,
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { onBeforeMount, onMounted, type Ref } from "vue"
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* This takes the value of the element at the given id (onBeforeMount, i.e. pre-hydration if available), and sets the given ref to that value onMounted.
|
|
5
|
+
*
|
|
6
|
+
* This should be compatible with both nuxt and vue.
|
|
7
|
+
*
|
|
8
|
+
* Nore that while it's generic, you will need to provide a transform function to convert the string to the desired type.
|
|
9
|
+
*
|
|
10
|
+
* @experimental
|
|
11
|
+
*/
|
|
12
|
+
export function usePreHydrationValue<T>(
|
|
13
|
+
id: string,
|
|
14
|
+
refVal: Ref<T>,
|
|
15
|
+
transform: (val: string) => T = val => val as any
|
|
16
|
+
): void {
|
|
17
|
+
// directly setting it in the onBeforeMount hook doesn't work
|
|
18
|
+
let temp = ""
|
|
19
|
+
onBeforeMount(() => {
|
|
20
|
+
const el = document.getElementById(id) as HTMLInputElement
|
|
21
|
+
if (el?.value) {
|
|
22
|
+
temp = el.value
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
onMounted(() => {
|
|
26
|
+
if (temp) {
|
|
27
|
+
refVal.value = transform(temp)
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
}
|
|
@@ -36,6 +36,8 @@ const dummyMessageSet = new Proxy({}, {
|
|
|
36
36
|
* Should be called only once. You can choose to await it or not (see the `useDummyMessageSetWhileLoading` option).
|
|
37
37
|
*
|
|
38
38
|
* A default function is available, see {@link defaultTranslationFunction}.
|
|
39
|
+
*
|
|
40
|
+
* To avoid hydration errors, on the server, the message loading is awaited.
|
|
39
41
|
*/
|
|
40
42
|
export async function useSetupI18n({
|
|
41
43
|
locale,
|
|
@@ -60,12 +62,16 @@ export async function useSetupI18n({
|
|
|
60
62
|
if (isLoaded) {
|
|
61
63
|
messages.value = loaded[l]
|
|
62
64
|
} else {
|
|
63
|
-
const newMessages = ((await messagesGlob[`../assets/locales/${l}.json`]()) as any).default as any
|
|
65
|
+
const newMessages = ((await messagesGlob[`../assets/locales/${l}.json`]!()) as any).default as any
|
|
64
66
|
loaded[l] = newMessages
|
|
65
67
|
messages.value = newMessages
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
|
-
|
|
70
|
+
if (import.meta.server) {
|
|
71
|
+
await loadMessageSet(locale.value)
|
|
72
|
+
} else {
|
|
73
|
+
void loadMessageSet(locale.value)
|
|
74
|
+
}
|
|
69
75
|
watch(locale, async () => {
|
|
70
76
|
void loadMessageSet(locale.value)
|
|
71
77
|
})
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
+
import { type AnyFunction } from "@alanscodelog/utils"
|
|
2
3
|
import { isBlank } from "@alanscodelog/utils/isBlank.js"
|
|
3
4
|
import { isObject } from "@alanscodelog/utils/isObject.js"
|
|
5
|
+
import { pushIfNotIn } from "@alanscodelog/utils/pushIfNotIn.js"
|
|
6
|
+
import { removeIfIn } from "@alanscodelog/utils/removeIfIn.js"
|
|
4
7
|
import { computed, type Ref, ref, toRaw, watch } from "vue"
|
|
5
8
|
|
|
6
9
|
import { type SuggestionsEmits,type SuggestionsOptions } from "../components/shared/props.js"
|
|
@@ -12,9 +15,10 @@ import { type SuggestionsEmits,type SuggestionsOptions } from "../components/sha
|
|
|
12
15
|
* 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).
|
|
13
16
|
*/
|
|
14
17
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
15
|
-
export function useSuggestions<TSuggestion>(
|
|
18
|
+
export function useSuggestions<TSuggestion, TMultivalue extends boolean = false>(
|
|
16
19
|
$inputValue: Ref<string>,
|
|
17
|
-
$modelValue: Ref<string>,
|
|
20
|
+
$modelValue: Ref<TMultivalue extends true ? string[] : string>,
|
|
21
|
+
$open: Ref<boolean>,
|
|
18
22
|
emit: SuggestionsEmits,
|
|
19
23
|
opts: SuggestionsOptions<TSuggestion>,
|
|
20
24
|
debug: boolean = false
|
|
@@ -23,29 +27,40 @@ export function useSuggestions<TSuggestion>(
|
|
|
23
27
|
throw new Error("`suggestionLabel` or `suggestionsFilter` must be passed if suggestions are objects.")
|
|
24
28
|
}
|
|
25
29
|
|
|
26
|
-
const isOpen = ref(false)
|
|
27
30
|
const activeSuggestion = ref(-1)
|
|
28
|
-
watch(isOpen, val => { emit("update:isOpen", val) })
|
|
29
31
|
watch(activeSuggestion, val => { emit("update:activeSuggestion", val) })
|
|
30
|
-
|
|
32
|
+
if (opts.suggestions) {
|
|
33
|
+
for (const suggestion of opts.suggestions) {
|
|
34
|
+
suggestionLabelGuard(suggestion, opts.suggestionLabel)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const getSuggestionLabel = (item: any): string => {
|
|
39
|
+
suggestionLabelGuard(item, opts.suggestionLabel)
|
|
31
40
|
if (isObject<any>(item)) {
|
|
32
|
-
|
|
33
|
-
return opts.suggestionLabel(item)
|
|
34
|
-
}
|
|
35
|
-
throw new Error("`suggestionLabel` must be passed if suggestions are objects.")
|
|
41
|
+
return opts.suggestionLabel!(item)
|
|
36
42
|
}
|
|
37
43
|
return item
|
|
38
44
|
}
|
|
39
|
-
const getSuggestionLabel = (item: any): string => opts.suggestionLabel?.(item) ?? suggestionKey(item) ?? ""
|
|
40
45
|
|
|
41
46
|
const defaultSuggestionsFilter = (input: string, items: TSuggestion[]): TSuggestion[] => input === ""
|
|
42
47
|
? [...items]
|
|
43
|
-
: items.filter(item =>
|
|
48
|
+
: items.filter(item => {
|
|
49
|
+
if (Array.isArray($modelValue.value)) {
|
|
50
|
+
// always include selected values for unselecting
|
|
51
|
+
if ($modelValue.value.includes(getSuggestionLabel(item))) return true
|
|
52
|
+
}
|
|
53
|
+
return getSuggestionLabel(item).toLowerCase().includes(input.toLowerCase())
|
|
54
|
+
})
|
|
44
55
|
const suggestionsFilter = computed(() => opts.suggestionsFilter ?? defaultSuggestionsFilter)
|
|
45
56
|
|
|
46
57
|
const suggestionsList = computed(() => {
|
|
47
58
|
if (opts.suggestions) {
|
|
48
|
-
const
|
|
59
|
+
const suggestions = [...opts.suggestions]
|
|
60
|
+
if (Array.isArray($modelValue.value) && !opts.showSelectedValues) {
|
|
61
|
+
pushIfNotIn(suggestions, $modelValue.value)
|
|
62
|
+
}
|
|
63
|
+
const res = suggestionsFilter.value($inputValue.value, suggestions)
|
|
49
64
|
return res
|
|
50
65
|
}
|
|
51
66
|
return undefined
|
|
@@ -79,9 +94,6 @@ export function useSuggestions<TSuggestion>(
|
|
|
79
94
|
: opts.suggestions!)
|
|
80
95
|
|
|
81
96
|
if (opts.restrictToSuggestions && !isValidSuggestion.value) return res
|
|
82
|
-
if (opts.preventDuplicateValues && opts.values) {
|
|
83
|
-
return res.filter(suggestion => !opts.values!.includes(suggestionKey(suggestion)))
|
|
84
|
-
}
|
|
85
97
|
return res
|
|
86
98
|
}
|
|
87
99
|
return undefined
|
|
@@ -89,13 +101,29 @@ export function useSuggestions<TSuggestion>(
|
|
|
89
101
|
|
|
90
102
|
|
|
91
103
|
// methods
|
|
104
|
+
// returns true if the value was removed
|
|
105
|
+
function setValue(val: string): boolean {
|
|
106
|
+
if (Array.isArray($modelValue.value)) {
|
|
107
|
+
// works like a toggle
|
|
108
|
+
if ($modelValue.value.includes(val)) {
|
|
109
|
+
removeIfIn($modelValue.value, val)
|
|
110
|
+
return true
|
|
111
|
+
} else {
|
|
112
|
+
pushIfNotIn($modelValue.value, [val])
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
($modelValue.value as string) = val
|
|
116
|
+
}
|
|
117
|
+
return false
|
|
118
|
+
}
|
|
92
119
|
|
|
93
|
-
|
|
120
|
+
function closeSuggestions(): void {
|
|
121
|
+
if (!opts.canClose) return
|
|
94
122
|
if (debug) console.log("closeSuggestions")
|
|
95
|
-
|
|
123
|
+
$open.value = false
|
|
96
124
|
activeSuggestion.value = -1
|
|
97
125
|
}
|
|
98
|
-
|
|
126
|
+
function openSuggestions(): void {
|
|
99
127
|
if (debug) console.log("openSuggestions", { openable: openable.value })
|
|
100
128
|
if (!openable.value) return
|
|
101
129
|
if (activeSuggestion.value === -1) {
|
|
@@ -105,23 +133,25 @@ export function useSuggestions<TSuggestion>(
|
|
|
105
133
|
activeSuggestion.value = 0
|
|
106
134
|
}
|
|
107
135
|
}
|
|
108
|
-
|
|
136
|
+
$open.value = true
|
|
109
137
|
}
|
|
110
138
|
|
|
111
|
-
function enterSuggestion(num: number): void {
|
|
139
|
+
function enterSuggestion(num: number, doClose: boolean = true): void {
|
|
112
140
|
if (num < -1 || num > (filteredSuggestions.value?.length ?? 0)) return
|
|
113
141
|
if (debug) console.log("enterSuggestion", num)
|
|
114
142
|
if (filteredSuggestions.value === undefined) return
|
|
115
143
|
|
|
116
144
|
const suggestion = filteredSuggestions.value[num]
|
|
117
|
-
const val =
|
|
118
|
-
|
|
119
|
-
$inputValue.value = getSuggestionLabel(suggestion)
|
|
120
|
-
|
|
121
|
-
|
|
145
|
+
const val = getSuggestionLabel(suggestion)
|
|
146
|
+
const wasRemoved = setValue(val)
|
|
147
|
+
$inputValue.value = Array.isArray($modelValue.value) ? "" : getSuggestionLabel(suggestion)
|
|
148
|
+
if (doClose) {
|
|
149
|
+
closeSuggestions()
|
|
150
|
+
}
|
|
151
|
+
emit("submit", val, toRaw(suggestion), wasRemoved)
|
|
122
152
|
}
|
|
123
153
|
|
|
124
|
-
|
|
154
|
+
function enterSelected(doClose: boolean = true): void {
|
|
125
155
|
if (activeSuggestion.value === -1) {
|
|
126
156
|
if (!opts.restrictToSuggestions) {
|
|
127
157
|
if (debug) console.log("enterSelected, unrestricted, emitting submit")
|
|
@@ -132,9 +162,10 @@ export function useSuggestions<TSuggestion>(
|
|
|
132
162
|
return
|
|
133
163
|
}
|
|
134
164
|
if (debug) console.log("enterSelected")
|
|
135
|
-
enterSuggestion(activeSuggestion.value)
|
|
165
|
+
enterSuggestion(activeSuggestion.value, doClose)
|
|
136
166
|
}
|
|
137
|
-
|
|
167
|
+
|
|
168
|
+
function selectSuggestion(num: number): void {
|
|
138
169
|
if (debug) console.log("selectSuggestion", num)
|
|
139
170
|
if (num >= -1) {
|
|
140
171
|
activeSuggestion.value = num
|
|
@@ -144,11 +175,11 @@ export function useSuggestions<TSuggestion>(
|
|
|
144
175
|
}
|
|
145
176
|
}
|
|
146
177
|
|
|
147
|
-
|
|
148
|
-
|
|
178
|
+
function toggleSuggestions(): void {
|
|
179
|
+
$open.value ? closeSuggestions() : openSuggestions()
|
|
149
180
|
}
|
|
150
181
|
|
|
151
|
-
|
|
182
|
+
function prevSuggestion(): void {
|
|
152
183
|
if (!filteredSuggestions.value) return
|
|
153
184
|
if (activeSuggestion.value > 0) {
|
|
154
185
|
activeSuggestion.value--
|
|
@@ -157,7 +188,7 @@ export function useSuggestions<TSuggestion>(
|
|
|
157
188
|
}
|
|
158
189
|
}
|
|
159
190
|
|
|
160
|
-
|
|
191
|
+
function nextSuggestion(): void {
|
|
161
192
|
if (!filteredSuggestions.value) return
|
|
162
193
|
if (activeSuggestion.value >= filteredSuggestions.value.length - 1) {
|
|
163
194
|
activeSuggestion.value = 0
|
|
@@ -165,14 +196,18 @@ export function useSuggestions<TSuggestion>(
|
|
|
165
196
|
activeSuggestion.value++
|
|
166
197
|
}
|
|
167
198
|
}
|
|
168
|
-
|
|
199
|
+
function firstSuggestion(): void {
|
|
169
200
|
selectSuggestion(0)
|
|
170
201
|
}
|
|
171
|
-
|
|
202
|
+
function lastSuggestion(): void {
|
|
172
203
|
selectSuggestion(Infinity)
|
|
173
204
|
}
|
|
174
205
|
|
|
175
|
-
|
|
206
|
+
function cancel(): void {
|
|
207
|
+
if (Array.isArray($modelValue.value)) {
|
|
208
|
+
$inputValue.value = ""
|
|
209
|
+
return
|
|
210
|
+
}
|
|
176
211
|
if (debug) console.log("cancel")
|
|
177
212
|
$inputValue.value = getSuggestionLabel($modelValue.value)
|
|
178
213
|
closeSuggestions()
|
|
@@ -203,11 +238,15 @@ export function useSuggestions<TSuggestion>(
|
|
|
203
238
|
// sync vmodels and vmodel effects
|
|
204
239
|
|
|
205
240
|
watch($modelValue, () => {
|
|
206
|
-
|
|
241
|
+
if (Array.isArray($modelValue.value)) {
|
|
242
|
+
$inputValue.value = ""
|
|
243
|
+
} else {
|
|
244
|
+
$inputValue.value = getSuggestionLabel($modelValue.value)
|
|
245
|
+
}
|
|
207
246
|
if (debug) console.log("modelValue changed")
|
|
208
247
|
})
|
|
209
248
|
|
|
210
|
-
|
|
249
|
+
function defaultSuggestionSelector(suggestions: TSuggestion[], input: string): number {
|
|
211
250
|
if (input.length === 0) return 0
|
|
212
251
|
let longestMatch
|
|
213
252
|
let ii = -1
|
|
@@ -227,16 +266,16 @@ export function useSuggestions<TSuggestion>(
|
|
|
227
266
|
|
|
228
267
|
watch($inputValue, () => {
|
|
229
268
|
if (debug) console.log("input changed:", $inputValue.value, "modelValue:", $modelValue.value)
|
|
230
|
-
if (getSuggestionLabel($modelValue.value) === $inputValue.value) return
|
|
269
|
+
if (!Array.isArray($modelValue.value) && getSuggestionLabel($modelValue.value) === $inputValue.value) return
|
|
231
270
|
|
|
232
271
|
if (suggestionAvailable.value) {
|
|
233
272
|
if (debug) console.log("input changed, suggestion available, opening suggestions")
|
|
234
273
|
openSuggestions()
|
|
235
274
|
}
|
|
236
275
|
|
|
237
|
-
if (!opts.restrictToSuggestions) {
|
|
276
|
+
if (!opts.restrictToSuggestions && !Array.isArray($modelValue.value)) {
|
|
238
277
|
if (debug) console.log("input changed, unrestricted, setting modelValue")
|
|
239
|
-
$
|
|
278
|
+
setValue($inputValue.value)
|
|
240
279
|
}
|
|
241
280
|
if (exactlyMatchingSuggestion.value && suggestionsList.value) {
|
|
242
281
|
if (debug) console.log("input changed, exactly matching, setting activeSuggestion")
|
|
@@ -264,11 +303,11 @@ export function useSuggestions<TSuggestion>(
|
|
|
264
303
|
hasValidSuggestion: isValidSuggestion,
|
|
265
304
|
openable,
|
|
266
305
|
getLabel: getSuggestionLabel,
|
|
267
|
-
|
|
306
|
+
$open,
|
|
268
307
|
open: openSuggestions,
|
|
269
308
|
close: closeSuggestions,
|
|
270
309
|
enterSelected,
|
|
271
|
-
enterSuggestion,
|
|
310
|
+
enterIndex: enterSuggestion,
|
|
272
311
|
toggle: toggleSuggestions,
|
|
273
312
|
cancel,
|
|
274
313
|
select: selectSuggestion,
|
|
@@ -276,13 +315,14 @@ export function useSuggestions<TSuggestion>(
|
|
|
276
315
|
next: nextSuggestion,
|
|
277
316
|
first: firstSuggestion,
|
|
278
317
|
last: lastSuggestion,
|
|
318
|
+
|
|
279
319
|
}
|
|
280
320
|
}
|
|
281
321
|
|
|
282
322
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
283
323
|
export function useSuggestionsInputAria(
|
|
284
324
|
id: Ref<string>,
|
|
285
|
-
|
|
325
|
+
$open: Ref<boolean>,
|
|
286
326
|
activeSuggestion: Ref<number>,
|
|
287
327
|
suggestions: Ref<any | undefined>
|
|
288
328
|
) {
|
|
@@ -290,8 +330,15 @@ export function useSuggestionsInputAria(
|
|
|
290
330
|
"aria-autocomplete": suggestions !== undefined ? "both" as const : undefined,
|
|
291
331
|
"aria-controls": suggestions !== undefined ? `suggestions-${id.value}` : undefined,
|
|
292
332
|
role: suggestions ? "combobox" : undefined,
|
|
293
|
-
"aria-expanded": suggestions !== undefined ?
|
|
294
|
-
"aria-activedescendant":
|
|
333
|
+
"aria-expanded": suggestions !== undefined ? $open.value : undefined,
|
|
334
|
+
"aria-activedescendant": $open.value ? `suggestion-${id.value}-${activeSuggestion.value}` : undefined,
|
|
295
335
|
}))
|
|
296
336
|
return ariaInputProps
|
|
297
337
|
}
|
|
338
|
+
export function suggestionLabelGuard<TFunction extends AnyFunction>(item: any, suggestionLabeler: TFunction | undefined): asserts suggestionLabeler is TFunction {
|
|
339
|
+
if (isObject<any>(item)) {
|
|
340
|
+
if (!suggestionLabeler) {
|
|
341
|
+
throw new Error("`suggestionLabel` must be passed if suggestions are objects.")
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|