@greypan/web-ui 4.0.0 → 5.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 +248 -139
- package/README.md +255 -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 +29 -0
- package/dist/components/context-menu/index.js +167 -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 +2 -0
- package/dist/components/dropdown/index.js +23 -13
- 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 +2 -1
- package/dist/components/popover/index.js +8 -4
- 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 +32 -28
- 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.js +2 -2
- 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 +4 -2
- package/dist/shared/menu-portal/menu-tree.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/portal.js +44 -13
- package/dist/shared/overlay/portal.js.map +1 -1
- package/package.json +5 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/dialog/index.ts"],"sourcesContent":["import { html, LitElement, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport '@/components/button'\nimport glass from '@/assets/glass.css?inline'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { defineNativeDialogPresence } from '@/shared/overlay/native-dialog-presence'\nimport { defineScrollLockLease } from '@/shared/scroll-lock/scroll-lock'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-dialog')\nexport class WebUiDialog 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 @property({ type: Boolean, reflect: true, attribute: 'no-escape-close' }) noEscapeClose = false\n\n @state() private _hasBody = false\n private readonly _userOpenChange = new UserChangeController()\n\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 private get dialog() {\n return this.shadowRoot?.querySelector('dialog') ?? null\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 override disconnectedCallback() {\n super.disconnectedCallback()\n this._presence.dispose()\n this._scrollLock.release()\n }\n\n // 以模态方式打开对话框(命令式)\n showModal() {\n if (this.open) return\n this.open = true\n }\n\n close() {\n this.open = false\n }\n\n private handleCancel(e: Event) {\n // 保留 top layer 直到视觉退场完成,避免原生关闭跳过退出动画。\n e.preventDefault()\n if (this.noEscapeClose) return\n this._userOpenChange.mark()\n this.close()\n }\n\n private handleBackdropClick(e: MouseEvent) {\n if (e.target !== (e.currentTarget as HTMLDialogElement)) return\n if (this.noBackdropClose) return\n this._userOpenChange.mark()\n this.close()\n }\n\n private emitOpenChange() {\n this.dispatchEvent(\n new CustomEvent('open-change', {\n detail: { open
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/dialog/index.ts"],"sourcesContent":["import { html, LitElement, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport '@/components/button'\nimport glass from '@/assets/glass.css?inline'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { defineNativeDialogPresence } from '@/shared/overlay/native-dialog-presence'\nimport { defineScrollLockLease } from '@/shared/scroll-lock/scroll-lock'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-dialog')\nexport class WebUiDialog 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 @property({ type: Boolean, reflect: true, attribute: 'no-escape-close' }) noEscapeClose = false\n\n /**\n * Controlled 模式下,Escape 和遮罩点击只派发 `open-change` 请求,\n * 不会自行修改 `open`。Consumer 回写 `open` 后才执行关闭动画。\n * 程序化 API(showModal/close/直接赋值 open)不受此模式影响,始终直通。\n */\n @property({ type: Boolean, reflect: true }) controlled = false\n\n @state() private _hasBody = false\n private readonly _userOpenChange = new UserChangeController()\n\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 private get dialog() {\n return this.shadowRoot?.querySelector('dialog') ?? null\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 override disconnectedCallback() {\n super.disconnectedCallback()\n this._presence.dispose()\n this._scrollLock.release()\n }\n\n // 以模态方式打开对话框(命令式)\n showModal() {\n if (this.open) return\n this.open = true\n }\n\n close() {\n this.open = false\n }\n\n private handleCancel(e: Event) {\n // 子控件(例如 file input)可能派发冒泡的 cancel;只让 native dialog 自身的 cancel 关闭。\n if (e.target !== e.currentTarget) return\n\n // 保留 top layer 直到视觉退场完成,避免原生关闭跳过退出动画。\n e.preventDefault()\n if (this.noEscapeClose) return\n if (this.controlled) {\n this.emitOpenChange(false)\n return\n }\n this._userOpenChange.mark()\n this.close()\n }\n\n private handleBackdropClick(e: MouseEvent) {\n if (e.target !== (e.currentTarget as HTMLDialogElement)) return\n if (this.noBackdropClose) return\n if (this.controlled) {\n this.emitOpenChange(false)\n return\n }\n this._userOpenChange.mark()\n this.close()\n }\n\n // controlled 下派发关闭请求:detail 固定 false(用户只能请求关闭,打开永远由 Consumer 写)。\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 _onTransitionEnd = (event: TransitionEvent) => {\n this._presence.handleTransitionEnd(event)\n }\n\n private _onNativeClose = () => {\n if (!this.open) return\n\n // controlled 下原生关闭(如表单 method=\"dialog\")视为未经 Consumer 批准的状态丢失:\n // 恢复受控状态并派发关闭请求,由 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 _syncScrollLock(isOpen = this.open) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\n }\n\n private _onBodySlotChange(e: Event) {\n if (!(e.target instanceof HTMLSlotElement)) return\n this._hasBody = e.target.assignedElements().length > 0\n }\n\n override render() {\n return html`\n <dialog\n @cancel=${this.handleCancel}\n @close=${this._onNativeClose}\n @click=${this.handleBackdropClick}\n @transitionend=${this._onTransitionEnd}\n >\n <div class=\"wui-dialog-body wui-glass\">\n ${\n this._hasBody\n ? html`<slot name=\"body\" @slotchange=${this._onBodySlotChange}></slot>`\n : html`\n <slot name=\"body\" @slotchange=${this._onBodySlotChange} hidden></slot>\n <div class=\"title\"><slot name=\"title\"></slot></div>\n <div class=\"desc\"><slot></slot></div>\n <div class=\"wui-dialog-footer\"><slot name=\"footer\"></slot></div>\n `\n }\n </div>\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-dialog': WebUiDialog\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/components/dialog/style.css?inline
|
|
2
|
-
var e = "*,:before,:after{box-sizing:border-box}:host{display:contents}dialog{transform:scale(var(--wui-scale-enter,.97));box-sizing:border-box;max-width:min(90vw, var(--wui-dialog-max-width,360px));max-height:90vh;color:var(--wui-color-text,#1b1b1b);opacity:0;transition:opacity var(--wui-duration-overlay-enter,.18s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), transform var(--wui-duration-overlay-enter,.18s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1));background:0 0;border:none;padding:0;font-family:inherit;overflow:visible}dialog::backdrop{opacity:0;background:var(--wui-dialog-overlay-bg,var(--wui-color-backdrop,#0000001a));transition:opacity var(--wui-duration-overlay-enter,.18s) ease}dialog[open].is-visible{opacity:1;transform:scale(1)}dialog.is-closing{pointer-events:none;transition-duration:var(--wui-duration-overlay-exit,.14s)}dialog.is-closing::backdrop{transition-duration:var(--wui-duration-overlay-exit,.14s)}dialog[open].is-visible::backdrop{opacity:1}@media (prefers-reduced-motion:reduce){dialog,dialog[open].is-visible{transition-duration:var(--wui-duration-feedback,.1s);transform:none}}.wui-dialog-body{--wui-internal-glass-shadow:var(--wui-shadow-overlay,2px 16px 40px #0006);background-color:var(--wui-color-surface-overlay,#
|
|
2
|
+
var e = "*,:before,:after{box-sizing:border-box}:host{display:contents}dialog{transform:scale(var(--wui-scale-enter,.97));box-sizing:border-box;max-width:min(90vw, var(--wui-dialog-max-width,360px));max-height:90vh;color:var(--wui-color-text,#1b1b1b);opacity:0;transition:opacity var(--wui-duration-overlay-enter,.18s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), transform var(--wui-duration-overlay-enter,.18s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1));background:0 0;border:none;padding:0;font-family:inherit;overflow:visible}dialog::backdrop{opacity:0;background:var(--wui-dialog-overlay-bg,var(--wui-color-backdrop,#0000001a));transition:opacity var(--wui-duration-overlay-enter,.18s) ease}dialog[open].is-visible{opacity:1;transform:scale(1)}dialog.is-closing{pointer-events:none;transition-duration:var(--wui-duration-overlay-exit,.14s)}dialog.is-closing::backdrop{transition-duration:var(--wui-duration-overlay-exit,.14s)}dialog[open].is-visible::backdrop{opacity:1}@media (prefers-reduced-motion:reduce){dialog,dialog[open].is-visible{transition-duration:var(--wui-duration-feedback,.1s);transform:none}}.wui-dialog-body{--wui-internal-glass-shadow:var(--wui-shadow-overlay,2px 16px 40px #0006);--wui-glass-corner-radius:32px;background-color:var(--wui-dialog-bg,var(--wui-color-surface-overlay,#f6f6f6e0));border-radius:32px;padding:20px 24px 24px}.title{color:var(--wui-color-text,#1b1b1b);margin:0 0 16px;padding:0;font-size:18px;font-weight:600;line-height:1.2}.desc{color:var(--wui-color-text,#1b1b1b);margin:0 0 24px;padding:0;font-size:14px;line-height:1.5}.wui-dialog-footer{flex-direction:column;gap:10px;display:flex}.wui-dialog-footer ::slotted(web-ui-button){width:100%;display:flex}:host([horizontal]) .wui-dialog-footer{flex-direction:row;justify-content:center;gap:12px}:host([horizontal]) .wui-dialog-footer ::slotted(web-ui-button:not([full])){width:auto}:host([horizontal]) .wui-dialog-footer ::slotted(web-ui-button[full]){flex:1;min-width:0}";
|
|
3
3
|
//#endregion
|
|
4
4
|
export { e as default };
|
|
5
5
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style.js","names":[],"sources":["../../../src/components/dialog/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: contents;\n}\n\ndialog {\n transform: scale(var(--wui-scale-enter, 0.97));\n\n overflow: visible;\n\n box-sizing: border-box;\n max-width: min(90vw, var(--wui-dialog-max-width, 360px));\n max-height: 90vh;\n padding: 0;\n border: none;\n\n font-family: inherit;\n color: var(--wui-color-text, #1b1b1b);\n\n opacity: 0;\n background: transparent;\n\n transition:\n opacity var(--wui-duration-overlay-enter, 180ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n transform var(--wui-duration-overlay-enter, 180ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n\n &::backdrop {\n opacity: 0;\n background: var(--wui-dialog-overlay-bg, var(--wui-color-backdrop, rgb(0 0 0 / 0.1)));\n transition: opacity var(--wui-duration-overlay-enter, 180ms) ease;\n }\n}\n\ndialog[open].is-visible {\n transform: scale(1);\n opacity: 1;\n}\n\ndialog.is-closing {\n pointer-events: none;\n transition-duration: var(--wui-duration-overlay-exit, 140ms);\n}\n\ndialog.is-closing::backdrop {\n transition-duration: var(--wui-duration-overlay-exit, 140ms);\n}\n\ndialog[open].is-visible::backdrop {\n opacity: 1;\n}\n\n@media (prefers-reduced-motion: reduce) {\n dialog,\n dialog[open].is-visible {\n transform: none;\n transition-duration: var(--wui-duration-feedback, 100ms);\n }\n}\n\n/* ===== 玻璃卡片主体(样式由 glass.css 提供) ===== */\n\n.wui-dialog-body {\n --wui-internal-glass-shadow: var(--wui-shadow-overlay, 2px 16px 40px rgb(0 0 0 / 0.4));\n
|
|
1
|
+
{"version":3,"file":"style.js","names":[],"sources":["../../../src/components/dialog/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: contents;\n}\n\ndialog {\n transform: scale(var(--wui-scale-enter, 0.97));\n\n overflow: visible;\n\n box-sizing: border-box;\n max-width: min(90vw, var(--wui-dialog-max-width, 360px));\n max-height: 90vh;\n padding: 0;\n border: none;\n\n font-family: inherit;\n color: var(--wui-color-text, #1b1b1b);\n\n opacity: 0;\n background: transparent;\n\n transition:\n opacity var(--wui-duration-overlay-enter, 180ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n transform var(--wui-duration-overlay-enter, 180ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n\n &::backdrop {\n opacity: 0;\n background: var(--wui-dialog-overlay-bg, var(--wui-color-backdrop, rgb(0 0 0 / 0.1)));\n transition: opacity var(--wui-duration-overlay-enter, 180ms) ease;\n }\n}\n\ndialog[open].is-visible {\n transform: scale(1);\n opacity: 1;\n}\n\ndialog.is-closing {\n pointer-events: none;\n transition-duration: var(--wui-duration-overlay-exit, 140ms);\n}\n\ndialog.is-closing::backdrop {\n transition-duration: var(--wui-duration-overlay-exit, 140ms);\n}\n\ndialog[open].is-visible::backdrop {\n opacity: 1;\n}\n\n@media (prefers-reduced-motion: reduce) {\n dialog,\n dialog[open].is-visible {\n transform: none;\n transition-duration: var(--wui-duration-feedback, 100ms);\n }\n}\n\n/* ===== 玻璃卡片主体(样式由 glass.css 提供) ===== */\n\n.wui-dialog-body {\n --wui-internal-glass-shadow: var(--wui-shadow-overlay, 2px 16px 40px rgb(0 0 0 / 0.4));\n --wui-glass-corner-radius: 32px;\n padding: 20px 24px 24px;\n border-radius: 32px;\n background-color: var(--wui-dialog-bg, var(--wui-color-surface-overlay, rgb(246 246 246 / 0.88)));\n}\n\n/* ===== 标题 ===== */\n\n.title {\n margin: 0 0 16px;\n padding: 0;\n\n font-size: 18px;\n font-weight: 600;\n line-height: 1.2;\n color: var(--wui-color-text, #1b1b1b);\n}\n\n/* ===== 描述 ===== */\n\n.desc {\n margin: 0 0 24px;\n padding: 0;\n\n font-size: 14px;\n line-height: 1.5;\n color: var(--wui-color-text, #1b1b1b);\n}\n\n/* ===== 按钮区域 ===== */\n\n.wui-dialog-footer {\n display: flex;\n flex-direction: column;\n gap: 10px;\n\n /* ===== 按钮全宽(默认垂直排列) ===== */\n\n & ::slotted(web-ui-button) {\n display: flex;\n width: 100%;\n }\n}\n\n/* ===== horizontal 模式 ===== */\n\n:host([horizontal]) .wui-dialog-footer {\n flex-direction: row;\n gap: 12px;\n justify-content: center;\n\n /* 非 full 按钮:居中,不拉伸 */\n\n & ::slotted(web-ui-button:not([full])) {\n width: auto;\n }\n\n /* full 按钮:平分剩余空间 */\n\n & ::slotted(web-ui-button[full]) {\n flex: 1;\n min-width: 0;\n }\n}\n"],"mappings":""}
|
|
@@ -7,10 +7,11 @@ export declare class WebUiDrawer extends LitElement {
|
|
|
7
7
|
noScrollLock: boolean;
|
|
8
8
|
noBackdropClose: boolean;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Controlled 模式下,Escape、遮罩、关闭按钮和拖拽关闭只派发 `open-change` 请求,
|
|
11
11
|
* 不会自行修改 `open`。Consumer 回写 `open` 后才执行关闭动画。
|
|
12
|
+
* 程序化 API(show/close/直接赋值 open)不受此模式影响,始终直通。
|
|
12
13
|
*/
|
|
13
|
-
|
|
14
|
+
controlled: boolean;
|
|
14
15
|
get placement(): DrawerPlacement;
|
|
15
16
|
set placement(v: string);
|
|
16
17
|
private _placement;
|
|
@@ -26,12 +27,41 @@ export declare class WebUiDrawer extends LitElement {
|
|
|
26
27
|
* 因为该模式不会渲染可自动关联的内置 header。
|
|
27
28
|
*/
|
|
28
29
|
dialogLabel: string;
|
|
30
|
+
/**
|
|
31
|
+
* 启用拖拽关闭:打开态在抽屉内缘渲染 drag bar(灰色胶囊 + 加宽热区),
|
|
32
|
+
* 指针拖拽实时跟手,松手按位移与甩动速度判定关闭或弹回。
|
|
33
|
+
* 关闭态基于原生 dialog 无可见渲染物,因此不支持从关闭态拖拽打开。
|
|
34
|
+
*/
|
|
35
|
+
draggable: boolean;
|
|
29
36
|
private get dialog();
|
|
30
37
|
private _hasHeaderSlot;
|
|
31
38
|
private _hasFooterSlot;
|
|
32
39
|
private readonly _userOpenChange;
|
|
33
40
|
private readonly _scrollLock;
|
|
34
41
|
private readonly _presence;
|
|
42
|
+
private readonly _nestedLayers;
|
|
43
|
+
private _dragGesture;
|
|
44
|
+
private _dragInitialOffset;
|
|
45
|
+
private _dragOffset;
|
|
46
|
+
private _dragAnimation;
|
|
47
|
+
private _dragAwaitWriteback;
|
|
48
|
+
private _dragRequestTimer;
|
|
49
|
+
private get _dragAxis();
|
|
50
|
+
private get _dragCloseSign();
|
|
51
|
+
private _measureDragSize;
|
|
52
|
+
private _readDrawerInset;
|
|
53
|
+
private _dragCloseDistance;
|
|
54
|
+
private _isReducedMotion;
|
|
55
|
+
private _isDragging;
|
|
56
|
+
private _cancelDragAwait;
|
|
57
|
+
private _handleDragPointerDown;
|
|
58
|
+
private _cancelActiveDrag;
|
|
59
|
+
private _applyDragOffset;
|
|
60
|
+
private _clearDragStyles;
|
|
61
|
+
private _springToClose;
|
|
62
|
+
private _springRebound;
|
|
63
|
+
private _closeFromDrag;
|
|
64
|
+
private readonly _handleDragWritebackTimeout;
|
|
35
65
|
connectedCallback(): void;
|
|
36
66
|
firstUpdated(): void;
|
|
37
67
|
disconnectedCallback(): void;
|
|
@@ -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":";;;;;;;;;;;;;;;;;AAiBA,IAAM,IAAqB;CAAC;CAAS;CAAQ;CAAO;AAAQ,GAKtD,IAAmB,IAAI,GACvB,IAAsB,KACtB,IAAyB,KACzB,IAAmB;AASzB,IAAI,OAAO,MAAQ,OAAe,sBAAsB,KAAK;CAC3D,IAAI;EACF,IAAI,iBAAiB;GACnB,MAAM;GACN,QAAQ;GACR,UAAU;GACV,cAAc;EAChB,CAAC;CACH,QAAQ,CAER;CAKA,IAAI;EACF,IAAI,iBAAiB;GACnB,MAAM;GACN,QAAQ;GACR,UAAU;GACV,cAAc;EAChB,CAAC;CACH,QAAQ,CAER;AACF;AAGO,IAAM,IAAN,cAA0B,EAAW;;EAscF,aAncW,KAAA,OAAA,IACqC,KAAA,eAAA,IACM,KAAA,kBAAA,IAOrC,KAAA,aAAA,IAWnB,KAAA,aAAA,SAGA,KAAA,UAAA,IAEiB,KAAA,WAAA,IAMA,KAAA,WAAA,IAMc,KAAA,cAAA,IAOJ,KAAA,YAAA,IAMxC,KAAA,iBAAA,IACA,KAAA,iBAAA,IACU,KAAA,kBAAA,IAAI,EAAqB,GAC7B,KAAA,cAAA,EAAsB,CAAC,CAAC,KAAK,GAC/B,KAAA,YAAA,EAA2B,CAAC,CAAC,KAAK;GAC7D,iBAAiB,KAAK;GACtB,mBAAmB,KAAK;GACxB,cAAc,KAAK;EACrB,CAAC,GAEgC,KAAA,gBAAA,EAAyB,CAAC,CAAC,KAAK;GAC/D,iBAAiB,KAAK;GACtB,oBAAoB,KAAK;EAC3B,CAAC,GAGgD,KAAA,eAAA,MAEpB,KAAA,qBAAA,GACP,KAAA,cAAA,GACqB,KAAA,iBAAA,MAEb,KAAA,sBAAA,IAsPuB,KAAA,oCAAA;GAEnD,IADA,KAAK,oBAAoB,KAAA,GACrB,CAAC,KAAK,uBAAuB,CAAC,KAAK,QAAQ,KAAK,YAAY,GAAG;IACjE,KAAK,sBAAsB;IAC3B;GACF;GACA,KAAK,sBAAsB;GAE3B,IAAM,IAAS,KAAK;GACf,MACL,EAAO,UAAU,IAAI,YAAY,GAEjC,KAAK,eAAe,GAAQ,GAAG,KAAK,mBAAmB,CAAM,CAAC;EAChE,GAwHwC,KAAA,uBAAA;GACjC,SAAK,QAGN,MAAK,qBACT;QAAI,KAAK,YAAY;KACnB,KAAK,eAAe,EAAK;KACzB;IACF;IAGA,AADA,KAAK,gBAAgB,KAAK,GAC1B,KAAK,MAAM;GAHX;EAIF;;;EAjdyB,KAAA,SAAA,CAAC,EAAU,CAAK,GAAG,EAAU,CAAK,CAAC;;CAa5D,IACI,YAA6B;EAC/B,OAAO,KAAK;CACd;CACA,IAAI,UAAU,GAAW;EACvB,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,aAAa,EAAiB,GAAG,GAAoB,OAAO,GACjE,KAAK,cAAc,aAAa,CAAG;CACrC;CA2BA,IAAY,SAAS;EACnB,OAAO,KAAK,YAAY,cAAc,QAAQ,KAAK;CACrD;CA4BA,IAAY,YAAuB;EACjC,OAAO,KAAK,eAAe,UAAU,KAAK,eAAe,UAAU,MAAM;CAC3E;CAGA,IAAY,iBAAyB;EACnC,QAAQ,KAAK,YAAb;GACE,KAAK,SACH,OAAO;GACT,KAAK,QACH,OAAO;GACT,KAAK,OACH,OAAO;GACT,KAAK,UACH,OAAO;EACX;CACF;CAEA,mBAAmC;EACjC,IAAM,IAAS,KAAK;EAEpB,OADK,IACE,KAAK,cAAc,MAAM,EAAO,cAAc,EAAO,eADxC;CAEtB;CAIA,iBAAyB,GAAmC;EAC1D,IAAM,IAAM,iBAAiB,CAAM,CAAC,CAAC,iBAAiB,6BAA6B,GAC7E,IAAS,OAAO,WAAW,CAAG;EACpC,OAAO,OAAO,SAAS,CAAM,IAAI,IAAS;CAC5C;CAIA,mBAA2B,GAAmC;EAC5D,OAAO,KAAK,iBAAiB,IAAI,KAAK,iBAAiB,CAAM;CAC/D;CAEA,mBAAoC;EAGlC,IAAM,IAAQ,EAAiB,IAAI;EACnC,IAAI,GAAO,OAAO,EAAM,gBAAgB;EACxC,IAAI;GACF,OAAO,OAAO,OAAO,cAAe,cAAc,OAAO,WAAW,kCAAkC,CAAC,CAAC;EAC1G,QAAQ;GACN,OAAO;EACT;CACF;CAEA,cAA+B;EAC7B,OAAO,KAAK,cAAc,WAAW,KAAK;CAC5C;CAEA,mBAA2B;EAKzB,AAJI,KAAK,sBAAsB,KAAA,MAC7B,aAAa,KAAK,iBAAiB,GACnC,KAAK,oBAAoB,KAAA,IAE3B,KAAK,sBAAsB;CAC7B;CAEA,uBAA+B,GAAiB;EAG9C,IAFI,CAAC,KAAK,QAAQ,CAAC,KAAK,aAAa,KAAK,YAAY,KAElD,EAAE,cAAc,IAAO;EAE3B,IAAM,IAAS,KAAK;EAIpB,IAHI,CAAC,KAGD,CAAC,EAAO,UAAU,SAAS,YAAY,GAAG;EAG9C,IAAM,IAAmB,iBAAiB,CAAM,CAAC,CAAC,WAC5C,IACJ,KAAoB,MAAqB,UAAU,OAAO,qBAAsB,aAC5E,IAAI,kBAAkB,CAAgB,CAAC,CAAC,KAAK,cAAc,MAAM,QAAQ,SACzE;EASN,AARA,KAAK,gBAAgB,OAAO,GAC5B,KAAK,iBAAiB,MACtB,KAAK,iBAAiB,GAEtB,KAAK,qBAAqB,IAAY,KAAK,gBAC3C,KAAK,cAAc,KAAK,oBACxB,EAAO,UAAU,IAAI,aAAa,GAElC,KAAK,eAAe,EAAkB,GAAG;GACvC,MAAM,KAAK;GACX,SAAQ,MAAQ;IACd,IAAM,IAAe,KAAK,cAAc,MAAM,EAAK,SAAS,EAAK,QAE3D,IAAM,KAAK,qBAAqB,IAAe,KAAK;IAC1D,KAAK,cAAc,EAAW,GAAK,KAAK,iBAAiB,IAAI,IAAK,GAAI;IAGtE,IAAM,IAAW,KAAK,iBAAiB;IAEvC,AADA,EAAO,UAAU,OAAO,iBAAiB,IAAW,KAAK,KAAK,cAAc,IAAW,CAAgB,GACvG,KAAK,iBAAiB,GAAQ,KAAK,WAAW;GAChD;GACA,QAAO,MAAQ;IAEb,AADA,KAAK,eAAe,MACpB,EAAO,UAAU,OAAO,eAAe,eAAe;IACtD,IAAM,IAAO,KAAK,iBAAiB,GAC7B,KAAY,KAAK,cAAc,MAAM,EAAK,YAAY,EAAK,aAAa,KAAK;IAInF,AAFE,KAAK,cAAc,IAAO,KAAqB,KAAK,cAAc,KAAK,IAAW,IAEnE,KAAK,eAAe,GAAQ,CAAQ,IAChD,KAAK,eAAe,GAAQ,GAAU,KAAK,WAAW;GAC7D;GACA,gBAAgB;IAGd,AAFA,KAAK,eAAe,MACpB,EAAO,UAAU,OAAO,eAAe,eAAe,GACtD,KAAK,eAAe,GAAQ,GAAG,KAAK,WAAW;GACjD;EACF,CAAC;CACH;CAIA,oBAA4B;EAC1B,IAAI,CAAC,KAAK,YAAY,GAAG;EAEzB,AADA,KAAK,cAAc,QAAQ,GAC3B,KAAK,eAAe;EACpB,IAAM,IAAS,KAAK;EACf,MACL,EAAO,UAAU,OAAO,eAAe,eAAe,GACtD,KAAK,iBAAiB,CAAM;CAC9B;CAGA,iBAAyB,GAA2B,GAAgB;EAElE,IAAM,IAAQ,IADD,KAAK;EAElB,EAAO,MAAM,YAAY,KAAK,cAAc,MAAM,cAAc,EAAM,OAAO,cAAc,EAAM;EACjG,IAAM,IAAO,KAAK,iBAAiB,GAC7B,IAAW,IAAO,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,IAAS,CAAI,CAAC,IAAI;EACtE,EAAO,MAAM,YAAY,wCAAwC,OAAO,IAAI,CAAQ,CAAC;CACvF;CAEA,iBAAyB,GAA2B;EAElD,AADA,EAAO,MAAM,eAAe,WAAW,GACvC,EAAO,MAAM,eAAe,sCAAsC;CACpE;CAGA,eAAuB,GAA2B,GAAkB;EAClE,IAAM,IAAO,KAAK;EAClB,KAAK,cAAc;EACnB,IAAM,IAAO,KAAK,gBAGZ,IAAK,KAAK,mBAAmB,CAAM,GACnC,IAAO,KAAK,iBAAiB,GAE7B,UAAoB;GACxB,IAAI,KAAK,YAAY;IAEnB,IAAM,IAAW;IAGjB,AAFA,EAAO,MAAM,YACX,KAAK,cAAc,MAAM,cAAc,IAAW,EAAK,OAAO,cAAc,IAAW,EAAK,MAC9F,EAAO,MAAM,YAAY,wCAAwC,GAAG;GACtE,OAIE,AADA,EAAO,UAAU,OAAO,YAAY,GACpC,KAAK,iBAAiB,CAAM;GAE9B,KAAK,eAAe;EACtB;EAEA,IAAI,KAAK,iBAAiB,KAAK,OAAO,EAAO,WAAY,YAAY;GACnE,EAAY;GACZ;EACF;EAEA,IAAM,IAAU,EAAc,GAAM,GAAI,GAAU,EAAe,KAAK,GAChE,IAAY,EAAQ,KAAI,OAAM;GAClC,WAAW,KAAK,cAAc,MAAM,cAAc,IAAI,EAAK,OAAO,cAAc,IAAI,EAAK;GACzF,wCAAwC,OAAO,KAAK,IAAI,GAAG,IAAI,IAAI,CAAI,CAAC;EAC1E,EAAE,GAEI,KAAY,EAAQ,SAAS,KAAK,GAGlC,IAAY,EAAO,QAAQ,GAAW;GAAE;GAAU,QAAQ;GAAU,MAAM;EAAO,CAAC;EAExF,EAAU,iBAAiB;GAEzB,AADA,EAAU,OAAO,GACjB,EAAY;EACd;CACF;CAGA,eAAuB,GAA2B,GAAkB,GAAc;EAChF,KAAK,cAAc;EAEnB,IAAM,UAAsB;GAG1B,AAFA,KAAK,iBAAiB,MACtB,EAAO,UAAU,OAAO,aAAa,GACrC,KAAK,iBAAiB,CAAM;EAC9B;EAEA,IAAI,KAAK,iBAAiB,KAAK,OAAO,EAAO,WAAY,cAAc,KAAK,IAAI,CAAI,IAAI,GAAG;GACzF,EAAc;GACd;EACF;EAEA,IAAM,IAAO,KAAK,gBACZ,IAAO,KAAK,iBAAiB,GAC7B,IAAU,EAAc,GAAM,GAAG,GAAU,EAAe,OAAO,GACjE,IAAY,EAAQ,KAAI,OAAM;GAClC,WAAW,KAAK,cAAc,MAAM,cAAc,IAAI,EAAK,OAAO,cAAc,IAAI,EAAK;GACzF,wCAAwC,OAAO,KAAK,IAAI,GAAG,IAAI,IAAI,CAAI,CAAC;EAC1E,EAAE;EAEF,EAAO,UAAU,IAAI,aAAa;EAClC,IAAM,KAAY,EAAQ,SAAS,KAAK,GAIlC,IAAY,EAAO,QAAQ,GAAW;GAAE;GAAU,QAAQ;GAAU,MAAM;EAAO,CAAC;EAMxF,AAJA,EAAU,iBAAiB;GAEzB,AADA,EAAU,OAAO,GACjB,EAAc;EAChB,GACA,KAAK,iBAAiB;CACxB;CAEA,iBAAyB;EAIvB,AADA,KAAK,eAAe,GAChB,KAAK,eACP,KAAK,sBAAsB,IAC3B,KAAK,oBAAoB,WAAW,KAAK,6BAA6B,CAAsB;CAEhG;CAkBA,oBAA6B;EAG3B,AAFA,MAAM,kBAAkB,GACxB,KAAK,iBAAiB,MAAM,KAAK,KAAK,QAAQ,CAAC,CAAC,MAAK,MAAS,EAAM,eAAe,MAAM,MAAM,QAAQ,GACvG,KAAK,iBAAiB,MAAM,KAAK,KAAK,QAAQ,CAAC,CAAC,MAAK,MAAS,EAAM,eAAe,MAAM,MAAM,QAAQ;CACzG;CAEA,eAAwB;EACtB,KAAK,kBAAkB,QAAQ;CACjC;CAEA,uBAAgC;EAS9B,AARA,MAAM,qBAAqB,GAC3B,KAAK,cAAc,QAAQ,GAC3B,KAAK,cAAc,QAAQ,GAC3B,KAAK,eAAe,MACpB,KAAK,UAAU,QAAQ,GACvB,KAAK,YAAY,QAAQ,GACzB,KAAK,gBAAgB,OAAO,GAC5B,KAAK,iBAAiB,MACtB,KAAK,iBAAiB;CACxB;CAEA,kBAA0B,GAAc;EACtC,IAAM,IAAO,KAAK,YAAY,cAAc,cAAc,EAAK,GAAG;EAClE,IAAI,CAAC,GAAM;EACX,IAAM,IAAM,EAAK,cAAc,CAAC,CAAC,SAAS;EAC1C,AAAI,MAAS,YAAY,MAAQ,KAAK,mBACpC,KAAK,iBAAiB,GACtB,KAAK,cAAc;CAEvB;CAEA,uBAA+B,GAAU;EACvC,IAAM,IAAO,EAAE,OAA2B,cAAc,CAAC,CAAC,SAAS;EACnE,AAAI,MAAQ,KAAK,mBACf,KAAK,iBAAiB,GACtB,KAAK,cAAc;CAEvB;CAEA,uBAA+B,GAAU;EACvC,IAAM,IAAO,EAAE,OAA2B,cAAc,CAAC,CAAC,SAAS;EACnE,AAAI,MAAQ,KAAK,mBACf,KAAK,iBAAiB,GACtB,KAAK,cAAc;CAEvB;CAEA,QAA2B,GAAuB;EAChD,UAAM,QAAQ,CAAK,GACd,KAAK,aAEV;OAAI,EAAM,IAAI,MAAM,GAAG;IAOrB,IAJI,KAAK,YAAY,KAAK,CAAC,KAAK,QAAM,KAAK,kBAAkB,GACzD,KAAK,gBAAgB,QAAQ,KAAG,KAAK,eAAe,GAGpD,KAAK,qBAAqB;KAC5B,KAAK,iBAAiB;KACtB,IAAM,IAAS,KAAK;KACpB,AAAI,KAAU,CAAC,KAAK,QAClB,EAAO,UAAU,OAAO,YAAY,GACpC,KAAK,iBAAiB,CAAM,KACnB,KAAU,KAAK,QACxB,KAAK,eAAe,GAAQ,GAAG,KAAK,mBAAmB,CAAM,CAAC;IAElE;IAEA,AADA,KAAK,UAAU,KAAK,KAAK,IAAI,GACzB,KAAK,OAIP,KAAK,cAAc,SAAS,IAE5B,KAAK,cAAc,WAAW;GAElC;GACA,CAAI,EAAM,IAAI,MAAM,KAAK,EAAM,IAAI,cAAc,MAAG,KAAK,gBAAgB;EADzE;CAEF;CAEA,oBAA4B,GAAoB;EAC9C,KAAK,UAAU,oBAAoB,CAAC;CACtC;CAEA,cAAsB,GAAkB;EACtC,IAAI,EAAE,QAAQ,UAAU;EAMxB,IAAM,IAAO,EAAE,aAAa,GACtB,IAAiB,EAAK,QAAQ,EAAE,aAAqB;QACvD,IAAiB,KACI,EAAK,MAAM,GAAG,CAAc,CAAC,CAAC,MAAK,MAAK,aAAa,iBACxE,IAGN;OAAI,KAAK,YAAY,GAAG;IACtB,EAAE,eAAe;IACjB;GACF;GAEA,AADA,EAAE,eAAe,GACjB,KAAK,eAAe;EAFpB;CAGF;CAEA,OAAO;EACD,AACJ,KAAK,SAAO;CACd;CAEA,QAAQ;EACD,AACL,KAAK,SAAO;CACd;CAgBA,aAAqB,GAAU;EAG7B,AADA,EAAE,eAAe,GACjB,KAAK,eAAe;CACtB;CAEA,oBAA4B;EACrB,SAAK,MAIV;OAAI,KAAK,qBAAqB;IAC5B,KAAK,iBAAiB;IACtB;GACF;GAGA,IAAI,KAAK,YAAY;IAEnB,AADA,KAAK,UAAU,KAAK,EAAI,GACxB,KAAK,eAAe,EAAK;IACzB;GACF;GAIA,AAFA,KAAK,UAAU,kBAAkB,GACjC,KAAK,gBAAgB,KAAK,GAC1B,KAAK,OAAO;EAXZ;CAYF;CAEA,oBAA4B,GAAe;EACrC,EAAE,WAAY,EAAE,kBAChB,KAAK,mBAEL,KAAK,YAAY,KACrB,KAAK,eAAe;CACtB;CAEA,eAAuB,IAAO,KAAK,MAAM;EACvC,KAAK,cACH,IAAI,YAAY,eAAe;GAC7B,QAAQ,EAAE,QAAK;GACf,SAAS;GACT,UAAU;EACZ,CAAC,CACH;CACF;CAEA,gBAAwB,IAAS,KAAK,MAAM;EAC1C,KAAK,YAAY,KAAK,KAAU,CAAC,KAAK,YAAY;CACpD;CAEA,SAAkB;EAChB,IAAM,IAAa,KAAK,kBAAkB,CAAC,CAAC,KAAK,SAC3C,IAAc,KAAK,YAAY,KAAK,GACpC,IAAmB,CAAC,KAAe,CAAC,KAAK,YAAY,IAAa,uBAAuB,GAGzF,IAAU,KAAK,YACjB,CAAI;2DAC+C,KAAK,uBAAuB;;;YAI/E;EAGJ,OAAO,CAAI;;qBAEM,KAAe,EAAQ;0BAClB,EAAiB;kBACzB,KAAK,aAAa;iBACnB,KAAK,kBAAkB;iBACvB,KAAK,oBAAoB;mBACvB,KAAK,cAAc;yBACb,KAAK,oBAAoB;;UAGxC,KAAK,WACD,CAAI,gBAAgB,MACpB,CAAI;;mFAEiE,CAAC,EAAW;sDACzC,KAAK,uBAAuB;wBAC1D,KAAK,UAAU,CAAI,oCAAoC,KAAK,QAAQ,WAAW,EAAQ;;;;;;2DAMpD,CAAC,KAAK,eAAe;sDAC1B,KAAK,uBAAuB;;;kBAIhE,KAAK,WACD,CAAI;;;mCAGS,KAAK,eAAe;;;;;;yDAME,EAAU;;0BAG7C,EACL;kBACC,EAAQ;gBAEjB;;;CAGP;AAKF;AAvkBG,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;CAAM,WAAW;AAAiB,CAAC,CAAA,GAAA,EAAA,WAAA,gBAAA,KAAA,CAAA,GACtE,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;CAAM,WAAW;AAAoB,CAAC,CAAA,GAAA,EAAA,WAAA,mBAAA,KAAA,CAAA,GAOzE,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,cAAA,KAAA,CAAA,GAEzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,IAAA,GAYxC,EAAA,CAAA,EAAS,EAAE,MAAM,OAAO,CAAC,CAAA,GAAA,EAAA,WAAA,WAAA,KAAA,CAAA,GAEzB,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GAMzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GAMzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,WAAW;AAAe,CAAC,CAAA,GAAA,EAAA,WAAA,eAAA,KAAA,CAAA,GAOpD,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GAhD3C,IAAA,EAAA,CAAA,EAAc,eAAe,CAAA,GAAA,CAAA"}
|