@greypan/web-ui 2.1.1 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.CN.md +43 -39
  2. package/README.md +53 -48
  3. package/dist/assets/menu-portal.js +1 -1
  4. package/dist/assets/menu-portal.js.map +1 -1
  5. package/dist/assets/toast-containers.js +1 -1
  6. package/dist/assets/toast-containers.js.map +1 -1
  7. package/dist/components/back-top/index.d.ts +3 -1
  8. package/dist/components/back-top/index.js +16 -12
  9. package/dist/components/back-top/index.js.map +1 -1
  10. package/dist/components/back-top/style.js +1 -1
  11. package/dist/components/back-top/style.js.map +1 -1
  12. package/dist/components/context-menu/index.d.ts +3 -4
  13. package/dist/components/context-menu/index.js +55 -69
  14. package/dist/components/context-menu/index.js.map +1 -1
  15. package/dist/components/context-menu/style.js +1 -1
  16. package/dist/components/context-menu/style.js.map +1 -1
  17. package/dist/components/dialog/index.d.ts +4 -11
  18. package/dist/components/dialog/index.js +29 -53
  19. package/dist/components/dialog/index.js.map +1 -1
  20. package/dist/components/drawer/index.d.ts +4 -11
  21. package/dist/components/drawer/index.js +42 -63
  22. package/dist/components/drawer/index.js.map +1 -1
  23. package/dist/components/dropdown/index.d.ts +3 -3
  24. package/dist/components/dropdown/index.js +70 -78
  25. package/dist/components/dropdown/index.js.map +1 -1
  26. package/dist/components/dropdown/style.js +1 -1
  27. package/dist/components/dropdown/style.js.map +1 -1
  28. package/dist/components/dropdown-item/style.js +1 -1
  29. package/dist/components/dropdown-item/style.js.map +1 -1
  30. package/dist/components/option/style.js +1 -1
  31. package/dist/components/option/style.js.map +1 -1
  32. package/dist/components/popover/index.d.ts +2 -5
  33. package/dist/components/popover/index.js +47 -70
  34. package/dist/components/popover/index.js.map +1 -1
  35. package/dist/components/select/index.d.ts +4 -7
  36. package/dist/components/select/index.js +64 -74
  37. package/dist/components/select/index.js.map +1 -1
  38. package/dist/components/select/style.js +1 -1
  39. package/dist/components/select/style.js.map +1 -1
  40. package/dist/components/switch/style.js +1 -1
  41. package/dist/components/switch/style.js.map +1 -1
  42. package/dist/components/theme/style.js +1 -1
  43. package/dist/components/theme/style.js.map +1 -1
  44. package/dist/components/toast/manager.js +1 -1
  45. package/dist/components/toast/manager.js.map +1 -1
  46. package/dist/components/toast/toast.d.ts +1 -1
  47. package/dist/components/toast/toast.js +26 -26
  48. package/dist/components/toast/toast.js.map +1 -1
  49. package/dist/components/tooltip/index.d.ts +3 -5
  50. package/dist/components/tooltip/index.js +61 -70
  51. package/dist/components/tooltip/index.js.map +1 -1
  52. package/dist/icons/generated/ooui-close.d.ts +6 -0
  53. package/dist/icons/generated/ooui-close.js +10 -0
  54. package/dist/icons/generated/ooui-close.js.map +1 -0
  55. package/dist/icons/index.d.ts +1 -0
  56. package/dist/icons/index.js +2 -1
  57. package/dist/shared/menu-portal/menu-portal.js +8 -1
  58. package/dist/shared/menu-portal/menu-portal.js.map +1 -1
  59. package/dist/shared/menu-portal/menu-tree.js +29 -0
  60. package/dist/shared/menu-portal/menu-tree.js.map +1 -0
  61. package/dist/shared/overlay/anchored-panel.js +49 -0
  62. package/dist/shared/overlay/anchored-panel.js.map +1 -0
  63. package/dist/shared/overlay/native-dialog-presence.js +45 -0
  64. package/dist/shared/overlay/native-dialog-presence.js.map +1 -0
  65. package/dist/shared/overlay/overlay.js +5 -2
  66. package/dist/shared/overlay/overlay.js.map +1 -1
  67. package/dist/shared/overlay/portal.js +3 -3
  68. package/dist/shared/overlay/portal.js.map +1 -1
  69. package/dist/shared/overlay/presence.js +1 -1
  70. package/dist/shared/overlay/presence.js.map +1 -1
  71. package/dist/shared/scroll-lock/scroll-lock.js +15 -1
  72. package/dist/shared/scroll-lock/scroll-lock.js.map +1 -1
  73. package/dist/types/vue.d.ts +2 -1
  74. package/package.json +1 -1
  75. package/dist/shared/property-converters/boolean-with-false-string.js +0 -9
  76. package/dist/shared/property-converters/boolean-with-false-string.js.map +0 -1
