edvoyui-component-library-test-flight 0.0.248 → 0.0.249

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.
@@ -37,6 +37,8 @@ interface Props {
37
37
  maxVisibleTags?: number;
38
38
  tagSize?: "sm" | "md" | "lg";
39
39
  dropdownWidth?: string;
40
+ /** Render the menu at body level to escape clipping scroll containers. */
41
+ teleported?: boolean;
40
42
  }
41
43
  export type SelectItemKey = string | (string | number)[] | ((item: object, fallback?: any) => any);
42
44
  declare function __VLS_template(): {
@@ -194,6 +196,8 @@ declare function __VLS_template(): {
194
196
  activeOptionId: string;
195
197
  expanded: boolean;
196
198
  }> | null;
199
+ triggerButtonRef: HTMLButtonElement;
200
+ dropdownContentRef: HTMLDivElement;
197
201
  options: HTMLUListElement;
198
202
  };
199
203
  rootEl: HTMLDivElement;
@@ -231,6 +235,7 @@ declare const __VLS_component: import('../../../node_modules/vue').DefineCompone
231
235
  clearable: boolean;
232
236
  searchable: boolean;
233
237
  placement: "auto" | "auto-start" | "auto-end" | "top" | "top-start" | "top-end" | "bottom" | "bottom-start" | "bottom-end" | "right" | "right-start" | "right-end" | "left" | "left-start" | "left-end";
238
+ teleported: boolean;
234
239
  classes: string;
235
240
  backendPagination: boolean;
236
241
  itemText: string;
@@ -387,6 +392,8 @@ declare const __VLS_component: import('../../../node_modules/vue').DefineCompone
387
392
  activeOptionId: string;
388
393
  expanded: boolean;
389
394
  }> | null;
395
+ triggerButtonRef: HTMLButtonElement;
396
+ dropdownContentRef: HTMLDivElement;
390
397
  options: HTMLUListElement;
391
398
  }, HTMLDivElement>;
392
399
  declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
@@ -10,16 +10,19 @@
10
10
  </label>
11
11
  </slot>
12
12
  <Popper
13
- :class="[`popper-defaultstyle w-full ${popperClasses}`]"
13
+ :class="[
14
+ `popper-defaultstyle w-full ${popperClasses}`,
15
+ { 'search-tag-select--teleported': teleported },
16
+ ]"
14
17
  v-bind="$attrs"
15
18
  :show="showDropDown"
16
- arrow
19
+ :arrow="!teleported"
17
20
  closeDelay="100"
18
21
  :offsetSkid="offsetSkid"
19
22
  :offsetDistance="offsetDistance"
20
23
  :placement="placement"
21
24
  :interactive="true"
22
- :auto-hide="true"
25
+ :auto-hide="!teleported"
23
26
  @open:popper="handleOpen"
24
27
  @close:popper="handleClose"
25
28
  >
@@ -41,6 +44,7 @@
41
44
  />
42
45
  <button
43
46
  v-else-if="!showDropDown && selectedValues.length > 0"
47
+ ref="triggerButtonRef"
44
48
  type="button"
45
49
  :disabled="disabled"
46
50
  class="flex items-center justify-between w-full h-10 gap-2 px-4 py-2 text-left bg-white border border-gray-200 border-solid cursor-pointer search-textstyle rounded-3xl focus-within:outline-violet-200"
@@ -90,10 +94,13 @@
90
94
  </div>
91
95
  </button>
92
96
  <template #content>
93
- <div
94
- v-if="showDropDown"
95
- :class="['w-full p-3 text-sm bg-white border-2 border-gray-100 border-solid shadow-lg rounded-3xl min-w-28', confirmSelection && selectType === 'multiple' ? '' : 'overflow-y-auto max-h-72 scrollbar--hide', dropdownWidth]"
96
- >
97
+ <Teleport to="body" :disabled="!teleported">
98
+ <div
99
+ v-if="showDropDown"
100
+ ref="dropdownContentRef"
101
+ :class="['w-full p-3 text-sm bg-white border-2 border-gray-100 border-solid shadow-lg rounded-3xl min-w-28', confirmSelection && selectType === 'multiple' ? '' : 'overflow-y-auto max-h-72 scrollbar--hide', dropdownWidth, teleported ? 'z-[60]' : '']"
102
+ @click.stop
103
+ >
97
104
  <div class="flex items-center justify-between p-2 pb-0 mb-1 -mx-px -mt-3">
98
105
  <h3
99
106
  class="mb-0 text-xs font-semibold tracking-wide text-gray-500 uppercase bg-white "
@@ -120,7 +127,7 @@
120
127
  tabindex="-1"
121
128
  role="listbox"
122
129
  aria-label="Search results"
123
- :class="['space-y-0.5', confirmSelection && selectType === 'multiple' ? 'max-h-52 overflow-y-auto scrollbar--hide' : '']"
130
+ :class="['space-y-0.5', confirmSelection && selectType === 'multiple' ? 'max-h-48 overflow-y-auto scrollbar--hide' : '']"
124
131
  >
125
132
  <li
126
133
  v-if="showAllOption"
@@ -268,7 +275,8 @@
268
275
  Apply
269
276
  </EUIButton>
270
277
  </div>
271
- </div>
278
+ </div>
279
+ </Teleport>
272
280
  </template>
273
281
  </Popper>
274
282
  <template v-if="errors && errors.length && !showDropDown">
@@ -351,6 +359,7 @@ import EUICheckbox from "../checkbox/EUICheckbox.vue";
351
359
  import EUITag from "../tag/EUITag.vue";
352
360
  import EUIButton from "../button/EUIButton.vue";
353
361
  import Popper from "vue3-popper";
362
+ import { createPopper, type Instance } from "@popperjs/core";
354
363
  import CheckTick from "../../assets/svg/CheckTick.vue";
