@eodash/eodash 5.3.3 → 5.5.0

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 (115) hide show
  1. package/core/client/asWebComponent.js +1 -1
  2. package/core/client/composables/DefineEodash.js +3 -1
  3. package/core/client/composables/DefineWidgets.js +12 -2
  4. package/core/client/eodashSTAC/EodashCollection.js +20 -37
  5. package/core/client/eodashSTAC/createLayers.js +306 -136
  6. package/core/client/eodashSTAC/helpers.js +60 -40
  7. package/core/client/eodashSTAC/parquet.js +2 -0
  8. package/core/client/eodashSTAC/triggers.js +5 -5
  9. package/core/client/store/actions.js +17 -17
  10. package/core/client/store/states.js +26 -4
  11. package/core/client/types.ts +12 -1
  12. package/core/client/utils/index.js +18 -1
  13. package/dist/client/{DashboardLayout-Cp8Rv3Ef.js → DashboardLayout-CkSgvaFF.js} +2 -2
  14. package/dist/client/{DynamicWebComponent-CBsxC82P.js → DynamicWebComponent-Ncsg6fb9.js} +1 -1
  15. package/dist/client/EodashChart-5v7adDpG.js +144 -0
  16. package/dist/client/{EodashDatePicker-Dewym-cx.js → EodashDatePicker-RoQJe6ss.js} +4 -4
  17. package/dist/client/{EodashItemFilter-CAsZpOoQ.js → EodashItemFilter-CCoVC5BE.js} +2 -2
  18. package/dist/client/{EodashLayerControl-fn-rt8Ac.js → EodashLayerControl-weVj7aQA.js} +2 -2
  19. package/dist/client/{EodashLayoutSwitcher-B9XqQXCS.js → EodashLayoutSwitcher-CL-Z9d5_.js} +3 -3
  20. package/dist/client/EodashMapBtns-CXU8IuPO.js +433 -0
  21. package/dist/client/{EodashStacInfo-lxBKoav9.js → EodashStacInfo-BbMnjf-n.js} +11 -15
  22. package/dist/client/{EodashTimeSlider-DI97QkNT.js → EodashTimeSlider-BZXnqfax.js} +2 -2
  23. package/dist/client/{EodashTools-D5ShUT1g.js → EodashTools-DUJlkkgx.js} +4 -4
  24. package/dist/client/{ExportState-ruNyRS2E.js → ExportState-CT3FQOHW.js} +46 -21
  25. package/dist/client/{Footer-IQNyfd78.js → Footer-D_iqP-1K.js} +1 -1
  26. package/dist/client/{Header-BBdi_-Lp.js → Header-Dzhnvsy-.js} +127 -17
  27. package/dist/client/MobileLayout-6Rg_PSO8.js +118 -0
  28. package/dist/client/{PopUp-DRgOmD7-.js → PopUp-DPPv_GSA.js} +8 -59
  29. package/dist/client/{ProcessList-DxyCFQdz.js → ProcessList-BIN_Mb27.js} +9 -13
  30. package/dist/client/{VImg-hwmwzSwG.js → VImg-DhbuvNrA.js} +2 -2
  31. package/dist/client/{VMain-vk4-rkw-.js → VMain-CVabY_NY.js} +1 -1
  32. package/dist/client/{VTooltip-BYUZeia1.js → VTooltip-Cc6au3Sn.js} +3 -4
  33. package/dist/client/{WidgetsContainer-DXD_8rqh.js → WidgetsContainer-ChqTJS4h.js} +1 -1
  34. package/dist/client/asWebComponent-DaIxULaA.js +9207 -0
  35. package/dist/client/{async-D1MvO_Z_.js → async-D6Lvv-fT.js} +15 -5
  36. package/dist/client/eo-dash.js +1 -1
  37. package/dist/client/{forwardRefs-DM-E2MfG.js → forwardRefs--IccUBdR.js} +196 -37
  38. package/dist/client/{handling-CbgeKrqT.js → handling-DSA67d6E.js} +160 -37
  39. package/dist/client/{helpers-CtUlAW0N.js → helpers-BBSdbOmv.js} +239 -126
  40. package/dist/client/{index-DBo0F4Fv.js → index-6LlXNkke.js} +5 -3
  41. package/dist/client/{index-BJvLt3Xf.js → index-BS-8Y5FE.js} +34 -77
  42. package/dist/client/{index-BkW06-Lg.js → index-CQihL_c6.js} +55 -15
  43. package/dist/client/{index-BxDh5v-H.js → index-qsZhYR_6.js} +15 -16
  44. package/dist/client/templates.js +52 -2
  45. package/dist/client/{transition-BdzATvPB.js → transition-DFr4cXu8.js} +1 -1
  46. package/dist/node/cli.js +1 -1
  47. package/dist/types/core/client/App.vue.d.ts +16 -6
  48. package/dist/types/core/client/asWebComponent.d.ts +2 -2
  49. package/dist/types/core/client/components/DashboardLayout.vue.d.ts +2 -1
  50. package/dist/types/core/client/components/DynamicWebComponent.vue.d.ts +36 -16
  51. package/dist/types/core/client/components/EodashOverlay.vue.d.ts +2 -1
  52. package/dist/types/core/client/components/ErrorAlert.vue.d.ts +9 -1
  53. package/dist/types/core/client/components/Footer.vue.d.ts +2 -1
  54. package/dist/types/core/client/components/Header.vue.d.ts +2 -1
  55. package/dist/types/core/client/components/IframeWrapper.vue.d.ts +12 -6
  56. package/dist/types/core/client/components/Loading.vue.d.ts +2 -1
  57. package/dist/types/core/client/components/MobileLayout.vue.d.ts +2 -1
  58. package/dist/types/core/client/composables/DefineEodash.d.ts +1 -1
  59. package/dist/types/core/client/eodashSTAC/EodashCollection.d.ts +27 -11
  60. package/dist/types/core/client/eodashSTAC/createLayers.d.ts +30 -23
  61. package/dist/types/core/client/eodashSTAC/helpers.d.ts +11 -4
  62. package/dist/types/core/client/store/actions.d.ts +1 -2
  63. package/dist/types/core/client/store/states.d.ts +22 -4
  64. package/dist/types/core/client/types.d.ts +7 -2
  65. package/dist/types/core/client/utils/index.d.ts +1 -0
  66. package/dist/types/core/client/views/Dashboard.vue.d.ts +20 -8
  67. package/dist/types/templates/compare.d.ts +20 -0
  68. package/dist/types/templates/expert.d.ts +30 -1
  69. package/dist/types/widgets/EodashChart.vue.d.ts +28 -0
  70. package/dist/types/widgets/EodashDatePicker.vue.d.ts +38 -9
  71. package/dist/types/widgets/EodashItemCatalog/index.vue.d.ts +88 -13
  72. package/dist/types/widgets/EodashItemCatalog/methods/map.d.ts +1 -1
  73. package/dist/types/widgets/EodashItemFilter.vue.d.ts +169 -26
  74. package/dist/types/widgets/EodashLayerControl.vue.d.ts +38 -10
  75. package/dist/types/widgets/EodashLayoutSwitcher.vue.d.ts +22 -7
  76. package/dist/types/widgets/EodashMap/EodashMapBtns.vue.d.ts +94 -19
  77. package/dist/types/widgets/EodashMap/index.vue.d.ts +647 -92
  78. package/dist/types/widgets/EodashMap/methods/btns.d.ts +14 -0
  79. package/dist/types/widgets/EodashProcess/ProcessList.vue.d.ts +24 -7
  80. package/dist/types/widgets/EodashProcess/index.vue.d.ts +26 -7
  81. package/dist/types/widgets/EodashProcess/methods/composables.d.ts +1 -2
  82. package/dist/types/widgets/EodashProcess/methods/handling.d.ts +18 -11
  83. package/dist/types/widgets/EodashProcess/methods/outputs.d.ts +2 -2
  84. package/dist/types/widgets/EodashProcess/methods/utils.d.ts +1 -0
  85. package/dist/types/widgets/EodashStacInfo.vue.d.ts +67 -18
  86. package/dist/types/widgets/EodashTimeSlider.vue.d.ts +14 -6
  87. package/dist/types/widgets/EodashTools.vue.d.ts +437 -47
  88. package/dist/types/widgets/ExportState.vue.d.ts +26 -8
  89. package/dist/types/widgets/PopUp.vue.d.ts +61 -11
  90. package/dist/types/widgets/WidgetsContainer.vue.d.ts +22 -6
  91. package/package.json +33 -34
  92. package/templates/baseConfig.js +2 -1
  93. package/templates/compare.js +28 -1
  94. package/templates/expert.js +23 -1
  95. package/widgets/EodashChart.vue +139 -0
  96. package/widgets/EodashItemCatalog/index.vue +2 -2
  97. package/widgets/EodashItemCatalog/methods/map.js +9 -10
  98. package/widgets/EodashMap/EodashMapBtns.vue +73 -93
  99. package/widgets/EodashMap/index.vue +14 -2
  100. package/widgets/EodashMap/methods/btns.js +155 -0
  101. package/widgets/EodashMap/methods/create-layers-config.js +26 -3
  102. package/widgets/EodashMap/methods/index.js +2 -1
  103. package/widgets/EodashProcess/ProcessList.vue +2 -3
  104. package/widgets/EodashProcess/index.vue +19 -70
  105. package/widgets/EodashProcess/methods/async.js +1 -1
  106. package/widgets/EodashProcess/methods/composables.js +13 -6
  107. package/widgets/EodashProcess/methods/custom-endpoints/chart/veda-endpoint.js +20 -7
  108. package/widgets/EodashProcess/methods/handling.js +100 -22
  109. package/widgets/EodashProcess/methods/outputs.js +44 -4
  110. package/widgets/EodashProcess/methods/utils.js +11 -1
  111. package/widgets/EodashStacInfo.vue +10 -23
  112. package/widgets/ExportState.vue +9 -15
  113. package/dist/client/EodashMapBtns-nFY6MIAX.js +0 -301
  114. package/dist/client/MobileLayout-BfBeF-JF.js +0 -118
  115. package/dist/client/asWebComponent-DdguWGDI.js +0 -8967
