@polymarbot/nuxt-layer-shadcn-ui 0.8.0 → 0.8.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.
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* Stacking order (low → high):
|
|
9
9
|
* layout header z-100 (project convention)
|
|
10
10
|
* dialog / sheet (Modal / Drawer) z-200 (cover the header)
|
|
11
|
+
* alert dialog (system interrupts) z-250 (always above other modals)
|
|
11
12
|
* tooltip / popover / dropdown / select z-300 (above modal when nested)
|
|
12
13
|
* ========================================================================= */
|
|
13
14
|
|
|
@@ -19,6 +20,17 @@
|
|
|
19
20
|
z-index: 200;
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
/* AlertDialog must always sit above regular Modals, regardless of teleport
|
|
24
|
+
* order. Vue's <Teleport> places content at a stable anchor based on the
|
|
25
|
+
* host component's mount time — so an AlertDialog declared in app.vue (early
|
|
26
|
+
* mount) ends up *behind* a page-level Modal opened later. The overlay is
|
|
27
|
+
* matched via :has() because reka-ui's DialogPortal renders it as the
|
|
28
|
+
* adjacent previous sibling of the content. */
|
|
29
|
+
[data-slot='dialog-content'][data-alert-dialog],
|
|
30
|
+
[data-slot='dialog-overlay']:has(+ [data-slot='dialog-content'][data-alert-dialog]) {
|
|
31
|
+
z-index: 250;
|
|
32
|
+
}
|
|
33
|
+
|
|
22
34
|
[data-slot='tooltip-content'],
|
|
23
35
|
[data-slot='popover-content'],
|
|
24
36
|
[data-slot='dropdown-menu-content'],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
const { current, isOpen, close, onClosed } = useDialogState()
|
|
2
|
+
const { current, isOpen, isActive, close, onClosed } = useDialogState()
|
|
3
3
|
|
|
4
4
|
const isAlert = computed(() => current.value?.options.rejectLabel === '')
|
|
5
5
|
const isDestructive = computed(() => {
|
|
@@ -10,6 +10,8 @@ const isDestructive = computed(() => {
|
|
|
10
10
|
|
|
11
11
|
<template>
|
|
12
12
|
<Modal
|
|
13
|
+
v-if="isActive"
|
|
14
|
+
data-alert-dialog
|
|
13
15
|
:visible="isOpen"
|
|
14
16
|
:title="current?.options.title"
|
|
15
17
|
:type="current?.options.type"
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
} from '../../shadcn/sheet'
|
|
12
12
|
import type { DrawerProps } from './types'
|
|
13
13
|
|
|
14
|
+
defineOptions({ inheritAttrs: false })
|
|
15
|
+
|
|
14
16
|
const props = withDefaults(defineProps<DrawerProps>(), {
|
|
15
17
|
showClose: true,
|
|
16
18
|
closeOnClickOutside: false,
|
|
@@ -92,6 +94,7 @@ const contentClass = computed(() =>
|
|
|
92
94
|
</SheetTrigger>
|
|
93
95
|
|
|
94
96
|
<SheetContent
|
|
97
|
+
v-bind="$attrs"
|
|
95
98
|
:side="side"
|
|
96
99
|
:class="contentClass"
|
|
97
100
|
@pointerDownOutside="onPointerDownOutside"
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
} from '../../shadcn/dialog'
|
|
12
12
|
import type { ModalProps } from './types'
|
|
13
13
|
|
|
14
|
+
defineOptions({ inheritAttrs: false })
|
|
15
|
+
|
|
14
16
|
const props = withDefaults(defineProps<ModalProps>(), {
|
|
15
17
|
showClose: true,
|
|
16
18
|
closeOnClickOutside: false,
|
|
@@ -97,6 +99,7 @@ const contentClass = computed(() =>
|
|
|
97
99
|
</DialogTrigger>
|
|
98
100
|
|
|
99
101
|
<DialogContent
|
|
102
|
+
v-bind="$attrs"
|
|
100
103
|
:class="contentClass"
|
|
101
104
|
:showCloseButton="false"
|
|
102
105
|
@pointerDownOutside="onPointerDownOutside"
|
|
@@ -18,6 +18,7 @@ interface DialogQueueItem {
|
|
|
18
18
|
|
|
19
19
|
const dialogQueue = reactive<DialogQueueItem[]>([])
|
|
20
20
|
const isOpen = ref(false)
|
|
21
|
+
const mountedInstances = ref<symbol[]>([])
|
|
21
22
|
|
|
22
23
|
function showDialog (options: DialogOptions): Promise<boolean> {
|
|
23
24
|
return new Promise<boolean>(resolve => {
|
|
@@ -52,8 +53,22 @@ export function useDialog () {
|
|
|
52
53
|
|
|
53
54
|
/**
|
|
54
55
|
* Internal composable for the AlertDialog component to access dialog queue.
|
|
56
|
+
*
|
|
57
|
+
* Multiple `<AlertDialog />` instances can be mounted simultaneously (e.g. in
|
|
58
|
+
* Storybook docs view), but only the first one renders the modal — the rest
|
|
59
|
+
* stay inert via `isActive`. This prevents stacked overlays and duplicate
|
|
60
|
+
* `onClosed` events from over-shifting the shared queue.
|
|
55
61
|
*/
|
|
56
62
|
export function useDialogState () {
|
|
63
|
+
const id = Symbol('AlertDialog')
|
|
64
|
+
mountedInstances.value.push(id)
|
|
65
|
+
|
|
66
|
+
onScopeDispose(() => {
|
|
67
|
+
const idx = mountedInstances.value.indexOf(id)
|
|
68
|
+
if (idx >= 0) mountedInstances.value.splice(idx, 1)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const isActive = computed(() => mountedInstances.value[0] === id)
|
|
57
72
|
const current = computed(() => dialogQueue[0] ?? null)
|
|
58
73
|
|
|
59
74
|
/** Resolve current dialog and trigger close animation */
|
|
@@ -72,5 +87,5 @@ export function useDialogState () {
|
|
|
72
87
|
}
|
|
73
88
|
}
|
|
74
89
|
|
|
75
|
-
return { current, isOpen, close, onClosed }
|
|
90
|
+
return { current, isOpen, isActive, close, onClosed }
|
|
76
91
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polymarbot/nuxt-layer-shadcn-ui",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Nuxt layer providing shadcn-vue based UI components",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"vue-i18n": "^11",
|
|
43
43
|
"vue-router": "^4 || ^5"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "6e895437229b0f15e709d90785903ea846399c36"
|
|
46
46
|
}
|