@witchcraft/ui 0.1.1 → 0.1.3

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 (122) hide show
  1. package/dist/module.cjs +5 -0
  2. package/dist/module.d.ts +36 -0
  3. package/dist/module.json +2 -2
  4. package/dist/module.mjs +2 -1
  5. package/dist/runtime/assets/utils.css +1 -1
  6. package/dist/runtime/components/Aria/Aria.vue +9 -5
  7. package/dist/runtime/components/Focus.stories.d.ts +11 -0
  8. package/dist/runtime/components/Focus.stories.js +53 -0
  9. package/dist/runtime/components/Icon/Icon.vue +30 -10
  10. package/dist/runtime/components/LibButton/LibButton.stories.d.ts +12 -0
  11. package/dist/runtime/components/LibButton/LibButton.stories.js +94 -0
  12. package/dist/runtime/components/LibButton/LibButton.vue +72 -58
  13. package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.d.ts +14 -0
  14. package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.js +29 -0
  15. package/dist/runtime/components/LibCheckbox/LibCheckbox.vue +74 -48
  16. package/dist/runtime/components/LibColorInput/LibColorInput.stories.d.ts +7 -0
  17. package/dist/runtime/components/LibColorInput/LibColorInput.stories.js +58 -0
  18. package/dist/runtime/components/LibColorInput/LibColorInput.vue +107 -63
  19. package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.d.ts +9 -0
  20. package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.js +68 -0
  21. package/dist/runtime/components/LibColorPicker/LibColorPicker.vue +352 -271
  22. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.d.ts +7 -0
  23. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.js +36 -0
  24. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue +56 -32
  25. package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.d.ts +11 -0
  26. package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.js +98 -0
  27. package/dist/runtime/components/LibDatePicker/LibDatePicker.vue +38 -17
  28. package/dist/runtime/components/LibDatePicker/LibRangeDatePicker.vue +82 -53
  29. package/dist/runtime/components/LibDatePicker/LibSingleDatePicker.vue +67 -50
  30. package/dist/runtime/components/LibDatePicker/LibTimeZonePicker.vue +8 -7
  31. package/dist/runtime/components/LibDebug/LibDebug.stories.d.ts +9 -0
  32. package/dist/runtime/components/LibDebug/LibDebug.stories.js +46 -0
  33. package/dist/runtime/components/LibDebug/LibDebug.vue +70 -42
  34. package/dist/runtime/components/LibDevOnly/LibDevOnly.vue +31 -18
  35. package/dist/runtime/components/LibFileInput/LibFileInput.stories.d.ts +10 -0
  36. package/dist/runtime/components/LibFileInput/LibFileInput.stories.js +63 -0
  37. package/dist/runtime/components/LibFileInput/LibFileInput.vue +156 -113
  38. package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.stories.d.ts +33 -0
  39. package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.stories.js +384 -0
  40. package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.vue +241 -215
  41. package/dist/runtime/components/LibLabel/LibLabel.stories.d.ts +6 -0
  42. package/dist/runtime/components/LibLabel/LibLabel.stories.js +25 -0
  43. package/dist/runtime/components/LibLabel/LibLabel.vue +46 -30
  44. package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.d.ts +23 -0
  45. package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.js +61 -0
  46. package/dist/runtime/components/LibMultiValues/LibMultiValues.vue +58 -44
  47. package/dist/runtime/components/LibNotifications/LibNotification.stories.d.ts +15 -0
  48. package/dist/runtime/components/LibNotifications/LibNotification.stories.js +126 -0
  49. package/dist/runtime/components/LibNotifications/LibNotification.vue +48 -32
  50. package/dist/runtime/components/LibNotifications/LibNotifications.stories.d.ts +6 -0
  51. package/dist/runtime/components/LibNotifications/LibNotifications.stories.js +109 -0
  52. package/dist/runtime/components/LibNotifications/LibNotifications.vue +83 -63
  53. package/dist/runtime/components/LibPagination/LibPagination.stories.d.ts +6 -0
  54. package/dist/runtime/components/LibPagination/LibPagination.stories.js +40 -0
  55. package/dist/runtime/components/LibPagination/LibPagination.vue +111 -67
  56. package/dist/runtime/components/LibPalette/LibPalette.stories.d.ts +6 -0
  57. package/dist/runtime/components/LibPalette/LibPalette.stories.js +20 -0
  58. package/dist/runtime/components/LibPalette/LibPalette.vue +23 -20
  59. package/dist/runtime/components/LibPopup/LibPopup.stories.d.ts +14 -0
  60. package/dist/runtime/components/LibPopup/LibPopup.stories.js +147 -0
  61. package/dist/runtime/components/LibPopup/LibPopup.vue +351 -314
  62. package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.d.ts +10 -0
  63. package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.js +81 -0
  64. package/dist/runtime/components/LibProgressBar/LibProgressBar.vue +91 -70
  65. package/dist/runtime/components/LibRecorder/LibRecorder.stories.d.ts +19 -0
  66. package/dist/runtime/components/LibRecorder/LibRecorder.stories.js +63 -0
  67. package/dist/runtime/components/LibRecorder/LibRecorder.vue +177 -133
  68. package/dist/runtime/components/LibRoot/LibRoot.vue +100 -73
  69. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.d.ts +26 -0
  70. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.js +78 -0
  71. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.vue +77 -49
  72. package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.d.ts +27 -0
  73. package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.js +112 -0
  74. package/dist/runtime/components/LibSuggestions/LibSuggestions.vue +156 -123
  75. package/dist/runtime/components/LibTable/LibTable.stories.d.ts +16 -0
  76. package/dist/runtime/components/LibTable/LibTable.stories.js +156 -0
  77. package/dist/runtime/components/LibTable/LibTable.vue +99 -63
  78. package/dist/runtime/components/Reset.stories.d.ts +5 -0
  79. package/dist/runtime/components/Reset.stories.js +19 -0
  80. package/dist/runtime/components/Scrolling.stories.d.ts +6 -0
  81. package/dist/runtime/components/Scrolling.stories.js +44 -0
  82. package/dist/runtime/components/Template/NAME.vue +36 -15
  83. package/dist/runtime/components/TestControls/TestControls.vue +9 -6
  84. package/dist/runtime/composables/useScrollNearContainerEdges.stories.d.ts +7 -0
  85. package/dist/runtime/composables/useScrollNearContainerEdges.stories.js +85 -0
  86. package/dist/types.d.mts +6 -2
  87. package/dist/types.d.ts +7 -0
  88. package/package.json +11 -5
  89. package/src/module.ts +2 -1
  90. package/src/runtime/assets/utils.css +5 -5
  91. package/src/runtime/components/LibButton/LibButton.vue +2 -6
  92. package/src/runtime/nuxt/plugins/vue-plugin.ts +1 -1
  93. package/dist/runtime/components/Aria/Aria.vue.d.ts +0 -5
  94. package/dist/runtime/components/Icon/Icon.vue.d.ts +0 -21
  95. package/dist/runtime/components/LibButton/LibButton.vue.d.ts +0 -36
  96. package/dist/runtime/components/LibCheckbox/LibCheckbox.vue.d.ts +0 -42
  97. package/dist/runtime/components/LibColorInput/LibColorInput.vue.d.ts +0 -63
  98. package/dist/runtime/components/LibColorPicker/LibColorPicker.vue.d.ts +0 -61
  99. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue.d.ts +0 -22
  100. package/dist/runtime/components/LibDatePicker/LibDatePicker.vue.d.ts +0 -40
  101. package/dist/runtime/components/LibDatePicker/LibRangeDatePicker.vue.d.ts +0 -34
  102. package/dist/runtime/components/LibDatePicker/LibSingleDatePicker.vue.d.ts +0 -34
  103. package/dist/runtime/components/LibDatePicker/LibTimeZonePicker.vue.d.ts +0 -22
  104. package/dist/runtime/components/LibDebug/LibDebug.vue.d.ts +0 -32
  105. package/dist/runtime/components/LibDevOnly/LibDevOnly.vue.d.ts +0 -22
  106. package/dist/runtime/components/LibFileInput/LibFileInput.vue.d.ts +0 -43
  107. package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.vue.d.ts +0 -165
  108. package/dist/runtime/components/LibLabel/LibLabel.vue.d.ts +0 -27
  109. package/dist/runtime/components/LibMultiValues/LibMultiValues.vue.d.ts +0 -29
  110. package/dist/runtime/components/LibNotifications/LibNotification.vue.d.ts +0 -17
  111. package/dist/runtime/components/LibNotifications/LibNotifications.vue.d.ts +0 -13
  112. package/dist/runtime/components/LibPagination/LibPagination.vue.d.ts +0 -104
  113. package/dist/runtime/components/LibPalette/LibPalette.vue.d.ts +0 -14
  114. package/dist/runtime/components/LibPopup/LibPopup.vue.d.ts +0 -46
  115. package/dist/runtime/components/LibProgressBar/LibProgressBar.vue.d.ts +0 -41
  116. package/dist/runtime/components/LibRecorder/LibRecorder.vue.d.ts +0 -77
  117. package/dist/runtime/components/LibRoot/LibRoot.vue.d.ts +0 -41
  118. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.vue.d.ts +0 -35
  119. package/dist/runtime/components/LibSuggestions/LibSuggestions.vue.d.ts +0 -94
  120. package/dist/runtime/components/LibTable/LibTable.vue.d.ts +0 -45
  121. package/dist/runtime/components/Template/NAME.vue.d.ts +0 -17
  122. package/dist/runtime/components/TestControls/TestControls.vue.d.ts +0 -5
