@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.
Files changed (147) hide show
  1. package/README.CN.md +95 -41
  2. package/README.md +100 -42
  3. package/dist/assets/glass.js.map +1 -1
  4. package/dist/assets/menu-portal.js +1 -1
  5. package/dist/assets/menu-portal.js.map +1 -1
  6. package/dist/components/autocomplete/index.d.ts +121 -0
  7. package/dist/components/autocomplete/index.js +414 -0
  8. package/dist/components/autocomplete/index.js.map +1 -0
  9. package/dist/components/autocomplete/style.js +6 -0
  10. package/dist/components/autocomplete/style.js.map +1 -0
  11. package/dist/components/avatar/index.d.ts +0 -1
  12. package/dist/components/avatar/index.js +9 -9
  13. package/dist/components/avatar/index.js.map +1 -1
  14. package/dist/components/back-top/index.d.ts +0 -1
  15. package/dist/components/back-top/index.js +1 -1
  16. package/dist/components/back-top/index.js.map +1 -1
  17. package/dist/components/badge/index.d.ts +0 -1
  18. package/dist/components/badge/index.js +5 -5
  19. package/dist/components/badge/index.js.map +1 -1
  20. package/dist/components/button/index.d.ts +6 -2
  21. package/dist/components/button/index.js +40 -19
  22. package/dist/components/button/index.js.map +1 -1
  23. package/dist/components/button/style.js +1 -1
  24. package/dist/components/button/style.js.map +1 -1
  25. package/dist/components/button-group/index.d.ts +0 -1
  26. package/dist/components/button-group/index.js.map +1 -1
  27. package/dist/components/checkbox/index.d.ts +0 -3
  28. package/dist/components/checkbox/index.js +7 -5
  29. package/dist/components/checkbox/index.js.map +1 -1
  30. package/dist/components/checkbox-group/index.js +2 -2
  31. package/dist/components/checkbox-group/index.js.map +1 -1
  32. package/dist/components/context-menu/index.d.ts +4 -3
  33. package/dist/components/context-menu/index.js +47 -50
  34. package/dist/components/context-menu/index.js.map +1 -1
  35. package/dist/components/dialog/index.d.ts +1 -1
  36. package/dist/components/dialog/index.js +20 -19
  37. package/dist/components/dialog/index.js.map +1 -1
  38. package/dist/components/drawer/index.d.ts +2 -3
  39. package/dist/components/drawer/index.js +43 -33
  40. package/dist/components/drawer/index.js.map +1 -1
  41. package/dist/components/drawer/style.js +1 -1
  42. package/dist/components/drawer/style.js.map +1 -1
  43. package/dist/components/dropdown/index.d.ts +2 -9
  44. package/dist/components/dropdown/index.js +58 -53
  45. package/dist/components/dropdown/index.js.map +1 -1
  46. package/dist/components/dropdown-divider/index.d.ts +0 -1
  47. package/dist/components/dropdown-divider/index.js.map +1 -1
  48. package/dist/components/dropdown-header/index.d.ts +0 -1
  49. package/dist/components/dropdown-header/index.js.map +1 -1
  50. package/dist/components/dropdown-item/index.d.ts +0 -2
  51. package/dist/components/dropdown-item/index.js.map +1 -1
  52. package/dist/components/dropdown-item/style.js +1 -1
  53. package/dist/components/dropdown-item/style.js.map +1 -1
  54. package/dist/components/empty/index.d.ts +0 -1
  55. package/dist/components/empty/index.js +6 -6
  56. package/dist/components/empty/index.js.map +1 -1
  57. package/dist/components/icon/index.d.ts +0 -1
  58. package/dist/components/icon/index.js.map +1 -1
  59. package/dist/components/index.d.ts +5 -0
  60. package/dist/components/index.js +36 -35
  61. package/dist/components/input/index.d.ts +3 -0
  62. package/dist/components/input/index.js +48 -24
  63. package/dist/components/input/index.js.map +1 -1
  64. package/dist/components/input/style.js +1 -1
  65. package/dist/components/input/style.js.map +1 -1
  66. package/dist/components/input-number/index.d.ts +2 -0
  67. package/dist/components/input-number/index.js +25 -12
  68. package/dist/components/input-number/index.js.map +1 -1
  69. package/dist/components/input-number/style.js +1 -1
  70. package/dist/components/input-number/style.js.map +1 -1
  71. package/dist/components/layout/index.d.ts +0 -1
  72. package/dist/components/layout/index.js +4 -4
  73. package/dist/components/layout/index.js.map +1 -1
  74. package/dist/components/option/index.d.ts +0 -11
  75. package/dist/components/option/index.js +1 -1
  76. package/dist/components/option/index.js.map +1 -1
  77. package/dist/components/option/style.js +1 -1
  78. package/dist/components/option/style.js.map +1 -1
  79. package/dist/components/popover/index.d.ts +1 -5
  80. package/dist/components/popover/index.js +42 -37
  81. package/dist/components/popover/index.js.map +1 -1
  82. package/dist/components/radio/index.d.ts +0 -3
  83. package/dist/components/radio/index.js +8 -5
  84. package/dist/components/radio/index.js.map +1 -1
  85. package/dist/components/radio-group/index.js +2 -2
  86. package/dist/components/radio-group/index.js.map +1 -1
  87. package/dist/components/segmented/index.js +8 -4
  88. package/dist/components/segmented/index.js.map +1 -1
  89. package/dist/components/segmented-trigger/index.d.ts +1 -0
  90. package/dist/components/segmented-trigger/index.js +12 -3
  91. package/dist/components/segmented-trigger/index.js.map +1 -1
  92. package/dist/components/segmented-trigger/style.js +1 -1
  93. package/dist/components/segmented-trigger/style.js.map +1 -1
  94. package/dist/components/select/index.d.ts +0 -1
  95. package/dist/components/select/index.js +22 -31
  96. package/dist/components/select/index.js.map +1 -1
  97. package/dist/components/select/style.js +1 -1
  98. package/dist/components/select/style.js.map +1 -1
  99. package/dist/components/slider/index.d.ts +0 -2
  100. package/dist/components/slider/index.js +1 -1
  101. package/dist/components/slider/index.js.map +1 -1
  102. package/dist/components/spinner/index.d.ts +0 -3
  103. package/dist/components/spinner/index.js.map +1 -1
  104. package/dist/components/svg-draw-lines/index.d.ts +0 -3
  105. package/dist/components/svg-draw-lines/index.js.map +1 -1
  106. package/dist/components/switch/index.d.ts +0 -1
  107. package/dist/components/switch/index.js +6 -6
  108. package/dist/components/switch/index.js.map +1 -1
  109. package/dist/components/switch/style.js +1 -1
  110. package/dist/components/switch/style.js.map +1 -1
  111. package/dist/components/textarea/index.d.ts +1 -0
  112. package/dist/components/textarea/index.js +51 -34
  113. package/dist/components/textarea/index.js.map +1 -1
  114. package/dist/components/textarea/style.js +1 -1
  115. package/dist/components/textarea/style.js.map +1 -1
  116. package/dist/components/theme/index.d.ts +0 -3
  117. package/dist/components/theme/index.js.map +1 -1
  118. package/dist/components/toast/manager.js.map +1 -1
  119. package/dist/components/toast/style.js +1 -1
  120. package/dist/components/toast/style.js.map +1 -1
  121. package/dist/components/toast/toast.d.ts +0 -4
  122. package/dist/components/toast/toast.js +25 -17
  123. package/dist/components/toast/toast.js.map +1 -1
  124. package/dist/components/toast/types.d.ts +0 -3
  125. package/dist/components/tooltip/index.d.ts +1 -0
  126. package/dist/components/tooltip/index.js +34 -33
  127. package/dist/components/tooltip/index.js.map +1 -1
  128. package/dist/shared/events/user-change.js +17 -0
  129. package/dist/shared/events/user-change.js.map +1 -0
  130. package/dist/shared/menu-portal/menu-portal.js +10 -11
  131. package/dist/shared/menu-portal/menu-portal.js.map +1 -1
  132. package/dist/shared/normalize/index.js.map +1 -1
  133. package/dist/shared/overlay/anchored-panel.js +12 -12
  134. package/dist/shared/overlay/native-dialog-presence.js +8 -3
  135. package/dist/shared/overlay/native-dialog-presence.js.map +1 -1
  136. package/dist/shared/overlay/overlay.js +55 -33
  137. package/dist/shared/overlay/overlay.js.map +1 -1
  138. package/dist/shared/overlay/portal.js +27 -13
  139. package/dist/shared/overlay/portal.js.map +1 -1
  140. package/dist/shared/overlay/presence.js.map +1 -1
  141. package/dist/shared/scroll-lock/scroll-lock.js +13 -12
  142. package/dist/shared/scroll-lock/scroll-lock.js.map +1 -1
  143. package/dist/shared/theme/overlay-root.js +3 -3
  144. package/dist/types/react.d.ts +15 -41
  145. package/dist/types/utils.d.ts +33 -4
  146. package/dist/types/vue.d.ts +17 -49
  147. 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":""}
@@ -21,7 +21,6 @@ export declare class WebUiAvatar extends LitElement {
21
21
  private _onImgError;
22
22
  private get _ariaLabel();
23
23
  render(): import('lit').TemplateResult<1>;
24
- readonly $events: Record<string, never>;
25
24
  }
26
25
  declare global {
27
26
  interface HTMLElementTagNameMap {
@@ -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 "../../assets/glass.js";
4
- import n from "../../icons/generated/lucide-user.js";
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 { classMap as d } from "lit/directives/class-map.js";
10
- import { ifDefined as f } from "lit/directives/if-defined.js";
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(t), s(i)];
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=${d({
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=${f(this._ariaLabel)}
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=${f(this.alt || void 0)}
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=${n} size=${this._iconSize}></web-ui-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\n declare readonly $events: Record<string, never>\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-avatar': WebUiAvatar\n }\n}\n"],"mappings":"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"}
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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"}
@@ -19,7 +19,6 @@ export declare class WebUiBackTop extends LitElement {
19
19
  toTop(): void;
20
20
  private onEnter;
21
21
  render(): import('lit').TemplateResult<1>;
22
- readonly $events: Record<string, never>;
23
22
  }
24
23
  declare global {
25
24
  interface HTMLElementTagNameMap {