@alikhalilll/a-responsive-popover 1.0.1

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 alikhalilll
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # @alikhalilll/a-responsive-popover
2
+
3
+ One breakpoint-aware component that renders a [reka-ui](https://reka-ui.com) **popover on desktop**
4
+ and a [vaul-vue](https://github.com/unovue/vaul-vue) **drawer on mobile**, with a single API. Built
5
+ on `@alikhalilll/a-popover` + `@alikhalilll/a-drawer` (both pulled in automatically).
6
+
7
+ Components: **`AResponsivePopover`** (root) · **`AResponsivePopoverTrigger`** · **`AResponsivePopoverContent`**.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pnpm add @alikhalilll/a-responsive-popover
13
+ ```
14
+
15
+ ## Styles
16
+
17
+ It renders the popover (desktop) and drawer (mobile), so import all three stylesheets plus the
18
+ shared tokens:
19
+
20
+ ```ts
21
+ import '@alikhalilll/a-popover/styles.css';
22
+ import '@alikhalilll/a-drawer/styles.css';
23
+ import '@alikhalilll/a-responsive-popover/styles.css';
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ```vue
29
+ <script setup lang="ts">
30
+ import { ref } from 'vue';
31
+ import {
32
+ AResponsivePopover,
33
+ AResponsivePopoverTrigger,
34
+ AResponsivePopoverContent,
35
+ } from '@alikhalilll/a-responsive-popover';
36
+
37
+ const open = ref(false);
38
+ </script>
39
+
40
+ <template>
41
+ <AResponsivePopover v-model:open="open">
42
+ <AResponsivePopoverTrigger>Open</AResponsivePopoverTrigger>
43
+ <AResponsivePopoverContent>
44
+ <template #default="{ isDesktop }">
45
+ <p>{{ isDesktop ? 'Popover (desktop)' : 'Drawer (mobile)' }}</p>
46
+ </template>
47
+ </AResponsivePopoverContent>
48
+ </AResponsivePopover>
49
+ </template>
50
+ ```
51
+
52
+ ## API
53
+
54
+ ### `AResponsivePopover` (root)
55
+
56
+ | Prop | Type | Default | Description |
57
+ | ------------ | ------------------------------ | -------------------- | ---------------------------------------------------------------------------------------------------------- |
58
+ | `open` | `boolean` | — | `v-model:open`. |
59
+ | `breakpoint` | `string` | `(min-width: 768px)` | Media query for the desktop break; below it, the drawer renders. |
60
+ | `scrollLock` | `'events' \| 'body' \| 'none'` | `events` | How desktop page-scroll is blocked while open (`events` keeps the scrollbar + `position: sticky` working). |
61
+ | `modal` | `boolean` | `true` | **Deprecated** — prefer `scrollLock`. `false` ≈ `scrollLock="none"`. |
62
+
63
+ Emits `update:open`. The default slot receives `{ isDesktop }` so you can branch content without a
64
+ separate `useMediaQuery`.
65
+
66
+ ### SSR
67
+
68
+ `useMediaQuery` returns `false` on the server, so the first server paint is the drawer branch; the
69
+ client may swap to popover on hydration. Both branches are pre-imported (no lazy chunks), and the
70
+ closed drawer is collapsed, so the swap is invisible.
71
+
72
+ ## Auto-import
73
+
74
+ **Nuxt:**
75
+
76
+ ```ts
77
+ export default defineNuxtConfig({
78
+ modules: ['@alikhalilll/a-responsive-popover/nuxt'],
79
+ css: [
80
+ '@alikhalilll/a-popover/styles.css',
81
+ '@alikhalilll/a-drawer/styles.css',
82
+ '@alikhalilll/a-responsive-popover/styles.css',
83
+ ],
84
+ });
85
+ ```
86
+
87
+ **Vite:** register `@alikhalilll/a-responsive-popover/resolver` in `unplugin-vue-components`.
88
+
89
+ ## License
90
+
91
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,279 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let vue = require("vue");
3
+ let _vueuse_core = require("@vueuse/core");
4
+ let _alikhalilll_a_popover = require("@alikhalilll/a-popover");
5
+ let _alikhalilll_a_drawer = require("@alikhalilll/a-drawer");
6
+ //#region src/composables/useResponsivePopoverContext.ts
7
+ const RESPONSIVE_POPOVER_CONTEXT = Symbol("AResponsivePopoverContext");
8
+ function provideResponsivePopoverContext(ctx) {
9
+ (0, vue.provide)(RESPONSIVE_POPOVER_CONTEXT, ctx);
10
+ }
11
+ function useResponsivePopoverContext() {
12
+ return (0, vue.inject)(RESPONSIVE_POPOVER_CONTEXT, null);
13
+ }
14
+ //#endregion
15
+ //#region \0/plugin-vue/export-helper
16
+ var export_helper_default = (sfc, props) => {
17
+ const target = sfc.__vccOpts || sfc;
18
+ for (const [key, val] of props) target[key] = val;
19
+ return target;
20
+ };
21
+ //#endregion
22
+ //#region src/components/AResponsivePopover.vue
23
+ const _sfc_main$2 = /* @__PURE__ */ (0, vue.defineComponent)({
24
+ __name: "AResponsivePopover",
25
+ props: /* @__PURE__ */ (0, vue.mergeModels)({
26
+ breakpoint: {
27
+ type: String,
28
+ required: false,
29
+ default: "(min-width: 768px)"
30
+ },
31
+ modal: {
32
+ type: Boolean,
33
+ required: false,
34
+ default: true
35
+ },
36
+ scrollLock: {
37
+ type: String,
38
+ required: false,
39
+ default: "events"
40
+ }
41
+ }, {
42
+ "open": { type: Boolean },
43
+ "openModifiers": {}
44
+ }),
45
+ emits: ["update:open"],
46
+ setup(__props, { expose: __expose }) {
47
+ __expose();
48
+ const props = __props;
49
+ const open = (0, vue.useModel)(__props, "open");
50
+ const isDesktop = (0, _vueuse_core.useMediaQuery)(() => props.breakpoint);
51
+ /**
52
+ * Pre-imported on both branches — do NOT lazy-load. Switching the component identity at runtime
53
+ * means we still hydrate the right tree client-side.
54
+ */
55
+ const Root = (0, vue.computed)(() => isDesktop.value ? _alikhalilll_a_popover.APopover : _alikhalilll_a_drawer.ADrawer);
56
+ /**
57
+ * Per-branch `modal` resolution — the two roots interpret the prop differently:
58
+ *
59
+ * APopover (desktop, reka-ui): `modal=true` triggers `PopoverContentModal` + its
60
+ * `useBodyScrollLock`. We only want that when the caller explicitly opted into the
61
+ * body-level scroll lock; for `'events'`/`'none'` we install our own lock in
62
+ * `AResponsivePopoverContent`. Legacy `modal=false` still forces non-modal.
63
+ *
64
+ * ADrawer (mobile, vaul-vue): `modal=false` SUPPRESSES THE OVERLAY entirely. Drawers
65
+ * are modal by convention (a dimmed backdrop is the affordance), so default to modal
66
+ * unless the caller explicitly turned the whole thing off.
67
+ */
68
+ const rekaModal = (0, vue.computed)(() => {
69
+ if (props.modal === false) return false;
70
+ return props.scrollLock === "body";
71
+ });
72
+ const drawerModal = (0, vue.computed)(() => props.modal !== false);
73
+ const rootModal = (0, vue.computed)(() => isDesktop.value ? rekaModal.value : drawerModal.value);
74
+ provideResponsivePopoverContext({
75
+ open: (0, vue.computed)(() => open.value ?? false),
76
+ isDesktop: (0, vue.computed)(() => isDesktop.value),
77
+ scrollLock: (0, vue.computed)(() => props.scrollLock)
78
+ });
79
+ const __returned__ = {
80
+ props,
81
+ open,
82
+ isDesktop,
83
+ Root,
84
+ rekaModal,
85
+ drawerModal,
86
+ rootModal
87
+ };
88
+ Object.defineProperty(__returned__, "__isScriptSetup", {
89
+ enumerable: false,
90
+ value: true
91
+ });
92
+ return __returned__;
93
+ }
94
+ });
95
+ function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
96
+ return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)($setup.Root), {
97
+ open: $setup.open,
98
+ "onUpdate:open": _cache[0] || (_cache[0] = ($event) => $setup.open = $event),
99
+ modal: $setup.rootModal,
100
+ "data-slot": "responsive-popover"
101
+ }, {
102
+ default: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "default", { isDesktop: $setup.isDesktop })]),
103
+ _: 3
104
+ }, 40, ["open", "modal"]);
105
+ }
106
+ var AResponsivePopover_default = /* @__PURE__ */ export_helper_default(_sfc_main$2, [["render", _sfc_render$2], ["__file", "/Users/alikhalill/Desktop/my-projects/ali-nuxt-toolkit/packages/ui-components/AResponsivePopover/src/components/AResponsivePopover.vue"]]);
107
+ //#endregion
108
+ //#region src/components/AResponsivePopoverTrigger.vue
109
+ const _sfc_main$1 = /* @__PURE__ */ (0, vue.defineComponent)({
110
+ __name: "AResponsivePopoverTrigger",
111
+ props: {
112
+ breakpoint: {
113
+ type: String,
114
+ required: false,
115
+ default: "(min-width: 768px)"
116
+ },
117
+ asChild: {
118
+ type: Boolean,
119
+ required: false
120
+ }
121
+ },
122
+ setup(__props, { expose: __expose }) {
123
+ __expose();
124
+ const props = __props;
125
+ const isDesktop = (0, _vueuse_core.useMediaQuery)(() => props.breakpoint);
126
+ const __returned__ = {
127
+ props,
128
+ isDesktop,
129
+ Trigger: (0, vue.computed)(() => isDesktop.value ? _alikhalilll_a_popover.APopoverTrigger : _alikhalilll_a_drawer.ADrawerTrigger)
130
+ };
131
+ Object.defineProperty(__returned__, "__isScriptSetup", {
132
+ enumerable: false,
133
+ value: true
134
+ });
135
+ return __returned__;
136
+ }
137
+ });
138
+ function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
139
+ return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)($setup.Trigger), {
140
+ "as-child": $setup.props.asChild,
141
+ "data-slot": "responsive-popover-trigger"
142
+ }, {
143
+ default: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "default")]),
144
+ _: 3
145
+ }, 8, ["as-child"]);
146
+ }
147
+ var AResponsivePopoverTrigger_default = /* @__PURE__ */ export_helper_default(_sfc_main$1, [["render", _sfc_render$1], ["__file", "/Users/alikhalill/Desktop/my-projects/ali-nuxt-toolkit/packages/ui-components/AResponsivePopover/src/components/AResponsivePopoverTrigger.vue"]]);
148
+ //#endregion
149
+ //#region src/components/AResponsivePopoverContent.vue
150
+ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
151
+ __name: "AResponsivePopoverContent",
152
+ props: {
153
+ breakpoint: {
154
+ type: String,
155
+ required: false,
156
+ default: "(min-width: 768px)"
157
+ },
158
+ class: {
159
+ type: [
160
+ Boolean,
161
+ null,
162
+ String,
163
+ Object,
164
+ Array
165
+ ],
166
+ required: false,
167
+ skipCheck: true
168
+ },
169
+ popoverClass: {
170
+ type: [
171
+ Boolean,
172
+ null,
173
+ String,
174
+ Object,
175
+ Array
176
+ ],
177
+ required: false,
178
+ skipCheck: true
179
+ },
180
+ drawerClass: {
181
+ type: [
182
+ Boolean,
183
+ null,
184
+ String,
185
+ Object,
186
+ Array
187
+ ],
188
+ required: false,
189
+ skipCheck: true
190
+ },
191
+ overlay: {
192
+ type: Boolean,
193
+ required: false,
194
+ default: false
195
+ },
196
+ align: {
197
+ type: String,
198
+ required: false,
199
+ default: "start"
200
+ },
201
+ sideOffset: {
202
+ type: Number,
203
+ required: false,
204
+ default: 4
205
+ }
206
+ },
207
+ setup(__props, { expose: __expose }) {
208
+ __expose();
209
+ const props = __props;
210
+ const ctx = useResponsivePopoverContext();
211
+ const fallbackIsDesktop = (0, _vueuse_core.useMediaQuery)(() => props.breakpoint);
212
+ const isDesktop = (0, vue.computed)(() => ctx?.isDesktop.value ?? fallbackIsDesktop.value);
213
+ const scrollLockMode = (0, vue.computed)(() => ctx?.scrollLock.value ?? "events");
214
+ const overlayLockScroll = (0, vue.computed)(() => scrollLockMode.value === "body");
215
+ const mergedClass = (0, vue.computed)(() => [props.class, isDesktop.value ? props.popoverClass : props.drawerClass]);
216
+ (0, _alikhalilll_a_popover.useEventScrollLock)({
217
+ allowedScrollContainer: () => {
218
+ if (typeof document === "undefined") return [];
219
+ return Array.from(document.querySelectorAll("[data-responsive-popover-scroll-container=\"true\"]"));
220
+ },
221
+ active: (0, vue.computed)(() => !!ctx?.open.value && isDesktop.value && scrollLockMode.value === "events")
222
+ });
223
+ const __returned__ = {
224
+ props,
225
+ ctx,
226
+ fallbackIsDesktop,
227
+ isDesktop,
228
+ scrollLockMode,
229
+ overlayLockScroll,
230
+ mergedClass,
231
+ get APopoverContent() {
232
+ return _alikhalilll_a_popover.APopoverContent;
233
+ },
234
+ get ADrawerContent() {
235
+ return _alikhalilll_a_drawer.ADrawerContent;
236
+ }
237
+ };
238
+ Object.defineProperty(__returned__, "__isScriptSetup", {
239
+ enumerable: false,
240
+ value: true
241
+ });
242
+ return __returned__;
243
+ }
244
+ });
245
+ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
246
+ return $setup.isDesktop ? ((0, vue.openBlock)(), (0, vue.createBlock)($setup["APopoverContent"], {
247
+ key: 0,
248
+ overlay: $setup.props.overlay,
249
+ "overlay-lock-scroll": $setup.overlayLockScroll,
250
+ align: $setup.props.align,
251
+ "side-offset": $setup.props.sideOffset,
252
+ class: (0, vue.normalizeClass)($setup.mergedClass),
253
+ "data-slot": "responsive-popover-content",
254
+ "data-responsive-popover-scroll-container": "true"
255
+ }, {
256
+ default: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "default")]),
257
+ _: 3
258
+ }, 8, [
259
+ "overlay",
260
+ "overlay-lock-scroll",
261
+ "align",
262
+ "side-offset",
263
+ "class"
264
+ ])) : ((0, vue.openBlock)(), (0, vue.createBlock)($setup["ADrawerContent"], {
265
+ key: 1,
266
+ class: (0, vue.normalizeClass)($setup.mergedClass),
267
+ "data-slot": "responsive-popover-content"
268
+ }, {
269
+ default: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "default")]),
270
+ _: 3
271
+ }, 8, ["class"]));
272
+ }
273
+ var AResponsivePopoverContent_default = /* @__PURE__ */ export_helper_default(_sfc_main, [["render", _sfc_render], ["__file", "/Users/alikhalill/Desktop/my-projects/ali-nuxt-toolkit/packages/ui-components/AResponsivePopover/src/components/AResponsivePopoverContent.vue"]]);
274
+ //#endregion
275
+ exports.AResponsivePopover = AResponsivePopover_default;
276
+ exports.AResponsivePopoverContent = AResponsivePopoverContent_default;
277
+ exports.AResponsivePopoverTrigger = AResponsivePopoverTrigger_default;
278
+
279
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/composables/useResponsivePopoverContext.ts","../src/components/AResponsivePopover.vue","../src/components/AResponsivePopoverTrigger.vue","../src/components/AResponsivePopoverContent.vue"],"sourcesContent":["import { inject, provide, type ComputedRef, type InjectionKey } from 'vue';\nimport type { ScrollLockMode } from '../types';\n\nexport interface ResponsivePopoverContext {\n open: ComputedRef<boolean>;\n isDesktop: ComputedRef<boolean>;\n scrollLock: ComputedRef<ScrollLockMode>;\n}\n\nconst RESPONSIVE_POPOVER_CONTEXT: InjectionKey<ResponsivePopoverContext> = Symbol(\n 'AResponsivePopoverContext'\n);\n\nexport function provideResponsivePopoverContext(ctx: ResponsivePopoverContext) {\n provide(RESPONSIVE_POPOVER_CONTEXT, ctx);\n}\n\nexport function useResponsivePopoverContext(): ResponsivePopoverContext | null {\n return inject(RESPONSIVE_POPOVER_CONTEXT, null);\n}\n","<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { useMediaQuery } from '@vueuse/core';\nimport { APopover } from '@alikhalilll/a-popover';\nimport { ADrawer } from '@alikhalilll/a-drawer';\nimport { provideResponsivePopoverContext } from '../composables/useResponsivePopoverContext';\nimport type { AResponsivePopoverProps, AResponsivePopoverSlots } from '../types';\n\nconst props = withDefaults(defineProps<AResponsivePopoverProps>(), {\n breakpoint: '(min-width: 768px)',\n modal: true,\n scrollLock: 'events',\n});\n\ndefineSlots<AResponsivePopoverSlots>();\n\nconst open = defineModel<boolean>('open');\n\nconst isDesktop = useMediaQuery(() => props.breakpoint);\n\n/**\n * Pre-imported on both branches — do NOT lazy-load. Switching the component identity at runtime\n * means we still hydrate the right tree client-side.\n */\nconst Root = computed(() => (isDesktop.value ? APopover : ADrawer));\n\n/**\n * Per-branch `modal` resolution — the two roots interpret the prop differently:\n *\n * APopover (desktop, reka-ui): `modal=true` triggers `PopoverContentModal` + its\n * `useBodyScrollLock`. We only want that when the caller explicitly opted into the\n * body-level scroll lock; for `'events'`/`'none'` we install our own lock in\n * `AResponsivePopoverContent`. Legacy `modal=false` still forces non-modal.\n *\n * ADrawer (mobile, vaul-vue): `modal=false` SUPPRESSES THE OVERLAY entirely. Drawers\n * are modal by convention (a dimmed backdrop is the affordance), so default to modal\n * unless the caller explicitly turned the whole thing off.\n */\nconst rekaModal = computed(() => {\n if (props.modal === false) return false;\n return props.scrollLock === 'body';\n});\nconst drawerModal = computed(() => props.modal !== false);\nconst rootModal = computed(() => (isDesktop.value ? rekaModal.value : drawerModal.value));\n\nprovideResponsivePopoverContext({\n open: computed(() => open.value ?? false),\n isDesktop: computed(() => isDesktop.value),\n scrollLock: computed(() => props.scrollLock),\n});\n</script>\n\n<template>\n <component :is=\"Root\" v-model:open=\"open\" :modal=\"rootModal\" data-slot=\"responsive-popover\">\n <slot :is-desktop=\"isDesktop\" />\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { useMediaQuery } from '@vueuse/core';\nimport { APopoverTrigger } from '@alikhalilll/a-popover';\nimport { ADrawerTrigger } from '@alikhalilll/a-drawer';\n\nconst props = withDefaults(\n defineProps<{\n breakpoint?: string;\n asChild?: boolean;\n }>(),\n { breakpoint: '(min-width: 768px)' }\n);\n\nconst isDesktop = useMediaQuery(() => props.breakpoint);\nconst Trigger = computed(() => (isDesktop.value ? APopoverTrigger : ADrawerTrigger));\n</script>\n\n<template>\n <component :is=\"Trigger\" :as-child=\"props.asChild\" data-slot=\"responsive-popover-trigger\">\n <slot />\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue';\nimport { computed } from 'vue';\nimport { useMediaQuery } from '@vueuse/core';\nimport { APopoverContent, useEventScrollLock } from '@alikhalilll/a-popover';\nimport { ADrawerContent } from '@alikhalilll/a-drawer';\nimport { useResponsivePopoverContext } from '../composables/useResponsivePopoverContext';\n\nconst props = withDefaults(\n defineProps<{\n breakpoint?: string;\n /** Classes applied on both branches. Avoid width / inset classes here. */\n class?: HTMLAttributes['class'];\n /** Classes applied only when the popover (desktop) branch is rendered. */\n popoverClass?: HTMLAttributes['class'];\n /** Classes applied only when the drawer (mobile) branch is rendered. */\n drawerClass?: HTMLAttributes['class'];\n /**\n * Render the dimmed overlay on the desktop popover branch. Defaults to `false` — popovers\n * on desktop are non-modal-looking by convention. The mobile drawer always has its own\n * overlay (vaul-vue's `DrawerOverlay`) regardless of this prop.\n */\n overlay?: boolean;\n align?: 'start' | 'center' | 'end';\n sideOffset?: number;\n }>(),\n {\n breakpoint: '(min-width: 768px)',\n align: 'start',\n sideOffset: 4,\n overlay: false,\n }\n);\n\nconst ctx = useResponsivePopoverContext();\n\n// Prefer the root's media query (so both layers agree). Fall back to a local one when this\n// component is used outside `AResponsivePopover` (unusual but supported).\nconst fallbackIsDesktop = useMediaQuery(() => props.breakpoint);\nconst isDesktop = computed(() => ctx?.isDesktop.value ?? fallbackIsDesktop.value);\n\nconst scrollLockMode = computed(() => ctx?.scrollLock.value ?? 'events');\nconst overlayLockScroll = computed(() => scrollLockMode.value === 'body');\n\nconst mergedClass = computed(() => [\n props.class,\n isDesktop.value ? props.popoverClass : props.drawerClass,\n]);\n\n// Sticky-safe scroll lock — only active while the popover is open on desktop and the root\n// asked for the event-based strategy. The getter resolves every responsive popover content\n// element currently in the DOM, which lets stacked popovers share the lock cleanly.\nuseEventScrollLock({\n allowedScrollContainer: () => {\n if (typeof document === 'undefined') return [];\n return Array.from(\n document.querySelectorAll<HTMLElement>('[data-responsive-popover-scroll-container=\"true\"]')\n );\n },\n active: computed(() => !!ctx?.open.value && isDesktop.value && scrollLockMode.value === 'events'),\n});\n</script>\n\n<template>\n <APopoverContent\n v-if=\"isDesktop\"\n :overlay=\"props.overlay\"\n :overlay-lock-scroll=\"overlayLockScroll\"\n :align=\"props.align\"\n :side-offset=\"props.sideOffset\"\n :class=\"mergedClass\"\n data-slot=\"responsive-popover-content\"\n data-responsive-popover-scroll-container=\"true\"\n >\n <slot />\n </APopoverContent>\n <ADrawerContent v-else :class=\"mergedClass\" data-slot=\"responsive-popover-content\">\n <slot />\n </ADrawerContent>\n</template>\n"],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ import { HTMLAttributes } from "vue";
2
+
3
+ //#region src/types.d.ts
4
+ type ScrollLockMode = 'events' | 'body' | 'none';
5
+ interface AResponsivePopoverProps {
6
+ /** CSS media query for the desktop break. Below this width we render a vaul drawer. */
7
+ breakpoint?: string;
8
+ /**
9
+ * @deprecated prefer `scrollLock`. Kept for back-compat: `modal=false` is a shorthand
10
+ * for `scrollLock="none"` (tooltip-style popover). `modal=true` (default) defers to
11
+ * `scrollLock`, which controls how page scroll is blocked.
12
+ */
13
+ modal?: boolean;
14
+ /**
15
+ * How desktop page scroll is blocked while the popover is open:
16
+ * - `'events'` (default) — wheel/touch/keyboard intercepted at document level.
17
+ * Page scrollbar stays visible; `position: sticky` keeps working.
18
+ * - `'body'` — legacy `document.body.style.overflow='hidden'` lock. Use when the
19
+ * page must reflow as the scrollbar goes away.
20
+ * - `'none'` — no page-scroll lock at all.
21
+ *
22
+ * Drawer (mobile) branch is unaffected — vaul-vue owns its own lock.
23
+ */
24
+ scrollLock?: ScrollLockMode;
25
+ }
26
+ /**
27
+ * Emit map for {@link AResponsivePopover}. `update:open` is the `v-model:open`.
28
+ */
29
+ type AResponsivePopoverEmits = {
30
+ 'update:open': [value: boolean | undefined];
31
+ };
32
+ /**
33
+ * Slot prop shape for {@link AResponsivePopover}. The default slot receives
34
+ * `isDesktop` so consumers can branch content on the active breakpoint without
35
+ * a separate `useMediaQuery` call.
36
+ */
37
+ interface AResponsivePopoverSlots {
38
+ default?: (props: {
39
+ isDesktop: boolean;
40
+ }) => unknown;
41
+ }
42
+ //#endregion
43
+ //#region src/components/AResponsivePopover.vue.d.ts
44
+ type __VLS_Props$2 = AResponsivePopoverProps;
45
+ type __VLS_Slots$2 = AResponsivePopoverSlots;
46
+ type __VLS_ModelProps = {
47
+ 'open'?: boolean;
48
+ };
49
+ type __VLS_PublicProps = __VLS_Props$2 & __VLS_ModelProps;
50
+ declare const __VLS_base$2: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
51
+ "update:open": (value: boolean | undefined) => any;
52
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
53
+ "onUpdate:open"?: ((value: boolean | undefined) => any) | undefined;
54
+ }>, {
55
+ breakpoint: string;
56
+ modal: boolean;
57
+ scrollLock: ScrollLockMode;
58
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
59
+ declare const __VLS_export$2: typeof __VLS_base$2;
60
+ declare const _default: typeof __VLS_export$2;
61
+ //#endregion
62
+ //#region src/components/AResponsivePopoverTrigger.vue.d.ts
63
+ type __VLS_Props$1 = {
64
+ breakpoint?: string;
65
+ asChild?: boolean;
66
+ };
67
+ declare var __VLS_8$1: {};
68
+ type __VLS_Slots$1 = {} & {
69
+ default?: (props: typeof __VLS_8$1) => any;
70
+ };
71
+ declare const __VLS_base$1: import("vue").DefineComponent<__VLS_Props$1, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props$1> & Readonly<{}>, {
72
+ breakpoint: string;
73
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
74
+ declare const __VLS_export$1: typeof __VLS_base$1;
75
+ declare const _default$2: typeof __VLS_export$1;
76
+ //#endregion
77
+ //#region src/components/AResponsivePopoverContent.vue.d.ts
78
+ type __VLS_Props = {
79
+ breakpoint?: string; /** Classes applied on both branches. Avoid width / inset classes here. */
80
+ class?: HTMLAttributes['class']; /** Classes applied only when the popover (desktop) branch is rendered. */
81
+ popoverClass?: HTMLAttributes['class']; /** Classes applied only when the drawer (mobile) branch is rendered. */
82
+ drawerClass?: HTMLAttributes['class'];
83
+ /**
84
+ * Render the dimmed overlay on the desktop popover branch. Defaults to `false` — popovers
85
+ * on desktop are non-modal-looking by convention. The mobile drawer always has its own
86
+ * overlay (vaul-vue's `DrawerOverlay`) regardless of this prop.
87
+ */
88
+ overlay?: boolean;
89
+ align?: 'start' | 'center' | 'end';
90
+ sideOffset?: number;
91
+ };
92
+ declare var __VLS_8: {}, __VLS_17: {};
93
+ type __VLS_Slots = {} & {
94
+ default?: (props: typeof __VLS_8) => any;
95
+ } & {
96
+ default?: (props: typeof __VLS_17) => any;
97
+ };
98
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
99
+ breakpoint: string;
100
+ overlay: boolean;
101
+ align: "start" | "center" | "end";
102
+ sideOffset: number;
103
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
104
+ declare const __VLS_export: typeof __VLS_base;
105
+ declare const _default$1: typeof __VLS_export;
106
+ //#endregion
107
+ export { _default as AResponsivePopover, _default$1 as AResponsivePopoverContent, type AResponsivePopoverEmits, type AResponsivePopoverProps, type AResponsivePopoverSlots, _default$2 as AResponsivePopoverTrigger, type ScrollLockMode };
108
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,108 @@
1
+ import { HTMLAttributes } from "vue";
2
+
3
+ //#region src/types.d.ts
4
+ type ScrollLockMode = 'events' | 'body' | 'none';
5
+ interface AResponsivePopoverProps {
6
+ /** CSS media query for the desktop break. Below this width we render a vaul drawer. */
7
+ breakpoint?: string;
8
+ /**
9
+ * @deprecated prefer `scrollLock`. Kept for back-compat: `modal=false` is a shorthand
10
+ * for `scrollLock="none"` (tooltip-style popover). `modal=true` (default) defers to
11
+ * `scrollLock`, which controls how page scroll is blocked.
12
+ */
13
+ modal?: boolean;
14
+ /**
15
+ * How desktop page scroll is blocked while the popover is open:
16
+ * - `'events'` (default) — wheel/touch/keyboard intercepted at document level.
17
+ * Page scrollbar stays visible; `position: sticky` keeps working.
18
+ * - `'body'` — legacy `document.body.style.overflow='hidden'` lock. Use when the
19
+ * page must reflow as the scrollbar goes away.
20
+ * - `'none'` — no page-scroll lock at all.
21
+ *
22
+ * Drawer (mobile) branch is unaffected — vaul-vue owns its own lock.
23
+ */
24
+ scrollLock?: ScrollLockMode;
25
+ }
26
+ /**
27
+ * Emit map for {@link AResponsivePopover}. `update:open` is the `v-model:open`.
28
+ */
29
+ type AResponsivePopoverEmits = {
30
+ 'update:open': [value: boolean | undefined];
31
+ };
32
+ /**
33
+ * Slot prop shape for {@link AResponsivePopover}. The default slot receives
34
+ * `isDesktop` so consumers can branch content on the active breakpoint without
35
+ * a separate `useMediaQuery` call.
36
+ */
37
+ interface AResponsivePopoverSlots {
38
+ default?: (props: {
39
+ isDesktop: boolean;
40
+ }) => unknown;
41
+ }
42
+ //#endregion
43
+ //#region src/components/AResponsivePopover.vue.d.ts
44
+ type __VLS_Props$2 = AResponsivePopoverProps;
45
+ type __VLS_Slots$2 = AResponsivePopoverSlots;
46
+ type __VLS_ModelProps = {
47
+ 'open'?: boolean;
48
+ };
49
+ type __VLS_PublicProps = __VLS_Props$2 & __VLS_ModelProps;
50
+ declare const __VLS_base$2: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
51
+ "update:open": (value: boolean | undefined) => any;
52
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
53
+ "onUpdate:open"?: ((value: boolean | undefined) => any) | undefined;
54
+ }>, {
55
+ breakpoint: string;
56
+ modal: boolean;
57
+ scrollLock: ScrollLockMode;
58
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
59
+ declare const __VLS_export$2: typeof __VLS_base$2;
60
+ declare const _default: typeof __VLS_export$2;
61
+ //#endregion
62
+ //#region src/components/AResponsivePopoverTrigger.vue.d.ts
63
+ type __VLS_Props$1 = {
64
+ breakpoint?: string;
65
+ asChild?: boolean;
66
+ };
67
+ declare var __VLS_8$1: {};
68
+ type __VLS_Slots$1 = {} & {
69
+ default?: (props: typeof __VLS_8$1) => any;
70
+ };
71
+ declare const __VLS_base$1: import("vue").DefineComponent<__VLS_Props$1, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props$1> & Readonly<{}>, {
72
+ breakpoint: string;
73
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
74
+ declare const __VLS_export$1: typeof __VLS_base$1;
75
+ declare const _default$2: typeof __VLS_export$1;
76
+ //#endregion
77
+ //#region src/components/AResponsivePopoverContent.vue.d.ts
78
+ type __VLS_Props = {
79
+ breakpoint?: string; /** Classes applied on both branches. Avoid width / inset classes here. */
80
+ class?: HTMLAttributes['class']; /** Classes applied only when the popover (desktop) branch is rendered. */
81
+ popoverClass?: HTMLAttributes['class']; /** Classes applied only when the drawer (mobile) branch is rendered. */
82
+ drawerClass?: HTMLAttributes['class'];
83
+ /**
84
+ * Render the dimmed overlay on the desktop popover branch. Defaults to `false` — popovers
85
+ * on desktop are non-modal-looking by convention. The mobile drawer always has its own
86
+ * overlay (vaul-vue's `DrawerOverlay`) regardless of this prop.
87
+ */
88
+ overlay?: boolean;
89
+ align?: 'start' | 'center' | 'end';
90
+ sideOffset?: number;
91
+ };
92
+ declare var __VLS_8: {}, __VLS_17: {};
93
+ type __VLS_Slots = {} & {
94
+ default?: (props: typeof __VLS_8) => any;
95
+ } & {
96
+ default?: (props: typeof __VLS_17) => any;
97
+ };
98
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
99
+ breakpoint: string;
100
+ overlay: boolean;
101
+ align: "start" | "center" | "end";
102
+ sideOffset: number;
103
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
104
+ declare const __VLS_export: typeof __VLS_base;
105
+ declare const _default$1: typeof __VLS_export;
106
+ //#endregion
107
+ export { _default as AResponsivePopover, _default$1 as AResponsivePopoverContent, type AResponsivePopoverEmits, type AResponsivePopoverProps, type AResponsivePopoverSlots, _default$2 as AResponsivePopoverTrigger, type ScrollLockMode };
108
+ //# sourceMappingURL=index.d.ts.map