weifuwu 0.36.2 → 0.38.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 (51) hide show
  1. package/README.md +141 -3
  2. package/dist/client/app.d.ts +4 -7
  3. package/dist/client/confirm.d.ts +26 -0
  4. package/dist/client/focus-trap.d.ts +4 -0
  5. package/dist/client/i18n.d.ts +27 -0
  6. package/dist/client/index.d.ts +8 -0
  7. package/dist/client/index.js +322 -60
  8. package/dist/client/locale/en_US.d.ts +34 -0
  9. package/dist/client/locale/zh_CN.d.ts +34 -0
  10. package/dist/client/scroll-lock.d.ts +5 -0
  11. package/dist/components/Accordion/Accordion.d.ts +11 -0
  12. package/dist/components/Alert/Alert.d.ts +9 -0
  13. package/dist/components/Avatar/Avatar.d.ts +7 -0
  14. package/dist/components/Badge/Badge.d.ts +8 -0
  15. package/dist/components/Breadcrumb/Breadcrumb.d.ts +9 -0
  16. package/dist/components/Button/Button.d.ts +12 -0
  17. package/dist/components/Card/Card.d.ts +9 -0
  18. package/dist/components/Checkbox/Checkbox.d.ts +8 -0
  19. package/dist/components/Divider/Divider.d.ts +6 -0
  20. package/dist/components/Drawer/Drawer.d.ts +14 -0
  21. package/dist/components/Dropdown/Dropdown.d.ts +14 -0
  22. package/dist/components/EmptyState/EmptyState.d.ts +8 -0
  23. package/dist/components/Field/Field.d.ts +9 -0
  24. package/dist/components/FileUpload/FileUpload.d.ts +13 -0
  25. package/dist/components/Form/Form.d.ts +6 -0
  26. package/dist/components/Img/Img.d.ts +17 -0
  27. package/dist/components/Input/Input.d.ts +14 -0
  28. package/dist/components/Loading/Loading.d.ts +5 -0
  29. package/dist/components/Modal/Modal.d.ts +12 -0
  30. package/dist/components/PageHeader/PageHeader.d.ts +7 -0
  31. package/dist/components/Pagination/Pagination.d.ts +8 -0
  32. package/dist/components/Popover/Popover.d.ts +26 -0
  33. package/dist/components/ProgressBar/ProgressBar.d.ts +8 -0
  34. package/dist/components/RadioGroup/RadioGroup.d.ts +14 -0
  35. package/dist/components/SearchInput/SearchInput.d.ts +8 -0
  36. package/dist/components/Select/Select.d.ts +18 -0
  37. package/dist/components/Skeleton/Skeleton.d.ts +21 -0
  38. package/dist/components/Slider/Slider.d.ts +10 -0
  39. package/dist/components/StatCard/StatCard.d.ts +9 -0
  40. package/dist/components/Steps/Steps.d.ts +12 -0
  41. package/dist/components/Switch/Switch.d.ts +8 -0
  42. package/dist/components/Table/Table.d.ts +13 -0
  43. package/dist/components/Tabs/Tabs.d.ts +12 -0
  44. package/dist/components/Tag/Tag.d.ts +8 -0
  45. package/dist/components/Textarea/Textarea.d.ts +13 -0
  46. package/dist/components/Toast/Toast.d.ts +12 -0
  47. package/dist/components/Tooltip/Tooltip.d.ts +9 -0
  48. package/dist/components/index.d.ts +81 -0
  49. package/dist/components/index.js +1064 -0
  50. package/dist/components/style.css +2005 -0
  51. package/package.json +7 -2
