@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.
Files changed (224) hide show
  1. package/README.md +18 -28
  2. package/dist/module.d.mts +3 -1
  3. package/dist/module.json +3 -3
  4. package/dist/module.mjs +21 -12
  5. package/dist/runtime/assets/base.css +1 -1
  6. package/dist/runtime/assets/locales/en.json +2 -2
  7. package/dist/runtime/assets/tailwind.css +1 -1
  8. package/dist/runtime/assets/utils.css +1 -0
  9. package/dist/runtime/build/WitchcraftUiResolver.js +1 -1
  10. package/dist/runtime/components/Aria/Aria.vue +5 -9
  11. package/dist/runtime/components/Aria/Aria.vue.d.ts +5 -0
  12. package/dist/runtime/components/Icon/Icon.vue +12 -28
  13. package/dist/runtime/components/Icon/Icon.vue.d.ts +21 -0
  14. package/dist/runtime/components/LibButton/LibButton.vue +93 -117
  15. package/dist/runtime/components/LibButton/LibButton.vue.d.ts +36 -0
  16. package/dist/runtime/components/LibCheckbox/LibCheckbox.vue +53 -76
  17. package/dist/runtime/components/LibCheckbox/LibCheckbox.vue.d.ts +42 -0
  18. package/dist/runtime/components/LibColorInput/LibColorInput.vue +131 -101
  19. package/dist/runtime/components/LibColorInput/LibColorInput.vue.d.ts +63 -0
  20. package/dist/runtime/components/LibColorPicker/LibColorPicker.vue +326 -296
  21. package/dist/runtime/components/LibColorPicker/LibColorPicker.vue.d.ts +61 -0
  22. package/dist/runtime/components/LibColorPicker/utils/safeConvertToHsva.d.ts +2 -0
  23. package/dist/runtime/components/LibColorPicker/utils/safeConvertToHsva.js +18 -0
  24. package/dist/runtime/components/LibColorPicker/utils/safeConvertToRgba.d.ts +2 -0
  25. package/dist/runtime/components/LibColorPicker/utils/safeConvertToRgba.js +17 -0
  26. package/dist/runtime/components/LibColorPicker/utils/toLowPrecisionRgbaString.d.ts +2 -0
  27. package/dist/runtime/components/LibColorPicker/utils/toLowPrecisionRgbaString.js +8 -0
  28. package/dist/runtime/components/LibColorPicker/utils/truncate.d.ts +1 -0
  29. package/dist/runtime/components/LibColorPicker/utils/truncate.js +5 -0
  30. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue +42 -64
  31. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue.d.ts +22 -0
  32. package/dist/runtime/components/LibDatePicker/LibDatePicker.vue +20 -54
  33. package/dist/runtime/components/LibDatePicker/LibDatePicker.vue.d.ts +40 -0
  34. package/dist/runtime/components/LibDatePicker/LibRangeDatePicker.vue +205 -173
  35. package/dist/runtime/components/LibDatePicker/LibRangeDatePicker.vue.d.ts +34 -0
  36. package/dist/runtime/components/LibDatePicker/LibSingleDatePicker.vue +215 -164
  37. package/dist/runtime/components/LibDatePicker/LibSingleDatePicker.vue.d.ts +34 -0
  38. package/dist/runtime/components/LibDatePicker/LibTimeZonePicker.vue +9 -10
  39. package/dist/runtime/components/LibDatePicker/LibTimeZonePicker.vue.d.ts +22 -0
  40. package/dist/runtime/components/LibDebug/LibDebug.vue +47 -65
  41. package/dist/runtime/components/LibDebug/LibDebug.vue.d.ts +32 -0
  42. package/dist/runtime/components/LibDevOnly/LibDevOnly.vue +19 -34
  43. package/dist/runtime/components/LibDevOnly/LibDevOnly.vue.d.ts +22 -0
  44. package/dist/runtime/components/LibFileInput/LibFileInput.vue +155 -173
  45. package/dist/runtime/components/LibFileInput/LibFileInput.vue.d.ts +43 -0
  46. package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.vue +352 -0
  47. package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.vue.d.ts +165 -0
  48. package/dist/runtime/components/LibLabel/LibLabel.vue +30 -46
  49. package/dist/runtime/components/LibLabel/LibLabel.vue.d.ts +27 -0
  50. package/dist/runtime/components/LibMultiValues/LibMultiValues.vue +50 -66
  51. package/dist/runtime/components/LibMultiValues/LibMultiValues.vue.d.ts +29 -0
  52. package/dist/runtime/components/LibNotifications/LibNotification.vue +48 -56
  53. package/dist/runtime/components/LibNotifications/LibNotification.vue.d.ts +17 -0
  54. package/dist/runtime/components/LibNotifications/LibNotifications.vue +71 -83
  55. package/dist/runtime/components/LibNotifications/LibNotifications.vue.d.ts +13 -0
  56. package/dist/runtime/components/LibPagination/LibPagination.vue +86 -131
  57. package/dist/runtime/components/LibPagination/LibPagination.vue.d.ts +104 -0
  58. package/dist/runtime/components/LibPalette/LibPalette.vue +23 -26
  59. package/dist/runtime/components/LibPalette/LibPalette.vue.d.ts +14 -0
  60. package/dist/runtime/components/LibPopup/LibPopup.vue +326 -400
  61. package/dist/runtime/components/LibPopup/LibPopup.vue.d.ts +46 -0
  62. package/dist/runtime/components/LibProgressBar/LibProgressBar.vue +73 -93
  63. package/dist/runtime/components/LibProgressBar/LibProgressBar.vue.d.ts +41 -0
  64. package/dist/runtime/components/LibRecorder/LibRecorder.vue +134 -179
  65. package/dist/runtime/components/LibRecorder/LibRecorder.vue.d.ts +77 -0
  66. package/dist/runtime/components/LibRoot/LibRoot.vue +75 -89
  67. package/dist/runtime/components/LibRoot/LibRoot.vue.d.ts +41 -0
  68. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.vue +51 -82
  69. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.vue.d.ts +35 -0
  70. package/dist/runtime/components/LibSuggestions/LibSuggestions.vue +147 -164
  71. package/dist/runtime/components/LibSuggestions/LibSuggestions.vue.d.ts +94 -0
  72. package/dist/runtime/components/LibTable/LibTable.vue +69 -106
  73. package/dist/runtime/components/LibTable/LibTable.vue.d.ts +45 -0
  74. package/dist/runtime/components/Template/NAME.vue +15 -36
  75. package/dist/runtime/components/Template/NAME.vue.d.ts +17 -0
  76. package/dist/runtime/components/TestControls/TestControls.vue +7 -10
  77. package/dist/runtime/components/TestControls/TestControls.vue.d.ts +5 -0
  78. package/dist/runtime/components/index.d.ts +12 -11
  79. package/dist/runtime/components/index.js +12 -11
  80. package/dist/runtime/components/shared/props.d.ts +81 -16
  81. package/dist/runtime/components/shared/storyHelpers/playInput.js +5 -5
  82. package/dist/runtime/components/shared/storyHelpers/playSuggestions.js +15 -11
  83. package/dist/runtime/composables/index.d.ts +5 -0
  84. package/dist/runtime/composables/index.js +5 -0
  85. package/dist/runtime/composables/useDivideAttrs.js +1 -0
  86. package/dist/runtime/composables/useDragWithThreshold.d.ts +71 -0
  87. package/dist/runtime/composables/useDragWithThreshold.js +40 -0
  88. package/dist/runtime/composables/usePreHydrationValue.d.ts +12 -0
  89. package/dist/runtime/composables/usePreHydrationValue.js +15 -0
  90. package/dist/runtime/composables/useSetupI18n.d.ts +2 -0
  91. package/dist/runtime/composables/useSetupI18n.js +5 -1
  92. package/dist/runtime/composables/useSuggestions.d.ts +7 -5
  93. package/dist/runtime/composables/useSuggestions.js +94 -57
  94. package/dist/runtime/directives/vResizableCols.js +92 -84
  95. package/dist/runtime/helpers/NotificationHandler.d.ts +5 -0
  96. package/dist/runtime/helpers/index.d.ts +3 -1
  97. package/dist/runtime/helpers/index.js +3 -1
  98. package/dist/runtime/types/index.d.ts +6 -0
  99. package/dist/runtime/utils/notifyIfError.d.ts +14 -0
  100. package/dist/runtime/utils/notifyIfError.js +29 -0
  101. package/dist/types.d.mts +2 -6
  102. package/package.json +27 -29
  103. package/src/module.ts +31 -12
  104. package/src/runtime/assets/base.css +10 -1
  105. package/src/runtime/assets/locales/en.json +2 -2
  106. package/src/runtime/assets/tailwind.css +1 -1
  107. package/src/runtime/assets/{style.css → utils.css} +86 -4
  108. package/src/runtime/build/WitchcraftUiResolver.ts +1 -1
  109. package/src/runtime/components/Focus.stories.ts +3 -2
  110. package/src/runtime/components/Icon/Icon.vue +10 -6
  111. package/src/runtime/components/LibButton/LibButton.vue +41 -47
  112. package/src/runtime/components/LibCheckbox/LibCheckbox.vue +7 -4
  113. package/src/runtime/components/LibColorInput/LibColorInput.vue +111 -37
  114. package/src/runtime/components/LibColorPicker/LibColorPicker.stories.ts +25 -4
  115. package/src/runtime/components/LibColorPicker/LibColorPicker.vue +242 -131
  116. package/src/runtime/components/LibColorPicker/utils/safeConvertToHsva.ts +24 -0
  117. package/src/runtime/components/LibColorPicker/utils/safeConvertToRgba.ts +23 -0
  118. package/src/runtime/components/LibColorPicker/utils/toLowPrecisionRgbaString.ts +13 -0
  119. package/src/runtime/components/LibColorPicker/utils/truncate.ts +6 -0
  120. package/src/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.ts +1 -1
  121. package/src/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue +11 -9
  122. package/src/runtime/components/LibDatePicker/LibDatePicker.vue +4 -17
  123. package/src/runtime/components/LibDatePicker/LibRangeDatePicker.vue +192 -131
  124. package/src/runtime/components/LibDatePicker/LibSingleDatePicker.vue +183 -115
  125. package/src/runtime/components/LibDatePicker/LibTimeZonePicker.vue +3 -3
  126. package/src/runtime/components/LibDebug/LibDebug.vue +15 -5
  127. package/src/runtime/components/LibDevOnly/LibDevOnly.vue +1 -3
  128. package/src/runtime/components/LibFileInput/LibFileInput.vue +54 -29
  129. package/src/runtime/components/{LibInput/LibInput.stories.ts → LibInputDeprecated/LibInputDeprecated.stories.ts} +64 -19
  130. package/{dist/runtime/components/LibInput/LibInput.vue → src/runtime/components/LibInputDeprecated/LibInputDeprecated.vue} +40 -34
  131. package/src/runtime/components/LibLabel/LibLabel.vue +2 -2
  132. package/src/runtime/components/LibMultiValues/LibMultiValues.stories.ts +5 -4
  133. package/src/runtime/components/LibMultiValues/LibMultiValues.vue +11 -13
  134. package/src/runtime/components/LibNotifications/LibNotification.vue +19 -11
  135. package/src/runtime/components/LibNotifications/LibNotifications.stories.ts +2 -2
  136. package/src/runtime/components/LibNotifications/LibNotifications.vue +20 -12
  137. package/src/runtime/components/LibPagination/LibPagination.stories.ts +2 -2
  138. package/src/runtime/components/LibPagination/LibPagination.vue +19 -20
  139. package/src/runtime/components/LibPalette/LibPalette.vue +3 -3
  140. package/src/runtime/components/LibPopup/LibPopup.stories.ts +2 -2
  141. package/src/runtime/components/LibPopup/LibPopup.vue +30 -67
  142. package/src/runtime/components/LibProgressBar/LibProgressBar.vue +3 -2
  143. package/src/runtime/components/LibRecorder/LibRecorder.vue +2 -3
  144. package/src/runtime/components/LibRoot/LibRoot.vue +14 -1
  145. package/src/runtime/components/LibSimpleInput/LibSimpleInput.stories.ts +1 -1
  146. package/src/runtime/components/LibSimpleInput/LibSimpleInput.vue +5 -8
  147. package/src/runtime/components/LibSuggestions/LibSuggestions.vue +42 -26
  148. package/src/runtime/components/LibTable/LibTable.vue +8 -9
  149. package/src/runtime/components/Scrolling.stories.ts +58 -0
  150. package/src/runtime/components/Template/NAME.vue +1 -1
  151. package/src/runtime/components/TestControls/TestControls.vue +1 -1
  152. package/src/runtime/components/index.ts +12 -12
  153. package/src/runtime/components/shared/props.ts +82 -19
  154. package/src/runtime/components/shared/storyHelpers/playInput.ts +6 -5
  155. package/src/runtime/components/shared/storyHelpers/playSuggestions.ts +25 -11
  156. package/src/runtime/composables/index.ts +5 -0
  157. package/src/runtime/composables/useDarkMode.ts +2 -2
  158. package/src/runtime/composables/useDivideAttrs.ts +1 -0
  159. package/src/runtime/composables/useDragWithThreshold.ts +108 -0
  160. package/src/runtime/composables/usePreHydrationValue.ts +30 -0
  161. package/src/runtime/composables/useSetupI18n.ts +8 -2
  162. package/src/runtime/composables/useSuggestions.ts +92 -45
  163. package/src/runtime/directives/vResizableCols.ts +82 -74
  164. package/src/runtime/helpers/NotificationHandler.ts +5 -0
  165. package/src/runtime/helpers/index.ts +3 -1
  166. package/src/runtime/types/index.ts +5 -0
  167. package/src/runtime/utils/notifyIfError.ts +45 -0
  168. package/dist/module.cjs +0 -5
  169. package/dist/module.d.ts +0 -34
  170. package/dist/runtime/assets/style.css +0 -1
  171. package/dist/runtime/components/Focus.stories.d.ts +0 -11
  172. package/dist/runtime/components/Focus.stories.js +0 -53
  173. package/dist/runtime/components/LibButton/LibButton.stories.d.ts +0 -12
  174. package/dist/runtime/components/LibButton/LibButton.stories.js +0 -94
  175. package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.d.ts +0 -14
  176. package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.js +0 -29
  177. package/dist/runtime/components/LibColorInput/LibColorInput.stories.d.ts +0 -7
  178. package/dist/runtime/components/LibColorInput/LibColorInput.stories.js +0 -58
  179. package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.d.ts +0 -7
  180. package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.js +0 -51
  181. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.d.ts +0 -7
  182. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.js +0 -36
  183. package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.d.ts +0 -11
  184. package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.js +0 -98
  185. package/dist/runtime/components/LibDebug/LibDebug.stories.d.ts +0 -9
  186. package/dist/runtime/components/LibDebug/LibDebug.stories.js +0 -46
  187. package/dist/runtime/components/LibFileInput/LibFileInput.stories.d.ts +0 -10
  188. package/dist/runtime/components/LibFileInput/LibFileInput.stories.js +0 -63
  189. package/dist/runtime/components/LibInput/LibInput.stories.d.ts +0 -33
  190. package/dist/runtime/components/LibInput/LibInput.stories.js +0 -339
  191. package/dist/runtime/components/LibLabel/LibLabel.stories.d.ts +0 -6
  192. package/dist/runtime/components/LibLabel/LibLabel.stories.js +0 -25
  193. package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.d.ts +0 -23
  194. package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.js +0 -60
  195. package/dist/runtime/components/LibNotifications/LibNotification.stories.d.ts +0 -15
  196. package/dist/runtime/components/LibNotifications/LibNotification.stories.js +0 -126
  197. package/dist/runtime/components/LibNotifications/LibNotifications.stories.d.ts +0 -6
  198. package/dist/runtime/components/LibNotifications/LibNotifications.stories.js +0 -109
  199. package/dist/runtime/components/LibPagination/LibPagination.stories.d.ts +0 -6
  200. package/dist/runtime/components/LibPagination/LibPagination.stories.js +0 -40
  201. package/dist/runtime/components/LibPalette/LibPalette.stories.d.ts +0 -6
  202. package/dist/runtime/components/LibPalette/LibPalette.stories.js +0 -20
  203. package/dist/runtime/components/LibPopup/LibPopup.stories.d.ts +0 -14
  204. package/dist/runtime/components/LibPopup/LibPopup.stories.js +0 -147
  205. package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.d.ts +0 -10
  206. package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.js +0 -81
  207. package/dist/runtime/components/LibRecorder/LibRecorder.stories.d.ts +0 -19
  208. package/dist/runtime/components/LibRecorder/LibRecorder.stories.js +0 -63
  209. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.d.ts +0 -26
  210. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.js +0 -78
  211. package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.d.ts +0 -27
  212. package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.js +0 -112
  213. package/dist/runtime/components/LibTable/LibTable.stories.d.ts +0 -16
  214. package/dist/runtime/components/LibTable/LibTable.stories.js +0 -156
  215. package/dist/runtime/components/reset.stories.d.ts +0 -5
  216. package/dist/runtime/components/reset.stories.js +0 -19
  217. package/dist/runtime/composables/useScrollNearContainerEdges.stories.d.ts +0 -7
  218. package/dist/runtime/composables/useScrollNearContainerEdges.stories.js +0 -85
  219. package/dist/runtime/helpers/addValue.d.ts +0 -1
  220. package/dist/runtime/helpers/addValue.js +0 -8
  221. package/dist/types.d.ts +0 -7
  222. package/src/runtime/components/LibInput/LibInput.vue +0 -372
  223. package/src/runtime/helpers/addValue.ts +0 -10
  224. /package/src/runtime/components/{reset.stories.ts → Reset.stories.ts} +0 -0
