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