355
364
  import { XMarkIcon } from "@heroicons/vue/20/solid";
356
365
  import EUIErrorMessage from "../errorMessage/EUIErrorMessage.vue";
@@ -409,6 +418,8 @@ interface Props {
409
418
  maxVisibleTags?: number;
410
419
  tagSize?: "sm" | "md" | "lg";
411
420
  dropdownWidth?: string,
421
+ /** Render the menu at body level to escape clipping scroll containers. */
422
+ teleported?: boolean;
412
423
  }
413
424
  const props = withDefaults(defineProps<Props>(), {
414
425
  items: () => [],
@@ -440,7 +451,8 @@ const props = withDefaults(defineProps<Props>(), {
440
451
  selectAllLabel: "All",
441
452
  maxVisibleTags: 0,
442
453
  tagSize: "md",
443
- dropdownWidth: ''
454
+ dropdownWidth: '',
455
+ teleported: false,
444
456
  });
445
457
 
446
458
 
@@ -464,6 +476,9 @@ const draftValues = ref<any[]>([]);
464
476
  const options = ref<HTMLElement>();
465
477
  const searchInputRef = ref<any>();
466
478
  const componentRef = ref<HTMLElement>();
479
+ const triggerButtonRef = ref<HTMLButtonElement>();
480
+ const dropdownContentRef = ref<HTMLElement>();
481
+ let teleportedPopper: Instance | undefined;
467
482
  const tagsExpanded = ref(false);
468
483
  const highlightedIndex = ref(-1);
469
484
  const listboxId = `search-tag-listbox-${getCurrentInstance()?.uid ?? 0}`;
@@ -828,6 +843,43 @@ const handleSearchKeydown = (event: KeyboardEvent) => {
828
843
  else handleSelect(item);
829
844
  };
830
845
 
846
+ const destroyTeleportedPopper = () => {
847
+ teleportedPopper?.destroy();
848
+ teleportedPopper = undefined;
849
+ };
850
+
851
+ const createTeleportedPopper = () => {
852
+ if (!props.teleported || !dropdownContentRef.value) return;
853
+
854
+ const trigger =
855
+ (searchInputRef.value?.$el as HTMLElement | undefined) ||
856
+ triggerButtonRef.value;
857
+ if (!trigger) return;
858
+
859
+ destroyTeleportedPopper();
860
+ teleportedPopper = createPopper(trigger, dropdownContentRef.value, {
861
+ placement: props.placement,
862
+ strategy: "fixed",
863
+ modifiers: [
864
+ {
865
+ name: "offset",
866
+ options: { offset: [Number(props.offsetSkid), Number(props.offsetDistance)] },
867
+ },
868
+ { name: "flip", options: { padding: 8 } },
869
+ { name: "preventOverflow", options: { padding: 8 } },
870
+ {
871
+ name: "sameWidth",
872
+ enabled: true,
873
+ phase: "beforeWrite",
874
+ requires: ["computeStyles"],
875
+ fn: ({ state }) => {
876
+ state.styles.popper.width = `${state.rects.reference.width}px`;
877
+ },
878
+ },
879
+ ],
880
+ });
881
+ };
882
+
831
883
  const handleOpen = () => {
832
884
  if (props.disabled || showDropDown.value) return;
833
885
 
@@ -847,6 +899,7 @@ const handleOpen = () => {
847
899
 
848
900
  nextTick(() => {
849
901
  if (!showDropDown.value) return;
902
+ createTeleportedPopper();
850
903
  focusTimer = setTimeout(() => {
851
904
  focusTimer = undefined;
852
905
  if (!showDropDown.value) return;
@@ -878,6 +931,7 @@ const handleApply = () => {
878
931
  const handleClose = () => {
879
932
  highlightedIndex.value = -1;
880
933
  window.removeEventListener("scroll", handleScroll, true);
934
+ destroyTeleportedPopper();
881
935
  if (focusTimer) {
882
936
  clearTimeout(focusTimer);
883
937
  focusTimer = undefined;
@@ -914,7 +968,8 @@ const handleDocumentClick = (event: MouseEvent) => {
914
968
  if (
915
969
  showDropDown.value &&
916
970
  componentRef.value &&
917
- !event.composedPath().includes(componentRef.value)
971
+ !event.composedPath().includes(componentRef.value) &&
972
+ !event.composedPath().includes(dropdownContentRef.value as EventTarget)
918
973
  ) {
919
974
  handleDismiss();
920
975
  }
@@ -922,6 +977,10 @@ const handleDocumentClick = (event: MouseEvent) => {
922
977
 
923
978
  const handleScroll = (event: Event) => {
924
979
  if (!showDropDown.value) return;
980
+ if (props.teleported) {
981
+ teleportedPopper?.update();
982
+ return;
983
+ }
925
984
  const target = event.target;
926
985
  // Keep the options usable; scrolling any ancestor or the page closes them.
927
986
  if (target instanceof Node && componentRef.value?.contains(target)) return;
@@ -936,6 +995,7 @@ onMounted(() => {
936
995
  onUnmounted(() => {
937
996
  document.removeEventListener("click", handleDocumentClick);
938
997
  window.removeEventListener("scroll", handleScroll, true);
998
+ destroyTeleportedPopper();
939
999
  if (focusTimer) clearTimeout(focusTimer);
940
1000
  });
941
1001
 
@@ -955,6 +1015,10 @@ watch(internalSearch, (value: string) => {
955
1015
  & > div.popper {
956
1016
  width: 100% !important;
957
1017
  }
1018
+
1019
+ &.search-tag-select--teleported > div.popper {
1020
+ display: none !important;
1021
+ }
958
1022
  }
959
1023
 
960
1024
  .show-count {