@@ -1,26 +1,33 @@
1
- <!-- Popover API WHEN :sob:
2
- #awaiting https://developer.mozilla.org/en-US/docs/Web/API/Popover_API#browser_compatibility -->
3
1
  <template>
4
2
  <slot name="button"
5
- :extract-el="(_:any)=> buttonEl = _"
3
+ :extract-el="(_) => buttonEl = _"
6
4
  />
7
5
  <!-- <Transition> -->
8
6
  <component
7
+ v-if="modelValue || useDialogForBackdrop"
9
8
  :id="id ?? fallbackId"
10
9
  :class="twMerge(
11
- useBackdrop && `bg-transparent
10
+ useBackdrop && useDialogForBackdrop && `
11
+ popup--backdrop
12
+ bg-transparent
12
13
  p-0
13
14
  backdrop:bg-transparent
14
15
  `,
15
- $attrs.class as any
16
- )"
17
- v-bind="{...$attrs, class:undefined}"
18
- :is="useBackdrop ? 'dialog' : 'div'"
16
+ modelValue && useBackdrop && !useDialogForBackdrop && `
17
+ popup--backdrop
18
+ z-100
19
+ fixed
20
+ inset-0
21
+ `,
22
+ $attrs.class
23
+ )"
24
+ v-bind="{ ...$attrs, class: void 0 }"
25
+ :is="useDialogForBackdrop ? 'dialog' : 'div'"
19
26
  ref="dialogEl"
20
27
  @mousedown.self="handleMouseup"
21
28
  >
22
- <div v-if="useBackdrop || modelValue"
23
- :class="`fixed ${props.avoidRepositioning ? 'transition-[top,left]' : ''}`"
29
+ <div v-if="modelValue"
30
+ :class="`popup z-100 fixed ${props.avoidRepositioning ? 'transition-[top,left]' : ''}`"
24
31
  :style="`
