@livestorm/ui-vue 2.0.3 → 2.0.5

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 (41) hide show
  1. package/README.md +30 -2
  2. package/dist/{UiTimelineItem.vue_vue_type_style_index_0_lang-UNNkatTS.mjs → UiTimelineItem.vue_vue_type_style_index_0_lang-DJFdCn2R.mjs} +1522 -1518
  3. package/dist/a11y-BhF_nl7L.mjs +159 -0
  4. package/dist/components.mjs +2 -2
  5. package/dist/i18n-Cktw9hIu.mjs +49 -0
  6. package/dist/index.mjs +2 -2
  7. package/dist/integrations.mjs +10 -4
  8. package/dist/layouts.mjs +1 -1
  9. package/dist/types/src/components/Toast/ToastMessage.vue.d.ts +4 -4
  10. package/dist/types/src/components/UiBanner/UiBanner.vue.d.ts +2 -2
  11. package/dist/types/src/components/UiButton/UiButton.vue.d.ts +1 -1
  12. package/dist/types/src/components/UiButtonGroup/UiButtonGroup.vue.d.ts +1 -1
  13. package/dist/types/src/components/UiColorField/UiColorField.vue.d.ts +2 -2
  14. package/dist/types/src/components/UiColorPicker/UiColorPicker.vue.d.ts +2 -2
  15. package/dist/types/src/components/UiDropdown/UiDropdownTrigger.vue.d.ts +1 -1
  16. package/dist/types/src/components/UiFieldWrapper/UiFieldWrapper.vue.d.ts +1 -1
  17. package/dist/types/src/components/UiForm/UiFormField.vue.d.ts +1 -1
  18. package/dist/types/src/components/UiInputCheckbox/UiInputCheckbox.vue.d.ts +5 -5
  19. package/dist/types/src/components/UiInputSelect/UiInputSelect.vue.d.ts +3 -3
  20. package/dist/types/src/components/UiInputTextarea/UiInputTextarea.vue.d.ts +3 -3
  21. package/dist/types/src/components/UiTextField/UiTextField.vue.d.ts +5 -5
  22. package/dist/types/src/composables/useButtonStyles.d.ts +1 -1
  23. package/dist/types/src/integrations/index.d.ts +1 -0
  24. package/dist/types/src/utils/i18n.d.ts +51 -0
  25. package/dist/ui-vue.css +1 -1
  26. package/dist/{useThemeAndModes-CUK56j0z.mjs → useThemeAndModes-BzYwSOEv.mjs} +1 -1
  27. package/dist/utils.mjs +152 -97
  28. package/integrations.d.ts +1 -0
  29. package/package.json +26 -19
  30. package/src/components/UiBanner/UiBanner.vue +4 -2
  31. package/src/components/UiButtonGroup/UiButtonGroup.vue +2 -0
  32. package/src/components/UiButtonGroup/UiButtonGroupItem.vue +2 -0
  33. package/src/components/UiDialog/UiDialogContent.vue +12 -4
  34. package/src/components/UiPage/UiPage.vue +7 -2
  35. package/src/components/UiSideMenu/UiSideMenu.vue +4 -3
  36. package/src/css/body.css +15 -7
  37. package/src/css/fonts.css +10 -0
  38. package/src/integrations/index.js +1 -0
  39. package/src/utils/clipboard.js +5 -2
  40. package/src/utils/i18n.ts +113 -0
  41. package/dist/a11y--y7uaY4j.mjs +0 -217
@@ -1,6 +1,5 @@
1
1
  <script setup lang="ts">
2
2
  import { useMutationObserver, useThrottleFn } from '@vueuse/core'
3
- import i18n from 'i18next'
4
3
  import type { DialogContentEmits, DialogContentProps } from 'reka-ui'
