fds-vue-core 8.7.0 → 8.8.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.
@@ -3,5 +3,6 @@ type __VLS_Props = {
3
3
  };
4
4
  declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
5
5
  containerRef: HTMLDivElement;
6
+ popoverRef: HTMLDivElement;
6
7
  }, HTMLDivElement>;
7
8
  export default _default;
@@ -33,5 +33,7 @@ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {
33
33
  }>, {
34
34
  environment: DevModeEnvironmentKey | null;
35
35
  toggles: DevModeOverlayToggle[];
36
- }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
36
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
37
+ overlayRef: HTMLDivElement;
38
+ }, any>;
37
39
  export default _default;
@@ -0,0 +1,41 @@
1
+ import { Ref } from 'vue';
2
+ export declare const VIEWPORT_MARGIN = 8;
3
+ export declare function clampBoxToViewport(box: {
4
+ left: number;
5
+ top: number;
6
+ width: number;
7
+ height: number;
8
+ }, viewport: {
9
+ width: number;
10
+ height: number;
11
+ }, margin?: number): {
12
+ left: number;
13
+ top: number;
14
+ width: number;
15
+ height: number;
16
+ };
17
+ export declare function computeAnchoredPlacement(args: {
18
+ anchorLeft: number;
19
+ anchorTop: number;
20
+ anchorWidth: number;
21
+ anchorHeight: number;
22
+ contentWidth: number;
23
+ contentHeight: number;
24
+ viewportWidth: number;
25
+ viewportHeight: number;
26
+ margin?: number;
27
+ gap?: number;
28
+ align?: 'start' | 'end';
29
+ }): {
30
+ above: boolean;
31
+ left: number;
32
+ maxHeight: number;
33
+ maxWidth: number;
34
+ };
35
+ /** Keeps an absolutely positioned popover inside the viewport, anchored to its parent. */
36
+ export declare function useStickInViewport(targetRef: Ref<HTMLElement | null>, options?: {
37
+ gap?: number;
38
+ align?: 'start' | 'end';
39
+ }): {
40
+ style: Ref<Record<string, string>, Record<string, string>>;
41
+ };
@@ -4,6 +4,7 @@ export declare function useModalDragResize(options: {
4
4
  resizable: Ref<boolean>;
5
5
  elementRef: Ref<HTMLElement | null>;
6
6
  heading: Ref<string>;
7
+ constrainToViewport?: boolean;
7
8
  }): {
8
9
  isCustomPositioned: import('vue').ComputedRef<boolean>;
9
10
  style: import('vue').ComputedRef<Record<string, string> | undefined>;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Query on the previous history entry is restored by the browser back button.
3
+ * `router.push('/path')` drops it.
4
+ * When that entry's pathname matches, reuse its full path.
5
+ */
6
+ export declare const usePreviousLocation: () => {
7
+ hrefFor: (fallbackPath: string, matchPaths?: readonly string[]) => string;
8
+ goTo: (fallbackPath: string, matchPaths?: readonly string[]) => void;
9
+ };
@@ -1087,7 +1087,7 @@ const _hoisted_5$f = {
1087
1087
  key: 0,
1088
1088
  class: "w-full flex mt-2"
1089
1089
  };
1090
- const _hoisted_6$c = ["aria-hidden"];
1090
+ const _hoisted_6$b = ["aria-hidden"];
1091
1091
  const _sfc_main$K = /* @__PURE__ */ vue.defineComponent({
1092
1092
  ...{
1093
1093
  inheritAttrs: false
@@ -1204,7 +1204,7 @@ const _sfc_main$K = /* @__PURE__ */ vue.defineComponent({
1204
1204
  class: "mb-0-last-child block px-4 pb-6 rounded-b-2xl bg-white"
1205
1205
  }, [
1206
1206
  vue.renderSlot(_ctx.$slots, "default")
1207
- ], 8, _hoisted_6$c), [
1207
+ ], 8, _hoisted_6$b), [
1208
1208
  [vue.vShow, isOpen.value]
1209
1209
  ])
1210
1210
  ], 16);
