@greypan/web-ui 2.1.7 → 3.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 +95 -41
- package/README.md +100 -42
- package/dist/assets/glass.js.map +1 -1
- package/dist/assets/menu-portal.js +1 -1
- package/dist/assets/menu-portal.js.map +1 -1
- package/dist/components/autocomplete/index.d.ts +121 -0
- package/dist/components/autocomplete/index.js +414 -0
- package/dist/components/autocomplete/index.js.map +1 -0
- package/dist/components/autocomplete/style.js +6 -0
- package/dist/components/autocomplete/style.js.map +1 -0
- package/dist/components/avatar/index.d.ts +0 -1
- package/dist/components/avatar/index.js +9 -9
- package/dist/components/avatar/index.js.map +1 -1
- package/dist/components/back-top/index.d.ts +0 -1
- package/dist/components/back-top/index.js +1 -1
- package/dist/components/back-top/index.js.map +1 -1
- package/dist/components/badge/index.d.ts +0 -1
- package/dist/components/badge/index.js +5 -5
- package/dist/components/badge/index.js.map +1 -1
- package/dist/components/button/index.d.ts +6 -2
- package/dist/components/button/index.js +40 -19
- package/dist/components/button/index.js.map +1 -1
- package/dist/components/button/style.js +1 -1
- package/dist/components/button/style.js.map +1 -1
- package/dist/components/button-group/index.d.ts +0 -1
- package/dist/components/button-group/index.js.map +1 -1
- package/dist/components/checkbox/index.d.ts +0 -3
- package/dist/components/checkbox/index.js +7 -5
- package/dist/components/checkbox/index.js.map +1 -1
- package/dist/components/checkbox-group/index.js +2 -2
- package/dist/components/checkbox-group/index.js.map +1 -1
- package/dist/components/context-menu/index.d.ts +4 -3
- package/dist/components/context-menu/index.js +47 -50
- package/dist/components/context-menu/index.js.map +1 -1
- package/dist/components/dialog/index.d.ts +1 -1
- package/dist/components/dialog/index.js +20 -19
- package/dist/components/dialog/index.js.map +1 -1
- package/dist/components/drawer/index.d.ts +2 -3
- package/dist/components/drawer/index.js +43 -33
- package/dist/components/drawer/index.js.map +1 -1
- package/dist/components/drawer/style.js +1 -1
- package/dist/components/drawer/style.js.map +1 -1
- package/dist/components/dropdown/index.d.ts +2 -9
- package/dist/components/dropdown/index.js +58 -53
- package/dist/components/dropdown/index.js.map +1 -1
- package/dist/components/dropdown-divider/index.d.ts +0 -1
- package/dist/components/dropdown-divider/index.js.map +1 -1
- package/dist/components/dropdown-header/index.d.ts +0 -1
- package/dist/components/dropdown-header/index.js.map +1 -1
- package/dist/components/dropdown-item/index.d.ts +0 -2
- package/dist/components/dropdown-item/index.js.map +1 -1
- package/dist/components/dropdown-item/style.js +1 -1
- package/dist/components/dropdown-item/style.js.map +1 -1
- package/dist/components/empty/index.d.ts +0 -1
- package/dist/components/empty/index.js +6 -6
- package/dist/components/empty/index.js.map +1 -1
- package/dist/components/icon/index.d.ts +0 -1
- package/dist/components/icon/index.js.map +1 -1
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.js +36 -35
- package/dist/components/input/index.d.ts +3 -0
- package/dist/components/input/index.js +48 -24
- package/dist/components/input/index.js.map +1 -1
- package/dist/components/input/style.js +1 -1
- package/dist/components/input/style.js.map +1 -1
- package/dist/components/input-number/index.d.ts +2 -0
- package/dist/components/input-number/index.js +25 -12
- package/dist/components/input-number/index.js.map +1 -1
- package/dist/components/input-number/style.js +1 -1
- package/dist/components/input-number/style.js.map +1 -1
- package/dist/components/layout/index.d.ts +0 -1
- package/dist/components/layout/index.js +4 -4
- package/dist/components/layout/index.js.map +1 -1
- package/dist/components/option/index.d.ts +0 -11
- package/dist/components/option/index.js +1 -1
- package/dist/components/option/index.js.map +1 -1
- package/dist/components/option/style.js +1 -1
- package/dist/components/option/style.js.map +1 -1
- package/dist/components/popover/index.d.ts +1 -5
- package/dist/components/popover/index.js +42 -37
- package/dist/components/popover/index.js.map +1 -1
- package/dist/components/radio/index.d.ts +0 -3
- package/dist/components/radio/index.js +8 -5
- package/dist/components/radio/index.js.map +1 -1
- package/dist/components/radio-group/index.js +2 -2
- package/dist/components/radio-group/index.js.map +1 -1
- package/dist/components/segmented/index.js +8 -4
- package/dist/components/segmented/index.js.map +1 -1
- package/dist/components/segmented-trigger/index.d.ts +1 -0
- package/dist/components/segmented-trigger/index.js +12 -3
- package/dist/components/segmented-trigger/index.js.map +1 -1
- package/dist/components/segmented-trigger/style.js +1 -1
- package/dist/components/segmented-trigger/style.js.map +1 -1
- package/dist/components/select/index.d.ts +0 -1
- package/dist/components/select/index.js +22 -31
- package/dist/components/select/index.js.map +1 -1
- package/dist/components/select/style.js +1 -1
- package/dist/components/select/style.js.map +1 -1
- package/dist/components/slider/index.d.ts +0 -2
- package/dist/components/slider/index.js +1 -1
- package/dist/components/slider/index.js.map +1 -1
- package/dist/components/spinner/index.d.ts +0 -3
- package/dist/components/spinner/index.js.map +1 -1
- package/dist/components/svg-draw-lines/index.d.ts +0 -3
- package/dist/components/svg-draw-lines/index.js.map +1 -1
- package/dist/components/switch/index.d.ts +0 -1
- package/dist/components/switch/index.js +6 -6
- package/dist/components/switch/index.js.map +1 -1
- package/dist/components/switch/style.js +1 -1
- package/dist/components/switch/style.js.map +1 -1
- package/dist/components/textarea/index.d.ts +1 -0
- package/dist/components/textarea/index.js +51 -34
- package/dist/components/textarea/index.js.map +1 -1
- package/dist/components/textarea/style.js +1 -1
- package/dist/components/textarea/style.js.map +1 -1
- package/dist/components/theme/index.d.ts +0 -3
- package/dist/components/theme/index.js.map +1 -1
- package/dist/components/toast/manager.js.map +1 -1
- package/dist/components/toast/style.js +1 -1
- package/dist/components/toast/style.js.map +1 -1
- package/dist/components/toast/toast.d.ts +0 -4
- package/dist/components/toast/toast.js +25 -17
- package/dist/components/toast/toast.js.map +1 -1
- package/dist/components/toast/types.d.ts +0 -3
- package/dist/components/tooltip/index.d.ts +1 -0
- package/dist/components/tooltip/index.js +34 -33
- package/dist/components/tooltip/index.js.map +1 -1
- package/dist/shared/events/user-change.js +17 -0
- package/dist/shared/events/user-change.js.map +1 -0
- package/dist/shared/menu-portal/menu-portal.js +10 -11
- package/dist/shared/menu-portal/menu-portal.js.map +1 -1
- package/dist/shared/normalize/index.js.map +1 -1
- package/dist/shared/overlay/anchored-panel.js +12 -12
- package/dist/shared/overlay/native-dialog-presence.js +8 -3
- package/dist/shared/overlay/native-dialog-presence.js.map +1 -1
- package/dist/shared/overlay/overlay.js +55 -33
- package/dist/shared/overlay/overlay.js.map +1 -1
- package/dist/shared/overlay/portal.js +27 -13
- package/dist/shared/overlay/portal.js.map +1 -1
- package/dist/shared/overlay/presence.js.map +1 -1
- package/dist/shared/scroll-lock/scroll-lock.js +13 -12
- package/dist/shared/scroll-lock/scroll-lock.js.map +1 -1
- package/dist/shared/theme/overlay-root.js +3 -3
- package/dist/types/react.d.ts +15 -41
- package/dist/types/utils.d.ts +33 -4
- package/dist/types/vue.d.ts +17 -49
- package/package.json +11 -6
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
import e from "../../_virtual/_@oxc-project_runtime@0.140.0/helpers/esm/decorate.js";
|
|
2
|
+
import "../option/index.js";
|
|
3
|
+
import t from "../../assets/glass.js";
|
|
4
|
+
import n from "../../assets/overlay-motion.js";
|
|
5
|
+
import { normalizeLiteral as r } from "../../shared/normalize/index.js";
|
|
6
|
+
import { defineAnchoredPanel as i } from "../../shared/overlay/anchored-panel.js";
|
|
7
|
+
import { defineOverlayPortal as a } from "../../shared/overlay/portal.js";
|
|
8
|
+
import { defineScrollLockLease as o } from "../../shared/scroll-lock/scroll-lock.js";
|
|
9
|
+
import s from "./style.js";
|
|
10
|
+
import { LitElement as c, html as l, nothing as u, unsafeCSS as d } from "lit";
|
|
11
|
+
import { customElement as f, property as p, state as m } from "lit/decorators.js";
|
|
12
|
+
import { ifDefined as h } from "lit/directives/if-defined.js";
|
|
13
|
+
//#region src/components/autocomplete/index.ts
|
|
14
|
+
var g, _ = [
|
|
15
|
+
"none",
|
|
16
|
+
"prefix",
|
|
17
|
+
"contains"
|
|
18
|
+
], v = class extends c {
|
|
19
|
+
static {
|
|
20
|
+
g = this;
|
|
21
|
+
}
|
|
22
|
+
constructor(...e) {
|
|
23
|
+
super(...e), this._formDisabled = !1, this.placeholder = "", this.disabled = !1, this.readonly = !1, this.required = !1, this.portal = !1, this.noScrollLock = !1, this.name = "", this.ariaLabel = null, this._filter = "contains", this._value = "", this._selectedValue = "", this._isOpen = !1, this._activeIndex = -1, this._focused = !1, this._idPrefix = `web-ui-autocomplete-${++g._nextInstanceId}`, this._optionIds = /* @__PURE__ */ new WeakMap(), this._a11yOptionIds = /* @__PURE__ */ new WeakMap(), this._nextOptionId = 0, this._nextA11yOptionId = 0, this._options = [], this._pendingUnregisteredOptions = /* @__PURE__ */ new Set(), this._scrollLock = o().make(), this._panel = i().make({
|
|
24
|
+
getAnchor: () => this.shadowRoot?.querySelector(".input-wrapper") ?? null,
|
|
25
|
+
getLocalPanel: () => this.shadowRoot?.querySelector(".autocomplete-overlay") ?? null,
|
|
26
|
+
getPositioning: () => ({
|
|
27
|
+
placement: "bottom-start",
|
|
28
|
+
offset: 4,
|
|
29
|
+
minAnchorWidth: !0,
|
|
30
|
+
strategy: this.portal ? "fixed" : "absolute"
|
|
31
|
+
}),
|
|
32
|
+
isPortal: () => this.portal,
|
|
33
|
+
createPortal: () => this._createPortal()
|
|
34
|
+
}), this._onClickOutside = (e) => {
|
|
35
|
+
if (!this._isOpen) return;
|
|
36
|
+
let t = e.composedPath(), n = this._panel.getPanel();
|
|
37
|
+
!t.includes(this) && (!n || !t.includes(n)) && this._close();
|
|
38
|
+
}, this._onFocusOut = () => {
|
|
39
|
+
requestAnimationFrame(() => {
|
|
40
|
+
this._isOpen && !this.matches(":focus-within") && !this._panel.getPanel()?.matches(":focus-within") && this._close();
|
|
41
|
+
});
|
|
42
|
+
}, this._handlePanelPointerDown = (e) => {
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
}, this._bindOption = (e) => {
|
|
45
|
+
e.addEventListener("click", this._handleOptionClick), e.addEventListener("pointerover", this._handleOptionPointerOver), e.addEventListener("pointerdown", this._handleOptionPointerDown), e.addEventListener("option-update", this._onOptionUpdate), e.addEventListener("option-unregister", this._onOptionUnregister);
|
|
46
|
+
}, this._unbindOption = (e) => {
|
|
47
|
+
e.removeEventListener("click", this._handleOptionClick), e.removeEventListener("pointerover", this._handleOptionPointerOver), e.removeEventListener("pointerdown", this._handleOptionPointerDown), e.removeEventListener("option-update", this._onOptionUpdate), e.removeEventListener("option-unregister", this._onOptionUnregister);
|
|
48
|
+
}, this._onOptionRegister = () => {
|
|
49
|
+
this._scheduleOptionsRefresh();
|
|
50
|
+
}, this._onOptionUnregister = (e) => {
|
|
51
|
+
e.target instanceof HTMLElement && e.target.localName === "web-ui-option" && this._pendingUnregisteredOptions.add(e.target), this._scheduleOptionsRefresh();
|
|
52
|
+
}, this._onSlotChange = () => {
|
|
53
|
+
this._scheduleOptionsRefresh();
|
|
54
|
+
}, this._handleOptionClick = (e) => {
|
|
55
|
+
if (!(e.currentTarget instanceof HTMLElement)) return;
|
|
56
|
+
let t = e.currentTarget;
|
|
57
|
+
t.disabled || this._selectOption(t);
|
|
58
|
+
}, this._onOptionUpdate = () => {
|
|
59
|
+
this._scheduleOptionsRefresh();
|
|
60
|
+
}, this._handleOptionPointerOver = (e) => {
|
|
61
|
+
e.pointerType !== "touch" && (!this._isOpen || !(e.currentTarget instanceof HTMLElement) || (this._activeIndex = -1, this._syncActiveOption()));
|
|
62
|
+
}, this._handleOptionPointerDown = (e) => {
|
|
63
|
+
e.preventDefault();
|
|
64
|
+
}, this._onKeydown = (e) => {
|
|
65
|
+
if (!(this._isDisabled || this.readonly)) switch (e.key) {
|
|
66
|
+
case "Escape":
|
|
67
|
+
this._isOpen && (this._close(), e.preventDefault());
|
|
68
|
+
break;
|
|
69
|
+
case "ArrowDown":
|
|
70
|
+
e.preventDefault(), this._isOpen ? this._navigateActive(1) : this._open(!0);
|
|
71
|
+
break;
|
|
72
|
+
case "ArrowUp":
|
|
73
|
+
e.preventDefault(), this._isOpen ? this._navigateActive(-1) : this._open(!0);
|
|
74
|
+
break;
|
|
75
|
+
case "Enter":
|
|
76
|
+
if (this._isOpen) {
|
|
77
|
+
e.preventDefault();
|
|
78
|
+
let t = this._options[this._activeIndex];
|
|
79
|
+
t && !t.disabled && !t.hasAttribute("data-filtered") && this._selectOption(t);
|
|
80
|
+
}
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}, this._onInput = (e) => {
|
|
84
|
+
if (this._isDisabled || this.readonly) return;
|
|
85
|
+
let t = e.target;
|
|
86
|
+
t.value !== this._value && (this.value = t.value, this._activeIndex = -1, this._syncActiveOption(), this._isOpen || this._open());
|
|
87
|
+
}, this._onInnerChange = (e) => {
|
|
88
|
+
e.stopPropagation();
|
|
89
|
+
}, this._onFocus = () => {
|
|
90
|
+
this._isDisabled || (this._focused = !0, !this.readonly && this._options.length > 0 && this._open());
|
|
91
|
+
}, this._onBlur = () => {
|
|
92
|
+
this._focused = !1;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
static {
|
|
96
|
+
this.styles = [
|
|
97
|
+
d(t),
|
|
98
|
+
d(n),
|
|
99
|
+
d(s)
|
|
100
|
+
];
|
|
101
|
+
}
|
|
102
|
+
static {
|
|
103
|
+
this.formAssociated = !0;
|
|
104
|
+
}
|
|
105
|
+
get filter() {
|
|
106
|
+
return this._filter;
|
|
107
|
+
}
|
|
108
|
+
set filter(e) {
|
|
109
|
+
let t = this._filter;
|
|
110
|
+
this._filter = r(e, _, "contains"), this.requestUpdate("filter", t);
|
|
111
|
+
}
|
|
112
|
+
get value() {
|
|
113
|
+
return this._value;
|
|
114
|
+
}
|
|
115
|
+
set value(e) {
|
|
116
|
+
let t = this._value;
|
|
117
|
+
this._value = e, this._internals?.setFormValue?.(e), this.requestUpdate("value", t);
|
|
118
|
+
}
|
|
119
|
+
get selectedValue() {
|
|
120
|
+
return this._selectedValue;
|
|
121
|
+
}
|
|
122
|
+
_setSelectedValue(e) {
|
|
123
|
+
let t = this._selectedValue;
|
|
124
|
+
(t !== e || this.getAttribute("selected-value") !== e) && (this._selectedValue = e, this.setAttribute("selected-value", e), t !== e && this.requestUpdate("selectedValue", t));
|
|
125
|
+
}
|
|
126
|
+
get _isDisabled() {
|
|
127
|
+
return this.disabled || this._formDisabled;
|
|
128
|
+
}
|
|
129
|
+
static {
|
|
130
|
+
this._nextInstanceId = 0;
|
|
131
|
+
}
|
|
132
|
+
get isOpen() {
|
|
133
|
+
return this._isOpen;
|
|
134
|
+
}
|
|
135
|
+
get open() {
|
|
136
|
+
return this._isOpen;
|
|
137
|
+
}
|
|
138
|
+
connectedCallback() {
|
|
139
|
+
super.connectedCallback(), this._internals ||= this.attachInternals();
|
|
140
|
+
let e = this.getAttribute("value");
|
|
141
|
+
e !== null && (this._value = e, this._internals?.setFormValue?.(e)), this.addEventListener("option-register", this._onOptionRegister), this.addEventListener("option-unregister", this._onOptionUnregister), this.addEventListener("keydown", this._onKeydown), this.addEventListener("focusout", this._onFocusOut), document.addEventListener("click", this._onClickOutside);
|
|
142
|
+
}
|
|
143
|
+
attributeChangedCallback(e, t, n) {
|
|
144
|
+
super.attributeChangedCallback(e, t, n), e === "selected-value" && this.isConnected && n !== this._selectedValue && queueMicrotask(() => {
|
|
145
|
+
this.isConnected && this._syncSelectedValue();
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
disconnectedCallback() {
|
|
149
|
+
super.disconnectedCallback(), this.removeEventListener("option-register", this._onOptionRegister), this.removeEventListener("option-unregister", this._onOptionUnregister), this.removeEventListener("keydown", this._onKeydown), this.removeEventListener("focusout", this._onFocusOut), document.removeEventListener("click", this._onClickOutside), this._options.forEach(this._unbindOption), this._pendingUnregisteredOptions.clear(), this._close(), this._portal = void 0, this._portalContent = void 0, this._panel.dispose(), this._scrollLock.release();
|
|
150
|
+
}
|
|
151
|
+
firstUpdated() {
|
|
152
|
+
requestAnimationFrame(() => {
|
|
153
|
+
this.isConnected && this._onSlotChange();
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
_queryOptions() {
|
|
157
|
+
let e = this.portal ? this._panel.getPanel() : null, t = e ? [...e.querySelectorAll("web-ui-option")] : [];
|
|
158
|
+
return t.length > 0 ? t : [...this.querySelectorAll("web-ui-option")];
|
|
159
|
+
}
|
|
160
|
+
willUpdate() {
|
|
161
|
+
this._refreshOptions(), this._ensureOptionIds(), this._syncSelectedValue(), this._applyFilter(), this._syncOptionA11y(), this._syncActiveOption();
|
|
162
|
+
}
|
|
163
|
+
updated(e) {
|
|
164
|
+
let t = this.shadowRoot?.querySelector(".autocomplete-input");
|
|
165
|
+
t && t.value !== this._value && (t.value = this._value), (e.has("portal") || e.has("overlayContainer")) && requestAnimationFrame(() => this._reconfigureOverlay()), e.has("noScrollLock") && this._syncScrollLock(), this.toggleAttribute("focused", this._focused), this._syncOpenAttribute(), this._syncValidity(), this._syncEmptyState();
|
|
166
|
+
}
|
|
167
|
+
formResetCallback() {
|
|
168
|
+
this.value = this.getAttribute("value") || "";
|
|
169
|
+
}
|
|
170
|
+
formDisabledCallback(e) {
|
|
171
|
+
this._formDisabled = e, e && this._isOpen && this._close();
|
|
172
|
+
}
|
|
173
|
+
formStateRestoreCallback(e) {
|
|
174
|
+
typeof e == "string" && (this.value = e);
|
|
175
|
+
}
|
|
176
|
+
_syncValidity() {
|
|
177
|
+
!this._internals || typeof this._internals.setValidity != "function" || (this._isDisabled || this.readonly || !this.required || this._value ? this._internals.setValidity({}) : this._internals.setValidity({ valueMissing: !0 }, "请输入内容"));
|
|
178
|
+
}
|
|
179
|
+
_syncOpenAttribute() {
|
|
180
|
+
this.toggleAttribute("open", this._isOpen);
|
|
181
|
+
}
|
|
182
|
+
_syncSelectedValue() {
|
|
183
|
+
let e = this._value.trim().toLowerCase(), t = e ? this._options.find((t) => t.label.trim().toLowerCase() === e)?.value ?? "" : "";
|
|
184
|
+
this._setSelectedValue(t);
|
|
185
|
+
}
|
|
186
|
+
_syncOptionA11y() {
|
|
187
|
+
this._options.forEach((e) => {
|
|
188
|
+
e.setAttribute("role", "option"), e.setAttribute("aria-selected", e.value === this._selectedValue ? "true" : "false"), e.setAttribute("aria-hidden", "true");
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
_ensureOptionIds() {
|
|
192
|
+
let e = new Set(this._options.map((e) => e.id).filter(Boolean));
|
|
193
|
+
this._options.forEach((t) => {
|
|
194
|
+
if (t.id) return;
|
|
195
|
+
let n = this._optionIds.get(t);
|
|
196
|
+
if (!n || e.has(n)) {
|
|
197
|
+
do
|
|
198
|
+
n = `${this._idPrefix}-option-${++this._nextOptionId}`;
|
|
199
|
+
while (e.has(n));
|
|
200
|
+
this._optionIds.set(t, n);
|
|
201
|
+
}
|
|
202
|
+
t.id = n, e.add(n);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
_getA11yOptionId(e) {
|
|
206
|
+
let t = this._a11yOptionIds.get(e);
|
|
207
|
+
return t || (t = `${this._idPrefix}-a11y-option-${++this._nextA11yOptionId}`, this._a11yOptionIds.set(e, t)), t;
|
|
208
|
+
}
|
|
209
|
+
_applyFilter() {
|
|
210
|
+
let e = this._value.trim().toLowerCase(), t = this._filter;
|
|
211
|
+
this._options.forEach((n) => {
|
|
212
|
+
let r = n.label.trim().toLowerCase(), i = t === "none" || !e || (t === "prefix" ? r.startsWith(e) : r.includes(e));
|
|
213
|
+
n.toggleAttribute("data-filtered", !i);
|
|
214
|
+
});
|
|
215
|
+
let n = this._options[this._activeIndex];
|
|
216
|
+
this._activeIndex >= 0 && (!n || n.hasAttribute("data-filtered") || n.disabled) && (this._activeIndex = -1, this._syncActiveOption());
|
|
217
|
+
}
|
|
218
|
+
_syncEmptyState() {
|
|
219
|
+
let e = this._panel.getPanel();
|
|
220
|
+
if (!e) return;
|
|
221
|
+
let t = e.querySelector(".autocomplete-empty");
|
|
222
|
+
if (!t) return;
|
|
223
|
+
let n = this._options.filter((e) => !e.hasAttribute("data-filtered"));
|
|
224
|
+
t.hidden = !(this._options.length > 0 && n.length === 0);
|
|
225
|
+
}
|
|
226
|
+
_refreshOptions() {
|
|
227
|
+
let e = this._options[this._activeIndex], t = this._queryOptions();
|
|
228
|
+
this._options.filter((e) => !t.includes(e)).forEach(this._unbindOption), t.forEach(this._bindOption), this._options = t, this._activeIndex = e && t.includes(e) ? t.indexOf(e) : -1;
|
|
229
|
+
}
|
|
230
|
+
_syncPortalContent() {
|
|
231
|
+
if (!this._portal || !this._portalContent) return;
|
|
232
|
+
for (let e of this._pendingUnregisteredOptions) !this._portalContent.contains(e) && !this.contains(e) && this._portal.removeContent([e]);
|
|
233
|
+
if (this._pendingUnregisteredOptions.clear(), !this._isOpen) return;
|
|
234
|
+
let e = Array.from(this.childNodes);
|
|
235
|
+
e.length && this._portal.appendContent(e, this._portalContent);
|
|
236
|
+
}
|
|
237
|
+
_scheduleOptionsRefresh() {
|
|
238
|
+
queueMicrotask(() => {
|
|
239
|
+
this.isConnected && (this._syncPortalContent(), this.requestUpdate());
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
_navigateActive(e) {
|
|
243
|
+
let t = this._options.filter((e) => !e.disabled && !e.hasAttribute("data-filtered"));
|
|
244
|
+
if (!t.length) return;
|
|
245
|
+
let n = (this._activeIndex >= 0 ? t.indexOf(this._options[this._activeIndex]) : e > 0 ? -1 : 0) + e;
|
|
246
|
+
n < 0 && (n = t.length - 1), n >= t.length && (n = 0), this._activeIndex = this._options.indexOf(t[n]), this._syncActiveOption();
|
|
247
|
+
}
|
|
248
|
+
_setInitialActiveOption() {
|
|
249
|
+
let e = this._options.findIndex((e) => !e.disabled && !e.hasAttribute("data-filtered"));
|
|
250
|
+
this._activeIndex = e, this._syncActiveOption();
|
|
251
|
+
}
|
|
252
|
+
_syncActiveOption() {
|
|
253
|
+
this._options.forEach((e, t) => e.toggleAttribute("active", t === this._activeIndex));
|
|
254
|
+
}
|
|
255
|
+
_selectOption(e) {
|
|
256
|
+
this.readonly || (this.value = e.label, this._setSelectedValue(e.value), this._close(), this.dispatchEvent(new Event("input", {
|
|
257
|
+
bubbles: !0,
|
|
258
|
+
composed: !0
|
|
259
|
+
})), this.dispatchEvent(new Event("change", {
|
|
260
|
+
bubbles: !0,
|
|
261
|
+
composed: !0
|
|
262
|
+
})));
|
|
263
|
+
}
|
|
264
|
+
_open(e = !1) {
|
|
265
|
+
this._isDisabled || this.readonly || this._isOpen || (this._isOpen = !0, this._dispatchOpenChange(), e ? this._setInitialActiveOption() : this._syncActiveOption(), this._syncScrollLock(), this.portal ? requestAnimationFrame(() => {
|
|
266
|
+
this._isOpen && this._openOverlay(e);
|
|
267
|
+
}) : this._openOverlay(e));
|
|
268
|
+
}
|
|
269
|
+
_close() {
|
|
270
|
+
this._isOpen && (this._syncPortalContent(), this._isOpen = !1, this._dispatchOpenChange(), this._activeIndex = -1, this._options.forEach((e) => e.removeAttribute("active")), this._syncScrollLock(!1), this._closeOverlay());
|
|
271
|
+
}
|
|
272
|
+
_dispatchOpenChange() {
|
|
273
|
+
this.dispatchEvent(new CustomEvent("open-change", {
|
|
274
|
+
detail: { open: this._isOpen },
|
|
275
|
+
bubbles: !0,
|
|
276
|
+
composed: !0
|
|
277
|
+
}));
|
|
278
|
+
}
|
|
279
|
+
_openOverlay(e = !1) {
|
|
280
|
+
this._panel.open(e), this._syncEmptyState();
|
|
281
|
+
}
|
|
282
|
+
async _closeOverlay() {
|
|
283
|
+
await this._panel.close(() => this._isOpen) && (this._portal = void 0, this._portalContent = void 0);
|
|
284
|
+
}
|
|
285
|
+
_reconfigureOverlay() {
|
|
286
|
+
this._portal = void 0, this._portalContent = void 0, this._panel.reconfigure(this._isOpen);
|
|
287
|
+
}
|
|
288
|
+
_syncScrollLock(e = this._isOpen) {
|
|
289
|
+
this._scrollLock.sync(e && !this.noScrollLock);
|
|
290
|
+
}
|
|
291
|
+
_createPortal() {
|
|
292
|
+
let e = a().make({
|
|
293
|
+
container: this.overlayContainer,
|
|
294
|
+
target: this,
|
|
295
|
+
style: `${t}\n${n}\n${s}`,
|
|
296
|
+
className: "wui-glass autocomplete-overlay portal wui-floating-panel"
|
|
297
|
+
});
|
|
298
|
+
this._portal = e, e.panel.setAttribute("aria-hidden", "true"), e.panel.addEventListener("pointerdown", this._handlePanelPointerDown);
|
|
299
|
+
let r = document.createElement("div");
|
|
300
|
+
r.className = "autocomplete-scroll";
|
|
301
|
+
let i = document.createElement("div");
|
|
302
|
+
i.className = "autocomplete-content", this._portalContent = i;
|
|
303
|
+
let o = document.createElement("div");
|
|
304
|
+
return o.className = "autocomplete-empty", o.hidden = !0, o.textContent = "无匹配选项", r.append(i), i.append(o), e.panel.append(r), e.moveContent(Array.from(this.children), i), e;
|
|
305
|
+
}
|
|
306
|
+
_getLabelledbyText() {
|
|
307
|
+
if (!this.ariaLabelledby) return "";
|
|
308
|
+
let e = this.getRootNode();
|
|
309
|
+
return e instanceof Document || e instanceof ShadowRoot ? this.ariaLabelledby.trim().split(/\s+/).map((t) => {
|
|
310
|
+
let n = typeof CSS < "u" && CSS.escape ? CSS.escape(t) : t;
|
|
311
|
+
return e.querySelector(`#${n}`)?.textContent?.trim() ?? "";
|
|
312
|
+
}).filter(Boolean).join(" ") : "";
|
|
313
|
+
}
|
|
314
|
+
render() {
|
|
315
|
+
let e = `${this._idPrefix}-listbox`, t = `${this._idPrefix}-label`, n = this._getLabelledbyText(), r = this._options.filter((e) => !e.hasAttribute("data-filtered")), i = this._isOpen && this._activeIndex >= 0 ? this._options[this._activeIndex] : void 0, a = i ? this._getA11yOptionId(i) : u;
|
|
316
|
+
return l`
|
|
317
|
+
<div class="wui-autocomplete-inner">
|
|
318
|
+
${n ? l`<span class="autocomplete-a11y-only" id=${t}>${n}</span>` : u}
|
|
319
|
+
<div class="wui-glass input-wrapper">
|
|
320
|
+
<input
|
|
321
|
+
class="autocomplete-input"
|
|
322
|
+
type="text"
|
|
323
|
+
placeholder=${this.placeholder}
|
|
324
|
+
name=${this.name}
|
|
325
|
+
.value=${this._value}
|
|
326
|
+
aria-label=${h(this.ariaLabel)}
|
|
327
|
+
aria-labelledby=${n ? t : u}
|
|
328
|
+
?disabled=${this._isDisabled}
|
|
329
|
+
?readonly=${this.readonly}
|
|
330
|
+
?required=${this.required}
|
|
331
|
+
role="combobox"
|
|
332
|
+
aria-expanded=${this._isOpen}
|
|
333
|
+
aria-haspopup="listbox"
|
|
334
|
+
aria-autocomplete="list"
|
|
335
|
+
aria-controls=${e}
|
|
336
|
+
aria-disabled=${String(this._isDisabled)}
|
|
337
|
+
aria-readonly=${this.readonly ? "true" : u}
|
|
338
|
+
aria-activedescendant=${a}
|
|
339
|
+
@input=${this._onInput}
|
|
340
|
+
@change=${this._onInnerChange}
|
|
341
|
+
@focus=${this._onFocus}
|
|
342
|
+
@blur=${this._onBlur}
|
|
343
|
+
/>
|
|
344
|
+
</div>
|
|
345
|
+
<div
|
|
346
|
+
class="autocomplete-a11y-listbox"
|
|
347
|
+
id=${e}
|
|
348
|
+
role="listbox"
|
|
349
|
+
?hidden=${!this._isOpen}
|
|
350
|
+
aria-hidden=${String(!this._isOpen)}
|
|
351
|
+
>
|
|
352
|
+
${r.map((e) => l`<div
|
|
353
|
+
id=${this._getA11yOptionId(e)}
|
|
354
|
+
role="option"
|
|
355
|
+
aria-selected=${e.value === this._selectedValue ? "true" : "false"}
|
|
356
|
+
aria-hidden=${String(!this._isOpen)}
|
|
357
|
+
aria-disabled=${String(e.disabled)}
|
|
358
|
+
>
|
|
359
|
+
${e.label}
|
|
360
|
+
</div>`)}
|
|
361
|
+
</div>
|
|
362
|
+
<div
|
|
363
|
+
class="wui-glass autocomplete-overlay wui-floating-panel"
|
|
364
|
+
hidden
|
|
365
|
+
aria-hidden="true"
|
|
366
|
+
@pointerdown=${this._handlePanelPointerDown}
|
|
367
|
+
>
|
|
368
|
+
<div class="autocomplete-scroll">
|
|
369
|
+
<div class="autocomplete-content">
|
|
370
|
+
<slot @slotchange=${this._onSlotChange}></slot>
|
|
371
|
+
<div class="autocomplete-empty" hidden>无匹配选项</div>
|
|
372
|
+
</div>
|
|
373
|
+
</div>
|
|
374
|
+
</div>
|
|
375
|
+
</div>
|
|
376
|
+
`;
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
e([m()], v.prototype, "_formDisabled", void 0), e([p({
|
|
380
|
+
type: String,
|
|
381
|
+
reflect: !0
|
|
382
|
+
})], v.prototype, "placeholder", void 0), e([p({
|
|
383
|
+
type: Boolean,
|
|
384
|
+
reflect: !0
|
|
385
|
+
})], v.prototype, "disabled", void 0), e([p({
|
|
386
|
+
type: Boolean,
|
|
387
|
+
reflect: !0
|
|
388
|
+
})], v.prototype, "readonly", void 0), e([p({
|
|
389
|
+
type: Boolean,
|
|
390
|
+
reflect: !0
|
|
391
|
+
})], v.prototype, "required", void 0), e([p({
|
|
392
|
+
type: Boolean,
|
|
393
|
+
reflect: !0
|
|
394
|
+
})], v.prototype, "portal", void 0), e([p({
|
|
395
|
+
type: Boolean,
|
|
396
|
+
reflect: !0,
|
|
397
|
+
attribute: "no-scroll-lock"
|
|
398
|
+
})], v.prototype, "noScrollLock", void 0), e([p({ attribute: !1 })], v.prototype, "overlayContainer", void 0), e([p({
|
|
399
|
+
type: String,
|
|
400
|
+
reflect: !0
|
|
401
|
+
})], v.prototype, "name", void 0), e([p({
|
|
402
|
+
type: String,
|
|
403
|
+
attribute: "aria-label"
|
|
404
|
+
})], v.prototype, "ariaLabel", void 0), e([p({
|
|
405
|
+
type: String,
|
|
406
|
+
attribute: "aria-labelledby"
|
|
407
|
+
})], v.prototype, "ariaLabelledby", void 0), e([p({
|
|
408
|
+
type: String,
|
|
409
|
+
reflect: !0
|
|
410
|
+
})], v.prototype, "filter", null), e([m()], v.prototype, "_value", void 0), e([m()], v.prototype, "_selectedValue", void 0), e([m()], v.prototype, "_isOpen", void 0), e([m()], v.prototype, "_activeIndex", void 0), e([m()], v.prototype, "_focused", void 0), v = g = e([f("web-ui-autocomplete")], v);
|
|
411
|
+
//#endregion
|
|
412
|
+
export { v as WebUiAutocomplete };
|
|
413
|
+
|
|
414
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/autocomplete/index.ts"],"sourcesContent":["import { html, LitElement, nothing, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport '@/components/option'\nimport glass from '@/assets/glass.css?inline'\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport type { WebUiOption } from '@/components/option'\nimport { normalizeLiteral } from '@/shared/normalize'\nimport { defineAnchoredPanel } from '@/shared/overlay/anchored-panel'\nimport { defineOverlayPortal } from '@/shared/overlay/portal'\nimport type { OverlayContainer, OverlayPortal } from '@/shared/overlay/portal'\nimport { defineScrollLockLease } from '@/shared/scroll-lock/scroll-lock'\n\nimport style from './style.css?inline'\n\nconst FILTER_MODES = ['none', 'prefix', 'contains'] as const\ntype FilterMode = (typeof FILTER_MODES)[number]\n\n/**\n * `web-ui-autocomplete`:可输入并过滤候选的单值选择器。\n *\n * 与 `web-ui-select` 共用 `<web-ui-option>` 子项注册协议与浮层能力,但触发区是\n * 可编辑输入框:`value` 即当前输入文本(表单值),键入时按 `filter` 模式过滤候选,\n * 选择 option 时文本回填为该项 label,`selected-value` 暴露该项的 value。\n */\n@customElement('web-ui-autocomplete')\nexport class WebUiAutocomplete extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(overlayMotion), unsafeCSS(style)]\n\n static formAssociated = true\n\n // ElementInternals 实例,在 connectedCallback 中初始化\n private _internals?: ElementInternals\n @state() private _formDisabled = false\n\n @property({ type: String, reflect: true }) placeholder = ''\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) readonly = false\n @property({ type: Boolean, reflect: true }) required = false\n @property({ type: Boolean, reflect: true }) portal = false\n @property({ type: Boolean, reflect: true, attribute: 'no-scroll-lock' })\n noScrollLock = false\n @property({ attribute: false }) overlayContainer?: OverlayContainer\n @property({ type: String, reflect: true }) name = ''\n @property({ type: String, attribute: 'aria-label' }) override ariaLabel: string | null = null\n @property({ type: String, attribute: 'aria-labelledby' }) ariaLabelledby: string | undefined\n\n private _filter: FilterMode = 'contains'\n\n @property({ type: String, reflect: true })\n get filter(): FilterMode {\n return this._filter\n }\n set filter(v: string) {\n const old = this._filter\n this._filter = normalizeLiteral(v, FILTER_MODES, 'contains')\n this.requestUpdate('filter', old)\n }\n\n // value 使用内部状态 + 访问器模式,在变更时同步 ElementInternals。\n // 与 Select 一致不反射 attribute:value attribute 保留为表单重置的初始默认值,\n // 避免设置属性时回写 attribute 导致 formResetCallback 读取到当前值。\n @state() private _value = ''\n\n get value(): string {\n return this._value\n }\n set value(v: string) {\n const old = this._value\n this._value = v\n this._internals?.setFormValue?.(v)\n this.requestUpdate('value', old)\n }\n\n // selected-value:文本精确匹配 option label 时派生出的 option value(只读反射)。\n @state() private _selectedValue = ''\n\n get selectedValue(): string {\n return this._selectedValue\n }\n\n private _setSelectedValue(value: string) {\n const old = this._selectedValue\n if (old === value && this.getAttribute('selected-value') === value) return\n\n this._selectedValue = value\n this.setAttribute('selected-value', value)\n if (old !== value) this.requestUpdate('selectedValue', old)\n }\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formDisabled\n }\n\n @state() private _isOpen = false\n @state() private _activeIndex = -1\n @state() private _focused = false\n\n private static _nextInstanceId = 0\n private readonly _idPrefix = `web-ui-autocomplete-${++WebUiAutocomplete._nextInstanceId}`\n private readonly _optionIds = new WeakMap<WebUiOption, string>()\n private readonly _a11yOptionIds = new WeakMap<WebUiOption, string>()\n private _nextOptionId = 0\n private _nextA11yOptionId = 0\n private _options: WebUiOption[] = []\n private _portal?: OverlayPortal\n private _portalContent?: HTMLElement\n private readonly _pendingUnregisteredOptions = new Set<WebUiOption>()\n private readonly _scrollLock = defineScrollLockLease().make()\n private readonly _panel = defineAnchoredPanel().make({\n getAnchor: () => this.shadowRoot?.querySelector<HTMLElement>('.input-wrapper') ?? null,\n getLocalPanel: () => this.shadowRoot?.querySelector<HTMLElement>('.autocomplete-overlay') ?? null,\n getPositioning: () => ({\n placement: 'bottom-start',\n offset: 4,\n minAnchorWidth: true,\n strategy: this.portal ? 'fixed' : 'absolute'\n }),\n isPortal: () => this.portal,\n createPortal: () => this._createPortal()\n })\n\n get isOpen(): boolean {\n return this._isOpen\n }\n\n get open(): boolean {\n return this._isOpen\n }\n\n private _onClickOutside = (e: MouseEvent) => {\n if (!this._isOpen) return\n\n const path = e.composedPath()\n const panel = this._panel.getPanel()\n if (!path.includes(this) && (!panel || !path.includes(panel))) this._close()\n }\n\n private _onFocusOut = () => {\n requestAnimationFrame(() => {\n if (this._isOpen && !this.matches(':focus-within') && !this._panel.getPanel()?.matches(':focus-within')) {\n this._close()\n }\n })\n }\n\n private _handlePanelPointerDown = (e: PointerEvent) => {\n // 非 option 区域不可聚焦;阻止 pointerdown 的默认聚焦行为,保持 combobox 焦点,\n // 使点击 empty state、滚动区和面板 padding 不会被 focusout 误判为外部交互。\n e.preventDefault()\n }\n\n override connectedCallback() {\n super.connectedCallback()\n // 元素被移动时会重连,ElementInternals 只能 attach 一次\n if (!this._internals) {\n this._internals = this.attachInternals()\n }\n // 同步 HTML 属性中预设的 value,补全访问器模式不处理 attribute 反射\n const attrValue = this.getAttribute('value')\n if (attrValue !== null) {\n this._value = attrValue\n this._internals?.setFormValue?.(attrValue)\n }\n this.addEventListener('option-register', this._onOptionRegister)\n this.addEventListener('option-unregister', this._onOptionUnregister)\n this.addEventListener('keydown', this._onKeydown)\n this.addEventListener('focusout', this._onFocusOut)\n document.addEventListener('click', this._onClickOutside)\n }\n\n override attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {\n super.attributeChangedCallback(name, oldValue, newValue)\n if (name === 'selected-value' && this.isConnected && newValue !== this._selectedValue) {\n queueMicrotask(() => {\n if (this.isConnected) this._syncSelectedValue()\n })\n }\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this.removeEventListener('option-register', this._onOptionRegister)\n this.removeEventListener('option-unregister', this._onOptionUnregister)\n this.removeEventListener('keydown', this._onKeydown)\n this.removeEventListener('focusout', this._onFocusOut)\n document.removeEventListener('click', this._onClickOutside)\n this._options.forEach(this._unbindOption)\n this._pendingUnregisteredOptions.clear()\n this._close()\n this._portal = undefined\n this._portalContent = undefined\n this._panel.dispose()\n this._scrollLock.release()\n }\n\n override firstUpdated() {\n requestAnimationFrame(() => {\n if (this.isConnected) this._onSlotChange()\n })\n }\n\n private _queryOptions(): WebUiOption[] {\n const panel = this.portal ? this._panel.getPanel() : null\n const panelOptions = panel ? [...panel.querySelectorAll<WebUiOption>('web-ui-option')] : []\n // 面板内容仅在浮层打开、moveContent 之后存在;关闭时回退 light DOM,\n // 否则 portal 模式首次加载时 _options 为空。\n return panelOptions.length > 0 ? panelOptions : [...this.querySelectorAll<WebUiOption>('web-ui-option')]\n }\n\n override willUpdate() {\n this._refreshOptions()\n this._ensureOptionIds()\n this._syncSelectedValue()\n this._applyFilter()\n this._syncOptionA11y()\n this._syncActiveOption()\n }\n\n override updated(changed: PropertyValues) {\n const input = this.shadowRoot?.querySelector<HTMLInputElement>('.autocomplete-input')\n if (input && input.value !== this._value) input.value = this._value\n if (changed.has('portal') || changed.has('overlayContainer'))\n requestAnimationFrame(() => this._reconfigureOverlay())\n if (changed.has('noScrollLock')) this._syncScrollLock()\n this.toggleAttribute('focused', this._focused)\n this._syncOpenAttribute()\n this._syncValidity()\n this._syncEmptyState()\n }\n\n formResetCallback() {\n this.value = this.getAttribute('value') || ''\n }\n\n formDisabledCallback(disabled: boolean) {\n this._formDisabled = disabled\n if (disabled && this._isOpen) this._close()\n }\n\n formStateRestoreCallback(state: string | File | FormData | null) {\n if (typeof state === 'string') this.value = state\n }\n\n private _syncValidity() {\n if (!this._internals || typeof this._internals.setValidity !== 'function') return\n // readonly 与 disabled 一致:值不可由用户修改,视为通过校验(原生 barred-from-validation 语义)\n if (this._isDisabled || this.readonly || !this.required || this._value) this._internals.setValidity({})\n else this._internals.setValidity({ valueMissing: true }, '请输入内容')\n }\n\n private _syncOpenAttribute() {\n this.toggleAttribute('open', this._isOpen)\n }\n\n private _syncSelectedValue() {\n const query = this._value.trim().toLowerCase()\n const next = query ? (this._options.find(o => o.label.trim().toLowerCase() === query)?.value ?? '') : ''\n this._setSelectedValue(next)\n }\n\n private _syncOptionA11y() {\n this._options.forEach(o => {\n o.setAttribute('role', 'option')\n o.setAttribute('aria-selected', o.value === this._selectedValue ? 'true' : 'false')\n o.setAttribute('aria-hidden', 'true')\n })\n }\n\n private _ensureOptionIds() {\n const usedIds = new Set(this._options.map(option => option.id).filter(Boolean))\n this._options.forEach(option => {\n if (option.id) return\n\n let id = this._optionIds.get(option)\n if (!id || usedIds.has(id)) {\n do {\n id = `${this._idPrefix}-option-${++this._nextOptionId}`\n } while (usedIds.has(id))\n this._optionIds.set(option, id)\n }\n option.id = id\n usedIds.add(id)\n })\n }\n\n private _getA11yOptionId(option: WebUiOption): string {\n let id = this._a11yOptionIds.get(option)\n if (!id) {\n id = `${this._idPrefix}-a11y-option-${++this._nextA11yOptionId}`\n this._a11yOptionIds.set(option, id)\n }\n return id\n }\n\n // 按当前文本与 filter 模式过滤候选,非匹配项以 data-filtered 隐藏并跳过导航\n private _applyFilter() {\n const query = this._value.trim().toLowerCase()\n const mode = this._filter\n this._options.forEach(o => {\n const label = o.label.trim().toLowerCase()\n const match = mode === 'none' || !query || (mode === 'prefix' ? label.startsWith(query) : label.includes(query))\n o.toggleAttribute('data-filtered', !match)\n })\n // 活动项被过滤或禁用时清除键盘激活,避免激活不可见项\n const active = this._options[this._activeIndex]\n if (this._activeIndex >= 0 && (!active || active.hasAttribute('data-filtered') || active.disabled)) {\n this._activeIndex = -1\n this._syncActiveOption()\n }\n }\n\n private _syncEmptyState() {\n const panel = this._panel.getPanel()\n if (!panel) return\n const empty = panel.querySelector<HTMLElement>('.autocomplete-empty')\n if (!empty) return\n const matching = this._options.filter(o => !o.hasAttribute('data-filtered'))\n empty.hidden = !(this._options.length > 0 && matching.length === 0)\n }\n\n private _bindOption = (option: WebUiOption) => {\n option.addEventListener('click', this._handleOptionClick)\n option.addEventListener('pointerover', this._handleOptionPointerOver)\n option.addEventListener('pointerdown', this._handleOptionPointerDown)\n option.addEventListener('option-update', this._onOptionUpdate)\n // Portal 迁移后 option 不再向宿主冒泡事件,直接监听以覆盖真实删除。\n option.addEventListener('option-unregister', this._onOptionUnregister)\n }\n\n private _unbindOption = (option: WebUiOption) => {\n option.removeEventListener('click', this._handleOptionClick)\n option.removeEventListener('pointerover', this._handleOptionPointerOver)\n option.removeEventListener('pointerdown', this._handleOptionPointerDown)\n option.removeEventListener('option-update', this._onOptionUpdate)\n option.removeEventListener('option-unregister', this._onOptionUnregister)\n }\n\n private _refreshOptions() {\n const activeOption = this._options[this._activeIndex]\n const nextOptions = this._queryOptions()\n\n this._options.filter(option => !nextOptions.includes(option)).forEach(this._unbindOption)\n nextOptions.forEach(this._bindOption)\n this._options = nextOptions\n this._activeIndex = activeOption && nextOptions.includes(activeOption) ? nextOptions.indexOf(activeOption) : -1\n }\n\n private _syncPortalContent() {\n if (!this._portal || !this._portalContent) return\n\n for (const option of this._pendingUnregisteredOptions) {\n if (!this._portalContent.contains(option) && !this.contains(option)) this._portal.removeContent([option])\n }\n this._pendingUnregisteredOptions.clear()\n\n if (!this._isOpen) return\n\n const lightDomNodes = Array.from(this.childNodes)\n if (lightDomNodes.length) this._portal.appendContent(lightDomNodes, this._portalContent)\n }\n\n private _scheduleOptionsRefresh() {\n // disconnectedCallback 在 Portal 迁移与实际删除时都会触发。延迟到当前微任务结束,\n // 才能根据 option 的最终位置区分二者并同时同步 active/selected/ARIA 状态。\n queueMicrotask(() => {\n if (!this.isConnected) return\n this._syncPortalContent()\n this.requestUpdate()\n })\n }\n\n private _onOptionRegister = () => {\n this._scheduleOptionsRefresh()\n }\n\n private _onOptionUnregister = (e: Event) => {\n if (e.target instanceof HTMLElement && e.target.localName === 'web-ui-option')\n this._pendingUnregisteredOptions.add(e.target as WebUiOption)\n this._scheduleOptionsRefresh()\n }\n\n private _onSlotChange = () => {\n this._scheduleOptionsRefresh()\n }\n\n private _handleOptionClick = (e: Event) => {\n if (!(e.currentTarget instanceof HTMLElement)) return\n const option = e.currentTarget as WebUiOption\n if (option.disabled) return\n this._selectOption(option)\n }\n\n private _onOptionUpdate = () => {\n this._scheduleOptionsRefresh()\n }\n\n private _handleOptionPointerOver = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (!this._isOpen || !(e.currentTarget instanceof HTMLElement)) return\n\n // 指针接管后只保留 :hover,避免键盘激活项与悬停项同时高亮。\n this._activeIndex = -1\n this._syncActiveOption()\n }\n\n private _handleOptionPointerDown = (e: PointerEvent) => {\n // 保持输入框焦点,避免 focusout 在 click 前关闭浮层。\n e.preventDefault()\n }\n\n private _onKeydown = (e: KeyboardEvent) => {\n if (this._isDisabled || this.readonly) return\n\n switch (e.key) {\n case 'Escape':\n if (this._isOpen) {\n this._close()\n e.preventDefault()\n }\n break\n case 'ArrowDown':\n e.preventDefault()\n if (!this._isOpen) this._open(true)\n else this._navigateActive(1)\n break\n case 'ArrowUp':\n e.preventDefault()\n if (!this._isOpen) this._open(true)\n else this._navigateActive(-1)\n break\n case 'Enter':\n // 面板打开时接管 Enter:选中活动项或拦截表单提交;关闭时不拦截\n if (this._isOpen) {\n e.preventDefault()\n const option = this._options[this._activeIndex]\n if (option && !option.disabled && !option.hasAttribute('data-filtered')) {\n this._selectOption(option)\n }\n }\n break\n }\n }\n\n private _navigateActive(delta: number) {\n const enabled = this._options.filter(o => !o.disabled && !o.hasAttribute('data-filtered'))\n if (!enabled.length) return\n\n const currentIdx = this._activeIndex >= 0 ? enabled.indexOf(this._options[this._activeIndex]) : delta > 0 ? -1 : 0\n let nextIdx = currentIdx + delta\n if (nextIdx < 0) nextIdx = enabled.length - 1\n if (nextIdx >= enabled.length) nextIdx = 0\n\n this._activeIndex = this._options.indexOf(enabled[nextIdx])\n this._syncActiveOption()\n }\n\n private _setInitialActiveOption() {\n const firstEnabled = this._options.findIndex(o => !o.disabled && !o.hasAttribute('data-filtered'))\n this._activeIndex = firstEnabled\n this._syncActiveOption()\n }\n\n private _syncActiveOption() {\n this._options.forEach((option, index) => option.toggleAttribute('active', index === this._activeIndex))\n }\n\n private _selectOption(option: WebUiOption) {\n if (this.readonly) return\n // value 即输入文本:选择后回填为 option label,selected-value 取 option value\n this.value = option.label\n this._setSelectedValue(option.value)\n this._close()\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n\n private _onInput = (e: Event) => {\n if (this._isDisabled || this.readonly) return\n const input = e.target as HTMLInputElement\n if (input.value === this._value) return\n this.value = input.value\n this._activeIndex = -1\n this._syncActiveOption()\n if (!this._isOpen) this._open()\n }\n\n // 内部原生 input 在失焦时也会派发 change;组件契约中 change 仅表示「选中提交」,\n // 阻止原生 change 冒泡到宿主,避免消费端收到未选择时的 change。\n private _onInnerChange = (e: Event) => {\n e.stopPropagation()\n }\n\n private _onFocus = () => {\n if (this._isDisabled) return\n this._focused = true\n // readonly 仅可聚焦选中,不展开候选\n if (this.readonly) return\n if (this._options.length > 0) this._open()\n }\n\n private _onBlur = () => {\n this._focused = false\n }\n\n private _open(isKeyboardNavigation = false) {\n if (this._isDisabled || this.readonly || this._isOpen) return\n this._isOpen = true\n this._dispatchOpenChange()\n if (isKeyboardNavigation) this._setInitialActiveOption()\n else this._syncActiveOption()\n this._syncScrollLock()\n if (this.portal) {\n requestAnimationFrame(() => {\n if (this._isOpen) this._openOverlay(isKeyboardNavigation)\n })\n } else {\n this._openOverlay(isKeyboardNavigation)\n }\n }\n\n private _close() {\n if (!this._isOpen) return\n // Portal 内容可能在当前微任务尚未完成同步;先把 light DOM 中新增或重排的节点\n // 收回当前 content,再关闭并 restore,避免 restoreContent() 按旧 tracking 顺序把\n // 新 option 插到旧 option 前面。\n this._syncPortalContent()\n this._isOpen = false\n this._dispatchOpenChange()\n this._activeIndex = -1\n this._options.forEach(o => o.removeAttribute('active'))\n this._syncScrollLock(false)\n void this._closeOverlay()\n }\n\n private _dispatchOpenChange() {\n this.dispatchEvent(\n new CustomEvent('open-change', {\n detail: { open: this._isOpen },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private _openOverlay(isKeyboardNavigation = false) {\n this._panel.open(isKeyboardNavigation)\n this._syncEmptyState()\n }\n\n private async _closeOverlay() {\n const closed = await this._panel.close(() => this._isOpen)\n if (closed) {\n this._portal = undefined\n this._portalContent = undefined\n }\n }\n\n private _reconfigureOverlay() {\n this._portal = undefined\n this._portalContent = undefined\n this._panel.reconfigure(this._isOpen)\n }\n\n private _syncScrollLock(isOpen = this._isOpen) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\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: 'wui-glass autocomplete-overlay portal wui-floating-panel'\n })\n this._portal = portal\n portal.panel.setAttribute('aria-hidden', 'true')\n portal.panel.addEventListener('pointerdown', this._handlePanelPointerDown)\n const scroll = document.createElement('div')\n scroll.className = 'autocomplete-scroll'\n const content = document.createElement('div')\n content.className = 'autocomplete-content'\n this._portalContent = content\n const empty = document.createElement('div')\n empty.className = 'autocomplete-empty'\n empty.hidden = true\n empty.textContent = '无匹配选项'\n scroll.append(content)\n content.append(empty)\n portal.panel.append(scroll)\n portal.moveContent(Array.from(this.children), content)\n return portal\n }\n\n private _getLabelledbyText(): string {\n if (!this.ariaLabelledby) return ''\n\n const root = this.getRootNode()\n if (!(root instanceof Document || root instanceof ShadowRoot)) return ''\n\n return this.ariaLabelledby\n .trim()\n .split(/\\s+/)\n .map(id => {\n const escapedId = typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(id) : id\n return root.querySelector(`#${escapedId}`)?.textContent?.trim() ?? ''\n })\n .filter(Boolean)\n .join(' ')\n }\n\n override render() {\n const listboxId = `${this._idPrefix}-listbox`\n const labelId = `${this._idPrefix}-label`\n const labelledbyText = this._getLabelledbyText()\n const visibleOptions = this._options.filter(option => !option.hasAttribute('data-filtered'))\n const activeOption = this._isOpen && this._activeIndex >= 0 ? this._options[this._activeIndex] : undefined\n const activeDescendant = activeOption ? this._getA11yOptionId(activeOption) : nothing\n\n return html`\n <div class=\"wui-autocomplete-inner\">\n ${labelledbyText ? html`<span class=\"autocomplete-a11y-only\" id=${labelId}>${labelledbyText}</span>` : nothing}\n <div class=\"wui-glass input-wrapper\">\n <input\n class=\"autocomplete-input\"\n type=\"text\"\n placeholder=${this.placeholder}\n name=${this.name}\n .value=${this._value}\n aria-label=${ifDefined(this.ariaLabel)}\n aria-labelledby=${labelledbyText ? labelId : nothing}\n ?disabled=${this._isDisabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n role=\"combobox\"\n aria-expanded=${this._isOpen}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n aria-controls=${listboxId}\n aria-disabled=${String(this._isDisabled)}\n aria-readonly=${this.readonly ? 'true' : nothing}\n aria-activedescendant=${activeDescendant}\n @input=${this._onInput}\n @change=${this._onInnerChange}\n @focus=${this._onFocus}\n @blur=${this._onBlur}\n />\n </div>\n <div\n class=\"autocomplete-a11y-listbox\"\n id=${listboxId}\n role=\"listbox\"\n ?hidden=${!this._isOpen}\n aria-hidden=${String(!this._isOpen)}\n >\n ${visibleOptions.map(\n option =>\n html`<div\n id=${this._getA11yOptionId(option)}\n role=\"option\"\n aria-selected=${option.value === this._selectedValue ? 'true' : 'false'}\n aria-hidden=${String(!this._isOpen)}\n aria-disabled=${String(option.disabled)}\n >\n ${option.label}\n </div>`\n )}\n </div>\n <div\n class=\"wui-glass autocomplete-overlay wui-floating-panel\"\n hidden\n aria-hidden=\"true\"\n @pointerdown=${this._handlePanelPointerDown}\n >\n <div class=\"autocomplete-scroll\">\n <div class=\"autocomplete-content\">\n <slot @slotchange=${this._onSlotChange}></slot>\n <div class=\"autocomplete-empty\" hidden>无匹配选项</div>\n </div>\n </div>\n </div>\n </div>\n `\n }\n\n declare readonly $events: {\n input: Event\n change: Event\n focus: FocusEvent\n blur: FocusEvent\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-autocomplete': WebUiAutocomplete\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/components/autocomplete/style.css?inline
|
|
2
|
+
var e = "*,:before,:after{box-sizing:border-box}:host{display:inline-block}:host([disabled]){cursor:not-allowed;opacity:.4}.input-wrapper{box-sizing:border-box;width:var(--wui-input-width,200px);min-width:var(--wui-button-size,40px);height:var(--wui-button-size,40px);transition:border-color var(--wui-duration-focus,.2s), box-shadow var(--wui-duration-focus,.2s);border-radius:2147483647px;align-items:center;gap:8px;padding:0 12px;display:flex}:host([focused]) .input-wrapper{--wui-glass-shadow:var(--wui-shadow-glass,0 2px 16px #0000000f), 0 0 0 3px var(--wui-focus-ring,#08f6);border-color:var(--wui-color-border-strong,#006ee680)}.autocomplete-input{min-width:0;height:100%;font:inherit;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);background:0 0;border:none;outline:none;flex:1;margin:0;padding:0}.autocomplete-input::placeholder{color:var(--wui-color-text-muted,#6a6a6a)}.autocomplete-input:disabled{cursor:not-allowed;opacity:.4}.autocomplete-overlay{--wui-glass-shadow:var(--wui-shadow-pop,0 3px 9px #00000045);--wui-duration-overlay-enter:var(--wui-duration-menu-enter,.14s);--wui-duration-overlay-exit:var(--wui-duration-menu-exit,.1s);--wui-overlay-min-width:200px;z-index:var(--wui-layer-local-overlay,1);box-sizing:border-box;min-width:var(--wui-overlay-min-width,120px);background-color:var(--wui-color-surface-overlay,#f6f6f6e0);border-radius:20px;max-width:500px;position:absolute;overflow:hidden}.autocomplete-overlay.portal{z-index:var(--wui-layer-menu,100);position:fixed}.autocomplete-overlay.hidden{display:none}.autocomplete-scroll{max-height:320px;overflow-y:auto}.autocomplete-content{padding:4px}.autocomplete-empty{font-size:var(--wui-font-size,14px);color:var(--wui-color-text-muted,#6a6a6a);text-align:center;padding:8px 12px}::slotted(web-ui-option[data-filtered]),.autocomplete-content web-ui-option[data-filtered],:host([portal]) .autocomplete-overlay{display:none}.autocomplete-a11y-only,.autocomplete-a11y-listbox{white-space:nowrap;clip-path:inset(50%);border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}";
|
|
3
|
+
//#endregion
|
|
4
|
+
export { e as default };
|
|
5
|
+
|
|
6
|
+
//# sourceMappingURL=style.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.js","names":[],"sources":["../../../src/components/autocomplete/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: inline-block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.input-wrapper {\n display: flex;\n gap: 8px;\n align-items: center;\n\n box-sizing: border-box;\n width: var(--wui-input-width, 200px);\n min-width: var(--wui-button-size, 40px);\n height: var(--wui-button-size, 40px);\n padding: 0 12px;\n border-radius: calc(infinity * 1px);\n\n transition:\n border-color var(--wui-duration-focus, 200ms),\n box-shadow var(--wui-duration-focus, 200ms);\n}\n\n:host([focused]) .input-wrapper {\n --wui-glass-shadow:\n var(--wui-shadow-glass, 0 2px 16px rgb(0 0 0 / 0.06)), 0 0 0 3px var(--wui-focus-ring, rgb(0 136 255 / 0.4));\n border-color: var(--wui-color-border-strong, rgb(0 110 230 / 0.5));\n}\n\n.autocomplete-input {\n flex: 1;\n\n min-width: 0;\n height: 100%;\n margin: 0;\n padding: 0;\n border: none;\n\n /* 表单控件不继承字体;显式继承以对齐宿主排版,避免 UA 默认字体差异 */\n font: inherit;\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text, #1b1b1b);\n\n background: transparent;\n outline: none;\n\n &::placeholder {\n color: var(--wui-color-text-muted, #6a6a6a);\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n}\n\n/* ===== 浮层(glass 样式参考 select) ===== */\n\n.autocomplete-overlay {\n --wui-glass-shadow: var(--wui-shadow-pop, 0 3px 9px rgb(0 0 0 / 0.27));\n --wui-duration-overlay-enter: var(--wui-duration-menu-enter, 140ms);\n --wui-duration-overlay-exit: var(--wui-duration-menu-exit, 100ms);\n --wui-overlay-min-width: 200px;\n position: absolute;\n z-index: var(--wui-layer-local-overlay, 1);\n\n overflow: hidden;\n\n box-sizing: border-box;\n min-width: var(--wui-overlay-min-width, 120px);\n max-width: 500px;\n border-radius: 20px;\n\n background-color: var(--wui-color-surface-overlay, rgb(246 246 246 / 0.88));\n\n &.portal {\n position: fixed;\n z-index: var(--wui-layer-menu, 100);\n }\n\n &.hidden {\n display: none;\n }\n}\n\n.autocomplete-scroll {\n overflow-y: auto;\n max-height: 320px;\n}\n\n.autocomplete-content {\n padding: 4px;\n}\n\n.autocomplete-empty {\n padding: 8px 12px;\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text-muted, #6a6a6a);\n text-align: center;\n}\n\n/* 非匹配候选隐藏:本地模式经 slot 投影,portal 模式为面板直接子元素 */\n::slotted(web-ui-option[data-filtered]) {\n display: none;\n}\n\n.autocomplete-content web-ui-option[data-filtered] {\n display: none;\n}\n\n:host([portal]) .autocomplete-overlay {\n display: none;\n}\n\n/* Shadow DOM idref 不能跨越 Portal 或 light DOM;保留同根可访问的语义镜像。 */\n.autocomplete-a11y-only,\n.autocomplete-a11y-listbox {\n position: absolute;\n\n overflow: hidden;\n\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n\n white-space: nowrap;\n\n clip-path: inset(50%);\n}\n"],"mappings":""}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import e from "../../_virtual/_@oxc-project_runtime@0.140.0/helpers/esm/decorate.js";
|
|
2
2
|
import "../icon/index.js";
|
|
3
|
-
import t from "../../
|
|
4
|
-
import n from "../../
|
|
3
|
+
import t from "../../icons/generated/lucide-user.js";
|
|
4
|
+
import n from "../../assets/glass.js";
|
|
5
5
|
import { normalizeLiteral as r } from "../../shared/normalize/index.js";
|
|
6
6
|
import i from "./style.js";
|
|
7
7
|
import { LitElement as a, html as o, unsafeCSS as s } from "lit";
|
|
8
8
|
import { customElement as c, property as l, state as u } from "lit/decorators.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { ifDefined as d } from "lit/directives/if-defined.js";
|
|
10
|
+
import { classMap as f } from "lit/directives/class-map.js";
|
|
11
11
|
//#region src/components/avatar/index.ts
|
|
12
12
|
var p = ["circle", "square"], m = class extends a {
|
|
13
13
|
constructor(...e) {
|
|
14
14
|
super(...e), this._src = "", this.alt = "", this.name = "", this.size = 40, this._shape = "circle", this._imgError = !1, this._hasDefaultSlot = !1;
|
|
15
15
|
}
|
|
16
16
|
static {
|
|
17
|
-
this.styles = [s(
|
|
17
|
+
this.styles = [s(n), s(i)];
|
|
18
18
|
}
|
|
19
19
|
set src(e) {
|
|
20
20
|
let t = this._src;
|
|
@@ -66,25 +66,25 @@ var p = ["circle", "square"], m = class extends a {
|
|
|
66
66
|
let e = !this._ariaLabel;
|
|
67
67
|
return o`
|
|
68
68
|
<div
|
|
69
|
-
class=${
|
|
69
|
+
class=${f({
|
|
70
70
|
"avatar-inner": !0,
|
|
71
71
|
"wui-glass": this._showFallback
|
|
72
72
|
})}
|
|
73
73
|
role=${e ? "presentation" : "img"}
|
|
74
|
-
aria-label=${
|
|
74
|
+
aria-label=${d(this._ariaLabel)}
|
|
75
75
|
aria-hidden=${e ? "true" : void 0}
|
|
76
76
|
style="width:${this.size}px;height:${this.size}px;--wui-avatar-size:${this.size}px"
|
|
77
77
|
>
|
|
78
78
|
${this._showImage ? o`<img
|
|
79
79
|
class="avatar-img"
|
|
80
80
|
src=${this.src}
|
|
81
|
-
alt=${
|
|
81
|
+
alt=${d(this.alt || void 0)}
|
|
82
82
|
@error=${this._onImgError}
|
|
83
83
|
/>` : ""}
|
|
84
84
|
<slot @slotchange=${this._checkSlot}></slot>
|
|
85
85
|
${this._showFallback && this._initials ? o`<span class="avatar-fallback avatar-initials">${this._initials}</span>` : ""}
|
|
86
86
|
${this._showFallback && !this._initials ? o`<span class="avatar-fallback"
|
|
87
|
-
><web-ui-icon .icon=${
|
|
87
|
+
><web-ui-icon .icon=${t} .size=${this._iconSize}></web-ui-icon
|
|
88
88
|
></span>` : ""}
|
|
89
89
|
</div>
|
|
90
90
|
`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/avatar/index.ts"],"sourcesContent":["import { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\n// 注册 web-ui-icon(Rolldown tree-shake 副作用 import,引用类名阻止删除)\nimport '@/components/icon'\nimport glass from '@/assets/glass.css?inline'\nimport { lucideUser } from '@/icons'\nimport { normalizeLiteral } from '@/shared/normalize'\n\nimport style from './style.css?inline'\n\nconst ALLOWED_SHAPES = ['circle', 'square'] as const\n\n@customElement('web-ui-avatar')\nexport class WebUiAvatar extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: String, reflect: true })\n set src(value: string) {\n const old = this._src\n this._src = value\n if (old !== value) {\n this._imgError = false\n this.requestUpdate('src', old)\n }\n }\n\n get src(): string {\n return this._src\n }\n\n private _src = ''\n\n @property({ type: String, reflect: true }) alt = ''\n @property({ type: String, reflect: true }) name = ''\n @property({ type: Number, reflect: true }) size = 40\n\n @property({ type: String, reflect: true })\n set shape(value: string) {\n const normalized = normalizeLiteral(value, ALLOWED_SHAPES, 'circle')\n if (this._shape !== normalized) {\n const old = this._shape\n this._shape = normalized\n this.requestUpdate('shape', old)\n }\n // 外部 setAttribute 非法值后,宿主 attribute 与规范化后的值不同步,立即修正\n if (this.getAttribute('shape') !== normalized) {\n this.setAttribute('shape', normalized)\n }\n }\n\n get shape(): 'circle' | 'square' {\n return this._shape\n }\n\n private _shape: 'circle' | 'square' = 'circle'\n\n @state() private _imgError = false\n @state() private _hasDefaultSlot = false\n\n override connectedCallback() {\n super.connectedCallback()\n void this.updateComplete.then(() => {\n this.shadowRoot?.querySelector('slot:not([name])')?.addEventListener('slotchange', () => this._checkSlot())\n })\n }\n\n private _checkSlot() {\n const slot = this.shadowRoot?.querySelector('slot:not([name])')\n const has = slot instanceof HTMLSlotElement && slot.assignedElements().length > 0\n if (this._hasDefaultSlot !== has) {\n this._hasDefaultSlot = has\n }\n }\n\n private get _initials(): string {\n const words = this.name.trim().split(/\\s+/)\n return words\n .slice(0, 2)\n .map(w => Array.from(w)[0])\n .join('')\n .toUpperCase()\n }\n\n private get _iconSize(): number {\n return Math.round(this.size * 0.4)\n }\n\n private get _showImage(): boolean {\n return !!this.src && !this._imgError\n }\n\n private get _showFallback(): boolean {\n return !this._showImage && !this._hasDefaultSlot\n }\n\n private _onImgError() {\n this._imgError = true\n }\n\n private get _ariaLabel(): string | undefined {\n if (this.alt) return this.alt\n if (this.name) return this.name\n return undefined\n }\n\n override render() {\n const isDecorative = !this._ariaLabel\n\n return html`\n <div\n class=${classMap({ 'avatar-inner': true, 'wui-glass': this._showFallback })}\n role=${isDecorative ? 'presentation' : 'img'}\n aria-label=${ifDefined(this._ariaLabel)}\n aria-hidden=${isDecorative ? 'true' : undefined}\n style=\"width:${this.size}px;height:${this.size}px;--wui-avatar-size:${this.size}px\"\n >\n ${this._showImage\n ? html`<img\n class=\"avatar-img\"\n src=${this.src}\n alt=${ifDefined(this.alt || undefined)}\n @error=${this._onImgError}\n />`\n : ''}\n <slot @slotchange=${this._checkSlot}></slot>\n ${this._showFallback && this._initials\n ? html`<span class=\"avatar-fallback avatar-initials\">${this._initials}</span>`\n : ''}\n ${this._showFallback && !this._initials\n ? html`<span class=\"avatar-fallback\"\n ><web-ui-icon .icon=${lucideUser} size=${this._iconSize}></web-ui-icon\n ></span>`\n : ''}\n </div>\n `\n }\n
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/avatar/index.ts"],"sourcesContent":["import { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\n// 注册 web-ui-icon(Rolldown tree-shake 副作用 import,引用类名阻止删除)\nimport '@/components/icon'\nimport glass from '@/assets/glass.css?inline'\nimport { lucideUser } from '@/icons'\nimport { normalizeLiteral } from '@/shared/normalize'\n\nimport style from './style.css?inline'\n\nconst ALLOWED_SHAPES = ['circle', 'square'] as const\n\n@customElement('web-ui-avatar')\nexport class WebUiAvatar extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: String, reflect: true })\n set src(value: string) {\n const old = this._src\n this._src = value\n if (old !== value) {\n this._imgError = false\n this.requestUpdate('src', old)\n }\n }\n\n get src(): string {\n return this._src\n }\n\n private _src = ''\n\n @property({ type: String, reflect: true }) alt = ''\n @property({ type: String, reflect: true }) name = ''\n @property({ type: Number, reflect: true }) size = 40\n\n @property({ type: String, reflect: true })\n set shape(value: string) {\n const normalized = normalizeLiteral(value, ALLOWED_SHAPES, 'circle')\n if (this._shape !== normalized) {\n const old = this._shape\n this._shape = normalized\n this.requestUpdate('shape', old)\n }\n // 外部 setAttribute 非法值后,宿主 attribute 与规范化后的值不同步,立即修正\n if (this.getAttribute('shape') !== normalized) {\n this.setAttribute('shape', normalized)\n }\n }\n\n get shape(): 'circle' | 'square' {\n return this._shape\n }\n\n private _shape: 'circle' | 'square' = 'circle'\n\n @state() private _imgError = false\n @state() private _hasDefaultSlot = false\n\n override connectedCallback() {\n super.connectedCallback()\n void this.updateComplete.then(() => {\n this.shadowRoot?.querySelector('slot:not([name])')?.addEventListener('slotchange', () => this._checkSlot())\n })\n }\n\n private _checkSlot() {\n const slot = this.shadowRoot?.querySelector('slot:not([name])')\n const has = slot instanceof HTMLSlotElement && slot.assignedElements().length > 0\n if (this._hasDefaultSlot !== has) {\n this._hasDefaultSlot = has\n }\n }\n\n private get _initials(): string {\n const words = this.name.trim().split(/\\s+/)\n return words\n .slice(0, 2)\n .map(w => Array.from(w)[0])\n .join('')\n .toUpperCase()\n }\n\n private get _iconSize(): number {\n return Math.round(this.size * 0.4)\n }\n\n private get _showImage(): boolean {\n return !!this.src && !this._imgError\n }\n\n private get _showFallback(): boolean {\n return !this._showImage && !this._hasDefaultSlot\n }\n\n private _onImgError() {\n this._imgError = true\n }\n\n private get _ariaLabel(): string | undefined {\n if (this.alt) return this.alt\n if (this.name) return this.name\n return undefined\n }\n\n override render() {\n const isDecorative = !this._ariaLabel\n\n return html`\n <div\n class=${classMap({ 'avatar-inner': true, 'wui-glass': this._showFallback })}\n role=${isDecorative ? 'presentation' : 'img'}\n aria-label=${ifDefined(this._ariaLabel)}\n aria-hidden=${isDecorative ? 'true' : undefined}\n style=\"width:${this.size}px;height:${this.size}px;--wui-avatar-size:${this.size}px\"\n >\n ${this._showImage\n ? html`<img\n class=\"avatar-img\"\n src=${this.src}\n alt=${ifDefined(this.alt || undefined)}\n @error=${this._onImgError}\n />`\n : ''}\n <slot @slotchange=${this._checkSlot}></slot>\n ${this._showFallback && this._initials\n ? html`<span class=\"avatar-fallback avatar-initials\">${this._initials}</span>`\n : ''}\n ${this._showFallback && !this._initials\n ? html`<span class=\"avatar-fallback\"\n ><web-ui-icon .icon=${lucideUser} .size=${this._iconSize}></web-ui-icon\n ></span>`\n : ''}\n </div>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-avatar': WebUiAvatar\n }\n}\n"],"mappings":"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"}
|