25
32
  top:${pos.y}px;
26
33
  left:${pos.x}px;
@@ -31,411 +38,330 @@
31
38
  <slot
32
39
  name="popup"
33
40
  :position="pos"
34
- :extract-el="(_:any) => popupEl = _"
41
+ :extract-el="(_) => popupEl = _"
35
42
  />
36
43
  </div>
37
44
  </component>
38
45
  <!-- </Transition> -->
39
46
  </template>
40
47
 
41
- <script setup lang="ts">
42
- // eslint-disable-next-line simple-import-sort/imports
43
- import { onMounted, nextTick, ref, useAttrs, watch , type HTMLAttributes } from "vue"
44
- import { getFallbackId, type LinkableByIdProps,type TailwindClassProp } from "../shared/props.js"
45
-
46
- import { twMerge } from "../../utils/twMerge.js"
47
- import { castType } from "@alanscodelog/utils/castType.js"
48
- import { isArray } from "@alanscodelog/utils/isArray.js"
49
- import type { IPopupReference, PopupPosition, PopupPositioner, PopupPositionModifier, SimpleDOMRect } from "../../types/index.js"
50
-
51
- const fallbackId = getFallbackId()
52
- // eslint-disable-next-line no-use-before-define
53
- const props = withDefaults(defineProps<Props>(), {
54
- useBackdrop: true,
55
- // vue is getting confused when the prop type can also be a function
56
- preferredHorizontal: () => ["center-most", "either"] satisfies Props["preferredHorizontal"],
57
- preferredVertical: () => ["top", "bottom", "either"] satisfies Props["preferredVertical"] ,
58
- avoidRepositioning: false,
59
- })
60
- const $attrs = useAttrs()
61
- defineOptions({ name: "lib-popup" })
62
-
63
-
64
- const dialogEl = ref<HTMLDialogElement | null>(null)
65
- const popupEl = ref<IPopupReference | null>(null)
66
- const buttonEl = ref<IPopupReference | null>(null)
67
- const backgroundEl = ref<IPopupReference | null>(null)
68
-
69
- const pos = ref<PopupPosition>({} as any)
70
- const modelValue = defineModel<boolean>({ default: false })
71
- let isOpen = false
72
-
73
-
74
- /**
75
- * We don't have access to the dialog backdrop and without extra styling, it's of 0 width/height, positioned in the center of the screen, with margins taking up all the space.
76
- *
77
- * This returns a modified rect that makes more logical sense.
78
- */
79
- const getDialogBoundingRect = (): SimpleDOMRect => ({
80
- x: 0,
81
- y: 0,
82
- width: window.innerWidth,
83
- height: window.innerHeight,
84
- top: 0,
85
- bottom: 0,
86
- left: 0,
87
- right: 0,
88
- })
89
- let lastButtonElPos: SimpleDOMRect | undefined
90
- const recompute = (force: boolean = false): void => {
91
- requestAnimationFrame(() => {
92
- const horzHasCenterScreen = isArray(props.preferredHorizontal)
93
- && props.preferredHorizontal[0] === "center-screen"
94
- const vertHasCenterScreen = isArray(props.preferredVertical)
95
- && props.preferredVertical[0] === "center-screen"
96
-
97
- const canBePositionedWithoutButton =
98
- (horzHasCenterScreen || typeof props.preferredHorizontal === "function")
99
- && (vertHasCenterScreen || typeof props.preferredVertical === "function")
100
-
101
- if (!popupEl.value || !dialogEl.value || (!buttonEl.value && !canBePositionedWithoutButton)) {
102
- pos.value = {} as any
103
- return
104
- }
105
- const el = buttonEl.value?.getBoundingClientRect()
106
- const bg = backgroundEl.value?.getBoundingClientRect() ?? (
107
- props.useBackdrop
108
- ? getDialogBoundingRect()
109
- : document.body.getBoundingClientRect()
110
- )
111
- const popup = popupEl.value.getBoundingClientRect()
112
-
113
- let finalPos: { x: number, y: number, maxWidth?: number, maxHeight?: number } = {} as any
114
-
115
-
116
- if (!force && modelValue.value && props.avoidRepositioning && buttonEl.value && lastButtonElPos) {
117
- const shiftX = buttonEl.value.getBoundingClientRect().x - lastButtonElPos.x
118
- const shiftY = buttonEl.value.getBoundingClientRect().y - lastButtonElPos.y
119
-
120
- pos.value.x += shiftX
121
- pos.value.y += shiftY
122
- lastButtonElPos = el
123
- return
124
- }
125
-
126
- const space = {
127
- left: 0,
128
- right: 0,
129
- leftLeft: 0,
130
- rightRight: 0,
131
- leftFromCenter: 0,
132
- rightFromCenter: 0,
133
- topFromCenter: 0,
134
- bottomFromCenter: 0,
135
- top: 0,
136
- bottom: 0,
137
- }
138
- if (el) {
139
- space.left = (el.x + el.width) - bg.x
140
- space.leftLeft = el.x - bg.x
141
- space.right = (bg.x + bg.width) - (el.x + el.width)
142
- space.rightRight = bg.x + bg.width - el.x
143
- space.leftFromCenter = (el.x + (el.width / 2)) - bg.x
144
- space.rightFromCenter = (bg.x + bg.width) - (el.x + (el.width / 2))
145
- space.topFromCenter = (el.y + (el.height / 2)) - bg.y
146
- space.bottomFromCenter = (bg.y + bg.height) - (el.y + (el.height / 2))
147
- space.top = el.y - bg.y
148
- space.bottom = (bg.y + bg.height) - (el.y + el.height)
149
- }
150
- const { preferredHorizontal, preferredVertical } = props
151
- let maxWidth: number | undefined
152
- let maxHeight: number | undefined
153
- if (typeof preferredHorizontal === "function") {
154
- finalPos.x = preferredHorizontal(el, popup, bg, space)
155
- } else {
156
- /* eslint-disable no-labels */
157
- outerloop:
158
- for (const type of preferredHorizontal) {
159
- switch (type) {
160
- case "center-screen":
161
- if (popup.width < bg.width) {
162
- finalPos.x = (bg.width / 2) - (popup.width / 2)
163
- } else {
164
- finalPos.x = 0
165
- maxWidth = finalPos.x
166
- }
167
- break
168
- case "center-most":
169
- case "center":
170
- castType<DOMRect>(el)
171
- if (space.leftFromCenter >= (popup.width / 2) &&
172
- space.rightFromCenter >= (popup.width / 2)) {
173
- finalPos.x = el.x + (el.width / 2) - (popup.width / 2)
174
- break outerloop
175
- }
176
- // todo temp fix when it's too wide, will prefer left
177
- if (((space.rightFromCenter + space.leftFromCenter) <= popup.width)) {
178
- finalPos.x = 0
179
- break outerloop
180
- }
181
- if (type === "center-most") {
182
- if (space.leftFromCenter < space.rightFromCenter) {
183
- finalPos.x = el.x + (el.width / 2) - space.leftFromCenter; break outerloop
184
- } else {
185
- finalPos.x = el.x + (el.width / 2) + space.rightFromCenter - popup.width; break outerloop
186
- }
187
- }
188
- break
189
- case "left-most":
190
- castType<DOMRect>(el)
191
- if (space.left >= popup.width) {
192
- finalPos.x = el.x - popup.width; break outerloop
193
- } else {
194
- finalPos.x = 0; break outerloop
195
- }
196
- case "right-most":
197
- castType<DOMRect>(el)
198
- if (space.right >= popup.width) {
199
- finalPos.x = el.x + el.width; break outerloop
200
- } else {
201
- finalPos.x = bg.x + bg.width - popup.width; break outerloop
202
- }
203
-
204
- case "right":
205
- castType<DOMRect>(el)
206
- if (space.right >= popup.width) {
207
- finalPos.x = el.x; break outerloop
208
- }
209
- break
210
- case "left":
211
- castType<DOMRect>(el)
212
- if (space.left >= popup.width) {
213
- finalPos.x = (el.x + el.width) - popup.width; break outerloop
214
- }
215
- break
216
- case "either": {
217
- castType<DOMRect>(el)
218
- if (space.right >= space.left) {
219
- finalPos.x = el.x; break outerloop
220
- } else {
221
- finalPos.x = (el.x + el.width) - popup.width
222
- break outerloop
223
- }
224
- }
225
- }
226
- }
227
- }
228
- if (typeof preferredVertical === "function") {
229
- finalPos.y = preferredVertical(el, popup, bg, space)
230
- } else {
231
- outerloop:
232
- for (const type of preferredVertical) {
233
- switch (type) {
234
- case "center-screen":
235
- if (popup.height < bg.height) {
236
- finalPos.y = (bg.height / 2) - (popup.height / 2)
237
- } else {
238
- finalPos.y = 0
239
- maxHeight = finalPos.y
240
- }
241
- break
242
- case "top":
243
- castType<DOMRect>(el)
244
- if (space.top >= popup.height) {
245
- finalPos.y = el.y - popup.height; break outerloop
246
- }
247
- break
248
- case "bottom":
249
- castType<DOMRect>(el)
250
- if (space.bottom >= popup.height) {
251
- finalPos.y = el.y + el.height; break outerloop
252
- }
253
- break
254
- case "top-most":
255
- castType<DOMRect>(el)
256
- if (space.top >= popup.height) {
257
- finalPos.y = el.y - popup.height; break outerloop
258
- } else {
259
- finalPos.y = 0; break outerloop
260
- }
261
- case "bottom-most":
262
- castType<DOMRect>(el)
263
- if (space.bottom >= popup.height) {
264
- finalPos.y = el.y + el.height; break outerloop
265
- } else {
266
- finalPos.y = bg.y + bg.height - popup.height; break outerloop
267
- }
268
- case "center-most":
269
- case "center":
270
- castType<DOMRect>(el)
271
- if (space.topFromCenter >= (popup.height / 2) &&
272
- space.bottomFromCenter >= (popup.height / 2)) {
273
- finalPos.y = el.y + (el.height / 2) - (popup.height / 2)
274
- break outerloop
275
- }
276
- // todo temp fix when it's too wide, will prefer the top
277
- if (((space.bottomFromCenter + space.topFromCenter) <= popup.height)) {
278
- finalPos.y = 0
279
- break outerloop
280
- }
281
- if (type === "center-most") {
282
- if (space.topFromCenter < space.bottomFromCenter) {
283
- finalPos.y = el.y + (el.height / 2) - space.topFromCenter; break outerloop
284
- } else {
285
- finalPos.y = el.y + (el.height / 2) + space.bottomFromCenter - popup.height; break outerloop
286
- }
287
- }
288
- break
289
- case "either": {
290
- castType<DOMRect>(el)
291
- if (space.top >= space.bottom) {
292
- finalPos.y = el.y - popup.height; break outerloop
293
- } else { finalPos.y = el.y + el.height; break outerloop }
294
- }
295
- }
296
- }
297
- }
298
- finalPos.maxWidth = maxWidth ?? undefined
299
- finalPos.maxHeight = maxHeight ?? undefined
300
- /* eslint-enable no-labels */
301
- if (props.modifyPosition) {
302
- finalPos = props.modifyPosition(finalPos, el, popup, bg, space)
303
- }
304
- pos.value = finalPos
305
- lastButtonElPos = el
306
- })
307
- }
308
-
48
+ <script setup>
49
+ import { onMounted, nextTick, ref, useAttrs, watch } from "vue";
50
+ import { getFallbackId } from "../shared/props.js";
51
+ import { twMerge } from "../../utils/twMerge.js";
52
+ import { castType } from "@alanscodelog/utils/castType.js";
53
+ import { isArray } from "@alanscodelog/utils/isArray.js";
54
+ const fallbackId = getFallbackId();
55
+ const props = defineProps({
56
+ id: { type: String, required: false },
57
+ useDialogForBackdrop: { type: Boolean, required: false, default: false },
58
+ useBackdrop: { type: Boolean, required: false, default: true },
59
+ preferredHorizontal: { type: [Array, Function], required: false, default: () => ["center-most", "either"] },
60
+ preferredVertical: { type: [Array, Function], required: false, default: () => ["top", "bottom", "either"] },
61
+ avoidRepositioning: { type: Boolean, required: false, default: false },
62
+ modifyPosition: { type: Function, required: false },
63
+ canClose: { type: Boolean, required: false, default: true }
64
+ });
65
+ const $attrs = useAttrs();
66
+ defineOptions({
67
+ name: "lib-popup",
68
+ inheritAttrs: false
69
+ });
70
+ const emit = defineEmits(["close"]);
71
+ const dialogEl = ref(null);
72
+ const popupEl = ref(null);
73
+ const buttonEl = ref(null);
74
+ const backgroundEl = ref(null);
75
+ const pos = ref({});
76
+ const modelValue = defineModel({ type: Boolean, ...{ default: false } });
77
+ let isOpen = false;
78
+ const getDialogBoundingRect = () => ({
79
+ x: 0,
80
+ y: 0,
81
+ width: window.innerWidth,
82
+ height: window.innerHeight,
83
+ top: 0,
84
+ bottom: 0,
85
+ left: 0,
86
+ right: 0
87
+ });
88
+ let lastButtonElPos;
89
+ const recompute = (force = false) => {
90
+ requestAnimationFrame(() => {
91
+ const horzHasCenterScreen = isArray(props.preferredHorizontal) && props.preferredHorizontal[0] === "center-screen";
92
+ const vertHasCenterScreen = isArray(props.preferredVertical) && props.preferredVertical[0] === "center-screen";
93
+ const canBePositionedWithoutButton = (horzHasCenterScreen || typeof props.preferredHorizontal === "function") && (vertHasCenterScreen || typeof props.preferredVertical === "function");
94
+ if (!popupEl.value || !dialogEl.value || !buttonEl.value && !canBePositionedWithoutButton) {
95
+ pos.value = {};
96
+ return;
97
+ }
98
+ const el = buttonEl.value?.getBoundingClientRect();
99
+ const bg = backgroundEl.value?.getBoundingClientRect() ?? (props.useBackdrop ? getDialogBoundingRect() : document.body.getBoundingClientRect());
100
+ const popup = popupEl.value.getBoundingClientRect();
101
+ let finalPos = {};
102
+ if (!force && modelValue.value && props.avoidRepositioning && buttonEl.value && lastButtonElPos) {
103
+ const shiftX = buttonEl.value.getBoundingClientRect().x - lastButtonElPos.x;
104
+ const shiftY = buttonEl.value.getBoundingClientRect().y - lastButtonElPos.y;
105
+ pos.value.x += shiftX;
106
+ pos.value.y += shiftY;
107
+ lastButtonElPos = el;
108
+ return;
109
+ }
110
+ const space = {
111
+ left: 0,
112
+ right: 0,
113
+ leftLeft: 0,
114
+ rightRight: 0,
115
+ leftFromCenter: 0,
116
+ rightFromCenter: 0,
117
+ topFromCenter: 0,
118
+ bottomFromCenter: 0,
119
+ top: 0,
120
+ bottom: 0
121
+ };
122
+ if (el) {
123
+ space.left = el.x + el.width - bg.x;
124
+ space.leftLeft = el.x - bg.x;
125
+ space.right = bg.x + bg.width - (el.x + el.width);
126
+ space.rightRight = bg.x + bg.width - el.x;
127
+ space.leftFromCenter = el.x + el.width / 2 - bg.x;
128
+ space.rightFromCenter = bg.x + bg.width - (el.x + el.width / 2);
129
+ space.topFromCenter = el.y + el.height / 2 - bg.y;
130
+ space.bottomFromCenter = bg.y + bg.height - (el.y + el.height / 2);
131
+ space.top = el.y - bg.y;
132
+ space.bottom = bg.y + bg.height - (el.y + el.height);
133
+ }
134
+ const { preferredHorizontal, preferredVertical } = props;
135
+ let maxWidth;
136
+ let maxHeight;
137
+ if (typeof preferredHorizontal === "function") {
138
+ finalPos.x = preferredHorizontal(el, popup, bg, space);
139
+ } else {
140
+ outerloop:
141
+ for (const type of preferredHorizontal) {
142
+ switch (type) {
143
+ case "center-screen":
144
+ if (popup.width < bg.width) {
145
+ finalPos.x = bg.width / 2 - popup.width / 2;
146
+ } else {
147
+ finalPos.x = 0;
148
+ maxWidth = finalPos.x;
149
+ }
150
+ break;
151
+ case "center-most":
152
+ case "center":
153
+ castType(el);
154
+ if (space.leftFromCenter >= popup.width / 2 && space.rightFromCenter >= popup.width / 2) {
155
+ finalPos.x = el.x + el.width / 2 - popup.width / 2;
156
+ break outerloop;
157
+ }
158
+ if (space.rightFromCenter + space.leftFromCenter <= popup.width) {
159
+ finalPos.x = 0;
160
+ break outerloop;
161
+ }
162
+ if (type === "center-most") {
163
+ if (space.leftFromCenter < space.rightFromCenter) {
164
+ finalPos.x = el.x + el.width / 2 - space.leftFromCenter;
165
+ break outerloop;
166
+ } else {
167
+ finalPos.x = el.x + el.width / 2 + space.rightFromCenter - popup.width;
168
+ break outerloop;
169
+ }
170
+ }
171
+ break;
172
+ case "left-most":
173
+ castType(el);
174
+ if (space.left >= popup.width) {
175
+ finalPos.x = el.x - popup.width;
176
+ break outerloop;
177
+ } else {
178
+ finalPos.x = 0;
179
+ break outerloop;
180
+ }
181
+ case "right-most":
182
+ castType(el);
183
+ if (space.right >= popup.width) {
184
+ finalPos.x = el.x + el.width;
185
+ break outerloop;
186
+ } else {
187
+ finalPos.x = bg.x + bg.width - popup.width;
188
+ break outerloop;
189
+ }
190
+ case "right":
191
+ castType(el);
192
+ if (space.right >= popup.width) {
193
+ finalPos.x = el.x;
194
+ break outerloop;
195
+ }
196
+ break;
197
+ case "left":
198
+ castType(el);
199
+ if (space.left >= popup.width) {
200
+ finalPos.x = el.x + el.width - popup.width;
201
+ break outerloop;
202
+ }
203
+ break;
204
+ case "either": {
205
+ castType(el);
206
+ if (space.right >= space.left) {
207
+ finalPos.x = el.x;
208
+ break outerloop;
209
+ } else {
210
+ finalPos.x = el.x + el.width - popup.width;
211
+ break outerloop;
212
+ }
213
+ }
214
+ }
215
+ }
216
+ }
217
+ if (typeof preferredVertical === "function") {
218
+ finalPos.y = preferredVertical(el, popup, bg, space);
219
+ } else {
220
+ outerloop:
221
+ for (const type of preferredVertical) {
222
+ switch (type) {
223
+ case "center-screen":
224
+ if (popup.height < bg.height) {
225
+ finalPos.y = bg.height / 2 - popup.height / 2;
226
+ } else {
227
+ finalPos.y = 0;
228
+ maxHeight = finalPos.y;
229
+ }
230
+ break;
231
+ case "top":
232
+ castType(el);
233
+ if (space.top >= popup.height) {
234
+ finalPos.y = el.y - popup.height;
235
+ break outerloop;
236
+ }
237
+ break;
238
+ case "bottom":
239
+ castType(el);
240
+ if (space.bottom >= popup.height) {
241
+ finalPos.y = el.y + el.height;
242
+ break outerloop;
243
+ }
244
+ break;
245
+ case "top-most":
246
+ castType(el);
247
+ if (space.top >= popup.height) {
248
+ finalPos.y = el.y - popup.height;
249
+ break outerloop;
250
+ } else {
251
+ finalPos.y = 0;
252
+ break outerloop;
253
+ }
254
+ case "bottom-most":
255
+ castType(el);
256
+ if (space.bottom >= popup.height) {
257
+ finalPos.y = el.y + el.height;
258
+ break outerloop;
259
+ } else {
260
+ finalPos.y = bg.y + bg.height - popup.height;
261
+ break outerloop;
262
+ }
263
+ case "center-most":
264
+ case "center":
265
+ castType(el);
266
+ if (space.topFromCenter >= popup.height / 2 && space.bottomFromCenter >= popup.height / 2) {
267
+ finalPos.y = el.y + el.height / 2 - popup.height / 2;
268
+ break outerloop;
269
+ }
270
+ if (space.bottomFromCenter + space.topFromCenter <= popup.height) {
271
+ finalPos.y = 0;
272
+ break outerloop;
273
+ }
274
+ if (type === "center-most") {
275
+ if (space.topFromCenter < space.bottomFromCenter) {
276
+ finalPos.y = el.y + el.height / 2 - space.topFromCenter;
277
+ break outerloop;
278
+ } else {
279
+ finalPos.y = el.y + el.height / 2 + space.bottomFromCenter - popup.height;
280
+ break outerloop;
281
+ }
282
+ }
283
+ break;
284
+ case "either": {
285
+ castType(el);
286
+ if (space.top >= space.bottom) {
287
+ finalPos.y = el.y - popup.height;
288
+ break outerloop;
289
+ } else {
290
+ finalPos.y = el.y + el.height;
291
+ break outerloop;
292
+ }
293
+ }
294
+ }
295
+ }
296
+ }
297
+ finalPos.maxWidth = maxWidth ?? void 0;
298
+ finalPos.maxHeight = maxHeight ?? void 0;
299
+ if (props.modifyPosition) {
300
+ finalPos = props.modifyPosition(finalPos, el, popup, bg, space);
301
+ }
302
+ pos.value = finalPos;
303
+ lastButtonElPos = el;
304
+ });
305
+ };
309
306
  const show = () => {
310
- if (!isOpen) {
311
- isOpen = true
312
- modelValue.value = isOpen
313
- if (props.useBackdrop) dialogEl.value?.showModal()
314
- recompute(true)
315
- }
316
- }
317
-
307
+ if (!isOpen) {
308
+ isOpen = true;
309
+ modelValue.value = isOpen;
310
+ if (props.useBackdrop && props.useDialogForBackdrop) dialogEl.value?.showModal();
311
+ recompute(true);
312
+ }
313
+ };
318
314
  const close = () => {
319
- if (isOpen) {
320
- isOpen = false
321
- modelValue.value = isOpen
322
- pos.value.maxWidth = undefined
323
- if (props.useBackdrop) dialogEl.value?.close()
324
- }
325
- }
326
-
315
+ if (isOpen) {
316
+ const res = props.canClose ?? false;
317
+ emit("close");
318
+ if (res === false) return;
319
+ isOpen = false;
320
+ modelValue.value = isOpen;
321
+ pos.value.maxWidth = void 0;
322
+ if (props.useBackdrop && props.useDialogForBackdrop) dialogEl.value?.close();
323
+ }
324
+ };
327
325
  const toggle = () => {
328
- if (!isOpen) show()
329
- else close()
330
- }
331
-
332
- const recomputeListener = () => recompute()
333
-
326
+ if (!isOpen) show();
327
+ else close();
328
+ };
329
+ const recomputeListener = () => recompute();
334
330
  const bindListeners = () => {
335
- window.addEventListener("resize", recomputeListener)
336
- window.addEventListener("scroll", recomputeListener, true)
337
- }
331
+ window.addEventListener("resize", recomputeListener);
332
+ window.addEventListener("scroll", recomputeListener, true);
333
+ };
338
334
  const unbindListeners = () => {
339
- window.removeEventListener("resize", recomputeListener)
340
- window.removeEventListener("scroll", recomputeListener, true)
341
- }
342
-
335
+ window.removeEventListener("resize", recomputeListener);
336
+ window.removeEventListener("scroll", recomputeListener, true);
337
+ };
343
338
  watch([modelValue, popupEl], () => {
344
- if (modelValue.value) {
345
- show()
346
- bindListeners()
347
- } else {
348
- close()
349
- unbindListeners()
350
- }
351
- })
352
-
353
-
354
- const handleMouseup = ($event: MouseEvent) => {
355
- $event.preventDefault()
356
- toggle()
357
- }
339
+ if (modelValue.value) {
340
+ show();
341
+ bindListeners();
342
+ } else {
343
+ close();
344
+ unbindListeners();
345
+ }
346
+ });
347
+ const handleMouseup = ($event) => {
348
+ $event.preventDefault();
349
+ toggle();
350
+ };
358
351
  onMounted(() => {
359
- recompute()
360
- })
361
-
352
+ recompute();
353
+ });
362
354
  defineExpose({
363
- recompute,
364
- setReference: (el: IPopupReference | null) => {
365
- buttonEl.value = el
366
- },
367
- setBackground: (el: IPopupReference | null) => {
368
- backgroundEl.value = el
369
- },
370
-
371
- })
372
-
355
+ recompute,
356
+ setReference: (el) => {
357
+ buttonEl.value = el;
358
+ },
359
+ setBackground: (el) => {
360
+ backgroundEl.value = el;
361
+ }
362
+ });
373
363
  </script>