@@ -1,27 +1,29 @@
1
+ <!-- Popover API WHEN :sob:
2
+ #awaiting https://developer.mozilla.org/en-US/docs/Web/API/Popover_API#browser_compatibility -->
1
3
  <template>
2
4
  <slot name="button"
3
- :extract-el="(_) => buttonEl = _"
5
+ :extract-el="(_:any)=> buttonEl = _"
4
6
  />
5
7
  <!-- <Transition> -->
6
8
  <component
7
9
  v-if="modelValue || useDialogForBackdrop"
8
10
  :id="id ?? fallbackId"
9
11
  :class="twMerge(
10
- useBackdrop && useDialogForBackdrop && `
12
+ useBackdrop && useDialogForBackdrop && `
11
13
  popup--backdrop
12
14
  bg-transparent
13
15
  p-0
14
16
  backdrop:bg-transparent
15
17
  `,
16
- modelValue && useBackdrop && !useDialogForBackdrop && `
18
+ modelValue && useBackdrop && !useDialogForBackdrop && `
17
19
  popup--backdrop
18
20
  z-100
19
21
  fixed
20
22
  inset-0
21
23
  `,
22
- $attrs.class
23
- )"
24
- v-bind="{ ...$attrs, class: void 0 }"
24
+ $attrs.class as any
25
+ )"
26
+ v-bind="{...$attrs, class:undefined}"
25
27
  :is="useDialogForBackdrop ? 'dialog' : 'div'"