@@ -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 { getTransitionDuration } from '@/shared/overlay/presence'\nimport { booleanWithFalseString } from '@/shared/property-converters/boolean-with-false-string'\nimport { lockScroll, unlockScroll } 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({ reflect: true, attribute: 'lock-scroll', converter: booleanWithFalseString }) lockScroll = true\n @property({ reflect: true, attribute: 'overlay-closable', converter: booleanWithFalseString }) overlayClosable = true\n\n @state() private _hasBody = false\n\n private _hasScrollLock = false\n private _closeFallbackTimer?: ReturnType<typeof setTimeout>\n private _openFrame?: number\n private _isClosing = false\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 this.emitOpenChange()\n if (this.open) this._startOpening()\n else this._startClosing()\n }\n if (props.has('open') || props.has('lockScroll')) this._syncScrollLock()\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._cancelOpenFrame()\n this._clearCloseFallback()\n this._syncScrollLock(false)\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 this.close()\n }\n\n private handleBackdropClick(e: MouseEvent) {\n if (e.target !== (e.currentTarget as HTMLDialogElement)) return\n if (!this.overlayClosable) return\n this.close()\n }\n\n private emitOpenChange() {\n this.dispatchEvent(\n new CustomEvent('open-change', {\n detail: { open: this.open },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private _startOpening() {\n const dialog = this.dialog\n if (!dialog) return\n\n this._isClosing = false\n this._clearCloseFallback()\n dialog.classList.remove('is-closing')\n if (!dialog.open) dialog.showModal?.()\n\n this._cancelOpenFrame()\n this._openFrame = requestAnimationFrame(() => {\n this._openFrame = undefined\n if (!this.isConnected || !this.open || !dialog.open) return\n dialog.classList.add('is-visible')\n })\n }\n\n private _startClosing() {\n const dialog = this.dialog\n if (!dialog?.open) return\n\n this._cancelOpenFrame()\n this._isClosing = true\n if (!dialog.classList.contains('is-visible')) {\n this._finishClosing()\n return\n }\n\n dialog.classList.add('is-closing')\n dialog.classList.remove('is-visible')\n this._clearCloseFallback()\n this._closeFallbackTimer = setTimeout(() => this._finishClosing(), getTransitionDuration(dialog) + 80)\n }\n\n private _finishClosing() {\n const dialog = this.dialog\n if (!dialog || !this._isClosing || this.open) return\n\n this._clearCloseFallback()\n this._isClosing = false\n dialog.classList.remove('is-closing', 'is-visible')\n if (dialog.open) dialog.close?.()\n }\n\n private _clearCloseFallback() {\n if (this._closeFallbackTimer === undefined) return\n clearTimeout(this._closeFallbackTimer)\n this._closeFallbackTimer = undefined\n }\n\n private _cancelOpenFrame() {\n if (this._openFrame === undefined) return\n cancelAnimationFrame(this._openFrame)\n this._openFrame = undefined\n }\n\n private _onTransitionEnd = (event: TransitionEvent) => {\n if (event.target !== this.dialog || event.propertyName !== 'transform') return\n this._finishClosing()\n }\n\n private _onNativeClose = () => {\n if (!this.open) return\n this._cancelOpenFrame()\n this._clearCloseFallback()\n this._isClosing = false\n this.dialog?.classList.remove('is-closing', 'is-visible')\n this.open = false\n }\n\n private _syncScrollLock(isOpen = this.open) {\n const shouldLock = isOpen && this.lockScroll\n if (shouldLock === this._hasScrollLock) return\n\n if (shouldLock) lockScroll()\n else unlockScroll()\n this._hasScrollLock = shouldLock\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 ${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 </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
+ {"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 { defineNativeDialogPresence } from '@/shared/overlay/native-dialog-presence'\nimport { createScrollLockLease } 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\n @state() private _hasBody = false\n\n private readonly _scrollLock = createScrollLockLease()\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 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 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.close()\n }\n\n private emitOpenChange() {\n this.dispatchEvent(\n new CustomEvent('open-change', {\n detail: { open: this.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 this._presence.handleNativeClose()\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 ${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 </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":";;;;;;;;;AAWO,IAAM,IAAN,cAA0B,EAAW;;EAyEX,aAtEoB,KAAA,OAAA,IACqC,KAAA,eAAA,IACM,KAAA,kBAAA,IAElE,KAAA,WAAA,IAEG,KAAA,cAAA,EAAsB,GACxB,KAAA,YAAA,EAA2B,CAAC,CAAC,KAAK;GAC7D,iBAAiB,KAAK;GACtB,mBAAmB,KAAK;GACxB,cAAc,KAAK;EACrB,CAAC,GAuD2B,KAAA,oBAAA,MAA2B;GACrD,KAAK,UAAU,oBAAoB,CAAK;EAC1C,GAE+B,KAAA,uBAAA;GACxB,AAEL,KAAK,UADL,KAAK,UAAU,kBAAkB,GACrB;EACd;;;EA5EyB,KAAA,SAAA,CAAC,EAAU,CAAK,GAAG,EAAU,CAAK,CAAC;;CAe5D,IAAY,SAAS;EACnB,OAAO,KAAK,YAAY,cAAc,QAAQ,KAAK;CACrD;CAEA,QAA2B,GAAuB;EAChD,MAAM,QAAQ,CAAK,GACd,KAAK,gBAEN,EAAM,IAAI,MAAM,MAClB,KAAK,eAAe,GACpB,KAAK,UAAU,KAAK,KAAK,IAAI,KAE3B,EAAM,IAAI,MAAM,KAAK,EAAM,IAAI,cAAc,MAAG,KAAK,gBAAgB;CAC3E;CAEA,uBAAgC;EAG9B,AAFA,MAAM,qBAAqB,GAC3B,KAAK,UAAU,QAAQ,GACvB,KAAK,YAAY,QAAQ;CAC3B;CAGA,YAAY;EACN,AACJ,KAAK,SAAO;CACd;CAEA,QAAQ;EACN,KAAK,OAAO;CACd;CAEA,aAAqB,GAAU;EAG7B,AADA,EAAE,eAAe,GACjB,KAAK,MAAM;CACb;CAEA,oBAA4B,GAAe;EACrC,EAAE,WAAY,EAAE,kBAChB,KAAK,mBACT,KAAK,MAAM;CACb;CAEA,iBAAyB;EACvB,KAAK,cACH,IAAI,YAAY,eAAe;GAC7B,QAAQ,EAAE,MAAM,KAAK,KAAK;GAC1B,SAAS;GACT,UAAU;EACZ,CAAC,CACH;CACF;CAYA,gBAAwB,IAAS,KAAK,MAAM;EAC1C,KAAK,YAAY,KAAK,KAAU,CAAC,KAAK,YAAY;CACpD;CAEA,kBAA0B,GAAU;EAC5B,EAAE,kBAAkB,oBAC1B,KAAK,WAAW,EAAE,OAAO,iBAAiB,CAAC,CAAC,SAAS;CACvD;CAEA,SAAkB;EAChB,OAAO,CAAI;;kBAEG,KAAK,aAAa;iBACnB,KAAK,eAAe;iBACpB,KAAK,oBAAoB;yBACjB,KAAK,iBAAiB;;;YAGnC,KAAK,WACH,CAAI,iCAAiC,KAAK,kBAAkB,YAC5D,CAAI;gDAC8B,KAAK,kBAAkB;;;;gBAIvD;;;;CAId;AAKF;AA9GG,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,GAEzE,EAAA,CAAA,EAAM,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GARR,IAAA,EAAA,CAAA,EAAc,eAAe,CAAA,GAAA,CAAA"}
@@ -4,8 +4,8 @@ export type DrawerPlacement = (typeof ALLOWED_PLACEMENTS)[number];
4
4
  export declare class WebUiDrawer extends LitElement {
5
5
  static styles: import('lit').CSSResult[];
6
6
  open: boolean;
7
- lockScroll: boolean;
8
- overlayClosable: boolean;
7
+ noScrollLock: boolean;
8
+ noBackdropClose: boolean;
9
9
  get placement(): DrawerPlacement;
10
10
  set placement(v: string);
11
11
  private _placement;
@@ -13,12 +13,10 @@ export declare class WebUiDrawer extends LitElement {
13
13
  heading: string;
14
14
  closable: boolean;
15
15
  private get dialog();
16
- private _closeFallbackTimer;
17
- private _openFrame;
18
- private _isClosing;
19
16
  private _hasHeaderSlot;
20
17
  private _hasFooterSlot;
21
- private _hasScrollLock;
18
+ private readonly _scrollLock;
19
+ private readonly _presence;
22
20
  connectedCallback(): void;
23
21
  firstUpdated(): void;
24
22
  disconnectedCallback(): void;
@@ -26,11 +24,6 @@ export declare class WebUiDrawer extends LitElement {
26
24
  private handleHeaderSlotChange;
27
25
  private handleFooterSlotChange;
28
26
  protected updated(props: PropertyValues): void;
29
- private _startOpening;
30
- private _startClosing;
31
- private _finishClosing;
32
- private _clearCloseFallback;
33
- private _cancelOpenFrame;
34
27
  private handleTransitionEnd;
35
28
  private handleKeydown;
36
29
  /** 打开抽屉(命令式) */
@@ -1,34 +1,37 @@
1
1
  import e from "../../_virtual/_@oxc-project_runtime@0.140.0/helpers/esm/decorate.js";
2
2
  import "../icon/index.js";
3
3
  import t from "../../assets/glass.js";
4
- import n from "../../icons/generated/lucide-x.js";
4
+ import n from "../../icons/generated/ooui-close.js";
5
5
  import { normalizeLiteral as r } from "../../shared/normalize/index.js";
6
6
  import "../button/index.js";
7
- import { booleanWithFalseString as i } from "../../shared/property-converters/boolean-with-false-string.js";
8
- import { getTransitionDuration as a } from "../../shared/overlay/presence.js";
9
- import { lockScroll as o, unlockScroll as s } from "../../shared/scroll-lock/scroll-lock.js";
10
- import c from "./style.js";
11
- import { LitElement as l, html as u, nothing as d, unsafeCSS as f } from "lit";
12
- import { customElement as p, property as m } from "lit/decorators.js";
7
+ import { createScrollLockLease as i } from "../../shared/scroll-lock/scroll-lock.js";
8
+ import { defineNativeDialogPresence as a } from "../../shared/overlay/native-dialog-presence.js";
9
+ import o from "./style.js";
10
+ import { LitElement as s, html as c, nothing as l, unsafeCSS as u } from "lit";
11
+ import { customElement as d, property as f } from "lit/decorators.js";
13
12
  //#region src/components/drawer/index.ts
14
- var h = [
13
+ var p = [
15
14
  "right",
16
15
  "left",
17
16
  "top",
18
17
  "bottom"
19
- ], g = class extends l {
18
+ ], m = class extends s {
20
19
  constructor(...e) {
21
- super(...e), this.open = !1, this.lockScroll = !0, this.overlayClosable = !0, this._placement = "right", this.heading = "", this.closable = !1, this._closeFallbackTimer = null, this._openFrame = null, this._isClosing = !1, this._hasHeaderSlot = !1, this._hasFooterSlot = !1, this._hasScrollLock = !1;
20
+ super(...e), this.open = !1, this.noScrollLock = !1, this.noBackdropClose = !1, this._placement = "right", this.heading = "", this.closable = !1, this._hasHeaderSlot = !1, this._hasFooterSlot = !1, this._scrollLock = i(), this._presence = a().make({
21
+ getDialog: () => this.dialog,
22
+ isConnected: () => this.isConnected,
23
+ isOpen: () => this.open
24
+ });
22
25
  }
23
26
  static {
24
- this.styles = [f(t), f(c)];
27
+ this.styles = [u(t), u(o)];
25
28
  }
26
29
  get placement() {
27
30
  return this._placement;
28
31
  }
29
32
  set placement(e) {
30
33
  let t = this._placement;
31
- this._placement = r(e, h, "right"), this.requestUpdate("placement", t);
34
+ this._placement = r(e, p, "right"), this.requestUpdate("placement", t);
32
35
  }
33
36
  get dialog() {
34
37
  return this.shadowRoot?.querySelector("dialog") ?? null;
@@ -40,7 +43,7 @@ var h = [
40
43
  this._checkSlotContent("footer");
41
44
  }
42
45
  disconnectedCallback() {
43
- super.disconnectedCallback(), this._cancelOpenFrame(), this._clearCloseFallback(), this._syncScrollLock(!1);
46
+ super.disconnectedCallback(), this._presence.dispose(), this._scrollLock.release();
44
47
  }
45
48
  _checkSlotContent(e) {
46
49
  let t = this.shadowRoot?.querySelector(`slot[name="${e}"]`);
@@ -57,36 +60,10 @@ var h = [
57
60
  t !== this._hasFooterSlot && (this._hasFooterSlot = t, this.requestUpdate());
58
61
  }
59
62
  updated(e) {
60
- super.updated(e), this.isConnected && (e.has("open") && (this.emitOpenChange(), this.open ? this._startOpening() : this._startClosing()), (e.has("open") || e.has("lockScroll")) && this._syncScrollLock());
61
- }
62
- _startOpening() {
63
- let e = this.dialog;
64
- e && (this._isClosing = !1, this._clearCloseFallback(), e.classList.remove("is-closing"), e.open || e.showModal?.(), this._cancelOpenFrame(), this._openFrame = requestAnimationFrame(() => {
65
- this._openFrame = null, !(!this.isConnected || !this.open || !e.open) && e.classList.add("is-visible");
66
- }));
67
- }
68
- _startClosing() {
69
- let e = this.dialog;
70
- if (e?.open) {
71
- if (this._cancelOpenFrame(), this._isClosing = !0, !e.classList.contains("is-visible")) {
72
- this._finishClosing();
73
- return;
74
- }
75
- e.classList.add("is-closing"), e.classList.remove("is-visible"), this._clearCloseFallback(), this._closeFallbackTimer = setTimeout(() => this._finishClosing(), a(e) + 80);
76
- }
77
- }
78
- _finishClosing() {
79
- let e = this.dialog;
80
- !e || !this._isClosing || this.open || (this._clearCloseFallback(), this._isClosing = !1, e.classList.remove("is-closing", "is-visible"), e.open && e.close?.());
81
- }
82
- _clearCloseFallback() {
83
- this._closeFallbackTimer &&= (clearTimeout(this._closeFallbackTimer), null);
84
- }
85
- _cancelOpenFrame() {
86
- this._openFrame !== null && (cancelAnimationFrame(this._openFrame), this._openFrame = null);
63
+ super.updated(e), this.isConnected && (e.has("open") && (this.emitOpenChange(), this._presence.sync(this.open)), (e.has("open") || e.has("noScrollLock")) && this._syncScrollLock());
87
64
  }
88
65
  handleTransitionEnd(e) {
89
- e.target === this.dialog && e.propertyName === "transform" && this._finishClosing();
66
+ this._presence.handleTransitionEnd(e);
90
67
  }
91
68
  handleKeydown(e) {
92
69
  e.key === "Escape" && (e.preventDefault(), this.close());
@@ -101,10 +78,10 @@ var h = [
101
78
  e.preventDefault(), this.close();
102
79
  }
103
80
  handleNativeClose() {
104
- this.open &&= (this._cancelOpenFrame(), this._clearCloseFallback(), this._isClosing = !1, this.dialog?.classList.remove("is-closing", "is-visible"), !1);
81
+ this.open &&= (this._presence.handleNativeClose(), !1);
105
82
  }
106
83
  handleBackdropClick(e) {
107
- e.target === e.currentTarget && this.overlayClosable && this.close();
84
+ e.target === e.currentTarget && (this.noBackdropClose || this.close());
108
85
  }
109
86
  emitOpenChange() {
110
87
  this.dispatchEvent(new CustomEvent("open-change", {
@@ -114,12 +91,11 @@ var h = [
114
91
  }));
115
92
  }
116
93
  _syncScrollLock(e = this.open) {
117
- let t = e && this.lockScroll;
118
- t !== this._hasScrollLock && (t ? o() : s(), this._hasScrollLock = t);
94
+ this._scrollLock.sync(e && !this.noScrollLock);
119
95
  }
120
96
  render() {
121
97
  let e = this._hasHeaderSlot || !!this.heading;
122
- return u`
98
+ return c`
123
99
  <dialog
124
100
  @cancel=${this.handleCancel}
125
101
  @close=${this.handleNativeClose}
@@ -128,13 +104,13 @@ var h = [
128
104
  @transitionend=${this.handleTransitionEnd}
129
105
  >
130
106
  <div class="wui-drawer-body wui-glass">
131
- ${e ? u`
107
+ ${e ? c`
132
108
  <div class="wui-drawer-header">
133
109
  <slot name="header" @slotchange=${this.handleHeaderSlotChange}>
134
- ${this.heading ? u`<span class="wui-drawer-heading">${this.heading}</span>` : d}
110
+ ${this.heading ? c`<span class="wui-drawer-heading">${this.heading}</span>` : l}
135
111
  </slot>
136
112
  </div>
137
- ` : d}
113
+ ` : l}
138
114
  <div class="wui-drawer-content">
139
115
  <slot></slot>
140
116
  </div>
@@ -142,31 +118,34 @@ var h = [
142
118
  <slot name="footer" @slotchange=${this.handleFooterSlotChange}></slot>
143
119
  </div>
144
120
  </div>
145
- ${this.closable ? u`
146
- <web-ui-button class="wui-drawer-close" @click=${this.close} aria-label="关闭" icon>
147
- <web-ui-icon .icon=${n} size="16"></web-ui-icon>
121
+ ${this.closable ? c`
122
+ <web-ui-button class="wui-drawer-close" @click=${this.close} aria-label="关闭" variant="secondary" icon>
123
+ <web-ui-icon .icon=${n}></web-ui-icon>
148
124
  </web-ui-button>
149
- ` : d}
125
+ ` : l}
150
126
  </dialog>
151
127
  `;
152
128
  }
153
129
  };
154
- e([m({
130
+ e([f({
155
131
  type: Boolean,
156
132
  reflect: !0
157
- })], g.prototype, "open", void 0), e([m({
133
+ })], m.prototype, "open", void 0), e([f({
134
+ type: Boolean,
158
135
  reflect: !0,
159
- attribute: "lock-scroll",
160
- converter: i
161
- })], g.prototype, "lockScroll", void 0), e([m({
136
+ attribute: "no-scroll-lock"
137
+ })], m.prototype, "noScrollLock", void 0), e([f({
138
+ type: Boolean,
162
139
  reflect: !0,
163
- attribute: "overlay-closable",
164
- converter: i
165
- })], g.prototype, "overlayClosable", void 0), e([m({ reflect: !0 })], g.prototype, "placement", null), e([m({ type: String })], g.prototype, "heading", void 0), e([m({
140
+ attribute: "no-backdrop-close"
141
+ })], m.prototype, "noBackdropClose", void 0), e([f({
142
+ type: String,
143
+ reflect: !0
144
+ })], m.prototype, "placement", null), e([f({ type: String })], m.prototype, "heading", void 0), e([f({
166
145
  type: Boolean,
167
146
  reflect: !0
168
- })], g.prototype, "closable", void 0), g = e([p("web-ui-drawer")], g);
147
+ })], m.prototype, "closable", void 0), m = e([d("web-ui-drawer")], m);
169
148
  //#endregion
170
- export { g as WebUiDrawer };
149
+ export { m as WebUiDrawer };
171
150
 
172
151
  //# 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 { lucideX } from '@/icons'\nimport { normalizeLiteral } from '@/shared/normalize'\nimport { getTransitionDuration } from '@/shared/overlay/presence'\nimport { booleanWithFalseString } from '@/shared/property-converters/boolean-with-false-string'\nimport { lockScroll, unlockScroll } 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({ reflect: true, attribute: 'lock-scroll', converter: booleanWithFalseString }) lockScroll = true\n @property({ reflect: true, attribute: 'overlay-closable', converter: booleanWithFalseString }) overlayClosable = true\n @property({ 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 private get dialog() {\n return this.shadowRoot?.querySelector('dialog') ?? null\n }\n\n private _closeFallbackTimer: ReturnType<typeof setTimeout> | null = null\n private _openFrame: number | null = null\n private _isClosing = false\n private _hasHeaderSlot = false\n private _hasFooterSlot = false\n private _hasScrollLock = false\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._cancelOpenFrame()\n this._clearCloseFallback()\n this._syncScrollLock(false)\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 this.emitOpenChange()\n if (this.open) this._startOpening()\n else this._startClosing()\n }\n if (props.has('open') || props.has('lockScroll')) this._syncScrollLock()\n }\n\n private _startOpening() {\n const dialog = this.dialog\n if (!dialog) return\n\n this._isClosing = false\n this._clearCloseFallback()\n dialog.classList.remove('is-closing')\n if (!dialog.open) dialog.showModal?.()\n\n this._cancelOpenFrame()\n this._openFrame = requestAnimationFrame(() => {\n this._openFrame = null\n if (!this.isConnected || !this.open || !dialog.open) return\n dialog.classList.add('is-visible')\n })\n }\n\n private _startClosing() {\n const dialog = this.dialog\n if (!dialog?.open) return\n\n this._cancelOpenFrame()\n this._isClosing = true\n\n // 还未进入可见帧时没有可过渡的视觉状态,直接释放原生 dialog。\n if (!dialog.classList.contains('is-visible')) {\n this._finishClosing()\n return\n }\n\n dialog.classList.add('is-closing')\n dialog.classList.remove('is-visible')\n this._clearCloseFallback()\n this._closeFallbackTimer = setTimeout(() => this._finishClosing(), getTransitionDuration(dialog) + 80)\n }\n\n private _finishClosing() {\n const dialog = this.dialog\n if (!dialog || !this._isClosing || this.open) return\n\n this._clearCloseFallback()\n this._isClosing = false\n dialog.classList.remove('is-closing', 'is-visible')\n if (dialog.open) dialog.close?.()\n }\n\n private _clearCloseFallback() {\n if (!this._closeFallbackTimer) return\n clearTimeout(this._closeFallbackTimer)\n this._closeFallbackTimer = null\n }\n\n private _cancelOpenFrame() {\n if (this._openFrame === null) return\n cancelAnimationFrame(this._openFrame)\n this._openFrame = null\n }\n\n private handleTransitionEnd(e: TransitionEvent) {\n if (e.target !== this.dialog || e.propertyName !== 'transform') return\n this._finishClosing()\n }\n\n private handleKeydown(e: KeyboardEvent) {\n if (e.key !== 'Escape') return\n e.preventDefault()\n this.close()\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 handleCancel(e: Event) {\n // 保留 top layer 直到 CSS 过渡结束,避免原生关闭跳过退出动画。\n e.preventDefault()\n this.close()\n }\n\n private handleNativeClose() {\n if (!this.open) return\n\n // 原生关闭可绕过 cancel;同步受控状态,避免 show() 误判为已打开。\n this._cancelOpenFrame()\n this._clearCloseFallback()\n this._isClosing = false\n this.dialog?.classList.remove('is-closing', 'is-visible')\n this.open = false\n }\n\n private handleBackdropClick(e: MouseEvent) {\n if (e.target !== (e.currentTarget as HTMLDialogElement)) return\n if (!this.overlayClosable) return\n this.close()\n }\n\n private emitOpenChange() {\n this.dispatchEvent(\n new CustomEvent('open-change', {\n detail: { open: this.open },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private _syncScrollLock(isOpen = this.open) {\n const shouldLock = isOpen && this.lockScroll\n if (shouldLock === this._hasScrollLock) return\n\n if (shouldLock) lockScroll()\n else unlockScroll()\n this._hasScrollLock = shouldLock\n }\n\n override render() {\n const showHeader = this._hasHeaderSlot || !!this.heading\n\n return html`\n <dialog\n @cancel=${this.handleCancel}\n @close=${this.handleNativeClose}\n @click=${this.handleBackdropClick}\n @keydown=${this.handleKeydown}\n @transitionend=${this.handleTransitionEnd}\n >\n <div class=\"wui-drawer-body wui-glass\">\n ${showHeader\n ? html`\n <div class=\"wui-drawer-header\">\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 `\n : nothing}\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 ${this.closable\n ? html`\n <web-ui-button class=\"wui-drawer-close\" @click=${this.close} aria-label=\"关闭\" icon>\n <web-ui-icon .icon=${lucideX} size=\"16\"></web-ui-icon>\n </web-ui-button>\n `\n : nothing}\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 { normalizeLiteral } from '@/shared/normalize'\nimport { defineNativeDialogPresence } from '@/shared/overlay/native-dialog-presence'\nimport { createScrollLockLease } 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 @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 private get dialog() {\n return this.shadowRoot?.querySelector('dialog') ?? null\n }\n\n private _hasHeaderSlot = false\n private _hasFooterSlot = false\n private readonly _scrollLock = createScrollLockLease()\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 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.close()\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 handleCancel(e: Event) {\n // 保留 top layer 直到 CSS 过渡结束,避免原生关闭跳过退出动画。\n e.preventDefault()\n this.close()\n }\n\n private handleNativeClose() {\n if (!this.open) return\n\n // 原生关闭可绕过 cancel;同步受控状态,避免 show() 误判为已打开。\n this._presence.handleNativeClose()\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.close()\n }\n\n private emitOpenChange() {\n this.dispatchEvent(\n new CustomEvent('open-change', {\n detail: { open: this.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\n return html`\n <dialog\n @cancel=${this.handleCancel}\n @close=${this.handleNativeClose}\n @click=${this.handleBackdropClick}\n @keydown=${this.handleKeydown}\n @transitionend=${this.handleTransitionEnd}\n >\n <div class=\"wui-drawer-body wui-glass\">\n ${showHeader\n ? html`\n <div class=\"wui-drawer-header\">\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 `\n : nothing}\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 ${this.closable\n ? html`\n <web-ui-button class=\"wui-drawer-close\" @click=${this.close} aria-label=\"关闭\" variant=\"secondary\" icon>\n <web-ui-icon .icon=${oouiClose}></web-ui-icon>\n </web-ui-button>\n `\n : nothing}\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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"}
@@ -2,11 +2,11 @@ import { Placement } from '@floating-ui/dom';
2
2
  import { LitElement } from 'lit';
3
3
  export type { Placement };
4
4
  export declare class WebUiDropdown extends LitElement {
5
- static styles: import('lit').CSSResult[];
5
+ static styles: import('lit').CSSResult;
6
6
  open: boolean;
7
7
  disabled: boolean;
8
8
  matchWidth: boolean;
9
- lockScroll: boolean;
9
+ noScrollLock: boolean;
10
10
  private _placement;
11
11
  get placement(): Placement;
12
12
  set placement(v: string);
@@ -20,7 +20,7 @@ export declare class WebUiDropdown extends LitElement {
20
20
  private _ignoreOutsideClick;
21
21
  private _ignoreOutsideClickTimer?;
22
22
  private _hoverCleanupFns;
23
- private _hasScrollLock;
23
+ private readonly _scrollLock;
24
24
  private _restoreFocusTarget?;
25
25
  private _shouldOpenInstantly;
26
26
  get isOpen(): boolean;