374
- <script lang="ts">
375
364
 
376
- type RealProps =
377
- & LinkableByIdProps
378
- & {
379
- useBackdrop?: boolean
380
- /**
381
- * The preferred horizontal positioning of the popup. The first position in the array to fit is used.
382
- *
383
- * All elements need to have box-sizing: border-box set. Also note that while the component should work with dynamic popup sizes, in practice there's issues with the positioning being slightly off. Giving the popup element a static size is better. If you need margins around the popup, this can be done with a wrapper element + padding.
384
- *
385
- * The positions `right`/`left`/`top`/`bottom` are relative to the opposite side of the button element so as to try not to cover the triggering button.
386
- *
387
- * So positioning `right` and `left` look like this:
388
- *
389
- * ```
390
- * // right
391
- * [button]
392
- * [----popup----]
393
- *
394
- * // left
395
- * [button]
396
- * [----popup----]
397
- * ```
398
- *
399
- * Positions `*-most` try to position the popup as close to that side of the screen as possible, otherwise limiting the popup to that edge. For example:
400
- *
401
- * ```
402
- * [--------------screen---------------]
403
- * // right-most
404
- * [button]
405
- * [----popup----]
406
- * // near the edge:
407
- * [button]
408
- * [----popup----]
409
- * ```
410
- *
411
- * There is also the `center-screen` position, which centers the popup on the screen.
412
- *
413
- * These last two (`*-most` and `center-screen`) are greedy, they will always find a position that fits. Positions listed after are ignored.
414
- *
415
- * You can also specify a function instead which is given some additional information regarding the space around the button reference element. It should a number for the x position (or y, if preferredVertical).
416
- *
417
- * If you only need to slightly modify the position, you can use the `modifyPosition` option instead.
418
- */
419
- preferredHorizontal?: ("center" | "right" | "left" | "either" | "center-screen" | "right-most" | "left-most" | "center-most")[] | PopupPositioner
420
- /** See `preferredHorizontal`. */
421
- preferredVertical?: ("top" | "bottom" | "center" | "either" | "center-screen" | "top-most" | "bottom-most" | "center-most")[] | PopupPositioner
422
- /**
423
- * When the user scrolls or resizes, normally the entire popup position is recomputed, taking into account the preferred positioning.
424
- *
425
- * This can cause it to shift around.
426
- *
427
- * Set this to true to only shift the popup depending on how much the button element moved and avoid recalculating the best position.
428
- */
429
- avoidRepositioning?: boolean
430
- /**
431
- * Allows modifying the calculated position, to for example, clamp it.
432
- */
433
- modifyPosition?: PopupPositionModifier
434
- }
365
+ <script>
435
366
 
436
- interface Props
437
- extends
438
- /** @vue-ignore */
439
- Partial<Omit<HTMLAttributes,"class"> & TailwindClassProp>,
440
- RealProps { }
441
367
  </script>