26
28
  ref="dialogEl"
27
29
  @mousedown.self="handleMouseup"
@@ -38,330 +40,365 @@
38
40
  <slot
39
41
  name="popup"
40
42
  :position="pos"
41
- :extract-el="(_) => popupEl = _"
43
+ :extract-el="(_:any) => popupEl = _"
42
44
  />
43
45
  </div>
44
46
  </component>
45
47
  <!-- </Transition> -->
46
48
  </template>
47
49
 
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();
50
+ <script setup lang="ts">
51
+ // eslint-disable-next-line simple-import-sort/imports
52
+ import { onMounted, nextTick, ref, useAttrs, watch , type HTMLAttributes } from "vue"
53
+ import { getFallbackId, type LinkableByIdProps, type TailwindClassProp, type PopupProps } from "../shared/props.js"
54
+
55
+ import { twMerge } from "../../utils/twMerge.js"
56
+ import { castType } from "@alanscodelog/utils/castType.js"
57
+ import { isArray } from "@alanscodelog/utils/isArray.js"
58
+ import type { IPopupReference, PopupPosition, PopupPositioner, PopupPositionModifier, SimpleDOMRect } from "../../types/index.js"
59
+
60
+ const fallbackId = getFallbackId()
61
+ const props = withDefaults(defineProps<Props>(), {
62
+ useBackdrop: true,
63
+ useDialogForBackdrop: false,
64
+ // vue is getting confused when the prop type can also be a function
65
+ preferredHorizontal: () => ["center-most", "either"] satisfies Props["preferredHorizontal"],
66
+ preferredVertical: () => ["top", "bottom", "either"] satisfies Props["preferredVertical"] ,
67
+ avoidRepositioning: false,
68
+ canClose: true,
69
+ })
70
+ const $attrs = useAttrs()
66
71
  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
