@greypan/web-ui 4.0.0 → 6.0.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.
- package/README.CN.md +259 -139
- package/README.md +296 -139
- package/dist/assets/glass.js +1 -1
- package/dist/assets/glass.js.map +1 -1
- package/dist/assets/menu-portal.js +1 -1
- package/dist/assets/menu-portal.js.map +1 -1
- package/dist/components/autocomplete/index.d.ts +8 -0
- package/dist/components/autocomplete/index.js +108 -50
- package/dist/components/autocomplete/index.js.map +1 -1
- package/dist/components/autocomplete/style.js +1 -1
- package/dist/components/autocomplete/style.js.map +1 -1
- package/dist/components/back-top/index.js +1 -1
- package/dist/components/back-top/index.js.map +1 -1
- package/dist/components/back-top/style.js +1 -1
- package/dist/components/back-top/style.js.map +1 -1
- package/dist/components/button/index.js +33 -32
- package/dist/components/button/index.js.map +1 -1
- package/dist/components/button/style.js +1 -1
- package/dist/components/button/style.js.map +1 -1
- package/dist/components/button-group/index.js +14 -12
- package/dist/components/button-group/index.js.map +1 -1
- package/dist/components/button-group/style.js +1 -1
- package/dist/components/button-group/style.js.map +1 -1
- package/dist/components/checkbox/index.js +23 -16
- package/dist/components/checkbox/index.js.map +1 -1
- package/dist/components/checkbox/style.js +1 -1
- package/dist/components/checkbox/style.js.map +1 -1
- package/dist/components/collapse/index.d.ts +66 -0
- package/dist/components/collapse/index.js +159 -0
- package/dist/components/collapse/index.js.map +1 -0
- package/dist/components/collapse/style.js +6 -0
- package/dist/components/collapse/style.js.map +1 -0
- package/dist/components/context-menu/index.d.ts +9 -0
- package/dist/components/context-menu/index.js +109 -51
- package/dist/components/context-menu/index.js.map +1 -1
- package/dist/components/dialog/index.d.ts +6 -0
- package/dist/components/dialog/index.js +28 -7
- package/dist/components/dialog/index.js.map +1 -1
- package/dist/components/dialog/style.js +1 -1
- package/dist/components/dialog/style.js.map +1 -1
- package/dist/components/drawer/index.d.ts +32 -2
- package/dist/components/drawer/index.js +229 -39
- package/dist/components/drawer/index.js.map +1 -1
- package/dist/components/drawer/style.js +1 -1
- package/dist/components/drawer/style.js.map +1 -1
- package/dist/components/dropdown/index.d.ts +8 -0
- package/dist/components/dropdown/index.js +84 -40
- package/dist/components/dropdown/index.js.map +1 -1
- package/dist/components/dropdown-item/style.js +1 -1
- package/dist/components/dropdown-item/style.js.map +1 -1
- package/dist/components/empty/index.d.ts +1 -0
- package/dist/components/empty/index.js +23 -21
- package/dist/components/empty/index.js.map +1 -1
- package/dist/components/empty/style.js +1 -1
- package/dist/components/empty/style.js.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +28 -27
- package/dist/components/input/style.js +1 -1
- package/dist/components/input/style.js.map +1 -1
- package/dist/components/input-number/style.js +1 -1
- package/dist/components/input-number/style.js.map +1 -1
- package/dist/components/layout/index.d.ts +23 -0
- package/dist/components/layout/index.js +134 -30
- package/dist/components/layout/index.js.map +1 -1
- package/dist/components/layout/style.js +1 -1
- package/dist/components/layout/style.js.map +1 -1
- package/dist/components/option/style.js +1 -1
- package/dist/components/option/style.js.map +1 -1
- package/dist/components/popover/index.d.ts +4 -1
- package/dist/components/popover/index.js +18 -6
- package/dist/components/popover/index.js.map +1 -1
- package/dist/components/popover/style.js +1 -1
- package/dist/components/popover/style.js.map +1 -1
- package/dist/components/radio/index.js +18 -15
- package/dist/components/radio/index.js.map +1 -1
- package/dist/components/radio/style.js +1 -1
- package/dist/components/radio/style.js.map +1 -1
- package/dist/components/segmented/index.d.ts +8 -1
- package/dist/components/segmented/index.js +87 -21
- package/dist/components/segmented/index.js.map +1 -1
- package/dist/components/segmented/style.js +1 -1
- package/dist/components/segmented/style.js.map +1 -1
- package/dist/components/segmented-trigger/index.js +17 -14
- package/dist/components/segmented-trigger/index.js.map +1 -1
- package/dist/components/segmented-trigger/style.js +1 -1
- package/dist/components/segmented-trigger/style.js.map +1 -1
- package/dist/components/select/index.js +33 -29
- package/dist/components/select/index.js.map +1 -1
- package/dist/components/select/style.js +1 -1
- package/dist/components/select/style.js.map +1 -1
- package/dist/components/slider/index.d.ts +3 -2
- package/dist/components/slider/index.js +65 -47
- package/dist/components/slider/index.js.map +1 -1
- package/dist/components/slider/style.js +1 -1
- package/dist/components/slider/style.js.map +1 -1
- package/dist/components/spinner/index.js.map +1 -1
- package/dist/components/switch/index.d.ts +8 -0
- package/dist/components/switch/index.js +72 -25
- package/dist/components/switch/index.js.map +1 -1
- package/dist/components/switch/style.js +1 -1
- package/dist/components/switch/style.js.map +1 -1
- package/dist/components/textarea/index.js +1 -4
- package/dist/components/textarea/index.js.map +1 -1
- package/dist/components/textarea/style.js +1 -1
- package/dist/components/textarea/style.js.map +1 -1
- package/dist/components/theme/style.js +1 -1
- package/dist/components/theme/style.js.map +1 -1
- package/dist/components/toast/style.js +1 -1
- package/dist/components/toast/style.js.map +1 -1
- package/dist/components/toast/toast.js.map +1 -1
- package/dist/components/tooltip/index.d.ts +1 -0
- package/dist/components/tooltip/index.js +9 -4
- package/dist/components/tooltip/index.js.map +1 -1
- package/dist/components/tooltip/style.js +1 -1
- package/dist/components/tooltip/style.js.map +1 -1
- package/dist/icons/generated/heroicons-arrow-down-16-solid.d.ts +6 -0
- package/dist/icons/generated/heroicons-arrow-up-16-solid.d.ts +6 -0
- package/dist/icons/generated/heroicons-bars-arrow-down-16-solid.d.ts +6 -0
- package/dist/icons/generated/heroicons-bars-arrow-down-16-solid.js +10 -0
- package/dist/icons/generated/heroicons-bars-arrow-down-16-solid.js.map +1 -0
- package/dist/icons/generated/heroicons-bars-arrow-up-16-solid.d.ts +6 -0
- package/dist/icons/generated/heroicons-bars-arrow-up-16-solid.js +10 -0
- package/dist/icons/generated/heroicons-bars-arrow-up-16-solid.js.map +1 -0
- package/dist/icons/generated/lucide-code.d.ts +6 -0
- package/dist/icons/generated/lucide-code.js +10 -0
- package/dist/icons/generated/lucide-code.js.map +1 -0
- package/dist/icons/generated/lucide-ellipsis-vertical.d.ts +6 -0
- package/dist/icons/generated/lucide-ellipsis-vertical.js +10 -0
- package/dist/icons/generated/lucide-ellipsis-vertical.js.map +1 -0
- package/dist/icons/generated/lucide-list-filter.d.ts +6 -0
- package/dist/icons/generated/lucide-list-filter.js +10 -0
- package/dist/icons/generated/lucide-list-filter.js.map +1 -0
- package/dist/icons/generated/lucide-list-restart.d.ts +6 -0
- package/dist/icons/generated/lucide-list-restart.js +10 -0
- package/dist/icons/generated/lucide-list-restart.js.map +1 -0
- package/dist/icons/generated/lucide-tag.d.ts +6 -0
- package/dist/icons/generated/lucide-tag.js +10 -0
- package/dist/icons/generated/lucide-tag.js.map +1 -0
- package/dist/icons/generated/tabler-sort-ascending-letters.d.ts +6 -0
- package/dist/icons/generated/tabler-sort-ascending-letters.js +10 -0
- package/dist/icons/generated/tabler-sort-ascending-letters.js.map +1 -0
- package/dist/icons/index.d.ts +8 -0
- package/dist/icons/index.js +18 -10
- package/dist/shared/gesture/drag-gesture.js +133 -0
- package/dist/shared/gesture/drag-gesture.js.map +1 -0
- package/dist/shared/gesture/physics.js +45 -0
- package/dist/shared/gesture/physics.js.map +1 -0
- package/dist/shared/group-management/index.js +49 -47
- package/dist/shared/group-management/index.js.map +1 -1
- package/dist/shared/menu-portal/menu-portal.js +22 -10
- package/dist/shared/menu-portal/menu-portal.js.map +1 -1
- package/dist/shared/menu-portal/menu-tree.js +63 -2
- package/dist/shared/menu-portal/menu-tree.js.map +1 -1
- package/dist/shared/option-portal/index.js +1 -1
- package/dist/shared/option-portal/index.js.map +1 -1
- package/dist/shared/overlay/native-dialog-presence.js.map +1 -1
- package/dist/shared/overlay/nested-drawer-layers.js +55 -0
- package/dist/shared/overlay/nested-drawer-layers.js.map +1 -0
- package/dist/shared/overlay/overlay.js.map +1 -1
- package/dist/shared/overlay/portal.js +119 -16
- package/dist/shared/overlay/portal.js.map +1 -1
- package/package.json +8 -3
|
@@ -3,28 +3,62 @@ import "../icon/index.js";
|
|
|
3
3
|
import t from "../../icons/generated/ooui-close.js";
|
|
4
4
|
import n from "../../assets/glass.js";
|
|
5
5
|
import { normalizeLiteral as r } from "../../shared/normalize/index.js";
|
|
6
|
-
import {
|
|
6
|
+
import { findNearestTheme as i } from "../../shared/theme/theme-scope.js";
|
|
7
|
+
import { defineScrollLockLease as a } from "../../shared/scroll-lock/scroll-lock.js";
|
|
7
8
|
import "../button/index.js";
|
|
8
|
-
import { UserChangeController as
|
|
9
|
-
import { defineNativeDialogPresence as
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
9
|
+
import { UserChangeController as o } from "../../shared/events/user-change.js";
|
|
10
|
+
import { defineNativeDialogPresence as s } from "../../shared/overlay/native-dialog-presence.js";
|
|
11
|
+
import { attachDragGesture as c } from "../../shared/gesture/drag-gesture.js";
|
|
12
|
+
import { SPRING_PRESETS as l, rubberband as u, springOffsets as d } from "../../shared/gesture/physics.js";
|
|
13
|
+
import { defineNestedDrawerLayers as f } from "../../shared/overlay/nested-drawer-layers.js";
|
|
14
|
+
import p from "./style.js";
|
|
15
|
+
import { LitElement as m, html as h, nothing as g, unsafeCSS as _ } from "lit";
|
|
16
|
+
import { customElement as v, property as y } from "lit/decorators.js";
|
|
13
17
|
//#region src/components/drawer/index.ts
|
|
14
|
-
var
|
|
18
|
+
var b = [
|
|
15
19
|
"right",
|
|
16
20
|
"left",
|
|
17
21
|
"top",
|
|
18
22
|
"bottom"
|
|
19
|
-
],
|
|
23
|
+
], x = 1 / 3, S = 500, C = 120, w = 16;
|
|
24
|
+
if (typeof CSS < "u" && "registerProperty" in CSS) {
|
|
25
|
+
try {
|
|
26
|
+
CSS.registerProperty({
|
|
27
|
+
name: "--wui-internal-drag-backdrop-opacity",
|
|
28
|
+
syntax: "<number>",
|
|
29
|
+
inherits: !0,
|
|
30
|
+
initialValue: "1"
|
|
31
|
+
});
|
|
32
|
+
} catch {}
|
|
33
|
+
try {
|
|
34
|
+
CSS.registerProperty({
|
|
35
|
+
name: "--wui-drawer-inset",
|
|
36
|
+
syntax: "<length>",
|
|
37
|
+
inherits: !0,
|
|
38
|
+
initialValue: "8px"
|
|
39
|
+
});
|
|
40
|
+
} catch {}
|
|
41
|
+
}
|
|
42
|
+
var T = class extends m {
|
|
20
43
|
constructor(...e) {
|
|
21
|
-
super(...e), this.open = !1, this.noScrollLock = !1, this.noBackdropClose = !1, this.
|
|
44
|
+
super(...e), this.open = !1, this.noScrollLock = !1, this.noBackdropClose = !1, this.controlled = !1, this._placement = "right", this.heading = "", this.closable = !1, this.headless = !1, this.dialogLabel = "", this.draggable = !1, this._hasHeaderSlot = !1, this._hasFooterSlot = !1, this._userOpenChange = new o(), this._scrollLock = a().make(), this._presence = s().make({
|
|
22
45
|
getDialog: () => this.dialog,
|
|
23
46
|
isConnected: () => this.isConnected,
|
|
24
47
|
isOpen: () => this.open
|
|
25
|
-
}), this.
|
|
26
|
-
|
|
27
|
-
|
|
48
|
+
}), this._nestedLayers = f().make({
|
|
49
|
+
getDialog: () => this.dialog,
|
|
50
|
+
getPlacement: () => this._placement
|
|
51
|
+
}), this._dragGesture = null, this._dragInitialOffset = 0, this._dragOffset = 0, this._dragAnimation = null, this._dragAwaitWriteback = !1, this._handleDragWritebackTimeout = () => {
|
|
52
|
+
if (this._dragRequestTimer = void 0, !this._dragAwaitWriteback || !this.open || this._isDragging()) {
|
|
53
|
+
this._dragAwaitWriteback = !1;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
this._dragAwaitWriteback = !1;
|
|
57
|
+
let e = this.dialog;
|
|
58
|
+
e && (e.classList.add("is-visible"), this._springRebound(e, 0, this._dragCloseDistance(e)));
|
|
59
|
+
}, this._closeFromUser = () => {
|
|
60
|
+
if (this.open && !this._dragAwaitWriteback) {
|
|
61
|
+
if (this.controlled) {
|
|
28
62
|
this.emitOpenChange(!1);
|
|
29
63
|
return;
|
|
30
64
|
}
|
|
@@ -33,18 +67,145 @@ var m = [
|
|
|
33
67
|
};
|
|
34
68
|
}
|
|
35
69
|
static {
|
|
36
|
-
this.styles = [
|
|
70
|
+
this.styles = [_(n), _(p)];
|
|
37
71
|
}
|
|
38
72
|
get placement() {
|
|
39
73
|
return this._placement;
|
|
40
74
|
}
|
|
41
75
|
set placement(e) {
|
|
42
76
|
let t = this._placement;
|
|
43
|
-
this._placement = r(e,
|
|
77
|
+
this._placement = r(e, b, "right"), this.requestUpdate("placement", t);
|
|
44
78
|
}
|
|
45
79
|
get dialog() {
|
|
46
80
|
return this.shadowRoot?.querySelector("dialog") ?? null;
|
|
47
81
|
}
|
|
82
|
+
get _dragAxis() {
|
|
83
|
+
return this._placement === "left" || this._placement === "right" ? "x" : "y";
|
|
84
|
+
}
|
|
85
|
+
get _dragCloseSign() {
|
|
86
|
+
switch (this._placement) {
|
|
87
|
+
case "right": return 1;
|
|
88
|
+
case "left": return -1;
|
|
89
|
+
case "top": return -1;
|
|
90
|
+
case "bottom": return 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
_measureDragSize() {
|
|
94
|
+
let e = this.dialog;
|
|
95
|
+
return e ? this._dragAxis === "x" ? e.offsetWidth : e.offsetHeight : 0;
|
|
96
|
+
}
|
|
97
|
+
_readDrawerInset(e) {
|
|
98
|
+
let t = getComputedStyle(e).getPropertyValue("--wui-internal-drawer-inset"), n = Number.parseFloat(t);
|
|
99
|
+
return Number.isFinite(n) ? n : 0;
|
|
100
|
+
}
|
|
101
|
+
_dragCloseDistance(e) {
|
|
102
|
+
return this._measureDragSize() + this._readDrawerInset(e);
|
|
103
|
+
}
|
|
104
|
+
_isReducedMotion() {
|
|
105
|
+
let e = i(this);
|
|
106
|
+
if (e) return e.isReducedMotion();
|
|
107
|
+
try {
|
|
108
|
+
return typeof window.matchMedia == "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
109
|
+
} catch {
|
|
110
|
+
return !1;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
_isDragging() {
|
|
114
|
+
return this._dragGesture?.isDragging() ?? !1;
|
|
115
|
+
}
|
|
116
|
+
_cancelDragAwait() {
|
|
117
|
+
this._dragRequestTimer !== void 0 && (clearTimeout(this._dragRequestTimer), this._dragRequestTimer = void 0), this._dragAwaitWriteback = !1;
|
|
118
|
+
}
|
|
119
|
+
_handleDragPointerDown(e) {
|
|
120
|
+
if (!this.open || !this.draggable || this._isDragging() || e.isPrimary === !1) return;
|
|
121
|
+
let t = this.dialog;
|
|
122
|
+
if (!t || !t.classList.contains("is-visible")) return;
|
|
123
|
+
let n = getComputedStyle(t).transform, r = n && n !== "none" && typeof DOMMatrixReadOnly == "function" ? new DOMMatrixReadOnly(n)[this._dragAxis === "x" ? "m41" : "m42"] : 0;
|
|
124
|
+
this._dragAnimation?.cancel(), this._dragAnimation = null, this._cancelDragAwait(), this._dragInitialOffset = r * this._dragCloseSign, this._dragOffset = this._dragInitialOffset, t.classList.add("is-dragging"), this._dragGesture = c(e, {
|
|
125
|
+
axis: this._dragAxis,
|
|
126
|
+
onMove: (e) => {
|
|
127
|
+
let n = this._dragAxis === "x" ? e.deltaX : e.deltaY, r = this._dragInitialOffset + n * this._dragCloseSign;
|
|
128
|
+
this._dragOffset = u(r, this._measureDragSize() * .1, .15);
|
|
129
|
+
let i = this._measureDragSize();
|
|
130
|
+
t.classList.toggle("is-drag-close", i > 0 && this._dragOffset > i * x), this._applyDragOffset(t, this._dragOffset);
|
|
131
|
+
},
|
|
132
|
+
onEnd: (e) => {
|
|
133
|
+
this._dragGesture = null, t.classList.remove("is-dragging", "is-drag-close");
|
|
134
|
+
let n = this._measureDragSize(), r = (this._dragAxis === "x" ? e.velocityX : e.velocityY) * this._dragCloseSign;
|
|
135
|
+
this._dragOffset > n * x || this._dragOffset > 8 && r > S ? this._springToClose(t, r) : this._springRebound(t, r, this._dragOffset);
|
|
136
|
+
},
|
|
137
|
+
onCancel: () => {
|
|
138
|
+
this._dragGesture = null, t.classList.remove("is-dragging", "is-drag-close"), this._springRebound(t, 0, this._dragOffset);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
_cancelActiveDrag() {
|
|
143
|
+
if (!this._isDragging()) return;
|
|
144
|
+
this._dragGesture?.destroy(), this._dragGesture = null;
|
|
145
|
+
let e = this.dialog;
|
|
146
|
+
e && (e.classList.remove("is-dragging", "is-drag-close"), this._clearDragStyles(e));
|
|
147
|
+
}
|
|
148
|
+
_applyDragOffset(e, t) {
|
|
149
|
+
let n = t * this._dragCloseSign;
|
|
150
|
+
e.style.transform = this._dragAxis === "x" ? `translateX(${n}px)` : `translateY(${n}px)`;
|
|
151
|
+
let r = this._measureDragSize(), i = r > 0 ? Math.min(1, Math.max(0, t / r)) : 0;
|
|
152
|
+
e.style.setProperty("--wui-internal-drag-backdrop-opacity", String(1 - i));
|
|
153
|
+
}
|
|
154
|
+
_clearDragStyles(e) {
|
|
155
|
+
e.style.removeProperty("transform"), e.style.removeProperty("--wui-internal-drag-backdrop-opacity");
|
|
156
|
+
}
|
|
157
|
+
_springToClose(e, t) {
|
|
158
|
+
let n = this._dragOffset;
|
|
159
|
+
this._dragOffset = 0;
|
|
160
|
+
let r = this._dragCloseSign, i = this._dragCloseDistance(e), a = this._measureDragSize(), o = () => {
|
|
161
|
+
if (this.controlled) {
|
|
162
|
+
let t = i;
|
|
163
|
+
e.style.transform = this._dragAxis === "x" ? `translateX(${t * r}px)` : `translateY(${t * r}px)`, e.style.setProperty("--wui-internal-drag-backdrop-opacity", "0");
|
|
164
|
+
} else e.classList.remove("is-visible"), this._clearDragStyles(e);
|
|
165
|
+
this._closeFromDrag();
|
|
166
|
+
};
|
|
167
|
+
if (this._isReducedMotion() || typeof e.animate != "function") {
|
|
168
|
+
o();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
let s = d(n, i, t, l.close), c = s.map((e) => ({
|
|
172
|
+
transform: this._dragAxis === "x" ? `translateX(${e * r}px)` : `translateY(${e * r}px)`,
|
|
173
|
+
"--wui-internal-drag-backdrop-opacity": String(Math.max(0, 1 - e / a))
|
|
174
|
+
})), u = (s.length - 1) * w, f = e.animate(c, {
|
|
175
|
+
duration: u,
|
|
176
|
+
easing: "linear",
|
|
177
|
+
fill: "both"
|
|
178
|
+
});
|
|
179
|
+
f.onfinish = () => {
|
|
180
|
+
f.cancel(), o();
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
_springRebound(e, t, n) {
|
|
184
|
+
this._dragOffset = 0;
|
|
185
|
+
let r = () => {
|
|
186
|
+
this._dragAnimation = null, e.classList.remove("is-dragging"), this._clearDragStyles(e);
|
|
187
|
+
};
|
|
188
|
+
if (this._isReducedMotion() || typeof e.animate != "function" || Math.abs(n) < 1) {
|
|
189
|
+
r();
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
let i = this._dragCloseSign, a = this._measureDragSize(), o = d(n, 0, t, l.rebound), s = o.map((e) => ({
|
|
193
|
+
transform: this._dragAxis === "x" ? `translateX(${e * i}px)` : `translateY(${e * i}px)`,
|
|
194
|
+
"--wui-internal-drag-backdrop-opacity": String(Math.max(0, 1 - e / a))
|
|
195
|
+
}));
|
|
196
|
+
e.classList.add("is-dragging");
|
|
197
|
+
let c = (o.length - 1) * w, u = e.animate(s, {
|
|
198
|
+
duration: c,
|
|
199
|
+
easing: "linear",
|
|
200
|
+
fill: "both"
|
|
201
|
+
});
|
|
202
|
+
u.onfinish = () => {
|
|
203
|
+
u.cancel(), r();
|
|
204
|
+
}, this._dragAnimation = u;
|
|
205
|
+
}
|
|
206
|
+
_closeFromDrag() {
|
|
207
|
+
this._closeFromUser(), this.controlled && (this._dragAwaitWriteback = !0, this._dragRequestTimer = setTimeout(this._handleDragWritebackTimeout, C));
|
|
208
|
+
}
|
|
48
209
|
connectedCallback() {
|
|
49
210
|
super.connectedCallback(), this._hasHeaderSlot = Array.from(this.children).some((e) => e.getAttribute?.("slot") === "header"), this._hasFooterSlot = Array.from(this.children).some((e) => e.getAttribute?.("slot") === "footer");
|
|
50
211
|
}
|
|
@@ -52,7 +213,7 @@ var m = [
|
|
|
52
213
|
this._checkSlotContent("footer");
|
|
53
214
|
}
|
|
54
215
|
disconnectedCallback() {
|
|
55
|
-
super.disconnectedCallback(), this._presence.dispose(), this._scrollLock.release();
|
|
216
|
+
super.disconnectedCallback(), this._nestedLayers.dispose(), this._dragGesture?.destroy(), this._dragGesture = null, this._presence.dispose(), this._scrollLock.release(), this._dragAnimation?.cancel(), this._dragAnimation = null, this._cancelDragAwait();
|
|
56
217
|
}
|
|
57
218
|
_checkSlotContent(e) {
|
|
58
219
|
let t = this.shadowRoot?.querySelector(`slot[name="${e}"]`);
|
|
@@ -69,13 +230,31 @@ var m = [
|
|
|
69
230
|
t !== this._hasFooterSlot && (this._hasFooterSlot = t, this.requestUpdate());
|
|
70
231
|
}
|
|
71
232
|
updated(e) {
|
|
72
|
-
super.updated(e), this.isConnected
|
|
233
|
+
if (super.updated(e), this.isConnected) {
|
|
234
|
+
if (e.has("open")) {
|
|
235
|
+
if (this._isDragging() && !this.open && this._cancelActiveDrag(), this._userOpenChange.consume() && this.emitOpenChange(), this._dragAwaitWriteback) {
|
|
236
|
+
this._cancelDragAwait();
|
|
237
|
+
let e = this.dialog;
|
|
238
|
+
e && !this.open ? (e.classList.remove("is-visible"), this._clearDragStyles(e)) : e && this.open && this._springRebound(e, 0, this._dragCloseDistance(e));
|
|
239
|
+
}
|
|
240
|
+
this._presence.sync(this.open), this.open ? this._nestedLayers.register() : this._nestedLayers.unregister();
|
|
241
|
+
}
|
|
242
|
+
(e.has("open") || e.has("noScrollLock")) && this._syncScrollLock();
|
|
243
|
+
}
|
|
73
244
|
}
|
|
74
245
|
handleTransitionEnd(e) {
|
|
75
246
|
this._presence.handleTransitionEnd(e);
|
|
76
247
|
}
|
|
77
248
|
handleKeydown(e) {
|
|
78
|
-
e.key
|
|
249
|
+
if (e.key !== "Escape") return;
|
|
250
|
+
let t = e.composedPath(), n = t.indexOf(e.currentTarget);
|
|
251
|
+
if (!(n > 0 && t.slice(0, n).some((e) => e instanceof HTMLDialogElement))) {
|
|
252
|
+
if (this._isDragging()) {
|
|
253
|
+
e.preventDefault();
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
e.preventDefault(), this._closeFromUser();
|
|
257
|
+
}
|
|
79
258
|
}
|
|
80
259
|
show() {
|
|
81
260
|
this.open ||= !0;
|
|
@@ -88,7 +267,11 @@ var m = [
|
|
|
88
267
|
}
|
|
89
268
|
handleNativeClose() {
|
|
90
269
|
if (this.open) {
|
|
91
|
-
if (this.
|
|
270
|
+
if (this._dragAwaitWriteback) {
|
|
271
|
+
this._cancelDragAwait();
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (this.controlled) {
|
|
92
275
|
this._presence.sync(!0), this.emitOpenChange(!1);
|
|
93
276
|
return;
|
|
94
277
|
}
|
|
@@ -96,7 +279,7 @@ var m = [
|
|
|
96
279
|
}
|
|
97
280
|
}
|
|
98
281
|
handleBackdropClick(e) {
|
|
99
|
-
e.target === e.currentTarget && (this.noBackdropClose || this._closeFromUser());
|
|
282
|
+
e.target === e.currentTarget && (this.noBackdropClose || this._isDragging() || this._closeFromUser());
|
|
100
283
|
}
|
|
101
284
|
emitOpenChange(e = this.open) {
|
|
102
285
|
this.dispatchEvent(new CustomEvent("open-change", {
|
|
@@ -109,10 +292,14 @@ var m = [
|
|
|
109
292
|
this._scrollLock.sync(e && !this.noScrollLock);
|
|
110
293
|
}
|
|
111
294
|
render() {
|
|
112
|
-
let e = this._hasHeaderSlot || !!this.heading, n = this.dialogLabel.trim(), r = !n && !this.headless && e ? "wui-drawer-heading" :
|
|
113
|
-
|
|
295
|
+
let e = this._hasHeaderSlot || !!this.heading, n = this.dialogLabel.trim(), r = !n && !this.headless && e ? "wui-drawer-heading" : g, i = this.draggable ? h`
|
|
296
|
+
<div class="wui-drawer-drag-zone" @pointerdown=${this._handleDragPointerDown}>
|
|
297
|
+
<div class="wui-drawer-drag-bar"></div>
|
|
298
|
+
</div>
|
|
299
|
+
` : g;
|
|
300
|
+
return h`
|
|
114
301
|
<dialog
|
|
115
|
-
aria-label=${n ||
|
|
302
|
+
aria-label=${n || g}
|
|
116
303
|
aria-labelledby=${r}
|
|
117
304
|
@cancel=${this.handleCancel}
|
|
118
305
|
@close=${this.handleNativeClose}
|
|
@@ -120,11 +307,11 @@ var m = [
|
|
|
120
307
|
@keydown=${this.handleKeydown}
|
|
121
308
|
@transitionend=${this.handleTransitionEnd}
|
|
122
309
|
>
|
|
123
|
-
${this.headless ?
|
|
310
|
+
${this.headless ? h`<slot></slot>${i}` : h`
|
|
124
311
|
<div class="wui-drawer-body wui-glass">
|
|
125
312
|
<div class="wui-drawer-header" id="wui-drawer-heading" ?hidden=${!e}>
|
|
126
313
|
<slot name="header" @slotchange=${this.handleHeaderSlotChange}>
|
|
127
|
-
${this.heading ?
|
|
314
|
+
${this.heading ? h`<span class="wui-drawer-heading">${this.heading}</span>` : g}
|
|
128
315
|
</slot>
|
|
129
316
|
</div>
|
|
130
317
|
<div class="wui-drawer-content">
|
|
@@ -134,7 +321,7 @@ var m = [
|
|
|
134
321
|
<slot name="footer" @slotchange=${this.handleFooterSlotChange}></slot>
|
|
135
322
|
</div>
|
|
136
323
|
</div>
|
|
137
|
-
${this.closable ?
|
|
324
|
+
${this.closable ? h`
|
|
138
325
|
<web-ui-button
|
|
139
326
|
class="wui-drawer-close"
|
|
140
327
|
@click=${this._closeFromUser}
|
|
@@ -143,43 +330,46 @@ var m = [
|
|
|
143
330
|
icon
|
|
144
331
|
size="26"
|
|
145
332
|
>
|
|
146
|
-
<web-ui-icon .icon=${t}></web-ui-icon>
|
|
333
|
+
<web-ui-icon size="14" .icon=${t}></web-ui-icon>
|
|
147
334
|
</web-ui-button>
|
|
148
|
-
` :
|
|
335
|
+
` : g}
|
|
336
|
+
${i}
|
|
149
337
|
`}
|
|
150
338
|
</dialog>
|
|
151
339
|
`;
|
|
152
340
|
}
|
|
153
341
|
};
|
|
154
|
-
e([
|
|
342
|
+
e([y({
|
|
155
343
|
type: Boolean,
|
|
156
344
|
reflect: !0
|
|
157
|
-
})],
|
|
345
|
+
})], T.prototype, "open", void 0), e([y({
|
|
158
346
|
type: Boolean,
|
|
159
347
|
reflect: !0,
|
|
160
348
|
attribute: "no-scroll-lock"
|
|
161
|
-
})],
|
|
349
|
+
})], T.prototype, "noScrollLock", void 0), e([y({
|
|
162
350
|
type: Boolean,
|
|
163
351
|
reflect: !0,
|
|
164
352
|
attribute: "no-backdrop-close"
|
|
165
|
-
})],
|
|
353
|
+
})], T.prototype, "noBackdropClose", void 0), e([y({
|
|
166
354
|
type: Boolean,
|
|
167
|
-
reflect: !0
|
|
168
|
-
|
|
169
|
-
})], h.prototype, "requestOnly", void 0), e([p({
|
|
355
|
+
reflect: !0
|
|
356
|
+
})], T.prototype, "controlled", void 0), e([y({
|
|
170
357
|
type: String,
|
|
171
358
|
reflect: !0
|
|
172
|
-
})],
|
|
359
|
+
})], T.prototype, "placement", null), e([y({ type: String })], T.prototype, "heading", void 0), e([y({
|
|
173
360
|
type: Boolean,
|
|
174
361
|
reflect: !0
|
|
175
|
-
})],
|
|
362
|
+
})], T.prototype, "closable", void 0), e([y({
|
|
176
363
|
type: Boolean,
|
|
177
364
|
reflect: !0
|
|
178
|
-
})],
|
|
365
|
+
})], T.prototype, "headless", void 0), e([y({
|
|
179
366
|
type: String,
|
|
180
367
|
attribute: "dialog-label"
|
|
181
|
-
})],
|
|
368
|
+
})], T.prototype, "dialogLabel", void 0), e([y({
|
|
369
|
+
type: Boolean,
|
|
370
|
+
reflect: !0
|
|
371
|
+
})], T.prototype, "draggable", void 0), T = e([v("web-ui-drawer")], T);
|
|
182
372
|
//#endregion
|
|
183
|
-
export {
|
|
373
|
+
export { T as WebUiDrawer };
|
|
184
374
|
|
|
185
375
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/drawer/index.ts"],"sourcesContent":["import { html, LitElement, nothing, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport '@/components/icon'\nimport '@/components/button'\nimport glass from '@/assets/glass.css?inline'\nimport { oouiClose } from '@/icons'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { normalizeLiteral } from '@/shared/normalize'\nimport { defineNativeDialogPresence } from '@/shared/overlay/native-dialog-presence'\nimport { defineScrollLockLease } from '@/shared/scroll-lock/scroll-lock'\n\nimport style from './style.css?inline'\n\nconst ALLOWED_PLACEMENTS = ['right', 'left', 'top', 'bottom'] as const\n\nexport type DrawerPlacement = (typeof ALLOWED_PLACEMENTS)[number]\n\n@customElement('web-ui-drawer')\nexport class WebUiDrawer extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true, attribute: 'no-scroll-lock' }) noScrollLock = false\n @property({ type: Boolean, reflect: true, attribute: 'no-backdrop-close' }) noBackdropClose = false\n\n /**\n * request-only 模式下,Escape、遮罩和关闭按钮只派发 `open-change` 请求,\n * 不会自行修改 `open`。Consumer 回写 `open` 后才执行关闭动画。\n */\n @property({ type: Boolean, reflect: true, attribute: 'request-only' }) requestOnly = false\n\n @property({ type: String, reflect: true })\n get placement(): DrawerPlacement {\n return this._placement\n }\n set placement(v: string) {\n const old = this._placement\n this._placement = normalizeLiteral(v, ALLOWED_PLACEMENTS, 'right')\n this.requestUpdate('placement', old)\n }\n private _placement: DrawerPlacement = 'right'\n\n // 标题文字(未传 header slot 时显示默认 header)\n @property({ type: String }) heading = ''\n\n @property({ type: Boolean, reflect: true }) closable = false\n\n /**\n * Headless 模式:只保留 overlay 基础设施(backdrop、动画、scroll lock、dialog 语义),\n * 移除内置 UI(glass 样式、header、close 按钮、footer)。Consumer 自定义内容样式。\n */\n @property({ type: Boolean, reflect: true }) headless = false\n\n /**\n * 内部原生 dialog 的 accessible name。headless 模式必须由 Consumer 提供,\n * 因为该模式不会渲染可自动关联的内置 header。\n */\n @property({ type: String, attribute: 'dialog-label' }) dialogLabel = ''\n\n private get dialog() {\n return this.shadowRoot?.querySelector('dialog') ?? null\n }\n\n private _hasHeaderSlot = false\n private _hasFooterSlot = false\n private readonly _userOpenChange = new UserChangeController()\n private readonly _scrollLock = defineScrollLockLease().make()\n private readonly _presence = defineNativeDialogPresence().make({\n getDialog: () => this.dialog,\n isConnected: () => this.isConnected,\n isOpen: () => this.open\n })\n\n override connectedCallback() {\n super.connectedCallback()\n this._hasHeaderSlot = Array.from(this.children).some(child => child.getAttribute?.('slot') === 'header')\n this._hasFooterSlot = Array.from(this.children).some(child => child.getAttribute?.('slot') === 'footer')\n }\n\n override firstUpdated() {\n this._checkSlotContent('footer')\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._presence.dispose()\n this._scrollLock.release()\n }\n\n private _checkSlotContent(name: string) {\n const slot = this.shadowRoot?.querySelector(`slot[name=\"${name}\"]`) as HTMLSlotElement | null\n if (!slot) return\n const has = slot.assignedNodes().length > 0\n if (name === 'footer' && has !== this._hasFooterSlot) {\n this._hasFooterSlot = has\n this.requestUpdate()\n }\n }\n\n private handleHeaderSlotChange(e: Event) {\n const has = (e.target as HTMLSlotElement).assignedNodes().length > 0\n if (has !== this._hasHeaderSlot) {\n this._hasHeaderSlot = has\n this.requestUpdate()\n }\n }\n\n private handleFooterSlotChange(e: Event) {\n const has = (e.target as HTMLSlotElement).assignedNodes().length > 0\n if (has !== this._hasFooterSlot) {\n this._hasFooterSlot = has\n this.requestUpdate()\n }\n }\n\n protected override updated(props: PropertyValues) {\n super.updated(props)\n if (!this.isConnected) return\n\n if (props.has('open')) {\n if (this._userOpenChange.consume()) this.emitOpenChange()\n this._presence.sync(this.open)\n }\n if (props.has('open') || props.has('noScrollLock')) this._syncScrollLock()\n }\n\n private handleTransitionEnd(e: TransitionEvent) {\n this._presence.handleTransitionEnd(e)\n }\n\n private handleKeydown(e: KeyboardEvent) {\n if (e.key !== 'Escape') return\n e.preventDefault()\n this._closeFromUser()\n }\n\n // 打开抽屉(命令式)\n show() {\n if (this.open) return\n this.open = true\n }\n\n // 关闭抽屉(带动画)\n close() {\n if (!this.open) return\n this.open = false\n }\n\n private readonly _closeFromUser = () => {\n if (!this.open) return\n if (this.requestOnly) {\n this.emitOpenChange(false)\n return\n }\n\n this._userOpenChange.mark()\n this.close()\n }\n\n private handleCancel(e: Event) {\n // 保留 top layer 直到 CSS 过渡结束,避免原生关闭跳过退出动画。\n e.preventDefault()\n this._closeFromUser()\n }\n\n private handleNativeClose() {\n if (!this.open) return\n\n // 原生关闭可绕过 cancel;request-only 时恢复受控状态,由 Consumer 决定是否关闭。\n if (this.requestOnly) {\n this._presence.sync(true)\n this.emitOpenChange(false)\n return\n }\n\n this._presence.handleNativeClose()\n this._userOpenChange.mark()\n this.open = false\n }\n\n private handleBackdropClick(e: MouseEvent) {\n if (e.target !== (e.currentTarget as HTMLDialogElement)) return\n if (this.noBackdropClose) return\n this._closeFromUser()\n }\n\n private emitOpenChange(open = this.open) {\n this.dispatchEvent(\n new CustomEvent('open-change', {\n detail: { open },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private _syncScrollLock(isOpen = this.open) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\n }\n\n override render() {\n const showHeader = this._hasHeaderSlot || !!this.heading\n const dialogLabel = this.dialogLabel.trim()\n const dialogLabelledBy = !dialogLabel && !this.headless && showHeader ? 'wui-drawer-heading' : nothing\n\n // 保持同一个 dialog 实例,避免打开期间切换 headless 时脱离 top layer。\n return html`\n <dialog\n aria-label=${dialogLabel || nothing}\n aria-labelledby=${dialogLabelledBy}\n @cancel=${this.handleCancel}\n @close=${this.handleNativeClose}\n @click=${this.handleBackdropClick}\n @keydown=${this.handleKeydown}\n @transitionend=${this.handleTransitionEnd}\n >\n ${\n this.headless\n ? html`<slot></slot>`\n : html`\n <div class=\"wui-drawer-body wui-glass\">\n <div class=\"wui-drawer-header\" id=\"wui-drawer-heading\" ?hidden=${!showHeader}>\n <slot name=\"header\" @slotchange=${this.handleHeaderSlotChange}>\n ${this.heading ? html`<span class=\"wui-drawer-heading\">${this.heading}</span>` : nothing}\n </slot>\n </div>\n <div class=\"wui-drawer-content\">\n <slot></slot>\n </div>\n <div class=\"wui-drawer-footer\" ?hidden=${!this._hasFooterSlot}>\n <slot name=\"footer\" @slotchange=${this.handleFooterSlotChange}></slot>\n </div>\n </div>\n ${\n this.closable\n ? html`\n <web-ui-button\n class=\"wui-drawer-close\"\n @click=${this._closeFromUser}\n aria-label=\"关闭\"\n variant=\"secondary\"\n icon\n size=\"26\"\n >\n <web-ui-icon .icon=${oouiClose}></web-ui-icon>\n </web-ui-button>\n `\n : nothing\n }\n `\n }\n </dialog>\n `\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-drawer': WebUiDrawer\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/drawer/index.ts"],"sourcesContent":["import { html, LitElement, nothing, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport '@/components/icon'\nimport '@/components/button'\nimport glass from '@/assets/glass.css?inline'\nimport { oouiClose } from '@/icons'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { attachDragGesture, type DragGestureHandle, rubberband, SPRING_PRESETS, springOffsets } from '@/shared/gesture'\nimport { normalizeLiteral } from '@/shared/normalize'\nimport { defineNativeDialogPresence } from '@/shared/overlay/native-dialog-presence'\nimport { defineNestedDrawerLayers } from '@/shared/overlay/nested-drawer-layers'\nimport { defineScrollLockLease } from '@/shared/scroll-lock/scroll-lock'\nimport { findNearestTheme } from '@/shared/theme/theme-scope'\n\nimport style from './style.css?inline'\n\nconst ALLOWED_PLACEMENTS = ['right', 'left', 'top', 'bottom'] as const\n\nexport type DrawerPlacement = (typeof ALLOWED_PLACEMENTS)[number]\n\n// 拖拽关闭判定:位移超过抽屉尺寸 1/3,或闭合方向甩动速度超过 500px/s 视为关闭意图。\nconst DRAG_CLOSE_RATIO = 1 / 3\nconst DRAG_FLICK_VELOCITY = 500\nconst DRAG_REQUEST_WINDOW_MS = 120\nconst SPRING_SAMPLE_MS = 16\n\n/*\n * 拖拽期间由 JS 写入的遮罩透明度变量参与 WAAPI 关键帧。未注册的自定义属性在\n * 关键帧之间是离散插值(半帧跳变),注册为 <number> 后获得线性插值。\n * inherits 必须为 true:::backdrop 只从 originating element 继承「可继承属性」,\n * 注册为不可继承会让变量到不了遮罩,跟手淡出整体失效(Chrome 151 实证)。\n * 注册表是全局的,模块重复执行(HMR)时捕获已注册错误并忽略。\n */\nif (typeof CSS !== 'undefined' && 'registerProperty' in CSS) {\n try {\n CSS.registerProperty({\n name: '--wui-internal-drag-backdrop-opacity',\n syntax: '<number>',\n inherits: true,\n initialValue: '1'\n })\n } catch {\n // 已注册(如 HMR 重复执行)时忽略\n }\n /*\n * 公开 token 注册为 <length>:Consumer 传 unitless 0 时计算值被归一为 0px,\n * 避免 calc(100% + 0) 因 number/percentage 不兼容而使闭合位移失效。\n */\n try {\n CSS.registerProperty({\n name: '--wui-drawer-inset',\n syntax: '<length>',\n inherits: true,\n initialValue: '8px'\n })\n } catch {\n // 已注册(如 HMR 重复执行)时忽略\n }\n}\n\n@customElement('web-ui-drawer')\nexport class WebUiDrawer extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true, attribute: 'no-scroll-lock' }) noScrollLock = false\n @property({ type: Boolean, reflect: true, attribute: 'no-backdrop-close' }) noBackdropClose = false\n\n /**\n * Controlled 模式下,Escape、遮罩、关闭按钮和拖拽关闭只派发 `open-change` 请求,\n * 不会自行修改 `open`。Consumer 回写 `open` 后才执行关闭动画。\n * 程序化 API(show/close/直接赋值 open)不受此模式影响,始终直通。\n */\n @property({ type: Boolean, reflect: true }) controlled = false\n\n @property({ type: String, reflect: true })\n get placement(): DrawerPlacement {\n return this._placement\n }\n set placement(v: string) {\n const old = this._placement\n this._placement = normalizeLiteral(v, ALLOWED_PLACEMENTS, 'right')\n this.requestUpdate('placement', old)\n }\n private _placement: DrawerPlacement = 'right'\n\n // 标题文字(未传 header slot 时显示默认 header)\n @property({ type: String }) heading = ''\n\n @property({ type: Boolean, reflect: true }) closable = false\n\n /**\n * Headless 模式:只保留 overlay 基础设施(backdrop、动画、scroll lock、dialog 语义),\n * 移除内置 UI(glass 样式、header、close 按钮、footer)。Consumer 自定义内容样式。\n */\n @property({ type: Boolean, reflect: true }) headless = false\n\n /**\n * 内部原生 dialog 的 accessible name。headless 模式必须由 Consumer 提供,\n * 因为该模式不会渲染可自动关联的内置 header。\n */\n @property({ type: String, attribute: 'dialog-label' }) dialogLabel = ''\n\n /**\n * 启用拖拽关闭:打开态在抽屉内缘渲染 drag bar(灰色胶囊 + 加宽热区),\n * 指针拖拽实时跟手,松手按位移与甩动速度判定关闭或弹回。\n * 关闭态基于原生 dialog 无可见渲染物,因此不支持从关闭态拖拽打开。\n */\n @property({ type: Boolean, reflect: true }) override draggable = false\n\n private get dialog() {\n return this.shadowRoot?.querySelector('dialog') ?? null\n }\n\n private _hasHeaderSlot = false\n private _hasFooterSlot = false\n private readonly _userOpenChange = new UserChangeController()\n private readonly _scrollLock = defineScrollLockLease().make()\n private readonly _presence = defineNativeDialogPresence().make({\n getDialog: () => this.dialog,\n isConnected: () => this.isConnected,\n isOpen: () => this.open\n })\n // nested 层序:打开后纳入全局栈,上层打开/关闭时本层缩放平移(对齐 Base UI)。\n private readonly _nestedLayers = defineNestedDrawerLayers().make({\n getDialog: () => this.dialog,\n getPlacement: () => this._placement\n })\n\n // ===== 拖拽关闭手势状态 =====\n private _dragGesture: DragGestureHandle | null = null\n // pointerdown 时刻已存在的闭合方向位移(从弹回动画中抓取时非 0)。\n private _dragInitialOffset = 0\n private _dragOffset = 0\n private _dragAnimation: Animation | null = null\n // controlled:弹簧到闭合位后等待 Consumer 回写 open;超时未回写则弹回。\n private _dragAwaitWriteback = false\n private _dragRequestTimer: ReturnType<typeof setTimeout> | undefined\n\n // placement 的闭合轴向:right/left 沿 X 轴,top/bottom 沿 Y 轴。\n private get _dragAxis(): 'x' | 'y' {\n return this._placement === 'left' || this._placement === 'right' ? 'x' : 'y'\n }\n\n // 位移正方向 = 抽屉的闭合方向(拖出屏幕为正)。\n private get _dragCloseSign(): number {\n switch (this._placement) {\n case 'right':\n return 1\n case 'left':\n return -1\n case 'top':\n return -1\n case 'bottom':\n return 1\n }\n }\n\n private _measureDragSize(): number {\n const dialog = this.dialog\n if (!dialog) return 0\n return this._dragAxis === 'x' ? dialog.offsetWidth : dialog.offsetHeight\n }\n\n // 浮动卡片(非 headless)的四周留边;闭合位移需越过它才能完全滑出视口。\n // headless 在 :host([headless]) dialog 上显式归零(防嵌套继承),解析失败回退 0。\n private _readDrawerInset(dialog: HTMLDialogElement): number {\n const raw = getComputedStyle(dialog).getPropertyValue('--wui-internal-drawer-inset')\n const parsed = Number.parseFloat(raw)\n return Number.isFinite(parsed) ? parsed : 0\n }\n\n // 闭合方向上的完全出屏距离:抽屉尺寸 + 浮动留边(headless 下即尺寸本身)。\n // CSS 闭合态 transform、controlled 悬停终态与弹簧终点共用同一数学,避免衔接跳变。\n private _dragCloseDistance(dialog: HTMLDialogElement): number {\n return this._measureDragSize() + this._readDrawerInset(dialog)\n }\n\n private _isReducedMotion(): boolean {\n // 优先尊重所在 web-ui-theme 的 motion 设置(与 svg-draw-lines 一致);\n // 无主题范围时回退到系统 prefers-reduced-motion。jsdom 等环境无 matchMedia,视为完整动效。\n const theme = findNearestTheme(this)\n if (theme) return theme.isReducedMotion()\n try {\n return typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches\n } catch {\n return false\n }\n }\n\n private _isDragging(): boolean {\n return this._dragGesture?.isDragging() ?? false\n }\n\n private _cancelDragAwait() {\n if (this._dragRequestTimer !== undefined) {\n clearTimeout(this._dragRequestTimer)\n this._dragRequestTimer = undefined\n }\n this._dragAwaitWriteback = false\n }\n\n private _handleDragPointerDown(e: PointerEvent) {\n if (!this.open || !this.draggable || this._isDragging()) return\n // 多点触控的副指针(isPrimary 明确为 false)不参与手势。\n if (e.isPrimary === false) return\n\n const dialog = this.dialog\n if (!dialog) return\n // is-visible 由 presence 在 showModal 后一帧加上;就位前(打开极早期)忽略。\n // 就位后即使 enter 过渡仍在进行也允许抓取,起始位移从当前计算值续接。\n if (!dialog.classList.contains('is-visible')) return\n\n // 先读取动画中的当前位移再取消弹回动画,避免取消后回跳到内联样式值。\n const currentTransform = getComputedStyle(dialog).transform\n const axisValue =\n currentTransform && currentTransform !== 'none' && typeof DOMMatrixReadOnly === 'function'\n ? new DOMMatrixReadOnly(currentTransform)[this._dragAxis === 'x' ? 'm41' : 'm42']\n : 0\n this._dragAnimation?.cancel()\n this._dragAnimation = null\n this._cancelDragAwait()\n\n this._dragInitialOffset = axisValue * this._dragCloseSign\n this._dragOffset = this._dragInitialOffset\n dialog.classList.add('is-dragging')\n\n this._dragGesture = attachDragGesture(e, {\n axis: this._dragAxis,\n onMove: info => {\n const pointerDelta = this._dragAxis === 'x' ? info.deltaX : info.deltaY\n // 闭合方向全额跟随;开启方向施加阻尼(橡皮筋),最多回弹 10% 抽屉尺寸。\n const raw = this._dragInitialOffset + pointerDelta * this._dragCloseSign\n this._dragOffset = rubberband(raw, this._measureDragSize() * 0.1, 0.15)\n\n // 达到关闭阈值时胶囊变 accent 色作视觉确认(ADR-0035)。\n const dragSize = this._measureDragSize()\n dialog.classList.toggle('is-drag-close', dragSize > 0 && this._dragOffset > dragSize * DRAG_CLOSE_RATIO)\n this._applyDragOffset(dialog, this._dragOffset)\n },\n onEnd: info => {\n this._dragGesture = null\n dialog.classList.remove('is-dragging', 'is-drag-close')\n const size = this._measureDragSize()\n const velocity = (this._dragAxis === 'x' ? info.velocityX : info.velocityY) * this._dragCloseSign\n const shouldClose =\n this._dragOffset > size * DRAG_CLOSE_RATIO || (this._dragOffset > 8 && velocity > DRAG_FLICK_VELOCITY)\n\n if (shouldClose) this._springToClose(dialog, velocity)\n else this._springRebound(dialog, velocity, this._dragOffset)\n },\n onCancel: () => {\n this._dragGesture = null\n dialog.classList.remove('is-dragging', 'is-drag-close')\n this._springRebound(dialog, 0, this._dragOffset)\n }\n })\n }\n\n // 受控状态写入等外部原因强制终结拖拽:清手势状态与拖拽样式,不弹回,\n // 后续管线(关闭/打开)由调用方继续执行。\n private _cancelActiveDrag() {\n if (!this._isDragging()) return\n this._dragGesture?.destroy()\n this._dragGesture = null\n const dialog = this.dialog\n if (!dialog) return\n dialog.classList.remove('is-dragging', 'is-drag-close')\n this._clearDragStyles(dialog)\n }\n\n // 将闭合方向位移映射为 dialog transform,并同步遮罩透明度保持跟手反馈。\n private _applyDragOffset(dialog: HTMLDialogElement, offset: number) {\n const sign = this._dragCloseSign\n const value = offset * sign\n dialog.style.transform = this._dragAxis === 'x' ? `translateX(${value}px)` : `translateY(${value}px)`\n const size = this._measureDragSize()\n const progress = size > 0 ? Math.min(1, Math.max(0, offset / size)) : 0\n dialog.style.setProperty('--wui-internal-drag-backdrop-opacity', String(1 - progress))\n }\n\n private _clearDragStyles(dialog: HTMLDialogElement) {\n dialog.style.removeProperty('transform')\n dialog.style.removeProperty('--wui-internal-drag-backdrop-opacity')\n }\n\n // 弹簧到完全闭合;controlled 下保持闭合位等待回写,其余走常规关闭管线。\n private _springToClose(dialog: HTMLDialogElement, velocity: number) {\n const from = this._dragOffset\n this._dragOffset = 0\n const sign = this._dragCloseSign\n // 弹簧终点 = 完全出屏距离(含浮动留边),与 CSS 闭合态/悬停终态一致,\n // 否则 onfinish 后会有一个留边宽度的瞬移。\n const to = this._dragCloseDistance(dialog)\n const size = this._measureDragSize()\n\n const finishClose = () => {\n if (this.controlled) {\n // 保持在闭合位(is-visible 未移除,状态仍 open),等待 Consumer 回写或超时弹回。\n const distance = to\n dialog.style.transform =\n this._dragAxis === 'x' ? `translateX(${distance * sign}px)` : `translateY(${distance * sign}px)`\n dialog.style.setProperty('--wui-internal-drag-backdrop-opacity', '0')\n } else {\n // 移除 is-visible 后基础 transform 即闭合位,清内联样式不产生跳变;\n // presence.sync(false) 检测不到 is-visible 会立即完成关闭,不重播退出动画。\n dialog.classList.remove('is-visible')\n this._clearDragStyles(dialog)\n }\n this._closeFromDrag()\n }\n\n if (this._isReducedMotion() || typeof dialog.animate !== 'function') {\n finishClose()\n return\n }\n\n const samples = springOffsets(from, to, velocity, SPRING_PRESETS.close)\n const keyframes = samples.map(o => ({\n transform: this._dragAxis === 'x' ? `translateX(${o * sign}px)` : `translateY(${o * sign}px)`,\n '--wui-internal-drag-backdrop-opacity': String(Math.max(0, 1 - o / size))\n }))\n // 采样帧含首值与附加终点,实际时长为帧间隔数 × 采样周期。\n const duration = (samples.length - 1) * SPRING_SAMPLE_MS\n // fill:'both' 与 _springRebound 对称:堵住 finish→onfinish 清理窗口,\n // 防止该窗口内绘制的帧暴露内联位移、随清理触发跳变。\n const animation = dialog.animate(keyframes, { duration, easing: 'linear', fill: 'both' })\n // onfinish 同步应用终态并取消动画:fill 会持续覆盖 transform,阻断后续 CSS 过渡。\n animation.onfinish = () => {\n animation.cancel()\n finishClose()\n }\n }\n\n // 弹回打开:从 from 位移弹回 0;结束后清内联样式交还 CSS transition 管辖。\n private _springRebound(dialog: HTMLDialogElement, velocity: number, from: number) {\n this._dragOffset = 0\n\n const finishRebound = () => {\n this._dragAnimation = null\n dialog.classList.remove('is-dragging')\n this._clearDragStyles(dialog)\n }\n\n if (this._isReducedMotion() || typeof dialog.animate !== 'function' || Math.abs(from) < 1) {\n finishRebound()\n return\n }\n\n const sign = this._dragCloseSign\n const size = this._measureDragSize()\n const samples = springOffsets(from, 0, velocity, SPRING_PRESETS.rebound)\n const keyframes = samples.map(o => ({\n transform: this._dragAxis === 'x' ? `translateX(${o * sign}px)` : `translateY(${o * sign}px)`,\n '--wui-internal-drag-backdrop-opacity': String(Math.max(0, 1 - o / size))\n }))\n // 弹回期间抑制 transform/backdrop 的 CSS transition,避免与弹簧动画叠加。\n dialog.classList.add('is-dragging')\n const duration = (samples.length - 1) * SPRING_SAMPLE_MS\n // fill:'both' 堵住 finish→onfinish 清理之间的竞态窗口:无 fill 时动画结束即\n // 失效,窗口内被绘制的帧会暴露内联拖拽位移,随后的清理再触发 CSS 过渡滑回\n // 打开位 —— 表现为回弹后又多弹一次。\n const animation = dialog.animate(keyframes, { duration, easing: 'linear', fill: 'both' })\n // onfinish 同步清除内联样式并取消动画:fill 会持续覆盖 transform,阻断后续 CSS 过渡。\n animation.onfinish = () => {\n animation.cancel()\n finishRebound()\n }\n this._dragAnimation = animation\n }\n\n private _closeFromDrag() {\n // 先派发关闭请求(_closeFromUser),再进入悬停等待:等待态中 _closeFromUser\n // 会被 L2 去重守卫短路,顺序颠倒会吞掉首次请求。\n this._closeFromUser()\n if (this.controlled) {\n this._dragAwaitWriteback = true\n this._dragRequestTimer = setTimeout(this._handleDragWritebackTimeout, DRAG_REQUEST_WINDOW_MS)\n }\n }\n\n // controlled 回写窗口超时:Consumer 拒绝关闭,从闭合位弹回打开位。\n private readonly _handleDragWritebackTimeout = () => {\n this._dragRequestTimer = undefined\n if (!this._dragAwaitWriteback || !this.open || this._isDragging()) {\n this._dragAwaitWriteback = false\n return\n }\n this._dragAwaitWriteback = false\n\n const dialog = this.dialog\n if (!dialog) return\n dialog.classList.add('is-visible')\n // 悬停终态位于完全出屏位(含留边),弹回也从该真实位置起步,避免首帧内跳。\n this._springRebound(dialog, 0, this._dragCloseDistance(dialog))\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._hasHeaderSlot = Array.from(this.children).some(child => child.getAttribute?.('slot') === 'header')\n this._hasFooterSlot = Array.from(this.children).some(child => child.getAttribute?.('slot') === 'footer')\n }\n\n override firstUpdated() {\n this._checkSlotContent('footer')\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._nestedLayers.dispose()\n this._dragGesture?.destroy()\n this._dragGesture = null\n this._presence.dispose()\n this._scrollLock.release()\n this._dragAnimation?.cancel()\n this._dragAnimation = null\n this._cancelDragAwait()\n }\n\n private _checkSlotContent(name: string) {\n const slot = this.shadowRoot?.querySelector(`slot[name=\"${name}\"]`) as HTMLSlotElement | null\n if (!slot) return\n const has = slot.assignedNodes().length > 0\n if (name === 'footer' && has !== this._hasFooterSlot) {\n this._hasFooterSlot = has\n this.requestUpdate()\n }\n }\n\n private handleHeaderSlotChange(e: Event) {\n const has = (e.target as HTMLSlotElement).assignedNodes().length > 0\n if (has !== this._hasHeaderSlot) {\n this._hasHeaderSlot = has\n this.requestUpdate()\n }\n }\n\n private handleFooterSlotChange(e: Event) {\n const has = (e.target as HTMLSlotElement).assignedNodes().length > 0\n if (has !== this._hasFooterSlot) {\n this._hasFooterSlot = has\n this.requestUpdate()\n }\n }\n\n protected override updated(props: PropertyValues) {\n super.updated(props)\n if (!this.isConnected) return\n\n if (props.has('open')) {\n // Consumer 在拖拽进行中写入受控 open:受控状态优先,立即终结手势(等同\n // pointercancel 的清理但不弹回),交由下方 presence 走标准关闭/打开管线。\n if (this._isDragging() && !this.open) this._cancelActiveDrag()\n if (this._userOpenChange.consume()) this.emitOpenChange()\n // controlled 拖拽关闭的回写结果:确认关闭则清除闭合位悬停状态走正常关闭;\n // 拒绝关闭(回写 open=true)则从闭合位(含留边)弹回。\n if (this._dragAwaitWriteback) {\n this._cancelDragAwait()\n const dialog = this.dialog\n if (dialog && !this.open) {\n dialog.classList.remove('is-visible')\n this._clearDragStyles(dialog)\n } else if (dialog && this.open) {\n this._springRebound(dialog, 0, this._dragCloseDistance(dialog))\n }\n }\n this._presence.sync(this.open)\n if (this.open) {\n // presence.sync 已同步发起 showModal:此刻 dialog.open 为真,计数出正确\n // 的层序 depth 并驱动下层缩放。直接同步 register,不等待 is-visible\n //(那要再等一帧,且打开过渡期间上层关系已应确立)。\n this._nestedLayers.register()\n } else {\n this._nestedLayers.unregister()\n }\n }\n if (props.has('open') || props.has('noScrollLock')) this._syncScrollLock()\n }\n\n private handleTransitionEnd(e: TransitionEvent) {\n this._presence.handleTransitionEnd(e)\n }\n\n private handleKeydown(e: KeyboardEvent) {\n if (e.key !== 'Escape') return\n /*\n * nested 场景防连锁:子 drawer 的 dialog 经 slot 投影在本层 shadow 内,其\n * keydown composed 冒泡路径会再次经过本层 dialog(事件路径含 slot 宿主链)。\n * 若事件传播路径在本层 dialog 之前已存在其他 <dialog>,说明该事件来自子层,本层忽略。\n */\n const path = e.composedPath()\n const ownDialogIndex = path.indexOf(e.currentTarget as Node)\n if (ownDialogIndex > 0) {\n const hasChildDialog = path.slice(0, ownDialogIndex).some(n => n instanceof HTMLDialogElement)\n if (hasChildDialog) return\n }\n // 拖拽进行中忽略 ESC,避免手势与关闭管线竞争。\n if (this._isDragging()) {\n e.preventDefault()\n return\n }\n e.preventDefault()\n this._closeFromUser()\n }\n\n show() {\n if (this.open) return\n this.open = true\n }\n\n close() {\n if (!this.open) return\n this.open = false\n }\n\n private readonly _closeFromUser = () => {\n if (!this.open) return\n // controlled 悬停等待回写期间,关闭意图已在途(open-change 已派发):\n // Escape/遮罩/关闭按钮的重复触发不再派发第二次请求,也不与超时弹回竞争。\n if (this._dragAwaitWriteback) return\n if (this.controlled) {\n this.emitOpenChange(false)\n return\n }\n\n this._userOpenChange.mark()\n this.close()\n }\n\n private handleCancel(e: Event) {\n // 保留 top layer 直到 CSS 过渡结束,避免原生关闭跳过退出动画。\n e.preventDefault()\n this._closeFromUser()\n }\n\n private handleNativeClose() {\n if (!this.open) return\n\n // 悬停等待期间的原生关闭(如表单 method=\"dialog\"):视为回写窗口内的重复\n // 关闭意图,取消等待不补发请求;已原生关闭的 dialog 不再被超时弹回拉起。\n if (this._dragAwaitWriteback) {\n this._cancelDragAwait()\n return\n }\n\n // 原生关闭可绕过 cancel;controlled 时恢复受控状态,由 Consumer 决定是否关闭。\n if (this.controlled) {\n this._presence.sync(true)\n this.emitOpenChange(false)\n return\n }\n\n this._presence.handleNativeClose()\n this._userOpenChange.mark()\n this.open = false\n }\n\n private handleBackdropClick(e: MouseEvent) {\n if (e.target !== (e.currentTarget as HTMLDialogElement)) return\n if (this.noBackdropClose) return\n // 拖拽进行中 pointer capture 使 click 落在 dialog 上,忽略以避免与手势竞争。\n if (this._isDragging()) return\n this._closeFromUser()\n }\n\n private emitOpenChange(open = this.open) {\n this.dispatchEvent(\n new CustomEvent('open-change', {\n detail: { open },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private _syncScrollLock(isOpen = this.open) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\n }\n\n override render() {\n const showHeader = this._hasHeaderSlot || !!this.heading\n const dialogLabel = this.dialogLabel.trim()\n const dialogLabelledBy = !dialogLabel && !this.headless && showHeader ? 'wui-drawer-heading' : nothing\n\n // 拖拽热区:仅在打开且 draggable 时渲染;胶囊 + 加宽命中条贴在抽屉内缘。\n const dragBar = this.draggable\n ? html`\n <div class=\"wui-drawer-drag-zone\" @pointerdown=${this._handleDragPointerDown}>\n <div class=\"wui-drawer-drag-bar\"></div>\n </div>\n `\n : nothing\n\n // 保持同一个 dialog 实例,避免打开期间切换 headless 时脱离 top layer。\n return html`\n <dialog\n aria-label=${dialogLabel || nothing}\n aria-labelledby=${dialogLabelledBy}\n @cancel=${this.handleCancel}\n @close=${this.handleNativeClose}\n @click=${this.handleBackdropClick}\n @keydown=${this.handleKeydown}\n @transitionend=${this.handleTransitionEnd}\n >\n ${\n this.headless\n ? html`<slot></slot>${dragBar}`\n : html`\n <div class=\"wui-drawer-body wui-glass\">\n <div class=\"wui-drawer-header\" id=\"wui-drawer-heading\" ?hidden=${!showHeader}>\n <slot name=\"header\" @slotchange=${this.handleHeaderSlotChange}>\n ${this.heading ? html`<span class=\"wui-drawer-heading\">${this.heading}</span>` : nothing}\n </slot>\n </div>\n <div class=\"wui-drawer-content\">\n <slot></slot>\n </div>\n <div class=\"wui-drawer-footer\" ?hidden=${!this._hasFooterSlot}>\n <slot name=\"footer\" @slotchange=${this.handleFooterSlotChange}></slot>\n </div>\n </div>\n ${\n this.closable\n ? html`\n <web-ui-button\n class=\"wui-drawer-close\"\n @click=${this._closeFromUser}\n aria-label=\"关闭\"\n variant=\"secondary\"\n icon\n size=\"26\"\n >\n <web-ui-icon size=\"14\" .icon=${oouiClose}></web-ui-icon>\n </web-ui-button>\n `\n : nothing\n }\n ${dragBar}\n `\n }\n </dialog>\n `\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-drawer': WebUiDrawer\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/components/drawer/style.css?inline
|
|
2
|
-
var e = "*,:before,:after{box-sizing:border-box}:host{display:contents}dialog{box-sizing:border-box;width:var(--wui-drawer-width,320px);max-width:90vw;height:100dvh;max-height:100dvh;color:var(--wui-color-text,#1b1b1b);transition:transform var(--wui-duration-drawer-enter,.28s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1));background:0 0;border:none;margin:0;padding:0;font-family:inherit;inset:0 0 0 auto;overflow:visible;transform:translate(100%)}dialog::backdrop{opacity:0;background:var(--wui-drawer-overlay-bg,var(--wui-color-backdrop,#0000001f));transition:opacity var(--wui-duration-drawer-enter,.28s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1))}dialog[open].is-visible,:host([placement=left]) dialog[open].is-visible,:host([placement=top]) dialog[open].is-visible,:host([placement=bottom]) dialog[open].is-visible{transform:translate(0)}dialog.is-closing{pointer-events:none;transition:transform var(--wui-duration-drawer-exit,.24s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1))}dialog.is-closing::backdrop{transition:opacity var(--wui-duration-drawer-exit,.24s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1))}dialog[open].is-visible::backdrop{opacity:1}:host([placement=left]) dialog{left:0;right:auto;transform:translate(-100%)}:host([placement=top]) dialog,:host([placement=bottom]) dialog{width:100vw;max-width:100vw;height:var(--wui-drawer-height,300px);max-height:90dvh}:host([placement=top]) dialog{inset:0 0 auto;transform:translateY(-100%)}:host([placement=bottom]) dialog{inset:auto 0 0;transform:translateY(100%)}.wui-drawer-body{--wui-internal-glass-shadow:var(--wui-shadow-overlay,2px 16px 40px #0006);background-color:var(--wui-drawer-bg,var(--wui-color-surface-overlay,#f6f6f6d1));flex-direction:column;height:100%;display:flex}.wui-drawer-header{border-bottom:1px solid #0000000f;justify-content:space-between;align-items:center;padding:16px 20px;font-size:18px;font-weight:600;line-height:1.4;display:flex}.wui-drawer-header[hidden]{display:none}.wui-drawer-content{overscroll-behavior:contain;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);flex:1;padding:20px;line-height:1.5;overflow-y:auto}.wui-drawer-footer{border-top:1px solid #0000000f;flex-shrink:0;padding:16px 20px}
|
|
2
|
+
var e = "*,:before,:after{box-sizing:border-box}:host{display:contents}dialog{box-sizing:border-box;width:var(--wui-drawer-width,320px);max-width:90vw;height:100dvh;max-height:100dvh;color:var(--wui-color-text,#1b1b1b);transition:transform var(--wui-duration-drawer-enter,.28s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1));background:0 0;border:none;margin:0;padding:0;font-family:inherit;inset:0 0 0 auto;overflow:visible;transform:translate(100%)}dialog::backdrop{opacity:0;background:var(--wui-drawer-overlay-bg,var(--wui-color-backdrop,#0000001f));transition:opacity var(--wui-duration-drawer-enter,.28s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1))}dialog[open].is-visible{transform:translate(0)}:host(:not([headless])) dialog.is-dragging[open].is-visible,dialog.is-dragging,:is(:host(:not([headless])) dialog.is-dragging[open].is-visible,dialog.is-dragging)::backdrop{transition:none}:host([placement=left]) dialog[open].is-visible,:host([placement=top]) dialog[open].is-visible,:host([placement=bottom]) dialog[open].is-visible{transform:translate(0)}dialog.is-closing{pointer-events:none;transition:transform var(--wui-duration-drawer-exit,.24s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1))}dialog.is-closing::backdrop{transition:opacity var(--wui-duration-drawer-exit,.24s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1))}dialog[open].is-visible::backdrop{opacity:var(--wui-internal-drag-backdrop-opacity,1)}.wui-drawer-drag-zone{touch-action:none;cursor:grab;z-index:4;transition:opacity var(--wui-duration-feedback,.1s) ease;justify-content:center;align-items:center;display:flex;position:absolute}dialog.is-nested-lower .wui-drawer-drag-zone{pointer-events:none;opacity:0}:host([placement=right]) .wui-drawer-drag-zone{width:24px;height:100%;top:0;left:0}:host([placement=left]) .wui-drawer-drag-zone{width:24px;height:100%;top:0;right:0}:host([placement=top]) .wui-drawer-drag-zone,:host([placement=bottom]) .wui-drawer-drag-zone{width:100%;height:24px;left:0;right:0}:host([placement=top]) .wui-drawer-drag-zone{bottom:0}:host([placement=bottom]) .wui-drawer-drag-zone{top:0}.wui-drawer-drag-bar{background:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 24%, transparent);border-radius:999px;width:4px;height:48px}:host([placement=top]) .wui-drawer-drag-bar,:host([placement=bottom]) .wui-drawer-drag-bar{width:48px;height:4px}.wui-drawer-drag-zone:hover .wui-drawer-drag-bar,.wui-drawer-drag-zone:active .wui-drawer-drag-bar{background:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 40%, transparent)}dialog.is-drag-close .wui-drawer-drag-zone .wui-drawer-drag-bar{background:var(--wui-color-accent,#08f)}:host([placement=left]) dialog{left:0;right:auto;transform:translate(-100%)}:host([placement=top]) dialog,:host([placement=bottom]) dialog{width:100vw;max-width:100vw;height:var(--wui-drawer-height,300px);max-height:90dvh}:host([placement=top]) dialog{inset:0 0 auto;transform:translateY(-100%)}:host([placement=bottom]) dialog{inset:auto 0 0;transform:translateY(100%)}dialog.is-dragging .wui-drawer-drag-zone{cursor:grabbing}.wui-drawer-body{--wui-internal-glass-shadow:var(--wui-shadow-overlay,2px 16px 40px #0006);--wui-glass-corner-radius:var(--wui-drawer-radius,28px);background-color:var(--wui-drawer-bg,var(--wui-color-surface-overlay,#f6f6f6d1));flex-direction:column;height:100%;display:flex}.wui-drawer-header{border-bottom:1px solid #0000000f;justify-content:space-between;align-items:center;padding:16px 20px;font-size:18px;font-weight:600;line-height:1.4;display:flex}.wui-drawer-header[hidden]{display:none}.wui-drawer-content{overscroll-behavior:contain;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);flex:1;padding:20px;line-height:1.5;overflow-y:auto}.wui-drawer-footer{border-top:1px solid #0000000f;flex-shrink:0;padding:16px 20px}.wui-drawer-footer[hidden]{display:none}.wui-drawer-close{z-index:3;position:absolute;top:16px;right:16px}:host([headless]) dialog{--wui-internal-drawer-inset:0px;width:auto;max-width:none}:host(:not([headless])) dialog{--wui-internal-drawer-inset:var(--wui-drawer-inset,8px);--wui-internal-drawer-nested-depth:0;--wui-internal-drawer-nested-scale:1;--wui-internal-drawer-nested-shift:0px;top:var(--wui-internal-drawer-inset);right:var(--wui-internal-drawer-inset);bottom:var(--wui-internal-drawer-inset);transform:translateX(calc(100% + var(--wui-internal-drawer-inset)));border-radius:var(--wui-drawer-radius,28px);height:auto;left:auto}:host(:not([headless])) .wui-drawer-body{border-radius:inherit}:host(:not([headless])[placement=left]) dialog{top:var(--wui-internal-drawer-inset);right:auto;bottom:var(--wui-internal-drawer-inset);left:var(--wui-internal-drawer-inset);transform:translateX(calc(-100% - var(--wui-internal-drawer-inset)));height:auto}:host(:not([headless])[placement=top]) dialog{top:var(--wui-internal-drawer-inset);right:var(--wui-internal-drawer-inset);bottom:auto;left:var(--wui-internal-drawer-inset);transform:translateY(calc(-100% - var(--wui-internal-drawer-inset)));width:auto;max-width:none}:host(:not([headless])[placement=bottom]) dialog{top:auto;right:var(--wui-internal-drawer-inset);bottom:var(--wui-internal-drawer-inset);left:var(--wui-internal-drawer-inset);transform:translateY(calc(100% + var(--wui-internal-drawer-inset)));width:auto;max-width:none}:host(:not([headless])) dialog[open].is-visible{transform:translate(0);translate:calc(var(--wui-internal-drawer-nested-shift) * -1) 0;scale:var(--wui-internal-drawer-nested-scale);transition:transform var(--wui-duration-drawer-enter,.28s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), translate var(--wui-duration-drawer-nested,.45s) cubic-bezier(.22, 1, .36, 1), scale var(--wui-duration-drawer-nested,.45s) cubic-bezier(.22, 1, .36, 1)}:host(:not([headless])[placement=left]) dialog[open].is-visible{transform:translate(0);translate:var(--wui-internal-drawer-nested-shift) 0}:host(:not([headless])[placement=top]) dialog[open].is-visible{transform:translate(0);translate:0 var(--wui-internal-drawer-nested-shift)}:host(:not([headless])[placement=bottom]) dialog[open].is-visible{transform:translate(0);translate:0 calc(var(--wui-internal-drawer-nested-shift) * -1)}@media (prefers-reduced-motion:reduce){dialog:not(.is-dragging){transition:opacity var(--wui-duration-feedback,.1s) ease!important}dialog:not(.is-dragging)::backdrop{transition-duration:var(--wui-duration-feedback,.1s)!important}dialog[open].is-visible:not(.is-dragging){transform:translate(0)scale(1)!important}}";
|
|
3
3
|
//#endregion
|
|
4
4
|
export { e as default };
|
|
5
5
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style.js","names":[],"sources":["../../../src/components/drawer/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: contents;\n}\n\n/* ===== Dialog 容器 ===== */\ndialog {\n /* 默认:右侧滑出 — 需显式 left:auto 覆盖 UA dialog:modal 的 left:0 */\n top: 0;\n right: 0;\n bottom: 0;\n left: auto;\n transform: translateX(100%);\n\n /* 阴影属于抽屉主体,不能由同尺寸的原生 dialog 裁剪。内容滚动由 .wui-drawer-content 管理。 */\n overflow: visible;\n\n box-sizing: border-box;\n width: var(--wui-drawer-width, 320px);\n max-width: 90vw;\n height: 100vh;\n height: 100dvh;\n max-height: 100vh;\n max-height: 100dvh;\n margin: 0;\n padding: 0;\n border: none;\n\n font-family: inherit;\n color: var(--wui-color-text, #1b1b1b);\n\n background: transparent;\n\n transition: transform var(--wui-duration-drawer-enter, 280ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n\n &::backdrop {\n opacity: 0;\n background: var(--wui-drawer-overlay-bg, var(--wui-color-backdrop, rgb(0 0 0 / 0.12)));\n transition: opacity var(--wui-duration-drawer-enter, 280ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n }\n}\n\ndialog[open].is-visible {\n transform: translate(0, 0);\n}\n\n:host([placement='left']) dialog[open].is-visible,\n:host([placement='top']) dialog[open].is-visible,\n:host([placement='bottom']) dialog[open].is-visible {\n transform: translate(0, 0);\n}\n\ndialog.is-closing {\n pointer-events: none;\n transition: transform var(--wui-duration-drawer-exit, 240ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\ndialog.is-closing::backdrop {\n transition: opacity var(--wui-duration-drawer-exit, 240ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\ndialog[open].is-visible::backdrop {\n opacity: 1;\n}\n\n/* ===== Placement 变体 ===== */\n\n:host([placement='left']) dialog {\n right: auto;\n left: 0;\n transform: translateX(-100%);\n}\n\n:host([placement='top']) dialog,\n:host([placement='bottom']) dialog {\n width: 100vw;\n max-width: 100vw;\n height: var(--wui-drawer-height, 300px);\n max-height: 90dvh;\n}\n\n:host([placement='top']) dialog {\n top: 0;\n right: 0;\n bottom: auto;\n left: 0;\n transform: translateY(-100%);\n}\n\n:host([placement='bottom']) dialog {\n top: auto;\n right: 0;\n bottom: 0;\n left: 0;\n transform: translateY(100%);\n}\n\n/* ===== 抽屉主体 ===== */\n\n.wui-drawer-body {\n --wui-internal-glass-shadow: var(--wui-shadow-overlay, 2px 16px 40px rgb(0 0 0 / 0.4));\n display: flex;\n flex-direction: column;\n height: 100%;\n background-color: var(--wui-drawer-bg, var(--wui-color-surface-overlay, rgb(246 246 246 / 0.82)));\n}\n\n/* ===== Header ===== */\n\n.wui-drawer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n padding: 16px 20px;\n border-bottom: 1px solid rgb(0 0 0 / 0.06);\n\n font-size: 18px;\n font-weight: 600;\n line-height: 1.4;\n}\n\n/* ===== 隐藏态 ===== */\n\n.wui-drawer-header[hidden] {\n display: none;\n}\n\n/* ===== 内容区 ===== */\n\n.wui-drawer-content {\n overflow-y: auto;\n overscroll-behavior: contain;\n flex: 1;\n\n padding: 20px;\n\n font-size: var(--wui-font-size, 14px);\n line-height: 1.5;\n color: var(--wui-color-text, #1b1b1b);\n}\n\n/* ===== Footer ===== */\n\n.wui-drawer-footer {\n flex-shrink: 0;\n padding: 16px 20px;\n border-top: 1px solid rgb(0 0 0 / 0.06);\n}\n\n@media (prefers-reduced-motion: reduce) {\n dialog {\n transition: opacity var(--wui-duration-feedback, 100ms) ease;\n }\n\n dialog::backdrop {\n transition-duration: var(--wui-duration-feedback, 100ms);\n }\n\n dialog[open].is-visible {\n transform: none;\n }\n}\n\n.wui-drawer-footer[hidden] {\n display: none;\n}\n\n/* ===== 关闭按钮(独立定位,与 header 解耦) ===== */\n\n.wui-drawer-close {\n position: absolute;\n z-index: 3;\n top: 16px;\n right: 16px;\n}\n\n/* ===== Headless 模式 ===== */\n\n/* Headless 模式下,dialog 只作为 overlay 容器,不渲染内置 UI */\n:host([headless]) dialog {\n /* 保持 overlay 基础设施,移除内置样式 */\n width: auto;\n max-width: none;\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"style.js","names":[],"sources":["../../../src/components/drawer/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: contents;\n}\n\n/* ===== Dialog 容器 ===== */\ndialog {\n /* 默认:右侧滑出 — 需显式 left:auto 覆盖 UA dialog:modal 的 left:0 */\n top: 0;\n right: 0;\n bottom: 0;\n left: auto;\n transform: translateX(100%);\n\n /* 阴影属于抽屉主体,不能由同尺寸的原生 dialog 裁剪。内容滚动由 .wui-drawer-content 管理。 */\n overflow: visible;\n\n box-sizing: border-box;\n width: var(--wui-drawer-width, 320px);\n max-width: 90vw;\n height: 100vh;\n height: 100dvh;\n max-height: 100vh;\n max-height: 100dvh;\n margin: 0;\n padding: 0;\n border: none;\n\n font-family: inherit;\n color: var(--wui-color-text, #1b1b1b);\n\n background: transparent;\n\n transition: transform var(--wui-duration-drawer-enter, 280ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n\n &::backdrop {\n opacity: 0;\n background: var(--wui-drawer-overlay-bg, var(--wui-color-backdrop, rgb(0 0 0 / 0.12)));\n transition: opacity var(--wui-duration-drawer-enter, 280ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n }\n}\n\ndialog[open].is-visible {\n transform: translate(0, 0);\n}\n\n/*\n * 拖拽跟手期间与弹簧弹回期间,transform/backdrop 由 JS 内联样式与 WAAPI 管辖。\n * 特异性必须压过下方开放守卫块(:host(:not()) dialog[open].is-visible = (0,4,1)\n * 的 nested transition 声明),否则拖拽写入的 transform 会被平滑掉、跟手失效。\n * 复合选择器达 (0,6,1),恒高于守卫。\n */\n:host(:not([headless])) dialog.is-dragging[open].is-visible,\ndialog.is-dragging {\n transition: none;\n\n &::backdrop {\n transition: none;\n }\n}\n\n:host([placement='left']) dialog[open].is-visible,\n:host([placement='top']) dialog[open].is-visible,\n:host([placement='bottom']) dialog[open].is-visible {\n transform: translate(0, 0);\n}\n\ndialog.is-closing {\n pointer-events: none;\n transition: transform var(--wui-duration-drawer-exit, 240ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\ndialog.is-closing::backdrop {\n transition: opacity var(--wui-duration-drawer-exit, 240ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\ndialog[open].is-visible::backdrop {\n /* 拖拽期间由 JS 写入 --wui-internal-drag-backdrop-opacity 实现遮罩跟手淡出。 */\n opacity: var(--wui-internal-drag-backdrop-opacity, 1);\n}\n\n/* ===== Drag bar(拖拽关闭热区) ===== */\n\n/*\n * 热区贴在抽屉内缘,宽度约 24px 便于触控命中;胶囊本身是约 4×48px 的灰色短条。\n * 位置随 placement 切换:right 贴在左缘、left 贴在右缘、top 贴在底边、bottom 贴在顶边。\n */\n.wui-drawer-drag-zone {\n touch-action: none;\n cursor: grab;\n\n position: absolute;\n z-index: 4;\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n transition: opacity var(--wui-duration-feedback, 100ms) ease;\n}\n\ndialog.is-nested-lower .wui-drawer-drag-zone {\n pointer-events: none;\n opacity: 0;\n}\n\n:host([placement='right']) .wui-drawer-drag-zone {\n top: 0;\n left: 0;\n width: 24px;\n height: 100%;\n}\n\n:host([placement='left']) .wui-drawer-drag-zone {\n top: 0;\n right: 0;\n width: 24px;\n height: 100%;\n}\n\n:host([placement='top']) .wui-drawer-drag-zone,\n:host([placement='bottom']) .wui-drawer-drag-zone {\n right: 0;\n left: 0;\n width: 100%;\n height: 24px;\n}\n\n:host([placement='top']) .wui-drawer-drag-zone {\n bottom: 0;\n}\n\n:host([placement='bottom']) .wui-drawer-drag-zone {\n top: 0;\n}\n\n.wui-drawer-drag-bar {\n width: 4px;\n height: 48px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 24%, transparent);\n}\n\n:host([placement='top']) .wui-drawer-drag-bar,\n:host([placement='bottom']) .wui-drawer-drag-bar {\n width: 48px;\n height: 4px;\n}\n\n.wui-drawer-drag-zone:hover .wui-drawer-drag-bar,\n.wui-drawer-drag-zone:active .wui-drawer-drag-bar {\n background: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 40%, transparent);\n}\n\n/*\n * 达到关闭阈值的 accent 确认需压过上方 :hover/:active 中性色(拖拽全程 capture\n * 使 hover 恒成立),这里的选择器特异性 (0,3,1) 高于 hover/active 的 (0,3,0)。\n */\ndialog.is-drag-close .wui-drawer-drag-zone .wui-drawer-drag-bar {\n background: var(--wui-color-accent, #08f);\n}\n\n/* ===== Placement 变体 ===== */\n\n:host([placement='left']) dialog {\n right: auto;\n left: 0;\n transform: translateX(-100%);\n}\n\n:host([placement='top']) dialog,\n:host([placement='bottom']) dialog {\n width: 100vw;\n max-width: 100vw;\n height: var(--wui-drawer-height, 300px);\n max-height: 90dvh;\n}\n\n:host([placement='top']) dialog {\n top: 0;\n right: 0;\n bottom: auto;\n left: 0;\n transform: translateY(-100%);\n}\n\n:host([placement='bottom']) dialog {\n top: auto;\n right: 0;\n bottom: 0;\n left: 0;\n transform: translateY(100%);\n}\n\n/*\n * 拖拽中的 grabbing 光标。dialog 复合前缀使其特异性恒高于上方 placement 变体,\n * stylelint 的顺序比较对这种结构必然告警;cascade 上此规则不依赖 placement,\n * 置于其后仅为可读性,故显式豁免。\n */\n/* stylelint-disable-next-line no-descending-specificity */\ndialog.is-dragging .wui-drawer-drag-zone {\n cursor: grabbing;\n}\n\n/* ===== 抽屉主体 ===== */\n\n.wui-drawer-body {\n --wui-internal-glass-shadow: var(--wui-shadow-overlay, 2px 16px 40px rgb(0 0 0 / 0.4));\n --wui-glass-corner-radius: var(--wui-drawer-radius, 28px);\n display: flex;\n flex-direction: column;\n height: 100%;\n background-color: var(--wui-drawer-bg, var(--wui-color-surface-overlay, rgb(246 246 246 / 0.82)));\n}\n\n/* ===== Header ===== */\n\n.wui-drawer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n padding: 16px 20px;\n border-bottom: 1px solid rgb(0 0 0 / 0.06);\n\n font-size: 18px;\n font-weight: 600;\n line-height: 1.4;\n}\n\n/* ===== 隐藏态 ===== */\n\n.wui-drawer-header[hidden] {\n display: none;\n}\n\n/* ===== 内容区 ===== */\n\n.wui-drawer-content {\n overflow-y: auto;\n overscroll-behavior: contain;\n flex: 1;\n\n padding: 20px;\n\n font-size: var(--wui-font-size, 14px);\n line-height: 1.5;\n color: var(--wui-color-text, #1b1b1b);\n}\n\n/* ===== Footer ===== */\n\n.wui-drawer-footer {\n flex-shrink: 0;\n padding: 16px 20px;\n border-top: 1px solid rgb(0 0 0 / 0.06);\n}\n\n.wui-drawer-footer[hidden] {\n display: none;\n}\n\n/* ===== 关闭按钮(独立定位,与 header 解耦) ===== */\n\n.wui-drawer-close {\n position: absolute;\n z-index: 3;\n top: 16px;\n right: 16px;\n}\n\n/* ===== Headless 模式 ===== */\n\n/* Headless 模式下,dialog 只作为 overlay 容器,不渲染内置 UI */\n:host([headless]) dialog {\n /*\n * inset 只属于浮动卡片几何;headless 嵌套在非 headless 外层内时会沿\n * flattened tree 继承到 8px,破坏 JS 读取该变量得到的贴边几何假设\n * (parseFloat('0px') 与回退 0 语义一致),故显式归零。\n */\n --wui-internal-drawer-inset: 0px;\n\n /* 保持 overlay 基础设施,移除内置样式 */\n width: auto;\n max-width: none;\n}\n\n/* ===== 浮动卡片视觉语言(ADR-0036) ===== */\n\n/*\n * 非 headless 时抽屉是四周留边的圆角卡片,与 layout sidebar 的设计语言一致;\n * 弹性拖拽使边距变化(8px → 更大)是合法状态而非渲染缺口。\n * headless 保持贴边几何,视觉由 Consumer 自绘。\n *\n * 留边经公开 token --wui-drawer-inset 暴露(默认 8px,ADR-0036 修订);\n * 置 0 即贴边几何(与 headless 相同),通常与 --wui-drawer-radius: 0 搭配。\n *\n * 闭合位移需要越过留边才能完全滑出视口,因此闭合态 transform 以\n * --wui-internal-drawer-inset 补偿;JS 在 controlled 悬停终态读取同一变量,\n * 保证两条关闭路径的行为一致。headless 将该变量显式归零(见上方 Headless 模式)。\n */\n\n/* 默认 right:四周留边、高度随上下边距拉伸,闭合位移越过右侧留边 */\n:host(:not([headless])) dialog {\n --wui-internal-drawer-inset: var(--wui-drawer-inset, 8px);\n --wui-internal-drawer-nested-depth: 0;\n --wui-internal-drawer-nested-scale: 1;\n --wui-internal-drawer-nested-shift: 0px;\n\n top: var(--wui-internal-drawer-inset);\n right: var(--wui-internal-drawer-inset);\n bottom: var(--wui-internal-drawer-inset);\n left: auto;\n transform: translateX(calc(100% + var(--wui-internal-drawer-inset)));\n\n height: auto;\n border-radius: var(--wui-drawer-radius, 28px);\n}\n\n:host(:not([headless])) .wui-drawer-body {\n border-radius: inherit;\n}\n\n:host(:not([headless])[placement='left']) dialog {\n top: var(--wui-internal-drawer-inset);\n right: auto;\n bottom: var(--wui-internal-drawer-inset);\n left: var(--wui-internal-drawer-inset);\n transform: translateX(calc(-100% - var(--wui-internal-drawer-inset)));\n\n height: auto;\n}\n\n:host(:not([headless])[placement='top']) dialog {\n top: var(--wui-internal-drawer-inset);\n right: var(--wui-internal-drawer-inset);\n bottom: auto;\n left: var(--wui-internal-drawer-inset);\n transform: translateY(calc(-100% - var(--wui-internal-drawer-inset)));\n\n width: auto;\n max-width: none;\n}\n\n:host(:not([headless])[placement='bottom']) dialog {\n top: auto;\n right: var(--wui-internal-drawer-inset);\n bottom: var(--wui-internal-drawer-inset);\n left: var(--wui-internal-drawer-inset);\n transform: translateY(calc(100% + var(--wui-internal-drawer-inset)));\n\n width: auto;\n max-width: none;\n}\n\n/*\n * 开放态守卫:上方闭合 transform 与基础 `dialog[open].is-visible` 特异性相同且\n * 在文件更后方,必须以更高特异性显式恢复打开位,否则抽屉停在闭合位。\n *\n * Nested 层叠(对齐卡片堆栈效果):非顶层抽屉按 0.95^depth 缩放并向屏幕内侧\n * 平移(shift 为正,朝屏幕中心方向),使缩小的卡片在顶层后方露出阶梯式卡片边缘。\n * 用独立 translate/scale 属性(而非并入 transform):\n * 它们是标准可过渡属性,变量变化即触发平滑过渡;且与 transform 轴上的\n * 闭合/拖拽/弹簧位移互不覆写(独立属性先于 transform 应用后合并)。\n * JS 层序管理写入 depth/scale/shift 三个内部变量,单层使用时全为中性值。\n *\n * 层叠变化的平滑过渡(Base UI nested 实测规格:450ms easeOutQuint 类曲线)。\n * transform 保持既有 enter/exit 时长;translate/scale 只在层叠数变化时更新,\n * 用更长的 nested 时长。\n */\n:host(:not([headless])) dialog[open].is-visible {\n transform: translate(0, 0);\n translate: calc(var(--wui-internal-drawer-nested-shift) * -1) 0;\n scale: var(--wui-internal-drawer-nested-scale);\n transition:\n transform var(--wui-duration-drawer-enter, 280ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n translate var(--wui-duration-drawer-nested, 450ms) cubic-bezier(0.22, 1, 0.36, 1),\n scale var(--wui-duration-drawer-nested, 450ms) cubic-bezier(0.22, 1, 0.36, 1);\n}\n\n:host(:not([headless])[placement='left']) dialog[open].is-visible {\n transform: translate(0, 0);\n translate: var(--wui-internal-drawer-nested-shift) 0;\n}\n\n:host(:not([headless])[placement='top']) dialog[open].is-visible {\n transform: translate(0, 0);\n translate: 0 var(--wui-internal-drawer-nested-shift);\n}\n\n:host(:not([headless])[placement='bottom']) dialog[open].is-visible {\n transform: translate(0, 0);\n translate: 0 calc(var(--wui-internal-drawer-nested-shift) * -1);\n}\n\n@media (prefers-reduced-motion: reduce) {\n /*\n * reduce 下:位移一律归零、transform 不参与过渡(仅 opacity 反馈)。\n * 全部 !important:压过开放守卫(嵌套层叠变量的特异性猫鼠不可维护),\n * 排除 .is-dragging —— reduce 下拖拽仍需实时跟手(ADR-0035)。\n * JS 收尾移除内联 transform 后立即为终态,无 280ms 过渡尾巴。\n */\n dialog:not(.is-dragging) {\n transition: opacity var(--wui-duration-feedback, 100ms) ease !important;\n\n &::backdrop {\n transition-duration: var(--wui-duration-feedback, 100ms) !important;\n }\n }\n\n dialog[open].is-visible:not(.is-dragging) {\n transform: none !important;\n translate: none !important;\n scale: none !important;\n }\n}\n"],"mappings":""}
|
|
@@ -24,8 +24,12 @@ export declare class WebUiDropdown extends LitElement {
|
|
|
24
24
|
private readonly _userOpenChange;
|
|
25
25
|
private _restoreFocusTarget?;
|
|
26
26
|
private _shouldOpenInstantly;
|
|
27
|
+
private _menuSyncScheduled;
|
|
28
|
+
private readonly _level0ItemAnchors;
|
|
29
|
+
private readonly _menuContentObserver;
|
|
27
30
|
get isOpen(): boolean;
|
|
28
31
|
connectedCallback(): void;
|
|
32
|
+
firstUpdated(): void;
|
|
29
33
|
disconnectedCallback(): void;
|
|
30
34
|
protected updated(changed: Map<string, unknown>): void;
|
|
31
35
|
openMenu(): void;
|
|
@@ -41,18 +45,22 @@ export declare class WebUiDropdown extends LitElement {
|
|
|
41
45
|
private _syncActiveAttrs;
|
|
42
46
|
private _getLevelItems;
|
|
43
47
|
private _populateLevel0;
|
|
48
|
+
private _scheduleMenuSync;
|
|
49
|
+
private _syncOpenMenuContent;
|
|
44
50
|
private _returnLevel0Items;
|
|
45
51
|
private _populateOverlay;
|
|
46
52
|
private _depopulateOverlay;
|
|
47
53
|
private _ensureOverlay;
|
|
48
54
|
private _buildOverlay;
|
|
49
55
|
private _disposeOverlay;
|
|
56
|
+
private _rebindMenuContentObservers;
|
|
50
57
|
private _disposeAll;
|
|
51
58
|
private _closeSubmenuAfterPresence;
|
|
52
59
|
private _disposeClosingSubmenuOverlays;
|
|
53
60
|
private _restoreSubmenuItems;
|
|
54
61
|
private _syncScrollLock;
|
|
55
62
|
private _queryTriggerAnchor;
|
|
63
|
+
private _syncTriggerAria;
|
|
56
64
|
private _getSubmenuTriggerAnchor;
|
|
57
65
|
private _onTriggerClick;
|
|
58
66
|
private _onClickOutside;
|