@greypan/web-ui 7.0.0 → 8.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 +80 -13
- package/README.md +80 -13
- package/dist/components/autocomplete/index.d.ts +17 -5
- package/dist/components/autocomplete/index.js +136 -101
- 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/avatar/index.js +4 -4
- package/dist/components/button/index.js +15 -15
- package/dist/components/button-group/index.js +5 -5
- package/dist/components/checkbox/index.js +11 -11
- package/dist/components/checkbox-group/index.js +8 -8
- package/dist/components/context-menu/index.js +4 -1
- package/dist/components/context-menu/index.js.map +1 -1
- package/dist/components/dialog/index.js +11 -8
- package/dist/components/dialog/index.js.map +1 -1
- package/dist/components/drawer/index.js +11 -8
- package/dist/components/drawer/index.js.map +1 -1
- package/dist/components/dropdown/index.js +4 -1
- package/dist/components/dropdown/index.js.map +1 -1
- package/dist/components/editable-text/index.d.ts +471 -0
- package/dist/components/editable-text/index.js +206 -0
- package/dist/components/editable-text/index.js.map +1 -0
- package/dist/components/editable-text/style.js +6 -0
- package/dist/components/editable-text/style.js.map +1 -0
- package/dist/components/image-preview/index.js +21 -18
- package/dist/components/image-preview/index.js.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +39 -38
- package/dist/components/input/index.d.ts +2 -0
- package/dist/components/input/index.js +11 -5
- package/dist/components/input/index.js.map +1 -1
- package/dist/components/input-number/index.js +15 -15
- package/dist/components/layout/index.js +7 -7
- package/dist/components/layout/style.js +1 -1
- package/dist/components/layout/style.js.map +1 -1
- package/dist/components/popover/index.js +13 -10
- package/dist/components/popover/index.js.map +1 -1
- package/dist/components/radio/index.js +9 -9
- package/dist/components/radio-group/index.js +8 -8
- package/dist/components/segmented/index.d.ts +4 -1
- package/dist/components/segmented/index.js +42 -29
- 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/style.js +1 -1
- package/dist/components/segmented-trigger/style.js.map +1 -1
- package/dist/components/select/index.js +35 -32
- package/dist/components/select/index.js.map +1 -1
- package/dist/components/slider/index.js +11 -11
- package/dist/components/switch/index.js +12 -12
- package/dist/components/textarea/index.js +5 -5
- package/dist/components/theme/index.d.ts +1 -3
- package/dist/components/theme/index.js +51 -54
- package/dist/components/theme/index.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/toast.js +13 -13
- package/dist/components/tooltip/index.js +12 -9
- package/dist/components/tooltip/index.js.map +1 -1
- package/dist/shared/option-portal/combobox-shell.js +47 -5
- package/dist/shared/option-portal/combobox-shell.js.map +1 -1
- package/dist/shared/option-portal/index.js +9 -9
- package/dist/shared/overlay/anchored-panel.js +2 -2
- package/dist/shared/overlay/anchored-panel.js.map +1 -1
- package/dist/shared/overlay/open-overlay.js +38 -22
- package/dist/shared/overlay/open-overlay.js.map +1 -1
- package/dist/shared/theme/root-sync.js +42 -0
- package/dist/shared/theme/root-sync.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import e from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
2
2
|
import "../icon/index.js";
|
|
3
|
-
import t from "../../
|
|
4
|
-
import n from "../../icons/generated/lucide-
|
|
5
|
-
import r from "../../icons/generated/lucide-
|
|
6
|
-
import i from "../../icons/generated/lucide-
|
|
7
|
-
import a from "../../icons/generated/
|
|
8
|
-
import o from "../../
|
|
9
|
-
import { getTransitionDuration as s } from "../../shared/overlay/presence.js";
|
|
3
|
+
import t from "../../assets/glass.js";
|
|
4
|
+
import n from "../../icons/generated/lucide-check.js";
|
|
5
|
+
import r from "../../icons/generated/lucide-info.js";
|
|
6
|
+
import i from "../../icons/generated/lucide-triangle-alert.js";
|
|
7
|
+
import a from "../../icons/generated/lucide-circle-alert.js";
|
|
8
|
+
import o from "../../icons/generated/heroicons-x-mark-16-solid.js";
|
|
10
9
|
import "../button/index.js";
|
|
10
|
+
import { getTransitionDuration as s } from "../../shared/overlay/presence.js";
|
|
11
11
|
import c from "./style.js";
|
|
12
12
|
import { LitElement as l, html as u, nothing as d, unsafeCSS as f } from "lit";
|
|
13
13
|
import { customElement as p, property as m } from "lit/decorators.js";
|
|
14
14
|
//#region src/components/toast/toast.ts
|
|
15
15
|
var h = {
|
|
16
|
-
success:
|
|
17
|
-
info:
|
|
18
|
-
warning:
|
|
19
|
-
error:
|
|
16
|
+
success: n,
|
|
17
|
+
info: r,
|
|
18
|
+
warning: i,
|
|
19
|
+
error: a
|
|
20
20
|
};
|
|
21
21
|
function g() {
|
|
22
22
|
let e = /* @__PURE__ */ new Date();
|
|
@@ -39,7 +39,7 @@ var _ = class extends l {
|
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
static {
|
|
42
|
-
this.styles = [f(
|
|
42
|
+
this.styles = [f(t), f(c)];
|
|
43
43
|
}
|
|
44
44
|
get dismissing() {
|
|
45
45
|
return this._dismissing;
|
|
@@ -153,7 +153,7 @@ var _ = class extends l {
|
|
|
153
153
|
aria-label="关闭"
|
|
154
154
|
@click=${this._onCloseClick}
|
|
155
155
|
>
|
|
156
|
-
<web-ui-icon .icon=${
|
|
156
|
+
<web-ui-icon .icon=${o} size="16"></web-ui-icon>
|
|
157
157
|
</web-ui-button>
|
|
158
158
|
`}
|
|
159
159
|
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import e from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
2
2
|
import t from "../../assets/glass.js";
|
|
3
|
-
import n from "../../
|
|
4
|
-
import
|
|
3
|
+
import { normalizeLiteral as n, normalizeNumber as r } from "../../shared/normalize/index.js";
|
|
4
|
+
import i from "../../assets/overlay-motion.js";
|
|
5
5
|
import { dispatchOpenChangeEvent as a } from "../../shared/open-state/index.js";
|
|
6
6
|
import { defineAnchoredPanel as o } from "../../shared/overlay/anchored-panel.js";
|
|
7
7
|
import { defineOpenOverlay as s } from "../../shared/overlay/open-overlay.js";
|
|
@@ -14,7 +14,10 @@ import { customElement as h, property as g } from "lit/decorators.js";
|
|
|
14
14
|
//#region src/components/tooltip/index.ts
|
|
15
15
|
var _ = 0, v = class extends f {
|
|
16
16
|
constructor(...e) {
|
|
17
|
-
super(...e), this._placement = "top", this._showDelay = 200, this._hideDelay = 100, this.disabled = !1, this._offset = 6, this.content = "", this.open = !1, this.portal = !1, this._isCountedVisible = !1, this._userOpenChange = new l(), this._shouldOpenInstantly = !0, this._overlay = s().make({
|
|
17
|
+
super(...e), this._placement = "top", this._showDelay = 200, this._hideDelay = 100, this.disabled = !1, this._offset = 6, this.content = "", this.open = !1, this.portal = !1, this._isCountedVisible = !1, this._userOpenChange = new l(), this._shouldOpenInstantly = !0, this._overlay = s().make({
|
|
18
|
+
requestClose: () => this._hide(),
|
|
19
|
+
isConnected: () => this.isConnected
|
|
20
|
+
}), this._panel = o().make({
|
|
18
21
|
getAnchor: () => this.shadowRoot?.querySelector(".tooltip-trigger") ?? null,
|
|
19
22
|
getLocalPanel: () => this.shadowRoot?.querySelector(".tooltip-panel") ?? null,
|
|
20
23
|
getPositioning: () => ({
|
|
@@ -42,7 +45,7 @@ var _ = 0, v = class extends f {
|
|
|
42
45
|
static {
|
|
43
46
|
this.styles = [
|
|
44
47
|
m(t),
|
|
45
|
-
m(
|
|
48
|
+
m(i),
|
|
46
49
|
m(d)
|
|
47
50
|
];
|
|
48
51
|
}
|
|
@@ -51,28 +54,28 @@ var _ = 0, v = class extends f {
|
|
|
51
54
|
}
|
|
52
55
|
set placement(e) {
|
|
53
56
|
let t = this._placement;
|
|
54
|
-
this._placement =
|
|
57
|
+
this._placement = n(e, u, "top"), this.requestUpdate("placement", t);
|
|
55
58
|
}
|
|
56
59
|
get showDelay() {
|
|
57
60
|
return this._showDelay;
|
|
58
61
|
}
|
|
59
62
|
set showDelay(e) {
|
|
60
63
|
let t = this._showDelay;
|
|
61
|
-
this._showDelay =
|
|
64
|
+
this._showDelay = r(e, 0, 5e3, 200), this.requestUpdate("showDelay", t);
|
|
62
65
|
}
|
|
63
66
|
get hideDelay() {
|
|
64
67
|
return this._hideDelay;
|
|
65
68
|
}
|
|
66
69
|
set hideDelay(e) {
|
|
67
70
|
let t = this._hideDelay;
|
|
68
|
-
this._hideDelay =
|
|
71
|
+
this._hideDelay = r(e, 0, 5e3, 100), this.requestUpdate("hideDelay", t);
|
|
69
72
|
}
|
|
70
73
|
get offset() {
|
|
71
74
|
return this._offset;
|
|
72
75
|
}
|
|
73
76
|
set offset(e) {
|
|
74
77
|
let t = this._offset;
|
|
75
|
-
this._offset =
|
|
78
|
+
this._offset = r(e, 0, 100, 6), this.requestUpdate("offset", t);
|
|
76
79
|
}
|
|
77
80
|
get isOpen() {
|
|
78
81
|
return this.open;
|
|
@@ -102,7 +105,7 @@ var _ = 0, v = class extends f {
|
|
|
102
105
|
let e = c().make({
|
|
103
106
|
container: this.overlayContainer,
|
|
104
107
|
target: this,
|
|
105
|
-
style: `${t}\n${
|
|
108
|
+
style: `${t}\n${i}\n${d}`,
|
|
106
109
|
className: "tooltip-panel portal wui-glass wui-floating-panel",
|
|
107
110
|
migrateAddedNodes: (e) => e.filter((e) => e instanceof Element && e.getAttribute("slot") === "content")
|
|
108
111
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/tooltip/index.ts"],"sourcesContent":["import type { Placement } from '@floating-ui/dom'\nimport { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { normalizeLiteral, normalizeNumber } from '@/shared/normalize'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport { defineAnchoredPanel } from '@/shared/overlay/anchored-panel'\nimport { defineOpenOverlay } from '@/shared/overlay/open-overlay'\nimport { FLOATING_PLACEMENTS } from '@/shared/overlay/placement-props'\nimport { defineOverlayPortal } from '@/shared/overlay/portal'\nimport type { OverlayContainer, OverlayPortal } from '@/shared/overlay/portal'\n\nimport style from './style.css?inline'\n\nlet visibleTooltipCount = 0\n\n@customElement('web-ui-tooltip')\nexport class WebUiTooltip extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(overlayMotion), unsafeCSS(style)]\n\n @property({ type: String, reflect: true })\n get placement(): Placement {\n return this._placement\n }\n set placement(v: string) {\n const old = this._placement\n this._placement = normalizeLiteral(v, FLOATING_PLACEMENTS, 'top')\n this.requestUpdate('placement', old)\n }\n private _placement: Placement = 'top'\n\n @property({ type: Number, attribute: 'show-delay' })\n get showDelay(): number {\n return this._showDelay\n }\n set showDelay(v: number) {\n const old = this._showDelay\n this._showDelay = normalizeNumber(v, 0, 5000, 200)\n this.requestUpdate('showDelay', old)\n }\n private _showDelay = 200\n\n @property({ type: Number, attribute: 'hide-delay' })\n get hideDelay(): number {\n return this._hideDelay\n }\n set hideDelay(v: number) {\n const old = this._hideDelay\n this._hideDelay = normalizeNumber(v, 0, 5000, 100)\n this.requestUpdate('hideDelay', old)\n }\n private _hideDelay = 100\n\n @property({ type: Boolean, reflect: true }) disabled = false\n\n @property({ type: Number })\n get offset(): number {\n return this._offset\n }\n set offset(v: number) {\n const old = this._offset\n this._offset = normalizeNumber(v, 0, 100, 6)\n this.requestUpdate('offset', old)\n }\n private _offset = 6\n\n @property({ type: String }) content = ''\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true }) portal = false\n @property({ attribute: false }) overlayContainer?: OverlayContainer\n\n private _showTimer?: ReturnType<typeof setTimeout>\n private _hideTimer?: ReturnType<typeof setTimeout>\n private _isCountedVisible = false\n private readonly _userOpenChange = new UserChangeController()\n private _shouldOpenInstantly = true\n private _portal?: OverlayPortal\n /**\n * 实例作用域的帧事务入口。`requestClose` 是关闭入口的唯一接线:面板的\n * `arbitration: 'none'` 让 tooltip 在组合树里但永不成候选,因此这条**现在不会被\n * 模块调用**。保留它是不想把「怎么关」藏起来,也让仲裁策略变化时依然成立。\n */\n private readonly _overlay = defineOpenOverlay().make({\n requestClose: () => this._hide()\n })\n private readonly _panel = defineAnchoredPanel().make({\n getAnchor: () => this.shadowRoot?.querySelector<HTMLElement>('.tooltip-trigger') ?? null,\n getLocalPanel: () => this.shadowRoot?.querySelector<HTMLElement>('.tooltip-panel') ?? null,\n getPositioning: () => ({\n placement: this.placement,\n offset: this.offset,\n strategy: this.portal ? 'fixed' : 'absolute'\n }),\n isPortal: () => this.portal,\n createPortal: () => this._createPortal(),\n openOverlay: this._overlay,\n // tooltip 在逻辑组合树里(面板迁移后仍要判对「谁在谁里面」),但从不作为 Escape\n // 候选:按键穿过它落到下层浮层,与重构前一致。\n arbitration: 'none'\n })\n\n get isOpen(): boolean {\n return this.open\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._overlay.resume()\n this.addEventListener('pointerenter', this._onPointerEnter)\n this.addEventListener('pointerleave', this._onPointerLeave)\n this.addEventListener('focusin', this._onFocusIn)\n this.addEventListener('focusout', this._onFocusOut)\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n this.removeEventListener('focusin', this._onFocusIn)\n this.removeEventListener('focusout', this._onFocusOut)\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n // 停止帧调度;撤销登记由 _panel.dispose() 完成(句柄归它持有)。\n this._overlay.suspend()\n this._syncVisibleTooltipCount(false)\n this._panel.dispose()\n }\n\n override firstUpdated() {\n if (this.open) {\n this._openOverlay(this._shouldOpenInstantly)\n this._shouldOpenInstantly = true\n }\n }\n\n protected override updated(changed: Map<string, unknown>) {\n if (changed.has('portal') || changed.has('overlayContainer')) {\n // 同帧 open + reconfigure 可能重复建事务;invalidate 保证 reconfigure 是当前唯一帧回调。\n this._overlay.invalidate()\n this._overlay.scheduleFrame(() => this._reconfigureOverlay())\n } else if (changed.has('placement') || changed.has('offset'))\n requestAnimationFrame(() => this._panel.updatePosition())\n\n if (changed.has('open')) {\n this._syncVisibleTooltipCount(this.open)\n if (this.open) {\n this._openOverlay(this._shouldOpenInstantly)\n this._shouldOpenInstantly = true\n } else {\n this._overlay.invalidate()\n void this._closeOverlay()\n }\n if (this._userOpenChange.consume()) this._dispatchChange(this.open)\n }\n if (changed.has('content')) this._syncPortalContent()\n }\n\n private _onPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled) return\n clearTimeout(this._hideTimer)\n // 已有 tooltip 在场时(指针滑到相邻目标):既不等延迟,也不播入场动画。\n const isRepeat = visibleTooltipCount > 0\n this._showTimer = setTimeout(() => this._show(isRepeat), isRepeat ? 0 : this.showDelay)\n }\n\n private _onPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled) return\n clearTimeout(this._showTimer)\n this._hideTimer = setTimeout(() => this._hide(), this.hideDelay)\n }\n\n private _onFocusIn = (event: FocusEvent) => {\n if (this.disabled) return\n if (!(event.target instanceof Element) || !event.target.matches(':focus-visible')) return\n\n clearTimeout(this._hideTimer)\n this._show(true)\n }\n\n private _onFocusOut = () => {\n if (this.disabled) return\n clearTimeout(this._showTimer)\n this._hide()\n }\n\n private _show(isInstant = false) {\n if (this.open) return\n this._shouldOpenInstantly = isInstant\n this._userOpenChange.mark()\n this.open = true\n }\n\n private _hide() {\n if (!this.open) return\n this._userOpenChange.mark()\n this.open = false\n }\n\n private _openOverlay(isInstant = false) {\n this._panel.open(isInstant)\n }\n\n private _createPortal(): OverlayPortal {\n const portal = defineOverlayPortal().make({\n container: this.overlayContainer,\n target: this,\n style: `${glass}\\n${overlayMotion}\\n${style}`,\n className: 'tooltip-panel portal wui-glass wui-floating-panel',\n // 已迁移节点被框架删除后的解除追踪是 portal 内建默认行为,这里无需 onContentChange\n // 打开期实时渲染:新增的 slot=content 元素实时迁入面板(注释锚点无法携带\n // slot 属性,天然留在宿主作为框架 patch 的插入基准)。\n migrateAddedNodes: addedNodes =>\n addedNodes.filter(node => node instanceof Element && node.getAttribute('slot') === 'content')\n })\n this._portal = portal\n if (this.content) {\n const text = document.createElement('span')\n text.className = 'tooltip-text'\n text.textContent = this.content\n portal.panel.append(text)\n } else portal.moveContent(Array.from(this.querySelectorAll('[slot=\"content\"]')))\n portal.panel.setAttribute('role', 'tooltip')\n return portal\n }\n\n private async _closeOverlay() {\n await this._panel.close(() => this.open)\n }\n\n private _reconfigureOverlay() {\n this._panel.reconfigure(this.open)\n }\n\n private _syncPortalContent() {\n if (!this.portal || !this.open) return\n const localPanel = this._panel.getPanel()\n if (!localPanel) return\n const panel = this._portal?.panel ?? localPanel\n const text = localPanel.querySelector<HTMLElement>('.tooltip-text')\n if (text) {\n text.textContent = this.content\n return\n }\n if (!this.content) return\n panel.replaceChildren()\n const nextText = document.createElement('span')\n nextText.className = 'tooltip-text'\n nextText.textContent = this.content\n panel.append(nextText)\n }\n\n private _dispatchChange(open: boolean) {\n dispatchOpenChangeEvent(this, open)\n }\n\n private _syncVisibleTooltipCount(isVisible: boolean) {\n if (isVisible && !this._isCountedVisible) {\n visibleTooltipCount += 1\n this._isCountedVisible = true\n } else if (!isVisible && this._isCountedVisible) {\n visibleTooltipCount = Math.max(0, visibleTooltipCount - 1)\n this._isCountedVisible = false\n }\n }\n\n override render() {\n return html`\n <div class=\"tooltip-anchor\">\n <div class=\"tooltip-trigger\"><slot></slot></div>\n <div class=\"tooltip-panel wui-floating-panel wui-glass\" hidden role=\"tooltip\">\n ${this.content ? html`<span class=\"tooltip-text\">${this.content}</span>` : html`<slot name=\"content\"></slot>`}\n </div>\n </div>\n `\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-tooltip': WebUiTooltip\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/tooltip/index.ts"],"sourcesContent":["import type { Placement } from '@floating-ui/dom'\nimport { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { normalizeLiteral, normalizeNumber } from '@/shared/normalize'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport { defineAnchoredPanel } from '@/shared/overlay/anchored-panel'\nimport { defineOpenOverlay } from '@/shared/overlay/open-overlay'\nimport { FLOATING_PLACEMENTS } from '@/shared/overlay/placement-props'\nimport { defineOverlayPortal } from '@/shared/overlay/portal'\nimport type { OverlayContainer, OverlayPortal } from '@/shared/overlay/portal'\n\nimport style from './style.css?inline'\n\nlet visibleTooltipCount = 0\n\n@customElement('web-ui-tooltip')\nexport class WebUiTooltip extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(overlayMotion), unsafeCSS(style)]\n\n @property({ type: String, reflect: true })\n get placement(): Placement {\n return this._placement\n }\n set placement(v: string) {\n const old = this._placement\n this._placement = normalizeLiteral(v, FLOATING_PLACEMENTS, 'top')\n this.requestUpdate('placement', old)\n }\n private _placement: Placement = 'top'\n\n @property({ type: Number, attribute: 'show-delay' })\n get showDelay(): number {\n return this._showDelay\n }\n set showDelay(v: number) {\n const old = this._showDelay\n this._showDelay = normalizeNumber(v, 0, 5000, 200)\n this.requestUpdate('showDelay', old)\n }\n private _showDelay = 200\n\n @property({ type: Number, attribute: 'hide-delay' })\n get hideDelay(): number {\n return this._hideDelay\n }\n set hideDelay(v: number) {\n const old = this._hideDelay\n this._hideDelay = normalizeNumber(v, 0, 5000, 100)\n this.requestUpdate('hideDelay', old)\n }\n private _hideDelay = 100\n\n @property({ type: Boolean, reflect: true }) disabled = false\n\n @property({ type: Number })\n get offset(): number {\n return this._offset\n }\n set offset(v: number) {\n const old = this._offset\n this._offset = normalizeNumber(v, 0, 100, 6)\n this.requestUpdate('offset', old)\n }\n private _offset = 6\n\n @property({ type: String }) content = ''\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true }) portal = false\n @property({ attribute: false }) overlayContainer?: OverlayContainer\n\n private _showTimer?: ReturnType<typeof setTimeout>\n private _hideTimer?: ReturnType<typeof setTimeout>\n private _isCountedVisible = false\n private readonly _userOpenChange = new UserChangeController()\n private _shouldOpenInstantly = true\n private _portal?: OverlayPortal\n /**\n * 实例作用域的帧事务入口。`requestClose` 是关闭入口的唯一接线:面板的\n * `arbitration: 'none'` 让 tooltip 在组合树里但永不成候选,因此这条**现在不会被\n * 模块调用**。保留它是不想把「怎么关」藏起来,也让仲裁策略变化时依然成立。\n */\n private readonly _overlay = defineOpenOverlay().make({\n requestClose: () => this._hide(),\n isConnected: () => this.isConnected\n })\n private readonly _panel = defineAnchoredPanel().make({\n getAnchor: () => this.shadowRoot?.querySelector<HTMLElement>('.tooltip-trigger') ?? null,\n getLocalPanel: () => this.shadowRoot?.querySelector<HTMLElement>('.tooltip-panel') ?? null,\n getPositioning: () => ({\n placement: this.placement,\n offset: this.offset,\n strategy: this.portal ? 'fixed' : 'absolute'\n }),\n isPortal: () => this.portal,\n createPortal: () => this._createPortal(),\n openOverlay: this._overlay,\n // tooltip 在逻辑组合树里(面板迁移后仍要判对「谁在谁里面」),但从不作为 Escape\n // 候选:按键穿过它落到下层浮层,与重构前一致。\n arbitration: 'none'\n })\n\n get isOpen(): boolean {\n return this.open\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._overlay.resume()\n this.addEventListener('pointerenter', this._onPointerEnter)\n this.addEventListener('pointerleave', this._onPointerLeave)\n this.addEventListener('focusin', this._onFocusIn)\n this.addEventListener('focusout', this._onFocusOut)\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n this.removeEventListener('focusin', this._onFocusIn)\n this.removeEventListener('focusout', this._onFocusOut)\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n // 停止帧调度;撤销登记由 _panel.dispose() 完成(句柄归它持有)。\n this._overlay.suspend()\n this._syncVisibleTooltipCount(false)\n this._panel.dispose()\n }\n\n override firstUpdated() {\n if (this.open) {\n this._openOverlay(this._shouldOpenInstantly)\n this._shouldOpenInstantly = true\n }\n }\n\n protected override updated(changed: Map<string, unknown>) {\n if (changed.has('portal') || changed.has('overlayContainer')) {\n // 同帧 open + reconfigure 可能重复建事务;invalidate 保证 reconfigure 是当前唯一帧回调。\n this._overlay.invalidate()\n this._overlay.scheduleFrame(() => this._reconfigureOverlay())\n } else if (changed.has('placement') || changed.has('offset'))\n requestAnimationFrame(() => this._panel.updatePosition())\n\n if (changed.has('open')) {\n this._syncVisibleTooltipCount(this.open)\n if (this.open) {\n this._openOverlay(this._shouldOpenInstantly)\n this._shouldOpenInstantly = true\n } else {\n this._overlay.invalidate()\n void this._closeOverlay()\n }\n if (this._userOpenChange.consume()) this._dispatchChange(this.open)\n }\n if (changed.has('content')) this._syncPortalContent()\n }\n\n private _onPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled) return\n clearTimeout(this._hideTimer)\n // 已有 tooltip 在场时(指针滑到相邻目标):既不等延迟,也不播入场动画。\n const isRepeat = visibleTooltipCount > 0\n this._showTimer = setTimeout(() => this._show(isRepeat), isRepeat ? 0 : this.showDelay)\n }\n\n private _onPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled) return\n clearTimeout(this._showTimer)\n this._hideTimer = setTimeout(() => this._hide(), this.hideDelay)\n }\n\n private _onFocusIn = (event: FocusEvent) => {\n if (this.disabled) return\n if (!(event.target instanceof Element) || !event.target.matches(':focus-visible')) return\n\n clearTimeout(this._hideTimer)\n this._show(true)\n }\n\n private _onFocusOut = () => {\n if (this.disabled) return\n clearTimeout(this._showTimer)\n this._hide()\n }\n\n private _show(isInstant = false) {\n if (this.open) return\n this._shouldOpenInstantly = isInstant\n this._userOpenChange.mark()\n this.open = true\n }\n\n private _hide() {\n if (!this.open) return\n this._userOpenChange.mark()\n this.open = false\n }\n\n private _openOverlay(isInstant = false) {\n this._panel.open(isInstant)\n }\n\n private _createPortal(): OverlayPortal {\n const portal = defineOverlayPortal().make({\n container: this.overlayContainer,\n target: this,\n style: `${glass}\\n${overlayMotion}\\n${style}`,\n className: 'tooltip-panel portal wui-glass wui-floating-panel',\n // 已迁移节点被框架删除后的解除追踪是 portal 内建默认行为,这里无需 onContentChange\n // 打开期实时渲染:新增的 slot=content 元素实时迁入面板(注释锚点无法携带\n // slot 属性,天然留在宿主作为框架 patch 的插入基准)。\n migrateAddedNodes: addedNodes =>\n addedNodes.filter(node => node instanceof Element && node.getAttribute('slot') === 'content')\n })\n this._portal = portal\n if (this.content) {\n const text = document.createElement('span')\n text.className = 'tooltip-text'\n text.textContent = this.content\n portal.panel.append(text)\n } else portal.moveContent(Array.from(this.querySelectorAll('[slot=\"content\"]')))\n portal.panel.setAttribute('role', 'tooltip')\n return portal\n }\n\n private async _closeOverlay() {\n await this._panel.close(() => this.open)\n }\n\n private _reconfigureOverlay() {\n this._panel.reconfigure(this.open)\n }\n\n private _syncPortalContent() {\n if (!this.portal || !this.open) return\n const localPanel = this._panel.getPanel()\n if (!localPanel) return\n const panel = this._portal?.panel ?? localPanel\n const text = localPanel.querySelector<HTMLElement>('.tooltip-text')\n if (text) {\n text.textContent = this.content\n return\n }\n if (!this.content) return\n panel.replaceChildren()\n const nextText = document.createElement('span')\n nextText.className = 'tooltip-text'\n nextText.textContent = this.content\n panel.append(nextText)\n }\n\n private _dispatchChange(open: boolean) {\n dispatchOpenChangeEvent(this, open)\n }\n\n private _syncVisibleTooltipCount(isVisible: boolean) {\n if (isVisible && !this._isCountedVisible) {\n visibleTooltipCount += 1\n this._isCountedVisible = true\n } else if (!isVisible && this._isCountedVisible) {\n visibleTooltipCount = Math.max(0, visibleTooltipCount - 1)\n this._isCountedVisible = false\n }\n }\n\n override render() {\n return html`\n <div class=\"tooltip-anchor\">\n <div class=\"tooltip-trigger\"><slot></slot></div>\n <div class=\"tooltip-panel wui-floating-panel wui-glass\" hidden role=\"tooltip\">\n ${this.content ? html`<span class=\"tooltip-text\">${this.content}</span>` : html`<slot name=\"content\"></slot>`}\n </div>\n </div>\n `\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-tooltip': WebUiTooltip\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { definePlugin as e } from "@greypan/js-kit";
|
|
1
2
|
//#region src/shared/option-portal/combobox-shell.ts
|
|
2
|
-
function
|
|
3
|
+
function t(e) {
|
|
3
4
|
function t(t = !1) {
|
|
4
5
|
e.canOpen() === !1 || e.getIsOpen() || (e.setIsOpen(!0), e.dispatchOpenChange(), e.onOpen?.(t), e.syncScrollLock(!0), e.isPortal() ? requestAnimationFrame(() => {
|
|
5
6
|
e.getIsOpen() && e.openOverlay(t);
|
|
@@ -13,7 +14,48 @@ function e(e) {
|
|
|
13
14
|
close: n
|
|
14
15
|
};
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
var n = () => e((e) => {
|
|
18
|
+
let t = null, n = () => e.getCustomTrigger() ?? e.getFallbackTrigger() ?? null, r = (e) => {
|
|
19
|
+
let t = e?.value;
|
|
20
|
+
return typeof t == "string" ? t : null;
|
|
21
|
+
}, i = (e, t) => {
|
|
22
|
+
let n = e.target;
|
|
23
|
+
return !!t && n instanceof Node && (n === t || t.contains(n));
|
|
24
|
+
}, a = (t) => {
|
|
25
|
+
let a = n();
|
|
26
|
+
if (!i(t, a)) return;
|
|
27
|
+
let o = r(a);
|
|
28
|
+
o !== null && e.onInput(o);
|
|
29
|
+
}, o = (e) => {
|
|
30
|
+
i(e, n()) && e.stopPropagation();
|
|
31
|
+
}, s = () => e.onClick(), c = (t) => e.onFocusIn(t), l = (t) => e.onFocusOut(t);
|
|
32
|
+
return {
|
|
33
|
+
getTrigger: n,
|
|
34
|
+
getValue: () => r(n()),
|
|
35
|
+
setValue(e) {
|
|
36
|
+
let t = n(), i = r(t);
|
|
37
|
+
t && i !== null && i !== e && (t.value = e);
|
|
38
|
+
},
|
|
39
|
+
isMultilineEdit(e) {
|
|
40
|
+
return e.composedPath()[0] instanceof HTMLTextAreaElement;
|
|
41
|
+
},
|
|
42
|
+
focusTrigger(e) {
|
|
43
|
+
n()?.focus(e);
|
|
44
|
+
},
|
|
45
|
+
blurTrigger() {
|
|
46
|
+
n()?.blur();
|
|
47
|
+
},
|
|
48
|
+
bind() {
|
|
49
|
+
let n = e.getWrapper();
|
|
50
|
+
n && n !== t && (t = n, n.addEventListener("input", a), n.addEventListener("change", o), n.addEventListener("click", s), n.addEventListener("focusin", c), n.addEventListener("focusout", l));
|
|
51
|
+
},
|
|
52
|
+
dispose() {
|
|
53
|
+
let e = t;
|
|
54
|
+
t = null, e && (e.removeEventListener("input", a), e.removeEventListener("change", o), e.removeEventListener("click", s), e.removeEventListener("focusin", c), e.removeEventListener("focusout", l));
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
function r(e) {
|
|
17
59
|
function t(t) {
|
|
18
60
|
t.addEventListener("click", e.onClick), t.addEventListener("pointerover", e.onPointerOver), t.addEventListener("pointerdown", e.onPointerDown), t.addEventListener("option-update", e.onUpdate);
|
|
19
61
|
}
|
|
@@ -25,18 +67,18 @@ function t(e) {
|
|
|
25
67
|
unbind: n
|
|
26
68
|
};
|
|
27
69
|
}
|
|
28
|
-
function
|
|
70
|
+
function i(e, t, n, r) {
|
|
29
71
|
requestAnimationFrame(() => {
|
|
30
72
|
let i = t();
|
|
31
73
|
n() && !e.matches(":focus-within") && !i?.hasFocusWithin() && r();
|
|
32
74
|
});
|
|
33
75
|
}
|
|
34
|
-
function
|
|
76
|
+
function a(e, t, n) {
|
|
35
77
|
if (e === 0) return -1;
|
|
36
78
|
let r = t + n;
|
|
37
79
|
return r < 0 && (r = e - 1), r >= e && (r = 0), r;
|
|
38
80
|
}
|
|
39
81
|
//#endregion
|
|
40
|
-
export {
|
|
82
|
+
export { t as createComboboxOpenController, r as createOptionListenerBinding, n as defineComboboxTrigger, i as handleComboboxFocusOut, a as nextWrappingIndex };
|
|
41
83
|
|
|
42
84
|
//# sourceMappingURL=combobox-shell.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox-shell.js","names":[],"sources":["../../../src/shared/option-portal/combobox-shell.ts"],"sourcesContent":["import type { WebUiOption } from '@/components/option'\nimport type { OpenOverlayHandle } from '@/shared/overlay/open-overlay'\n\n/**\n * combobox 开合与 option 交互的共享骨架(select / autocomplete)。\n *\n * 与 option-portal 的边界约定一致:交互语义的\"差异点\"经回调注入,\n * 这里收口两组件逐行复制的生命周期不变量——\n * - open/close 状态迁移顺序:guard → 状态翻转 → open-change 派发 →\n * 激活钩子 → scroll-lock 配对 → portal 模式的 rAF 延迟 openOverlay\n * - close 路径:before-close 钩子(portal 内容先收敛)→ 激活清理 →\n * scroll-lock 释放 → closeOverlay(关闭后使 portal 引用失效)\n * - option 四事件监听对的绑定/解绑\n * - focusout 的 rAF :focus-within 复核\n * - 键盘导航的环绕游标算法\n */\n\nexport interface ComboboxOpenHooks {\n /** 是否允许打开(disabled / readonly 等由组件判断)。 */\n canOpen(): boolean\n getIsOpen(): boolean\n setIsOpen(open: boolean): void\n dispatchOpenChange(): void\n syncScrollLock(open: boolean): void\n /** 是否 portal 模式(决定 openOverlay 是否延迟到下一帧)。 */\n isPortal(): boolean\n openOverlay(isKeyboardNavigation: boolean): void\n closeOverlay(): void\n /** 打开时的激活项初始化(键盘导航取选中/首项,指针打开保留现状)。 */\n onOpen?(isKeyboardNavigation: boolean): void\n /** 关闭前钩子:autocomplete 需先把 light DOM 新增节点收敛进当前 portal content。 */\n onBeforeClose?(): void\n /** 关闭时清理激活状态(清 _activeIndex 与 active 属性)。 */\n onAfterClose?(): void\n}\n\nexport interface ComboboxOpenController {\n open(isKeyboardNavigation?: boolean): void\n close(): void\n}\n\nexport function createComboboxOpenController(hooks: ComboboxOpenHooks): ComboboxOpenController {\n function open(isKeyboardNavigation = false) {\n if (hooks.canOpen() === false || hooks.getIsOpen()) return\n hooks.setIsOpen(true)\n hooks.dispatchOpenChange()\n hooks.onOpen?.(isKeyboardNavigation)\n hooks.syncScrollLock(true)\n if (hooks.isPortal()) {\n requestAnimationFrame(() => {\n if (hooks.getIsOpen()) hooks.openOverlay(isKeyboardNavigation)\n })\n } else {\n hooks.openOverlay(isKeyboardNavigation)\n }\n }\n\n function close() {\n if (!hooks.getIsOpen()) return\n hooks.onBeforeClose?.()\n hooks.setIsOpen(false)\n hooks.dispatchOpenChange()\n hooks.onAfterClose?.()\n hooks.syncScrollLock(false)\n hooks.closeOverlay()\n }\n\n return { open, close }\n}\n\nexport interface OptionListenerHandlers {\n onClick: (event: Event) => void\n onPointerOver: (event: PointerEvent) => void\n onPointerDown: (event: PointerEvent) => void\n onUpdate: () => void\n}\n\n/** option 四事件监听对的绑定/解绑;两组件的 handler 签名一致,仅实现不同。 */\nexport function createOptionListenerBinding(handlers: OptionListenerHandlers) {\n function bind(option: WebUiOption) {\n option.addEventListener('click', handlers.onClick)\n option.addEventListener('pointerover', handlers.onPointerOver)\n option.addEventListener('pointerdown', handlers.onPointerDown)\n option.addEventListener('option-update', handlers.onUpdate)\n }\n function unbind(option: WebUiOption) {\n option.removeEventListener('click', handlers.onClick)\n option.removeEventListener('pointerover', handlers.onPointerOver)\n option.removeEventListener('pointerdown', handlers.onPointerDown)\n option.removeEventListener('option-update', handlers.onUpdate)\n }\n return { bind, unbind }\n}\n\n/**\n * focusout 关闭复核:焦点是否真的离开了宿主与面板。\n * rAF 等待 click/pointerdown 相关的焦点迁移完成后再判定。\n */\nexport function handleComboboxFocusOut(\n host: HTMLElement,\n getHandle: () => OpenOverlayHandle | null | undefined,\n getIsOpen: () => boolean,\n close: () => void\n): void {\n requestAnimationFrame(() => {\n const handle = getHandle()\n if (getIsOpen() && !host.matches(':focus-within') && !handle?.hasFocusWithin()) {\n close()\n }\n })\n}\n\n/**\n * 环绕游标:在 enabled 列表内按 delta 移动;从 -1(无激活)向下取首项、向上取末项。\n * 返回在 enabled 中的下一索引;调用方负责换算回全量 options 索引。\n */\nexport function nextWrappingIndex(enabledCount: number, currentIdx: number, delta: number): number {\n if (enabledCount === 0) return -1\n let nextIdx = currentIdx + delta\n if (nextIdx < 0) nextIdx = enabledCount - 1\n if (nextIdx >= enabledCount) nextIdx = 0\n return nextIdx\n}\n"],"mappings":";AAyCA,SAAgB,EAA6B,GAAkD;CAC7F,SAAS,EAAK,IAAuB,IAAO;EACtC,EAAM,QAAQ,MAAM,MAAS,EAAM,UAAU,MACjD,EAAM,UAAU,EAAI,GACpB,EAAM,mBAAmB,GACzB,EAAM,SAAS,CAAoB,GACnC,EAAM,eAAe,EAAI,GACrB,EAAM,SAAS,IACjB,4BAA4B;GAC1B,AAAI,EAAM,UAAU,KAAG,EAAM,YAAY,CAAoB;EAC/D,CAAC,IAED,EAAM,YAAY,CAAoB;CAE1C;CAEA,SAAS,IAAQ;EACV,EAAM,UAAU,MACrB,EAAM,gBAAgB,GACtB,EAAM,UAAU,EAAK,GACrB,EAAM,mBAAmB,GACzB,EAAM,eAAe,GACrB,EAAM,eAAe,EAAK,GAC1B,EAAM,aAAa;CACrB;CAEA,OAAO;EAAE;EAAM;CAAM;AACvB;AAUA,SAAgB,EAA4B,GAAkC;CAC5E,SAAS,EAAK,GAAqB;EAIjC,AAHA,EAAO,iBAAiB,SAAS,EAAS,OAAO,GACjD,EAAO,iBAAiB,eAAe,EAAS,aAAa,GAC7D,EAAO,iBAAiB,eAAe,EAAS,aAAa,GAC7D,EAAO,iBAAiB,iBAAiB,EAAS,QAAQ;CAC5D;CACA,SAAS,EAAO,GAAqB;EAInC,AAHA,EAAO,oBAAoB,SAAS,EAAS,OAAO,GACpD,EAAO,oBAAoB,eAAe,EAAS,aAAa,GAChE,EAAO,oBAAoB,eAAe,EAAS,aAAa,GAChE,EAAO,oBAAoB,iBAAiB,EAAS,QAAQ;CAC/D;CACA,OAAO;EAAE;EAAM;CAAO;AACxB;AAMA,SAAgB,EACd,GACA,GACA,GACA,GACM;CACN,4BAA4B;EAC1B,IAAM,IAAS,EAAU;EACzB,AAAI,EAAU,KAAK,CAAC,EAAK,QAAQ,eAAe,KAAK,CAAC,GAAQ,eAAe,KAC3E,EAAM;CAEV,CAAC;AACH;AAMA,SAAgB,EAAkB,GAAsB,GAAoB,GAAuB;CACjG,IAAI,MAAiB,GAAG,OAAO;CAC/B,IAAI,IAAU,IAAa;CAG3B,OAFI,IAAU,MAAG,IAAU,IAAe,IACtC,KAAW,MAAc,IAAU,IAChC;AACT"}
|
|
1
|
+
{"version":3,"file":"combobox-shell.js","names":[],"sources":["../../../src/shared/option-portal/combobox-shell.ts"],"sourcesContent":["import { definePlugin } from '@greypan/js-kit'\n\nimport type { WebUiOption } from '@/components/option'\nimport type { OpenOverlayHandle } from '@/shared/overlay/open-overlay'\n\n/**\n * combobox 开合与 option 交互的共享骨架(select / autocomplete)。\n *\n * 与 option-portal 的边界约定一致:交互语义的\"差异点\"经回调注入,\n * 这里收口两组件逐行复制的生命周期不变量——\n * - open/close 状态迁移顺序:guard → 状态翻转 → open-change 派发 →\n * 激活钩子 → scroll-lock 配对 → portal 模式的 rAF 延迟 openOverlay\n * - close 路径:before-close 钩子(portal 内容先收敛)→ 激活清理 →\n * scroll-lock 释放 → closeOverlay(关闭后使 portal 引用失效)\n * - option 四事件监听对的绑定/解绑\n * - focusout 的 rAF :focus-within 复核\n * - 键盘导航的环绕游标算法\n */\n\nexport interface ComboboxOpenHooks {\n /** 是否允许打开(disabled / readonly 等由组件判断)。 */\n canOpen(): boolean\n getIsOpen(): boolean\n setIsOpen(open: boolean): void\n dispatchOpenChange(): void\n syncScrollLock(open: boolean): void\n /** 是否 portal 模式(决定 openOverlay 是否延迟到下一帧)。 */\n isPortal(): boolean\n openOverlay(isKeyboardNavigation: boolean): void\n closeOverlay(): void\n /** 打开时的激活项初始化(键盘导航取选中/首项,指针打开保留现状)。 */\n onOpen?(isKeyboardNavigation: boolean): void\n /** 关闭前钩子:autocomplete 需先把 light DOM 新增节点收敛进当前 portal content。 */\n onBeforeClose?(): void\n /** 关闭时清理激活状态(清 _activeIndex 与 active 属性)。 */\n onAfterClose?(): void\n}\n\nexport interface ComboboxOpenController {\n open(isKeyboardNavigation?: boolean): void\n close(): void\n}\n\nexport function createComboboxOpenController(hooks: ComboboxOpenHooks): ComboboxOpenController {\n function open(isKeyboardNavigation = false) {\n if (hooks.canOpen() === false || hooks.getIsOpen()) return\n hooks.setIsOpen(true)\n hooks.dispatchOpenChange()\n hooks.onOpen?.(isKeyboardNavigation)\n hooks.syncScrollLock(true)\n if (hooks.isPortal()) {\n requestAnimationFrame(() => {\n if (hooks.getIsOpen()) hooks.openOverlay(isKeyboardNavigation)\n })\n } else {\n hooks.openOverlay(isKeyboardNavigation)\n }\n }\n\n function close() {\n if (!hooks.getIsOpen()) return\n hooks.onBeforeClose?.()\n hooks.setIsOpen(false)\n hooks.dispatchOpenChange()\n hooks.onAfterClose?.()\n hooks.syncScrollLock(false)\n hooks.closeOverlay()\n }\n\n return { open, close }\n}\n\nexport interface OptionListenerHandlers {\n onClick: (event: Event) => void\n onPointerOver: (event: PointerEvent) => void\n onPointerDown: (event: PointerEvent) => void\n onUpdate: () => void\n}\n\nexport interface ComboboxTriggerSource {\n /** 持 ARIA 与委托监听的 trigger 包装 div(shadow 内)。 */\n getWrapper(): HTMLElement | null\n /** `slot[name=\"trigger\"]` 的首个 assigned 元素;无自定义触发器时为 null。 */\n getCustomTrigger(): HTMLElement | null\n /** 默认触发器(shadow 内的 web-ui-input);未渲染时为 null。 */\n getFallbackTrigger(): HTMLElement | null\n}\n\nexport interface ComboboxTriggerHandlers {\n /** 触发器文本变化;value 取自触发器 host 的字符串 value 属性。 */\n onInput(value: string): void\n /** 点击触发器区域(含包装 div 自身留白)。 */\n onClick(): void\n onFocusIn(event: FocusEvent): void\n onFocusOut(event: FocusEvent): void\n}\n\nexport interface ComboboxTriggerApi {\n /** 当前生效的触发器 host:自定义 trigger slot 首个 assigned 元素,否则默认触发器。 */\n getTrigger(): HTMLElement | null\n /** 触发器当前文本;触发器不暴露字符串 value 时返回 null。 */\n getValue(): string | null\n /** 回写文本;仅在文本触发器且值确实变化时写入,避免无谓重渲染。 */\n setValue(value: string): void\n /** 多行可编辑元素判定:Enter 保留换行语义,不接管为「选中高亮项」。 */\n isMultilineEdit(event: KeyboardEvent): boolean\n /**\n * 程序化聚焦当前触发器。组件自带 focus 重定向(web-ui-input/textarea)时落到\n * 内部原生控件;自定义触发器没有该能力时,原生 focus() 聚焦 host 自身。\n */\n focusTrigger(options?: FocusOptions): void\n /** 失焦当前触发器,兜底语义同 focusTrigger。 */\n blurTrigger(): void\n /** 绑定包装 div 上的委托监听(幂等:包装 div 不变则跳过)。 */\n bind(): void\n dispose(): void\n}\n\n/**\n * combobox 触发器委托层(autocomplete)。\n *\n * 默认触发器是 shadow 内的 `web-ui-input`,自定义触发器由 `slot[name=\"trigger\"]`\n * 提供(`web-ui-textarea` 等)。两者对组件暴露同一形状:字符串 value、可聚焦、\n * 派发 composed 的 input / click / focusin / focusout。委托层把这些差异收敛成一份接口:\n * 监听统一挂在包装 div 上(事件委托,覆盖 shadow 内与 light DOM 两条路径),\n * 文本读写只认触发器 host 的 value 属性。\n *\n * 焦点用 focusin/focusout 而非 focus/blur:后两者不冒泡,到不了包装 div\n * (实测:shadow 内默认触发器与 light DOM 自定义触发器都不触发包装 div 的 focus/blur)。\n *\n * 触发器自身派发的 change(web-ui-input/textarea 在原生 change 不 composed 时补发)\n * 必须被拦下:组件的 change 只表示「选中提交」,否则失焦即误报一次 change。\n */\nexport const defineComboboxTrigger = () =>\n definePlugin<ComboboxTriggerApi, ComboboxTriggerSource & ComboboxTriggerHandlers>(source => {\n let boundWrapper: HTMLElement | null = null\n\n const getTrigger = (): HTMLElement | null => source.getCustomTrigger() ?? source.getFallbackTrigger() ?? null\n\n const readValue = (trigger: HTMLElement | null): string | null => {\n const value = (trigger as (HTMLElement & { value?: unknown }) | null)?.value\n return typeof value === 'string' ? value : null\n }\n\n // composed 事件在包装 div 上看到的是触发器 host(或其在 light DOM 内的后代);\n // 只有来自触发器内部的输入才计入,包装 div 上的其它内容不干扰。\n const isWithinTrigger = (event: Event, trigger: HTMLElement | null): boolean => {\n const target = event.target\n return !!trigger && target instanceof Node && (target === trigger || trigger.contains(target))\n }\n\n const onInput = (event: Event) => {\n const trigger = getTrigger()\n if (!isWithinTrigger(event, trigger)) return\n const value = readValue(trigger)\n if (value !== null) source.onInput(value)\n }\n\n const onNativeChange = (event: Event) => {\n if (isWithinTrigger(event, getTrigger())) event.stopPropagation()\n }\n\n const onClick = () => source.onClick()\n const onFocusIn = (event: FocusEvent) => source.onFocusIn(event)\n const onFocusOut = (event: FocusEvent) => source.onFocusOut(event)\n\n return {\n getTrigger,\n getValue: () => readValue(getTrigger()),\n setValue(value: string) {\n const trigger = getTrigger()\n const current = readValue(trigger)\n if (!trigger || current === null || current === value) return\n ;(trigger as HTMLElement & { value: string }).value = value\n },\n isMultilineEdit(event: KeyboardEvent) {\n // composedPath()[0] 是未 retarget 的真实可编辑元素:textarea 保留 Enter 换行\n return event.composedPath()[0] instanceof HTMLTextAreaElement\n },\n focusTrigger(options?: FocusOptions) {\n // web-ui-input/textarea 的公共 focus() 已重定向到内部原生控件;普通元素或\n // 未实现 focus 的自定义触发器走原生 HTMLElement.focus(),即聚焦 host 自身\n getTrigger()?.focus(options)\n },\n blurTrigger() {\n getTrigger()?.blur()\n },\n bind() {\n const wrapper = source.getWrapper()\n if (!wrapper || wrapper === boundWrapper) return\n boundWrapper = wrapper\n wrapper.addEventListener('input', onInput)\n wrapper.addEventListener('change', onNativeChange)\n wrapper.addEventListener('click', onClick)\n wrapper.addEventListener('focusin', onFocusIn)\n wrapper.addEventListener('focusout', onFocusOut)\n },\n dispose() {\n const wrapper = boundWrapper\n boundWrapper = null\n if (!wrapper) return\n wrapper.removeEventListener('input', onInput)\n wrapper.removeEventListener('change', onNativeChange)\n wrapper.removeEventListener('click', onClick)\n wrapper.removeEventListener('focusin', onFocusIn)\n wrapper.removeEventListener('focusout', onFocusOut)\n }\n }\n })\n\n/** option 四事件监听对的绑定/解绑;两组件的 handler 签名一致,仅实现不同。 */\nexport function createOptionListenerBinding(handlers: OptionListenerHandlers) {\n function bind(option: WebUiOption) {\n option.addEventListener('click', handlers.onClick)\n option.addEventListener('pointerover', handlers.onPointerOver)\n option.addEventListener('pointerdown', handlers.onPointerDown)\n option.addEventListener('option-update', handlers.onUpdate)\n }\n function unbind(option: WebUiOption) {\n option.removeEventListener('click', handlers.onClick)\n option.removeEventListener('pointerover', handlers.onPointerOver)\n option.removeEventListener('pointerdown', handlers.onPointerDown)\n option.removeEventListener('option-update', handlers.onUpdate)\n }\n return { bind, unbind }\n}\n\n/**\n * focusout 关闭复核:焦点是否真的离开了宿主与面板。\n * rAF 等待 click/pointerdown 相关的焦点迁移完成后再判定。\n */\nexport function handleComboboxFocusOut(\n host: HTMLElement,\n getHandle: () => OpenOverlayHandle | null | undefined,\n getIsOpen: () => boolean,\n close: () => void\n): void {\n requestAnimationFrame(() => {\n const handle = getHandle()\n if (getIsOpen() && !host.matches(':focus-within') && !handle?.hasFocusWithin()) {\n close()\n }\n })\n}\n\n/**\n * 环绕游标:在 enabled 列表内按 delta 移动;从 -1(无激活)向下取首项、向上取末项。\n * 返回在 enabled 中的下一索引;调用方负责换算回全量 options 索引。\n */\nexport function nextWrappingIndex(enabledCount: number, currentIdx: number, delta: number): number {\n if (enabledCount === 0) return -1\n let nextIdx = currentIdx + delta\n if (nextIdx < 0) nextIdx = enabledCount - 1\n if (nextIdx >= enabledCount) nextIdx = 0\n return nextIdx\n}\n"],"mappings":"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"}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { createComboboxOpenController as e, createOptionListenerBinding as t,
|
|
2
|
-
import { definePlugin as
|
|
1
|
+
import { createComboboxOpenController as e, createOptionListenerBinding as t, defineComboboxTrigger as n, handleComboboxFocusOut as r, nextWrappingIndex as i } from "./combobox-shell.js";
|
|
2
|
+
import { definePlugin as a } from "@greypan/js-kit";
|
|
3
3
|
//#region src/shared/option-portal/index.ts
|
|
4
|
-
var
|
|
4
|
+
var o = "web-ui-option", s = () => a((e) => {
|
|
5
5
|
let t = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new WeakMap(), r = 0, i = (t) => {
|
|
6
6
|
e.bindOption(t), t.addEventListener("option-unregister", s);
|
|
7
|
-
},
|
|
7
|
+
}, a = (t) => {
|
|
8
8
|
e.unbindOption(t), t.removeEventListener("option-unregister", s);
|
|
9
9
|
}, s = (e) => {
|
|
10
|
-
e.target instanceof HTMLElement && e.target.localName ===
|
|
10
|
+
e.target instanceof HTMLElement && e.target.localName === o && t.add(e.target), l.scheduleRefresh();
|
|
11
11
|
}, c = () => {
|
|
12
12
|
l.scheduleRefresh();
|
|
13
13
|
}, l = {
|
|
14
14
|
queryOptions() {
|
|
15
|
-
let t = e.getPortal()?.panel ?? e.getPortalContent(), n = t ? [...t.querySelectorAll(
|
|
16
|
-
return n.length > 0 ? n : [...e.element.querySelectorAll(
|
|
15
|
+
let t = e.getPortal()?.panel ?? e.getPortalContent(), n = t ? [...t.querySelectorAll(o)] : [];
|
|
16
|
+
return n.length > 0 ? n : [...e.element.querySelectorAll(o)];
|
|
17
17
|
},
|
|
18
18
|
refresh(e, t) {
|
|
19
19
|
let n = l.queryOptions();
|
|
20
|
-
for (let t of e) n.includes(t) ||
|
|
20
|
+
for (let t of e) n.includes(t) || a(t);
|
|
21
21
|
return n.forEach(i), {
|
|
22
22
|
options: n,
|
|
23
23
|
activeIndex: t && n.includes(t) ? n.indexOf(t) : -1
|
|
@@ -61,6 +61,6 @@ var a = "web-ui-option", o = () => i((e) => {
|
|
|
61
61
|
return l;
|
|
62
62
|
});
|
|
63
63
|
//#endregion
|
|
64
|
-
export { e as createComboboxOpenController, t as createOptionListenerBinding,
|
|
64
|
+
export { e as createComboboxOpenController, t as createOptionListenerBinding, n as defineComboboxTrigger, s as defineOptionPortal, r as handleComboboxFocusOut, i as nextWrappingIndex };
|
|
65
65
|
|
|
66
66
|
//# sourceMappingURL=index.js.map
|
|
@@ -37,9 +37,9 @@ var i = () => r((r) => {
|
|
|
37
37
|
},
|
|
38
38
|
open: f,
|
|
39
39
|
async close(e) {
|
|
40
|
-
|
|
40
|
+
o?.deferArbitration(), i?.close();
|
|
41
41
|
let n = s();
|
|
42
|
-
return n && !await t(n)
|
|
42
|
+
return n && !await t(n) ? !1 : e() ? (o?.deferArbitration(!1), !1) : (c(), l(), !0);
|
|
43
43
|
},
|
|
44
44
|
updatePosition() {
|
|
45
45
|
i?.update(r.getPositioning());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anchored-panel.js","names":[],"sources":["../../../src/shared/overlay/anchored-panel.ts"],"sourcesContent":["import { definePlugin } from '@greypan/js-kit'\n\nimport type { OpenOverlay, OpenOverlayHandle, OverlayArbitration } from './open-overlay'\nimport type { OverlayOptions } from './overlay'\nimport { defineOverlay } from './overlay'\nimport type { OverlayApi } from './overlay'\nimport type { OverlayPortal } from './portal'\nimport { hideOverlayPresence, showOverlayPresence } from './presence'\n\nexport interface AnchoredPanelOptions {\n getAnchor(): HTMLElement | null\n getLocalPanel(): HTMLElement | null\n getPositioning(): OverlayOptions\n isPortal(): boolean\n createPortal(): OverlayPortal\n /**\n * 承载「本面板是一次开启态浮层」的实例:登记与 Escape 归属由它完成,本模块不再\n * 自己维护逻辑父子关系。\n *\n * 必须是**调用方持有的那个实例**(而不是这里新建一个)——调用方同时要用它的帧\n * 事务入口,两个实例会让「我开着吗」重新分裂。\n */\n openOverlay: OpenOverlay\n /** 本面板与 Escape 仲裁的关系。tooltip 传 `none`;缺省 `escape`。 */\n arbitration?: OverlayArbitration\n}\n\n/**\n * 管理锚定面板的本地/Portal 容器、定位器和可中断 presence。\n * 内容迁移与交互语义由各组件保留,避免把不同组件的 public contract 混入此模块。\n */\nexport interface AnchoredPanelApi {\n getPanel(): HTMLElement | null\n /**\n *
|
|
1
|
+
{"version":3,"file":"anchored-panel.js","names":[],"sources":["../../../src/shared/overlay/anchored-panel.ts"],"sourcesContent":["import { definePlugin } from '@greypan/js-kit'\n\nimport type { OpenOverlay, OpenOverlayHandle, OverlayArbitration } from './open-overlay'\nimport type { OverlayOptions } from './overlay'\nimport { defineOverlay } from './overlay'\nimport type { OverlayApi } from './overlay'\nimport type { OverlayPortal } from './portal'\nimport { hideOverlayPresence, showOverlayPresence } from './presence'\n\nexport interface AnchoredPanelOptions {\n getAnchor(): HTMLElement | null\n getLocalPanel(): HTMLElement | null\n getPositioning(): OverlayOptions\n isPortal(): boolean\n createPortal(): OverlayPortal\n /**\n * 承载「本面板是一次开启态浮层」的实例:登记与 Escape 归属由它完成,本模块不再\n * 自己维护逻辑父子关系。\n *\n * 必须是**调用方持有的那个实例**(而不是这里新建一个)——调用方同时要用它的帧\n * 事务入口,两个实例会让「我开着吗」重新分裂。\n */\n openOverlay: OpenOverlay\n /** 本面板与 Escape 仲裁的关系。tooltip 传 `none`;缺省 `escape`。 */\n arbitration?: OverlayArbitration\n}\n\n/**\n * 管理锚定面板的本地/Portal 容器、定位器和可中断 presence。\n * 内容迁移与交互语义由各组件保留,避免把不同组件的 public contract 混入此模块。\n */\nexport interface AnchoredPanelApi {\n getPanel(): HTMLElement | null\n /**\n * 当前在场会话的句柄;没有任何在场会话时为 `null`。\n * 查询(`contains` / `containsEvent` / `hasFocusWithin`)与 `setInert` 都走它,\n * 调用方因此不必持有 panel 引用,也不知道存在全局注册表。\n * 退场等待期间仍是同一个句柄(暂缓仲裁),动画播完或重新 `open()` 才换人。\n */\n getHandle(): OpenOverlayHandle | null\n open(isInstant?: boolean): void\n close(isStillOpen: () => boolean): Promise<boolean>\n updatePosition(): void\n reconfigure(isOpen: boolean): void\n dispose(): void\n}\n\nexport const defineAnchoredPanel = () =>\n definePlugin<AnchoredPanelApi, AnchoredPanelOptions>(ctx => {\n let overlay: OverlayApi | undefined\n let portal: OverlayPortal | undefined\n let handle: OpenOverlayHandle | null = null\n\n const getPanel = () => portal?.panel ?? ctx.getLocalPanel()\n\n const releaseHandle = () => {\n handle?.release()\n handle = null\n }\n\n const disposePortal = () => {\n if (!portal) return\n portal.restoreContent()\n portal.remove()\n portal = undefined\n overlay = undefined\n }\n\n const getOrCreatePanel = (): HTMLElement | null => {\n if (!ctx.isPortal()) return ctx.getLocalPanel()\n portal ??= ctx.createPortal()\n return portal.panel\n }\n\n const ensureOverlay = (anchor: HTMLElement, panel: HTMLElement) => {\n if (overlay) {\n overlay.updateAnchor(anchor)\n overlay.update(ctx.getPositioning())\n return\n }\n overlay = defineOverlay().make({ anchor, overlay: panel, ...ctx.getPositioning() })\n }\n\n const open = (isInstant = false) => {\n const anchor = ctx.getAnchor()\n if (!anchor) return\n const panel = getOrCreatePanel()\n if (!panel) return\n // portal panel 与宿主物理分离;本地 panel 也可能隔着 shadow 边界。\n // 以 anchor 祖先链寻找最近的已开启浮层,建立统一逻辑父子关系。\n // claim ⟺ open:重复 open 视为新的一次开启,旧会话整体作废。\n releaseHandle()\n handle = ctx.openOverlay.claim(panel, { arbitration: ctx.arbitration, ancestryFrom: anchor })\n ensureOverlay(anchor, panel)\n overlay?.open()\n showOverlayPresence(panel, { isInstant })\n }\n\n const dispose = () => {\n overlay?.dispose()\n overlay = undefined\n releaseHandle()\n disposePortal()\n }\n\n return {\n getPanel() {\n return getPanel()\n },\n\n getHandle() {\n return handle\n },\n\n open,\n\n async close(isStillOpen) {\n /*\n * 第三态「可见但暂缓仲裁」:退场等待期间面板仍在场,登记不撤,但不再走关闭\n * 入口——它已经在关的路上了。撤销推迟到动画结束,或被 `open()` 以新会话取代。\n *\n * 旧实现在这里立即 `releaseHandle()`,于是两条提前返回的路径都把还看得见的面板\n * 留在未登记状态:未登记即不参与「谁是最内层」的仲裁,直到下一次 `open()` 才\n * 恢复(issue #138)。\n *\n * 暂缓层只是兜底候选:仍在开启的外层永远优先。否则「内层关掉后立刻再按一次\n * Escape」会被退场动画吞掉,外层永远等不到自己那一次——issue #120 的契约。\n *\n * 退场被打断时 `showOverlayPresence` 已把面板带回场,`open()` 同时重新 claim\n * (与「重复 open 视为新的一次开启」同一条路径),本条 `close()` 随后的\n * `return false` 不碰那个新句柄。\n *\n * 走到 `isStillOpen()` 时退场已经播完:面板已 `hidden`。此刻宿主仍认为开着,\n * 是面板状态与宿主状态不一致的那一格——把层交还仲裁而不是继续暂缓。继续暂缓的\n * 前提是「面板可见」,而这里面板已经看不见了:一个隐藏的面板无限吞掉 Escape,\n * 用户再也没有按键路径把这个状态收敛掉(按一次 Escape 走宿主的关闭入口,宿主\n * 回写 open=false 后由随后的 close() 正常收尾)。登记仍然不撤,「宿主认为开着\n * 就不掉出仲裁」的 #138 语义不变。\n */\n handle?.deferArbitration()\n overlay?.close()\n const panel = getPanel()\n if (panel && !(await hideOverlayPresence(panel))) return false\n if (isStillOpen()) {\n handle?.deferArbitration(false)\n return false\n }\n releaseHandle()\n disposePortal()\n return true\n },\n\n updatePosition() {\n overlay?.update(ctx.getPositioning())\n },\n\n reconfigure(isOpen) {\n const shouldAnimate = getPanel()?.dataset.wuiPresence === 'entering'\n dispose()\n if (isOpen) open(!shouldAnimate)\n },\n\n dispose\n }\n })\n"],"mappings":";;;;AA+CA,IAAa,UACX,GAAqD,MAAO;CAC1D,IAAI,GACA,GACA,IAAmC,MAEjC,UAAiB,GAAQ,SAAS,EAAI,cAAc,GAEpD,UAAsB;EAE1B,AADA,GAAQ,QAAQ,GAChB,IAAS;CACX,GAEM,UAAsB;EACrB,MACL,EAAO,eAAe,GACtB,EAAO,OAAO,GACd,IAAS,KAAA,GACT,IAAU,KAAA;CACZ,GAEM,UACC,EAAI,SAAS,KAClB,MAAW,EAAI,aAAa,GACrB,EAAO,SAFc,EAAI,cAAc,GAK1C,KAAiB,GAAqB,MAAuB;EACjE,IAAI,GAAS;GAEX,AADA,EAAQ,aAAa,CAAM,GAC3B,EAAQ,OAAO,EAAI,eAAe,CAAC;GACnC;EACF;EACA,IAAU,EAAc,CAAC,CAAC,KAAK;GAAE;GAAQ,SAAS;GAAO,GAAG,EAAI,eAAe;EAAE,CAAC;CACpF,GAEM,KAAQ,IAAY,OAAU;EAClC,IAAM,IAAS,EAAI,UAAU;EAC7B,IAAI,CAAC,GAAQ;EACb,IAAM,IAAQ,EAAiB;EAC1B,MAIL,EAAc,GACd,IAAS,EAAI,YAAY,MAAM,GAAO;GAAE,aAAa,EAAI;GAAa,cAAc;EAAO,CAAC,GAC5F,EAAc,GAAQ,CAAK,GAC3B,GAAS,KAAK,GACd,EAAoB,GAAO,EAAE,aAAU,CAAC;CAC1C,GAEM,UAAgB;EAIpB,AAHA,GAAS,QAAQ,GACjB,IAAU,KAAA,GACV,EAAc,GACd,EAAc;CAChB;CAEA,OAAO;EACL,WAAW;GACT,OAAO,EAAS;EAClB;EAEA,YAAY;GACV,OAAO;EACT;EAEA;EAEA,MAAM,MAAM,GAAa;GAwBvB,AADA,GAAQ,iBAAiB,GACzB,GAAS,MAAM;GACf,IAAM,IAAQ,EAAS;GAQvB,OAPI,KAAS,CAAE,MAAM,EAAoB,CAAK,IAAW,KACrD,EAAY,KACd,GAAQ,iBAAiB,EAAK,GACvB,OAET,EAAc,GACd,EAAc,GACP;EACT;EAEA,iBAAiB;GACf,GAAS,OAAO,EAAI,eAAe,CAAC;EACtC;EAEA,YAAY,GAAQ;GAClB,IAAM,IAAgB,EAAS,CAAC,EAAE,QAAQ,gBAAgB;GAE1D,AADA,EAAQ,GACJ,KAAQ,EAAK,CAAC,CAAa;EACjC;EAEA;CACF;AACF,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { definePlugin as e } from "@greypan/js-kit";
|
|
2
2
|
//#region src/shared/overlay/open-overlay.ts
|
|
3
3
|
var t = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new WeakMap(), r = /* @__PURE__ */ new WeakMap(), i = /* @__PURE__ */ new WeakMap(), a = /* @__PURE__ */ new WeakMap(), o = !1, s = 0, c = {
|
|
4
|
+
deferArbitration() {},
|
|
4
5
|
setInert() {},
|
|
5
6
|
adopt: () => c,
|
|
6
7
|
contains: () => !1,
|
|
@@ -58,10 +59,11 @@ function g(e) {
|
|
|
58
59
|
let e = n.get(t);
|
|
59
60
|
e ? g(e) : d(t);
|
|
60
61
|
}
|
|
61
|
-
t.delete(e), n.delete(e.panel), a.delete(e.panel), d(e.panel)
|
|
62
|
+
t.delete(e), n.delete(e.panel), a.delete(e.panel), d(e.panel);
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
function _(e) {
|
|
66
|
+
S();
|
|
65
67
|
let i = n.get(e.panel);
|
|
66
68
|
i && g(i);
|
|
67
69
|
let a = {
|
|
@@ -69,11 +71,15 @@ function _(e) {
|
|
|
69
71
|
host: e.host,
|
|
70
72
|
arbitration: e.arbitration,
|
|
71
73
|
inert: !1,
|
|
74
|
+
deferred: !1,
|
|
72
75
|
seq: ++s,
|
|
73
76
|
released: !1
|
|
74
77
|
};
|
|
75
78
|
t.add(a), n.set(e.panel, a), f(e.panel, e.parent);
|
|
76
79
|
let o = {
|
|
80
|
+
deferArbitration(e = !0) {
|
|
81
|
+
a.released || (a.deferred = e);
|
|
82
|
+
},
|
|
77
83
|
setInert(e) {
|
|
78
84
|
a.released || (a.inert = e);
|
|
79
85
|
},
|
|
@@ -95,43 +101,53 @@ function _(e) {
|
|
|
95
101
|
return !a.released && m(a.panel);
|
|
96
102
|
},
|
|
97
103
|
release() {
|
|
98
|
-
g(a);
|
|
104
|
+
g(a), C();
|
|
99
105
|
}
|
|
100
106
|
};
|
|
101
|
-
return r.set(o, a),
|
|
107
|
+
return r.set(o, a), C(!1), o;
|
|
102
108
|
}
|
|
103
109
|
function v(e) {
|
|
104
110
|
return !e.released && e.arbitration !== "none" && e.panel.isConnected;
|
|
105
111
|
}
|
|
106
|
-
function y() {
|
|
107
|
-
let
|
|
108
|
-
for (let n of
|
|
109
|
-
if (!
|
|
110
|
-
|
|
112
|
+
function y(e) {
|
|
113
|
+
let t = null;
|
|
114
|
+
for (let n of e) {
|
|
115
|
+
if (!t) {
|
|
116
|
+
t = n;
|
|
111
117
|
continue;
|
|
112
118
|
}
|
|
113
|
-
if (p(
|
|
114
|
-
|
|
119
|
+
if (p(t.panel, n.panel)) {
|
|
120
|
+
t = n;
|
|
115
121
|
continue;
|
|
116
122
|
}
|
|
117
|
-
p(n.panel,
|
|
123
|
+
p(n.panel, t.panel) || n.seq > t.seq && (t = n);
|
|
118
124
|
}
|
|
119
|
-
return
|
|
125
|
+
return t;
|
|
126
|
+
}
|
|
127
|
+
function b() {
|
|
128
|
+
C();
|
|
129
|
+
let e = [], n = [];
|
|
130
|
+
for (let r of t) v(r) && (r.deferred ? n.push(r) : e.push(r));
|
|
131
|
+
return y(e) ?? y(n);
|
|
120
132
|
}
|
|
121
|
-
function
|
|
133
|
+
function x(e) {
|
|
122
134
|
if (e.key !== "Escape" || e.defaultPrevented) return;
|
|
123
|
-
let t =
|
|
124
|
-
t && (e.preventDefault(), e.stopPropagation(), !t.inert && t.host.requestClose());
|
|
135
|
+
let t = b();
|
|
136
|
+
t && (e.preventDefault(), e.stopPropagation(), !(t.inert || t.deferred) && t.host.requestClose());
|
|
137
|
+
}
|
|
138
|
+
function S() {
|
|
139
|
+
for (let e of Array.from(t)) e.released || e.panel.isConnected || e.host.isConnected() || g(e);
|
|
125
140
|
}
|
|
126
|
-
function
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
141
|
+
function C(e = !0) {
|
|
142
|
+
e && S();
|
|
143
|
+
let n = !1;
|
|
144
|
+
for (let e of t) if (!e.released && e.arbitration !== "none") {
|
|
145
|
+
n = !0;
|
|
130
146
|
break;
|
|
131
147
|
}
|
|
132
|
-
|
|
148
|
+
n !== o && (o = n, n ? document.addEventListener("keydown", x, !0) : document.removeEventListener("keydown", x, !0));
|
|
133
149
|
}
|
|
134
|
-
var
|
|
150
|
+
var w = () => e((e) => {
|
|
135
151
|
let t = 0, n = !1, i = /* @__PURE__ */ new Set(), a = (e) => {
|
|
136
152
|
cancelAnimationFrame(e.id), i.delete(e);
|
|
137
153
|
}, o = () => {
|
|
@@ -177,6 +193,6 @@ var S = () => e((e) => {
|
|
|
177
193
|
};
|
|
178
194
|
});
|
|
179
195
|
//#endregion
|
|
180
|
-
export {
|
|
196
|
+
export { w as defineOpenOverlay };
|
|
181
197
|
|
|
182
198
|
//# sourceMappingURL=open-overlay.js.map
|