@@ -1222,7 +1222,7 @@ const _hoisted_4$g = {
1222
1222
  class: "mb-1"
1223
1223
  };
1224
1224
  const _hoisted_5$e = { class: "flex items-start justify-between gap-4" };
1225
- const _hoisted_6$b = { class: "m-0 text-base font-main font-bold tracking-wide" };
1225
+ const _hoisted_6$a = { class: "m-0 text-base font-main font-bold tracking-wide" };
1226
1226
  const _hoisted_7$a = { class: "flex items-start gap-3" };
1227
1227
  const _hoisted_8$6 = {
1228
1228
  key: 1,
@@ -1277,7 +1277,7 @@ const _sfc_main$J = /* @__PURE__ */ vue.defineComponent({
1277
1277
  vue.createElementVNode("div", _hoisted_3$i, [
1278
1278
  __props.heading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$g, [
1279
1279
  vue.createElementVNode("header", _hoisted_5$e, [
1280
- vue.createElementVNode("h3", _hoisted_6$b, vue.toDisplayString(__props.heading), 1),
1280
+ vue.createElementVNode("h3", _hoisted_6$a, vue.toDisplayString(__props.heading), 1),
1281
1281
  vue.createElementVNode("div", _hoisted_7$a, [
1282
1282
  vue.renderSlot(_ctx.$slots, "headerInfo")
1283
1283
  ])
@@ -5996,6 +5996,138 @@ function useDevModeToggles() {
5996
5996
  }
5997
5997
  return devModeTogglesInstance;
5998
5998
  }
5999
+ const VIEWPORT_MARGIN = 8;
6000
+ const viewportSize = () => ({
6001
+ width: document.documentElement.clientWidth || window.innerWidth,
6002
+ height: document.documentElement.clientHeight || window.innerHeight
6003
+ });
6004
+ function clampBoxToViewport(box, viewport, margin = VIEWPORT_MARGIN) {
6005
+ const width = Math.min(Math.max(box.width, 0), Math.max(viewport.width - margin * 2, 0));
6006
+ const height = Math.min(Math.max(box.height, 0), Math.max(viewport.height - margin * 2, 0));
6007
+ const minLeft = margin;
6008
+ const minTop = margin;
6009
+ const maxLeft = Math.max(minLeft, viewport.width - width - margin);
6010
+ const maxTop = Math.max(minTop, viewport.height - height - margin);
6011
+ return {
6012
+ left: Math.min(Math.max(box.left, minLeft), maxLeft),
6013
+ top: Math.min(Math.max(box.top, minTop), maxTop),
6014
+ width,
6015
+ height
6016
+ };
6017
+ }
6018
+ function computeAnchoredPlacement(args) {
6019
+ const margin = args.margin ?? VIEWPORT_MARGIN;
6020
+ const gap = args.gap ?? 12;
6021
+ const align = args.align ?? "end";
6022
+ const maxWidth = Math.max(args.viewportWidth - margin * 2, 0);
6023
+ const width = Math.min(Math.max(args.contentWidth, 0), maxWidth);
6024
+ const anchorBottom = args.anchorTop + args.anchorHeight;
6025
+ const spaceAbove = args.anchorTop - margin - gap;
6026
+ const spaceBelow = args.viewportHeight - anchorBottom - margin - gap;
6027
+ const above = spaceAbove >= args.contentHeight || spaceAbove >= spaceBelow;
6028
+ const maxHeight = Math.max(above ? spaceAbove : spaceBelow, 0);
6029
+ let left = align === "end" ? args.anchorWidth - width : 0;
6030
+ let viewportLeft = args.anchorLeft + left;
6031
+ if (viewportLeft < margin) {
6032
+ left += margin - viewportLeft;
6033
+ viewportLeft = margin;
6034
+ }
6035
+ const overflowRight = viewportLeft + width - (args.viewportWidth - margin);
6036
+ if (overflowRight > 0) {
6037
+ left -= overflowRight;
6038
+ viewportLeft -= overflowRight;
6039
+ }
6040
+ if (viewportLeft < margin) {
6041
+ left += margin - viewportLeft;
6042
+ }
6043
+ return { above, left, maxHeight, maxWidth };
6044
+ }
6045
+ const stylesEqual = (current, next) => {
6046
+ const keys = Object.keys(next);
6047
+ return keys.length === Object.keys(current).length && keys.every((key) => current[key] === next[key]);
6048
+ };
6049
+ function useStickInViewport(targetRef, options = {}) {
6050
+ const gap = options.gap ?? 12;
6051
+ const align = options.align ?? "end";
6052
+ const style = vue.ref({
6053
+ visibility: "hidden",
6054
+ right: "0px",
6055
+ bottom: `calc(100% + ${gap}px)`,
6056
+ maxWidth: "calc(100vw - 1rem)",
6057
+ maxHeight: "calc(100vh - 1rem)"
6058
+ });
6059
+ let frame = 0;
6060
+ let observer = null;
6061
+ const update = () => {
6062
+ const el = targetRef.value;
6063
+ if (!el?.isConnected || typeof window === "undefined") return;
6064
+ const anchor = el.parentElement;
6065
+ if (!anchor) return;
6066
+ const anchorRect = anchor.getBoundingClientRect();
6067
+ const width = el.offsetWidth;
6068
+ const height = el.scrollHeight;
6069
+ if (width <= 0 && height <= 0) return;
6070
+ const viewport = viewportSize();
6071
+ const placement = computeAnchoredPlacement({
6072
+ anchorLeft: anchorRect.left,
6073
+ anchorTop: anchorRect.top,
6074
+ anchorWidth: anchorRect.width,
6075
+ anchorHeight: anchorRect.height,
6076
+ contentWidth: width,
6077
+ contentHeight: height,
6078
+ viewportWidth: viewport.width,
6079
+ viewportHeight: viewport.height,
6080
+ gap,
6081
+ align
6082
+ });
6083
+ const next = {
6084
+ visibility: "visible",
6085
+ left: `${Math.round(placement.left)}px`,
6086
+ right: "auto",
6087
+ top: placement.above ? "auto" : `calc(100% + ${gap}px)`,
6088
+ bottom: placement.above ? `calc(100% + ${gap}px)` : "auto",
6089
+ maxWidth: `${Math.round(placement.maxWidth)}px`,
6090
+ maxHeight: `${Math.max(Math.round(placement.maxHeight), 0)}px`,
6091
+ overflowY: "auto"
6092
+ };
6093
+ if (!stylesEqual(style.value, next)) {
6094
+ style.value = next;
6095
+ }
6096
+ };
6097
+ const schedule = () => {
6098
+ if (typeof window === "undefined" || frame) return;
6099
+ frame = window.requestAnimationFrame(() => {
6100
+ frame = 0;
6101
+ update();
6102
+ });
6103
+ };
6104
+ vue.watch(
6105
+ targetRef,
6106
+ (el) => {
6107
+ observer?.disconnect();
6108
+ observer = null;
6109
+ if (el && typeof ResizeObserver !== "undefined") {
6110
+ observer = new ResizeObserver(() => schedule());
6111
+ observer.observe(el);
6112
+ }
6113
+ schedule();
6114
+ },
6115
+ { flush: "post", immediate: true }
6116
+ );
6117
+ if (typeof window !== "undefined") {
6118
+ window.addEventListener("resize", schedule);
6119
+ window.addEventListener("pointermove", schedule);
6120
+ window.addEventListener("pointerup", schedule);
6121
+ vue.onScopeDispose(() => {
6122
+ window.removeEventListener("resize", schedule);
6123
+ window.removeEventListener("pointermove", schedule);
6124
+ window.removeEventListener("pointerup", schedule);
6125
+ if (frame) window.cancelAnimationFrame(frame);
6126
+ observer?.disconnect();
6127
+ });
6128
+ }
6129
+ return { style };
6130
+ }
5999
6131
  const MIN_WIDTH = 288;
6000
6132
  const MIN_HEIGHT = 200;
6001
6133
  const getStorageKey = (key) => `fds-modal-${key}`;
@@ -6022,6 +6154,34 @@ function useModalDragResize(options) {
6022
6154
  } catch {
6023
6155
  }
6024
6156
  };
6157
+ const viewport = () => ({
6158
+ width: document.documentElement.clientWidth || window.innerWidth,
6159
+ height: document.documentElement.clientHeight || window.innerHeight
6160
+ });
6161
+ const applyViewportClamp = () => {
6162
+ if (!options.constrainToViewport || !modalPosition.value || typeof window === "undefined") return;
6163
+ const el = options.elementRef.value;
6164
+ if (!el) return;
6165
+ const width = el.offsetWidth;
6166
+ const height = el.offsetHeight;
6167
+ if (width <= 0 || height <= 0) return;
6168
+ const clamped = clampBoxToViewport(
6169
+ { left: modalPosition.value.left, top: modalPosition.value.top, width, height },
6170
+ viewport()
6171
+ );
6172
+ if (clamped.left === modalPosition.value.left && clamped.top === modalPosition.value.top) return;
6173
+ modalPosition.value = { left: clamped.left, top: clamped.top };
6174
+ };
6175
+ let clampFrame = 0;
6176
+ const scheduleViewportClamp = () => {
6177
+ applyViewportClamp();
6178
+ if (typeof window === "undefined") return;
6179
+ if (clampFrame) window.cancelAnimationFrame(clampFrame);
6180
+ clampFrame = window.requestAnimationFrame(() => {
6181
+ clampFrame = 0;
6182
+ applyViewportClamp();
6183
+ });
6184
+ };
6025
6185
  const restore = () => {
6026
6186
  if (!canPersist()) return false;
6027
6187
  try {
@@ -6036,6 +6196,7 @@ function useModalDragResize(options) {
6036
6196
  modalSize.value = data.size;
6037
6197
  hasBeenResized.value = true;
6038
6198
  }
6199
+ if (options.constrainToViewport) scheduleViewportClamp();
6039
6200
  return true;
6040
6201
  } catch {
6041
6202
  return false;
@@ -6085,10 +6246,17 @@ function useModalDragResize(options) {
6085
6246
  const onDragMove = (e) => {
6086
6247
  if (!isDragging.value) return;
6087
6248
  e.preventDefault();
6088
- modalPosition.value = {
6089
- left: e.clientX - dragOffset.value.x,
6090
- top: e.clientY - dragOffset.value.y
6091
- };
6249
+ let left = e.clientX - dragOffset.value.x;
6250
+ let top = e.clientY - dragOffset.value.y;
6251
+ if (options.constrainToViewport && typeof window !== "undefined") {
6252
+ const el = options.elementRef.value;
6253
+ const width = el?.offsetWidth ?? 0;
6254
+ const height = el?.offsetHeight ?? 0;
6255
+ if (width > 0 && height > 0) {
6256
+ ({ left, top } = clampBoxToViewport({ left, top, width, height }, viewport()));
6257
+ }
6258
+ }
6259
+ modalPosition.value = { left, top };
6092
6260
  };
6093
6261
  const onDragEnd = () => {
6094
6262
  isDragging.value = false;
@@ -6140,6 +6308,14 @@ function useModalDragResize(options) {
6140
6308
  newTop = resizeStart.value.top + (resizeStart.value.height - h);
6141
6309
  newHeight = h;
6142
6310
  }
6311
+ if (options.constrainToViewport && typeof window !== "undefined") {
6312
+ ({
6313
+ left: newLeft,
6314
+ top: newTop,
6315
+ width: newWidth,
6316
+ height: newHeight
6317
+ } = clampBoxToViewport({ left: newLeft, top: newTop, width: newWidth, height: newHeight }, viewport()));
6318
+ }
6143
6319
  modalPosition.value = { left: newLeft, top: newTop };
6144
6320
  modalSize.value = { width: newWidth, height: newHeight };
6145
6321
  };
@@ -6167,6 +6343,24 @@ function useModalDragResize(options) {
6167
6343
  document.removeEventListener("mousemove", onResizeMove);
6168
6344
  document.removeEventListener("mouseup", onResizeEnd);
6169
6345
  };
6346
+ if (options.constrainToViewport && typeof window !== "undefined") {
6347
+ const onWindowResize = () => applyViewportClamp();
6348
+ window.addEventListener("resize", onWindowResize);
6349
+ const observer = new ResizeObserver(() => applyViewportClamp());
6350
+ vue.watch(
6351
+ options.elementRef,
6352
+ (el) => {
6353
+ observer.disconnect();
6354
+ if (el) observer.observe(el);
6355
+ },
6356
+ { immediate: true }
6357
+ );
6358
+ vue.onScopeDispose(() => {
6359
+ window.removeEventListener("resize", onWindowResize);
6360
+ observer.disconnect();
6361
+ if (clampFrame) window.cancelAnimationFrame(clampFrame);
6362
+ });
6363
+ }
6170
6364
  const shouldBlockBackdropClick = () => Date.now() - lastInteractionEnd.value < 200;
6171
6365
  return {
6172
6366
  isCustomPositioned,
@@ -6229,6 +6423,8 @@ const _sfc_main$A = /* @__PURE__ */ vue.defineComponent({
6229
6423
  const { t } = useFdsI18n();
6230
6424
  const showBreakpointList = vue.ref(false);
6231
6425
  const containerRef = vue.ref(null);
6426
+ const popoverRef = vue.ref(null);
6427
+ const { style: popoverStyle } = useStickInViewport(popoverRef, { gap: 8, align: "start" });
6232
6428
  const toggleBreakpointList = () => {
6233
6429
  showBreakpointList.value = !showBreakpointList.value;
6234
6430
  };
@@ -6261,7 +6457,10 @@ const _sfc_main$A = /* @__PURE__ */ vue.defineComponent({
6261
6457
  }, vue.toDisplayString(vue.unref(currentBreakpoint)), 9, _hoisted_1$q),
6262
6458
  showBreakpointList.value ? (vue.openBlock(), vue.createElementBlock("div", {
6263
6459
  key: 0,
6264
- class: vue.normalizeClass(["absolute bottom-full left-0 mb-2 rounded-lg shadow-lg p-2 text-xs font-mono whitespace-nowrap z-10", __props.popoverClass])
6460
+ ref_key: "popoverRef",
6461
+ ref: popoverRef,
6462
+ class: vue.normalizeClass(["absolute z-10 rounded-lg p-2 font-mono text-xs whitespace-nowrap shadow-lg", __props.popoverClass]),
6463
+ style: vue.normalizeStyle(vue.unref(popoverStyle))
6265
6464
  }, [
6266
6465
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(breakpoints2), (bp) => {
6267
6466
  return vue.openBlock(), vue.createElementBlock("div", {
@@ -6278,7 +6477,7 @@ const _sfc_main$A = /* @__PURE__ */ vue.defineComponent({
6278
6477
  vue.createElementVNode("span", null, vue.toDisplayString(vue.unref(t)("FdsDevMode.baseBreakpoint")), 1),
6279
6478
  vue.createElementVNode("span", null, vue.toDisplayString(vue.unref(t)("FdsDevMode.baseBreakpointRange")), 1)
6280
6479
  ], 2)
6281
- ], 2)) : vue.createCommentVNode("", true)
6480
+ ], 6)) : vue.createCommentVNode("", true)
6282
6481
  ], 512);
6283
6482
  };
6284
6483
  }
@@ -6705,20 +6904,16 @@ const _sfc_main$x = /* @__PURE__ */ vue.defineComponent({
6705
6904
  }
6706
6905
  });
6707
6906
  const _hoisted_1$n = {
6708
- key: 0,
6709
- class: "absolute bottom-full right-0 mb-3 z-60 flex min-w-54 flex-col font-normal"
6710
- };
6711
- const _hoisted_2$h = {
6712
6907
  key: 0,
6713
6908
  class: "rounded-t-xl border border-b-0 border-gray-200 bg-white p-2 text-sm text-gray-900"
6714
6909
  };
6715
- const _hoisted_3$h = { class: "flex flex-col gap-2" };
6716
- const _hoisted_4$f = { key: 0 };
6717
- const _hoisted_5$d = {
6910
+ const _hoisted_2$h = { class: "flex flex-col gap-2" };
6911
+ const _hoisted_3$h = { key: 0 };
6912
+ const _hoisted_4$f = {
6718
6913
  key: 1,
6719
6914
  class: "flex flex-col gap-1"
6720
6915
  };
6721
- const _hoisted_6$a = { key: 2 };
6916
+ const _hoisted_5$d = { key: 2 };
6722
6917
  const OVERLAY_OPEN_KEY = "devModeOverlayOpen";
6723
6918
  const _sfc_main$w = /* @__PURE__ */ vue.defineComponent({
6724
6919
  __name: "FdsDevModeOverlay",
@@ -6783,13 +6978,21 @@ const _sfc_main$w = /* @__PURE__ */ vue.defineComponent({
6783
6978
  value: toggle.value
6784
6979
  });
6785
6980
  };
6981
+ const overlayRef = vue.ref(null);
6982
+ const { style: overlayStyle } = useStickInViewport(overlayRef, { gap: 12, align: "end" });
6786
6983
  const hasContent = vue.computed(
6787
6984
  () => checkToggles.value.length > 0 || radioToggles.value.length > 0 || buttonToggles.value.length > 0 || canToggleI18nKeys.value || showLocaleSwitcher.value
6788
6985
  );
6789
6986
  return (_ctx, _cache) => {
6790
- return hasContent.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$n, [
6791
- isOpen.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$h, [
6792
- vue.createElementVNode("div", _hoisted_3$h, [
6987
+ return hasContent.value ? (vue.openBlock(), vue.createElementBlock("div", {
6988
+ key: 0,
6989
+ ref_key: "overlayRef",
6990
+ ref: overlayRef,
6991
+ class: "absolute z-60 flex w-max min-w-[min(13.5rem,calc(100vw-1rem))] flex-col font-normal",
6992
+ style: vue.normalizeStyle(vue.unref(overlayStyle))
6993
+ }, [
6994
+ isOpen.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$n, [
6995
+ vue.createElementVNode("div", _hoisted_2$h, [
6793
6996
  vue.createElementVNode("div", null, [
6794
6997
  vue.unref(canToggleI18nKeys) ? (vue.openBlock(), vue.createBlock(_sfc_main$z, {
6795
6998
  key: 0,
@@ -6816,7 +7019,7 @@ const _sfc_main$w = /* @__PURE__ */ vue.defineComponent({
6816
7019
  }, 1032, ["checked", "onChange"]);
6817
7020
  }), 128))
6818
7021
  ]),
6819
- radioToggles.value.length > 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$f, [
7022
+ radioToggles.value.length > 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$h, [
6820
7023
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(radioToggles.value, (toggle) => {
6821
7024
  return vue.openBlock(), vue.createBlock(_sfc_main$y, {
6822
7025
  key: `${toggle.key}-${toggle.checked}`,
@@ -6833,7 +7036,7 @@ const _sfc_main$w = /* @__PURE__ */ vue.defineComponent({
6833
7036
  }, 1032, ["name", "value", "checked", "onChange"]);
6834
7037
  }), 128))
6835
7038
  ])) : vue.createCommentVNode("", true),
6836
- buttonToggles.value.length > 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$d, [
7039
+ buttonToggles.value.length > 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$f, [
6837
7040
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(buttonToggles.value, (toggle) => {
6838
7041
  return vue.openBlock(), vue.createBlock(_sfc_main$G, {
6839
7042
  key: toggle.key,
@@ -6844,7 +7047,7 @@ const _sfc_main$w = /* @__PURE__ */ vue.defineComponent({
6844
7047
  }, null, 8, ["text", "onClick"]);
6845
7048
  }), 128))
6846
7049
  ])) : vue.createCommentVNode("", true),
6847
- showLocaleSwitcher.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_6$a, [
7050
+ showLocaleSwitcher.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$d, [
6848
7051
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(localeOptions.value, (localeCode) => {
6849
7052
  return vue.openBlock(), vue.createBlock(_sfc_main$y, {
6850
7053
  key: localeCode,
@@ -6883,7 +7086,7 @@ const _sfc_main$w = /* @__PURE__ */ vue.defineComponent({
6883
7086
  }, null, 8, ["name"])
6884
7087
  ])
6885
7088
  ], 2)
6886
- ])) : vue.createCommentVNode("", true);
7089
+ ], 4)) : vue.createCommentVNode("", true);
6887
7090
  };
6888
7091
  }
6889
7092
  });
@@ -11603,7 +11806,8 @@ const _sfc_main$p = /* @__PURE__ */ vue.defineComponent({
11603
11806
  movable: vue.computed(() => true),
11604
11807
  resizable: vue.computed(() => false),
11605
11808
  elementRef: bannerRef,
11606
- heading: bannerStorageKey
11809
+ heading: bannerStorageKey,
11810
+ constrainToViewport: true
11607
11811
  });
11608
11812
  vue.onBeforeUnmount(() => {
11609
11813
  cleanupBannerDrag();
@@ -11633,9 +11837,11 @@ const _sfc_main$p = /* @__PURE__ */ vue.defineComponent({
11633
11837
  return "";
11634
11838
  });
11635
11839
  const envBannerPositionClasses = vue.computed(() => {
11636
- if (isCustomPositioned.value) return "fixed cursor-move select-none";
11637
- if (isLocalhost.value) return "fixed bottom-0 my-6 right-18";
11638
- return "fixed bottom-0 my-6 right-8";
11840
+ if (isCustomPositioned.value) {
11841
+ return "fixed max-w-[calc(100vw-1rem)] max-h-[calc(100vh-1rem)] cursor-move select-none";
11842
+ }
11843
+ if (isLocalhost.value) return "fixed bottom-0 my-6 right-18 max-w-[calc(100vw-5rem)] max-h-[calc(100vh-2rem)]";
11844
+ return "fixed bottom-0 my-6 right-8 max-w-[calc(100vw-2.5rem)] max-h-[calc(100vh-2rem)]";
11639
11845
  });
11640
11846
  const envBannerFillColor = vue.computed(() => {
11641
11847
  if (isDevMode.value) return "fill-white";
@@ -21548,6 +21754,30 @@ const teardownRouterLinkInterceptor = () => {
21548
21754
  }
21549
21755
  globalRouter = null;
21550
21756
  };
21757
+ const withoutHash = (location) => location.split("#")[0] ?? location;
21758
+ const pathOf = (location) => withoutHash(location).split("?")[0] ?? location;
21759
+ const usePreviousLocation = () => {
21760
+ const route = vueRouter.useRoute();
21761
+ const router = vueRouter.useRouter();
21762
+ const hrefFor = (fallbackPath, matchPaths = [fallbackPath]) => {
21763
+ void route.fullPath;
21764
+ const previous = router.options.history.state.back;
21765
+ if (typeof previous !== "string" || previous === "") return fallbackPath;
21766
+ const full = withoutHash(previous);
21767
+ if (!matchPaths.includes(pathOf(full))) return fallbackPath;
21768
+ return full;
21769
+ };
21770
+ const goTo = (fallbackPath, matchPaths) => {
21771
+ const href = hrefFor(fallbackPath, matchPaths);
21772
+ const previous = router.options.history.state.back;
21773
+ if (typeof previous === "string" && withoutHash(previous) === href) {
21774
+ router.back();
21775
+ return;
21776
+ }
21777
+ void router.push(href);
21778
+ };
21779
+ return { hrefFor, goTo };
21780
+ };
21551
21781
  const isArr = (v) => Array.isArray(v);
21552
21782
  const clone = (v) => isArr(v) ? [...v] : v;
21553
21783
  const cloneRecord = (defaults2) => {
@@ -22071,6 +22301,7 @@ exports.useExitConfirmationGuardState = useExitConfirmationGuardState;
22071
22301
  exports.useFileSizeValidation = useFileSizeValidation;
22072
22302
  exports.useFileValidation = useFileValidation;
22073
22303
  exports.useIsPid = useIsPid;
22304
+ exports.usePreviousLocation = usePreviousLocation;
22074
22305
  exports.useRouteFilters = useRouteFilters;
22075
22306
  exports.useRouteScrollPositions = useRouteScrollPositions;
22076
22307
  exports.useTreeState = useTreeState;