@@ -0,0 +1,1064 @@
1
+ // src/client/vnode.ts
2
+ var Fragment = /* @__PURE__ */ Symbol("Fragment");
3
+ function h(type, props, ...children) {
4
+ const p = normalizeProps(props ?? {});
5
+ if (children.length > 0) {
6
+ p.children = children.length === 1 ? children[0] : children;
7
+ }
8
+ return { type, props: p, key: props?.key ?? void 0 };
9
+ }
10
+ function normalizeProps(props) {
11
+ if (!props) return {};
12
+ const result = {};
13
+ for (const key of Object.keys(props)) {
14
+ if (key === "key") continue;
15
+ result[key] = props[key];
16
+ }
17
+ return result;
18
+ }
19
+
20
+ // src/components/Button/Button.ts
21
+ var Button = (props, ctx) => {
22
+ const { variant = "primary", size = "md", block, loading, disabled, type, onClick, children } = props;
23
+ const cls = [
24
+ "wf-btn",
25
+ `wf-btn--${variant}`,
26
+ `wf-btn--${size}`,
27
+ block && "wf-btn--block",
28
+ loading && "wf-btn--loading"
29
+ ].filter(Boolean).join(" ");
30
+ const L = ctx?.i18n?.components?.Button ?? {};
31
+ return h("button", {
32
+ class: cls,
33
+ type: type ?? "button",
34
+ disabled: disabled || loading || void 0,
35
+ "aria-busy": loading || void 0,
36
+ onClick
37
+ }, loading ? L.loading ?? "\u52A0\u8F7D\u4E2D..." : children);
38
+ };
39
+
40
+ // src/components/Input/Input.ts
41
+ var Input = (props) => {
42
+ const { label, type = "text", value, placeholder, required, disabled, error, hint, onInput, onChange } = props;
43
+ const inputEl = h("input", {
44
+ class: "wf-input",
45
+ type,
46
+ value: value ?? "",
47
+ placeholder,
48
+ required: required || void 0,
49
+ disabled: disabled || void 0,
50
+ onInput,
51
+ onChange
52
+ });
53
+ if (!label && !error && !hint) return inputEl;
54
+ const children = [];
55
+ if (label) {
56
+ const labelContent = [label];
57
+ if (required) labelContent.push(h("span", { class: "wf-input-req" }, "*"));
58
+ children.push(h("label", { class: "wf-input-label" }, labelContent));
59
+ }
60
+ children.push(inputEl);
61
+ if (error) children.push(h("div", { class: "wf-input-err" }, error));
62
+ if (hint && !error) children.push(h("div", { class: "wf-input-hint" }, hint));
63
+ return h("div", { class: `wf-input-wrap${error ? " wf-input--err" : ""}` }, children);
64
+ };
65
+
66
+ // src/components/Textarea/Textarea.ts
67
+ var Textarea = (props, _ctx) => {
68
+ const { label, value, placeholder, required, disabled, error, hint, rows = 3, onInput } = props;
69
+ const textareaEl = h("textarea", {
70
+ class: "wf-textarea",
71
+ value: value ?? "",
72
+ placeholder,
73
+ required: required || void 0,
74
+ disabled: disabled || void 0,
75
+ rows,
76
+ onInput
77
+ });
78
+ const children = [];
79
+ if (label) {
80
+ const labelContent = [label];
81
+ if (required) labelContent.push(h("span", { class: "wf-textarea-req" }, "*"));
82
+ children.push(h("label", { class: "wf-textarea-label" }, labelContent));
83
+ }
84
+ children.push(textareaEl);
85
+ if (error) children.push(h("div", { class: "wf-textarea-err" }, error));
86
+ if (hint && !error) children.push(h("div", { class: "wf-textarea-hint" }, hint));
87
+ return h("div", { class: `wf-textarea-wrap${error ? " wf-textarea--err" : ""}` }, children);
88
+ };
89
+
90
+ // src/components/Select/Select.ts
91
+ var Select = (props, _ctx) => {
92
+ const { label, value, options, placeholder, required, disabled, error, onChange, children } = props;
93
+ const optionEls = [];
94
+ if (placeholder) {
95
+ optionEls.push(h("option", { value: "", disabled: true }, placeholder));
96
+ }
97
+ if (options) {
98
+ for (const opt of options) {
99
+ optionEls.push(h("option", { value: opt.value, disabled: opt.disabled }, opt.label));
100
+ }
101
+ }
102
+ const selectEl = h("select", {
103
+ class: "wf-select",
104
+ value: value ?? "",
105
+ required: required || void 0,
106
+ disabled: disabled || void 0,
107
+ onChange
108
+ }, children ?? optionEls);
109
+ const wrapChildren = [];
110
+ if (label) {
111
+ const labelContent = [label];
112
+ if (required) labelContent.push(h("span", { class: "wf-select-req" }, "*"));
113
+ wrapChildren.push(h("label", { class: "wf-select-label" }, labelContent));
114
+ }
115
+ wrapChildren.push(selectEl);
116
+ if (error) wrapChildren.push(h("div", { class: "wf-select-err" }, error));
117
+ return h("div", { class: `wf-select-wrap${error ? " wf-select--err" : ""}` }, wrapChildren);
118
+ };
119
+
120
+ // src/components/Checkbox/Checkbox.ts
121
+ var Checkbox = (props, _ctx) => {
122
+ const { label, checked, disabled, onChange } = props;
123
+ const input = h("input", {
124
+ type: "checkbox",
125
+ class: "wf-checkbox-input",
126
+ checked: checked || void 0,
127
+ disabled: disabled || void 0,
128
+ onChange: onChange ? (e) => onChange(e.target.checked) : void 0
129
+ });
130
+ const visual = h("span", { class: "wf-checkbox-visual" });
131
+ if (!label) return h("label", { class: "wf-checkbox" }, [input, visual]);
132
+ return h("label", { class: "wf-checkbox" }, [
133
+ input,
134
+ visual,
135
+ h("span", { class: "wf-checkbox-label" }, label)
136
+ ]);
137
+ };
138
+
139
+ // src/components/Switch/Switch.ts
140
+ var Switch = (props, ctx) => {
141
+ const { label, checked, disabled, onChange } = props;
142
+ const input = h("input", {
143
+ type: "checkbox",
144
+ class: "wf-switch-input",
145
+ checked: checked || void 0,
146
+ disabled: disabled || void 0,
147
+ role: "switch",
148
+ "aria-checked": String(!!checked),
149
+ onChange: onChange ? (e) => onChange(e.target.checked) : void 0
150
+ });
151
+ const track = h("span", { class: "wf-switch-track" });
152
+ const SL = ctx?.i18n?.components?.Switch ?? {};
153
+ if (!label) return h("label", { class: "wf-switch", "aria-label": SL.ariaLabel ?? "\u5207\u6362" }, [input, track]);
154
+ return h("label", { class: "wf-switch" }, [
155
+ input,
156
+ track,
157
+ h("span", { class: "wf-switch-label" }, label)
158
+ ]);
159
+ };
160
+
161
+ // src/components/RadioGroup/RadioGroup.ts
162
+ var RadioGroup = (props, _ctx) => {
163
+ const { name, value, options = [], inline, onChange } = props;
164
+ const radios = options.map((opt) => {
165
+ const input = h("input", {
166
+ type: "radio",
167
+ class: "wf-radio-input",
168
+ name: name ?? "radio",
169
+ value: opt.value,
170
+ checked: value === opt.value || void 0,
171
+ disabled: opt.disabled || void 0,
172
+ onChange: onChange ? () => onChange(opt.value) : void 0
173
+ });
174
+ const visual = h("span", { class: "wf-radio-visual" });
175
+ const label = h("span", { class: "wf-radio-label-text" }, opt.label);
176
+ return h("label", {
177
+ class: "wf-radio",
178
+ key: opt.value
179
+ }, [input, visual, label]);
180
+ });
181
+ return h("div", {
182
+ class: `wf-radio-group${inline ? " wf-radio-group--inline" : ""}`
183
+ }, radios);
184
+ };
185
+
186
+ // src/components/Table/Table.ts
187
+ var Table = (props, _ctx) => {
188
+ const { data = [], columns, onRowClick } = props;
189
+ const headerCells = columns.map(
190
+ (col) => h("th", {
191
+ class: "wf-table-th",
192
+ scope: "col",
193
+ style: col.width ? { width: col.width } : void 0
194
+ }, col.label)
195
+ );
196
+ const headerRow = h("tr", { class: "wf-table-tr" }, headerCells);
197
+ const thead = h("thead", { class: "wf-table-thead" }, headerRow);
198
+ const bodyRows = data.map((row, i) => {
199
+ const cells = columns.map((col) => {
200
+ const val = row[col.key];
201
+ const content = col.render ? col.render(val, row, i) : String(val ?? "");
202
+ return h("td", { class: "wf-table-td" }, content);
203
+ });
204
+ return h("tr", {
205
+ class: "wf-table-tr",
206
+ onClick: onRowClick ? (e) => {
207
+ onRowClick(row, i);
208
+ } : void 0,
209
+ style: onRowClick ? { cursor: "pointer" } : void 0
210
+ }, cells);
211
+ });
212
+ const tbody = h("tbody", { class: "wf-table-tbody" }, bodyRows);
213
+ return h("table", { class: "wf-table" }, [thead, tbody]);
214
+ };
215
+
216
+ // src/client/scroll-lock.ts
217
+ var lockedCount = 0;
218
+ var originalOverflow = "";
219
+ var originalPosition = "";
220
+ var originalTop = "";
221
+ var originalWidth = "";
222
+ var scrollY = 0;
223
+ function canLock() {
224
+ return typeof window !== "undefined" && typeof document !== "undefined";
225
+ }
226
+ function lockScroll() {
227
+ lockedCount++;
228
+ if (lockedCount > 1) return;
229
+ if (!canLock()) return;
230
+ scrollY = window.scrollY;
231
+ const body = document.body;
232
+ originalOverflow = body.style.overflow;
233
+ originalPosition = body.style.position;
234
+ originalTop = body.style.top;
235
+ originalWidth = body.style.width;
236
+ body.style.overflow = "hidden";
237
+ const isIOS = /iPhone|iPad|iPod/.test(navigator.platform) || /Mac/.test(navigator.platform) && "ontouchend" in document;
238
+ if (isIOS) {
239
+ body.style.position = "fixed";
240
+ body.style.top = `-${scrollY}px`;
241
+ body.style.width = "100%";
242
+ }
243
+ }
244
+ function unlockScroll() {
245
+ lockedCount--;
246
+ if (lockedCount > 0) return;
247
+ if (!canLock()) return;
248
+ const body = document.body;
249
+ body.style.overflow = originalOverflow;
250
+ body.style.position = originalPosition;
251
+ body.style.top = originalTop;
252
+ body.style.width = originalWidth;
253
+ if (scrollY > 0) window.scrollTo(0, scrollY);
254
+ }
255
+
256
+ // src/client/focus-trap.ts
257
+ var FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
258
+ function trapFocus(container) {
259
+ const focusable = container.querySelectorAll(FOCUSABLE);
260
+ if (focusable.length === 0) return () => {
261
+ };
262
+ const first = focusable[0];
263
+ const last = focusable[focusable.length - 1];
264
+ const handler = (e) => {
265
+ if (e.key !== "Tab") return;
266
+ if (e.shiftKey && document.activeElement === first) {
267
+ e.preventDefault();
268
+ last.focus();
269
+ } else if (!e.shiftKey && document.activeElement === last) {
270
+ e.preventDefault();
271
+ first.focus();
272
+ }
273
+ };
274
+ const prevFocused = document.activeElement;
275
+ first.focus();
276
+ container.addEventListener("keydown", handler);
277
+ return () => {
278
+ container.removeEventListener("keydown", handler);
279
+ prevFocused?.focus();
280
+ };
281
+ }
282
+
283
+ // src/components/Modal/Modal.ts
284
+ var Modal = (props, ctx) => {
285
+ const { open, title, onClose, children, footer } = props;
286
+ const $ = ctx.ui.$;
287
+ if (!ctx.ui.ready) {
288
+ $.exiting = false;
289
+ $.prevOpen = open;
290
+ }
291
+ if ($.prevOpen !== open) {
292
+ $.prevOpen = open;
293
+ if (open && $.exiting) $.exiting = false;
294
+ }
295
+ const startClose = () => {
296
+ $.exiting = true;
297
+ };
298
+ const onExitEnd = () => {
299
+ $.exiting = false;
300
+ onClose?.();
301
+ };
302
+ if (!open && !$.exiting) return null;
303
+ const isClosing = $.exiting;
304
+ const handleKeyDown = (e) => {
305
+ if (e.key === "Escape" && !isClosing) startClose();
306
+ };
307
+ const modalRef = (el) => {
308
+ if (!el) return;
309
+ lockScroll();
310
+ const cleanupFocus = trapFocus(el);
311
+ return () => {
312
+ unlockScroll();
313
+ cleanupFocus();
314
+ };
315
+ };
316
+ const overlay = h("div", {
317
+ class: "wf-modal-overlay",
318
+ onClick: isClosing ? void 0 : startClose
319
+ });
320
+ const closeBtn = h("button", {
321
+ class: "wf-modal-close",
322
+ onClick: isClosing ? void 0 : startClose,
323
+ type: "button"
324
+ }, "\u2715");
325
+ const titleEl = title ? h("div", { class: "wf-modal-header" }, [title, closeBtn]) : null;
326
+ const bodyEl = h("div", { class: "wf-modal-body" }, children);
327
+ const footerEl = footer ? h("div", { class: "wf-modal-footer" }, footer) : null;
328
+ const content = h("div", {
329
+ class: "wf-modal-content",
330
+ onClick: (e) => e.stopPropagation()
331
+ }, [titleEl, bodyEl, footerEl].filter(Boolean));
332
+ const ML = ctx?.i18n?.components?.Modal ?? {};
333
+ const cls = isClosing ? "wf-modal wf-modal--exit" : "wf-modal wf-modal--enter";
334
+ return h("div", {
335
+ class: cls,
336
+ role: "dialog",
337
+ "aria-modal": "true",
338
+ "aria-label": title ?? (ML.ariaLabel ?? "\u5F39\u7A97"),
339
+ onKeyDown: handleKeyDown,
340
+ onAnimationEnd: isClosing ? onExitEnd : void 0,
341
+ ref: modalRef
342
+ }, [overlay, content]);
343
+ };
344
+
345
+ // src/components/Toast/Toast.ts
346
+ var Toast = (props, _ctx) => {
347
+ const { toasts = [], onRemove } = props;
348
+ if (toasts.length === 0) return null;
349
+ const items = toasts.map(
350
+ (t) => h("div", {
351
+ class: `wf-toast wf-toast--${t.type}`,
352
+ key: t.id,
353
+ onClick: onRemove ? () => onRemove(t.id) : void 0
354
+ }, [
355
+ h("span", { class: "wf-toast-icon" }, iconFor(t.type)),
356
+ h("span", { class: "wf-toast-msg" }, t.message)
357
+ ])
358
+ );
359
+ return h("div", { class: "wf-toast-container" }, items);
360
+ };
361
+ function iconFor(type) {
362
+ switch (type) {
363
+ case "success":
364
+ return "\u2713";
365
+ case "error":
366
+ return "\u2715";
367
+ case "warning":
368
+ return "\u26A0";
369
+ case "info":
370
+ return "\u2139";
371
+ }
372
+ }
373
+
374
+ // src/components/Alert/Alert.ts
375
+ var Alert = (props, _ctx) => {
376
+ const { variant = "info", closable, onClose, children } = props;
377
+ if (!children) return null;
378
+ const icon = h("span", { class: "wf-alert-icon" }, iconFor2(variant));
379
+ const closeBtn = closable ? h("button", { class: "wf-alert-close", onClick: onClose, type: "button" }, "\u2715") : null;
380
+ const msg = h("span", { class: "wf-alert-msg" }, children);
381
+ return h("div", { class: `wf-alert wf-alert--${variant}`, role: "alert" }, [icon, msg, closeBtn].filter(Boolean));
382
+ };
383
+ function iconFor2(variant) {
384
+ switch (variant) {
385
+ case "success":
386
+ return "\u2713";
387
+ case "error":
388
+ return "\u2715";
389
+ case "warning":
390
+ return "\u26A0";
391
+ case "info":
392
+ return "\u2139";
393
+ }
394
+ }
395
+
396
+ // src/components/Loading/Loading.ts
397
+ var Loading = (props, _ctx) => {
398
+ const { text = "\u52A0\u8F7D\u4E2D..." } = props;
399
+ return h("div", { class: "wf-loading", role: "status", "aria-live": "polite" }, [
400
+ h("div", { class: "wf-loading-spinner" }),
401
+ h("span", { class: "wf-loading-text" }, text)
402
+ ]);
403
+ };
404
+
405
+ // src/components/EmptyState/EmptyState.ts
406
+ var EmptyState = (props, _ctx) => {
407
+ const { icon = "\u{1F4E6}", text = "\u6682\u65E0\u6570\u636E", hint, children } = props;
408
+ const parts = [
409
+ h("div", { class: "wf-empty-icon" }, icon),
410
+ h("div", { class: "wf-empty-text" }, text)
411
+ ];
412
+ if (hint) parts.push(h("div", { class: "wf-empty-hint" }, hint));
413
+ if (children) parts.push(h("div", { class: "wf-empty-action" }, children));
414
+ return h("div", { class: "wf-empty", role: "status" }, parts);
415
+ };
416
+
417
+ // src/components/Tabs/Tabs.ts
418
+ var Tabs = (props, _ctx) => {
419
+ const { items = [], active, onChange } = props;
420
+ if (items.length === 0) return null;
421
+ const activeKey = active ?? items[0].key;
422
+ const tabList = items.map(
423
+ (tab) => h("button", {
424
+ class: `wf-tab${tab.key === activeKey ? " wf-tab--active" : ""}`,
425
+ key: tab.key,
426
+ role: "tab",
427
+ "aria-selected": tab.key === activeKey ? "true" : "false",
428
+ onClick: tab.key !== activeKey && onChange ? () => onChange(tab.key) : void 0
429
+ }, tab.label)
430
+ );
431
+ const activeTab = items.find((t) => t.key === activeKey);
432
+ const content = activeTab?.content ? h("div", { class: "wf-tab-content" }, activeTab.content) : null;
433
+ return h("div", { class: "wf-tabs", role: "tablist" }, [
434
+ h("div", { class: "wf-tab-list" }, tabList),
435
+ content
436
+ ].filter(Boolean));
437
+ };
438
+
439
+ // src/components/Dropdown/Dropdown.ts
440
+ var Dropdown = (props, _ctx) => {
441
+ const { trigger, items = [], open } = props;
442
+ const menuItems = items.map(
443
+ (item, i) => h("button", {
444
+ class: `wf-dropdown-item${item.variant === "danger" ? " wf-dropdown-item--danger" : ""}`,
445
+ key: item.value ?? i,
446
+ disabled: item.disabled || void 0,
447
+ role: "menuitem",
448
+ onClick: item.onClick
449
+ }, item.label)
450
+ );
451
+ const menu = open ? h("div", { class: "wf-dropdown-menu", role: "menu" }, menuItems) : null;
452
+ return h("div", { class: `wf-dropdown${open ? " wf-dropdown--open" : ""}` }, [
453
+ trigger,
454
+ menu
455
+ ].filter(Boolean));
456
+ };
457
+
458
+ // src/components/Pagination/Pagination.ts
459
+ var Pagination = (props, ctx) => {
460
+ const { total, page = 1, pageSize = 20, onChange } = props;
461
+ const totalPages = Math.max(1, Math.ceil(total / pageSize));
462
+ if (totalPages <= 1) return null;
463
+ const pages = [];
464
+ pages.push(h("button", {
465
+ class: `wf-page-btn${page <= 1 ? " wf-page-btn--disabled" : ""}`,
466
+ disabled: page <= 1,
467
+ onClick: page > 1 && onChange ? () => onChange(page - 1) : void 0
468
+ }, "\u2039"));
469
+ const range = getPageRange(page, totalPages);
470
+ for (const p of range) {
471
+ if (p === "...") {
472
+ pages.push(h("span", { class: "wf-page-ellipsis" }, "..."));
473
+ } else {
474
+ pages.push(h("button", {
475
+ class: `wf-page-btn${p === page ? " wf-page-btn--active" : ""}`,
476
+ "aria-current": p === page ? "page" : void 0,
477
+ onClick: p !== page && onChange ? () => onChange(p) : void 0
478
+ }, String(p)));
479
+ }
480
+ }
481
+ pages.push(h("button", {
482
+ class: `wf-page-btn${page >= totalPages ? " wf-page-btn--disabled" : ""}`,
483
+ disabled: page >= totalPages,
484
+ onClick: page < totalPages && onChange ? () => onChange(page + 1) : void 0
485
+ }, "\u203A"));
486
+ const PL = ctx?.i18n?.components?.Pagination ?? {};
487
+ return h("nav", { class: "wf-pagination", "aria-label": PL.ariaLabel ?? "\u5206\u9875" }, pages);
488
+ };
489
+ function getPageRange(current, total) {
490
+ if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);
491
+ const pages = [1];
492
+ if (current > 3) pages.push("...");
493
+ const start = Math.max(2, current - 1);
494
+ const end = Math.min(total - 1, current + 1);
495
+ for (let i = start; i <= end; i++) pages.push(i);
496
+ if (current < total - 2) pages.push("...");
497
+ pages.push(total);
498
+ return pages;
499
+ }
500
+
501
+ // src/components/Card/Card.ts
502
+ var Card = (props, _ctx) => {
503
+ const { variant = "default", padding = "md", clickable, onClick, children } = props;
504
+ const cls = [
505
+ "wf-card",
506
+ `wf-card--${variant}`,
507
+ `wf-card--pad-${padding}`,
508
+ clickable && "wf-card--clickable"
509
+ ].filter(Boolean).join(" ");
510
+ return h("div", { class: cls, onClick, role: clickable ? "button" : void 0, tabindex: clickable ? 0 : void 0 }, children);
511
+ };
512
+
513
+ // src/components/Badge/Badge.ts
514
+ var Badge = (props, _ctx) => {
515
+ const { variant = "default", dot, children } = props;
516
+ if (dot) {
517
+ return h("span", { class: `wf-badge-dot wf-badge-dot--${variant}` });
518
+ }
519
+ return h("span", { class: `wf-badge wf-badge--${variant}` }, children ?? "");
520
+ };
521
+
522
+ // src/components/Avatar/Avatar.ts
523
+ var COLORS = ["#4f6ef7", "#22c55e", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4", "#ec4899"];
524
+ function hashColor(name) {
525
+ let hash = 0;
526
+ for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);
527
+ return COLORS[Math.abs(hash) % COLORS.length];
528
+ }
529
+ var Avatar = (props, _ctx) => {
530
+ const { name = "", src, size = "md" } = props;
531
+ const initial = name.trim()[0]?.toUpperCase() ?? "?";
532
+ if (src) {
533
+ return h("img", {
534
+ class: `wf-avatar wf-avatar--${size}`,
535
+ src,
536
+ alt: name
537
+ });
538
+ }
539
+ return h("div", {
540
+ class: `wf-avatar wf-avatar--${size}`,
541
+ style: { background: hashColor(name) }
542
+ }, initial);
543
+ };
544
+
545
+ // src/components/Tag/Tag.ts
546
+ var Tag = (props, _ctx) => {
547
+ const { closable, onClose, variant = "default", children } = props;
548
+ const closeBtn = closable ? h("button", { class: "wf-tag-close", onClick: onClose, type: "button" }, "\u2715") : null;
549
+ return h("span", { class: `wf-tag wf-tag--${variant}` }, [
550
+ h("span", { class: "wf-tag-text" }, children),
551
+ closeBtn
552
+ ].filter(Boolean));
553
+ };
554
+
555
+ // src/components/StatCard/StatCard.ts
556
+ var StatCard = (props, _ctx) => {
557
+ const { label, value, trend, trendLabel, icon } = props;
558
+ const children = [];
559
+ if (icon) children.push(h("div", { class: "wf-stat-icon" }, icon));
560
+ children.push(h("div", { class: "wf-stat-value" }, String(value)));
561
+ children.push(h("div", { class: "wf-stat-label" }, label));
562
+ if (trend) {
563
+ children.push(h("div", {
564
+ class: `wf-stat-trend wf-stat-trend--${trend}`
565
+ }, [
566
+ h("span", { class: "wf-stat-trend-arrow" }, trend === "up" ? "\u2191" : "\u2193"),
567
+ trendLabel ? h("span", { class: "wf-stat-trend-label" }, trendLabel) : null
568
+ ].filter(Boolean)));
569
+ }
570
+ return h("div", { class: "wf-stat" }, children);
571
+ };
572
+
573
+ // src/components/Steps/Steps.ts
574
+ var Steps = (props, _ctx) => {
575
+ const { items = [], active, current = 0 } = props;
576
+ const activeKey = active ?? items[current]?.key;
577
+ const steps = items.map((item, i) => {
578
+ const idx = items.findIndex((s) => s.key === activeKey);
579
+ const isDone = i < idx;
580
+ const isCurrent = i === idx;
581
+ const cls = [
582
+ "wf-step",
583
+ isDone && "wf-step--done",
584
+ isCurrent && "wf-step--current"
585
+ ].filter(Boolean).join(" ");
586
+ const num = isDone ? h("span", { class: "wf-step-num" }, "\u2713") : h("span", { class: "wf-step-num" }, String(i + 1));
587
+ const label = h("span", { class: "wf-step-label" }, item.label);
588
+ const desc = item.description ? h("span", { class: "wf-step-desc" }, item.description) : null;
589
+ const connector = i < items.length - 1 ? h("span", { class: `wf-step-connector${isDone ? " wf-step-connector--done" : ""}` }) : null;
590
+ return h("div", { class: cls, key: item.key }, [
591
+ num,
592
+ label,
593
+ desc,
594
+ connector
595
+ ].filter(Boolean));
596
+ });
597
+ return h("div", { class: "wf-steps" }, steps);
598
+ };
599
+
600
+ // src/components/Form/Form.ts
601
+ var Form = (props, _ctx) => {
602
+ const { onSubmit, children } = props;
603
+ const handleSubmit = (e) => {
604
+ e.preventDefault();
605
+ onSubmit?.();
606
+ };
607
+ return h("form", {
608
+ class: "wf-form",
609
+ onSubmit: handleSubmit
610
+ }, children);
611
+ };
612
+
613
+ // src/components/Field/Field.ts
614
+ var Field = (props, _ctx) => {
615
+ const { label, required, error, hint, children } = props;
616
+ const parts = [];
617
+ if (label) {
618
+ const labelContent = [label];
619
+ if (required) labelContent.push(h("span", { class: "wf-field-req" }, "*"));
620
+ parts.push(h("label", { class: "wf-field-label" }, labelContent));
621
+ }
622
+ parts.push(children);
623
+ if (error) parts.push(h("div", { class: "wf-field-err" }, error));
624
+ if (hint && !error) parts.push(h("div", { class: "wf-field-hint" }, hint));
625
+ return h("div", { class: `wf-field${error ? " wf-field--err" : ""}` }, parts);
626
+ };
627
+
628
+ // src/components/Slider/Slider.ts
629
+ var Slider = (props, _ctx) => {
630
+ const { label, value = 0, min = 0, max = 100, step = 1, onChange } = props;
631
+ const numVal = Number(value);
632
+ const input = h("input", {
633
+ type: "range",
634
+ class: "wf-slider-input",
635
+ value: numVal,
636
+ min,
637
+ max,
638
+ step,
639
+ onChange: onChange ? (e) => onChange(Number(e.target.value)) : void 0
640
+ });
641
+ const display = h("span", { class: "wf-slider-value" }, String(numVal));
642
+ if (!label) return h("div", { class: "wf-slider" }, [input, display]);
643
+ return h("div", { class: "wf-slider-wrap" }, [
644
+ h("label", { class: "wf-slider-label" }, label),
645
+ h("div", { class: "wf-slider" }, [input, display])
646
+ ]);
647
+ };
648
+
649
+ // src/components/SearchInput/SearchInput.ts
650
+ var SearchInput = (props, _ctx) => {
651
+ const { value = "", placeholder = "\u641C\u7D22...", onInput, onClear } = props;
652
+ const clearBtn = value && onClear ? h("button", {
653
+ class: "wf-search-clear",
654
+ type: "button",
655
+ onClick: onClear
656
+ }, "\u2715") : null;
657
+ const icon = h("span", { class: "wf-search-icon" }, "\u{1F50D}");
658
+ return h("div", { class: "wf-search" }, [
659
+ icon,
660
+ h("input", {
661
+ class: "wf-search-input",
662
+ type: "search",
663
+ value,
664
+ placeholder,
665
+ onInput
666
+ }),
667
+ clearBtn
668
+ ].filter(Boolean));
669
+ };
670
+
671
+ // src/components/ProgressBar/ProgressBar.ts
672
+ var ProgressBar = (props, ctx) => {
673
+ const { value = 0, max = 100, label, showValue } = props;
674
+ const pct = Math.min(100, Math.max(0, value / max * 100));
675
+ const PBL = ctx?.i18n?.components?.ProgressBar ?? {};
676
+ const bar = h("div", {
677
+ class: "wf-progress",
678
+ role: "progressbar",
679
+ "aria-valuenow": Math.round(value),
680
+ "aria-valuemin": 0,
681
+ "aria-valuemax": Math.round(max),
682
+ "aria-label": label ?? (PBL.ariaLabel ?? "\u8FDB\u5EA6")
683
+ }, [
684
+ h("div", {
685
+ class: "wf-progress-fill",
686
+ style: { width: `${pct}%` }
687
+ })
688
+ ]);
689
+ if (!label && !showValue) return bar;
690
+ const parts = [];
691
+ if (label) parts.push(h("span", { class: "wf-progress-label" }, label));
692
+ parts.push(bar);
693
+ if (showValue) parts.push(h("span", { class: "wf-progress-value" }, `${Math.round(pct)}%`));
694
+ return h("div", { class: "wf-progress-wrap" }, parts);
695
+ };
696
+
697
+ // src/components/Accordion/Accordion.ts
698
+ var Accordion = (props, _ctx) => {
699
+ const { items = [], multiple } = props;
700
+ if (items.length === 0) return null;
701
+ const panels = items.map(
702
+ (item) => h("details", { class: "wf-accordion-item", key: item.key, open: true }, [
703
+ h("summary", { class: "wf-accordion-summary", "aria-expanded": "true" }, item.title),
704
+ item.content ? h("div", { class: "wf-accordion-content" }, item.content) : null
705
+ ].filter(Boolean))
706
+ );
707
+ return h("div", { class: "wf-accordion" }, panels);
708
+ };
709
+
710
+ // src/components/PageHeader/PageHeader.ts
711
+ var PageHeader = (props, _ctx) => {
712
+ const { title, sub, children } = props;
713
+ return h("div", { class: "wf-page-head" }, [
714
+ h("div", { class: "wf-page-head-left" }, [
715
+ h("h2", { class: "wf-page-title" }, title),
716
+ sub ? h("p", { class: "wf-page-sub" }, sub) : null
717
+ ].filter(Boolean)),
718
+ children ? h("div", { class: "wf-page-head-actions" }, children) : null
719
+ ].filter(Boolean));
720
+ };
721
+
722
+ // src/components/Breadcrumb/Breadcrumb.ts
723
+ var Breadcrumb = (props, ctx) => {
724
+ const { items } = props;
725
+ const children = items.flatMap((item, i) => {
726
+ const isLast = i === items.length - 1;
727
+ const el = isLast ? h("span", { class: "wf-breadcrumb-current", "aria-current": "page" }, item.label) : item.href ? h("a", { class: "wf-breadcrumb-link", href: item.href }, item.label) : h("span", { class: "wf-breadcrumb-text" }, item.label);
728
+ if (isLast) return el;
729
+ return [el, h("span", { class: "wf-breadcrumb-sep", "aria-hidden": "true" }, "/")];
730
+ });
731
+ const BL = ctx?.i18n?.components?.Breadcrumb ?? {};
732
+ return h("nav", { class: "wf-breadcrumb", "aria-label": BL.ariaLabel ?? "\u9762\u5305\u5C51" }, children);
733
+ };
734
+
735
+ // src/components/Divider/Divider.ts
736
+ var Divider = (props, _ctx) => {
737
+ const { vertical, children } = props;
738
+ if (vertical) {
739
+ return h("div", { class: "wf-divider wf-divider--vertical", role: "separator" });
740
+ }
741
+ const cls = children ? "wf-divider wf-divider--with-text" : "wf-divider";
742
+ return h(
743
+ "div",
744
+ { class: cls, role: "separator" },
745
+ children ? h("span", { class: "wf-divider-text" }, children) : void 0
746
+ );
747
+ };
748
+
749
+ // src/components/FileUpload/FileUpload.ts
750
+ function formatSize(bytes) {
751
+ if (bytes < 1024) return `${bytes}B`;
752
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
753
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
754
+ }
755
+ var FileUpload = (props, ctx) => {
756
+ const { accept, multiple, maxSize, disabled, error, hint, value, onChange, children } = props;
757
+ const FL = ctx?.i18n?.components?.FileUpload ?? {};
758
+ const files = value ?? [];
759
+ let dragOver = false;
760
+ const handleChange = (e) => {
761
+ const input = e.target;
762
+ const selected = Array.from(input.files ?? []);
763
+ if (maxSize) {
764
+ const oversized = selected.filter((f) => f.size > maxSize);
765
+ if (oversized.length > 0) return;
766
+ }
767
+ onChange?.(selected);
768
+ input.value = "";
769
+ };
770
+ const handleDrop = (e) => {
771
+ e.preventDefault();
772
+ dragOver = false;
773
+ if (disabled) return;
774
+ const dropped = Array.from(e.dataTransfer?.files ?? []);
775
+ if (maxSize) {
776
+ const oversized = dropped.filter((f) => f.size > maxSize);
777
+ if (oversized.length > 0) return;
778
+ }
779
+ onChange?.(dropped);
780
+ };
781
+ const handleDragOver = (e) => {
782
+ e.preventDefault();
783
+ dragOver = true;
784
+ };
785
+ const handleDragLeave = () => {
786
+ dragOver = false;
787
+ };
788
+ const handleRemove = (i) => {
789
+ const updated = files.filter((_, idx) => idx !== i);
790
+ onChange?.(updated);
791
+ };
792
+ const inputEl = h("input", {
793
+ type: "file",
794
+ class: "wf-upload-input",
795
+ accept: accept || void 0,
796
+ multiple: multiple || void 0,
797
+ disabled: disabled || void 0,
798
+ onChange: handleChange,
799
+ style: { display: "none" }
800
+ });
801
+ const dropZone = h("div", {
802
+ class: `wf-upload-zone${disabled ? " wf-upload-zone--disabled" : ""}${error ? " wf-upload-zone--err" : ""}`,
803
+ onClick: disabled ? void 0 : () => {
804
+ const input = document.querySelector(".wf-upload-input");
805
+ input?.click();
806
+ },
807
+ onDrop: handleDrop,
808
+ onDragOver: handleDragOver,
809
+ onDragLeave: handleDragLeave
810
+ }, children ?? h("div", { class: "wf-upload-placeholder" }, [
811
+ h("span", { class: "wf-upload-icon" }, "\u{1F4C1}"),
812
+ h("span", { class: "wf-upload-text" }, FL.placeholder ?? "\u70B9\u51FB\u6216\u62D6\u62FD\u4E0A\u4F20\u6587\u4EF6"),
813
+ accept ? h("span", { class: "wf-upload-hint" }, `${FL.supportedFormats ?? "\u652F\u6301\u683C\u5F0F: "}${accept}`) : null,
814
+ maxSize ? h("span", { class: "wf-upload-hint" }, `${FL.maxSize ?? "\u6700\u5927 "}${formatSize(maxSize)}`) : null
815
+ ].filter(Boolean)));
816
+ const fileList = files.length > 0 ? h(
817
+ "ul",
818
+ { class: "wf-upload-list" },
819
+ files.map(
820
+ (f, i) => h(
821
+ "li",
822
+ { class: "wf-upload-item", key: f.name + f.size },
823
+ h("span", { class: "wf-upload-item-info" }, [
824
+ h("span", { class: "wf-upload-item-name" }, f.name),
825
+ h("span", { class: "wf-upload-item-size" }, formatSize(f.size))
826
+ ]),
827
+ h("button", {
828
+ class: "wf-upload-item-remove",
829
+ "aria-label": `${FL.remove ?? "\u5220\u9664"} ${f.name}`,
830
+ onClick: () => handleRemove(i)
831
+ }, "\u2715")
832
+ )
833
+ )
834
+ ) : null;
835
+ const parts = [inputEl, dropZone, fileList];
836
+ if (error) parts.push(h("div", { class: "wf-upload-err" }, error));
837
+ if (hint && !error) parts.push(h("div", { class: "wf-upload-hint" }, hint));
838
+ return h("div", { class: "wf-upload" }, parts);
839
+ };
840
+
841
+ // src/components/Tooltip/Tooltip.ts
842
+ var Tooltip = (props, ctx) => {
843
+ const { content, position = "top", children, disabled } = props;
844
+ const $ = ctx.ui.$;
845
+ if (!ctx.ui.ready) {
846
+ $.show = false;
847
+ }
848
+ const show = () => {
849
+ $.show = true;
850
+ };
851
+ const hide = () => {
852
+ $.show = false;
853
+ };
854
+ const tip = $.show && !disabled ? h("div", {
855
+ class: `wf-tooltip wf-tooltip--${position}`,
856
+ role: "tooltip"
857
+ }, [
858
+ h("div", { class: "wf-tooltip-arrow" }),
859
+ h("div", { class: "wf-tooltip-content" }, content)
860
+ ]) : null;
861
+ return h("div", {
862
+ class: "wf-tooltip-wrap",
863
+ onMouseEnter: show,
864
+ onMouseLeave: hide,
865
+ onFocus: show,
866
+ onBlur: hide
867
+ }, [children, tip].filter(Boolean));
868
+ };
869
+
870
+ // src/components/Drawer/Drawer.ts
871
+ var Drawer = (props, ctx) => {
872
+ const { open, title, position = "right", onClose, children, footer } = props;
873
+ const $ = ctx.ui.$;
874
+ if (!ctx.ui.ready) {
875
+ $.exiting = false;
876
+ $.prevOpen = open;
877
+ }
878
+ if ($.prevOpen !== open) {
879
+ $.prevOpen = open;
880
+ if (open && $.exiting) $.exiting = false;
881
+ }
882
+ const startClose = () => {
883
+ $.exiting = true;
884
+ };
885
+ const onExitEnd = () => {
886
+ $.exiting = false;
887
+ onClose?.();
888
+ };
889
+ if (!open && !$.exiting) return null;
890
+ const isClosing = $.exiting;
891
+ const handleKeyDown = (e) => {
892
+ if (e.key === "Escape" && !isClosing) startClose();
893
+ };
894
+ const drawerRef = (el) => {
895
+ if (!el) return;
896
+ lockScroll();
897
+ const cleanupFocus = trapFocus(el);
898
+ return () => {
899
+ unlockScroll();
900
+ cleanupFocus();
901
+ };
902
+ };
903
+ const overlay = h("div", {
904
+ class: "wf-drawer-overlay",
905
+ onClick: isClosing ? void 0 : startClose
906
+ });
907
+ const closeBtn = h("button", {
908
+ class: "wf-drawer-close",
909
+ onClick: isClosing ? void 0 : startClose,
910
+ type: "button",
911
+ "aria-label": "\u5173\u95ED"
912
+ }, "\u2715");
913
+ const titleEl = title ? h("div", { class: "wf-drawer-header" }, [title, closeBtn]) : null;
914
+ const bodyEl = h("div", { class: "wf-drawer-body" }, children);
915
+ const footerEl = footer ? h("div", { class: "wf-drawer-footer" }, footer) : null;
916
+ const panel = h("div", {
917
+ class: `wf-drawer-panel wf-drawer-panel--${position}`,
918
+ onClick: (e) => e.stopPropagation(),
919
+ onAnimationEnd: isClosing ? onExitEnd : void 0
920
+ }, [titleEl, bodyEl, footerEl].filter(Boolean));
921
+ const DL = ctx?.i18n?.components?.Drawer ?? {};
922
+ const cls = isClosing ? `wf-drawer wf-drawer--${position} wf-drawer--exit` : `wf-drawer wf-drawer--${position} wf-drawer--enter`;
923
+ return h("div", {
924
+ class: cls,
925
+ role: "dialog",
926
+ "aria-modal": "true",
927
+ "aria-label": title ?? (DL.ariaLabel ?? "\u4FA7\u8FB9\u9762\u677F"),
928
+ onKeyDown: handleKeyDown,
929
+ ref: drawerRef
930
+ }, [overlay, panel]);
931
+ };
932
+
933
+ // src/components/Popover/Popover.ts
934
+ var Popover = (props, ctx) => {
935
+ const {
936
+ content,
937
+ trigger = "click",
938
+ position = "bottom",
939
+ open,
940
+ onOpenChange,
941
+ disabled,
942
+ children
943
+ } = props;
944
+ const $ = ctx.ui.$;
945
+ if (!ctx.ui.ready) {
946
+ $.show = false;
947
+ }
948
+ const isOpen = open !== void 0 ? open : $.show;
949
+ const setOpen = (v) => {
950
+ if (open === void 0) $.show = v;
951
+ onOpenChange?.(v);
952
+ };
953
+ const onClick = trigger === "click" && !disabled ? () => setOpen(!isOpen) : void 0;
954
+ const hoverProps = {};
955
+ if (trigger === "hover" && !disabled) {
956
+ hoverProps.onMouseEnter = () => setOpen(true);
957
+ hoverProps.onMouseLeave = () => setOpen(false);
958
+ hoverProps.onFocus = () => setOpen(true);
959
+ hoverProps.onBlur = () => setOpen(false);
960
+ }
961
+ const overlay = isOpen ? h("div", {
962
+ class: "wf-popover-overlay",
963
+ onMouseDown: () => setOpen(false)
964
+ }) : null;
965
+ const panel = isOpen ? h("div", {
966
+ class: `wf-popover wf-popover--${position}`,
967
+ role: "dialog",
968
+ "aria-modal": "true",
969
+ "aria-label": "\u5F39\u51FA\u9762\u677F",
970
+ onMouseDown: (e) => e.stopPropagation()
971
+ }, [
972
+ h("div", { class: "wf-popover-arrow" }),
973
+ h("div", { class: "wf-popover-content" }, content)
974
+ ]) : null;
975
+ return h("div", {
976
+ class: `wf-popover-wrap${isOpen ? " wf-popover-wrap--open" : ""}`,
977
+ ...hoverProps
978
+ }, [
979
+ h("div", { class: "wf-popover-trigger", onClick }, children),
980
+ overlay,
981
+ panel
982
+ ].filter(Boolean));
983
+ };
984
+
985
+ // src/components/Skeleton/Skeleton.ts
986
+ var Skeleton = (props) => {
987
+ const { variant = "text", lines = 1, width, height, className } = props;
988
+ const style = {};
989
+ if (width !== void 0) style.width = typeof width === "number" ? `${width}px` : width;
990
+ if (height !== void 0) style.height = typeof height === "number" ? `${height}px` : height;
991
+ const cls = [
992
+ "wf-skeleton",
993
+ `wf-skeleton--${variant}`,
994
+ className
995
+ ].filter(Boolean).join(" ");
996
+ if (lines <= 1) {
997
+ return h("div", { class: cls, style: Object.keys(style).length ? style : void 0 });
998
+ }
999
+ const items = Array.from({ length: lines }, (_, i) => {
1000
+ const itemCls = i === lines - 1 && lines > 1 ? `${cls} wf-skeleton--short` : cls;
1001
+ return h("div", { class: itemCls, style: Object.keys(style).length ? style : void 0 });
1002
+ });
1003
+ return h(Fragment, null, items);
1004
+ };
1005
+
1006
+ // src/components/Img/Img.ts
1007
+ var Img = (props) => {
1008
+ const { src, alt = "", fallback, loading, width, height, className, style } = props;
1009
+ const imgProps = {
1010
+ class: ["wf-image", className].filter(Boolean).join(" "),
1011
+ src: src ?? fallback ?? "",
1012
+ alt,
1013
+ loading: loading ?? "lazy"
1014
+ };
1015
+ if (width !== void 0) imgProps.width = width;
1016
+ if (height !== void 0) imgProps.height = height;
1017
+ if (style) imgProps.style = style;
1018
+ if (fallback) {
1019
+ imgProps.onError = (e) => {
1020
+ const el = e.currentTarget;
1021
+ if (el.src !== fallback) el.src = fallback;
1022
+ };
1023
+ }
1024
+ return h("img", imgProps);
1025
+ };
1026
+ export {
1027
+ Accordion,
1028
+ Alert,
1029
+ Avatar,
1030
+ Badge,
1031
+ Breadcrumb,
1032
+ Button,
1033
+ Card,
1034
+ Checkbox,
1035
+ Divider,
1036
+ Drawer,
1037
+ Dropdown,
1038
+ EmptyState,
1039
+ Field,
1040
+ FileUpload,
1041
+ Form,
1042
+ Img,
1043
+ Input,
1044
+ Loading,
1045
+ Modal,
1046
+ PageHeader,
1047
+ Pagination,
1048
+ Popover,
1049
+ ProgressBar,
1050
+ RadioGroup,
1051
+ SearchInput,
1052
+ Select,
1053
+ Skeleton,
1054
+ Slider,
1055
+ StatCard,
1056
+ Steps,
1057
+ Switch,
1058
+ Table,
1059
+ Tabs,
1060
+ Tag,
1061
+ Textarea,
1062
+ Toast,
1063
+ Tooltip
1064
+ };