@@ -1,5 +1,5 @@
1
- import { q as getCompareLayers, p as getLayers, V as replaceLayer, a as extractLayerConfig, w as extractLayerLegend, m as mergeGeojsons, j as axios, W as axios$1, H as compareIndicator, F as indicator } from './helpers-CtUlAW0N.js';
2
- import { P as useEmitLayersUpdate } from './asWebComponent-DdguWGDI.js';
1
+ import { x as getCompareLayers, w as getLayers, $ as replaceLayer, b as extractLayerConfig, v as extractLayerLegend, m as mergeGeojsons, d as axios, a0 as axios$1, I as compareIndicator, G as indicator } from './helpers-BBSdbOmv.js';
2
+ import { P as useEmitLayersUpdate } from './asWebComponent-DaIxULaA.js';
3
3
  import { isMulti } from '@eox/jsonform/src/custom-inputs/spatial/utils';
4
4
  import log from 'loglevel';
5
5
 
@@ -502,6 +502,16 @@ function extractAsyncResults(resultItem) {
502
502
  }
503
503
  return extracted;
504
504
  }
505
+
506
+ /** @param {*} jsonformSchema */
507
+ const getDrawToolsProperty = (jsonformSchema) => {
508
+ for (const property in jsonformSchema.properties) {
509
+ if (jsonformSchema.properties[property]?.options?.drawtools) {
510
+ return property;
511
+ }
512
+ }
513
+ };
514
+
505
515
  /**
506
516
  * @param {import("@eox/map").EOxMap | null} mapElement
507
517
  * @param {import("@eox/map").EoxLayer[]} processLayers
@@ -527,7 +537,7 @@ const applyProcessLayersToMap = (mapElement, processLayers) => {
527
537
  (l) => l.properties?.id === layer.properties?.id,
528
538
  );
529
539
  if (!exists) {
530
- analysisGroup.layers.unshift(layer);
540
+ analysisGroup.layers.push(layer);
531
541
  } else {
532
542
  analysisGroup.layers = replaceLayer(
533
543
  analysisGroup.layers,
@@ -669,7 +679,7 @@ async function updateJobsStatus(jobs, indicator) {
669
679
  new Date(a.job_start_datetime).getTime()
670
680
  );
671
681
  });
672
- jobs.value = jobResults;
682
+ jobs.value.splice(0, jobs.value.length, ...jobResults);
673
683
  }
674
684
 
675
685
  /**
@@ -801,4 +811,4 @@ const getJobStatusUrl = (jobID, indicator) => {
801
811
  return jobUrl;
802
812
  };
803
813
 
804
- export { creatAsyncProcessLayerDefinitions as a, generateTimePairs as b, createTiffLayerDefinition as c, download as d, extractAsyncResults as e, updateJsonformSchemaTarget as f, getBboxProperty as g, extractGeometries as h, applyProcessLayersToMap as i, getJobStatusUrl as j, downloadPreviousResults as k, loadProcess as l, deleteJob as m, pollProcessStatus as p, separateEndpointLinks as s, updateJobsStatus as u };
814
+ export { creatAsyncProcessLayerDefinitions as a, getBboxProperty as b, createTiffLayerDefinition as c, download as d, extractAsyncResults as e, generateTimePairs as f, getDrawToolsProperty as g, updateJsonformSchemaTarget as h, extractGeometries as i, applyProcessLayersToMap as j, getJobStatusUrl as k, loadProcess as l, downloadPreviousResults as m, deleteJob as n, pollProcessStatus as p, separateEndpointLinks as s, updateJobsStatus as u };
@@ -1,2 +1,2 @@
1
- export { aI as EodashConstructor, aH as register, aJ as store } from './asWebComponent-DdguWGDI.js';
1
+ export { aJ as EodashConstructor, aI as register, aK as store } from './asWebComponent-DaIxULaA.js';
2
2
  import 'vue';
@@ -1,17 +1,18 @@
1
- import { computed, watch, onScopeDispose, nextTick, ref, watchEffect, effectScope, inject, mergeProps, shallowRef, onMounted, toRef, reactive, provide, toValue, toRaw, readonly, warn, onBeforeUnmount, createElementVNode, Fragment, createVNode, Teleport, withDirectives, vShow, Transition } from 'vue';
2
- import { ar as isOn, as as eventName, p as propsFactory, at as destructComputed, au as parseAnchor, av as flipSide, aw as flipAlign, ax as flipCorner, ay as CircularBuffer, az as deepEqual, X as consoleError, aA as getAxis, o as convertToUnit, v as clamp, ao as IN_BROWSER, y as useToggleScope, aB as defer, ak as getCurrentInstance, aC as templateRef, aD as matchesSelector, D as useDisplay, q as makeThemeProps, d as makeDimensionProps, e as makeComponentProps, g as genericComponent, x as useProxiedModel, k as provideTheme, l as useRtl, f as useBackgroundColor, b as useDimension, aE as useRouter, aF as useBackButton, an as standardEasing, c as useRender } from './asWebComponent-DdguWGDI.js';
3
- import { m as makeTransitionProps, M as MaybeTransition } from './transition-BdzATvPB.js';
1
+ import { computed, watch, onScopeDispose, nextTick, ref, watchEffect, effectScope, inject, mergeProps, toRef, toValue, shallowRef, onMounted, reactive, provide, toRaw, readonly, warn, onBeforeUnmount, createElementVNode, Fragment, createVNode, Teleport, withDirectives, vShow, Transition } from 'vue';
2
+ import { aq as isOn, ar as eventName, p as propsFactory, as as destructComputed, at as parseAnchor, au as flipSide, av as flipAlign, aw as flipCorner, ax as CircularBuffer, ay as deepEqual, Y as consoleError, az as getAxis, o as convertToUnit, v as clamp, aA as IN_BROWSER, y as useToggleScope, aB as defer, al as getCurrentInstance, aC as templateRef, aD as matchesSelector, aE as focusableChildren, D as useDisplay, q as makeThemeProps, d as makeDimensionProps, e as makeComponentProps, g as genericComponent, $ as omit, x as useProxiedModel, k as provideTheme, l as useRtl, f as useBackgroundColor, b as useDimension, aF as useRouter, aG as useBackButton, ao as standardEasing, c as useRender } from './asWebComponent-DaIxULaA.js';
3
+ import { m as makeTransitionProps, M as MaybeTransition } from './transition-DFr4cXu8.js';
4
4
 
5
5
  class Box {
6
6
  constructor(args) {
7
7
  const pageScale = document.body.currentCSSZoom ?? 1;
8
- const factor = args instanceof DOMRect ? 1 + (1 - pageScale) / pageScale : 1;
8
+ const isElement = args instanceof Element;
9
+ const factor = isElement ? 1 + (1 - pageScale) / pageScale : 1;
9
10
  const {
10
11
  x,
11
12
  y,
12
13
  width,
13
14
  height
14
- } = args;
15
+ } = isElement ? args.getBoundingClientRect() : args;
15
16
  this.x = x * factor;
16
17
  this.y = y * factor;
17
18
  this.width = width * factor;
@@ -53,7 +54,7 @@ function getTargetBox(target) {
53
54
  height: 0 * factor
54
55
  });
55
56
  } else {
56
- return new Box(target.getBoundingClientRect());
57
+ return new Box(target);
57
58
  }
58
59
  }
59
60
  function getElementBox(el) {
@@ -75,20 +76,14 @@ function getElementBox(el) {
75
76
  });
76
77
  }
77
78
  } else {
78
- const rect = el.getBoundingClientRect();
79
- return new Box({
80
- x: rect.x,
81
- y: rect.y,
82
- width: el.clientWidth,
83
- height: el.clientHeight
84
- });
79
+ return new Box(el);
85
80
  }
86
81
  }
87
82
 
88
83
  // Utilities
89
84
  /** @see https://stackoverflow.com/a/57876601/2074736 */