5
4
  import {
6
5
  DialogContent,
@@ -12,6 +11,7 @@ import {
12
11
  VisuallyHidden,
13
12
  } from 'reka-ui'
14
13
  import { computed, ref, useAttrs, watch } from 'vue'
14
+ import { useTranslate } from '../../utils/i18n'
15
15
  import UiDialogClose from './UiDialogClose.vue'
16
16
 
17
17
  interface UiDialogContentProps extends DialogContentProps {
@@ -32,7 +32,7 @@ const props = withDefaults(defineProps<UiDialogContentProps>(), {
32
32
  title: undefined,
33
33
  description: undefined,
34
34
  hideClose: false,
35
- closeButtonAriaLabel: i18n.t('general_close'),
35
+ closeButtonAriaLabel: undefined,
36
36
  overlayClass: '',
37
37
  contentMode: 'light',
38
38
  closeButtonMode: undefined,
@@ -69,12 +69,20 @@ function checkScroll () {
69
69
 
70
70
  const throttledCheckScroll = useThrottleFn(checkScroll, 100)
71
71
 
72
+ const translate = useTranslate()
73
+
74
+ // Resolved at render time (not as a static prop default): the translation
75
+ // must follow the app-provided translator and the active locale.
76
+ const closeAriaLabel = computed(
77
+ () => props.closeButtonAriaLabel ?? translate('general_close'),
78
+ )
79
+
72
80
  const attrs = useAttrs();
73
81
  const accessibleTitle = computed(
74
82
  () =>
75
83
  props.title ||
76
84
  (attrs['aria-label'] as string) ||
77
- i18n.t('general_dialog_title'),
85
+ translate('general_dialog_title'),
78
86
  );
79
87
  const accessibleDescription = computed(
80
88
  () =>
@@ -150,7 +158,7 @@ useMutationObserver(contentRef, () => {
150
158
 
151
159
  <UiDialogClose
152
160
  v-if="!hideClose"
153
- :aria-label="closeButtonAriaLabel"
161
+ :aria-label="closeAriaLabel"
154
162
  :mode="closeButtonMode ?? contentMode"
155
163
  :class="{
156
164
  'ml-4': !noPadding
@@ -98,15 +98,20 @@ const { addElementToWatch } = useThemeAndModes()
98
98
  // the internal theming tooling is enabled, so the stored content mode
99
99
  // (driven by the ThemePicker) can apply; for everyone else the content
100
100
  // stays light regardless of what localStorage may hold.
101
- const isInternalThemingEnabled = localStorage.getItem('ls-internal-theming') === 'true'
101
+ // Read in onMounted, not at setup: setup also runs during SSR (no
102
+ // localStorage), and server + client-hydration markup must be identical —
103
+ // the pin lifts right after mount for the internal tooling instead.
104
+ const isInternalThemingEnabled = ref(false)
102
105
 
103
106
  onMounted(() => {
107
+ isInternalThemingEnabled.value = localStorage.getItem('ls-internal-theming') === 'true'
108
+
104
109
  addElementToWatch(
105
110
  'content',
106
111
  {
107
112
  selector: '[data-name="ui-page-content"]',
108
113
  element: PageContent.value!,
109
- ...(isInternalThemingEnabled ? {} : { modeOverride: 'light' }),
114
+ ...(isInternalThemingEnabled.value ? {} : { modeOverride: 'light' }),
110
115
  })
111
116
  })
112
117
 
@@ -8,11 +8,12 @@ import UiPopover from '../UiPopover/UiPopover.vue'
8
8
  import UiPopoverTrigger from '../UiPopover/UiPopoverTrigger.vue'
9
9
  import UiPopoverContent from '../UiPopover/UiPopoverContent.vue'
10
10
  import { useMobileMenu } from '../../composables/useMobileMenu'
11
- import i18next from 'i18next'
11
+ import { useTranslate } from '../../utils/i18n'
12
12
  import { focusFirstMenuItem } from '../../utils'
13
13
  import { computed, onBeforeUnmount, onMounted, provide, ref } from 'vue'
14
14
  import { SIDE_MENU_LAYOUT_KEY } from './injection'
15
15
  const { close, isOpen } = useMobileMenu()
16
+ const translate = useTranslate()
16
17
 
17
18
  // State for the responsive (short-height) more menu popover, which surfaces
18
19
  // the otherwise-hidden #bottom slot items.
@@ -287,7 +288,7 @@ function handleLogoClick (event: MouseEvent) {
287
288
  <UiPopover v-model:open="isCollapsedMenuOpen">
288
289
  <UiPopoverTrigger class="w-full cursor-pointer">
289
290
  <UiSideMenuItem
290
- :label="i18next.t('room_bottom-bar_controls-label_more')"
291
+ :label="translate('room_bottom-bar_controls-label_more')"
291
292
  icon="i-ls-more-horizontal"
292
293
  :is-active="false"
293
294
  :inside-interactive="true"
@@ -418,7 +419,7 @@ function handleLogoClick (event: MouseEvent) {
418
419
  >
419
420
  <UiPopoverTrigger class="cursor-pointer">
420
421
  <UiSideMenuItem
421
- :label="i18next.t('room_bottom-bar_controls-label_more')"
422
+ :label="translate('room_bottom-bar_controls-label_more')"
422
423
  icon="i-ls-more-vertical"
423
424
  :is-active="false"
424
425
  :inside-interactive="true"
package/src/css/body.css CHANGED
@@ -1,12 +1,20 @@
1
1
  @reference '@livestorm/ui-tokens/output/supernova/index.css';
2
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
3
2
 
4
- body {
5
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
6
- font-size: 14px;
7
- line-height: 1.5;
8
- font-weight: 400;
9
- color: var(--color-grey-700);
3
+ /*
4
+ Layered so the host app always wins: an unlayered rule (or the app's own
5
+ @layer base rules, declared after this import) overrides these defaults.
6
+ Without the layer, this body rule would beat a Tailwind v4 app's
7
+ `@layer base` typography no matter the import order.
8
+ The Inter font itself is NOT loaded here — see fonts.css.
9
+ */
10
+ @layer base {
11
+ body {
12
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
13
+ font-size: 14px;
14
+ line-height: 1.5;
15
+ font-weight: 400;
16
+ color: var(--color-grey-700);
17
+ }
10
18
  }
11
19
 
12
20
  /*
@@ -0,0 +1,10 @@
1
+ /*
2
+ Inter via Google Fonts — kept OUT of the base stylesheet (./style) on
3
+ purpose: a third-party font request must be the consumer's choice (GDPR,
4
+ self-hosting). Apps that want the quick path import this file once:
5
+
6
+ import '@livestorm/ui-vue/fonts'
7
+
8
+ The monorepo keeps loading it through ui-vue-legacy's style chain.
9
+ */
10
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
@@ -1 +1,2 @@
1
1
  export * from '../components/Toast/toastDSV2'
2
+ export * from '../utils/i18n'
@@ -1,6 +1,6 @@
1
1
  import { computed, createApp, h } from 'vue'
2
2
  import { useClipboard, usePermission } from '@vueuse/core'
3
- import i18n from 'i18next'
3
+ import { useTranslate } from './i18n'
4
4
 
5
5
  import UiTooltipProvider from '../components/UiTooltip/UiTooltipProvider.vue'
6
6
  import UiTooltip from '../components/UiTooltip/UiTooltip.vue'
@@ -82,10 +82,13 @@ function flashTooltip (el, text) {
82
82
  export function useCopyToClipboard () {
83
83
  const { isSupported, copy: _copy } = useClipboard()
84
84
  const permissionClipboardWrite = usePermission('clipboard-write')
85
+ // Captured at composable time so an app-provided UI_VUE_TRANSLATOR is
86
+ // honored; copy() itself runs later, in event handlers.
87
+ const translate = useTranslate()
85
88
 
86
89
  const canCopy = computed(() => isSupported.value && permissionClipboardWrite.value)
87
90
 
88
- async function copy (text, el, tooltipText = i18n.t('general_misc_copied-text')) {
91
+ async function copy (text, el, tooltipText = translate('general_misc_copied-text')) {
89
92
  await _copy(text)
90
93
 
91
94
  if (el) {
@@ -0,0 +1,113 @@
1
+ import i18next from 'i18next'
2
+ import { getCurrentInstance, inject } from 'vue'
3
+ import type { InjectionKey } from 'vue'
4
+
5
+ /**
6
+ * Built-in translations for the few strings components render themselves
7
+ * (aria-labels, tooltips). Keyed like the Livestorm app locales so a host
8
+ * app running i18next with these keys keeps full control.
9
+ */
10
+ const FALLBACK_BUNDLES: Record<string, Record<string, string>> = {
11
+ en: {
12
+ general_close: 'Close',
13
+ general_dialog_title: 'Dialog',
14
+ 'general_misc_copied-text': 'Copied!',
15
+ 'room_bottom-bar_controls-label_more': 'More',
16
+ },
17
+ fr: {
18
+ general_close: 'Fermer',
19
+ general_dialog_title: 'Dialog',
20
+ 'general_misc_copied-text': 'Copié !',
21
+ 'room_bottom-bar_controls-label_more': 'Plus',
22
+ },
23
+ }
24
+
25
+ /**
26
+ * Keys of the built-in labels. They MUST stay identical to the Livestorm
27
+ * app locale keys (Phrase): inside the app, translate() resolves through
28
+ * the app's i18next with these exact keys, and a silent mismatch would
29
+ * downgrade users to the EN/FR fallbacks. A spec in packages/frontend
30
+ * locks this contract against the app locales.
31
+ */
32
+ export const BUILT_IN_LABEL_KEYS: readonly string[] = Object.freeze(Object.keys(FALLBACK_BUNDLES.en))
33
+
34
+ /**
35
+ * A host-provided translate function. Return the translated string, or the
36
+ * key itself / null / undefined to decline and let the built-in bundles
37
+ * answer.
38
+ */
39
+ export type Translator = (key: string) => string | null | undefined
40
+
41
+ /**
42
+ * App-scoped translator: `app.provide(UI_VUE_TRANSLATOR, fn)` wires the
43
+ * host's i18n per application instance. This is the ONLY safe wiring for
44
+ * SSR servers rendering per-request locales — module state is shared
45
+ * between concurrent requests, an app-provided translator is not.
46
+ */
47
+ export const UI_VUE_TRANSLATOR: InjectionKey<Translator> = Symbol('ui-vue-translator')
48
+
49
+ let customTranslator: Translator | null = null
50
+
51
+ /**
52
+ * Plug the host app's own i18n stack (an i18next `createInstance()`,
53
+ * vue-i18n, anything callable) into the library's built-in labels. An
54
+ * explicitly wired translator wins over the ambient i18next singleton.
55
+ * Pass null to restore the default behavior.
56
+ *
57
+ * This is process-level state, right for SPAs and static setups. On an SSR
58
+ * server with per-request locales, provide UI_VUE_TRANSLATOR on the app
59
+ * instead: concurrent renders would otherwise overwrite each other here.
60
+ */
61
+ export function setTranslator (translator: Translator | null): void {
62
+ customTranslator = translator
63
+ }
64
+
65
+ function resolve (translator: Translator | null | undefined, key: string): string | null {
66
+ if (!translator) return null
67
+ const value = translator(key)
68
+ return typeof value === 'string' && value !== key ? value : null
69
+ }
70
+
71
+ /**
72
+ * Translate a key for a component's built-in label. Resolution order:
73
+ * 1. the translator wired via setTranslator(), when it answers;
74
+ * 2. the ambient i18next singleton, when initialized and it has the key
75
+ * (the Livestorm app path);
76
+ * 3. the built-in EN/FR bundles, language picked from `<html lang>`.
77
+ * Apps not using i18next at all get proper strings instead of raw keys.
78
+ *
79
+ * Components call this through useTranslate(), which puts an app-provided
80
+ * UI_VUE_TRANSLATOR at the very top of that chain.
81
+ */
82
+ export function translate (key: string): string {
83
+ return translateWith(null, key)
84
+ }
85
+
86
+ /**
87
+ * Component-side accessor: returns a translate function bound to the
88
+ * app-provided UI_VUE_TRANSLATOR when called inside setup(), falling back
89
+ * to the process-level chain otherwise. Safe to call outside a component.
90
+ */
91
+ export function useTranslate (): (key: string) => string {
92
+ const injected = getCurrentInstance() ? inject(UI_VUE_TRANSLATOR, null) : null
93
+ return (key: string) => translateWith(injected, key)
94
+ }
95
+
96
+ function translateWith (appTranslator: Translator | null, key: string): string {
97
+ const fromApp = resolve(appTranslator, key)
98
+ if (fromApp !== null) return fromApp
99
+
100
+ const fromProcess = resolve(customTranslator, key)
101
+ if (fromProcess !== null) return fromProcess
102
+
103
+ if (i18next.isInitialized && i18next.exists(key)) {
104
+ return i18next.t(key)
105
+ }
106
+
107
+ const lang = typeof document === 'undefined'
108
+ ? 'en'
109
+ : (document.documentElement.lang || 'en').toLowerCase().split('-')[0]
110
+ const bundle = FALLBACK_BUNDLES[lang] || FALLBACK_BUNDLES.en
111
+
112
+ return bundle[key] ?? FALLBACK_BUNDLES.en[key] ?? key
113
+ }
@@ -1,217 +0,0 @@
1
- import { defineComponent as g, createBlock as f, openBlock as c, unref as i, normalizeProps as y, guardReactiveProps as b, withCtx as l, renderSlot as m, computed as r, createVNode as h, mergeProps as T, createCommentVNode as D, getCurrentInstance as B, createElementBlock as A, Fragment as E, createTextVNode as U, toDisplayString as F, ref as N, watch as S, onUnmounted as I, onMounted as H, nextTick as O } from "vue";
2
- import { TooltipProvider as W, useForwardProps as q, TooltipTrigger as L, useForwardPropsEmits as C, TooltipPortal as M, TooltipContent as z, TooltipArrow as K, TooltipRoot as x } from "reka-ui";
3
- import { reactiveOmit as V, onKeyDown as R } from "@vueuse/core";
4
- const X = /* @__PURE__ */ g({
5
- __name: "UiTooltipProvider",
6
- props: {
7
- delayDuration: { default: 700 },
8
- skipDelayDuration: { default: 300 },
9
- disableHoverableContent: { type: Boolean },
10
- disableClosingTrigger: { type: Boolean },
11
- disabled: { type: Boolean },
12
- ignoreNonKeyboardFocus: { type: Boolean },
13
- content: {}
14
- },
15
- setup(t) {
16
- return (s, e) => (c(), f(i(W), y(b(s.$props)), {
17
- default: l(() => [
18
- m(s.$slots, "default")
19
- ]),
20
- _: 3
21
- }, 16));
22
- }
23
- }), j = /* @__PURE__ */ g({
24
- __name: "UiTooltipTrigger",
25
- props: {
26
- reference: {},
27
- asChild: { type: Boolean },
28
- as: {}
29
- },
30
- setup(t) {
31
- const e = q(t);
32
- return (o, p) => (c(), f(i(L), y(b({ ...i(e), ...o.$attrs })), {
33
- default: l(() => [
34
- m(o.$slots, "default")
35
- ]),
36
- _: 3
37
- }, 16));
38
- }
39
- }), G = /* @__PURE__ */ g({
40
- __name: "UiTooltipContent",
41
- props: {
42
- colorsSemantic: { default: "light" },
43
- maxWidth: { default: "base" },
44
- showArrow: { type: Boolean, default: !0 },
45
- arrowWidth: { default: 10 },
46
- arrowHeight: { default: 5 },
47
- forceMount: { type: Boolean },
48
- ariaLabel: {},
49
- asChild: { type: Boolean },
50
- as: {},
51
- side: {},
52
- sideOffset: { default: 12 },
53
- align: {},
54
- alignOffset: {},
55
- avoidCollisions: { type: Boolean },
56
- collisionBoundary: {},
57
- collisionPadding: {},
58
- arrowPadding: {},
59
- sticky: {},
60
- hideWhenDetached: { type: Boolean },
61
- positionStrategy: {},
62
- updatePositionStrategy: {}
63
- },
64
- emits: ["escapeKeyDown", "pointerDownOutside"],
65
- setup(t, { emit: s }) {
66
- const e = t, p = C(e, s), u = r(() => ({
67
- xs: "max-w-[150px]",
68
- sm: "max-w-[240px]",
69
- md: "max-w-md",
70
- base: "max-w-xs",
71
- lg: "max-w-lg",
72
- xl: "max-w-xl"
73
- })[e.maxWidth]);
74
- return (a, w) => (c(), f(i(M), null, {
75
- default: l(() => [
76
- h(i(z), T({ ...i(p), ...a.$attrs }, {
77
- "data-colors-semantic": e.colorsSemantic,
78
- class: [
79
- "ui-tooltip-content py-1.5 px-3 bg-surface-neutral-invert-bg-alpha text-text-neutral-invert-base text-content-text-md-regular rounded-md text-center z-50 shadow-shadows-drop-shadow-lg",
80
- "data-[state=delayed-open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=delayed-open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=delayed-open]:zoom-in-95",
81
- u.value
82
- ]
83
- }), {
84
- default: l(() => [
85
- m(a.$slots, "default"),
86
- e.showArrow ? (c(), f(i(K), {
87
- key: 0,
88
- width: e.arrowWidth,
89
- height: e.arrowHeight,
90
- class: "fill-surface-neutral-invert-bg-alpha"
91
- }, null, 8, ["width", "height"])) : D("", !0)
92
- ]),
93
- _: 3
94
- }, 16, ["data-colors-semantic", "class"])
95
- ]),
96
- _: 3
97
- }));
98
- }
99
- }), te = /* @__PURE__ */ g({
100
- inheritAttrs: !1,
101
- __name: "UiTooltip",
102
- props: {
103
- content: {},
104
- side: {},
105
- defaultOpen: { type: Boolean },
106
- open: { type: Boolean },
107
- delayDuration: {},
108
- disableHoverableContent: { type: Boolean },
109
- disableClosingTrigger: { type: Boolean },
110
- disabled: { type: Boolean },
111
- ignoreNonKeyboardFocus: { type: Boolean }
112
- },
113
- emits: ["update:open"],
114
- setup(t, { emit: s }) {
115
- const e = t, o = s, p = r(() => {
116
- const a = B()?.vnode.props;
117
- return !!a && "content" in a;
118
- }), u = C(V(e, "content", "side"), o);
119
- return (a, w) => p.value ? (c(), A(E, { key: 0 }, [
120
- t.content ? (c(), f(X, { key: 0 }, {
121
- default: l(() => [
122
- h(i(x), y(b({ ...i(u), ...a.$attrs })), {
123
- default: l(() => [
124
- h(j, { "as-child": "" }, {
125
- default: l(() => [
126
- m(a.$slots, "default")
127
- ]),
128
- _: 3
129
- }),
130
- h(G, { side: t.side }, {
131
- default: l(() => [
132
- U(F(t.content), 1)
133
- ]),
134
- _: 1
135
- }, 8, ["side"])
136
- ]),
137
- _: 3
138
- }, 16)
139
- ]),
140
- _: 3
141
- })) : m(a.$slots, "default", { key: 1 })
142
- ], 64)) : (c(), f(i(x), y(T({ key: 1 }, { ...i(u), ...a.$attrs })), {
143
- default: l(() => [
144
- m(a.$slots, "default")
145
- ]),
146
- _: 3
147
- }, 16));
148
- }
149
- });
150
- let J = 0;
151
- const d = N([]), Q = r(() => d.value.length > 0);
152
- function oe(t, s) {
153
- const e = J++, o = r(() => d.value.findIndex((n) => n.id === e));
154
- function p() {
155
- d.value.some((n) => n.id === e) || d.value.push({
156
- id: e,
157
- type: s
158
- });
159
- }
160
- function u() {
161
- o.value !== -1 && d.value.splice(o.value, 1);
162
- }
163
- S(t, (n) => {
164
- n ? p() : u();
165
- }, {
166
- immediate: !0
167
- }), I(() => {
168
- u();
169
- });
170
- const a = r(() => e === d.value[d.value.length - 1]?.id), w = r(() => o.value > 0), v = r(() => d.value.filter((n) => n.type === s)), _ = r(() => v.value.findIndex((n) => n.id === e) < v.value.length - 1), $ = r(() => v.value.findIndex((n) => n.id === e) > 0), k = [];
171
- function P(n) {
172
- k.push(n);
173
- }
174
- return R("Escape", () => {
175
- a.value && k.forEach((n) => n());
176
- }), {
177
- isActiveStacked: a,
178
- hasStackedBehind: w,
179
- isBehindSameType: _,
180
- hasStackedSameTypeBehind: $,
181
- stackIndex: o,
182
- onClose: P
183
- };
184
- }
185
- typeof document < "u" && S(Q, (t) => {
186
- t ? document.documentElement.classList.add("overflow-hidden") : document.documentElement.classList.remove("overflow-hidden");
187
- }, {
188
- immediate: !0
189
- });
190
- function ae() {
191
- const t = B();
192
- let s = null;
193
- H(async () => {
194
- await O();
195
- const e = t.proxy.$el;
196
- if (!e?.querySelector) return;
197
- let o = e.querySelector("[data-stackview-autofocus]");
198
- o ? ["INPUT", "A", "BUTTON", "TEXTAREA"].includes(o.tagName) || (o = o.querySelector("input, a, button, textarea") || o) : (o = e.querySelector('button[type="submit"]'), console.warn(
199
- "%cDEV",
200
- "background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;",
201
- "A element should have the data-stackview-autofocus attribute in this component. Fallback to submit button."
202
- )), clearTimeout(s), s = setTimeout(() => o?.focus(), 150);
203
- });
204
- }
205
- function ne(t) {
206
- t.preventDefault(), (t.target.closest('[role="menu"]') || t.target).querySelector("a")?.focus();
207
- }
208
- export {
209
- te as _,
210
- G as a,
211
- X as b,
212
- j as c,
213
- ae as d,
214
- ne as f,
215
- Q as h,
216
- oe as u
217
- };