- };
72
+ name: "lib-popup",
73
+ inheritAttrs: false
74
+ })
75
+
76
+ const emit = defineEmits<{
77
+ (e: "close"): void
78
+ }>()
79
+
80
+
81
+ const dialogEl = ref<HTMLDialogElement | null>(null)
82
+ const popupEl = ref<IPopupReference | null>(null)
83
+ const buttonEl = ref<IPopupReference | null>(null)
84
+ const backgroundEl = ref<IPopupReference | null>(null)
85
+
86
+ const pos = ref<PopupPosition>({} as any)
87
+ const modelValue = defineModel<boolean>({ default: false })
88
+ let isOpen = false
89
+
90
+
91
+ /**
92
+ * 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.
93
+ *
94
+ * This returns a modified rect that makes more logical sense.
95
+ */
96
+ const getDialogBoundingRect = (): SimpleDOMRect => ({
97
+ x: 0,
98
+ y: 0,
99
+ width: window.innerWidth,
100
+ height: window.innerHeight,
101
+ top: 0,
102
+ bottom: 0,
103
+ left: 0,
104
+ right: 0,
105
+ })
106
+ let lastButtonElPos: SimpleDOMRect | undefined
107
+ const recompute = (force: boolean = false): void => {
108
+ requestAnimationFrame(() => {
109
+ const horzHasCenterScreen = isArray(props.preferredHorizontal)
110
+ && props.preferredHorizontal[0] === "center-screen"
111
+ const vertHasCenterScreen = isArray(props.preferredVertical)
112
+ && props.preferredVertical[0] === "center-screen"
113
+
114
+ const canBePositionedWithoutButton =
115
+ (horzHasCenterScreen || typeof props.preferredHorizontal === "function")
116
+ && (vertHasCenterScreen || typeof props.preferredVertical === "function")
117
+ if (!popupEl.value || !dialogEl.value || (!buttonEl.value && !canBePositionedWithoutButton)) {
118
+ pos.value = {} as any
119
+ return
120
+ }
121
+ const el = buttonEl.value?.getBoundingClientRect()
122
+ const bg = backgroundEl.value?.getBoundingClientRect() ?? (
123
+ props.useBackdrop
124
+ ? getDialogBoundingRect()
125
+ : document.body.getBoundingClientRect()
126
+ )
127
+ const popup = popupEl.value.getBoundingClientRect()
128
+
129
+ let finalPos: { x: number, y: number, maxWidth?: number, maxHeight?: number } = {} as any
130
+
131
+
132
+ if (!force && modelValue.value && props.avoidRepositioning && buttonEl.value && lastButtonElPos) {
133
+ const shiftX = buttonEl.value.getBoundingClientRect().x - lastButtonElPos.x
134
+ const shiftY = buttonEl.value.getBoundingClientRect().y - lastButtonElPos.y
135
+
136
+ pos.value.x += shiftX
137
+ pos.value.y += shiftY
138
+ lastButtonElPos = el
139
+ return
140
+ }
141
+
142
+ const space = {
143
+ left: 0,
144
+ right: 0,
145
+ leftLeft: 0,
146
+ rightRight: 0,
147
+ leftFromCenter: 0,
148
+ rightFromCenter: 0,
149
+ topFromCenter: 0,
150
+ bottomFromCenter: 0,
151
+ top: 0,
152
+ bottom: 0,
153
+ }
154
+ if (el) {
155
+ space.left = (el.x + el.width) - bg.x
156
+ space.leftLeft = el.x - bg.x
157
+ space.right = (bg.x + bg.width) - (el.x + el.width)
158
+ space.rightRight = bg.x + bg.width - el.x
159
+ space.leftFromCenter = (el.x + (el.width / 2)) - bg.x
160
+ space.rightFromCenter = (bg.x + bg.width) - (el.x + (el.width / 2))
161
+ space.topFromCenter = (el.y + (el.height / 2)) - bg.y
162
+ space.bottomFromCenter = (bg.y + bg.height) - (el.y + (el.height / 2))
163
+ space.top = el.y - bg.y
164
+ space.bottom = (bg.y + bg.height) - (el.y + el.height)
165
+ }
166
+ const { preferredHorizontal, preferredVertical } = props
167
+ let maxWidth: number | undefined
168
+ let maxHeight: number | undefined
169
+ if (typeof preferredHorizontal === "function") {
170
+ finalPos.x = preferredHorizontal(el, popup, bg, space)
171
+ } else {
172
+ /* eslint-disable no-labels */
173
+ outerloop:
174
+ for (const type of preferredHorizontal) {
175
+ switch (type) {
176
+ case "center-screen":
177
+ if (popup.width < bg.width) {
178
+ finalPos.x = (bg.width / 2) - (popup.width / 2)
179
+ } else {
180
+ finalPos.x = 0
181
+ maxWidth = finalPos.x
182
+ }
183
+ break
184
+ case "center-most":
185
+ case "center":
186
+ castType<DOMRect>(el)
187
+ if (space.leftFromCenter >= (popup.width / 2) &&
188
+ space.rightFromCenter >= (popup.width / 2)) {
189
+ finalPos.x = el.x + (el.width / 2) - (popup.width / 2)
190
+ break outerloop
191
+ }
192
+ // todo temp fix when it's too wide, will prefer left
193
+ if (((space.rightFromCenter + space.leftFromCenter) <= popup.width)) {
194
+ finalPos.x = 0
195
+ break outerloop
196
+ }
197
+ if (type === "center-most") {
198
+ if (space.leftFromCenter < space.rightFromCenter) {
199
+ finalPos.x = el.x + (el.width / 2) - space.leftFromCenter; break outerloop
200
+ } else {
201
+ finalPos.x = el.x + (el.width / 2) + space.rightFromCenter - popup.width; break outerloop
202
+ }
203
+ }
204
+ break
205
+ case "left-most":
206
+ castType<DOMRect>(el)
207
+ if (space.left >= popup.width) {
208
+ finalPos.x = el.x - popup.width; break outerloop
209
+ } else {
210
+ finalPos.x = 0; break outerloop
211
+ }
212
+ case "right-most":
213
+ castType<DOMRect>(el)
214
+ if (space.right >= popup.width) {
215
+ finalPos.x = el.x + el.width; break outerloop
216
+ } else {
217
+ finalPos.x = bg.x + bg.width - popup.width; break outerloop
218
+ }
219
+
220
+ case "right":
221
+ castType<DOMRect>(el)
222
+ if (space.right >= popup.width) {
223
+ finalPos.x = el.x; break outerloop
224
+ }
225
+ break
226
+ case "left":
227
+ castType<DOMRect>(el)
228
+ if (space.left >= popup.width) {
229
+ finalPos.x = (el.x + el.width) - popup.width; break outerloop
230
+ }
231
+ break
232
+ case "either": {
233
+ castType<DOMRect>(el)
234
+ if (space.right >= space.left) {
235
+ finalPos.x = el.x; break outerloop
236
+ } else {
237
+ finalPos.x = (el.x + el.width) - popup.width
238
+ break outerloop
239
+ }
240
+ }
241
+ }
242
+ }
243
+ }
244
+ if (typeof preferredVertical === "function") {
245
+ finalPos.y = preferredVertical(el, popup, bg, space)
246
+ } else {
247
+ outerloop:
248
+ for (const type of preferredVertical) {
249
+ switch (type) {
250
+ case "center-screen":
251
+ if (popup.height < bg.height) {
252
+ finalPos.y = (bg.height / 2) - (popup.height / 2)
253
+ } else {
254
+ finalPos.y = 0
255
+ maxHeight = finalPos.y
256
+ }
257
+ break
258
+ case "top":
259
+ castType<DOMRect>(el)
260
+ if (space.top >= popup.height) {
261
+ finalPos.y = el.y - popup.height; break outerloop
262
+ }
263
+ break
264
+ case "bottom":
265
+ castType<DOMRect>(el)
266
+ if (space.bottom >= popup.height) {
267
+ finalPos.y = el.y + el.height; break outerloop
268
+ }
269
+ break
270
+ case "top-most":
271
+ castType<DOMRect>(el)
272
+ if (space.top >= popup.height) {
273
+ finalPos.y = el.y - popup.height; break outerloop
274
+ } else {
275
+ finalPos.y = 0; break outerloop
276
+ }
277
+ case "bottom-most":
278
+ castType<DOMRect>(el)
279
+ if (space.bottom >= popup.height) {
280
+ finalPos.y = el.y + el.height; break outerloop
281
+ } else {
282
+ finalPos.y = bg.y + bg.height - popup.height; break outerloop
283
+ }
284
+ case "center-most":
285
+ case "center":
286
+ castType<DOMRect>(el)
287
+ if (space.topFromCenter >= (popup.height / 2) &&
288
+ space.bottomFromCenter >= (popup.height / 2)) {
289
+ finalPos.y = el.y + (el.height / 2) - (popup.height / 2)
290
+ break outerloop
291
+ }
292
+ // todo temp fix when it's too wide, will prefer the top
293
+ if (((space.bottomFromCenter + space.topFromCenter) <= popup.height)) {
294
+ finalPos.y = 0
295
+ break outerloop
296
+ }
297
+ if (type === "center-most") {
298
+ if (space.topFromCenter < space.bottomFromCenter) {
299
+ finalPos.y = el.y + (el.height / 2) - space.topFromCenter; break outerloop
300
+ } else {
301
+ finalPos.y = el.y + (el.height / 2) + space.bottomFromCenter - popup.height; break outerloop
302
+ }
303
+ }
304
+ break
305
+ case "either": {
306
+ castType<DOMRect>(el)
307
+ if (space.top >= space.bottom) {
308
+ finalPos.y = el.y - popup.height; break outerloop
309
+ } else { finalPos.y = el.y + el.height; break outerloop }
310
+ }
311
+ }
312
+ }
313
+ }
314
+ finalPos.maxWidth = maxWidth ?? undefined
315
+ finalPos.maxHeight = maxHeight ?? undefined
316
+ /* eslint-enable no-labels */
317
+ if (props.modifyPosition) {
318
+ finalPos = props.modifyPosition(finalPos, el, popup, bg, space)
319
+ }
320
+ pos.value = finalPos
321
+ lastButtonElPos = el
322
+ })
323
+ }
324
+
306
325
  const show = () => {
307
- if (!isOpen) {
308
- isOpen = true;
309
- modelValue.value = isOpen;
310
- if (props.useBackdrop && props.useDialogForBackdrop) dialogEl.value?.showModal();
311
- recompute(true);
312
- }
313
- };
326
+ if (!isOpen) {
327
+ isOpen = true
328
+ modelValue.value = isOpen
329
+ if (props.useBackdrop && props.useDialogForBackdrop) dialogEl.value?.showModal()
330
+ recompute(true)
331
+ }
332
+ }
333
+
314
334
  const close = () => {
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
- };
335
+ if (isOpen) {
336
+ const res = props.canClose ?? false
337
+ emit("close")
338
+ if (res === false) return
339
+ isOpen = false
340
+ modelValue.value = isOpen
341
+ pos.value.maxWidth = undefined
342
+ if (props.useBackdrop && props.useDialogForBackdrop) dialogEl.value?.close()
343
+ }
344
+ }
345
+
325
346
  const toggle = () => {
326
- if (!isOpen) show();
327
- else close();
328
- };
329
- const recomputeListener = () => recompute();
347
+ if (!isOpen) show()
348
+ else close()
349
+ }
350
+
351
+ const recomputeListener = () => recompute()
352
+
330
353
  const bindListeners = () => {
331
- window.addEventListener("resize", recomputeListener);
332
- window.addEventListener("scroll", recomputeListener, true);
333
- };
354
+ window.addEventListener("resize", recomputeListener)
355
+ window.addEventListener("scroll", recomputeListener, true)
356
+ }
334
357
  const unbindListeners = () => {
335
- window.removeEventListener("resize", recomputeListener);
336
- window.removeEventListener("scroll", recomputeListener, true);
337
- };
358
+ window.removeEventListener("resize", recomputeListener)
359
+ window.removeEventListener("scroll", recomputeListener, true)
360
+ }
361
+
338
362
  watch([modelValue, popupEl], () => {
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
- };
363
+ if (modelValue.value) {
364
+ show()
365
+ bindListeners()
366
+ } else {
367
+ close()
368
+ unbindListeners()
369
+ }
370
+ })
371
+
372
+
373
+ const handleMouseup = ($event: MouseEvent) => {
374
+ $event.preventDefault()
375
+ toggle()
376
+ }
351
377
  onMounted(() => {
352
- recompute();
353
- });
378
+ recompute()
379
+ })
380
+
354
381
  defineExpose({
355
- recompute,
356
- setReference: (el) => {
357
- buttonEl.value = el;
358
- },
359
- setBackground: (el) => {
360
- backgroundEl.value = el;
361
- }
362
- });
382
+ recompute,
383
+ setReference: (el: IPopupReference | null) => {
384
+ buttonEl.value = el
385
+ },
386
+ setBackground: (el: IPopupReference | null) => {
387
+ backgroundEl.value = el
388
+ },
389
+
390
+ })
391
+
363
392
  </script>
393
+ <script lang="ts">
364
394
 
365
- <script>
395
+ type RealProps =
396
+ & LinkableByIdProps
397
+ & PopupProps
366
398
 
399
+ interface Props
400
+ extends
401
+ /** @vue-ignore */
402
+ Partial<Omit<HTMLAttributes,"class"> & TailwindClassProp>,
403
+ RealProps { }
367
404
  </script>