90
85
  function nullifyTransforms(el) {
91
- const rect = new Box(el.getBoundingClientRect());
86
+ const rect = new Box(el);
92
87
  const style = getComputedStyle(el);
93
88
  const tx = style.transform;
94
89
  if (tx) {
@@ -418,7 +413,11 @@ const makeLocationStrategyProps = propsFactory({
418
413
  default: 'auto'
419
414
  },
420
415
  offset: [Number, String, Array],
421
- stickToTarget: Boolean
416
+ stickToTarget: Boolean,
417
+ viewportMargin: {
418
+ type: [Number, String],
419
+ default: 12
420
+ }
422
421
  }, 'VOverlay-location-strategies');
423
422
  function useLocationStrategies(props, data) {
424
423
  const contentStyles = ref({});
@@ -605,7 +604,7 @@ function connectedLocationStrategy(data, props, contentStyles) {
605
604
 
606
605
  const contentBox = getIntrinsicSize(data.contentEl.value, data.isRtl.value);
607
606
  const scrollParents = getScrollParents(data.contentEl.value);
608
- const viewportMargin = 12;
607
+ const viewportMargin = Number(props.viewportMargin);
609
608
  if (!scrollParents.length) {
610
609
  scrollParents.push(document.documentElement);
611
610
  if (!(data.contentEl.value.style.top && data.contentEl.value.style.left)) {
@@ -625,10 +624,17 @@ function connectedLocationStrategy(data, props, contentStyles) {
625
624
  }
626
625
  return scrollBox;
627
626
  }, undefined);
628
- viewport.x += viewportMargin;
629
- viewport.y += viewportMargin;
630
- viewport.width -= viewportMargin * 2;
631
- viewport.height -= viewportMargin * 2;
627
+ if (props.stickToTarget) {
628
+ viewport.x += Math.min(viewportMargin, targetBox.x);
629
+ viewport.y += Math.min(viewportMargin, targetBox.y);
630
+ viewport.width = Math.max(viewport.width - viewportMargin * 2, targetBox.x + targetBox.width - viewportMargin);
631
+ viewport.height = Math.max(viewport.height - viewportMargin * 2, targetBox.y + targetBox.height - viewportMargin);
632
+ } else {
633
+ viewport.x += viewportMargin;
634
+ viewport.y += viewportMargin;
635
+ viewport.width -= viewportMargin * 2;
636
+ viewport.height -= viewportMargin * 2;
637
+ }
632
638
  let placement = {
633
639
  anchor: preferredAnchor.value,
634
640
  origin: preferredOrigin.value
@@ -739,19 +745,19 @@ function connectedLocationStrategy(data, props, contentStyles) {
739
745
 
740
746
  // shift
741
747
  if (overflows.x.before) {
742
- if (!props.stickToTarget) x += overflows.x.before;
748
+ x += overflows.x.before;
743
749
  contentBox.x += overflows.x.before;
744
750
  }
745
751
  if (overflows.x.after) {
746
- if (!props.stickToTarget) x -= overflows.x.after;
752
+ x -= overflows.x.after;
747
753
  contentBox.x -= overflows.x.after;
748
754
  }
749
755
  if (overflows.y.before) {
750
- if (!props.stickToTarget) y += overflows.y.before;
756
+ y += overflows.y.before;
751
757
  contentBox.y += overflows.y.before;
752
758
  }
753
759
  if (overflows.y.after) {
754
- if (!props.stickToTarget) y -= overflows.y.after;
760
+ y -= overflows.y.after;
755
761
  contentBox.y -= overflows.y.after;
756
762
  }
757
763
 
@@ -760,9 +766,9 @@ function connectedLocationStrategy(data, props, contentStyles) {
760
766
  const overflows = getOverflow(contentBox, viewport);
761
767
  available.x = viewport.width - overflows.x.before - overflows.x.after;
762
768
  available.y = viewport.height - overflows.y.before - overflows.y.after;
763
- if (!props.stickToTarget) x += overflows.x.before;
769
+ x += overflows.x.before;
764
770
  contentBox.x += overflows.x.before;
765
- if (!props.stickToTarget) y += overflows.y.before;
771
+ y += overflows.y.before;
766
772
  contentBox.y += overflows.y.before;
767
773
  }
768
774
  break;
@@ -985,11 +991,12 @@ const makeDelayProps = propsFactory({
985
991
  }, 'delay');
986
992
  function useDelay(props, cb) {
987
993
  let clearDelay = () => {};
988
- function runDelay(isOpening) {
994
+ function runDelay(isOpening, options) {
989
995
  clearDelay?.();
990
- const delay = Number(isOpening ? props.openDelay : props.closeDelay);
996
+ const delay = isOpening ? props.openDelay : props.closeDelay;
997
+ const normalizedDelay = Math.max(options?.minDelay ?? 0, Number(delay ?? 0));
991
998
  return new Promise(resolve => {
992
- clearDelay = defer(delay, () => {
999
+ clearDelay = defer(normalizedDelay, () => {
993
1000
  cb?.(isOpening);
994
1001
  resolve(isOpening);
995
1002
  });
@@ -998,8 +1005,8 @@ function useDelay(props, cb) {
998
1005
  function runOpenDelay() {
999
1006
  return runDelay(true);
1000
1007
  }
1001
- function runCloseDelay() {
1002
- return runDelay(false);
1008
+ function runCloseDelay(options) {
1009
+ return runDelay(false, options);
1003
1010
  }
1004
1011
  return {
1005
1012
  clearDelay,
@@ -1063,7 +1070,6 @@ function useActivator(props, _ref) {
1063
1070
  isActive.value = !isActive.value;
1064
1071
  },
1065
1072
  onMouseenter: e => {
1066
- if (e.sourceCapabilities?.firesTouchEvents) return;
1067
1073
  isHovered = true;
1068
1074
  activatorEl.value = e.currentTarget || e.target;
1069
1075
  runOpenDelay();
@@ -1082,7 +1088,9 @@ function useActivator(props, _ref) {
1082
1088
  onBlur: e => {
1083
1089
  isFocused = false;
1084
1090
  e.stopPropagation();
1085
- runCloseDelay();
1091
+ runCloseDelay({
1092
+ minDelay: 1
1093
+ });
1086
1094
  }
1087
1095
  };
1088
1096
  const activatorEvents = computed(() => {
@@ -1113,13 +1121,16 @@ function useActivator(props, _ref) {
1113
1121
  };
1114
1122
  }
1115
1123
  if (openOnFocus.value) {
1116
- events.onFocusin = () => {
1124
+ events.onFocusin = e => {
1125
+ if (!e.target.matches(':focus-visible')) return;
1117
1126
  isFocused = true;
1118
1127
  runOpenDelay();
1119
1128
  };
1120
1129
  events.onFocusout = () => {
1121
1130
  isFocused = false;
1122
- runCloseDelay();
1131
+ runCloseDelay({
1132
+ minDelay: 1
1133
+ });
1123
1134
  };
1124
1135
  }
1125
1136
  if (props.closeOnContentClick) {
@@ -1274,6 +1285,148 @@ function getTarget(selector, vm) {
1274
1285
  return target;
1275
1286
  }
1276
1287
 
1288
+ // Utilities
1289
+ // Types
1290
+ // Composables
1291
+ const makeFocusTrapProps = propsFactory({
1292
+ retainFocus: Boolean,
1293
+ captureFocus: Boolean,
1294
+ /** @deprecated */
1295
+ disableInitialFocus: Boolean
1296
+ }, 'focusTrap');
1297
+ const registry = new Map();
1298
+ let subscribers = 0;
1299
+ function onKeydown(e) {
1300
+ const activeElement = document.activeElement;
1301
+ if (e.key !== 'Tab' || !activeElement) return;
1302
+ const parentTraps = Array.from(registry.values()).filter(_ref => {
1303
+ let {
1304
+ isActive,
1305
+ contentEl
1306
+ } = _ref;
1307
+ return isActive.value && contentEl.value?.contains(activeElement);
1308
+ }).map(x => x.contentEl.value);
1309
+ let closestTrap;
1310
+ let currentParent = activeElement.parentElement;
1311
+ while (currentParent) {
1312
+ if (parentTraps.includes(currentParent)) {
1313
+ closestTrap = currentParent;
1314
+ break;
1315
+ }
1316
+ currentParent = currentParent.parentElement;
1317
+ }
1318
+ if (!closestTrap) return;
1319
+ const focusable = focusableChildren(closestTrap)
1320
+ // excluding VListItems with tabindex="-2"
1321
+ .filter(x => x.tabIndex >= 0);
1322
+ if (!focusable.length) return;
1323
+ const active = document.activeElement;
1324
+ if (focusable.length === 1 && focusable[0].classList.contains('v-list') && focusable[0].contains(active)) {
1325
+ e.preventDefault();
1326
+ return;
1327
+ }
1328
+ const firstElement = focusable[0];
1329
+ const lastElement = focusable[focusable.length - 1];
1330
+ if (e.shiftKey && (active === firstElement || firstElement.classList.contains('v-list') && firstElement.contains(active))) {
1331
+ e.preventDefault();
1332
+ lastElement.focus();
1333
+ }
1334
+ if (!e.shiftKey && (active === lastElement || lastElement.classList.contains('v-list') && lastElement.contains(active))) {
1335
+ e.preventDefault();
1336
+ firstElement.focus();
1337
+ }
1338
+ }
1339
+ function useFocusTrap(props, _ref2) {
1340
+ let {
1341
+ isActive,
1342
+ localTop,
1343
+ contentEl
1344
+ } = _ref2;
1345
+ const trapId = Symbol('trap');
1346
+ let focusTrapSuppressed = false;
1347
+ let focusTrapSuppressionTimeout = -1;
1348
+ async function onPointerdown() {
1349
+ focusTrapSuppressed = true;
1350
+ focusTrapSuppressionTimeout = window.setTimeout(() => {
1351
+ focusTrapSuppressed = false;
1352
+ }, 100);
1353
+ }
1354
+ async function captureOnFocus(e) {
1355
+ const before = e.relatedTarget;
1356
+ const after = e.target;
1357
+ document.removeEventListener('pointerdown', onPointerdown);
1358
+ document.removeEventListener('keydown', captureOnKeydown);
1359
+ await nextTick();
1360
+ if (isActive.value && !focusTrapSuppressed && before !== after && contentEl.value &&
1361
+ // We're the menu without open submenus or overlays
1362
+ toValue(localTop) &&
1363
+ // It isn't the document or the container body
1364
+ ![document, contentEl.value].includes(after) &&
1365
+ // It isn't inside the container body
1366
+ !contentEl.value.contains(after)) {
1367
+ const focusable = focusableChildren(contentEl.value);
1368
+ focusable[0]?.focus();
1369
+ }
1370
+ }
1371
+ function captureOnKeydown(e) {
1372
+ if (e.key !== 'Tab') return;
1373
+ document.removeEventListener('keydown', captureOnKeydown);
1374
+ if (isActive.value && contentEl.value && e.target && !contentEl.value.contains(e.target)) {
1375
+ const allFocusableElements = focusableChildren(document.documentElement);
1376
+ if (e.shiftKey && e.target === allFocusableElements.at(0) || !e.shiftKey && e.target === allFocusableElements.at(-1)) {
1377
+ const focusable = focusableChildren(contentEl.value);
1378
+ if (focusable.length > 0) {
1379
+ e.preventDefault();
1380
+ focusable[0].focus();
1381
+ }
1382
+ }
1383
+ }
1384
+ }
1385
+ const shouldCapture = toRef(() => isActive.value && props.captureFocus && !props.disableInitialFocus);
1386
+ if (IN_BROWSER) {
1387
+ watch(() => props.retainFocus, val => {
1388
+ if (val) {
1389
+ registry.set(trapId, {
1390
+ isActive,
1391
+ contentEl
1392
+ });
1393
+ } else {
1394
+ registry.delete(trapId);
1395
+ }
1396
+ }, {
1397
+ immediate: true
1398
+ });
1399
+ watch(shouldCapture, val => {
1400
+ if (val) {
1401
+ document.addEventListener('pointerdown', onPointerdown);
1402
+ document.addEventListener('focusin', captureOnFocus, {
1403
+ once: true
1404
+ });
1405
+ document.addEventListener('keydown', captureOnKeydown);
1406
+ } else {
1407
+ document.removeEventListener('pointerdown', onPointerdown);
1408
+ document.removeEventListener('focusin', captureOnFocus);
1409
+ document.removeEventListener('keydown', captureOnKeydown);
1410
+ }
1411
+ }, {
1412
+ immediate: true
1413
+ });
1414
+ if (subscribers++ < 1) {
1415
+ document.addEventListener('keydown', onKeydown);
1416
+ }
1417
+ }
1418
+ onScopeDispose(() => {
1419
+ registry.delete(trapId);
1420
+ clearTimeout(focusTrapSuppressionTimeout);
1421
+ document.removeEventListener('pointerdown', onPointerdown);
1422
+ document.removeEventListener('focusin', captureOnFocus);
1423
+ document.removeEventListener('keydown', captureOnKeydown);
1424
+ if (--subscribers < 1) {
1425
+ document.removeEventListener('keydown', onKeydown);
1426
+ }
1427
+ });
1428
+ }
1429
+
1277
1430
  // Composables
1278
1431
  function useHydration() {
1279
1432
  if (!IN_BROWSER) return shallowRef(false);
@@ -1432,6 +1585,7 @@ const makeVOverlayProps = propsFactory({
1432
1585
  ...makeLazyProps(),
1433
1586
  ...makeLocationStrategyProps(),
1434
1587
  ...makeScrollStrategyProps(),
1588
+ ...makeFocusTrapProps(),
1435
1589
  ...makeThemeProps(),
1436
1590
  ...makeTransitionProps()
1437
1591
  }, 'VOverlay');
@@ -1443,7 +1597,7 @@ const VOverlay = genericComponent()({
1443
1597
  inheritAttrs: false,
1444
1598
  props: {
1445
1599
  _disableGlobalStack: Boolean,
1446
- ...makeVOverlayProps()
1600
+ ...omit(makeVOverlayProps(), ['disableInitialFocus'])
1447
1601
  },
1448
1602
  emits: {
1449
1603
  'click:outside': e => true,
@@ -1543,10 +1697,14 @@ const VOverlay = genericComponent()({
1543
1697
  if (!props.persistent) isActive.value = false;else animateClick();
1544
1698
  }
1545
1699
  function closeConditional(e) {
1546
- return isActive.value && globalTop.value && (
1700
+ return isActive.value && localTop.value && (
1547
1701
  // If using scrim, only close if clicking on it rather than anything opened on top
1548
1702
  !props.scrim || e.target === scrimEl.value || e instanceof MouseEvent && e.shadowTarget === scrimEl.value);
1549
1703
  }
1704
+ useFocusTrap(props, {
1705
+ isActive,
1706
+ localTop,
1707
+ contentEl});
1550
1708
  IN_BROWSER && watch(isActive, val => {
1551
1709
  if (val) {
1552
1710
  window.addEventListener('keydown', onKeydown);
@@ -1672,6 +1830,7 @@ const VOverlay = genericComponent()({
1672
1830
  target,
1673
1831
  animateClick,
1674
1832
  contentEl,
1833
+ rootEl: root,
1675
1834
  globalTop,
1676
1835
  localTop,
1677
1836
  updateLocation