weifuwu 0.38.2 → 0.40.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 (33) hide show
  1. package/README.md +96 -66
  2. package/dist/client/app.d.ts +2 -6
  3. package/dist/client/error-boundary.d.ts +2 -2
  4. package/dist/client/index.d.ts +3 -1
  5. package/dist/client/index.js +350 -147
  6. package/dist/client/locale/en_US.d.ts +15 -0
  7. package/dist/client/locale/zh_CN.d.ts +15 -0
  8. package/dist/client/popup.d.ts +19 -0
  9. package/dist/client/render.d.ts +3 -3
  10. package/dist/client/router.d.ts +1 -1
  11. package/dist/client/types.d.ts +11 -5
  12. package/dist/client/vnode.d.ts +11 -2
  13. package/dist/components/Chart/Chart.d.ts +15 -0
  14. package/dist/components/Chart/chart-utils.d.ts +53 -0
  15. package/dist/components/DatePicker/DatePicker.d.ts +18 -0
  16. package/dist/components/DatePicker/calendar-utils.d.ts +30 -0
  17. package/dist/components/Dropdown/Dropdown.d.ts +3 -0
  18. package/dist/components/Editor/Editor.d.ts +13 -0
  19. package/dist/components/Editor/tools/format.d.ts +10 -0
  20. package/dist/components/Editor/tools/table.d.ts +7 -0
  21. package/dist/components/Editor/tools/toolbar.d.ts +9 -0
  22. package/dist/components/Editor/tools/types.d.ts +15 -0
  23. package/dist/components/FileUpload/FileUpload.d.ts +3 -0
  24. package/dist/components/Img/Img.d.ts +0 -2
  25. package/dist/components/InView/InView.d.ts +2 -17
  26. package/dist/components/Popover/Popover.d.ts +2 -12
  27. package/dist/components/Skeleton/Skeleton.d.ts +0 -8
  28. package/dist/components/Tooltip/Tooltip.d.ts +5 -1
  29. package/dist/components/index.d.ts +6 -0
  30. package/dist/components/index.js +1603 -343
  31. package/dist/components/style.css +734 -153
  32. package/dist/layout/weifuwu-layout.css +14 -0
  33. package/package.json +2 -2
@@ -1,5 +1,6 @@
1
1
  // src/client/vnode.ts
2
2
  var Fragment = /* @__PURE__ */ Symbol("Fragment");
3
+ var Portal = /* @__PURE__ */ Symbol("Portal");
3
4
  function h(type, props, ...children) {
4
5
  const p = normalizeProps(props ?? {});
5
6
  if (children.length > 0) {
@@ -16,9 +17,16 @@ function normalizeProps(props) {
16
17
  }
17
18
  return result;
18
19
  }
20
+ function createPortal(children, portalKey) {
21
+ return {
22
+ type: Portal,
23
+ props: { children, portalKey },
24
+ key: portalKey ?? void 0
25
+ };
26
+ }
19
27
 
20
28
  // src/components/Button/Button.ts
21
- var Button = (props, ctx) => {
29
+ var Button = (_init, ctx) => (props) => {
22
30
  const { variant = "primary", size = "md", block, loading, disabled, type, onClick, children } = props;
23
31
  const cls = [
24
32
  "wf-btn",
@@ -38,7 +46,7 @@ var Button = (props, ctx) => {
38
46
  };
39
47
 
40
48
  // src/components/Input/Input.ts
41
- var Input = (props) => {
49
+ var Input = (_init) => (props) => {
42
50
  const { label, type = "text", value, placeholder, required, disabled, error, hint, onInput, onChange } = props;
43
51
  const inputEl = h("input", {
44
52
  class: "wf-input",
@@ -64,7 +72,7 @@ var Input = (props) => {
64
72
  };
65
73
 
66
74
  // src/components/Textarea/Textarea.ts
67
- var Textarea = (props, _ctx) => {
75
+ var Textarea = (_init, _ctx) => (props) => {
68
76
  const { label, value, placeholder, required, disabled, error, hint, rows = 3, onInput } = props;
69
77
  const textareaEl = h("textarea", {
70
78
  class: "wf-textarea",
@@ -88,7 +96,7 @@ var Textarea = (props, _ctx) => {
88
96
  };
89
97
 
90
98
  // src/components/Select/Select.ts
91
- var Select = (props, _ctx) => {
99
+ var Select = (_init, _ctx) => (props) => {
92
100
  const { label, value, options, placeholder, required, disabled, error, onChange, children } = props;
93
101
  const optionEls = [];
94
102
  if (placeholder) {
@@ -118,7 +126,7 @@ var Select = (props, _ctx) => {
118
126
  };
119
127
 
120
128
  // src/components/Checkbox/Checkbox.ts
121
- var Checkbox = (props, _ctx) => {
129
+ var Checkbox = (_init, _ctx) => (props) => {
122
130
  const { label, checked, disabled, onChange } = props;
123
131
  const input = h("input", {
124
132
  type: "checkbox",
@@ -137,7 +145,7 @@ var Checkbox = (props, _ctx) => {
137
145
  };
138
146
 
139
147
  // src/components/Switch/Switch.ts
140
- var Switch = (props, ctx) => {
148
+ var Switch = (_init, ctx) => (props) => {
141
149
  const { label, checked, disabled, onChange } = props;
142
150
  const input = h("input", {
143
151
  type: "checkbox",
@@ -159,7 +167,7 @@ var Switch = (props, ctx) => {
159
167
  };
160
168
 
161
169
  // src/components/RadioGroup/RadioGroup.ts
162
- var RadioGroup = (props, _ctx) => {
170
+ var RadioGroup = (_init, _ctx) => (props) => {
163
171
  const { name, value, options = [], inline, onChange } = props;
164
172
  const radios = options.map((opt) => {
165
173
  const input = h("input", {
@@ -184,7 +192,7 @@ var RadioGroup = (props, _ctx) => {
184
192
  };
185
193
 
186
194
  // src/components/Table/Table.ts
187
- var Table = (props, _ctx) => {
195
+ var Table = (_init, _ctx) => (props) => {
188
196
  const { data = [], columns, onRowClick } = props;
189
197
  const headerCells = columns.map(
190
198
  (col) => h("th", {
@@ -281,69 +289,51 @@ function trapFocus(container) {
281
289
  }
282
290
 
283
291
  // 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;
292
+ var Modal = (_props, ctx) => {
293
+ let prevOpen;
294
+ ctx.ui.onmounted((el) => {
309
295
  lockScroll();
310
296
  const cleanupFocus = trapFocus(el);
311
297
  return () => {
312
298
  unlockScroll();
313
299
  cleanupFocus();
314
300
  };
315
- };
316
- const overlay = h("div", {
317
- class: "wf-modal-overlay",
318
- onClick: isClosing ? void 0 : startClose
319
301
  });
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]);
302
+ return (props) => {
303
+ const { open, title, onClose, children, footer } = props;
304
+ const ML = ctx?.i18n?.components?.Modal ?? {};
305
+ if (prevOpen !== open) {
306
+ prevOpen = open;
307
+ }
308
+ if (!open) return null;
309
+ const overlay = h("div", {
310
+ class: "wf-modal-overlay",
311
+ onClick: onClose
312
+ });
313
+ const closeBtn = h("button", {
314
+ class: "wf-modal-close",
315
+ onClick: onClose,
316
+ type: "button"
317
+ }, "\u2715");
318
+ const titleEl = title ? h("div", { class: "wf-modal-header" }, [title, closeBtn]) : null;
319
+ const bodyEl = h("div", { class: "wf-modal-body" }, children);
320
+ const footerEl = footer ? h("div", { class: "wf-modal-footer" }, footer) : null;
321
+ const content = h("div", {
322
+ class: "wf-modal-content",
323
+ onClick: (e) => e.stopPropagation()
324
+ }, [titleEl, bodyEl, footerEl].filter(Boolean));
325
+ const root = h("div", {
326
+ class: "wf-modal wf-modal--enter",
327
+ role: "dialog",
328
+ "aria-modal": "true",
329
+ "aria-label": title ?? (ML.ariaLabel ?? "\u5F39\u7A97")
330
+ }, [overlay, content]);
331
+ return createPortal(root, "modal");
332
+ };
343
333
  };
344
334
 
345
335
  // src/components/Toast/Toast.ts
346
- var Toast = (props, _ctx) => {
336
+ var Toast = (_init, ctx) => (props) => {
347
337
  const { toasts = [], onRemove } = props;
348
338
  if (toasts.length === 0) return null;
349
339
  const items = toasts.map(
@@ -356,7 +346,10 @@ var Toast = (props, _ctx) => {
356
346
  h("span", { class: "wf-toast-msg" }, t.message)
357
347
  ])
358
348
  );
359
- return h("div", { class: "wf-toast-container" }, items);
349
+ return createPortal(
350
+ h("div", { class: "wf-toast-container" }, items),
351
+ "toast"
352
+ );
360
353
  };
361
354
  function iconFor(type) {
362
355
  switch (type) {
@@ -372,7 +365,7 @@ function iconFor(type) {
372
365
  }
373
366
 
374
367
  // src/components/Alert/Alert.ts
375
- var Alert = (props, _ctx) => {
368
+ var Alert = (_init, _ctx) => (props) => {
376
369
  const { variant = "info", closable, onClose, children } = props;
377
370
  if (!children) return null;
378
371
  const icon = h("span", { class: "wf-alert-icon" }, iconFor2(variant));
@@ -394,7 +387,7 @@ function iconFor2(variant) {
394
387
  }
395
388
 
396
389
  // src/components/Loading/Loading.ts
397
- var Loading = (props, _ctx) => {
390
+ var Loading = (_init, _ctx) => (props) => {
398
391
  const { text = "\u52A0\u8F7D\u4E2D..." } = props;
399
392
  return h("div", { class: "wf-loading", role: "status", "aria-live": "polite" }, [
400
393
  h("div", { class: "wf-loading-spinner" }),
@@ -403,7 +396,7 @@ var Loading = (props, _ctx) => {
403
396
  };
404
397
 
405
398
  // src/components/EmptyState/EmptyState.ts
406
- var EmptyState = (props, _ctx) => {
399
+ var EmptyState = (_init, _ctx) => (props) => {
407
400
  const { icon = "\u{1F4E6}", text = "\u6682\u65E0\u6570\u636E", hint, children } = props;
408
401
  const parts = [
409
402
  h("div", { class: "wf-empty-icon" }, icon),
@@ -415,7 +408,7 @@ var EmptyState = (props, _ctx) => {
415
408
  };
416
409
 
417
410
  // src/components/Tabs/Tabs.ts
418
- var Tabs = (props, _ctx) => {
411
+ var Tabs = (_init, _ctx) => (props) => {
419
412
  const { items = [], active, onChange } = props;
420
413
  if (items.length === 0) return null;
421
414
  const activeKey = active ?? items[0].key;
@@ -437,26 +430,42 @@ var Tabs = (props, _ctx) => {
437
430
  };
438
431
 
439
432
  // 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));
433
+ var Dropdown = (_init, ctx) => {
434
+ let wrapEl;
435
+ ctx.ui.onmounted((el) => {
436
+ wrapEl = el;
437
+ });
438
+ return (props) => {
439
+ const { trigger, items = [], open } = props;
440
+ const pos = (() => {
441
+ if (!open) return { top: 0, left: 0 };
442
+ if (!wrapEl) return { top: 0, left: 0 };
443
+ const r = wrapEl.getBoundingClientRect();
444
+ return { top: r.bottom + 4, left: r.left };
445
+ })();
446
+ const menuItems = items.map(
447
+ (item, i) => h("button", {
448
+ class: `wf-dropdown-item${item.variant === "danger" ? " wf-dropdown-item--danger" : ""}`,
449
+ key: item.value ?? i,
450
+ disabled: item.disabled || void 0,
451
+ role: "menuitem",
452
+ onClick: item.onClick
453
+ }, item.label)
454
+ );
455
+ const menu = open ? h("div", {
456
+ class: "wf-dropdown-menu",
457
+ role: "menu",
458
+ style: { top: pos.top, left: pos.left }
459
+ }, menuItems) : null;
460
+ const portalContent = open ? createPortal(menu, "dropdown") : null;
461
+ return h("div", {
462
+ class: `wf-dropdown${open ? " wf-dropdown--open" : ""}`
463
+ }, [trigger, portalContent].filter(Boolean));
464
+ };
456
465
  };
457
466
 
458
467
  // src/components/Pagination/Pagination.ts
459
- var Pagination = (props, ctx) => {
468
+ var Pagination = (_init, ctx) => (props) => {
460
469
  const { total, page = 1, pageSize = 20, onChange } = props;
461
470
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
462
471
  if (totalPages <= 1) return null;
@@ -499,7 +508,7 @@ function getPageRange(current, total) {
499
508
  }
500
509
 
501
510
  // src/components/Card/Card.ts
502
- var Card = (props, _ctx) => {
511
+ var Card = (_init, _ctx) => (props) => {
503
512
  const { variant = "default", padding = "md", clickable, onClick, children } = props;
504
513
  const cls = [
505
514
  "wf-card",
@@ -511,7 +520,7 @@ var Card = (props, _ctx) => {
511
520
  };
512
521
 
513
522
  // src/components/Badge/Badge.ts
514
- var Badge = (props, _ctx) => {
523
+ var Badge = (_init, _ctx) => (props) => {
515
524
  const { variant = "default", dot, children } = props;
516
525
  if (dot) {
517
526
  return h("span", { class: `wf-badge-dot wf-badge-dot--${variant}` });
@@ -526,7 +535,7 @@ function hashColor(name) {
526
535
  for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);
527
536
  return COLORS[Math.abs(hash) % COLORS.length];
528
537
  }
529
- var Avatar = (props, _ctx) => {
538
+ var Avatar = (_init, _ctx) => (props) => {
530
539
  const { name = "", src, size = "md" } = props;
531
540
  const initial = name.trim()[0]?.toUpperCase() ?? "?";
532
541
  if (src) {
@@ -543,7 +552,7 @@ var Avatar = (props, _ctx) => {
543
552
  };
544
553
 
545
554
  // src/components/Tag/Tag.ts
546
- var Tag = (props, _ctx) => {
555
+ var Tag = (_init, _ctx) => (props) => {
547
556
  const { closable, onClose, variant = "default", children } = props;
548
557
  const closeBtn = closable ? h("button", { class: "wf-tag-close", onClick: onClose, type: "button" }, "\u2715") : null;
549
558
  return h("span", { class: `wf-tag wf-tag--${variant}` }, [
@@ -553,7 +562,7 @@ var Tag = (props, _ctx) => {
553
562
  };
554
563
 
555
564
  // src/components/StatCard/StatCard.ts
556
- var StatCard = (props, _ctx) => {
565
+ var StatCard = (_init, _ctx) => (props) => {
557
566
  const { label, value, trend, trendLabel, icon } = props;
558
567
  const children = [];
559
568
  if (icon) children.push(h("div", { class: "wf-stat-icon" }, icon));
@@ -571,7 +580,7 @@ var StatCard = (props, _ctx) => {
571
580
  };
572
581
 
573
582
  // src/components/Steps/Steps.ts
574
- var Steps = (props, _ctx) => {
583
+ var Steps = (_init, _ctx) => (props) => {
575
584
  const { items = [], active, current = 0 } = props;
576
585
  const activeKey = active ?? items[current]?.key;
577
586
  const steps = items.map((item, i) => {
@@ -598,7 +607,7 @@ var Steps = (props, _ctx) => {
598
607
  };
599
608
 
600
609
  // src/components/Form/Form.ts
601
- var Form = (props, _ctx) => {
610
+ var Form = (_init, _ctx) => (props) => {
602
611
  const { onSubmit, children } = props;
603
612
  const handleSubmit = (e) => {
604
613
  e.preventDefault();
@@ -611,7 +620,7 @@ var Form = (props, _ctx) => {
611
620
  };
612
621
 
613
622
  // src/components/Field/Field.ts
614
- var Field = (props, _ctx) => {
623
+ var Field = (_init, _ctx) => (props) => {
615
624
  const { label, required, error, hint, children } = props;
616
625
  const parts = [];
617
626
  if (label) {
@@ -626,7 +635,7 @@ var Field = (props, _ctx) => {
626
635
  };
627
636
 
628
637
  // src/components/Slider/Slider.ts
629
- var Slider = (props, _ctx) => {
638
+ var Slider = (_init, _ctx) => (props) => {
630
639
  const { label, value = 0, min = 0, max = 100, step = 1, onChange } = props;
631
640
  const numVal = Number(value);
632
641
  const input = h("input", {
@@ -647,7 +656,7 @@ var Slider = (props, _ctx) => {
647
656
  };
648
657
 
649
658
  // src/components/SearchInput/SearchInput.ts
650
- var SearchInput = (props, _ctx) => {
659
+ var SearchInput = (_init, _ctx) => (props) => {
651
660
  const { value = "", placeholder = "\u641C\u7D22...", onInput, onClear } = props;
652
661
  const clearBtn = value && onClear ? h("button", {
653
662
  class: "wf-search-clear",
@@ -669,7 +678,7 @@ var SearchInput = (props, _ctx) => {
669
678
  };
670
679
 
671
680
  // src/components/ProgressBar/ProgressBar.ts
672
- var ProgressBar = (props, ctx) => {
681
+ var ProgressBar = (_init, ctx) => (props) => {
673
682
  const { value = 0, max = 100, label, showValue } = props;
674
683
  const pct = Math.min(100, Math.max(0, value / max * 100));
675
684
  const PBL = ctx?.i18n?.components?.ProgressBar ?? {};
@@ -695,7 +704,7 @@ var ProgressBar = (props, ctx) => {
695
704
  };
696
705
 
697
706
  // src/components/Accordion/Accordion.ts
698
- var Accordion = (props, _ctx) => {
707
+ var Accordion = (_init, _ctx) => (props) => {
699
708
  const { items = [], multiple } = props;
700
709
  if (items.length === 0) return null;
701
710
  const panels = items.map(
@@ -708,7 +717,7 @@ var Accordion = (props, _ctx) => {
708
717
  };
709
718
 
710
719
  // src/components/PageHeader/PageHeader.ts
711
- var PageHeader = (props, _ctx) => {
720
+ var PageHeader = (_init, _ctx) => (props) => {
712
721
  const { title, sub, children } = props;
713
722
  return h("div", { class: "wf-page-head" }, [
714
723
  h("div", { class: "wf-page-head-left" }, [
@@ -720,7 +729,7 @@ var PageHeader = (props, _ctx) => {
720
729
  };
721
730
 
722
731
  // src/components/Breadcrumb/Breadcrumb.ts
723
- var Breadcrumb = (props, ctx) => {
732
+ var Breadcrumb = (_init, _ctx) => (props) => {
724
733
  const { items } = props;
725
734
  const children = items.flatMap((item, i) => {
726
735
  const isLast = i === items.length - 1;
@@ -728,12 +737,12 @@ var Breadcrumb = (props, ctx) => {
728
737
  if (isLast) return el;
729
738
  return [el, h("span", { class: "wf-breadcrumb-sep", "aria-hidden": "true" }, "/")];
730
739
  });
731
- const BL = ctx?.i18n?.components?.Breadcrumb ?? {};
740
+ const BL = _ctx?.i18n?.components?.Breadcrumb ?? {};
732
741
  return h("nav", { class: "wf-breadcrumb", "aria-label": BL.ariaLabel ?? "\u9762\u5305\u5C51" }, children);
733
742
  };
734
743
 
735
744
  // src/components/Divider/Divider.ts
736
- var Divider = (props, _ctx) => {
745
+ var Divider = (_init, _ctx) => (props) => {
737
746
  const { vertical, children } = props;
738
747
  if (vertical) {
739
748
  return h("div", { class: "wf-divider wf-divider--vertical", role: "separator" });
@@ -752,238 +761,266 @@ function formatSize(bytes) {
752
761
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
753
762
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
754
763
  }
755
- var FileUpload = (props, ctx) => {
756
- const { accept, multiple, maxSize, disabled, error, hint, value, onChange, children } = props;
764
+ var FileUpload = (_init, ctx) => {
757
765
  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")
766
+ return (props) => {
767
+ const { accept, multiple, maxSize, disabled, error, hint, value, onChange, children } = props;
768
+ const files = value ?? [];
769
+ const handleChange = (e) => {
770
+ const input = e.target;
771
+ const selected = Array.from(input.files ?? []);
772
+ if (maxSize) {
773
+ const oversized = selected.filter((f) => f.size > maxSize);
774
+ if (oversized.length > 0) return;
775
+ }
776
+ onChange?.(selected);
777
+ input.value = "";
778
+ };
779
+ const dragRef = (el) => {
780
+ if (!el || disabled) return;
781
+ const onDrop = (e) => {
782
+ e.preventDefault();
783
+ el.classList.remove("wf-upload-zone--drag");
784
+ if (disabled) return;
785
+ const dropped = Array.from(e.dataTransfer?.files ?? []);
786
+ if (maxSize) {
787
+ const oversized = dropped.filter((f) => f.size > maxSize);
788
+ if (oversized.length > 0) return;
789
+ }
790
+ onChange?.(dropped);
791
+ };
792
+ const onDragOver = (e) => {
793
+ e.preventDefault();
794
+ el.classList.add("wf-upload-zone--drag");
795
+ };
796
+ const onDragLeave = () => el.classList.remove("wf-upload-zone--drag");
797
+ el.addEventListener("drop", onDrop);
798
+ el.addEventListener("dragover", onDragOver);
799
+ el.addEventListener("dragleave", onDragLeave);
800
+ return () => {
801
+ el.removeEventListener("drop", onDrop);
802
+ el.removeEventListener("dragover", onDragOver);
803
+ el.removeEventListener("dragleave", onDragLeave);
804
+ };
805
+ };
806
+ const handleRemove = (i) => {
807
+ const updated = files.filter((_, idx) => idx !== i);
808
+ onChange?.(updated);
809
+ };
810
+ const inputEl = h("input", {
811
+ type: "file",
812
+ class: "wf-upload-input",
813
+ accept: accept || void 0,
814
+ multiple: multiple || void 0,
815
+ disabled: disabled || void 0,
816
+ onChange: handleChange,
817
+ style: { display: "none" }
818
+ });
819
+ const dropZone = h("div", {
820
+ class: `wf-upload-zone${disabled ? " wf-upload-zone--disabled" : ""}${error ? " wf-upload-zone--err" : ""}`,
821
+ onClick: disabled ? void 0 : () => {
822
+ const input = document.querySelector(".wf-upload-input");
823
+ input?.click();
824
+ },
825
+ ref: dragRef
826
+ }, children ?? h("div", { class: "wf-upload-placeholder" }, [
827
+ h("span", { class: "wf-upload-icon" }, "\u{1F4C1}"),
828
+ h("span", { class: "wf-upload-text" }, FL.placeholder ?? "\u70B9\u51FB\u6216\u62D6\u62FD\u4E0A\u4F20\u6587\u4EF6"),
829
+ accept ? h("span", { class: "wf-upload-hint" }, `${FL.supportedFormats ?? "\u652F\u6301\u683C\u5F0F: "}${accept}`) : null,
830
+ maxSize ? h("span", { class: "wf-upload-hint" }, `${FL.maxSize ?? "\u6700\u5927 "}${formatSize(maxSize)}`) : null
831
+ ].filter(Boolean)));
832
+ const fileList = files.length > 0 ? h(
833
+ "ul",
834
+ { class: "wf-upload-list" },
835
+ files.map(
836
+ (f, i) => h(
837
+ "li",
838
+ { class: "wf-upload-item", key: f.name + f.size },
839
+ h("span", { class: "wf-upload-item-info" }, [
840
+ h("span", { class: "wf-upload-item-name" }, f.name),
841
+ h("span", { class: "wf-upload-item-size" }, formatSize(f.size))
842
+ ]),
843
+ h("button", {
844
+ class: "wf-upload-item-remove",
845
+ "aria-label": `${FL.remove ?? "\u5220\u9664"} ${f.name}`,
846
+ onClick: () => handleRemove(i)
847
+ }, "\u2715")
848
+ )
832
849
  )
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);
850
+ ) : null;
851
+ const parts = [inputEl, dropZone, fileList];
852
+ if (error) parts.push(h("div", { class: "wf-upload-err" }, error));
853
+ if (hint && !error) parts.push(h("div", { class: "wf-upload-hint" }, hint));
854
+ return h("div", { class: "wf-upload" }, parts);
855
+ };
839
856
  };
840
857
 
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;
858
+ // src/client/popup.ts
859
+ function computeFixedPos(el, placement = "bottom", gap = 6, center = true) {
860
+ const rect = el.getBoundingClientRect();
861
+ switch (placement) {
862
+ case "bottom":
863
+ return {
864
+ top: rect.bottom + gap,
865
+ left: center ? rect.left + rect.width / 2 : rect.left
866
+ };
867
+ case "top":
868
+ return {
869
+ top: rect.top - gap,
870
+ left: center ? rect.left + rect.width / 2 : rect.left
871
+ };
872
+ case "left":
873
+ return {
874
+ top: center ? rect.top + rect.height / 2 : rect.top,
875
+ left: rect.left - gap
876
+ };
877
+ case "right":
878
+ return {
879
+ top: center ? rect.top + rect.height / 2 : rect.top,
880
+ left: rect.right + gap
881
+ };
847
882
  }
848
- const show = () => {
849
- $.show = true;
850
- };
851
- const hide = () => {
852
- $.show = false;
883
+ }
884
+
885
+ // src/components/Tooltip/Tooltip.ts
886
+ var Tooltip = (_props, ctx) => {
887
+ let show = false;
888
+ let pos = { top: 0, left: 0 };
889
+ return (props) => {
890
+ const { content, position = "top", children, disabled } = props;
891
+ const showe = (e) => {
892
+ pos = computeFixedPos(e.currentTarget, position, 6, true);
893
+ show = true;
894
+ ctx.ui.render();
895
+ };
896
+ const hide = () => {
897
+ show = false;
898
+ ctx.ui.render();
899
+ };
900
+ const p = pos;
901
+ const tip = !disabled ? h("div", {
902
+ class: `wf-tooltip wf-tooltip--${position}${show ? "" : " wf-tooltip--hidden"}`,
903
+ style: { top: p.top, left: p.left },
904
+ role: "tooltip"
905
+ }, [h("div", { class: "wf-tooltip-arrow" }), h("div", { class: "wf-tooltip-content" }, content)]) : null;
906
+ const portalContent = !disabled ? createPortal(tip, "tooltip") : null;
907
+ return h("div", {
908
+ class: "wf-tooltip-wrap",
909
+ onMouseEnter: showe,
910
+ onMouseLeave: hide,
911
+ onFocus: showe,
912
+ onBlur: hide
913
+ }, [children, portalContent].filter(Boolean));
853
914
  };
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
915
  };
869
916
 
870
917
  // 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;
918
+ var Drawer = (_props, ctx) => {
919
+ let prevOpen;
920
+ ctx.ui.onmounted((el) => {
896
921
  lockScroll();
897
922
  const cleanupFocus = trapFocus(el);
898
923
  return () => {
899
924
  unlockScroll();
900
925
  cleanupFocus();
901
926
  };
902
- };
903
- const overlay = h("div", {
904
- class: "wf-drawer-overlay",
905
- onClick: isClosing ? void 0 : startClose
906
927
  });
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]);
928
+ return (props) => {
929
+ const { open, title, position = "right", onClose, children, footer } = props;
930
+ const DL = ctx?.i18n?.components?.Drawer ?? {};
931
+ if (prevOpen !== open) {
932
+ prevOpen = open;
933
+ }
934
+ if (!open) return null;
935
+ const overlay = h("div", {
936
+ class: "wf-drawer-overlay",
937
+ onClick: onClose
938
+ });
939
+ const closeBtn = h("button", {
940
+ class: "wf-drawer-close",
941
+ onClick: onClose,
942
+ type: "button",
943
+ "aria-label": "\u5173\u95ED"
944
+ }, "\u2715");
945
+ const titleEl = title ? h("div", { class: "wf-drawer-header" }, [title, closeBtn]) : null;
946
+ const bodyEl = h("div", { class: "wf-drawer-body" }, children);
947
+ const footerEl = footer ? h("div", { class: "wf-drawer-footer" }, footer) : null;
948
+ const panel = h("div", {
949
+ class: `wf-drawer-panel wf-drawer-panel--${position}`,
950
+ onClick: (e) => e.stopPropagation()
951
+ }, [titleEl, bodyEl, footerEl].filter(Boolean));
952
+ const root = h("div", {
953
+ class: `wf-drawer wf-drawer--${position} wf-drawer--enter`,
954
+ role: "dialog",
955
+ "aria-modal": "true",
956
+ "aria-label": title ?? (DL.ariaLabel ?? "\u4FA7\u8FB9\u9762\u677F")
957
+ }, [overlay, panel]);
958
+ return createPortal(root, "drawer");
959
+ };
931
960
  };
932
961
 
933
962
  // 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);
963
+ var Popover = (_props, ctx) => {
964
+ let show = false;
965
+ let pos = { top: 0, left: 0 };
966
+ return (props) => {
967
+ const { content, trigger = "click", position = "bottom", open, onOpenChange, disabled, children } = props;
968
+ const isOpen = open !== void 0 ? open : show;
969
+ const setOpen = (v) => {
970
+ if (open === void 0) {
971
+ show = v;
972
+ ctx.ui.render();
973
+ }
974
+ onOpenChange?.(v);
975
+ };
976
+ const updatePos = (e) => {
977
+ pos = computeFixedPos(e.currentTarget, position, 6, true);
978
+ ctx.ui.render();
979
+ };
980
+ const onClick = trigger === "click" && !disabled ? (e) => {
981
+ updatePos(e);
982
+ setOpen(!isOpen);
983
+ } : void 0;
984
+ const hoverProps = {};
985
+ if (trigger === "hover" && !disabled) {
986
+ hoverProps.onMouseEnter = (e) => {
987
+ updatePos(e);
988
+ setOpen(true);
989
+ };
990
+ hoverProps.onMouseLeave = () => setOpen(false);
991
+ hoverProps.onFocus = (e) => {
992
+ updatePos(e);
993
+ setOpen(true);
994
+ };
995
+ hoverProps.onBlur = () => setOpen(false);
996
+ }
997
+ const p = pos;
998
+ const overlay = isOpen && trigger === "click" ? h("div", {
999
+ class: "wf-popover-overlay",
1000
+ onMouseDown: (e) => {
1001
+ e.stopPropagation();
1002
+ setOpen(false);
1003
+ }
1004
+ }) : null;
1005
+ const popover = isOpen ? h("div", {
1006
+ class: "wf-popover wf-popover--enter",
1007
+ style: { top: p.top, left: p.left },
1008
+ role: "tooltip"
1009
+ }, [
1010
+ h("div", { class: "wf-popover-arrow" }),
1011
+ h("div", { class: "wf-popover-content" }, content)
1012
+ ]) : null;
1013
+ const portalContent = isOpen ? createPortal([overlay, popover].filter(Boolean), "popover") : null;
1014
+ return h("div", {
1015
+ class: `wf-popover-wrap${isOpen ? " wf-popover-wrap--open" : ""}`,
1016
+ ...hoverProps,
1017
+ onClick
1018
+ }, [children, portalContent].filter(Boolean));
952
1019
  };
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
1020
  };
984
1021
 
985
1022
  // src/components/Skeleton/Skeleton.ts
986
- var Skeleton = (props) => {
1023
+ var Skeleton = (_init) => (props) => {
987
1024
  const { variant = "text", lines = 1, width, height, className } = props;
988
1025
  const style = {};
989
1026
  if (width !== void 0) style.width = typeof width === "number" ? `${width}px` : width;
@@ -1004,7 +1041,7 @@ var Skeleton = (props) => {
1004
1041
  };
1005
1042
 
1006
1043
  // src/components/Img/Img.ts
1007
- var Img = (props) => {
1044
+ var Img = (_init) => (props) => {
1008
1045
  const { src, alt = "", fallback, loading, width, height, className, style } = props;
1009
1046
  const imgProps = {
1010
1047
  class: ["wf-image", className].filter(Boolean).join(" "),
@@ -1025,47 +1062,1267 @@ var Img = (props) => {
1025
1062
  };
1026
1063
 
1027
1064
  // src/components/InView/InView.ts
1028
- var InView = (props, ctx) => {
1029
- const {
1030
- once = true,
1031
- threshold = 0,
1032
- rootMargin = "0px",
1033
- placeholder,
1034
- onEnter,
1035
- children
1036
- } = props;
1037
- const $ = ctx.ui.$;
1038
- if (!ctx.ui.ready) {
1039
- $.inView = false;
1065
+ var InView = (_props, ctx) => {
1066
+ let inView = false;
1067
+ let entered = false;
1068
+ let io;
1069
+ ctx.ui.onmounted((el) => {
1070
+ const sentinel = el.querySelector(".wf-inview-pending");
1071
+ if (!sentinel) return;
1072
+ io = new IntersectionObserver((entries) => {
1073
+ if (entries[0]?.isIntersecting) {
1074
+ inView = true;
1075
+ ctx.ui.render();
1076
+ }
1077
+ }, { threshold: _props.threshold ?? 0, rootMargin: _props.rootMargin ?? "0px" });
1078
+ io.observe(sentinel);
1079
+ return () => {
1080
+ io?.disconnect();
1081
+ };
1082
+ });
1083
+ return (props) => {
1084
+ if (inView) {
1085
+ if (!entered) {
1086
+ entered = true;
1087
+ const once = props.once !== false;
1088
+ if (once) io?.disconnect();
1089
+ props.onEnter?.();
1090
+ }
1091
+ return h("div", { class: "wf-inview wf-inview--loaded" }, props.children);
1092
+ }
1093
+ const placeholderEl = props.placeholder !== void 0 ? props.placeholder : h("div", { class: "wf-inview-placeholder" });
1094
+ return h("div", {
1095
+ class: "wf-inview wf-inview--pending"
1096
+ }, [
1097
+ h("div", { class: "wf-inview-pending", style: { width: "1px", height: "1px", opacity: 0, pointerEvents: "none" } }),
1098
+ placeholderEl
1099
+ ]);
1100
+ };
1101
+ };
1102
+
1103
+ // src/components/DatePicker/calendar-utils.ts
1104
+ var WEEKDAYS = ["\u65E5", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D"];
1105
+ function getWeekdays() {
1106
+ return WEEKDAYS;
1107
+ }
1108
+ function getDaysInMonth(year, month) {
1109
+ return new Date(year, month + 1, 0).getDate();
1110
+ }
1111
+ function getFirstDayOfMonth(year, month) {
1112
+ return new Date(year, month, 1).getDay();
1113
+ }
1114
+ function getCalendarGrid(year, month) {
1115
+ const days = [];
1116
+ const totalDays = getDaysInMonth(year, month);
1117
+ const firstDay = getFirstDayOfMonth(year, month);
1118
+ const prevMonth = month === 0 ? 11 : month - 1;
1119
+ const prevYear = month === 0 ? year - 1 : year;
1120
+ const prevMonthDays = getDaysInMonth(prevYear, prevMonth);
1121
+ const today = /* @__PURE__ */ new Date();
1122
+ let row = [];
1123
+ for (let i = firstDay - 1; i >= 0; i--) {
1124
+ const d = prevMonthDays - i;
1125
+ row.push({
1126
+ year: prevYear,
1127
+ month: prevMonth,
1128
+ day: d,
1129
+ isOtherMonth: true,
1130
+ isToday: prevYear === today.getFullYear() && prevMonth === today.getMonth() && d === today.getDate()
1131
+ });
1132
+ }
1133
+ for (let d = 1; d <= totalDays; d++) {
1134
+ row.push({
1135
+ year,
1136
+ month,
1137
+ day: d,
1138
+ isOtherMonth: false,
1139
+ isToday: year === today.getFullYear() && month === today.getMonth() && d === today.getDate()
1140
+ });
1141
+ if (row.length === 7) {
1142
+ days.push(row);
1143
+ row = [];
1144
+ }
1145
+ }
1146
+ const nextMonth = month === 11 ? 0 : month + 1;
1147
+ const nextYear = month === 11 ? year + 1 : year;
1148
+ let nextDay = 1;
1149
+ while (days.length < 6) {
1150
+ while (row.length < 7) {
1151
+ row.push({
1152
+ year: nextYear,
1153
+ month: nextMonth,
1154
+ day: nextDay++,
1155
+ isOtherMonth: true,
1156
+ isToday: nextYear === today.getFullYear() && nextMonth === today.getMonth() && nextDay - 1 === today.getDate()
1157
+ });
1158
+ }
1159
+ days.push(row);
1160
+ row = [];
1040
1161
  }
1041
- const sentinelRef = (el) => {
1042
- if (!el) return;
1043
- if ($.inView && once) return;
1044
- const io = new IntersectionObserver(
1045
- (entries) => {
1046
- if (entries[0]?.isIntersecting) {
1047
- $.inView = true;
1048
- onEnter?.();
1049
- if (once) io.disconnect();
1050
- } else if (!once) {
1051
- $.inView = false;
1162
+ return days;
1163
+ }
1164
+ function formatDate(year, month, day) {
1165
+ return `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
1166
+ }
1167
+ function formatTime(hour, minute) {
1168
+ return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
1169
+ }
1170
+ function formatDateTime(year, month, day, hour, minute) {
1171
+ return `${formatDate(year, month, day)} ${formatTime(hour, minute)}`;
1172
+ }
1173
+ function hourOptions() {
1174
+ return Array.from({ length: 24 }, (_, i) => i);
1175
+ }
1176
+ function minuteOptions() {
1177
+ return Array.from({ length: 12 }, (_, i) => i * 5);
1178
+ }
1179
+
1180
+ // src/components/DatePicker/DatePicker.ts
1181
+ var DatePicker = (_props, ctx) => {
1182
+ const L = ctx?.i18n?.components?.DatePicker ?? {};
1183
+ let show = false;
1184
+ let selectedValue = "";
1185
+ const now = /* @__PURE__ */ new Date();
1186
+ let viewYear = now.getFullYear();
1187
+ let viewMonth = now.getMonth();
1188
+ let hour = now.getHours();
1189
+ let minute = Math.round(now.getMinutes() / 5) * 5;
1190
+ let selYear = now.getFullYear();
1191
+ let selMonth = now.getMonth();
1192
+ let selDay = now.getDate();
1193
+ let rangeStart = null;
1194
+ let rangeEnd = null;
1195
+ let inputEl;
1196
+ ctx.ui.onmounted((el) => {
1197
+ inputEl = el.querySelector(".wf-datepicker-input");
1198
+ });
1199
+ return (props) => {
1200
+ const { mode = "date", value, onChange, placeholder = L.placeholder ?? "\u9009\u62E9\u65E5\u671F", disabled } = props;
1201
+ const isOpen = show;
1202
+ const setOpen = (v) => {
1203
+ show = v;
1204
+ ctx.ui.render();
1205
+ };
1206
+ const toggle = (e) => {
1207
+ if (disabled) return;
1208
+ setOpen(!show);
1209
+ };
1210
+ const pos = (() => {
1211
+ if (!isOpen) return { top: 0, left: 0 };
1212
+ if (!inputEl) return { top: 0, left: 0 };
1213
+ const r = inputEl.getBoundingClientRect();
1214
+ return { top: r.bottom + 4, left: r.left, width: r.width };
1215
+ })();
1216
+ const selectDate = (day) => {
1217
+ if (mode === "datetime") {
1218
+ selYear = day.year;
1219
+ selMonth = day.month;
1220
+ selDay = day.day;
1221
+ viewYear = day.year;
1222
+ viewMonth = day.month;
1223
+ ctx.ui.render();
1224
+ } else if (mode === "range") {
1225
+ if (!rangeStart || rangeStart && rangeEnd) {
1226
+ rangeStart = formatDate(day.year, day.month, day.day);
1227
+ rangeEnd = null;
1228
+ ctx.ui.render();
1229
+ } else {
1230
+ rangeEnd = formatDate(day.year, day.month, day.day);
1231
+ const ds = rangeStart < rangeEnd ? rangeStart : rangeEnd;
1232
+ const de = rangeStart < rangeEnd ? rangeEnd : rangeStart;
1233
+ selectedValue = `${ds} ~ ${de}`;
1234
+ onChange?.(selectedValue);
1235
+ setOpen(false);
1052
1236
  }
1053
- },
1054
- { threshold, rootMargin }
1237
+ } else {
1238
+ selectedValue = formatDate(day.year, day.month, day.day);
1239
+ onChange?.(selectedValue);
1240
+ setOpen(false);
1241
+ }
1242
+ };
1243
+ const prevMonth = () => {
1244
+ if (viewMonth === 0) {
1245
+ viewYear--;
1246
+ viewMonth = 11;
1247
+ } else viewMonth--;
1248
+ ctx.ui.render();
1249
+ };
1250
+ const nextMonth = () => {
1251
+ if (viewMonth === 11) {
1252
+ viewYear++;
1253
+ viewMonth = 0;
1254
+ } else viewMonth++;
1255
+ ctx.ui.render();
1256
+ };
1257
+ const confirmTime = () => {
1258
+ selectedValue = formatTime(hour, minute);
1259
+ onChange?.(selectedValue);
1260
+ setOpen(false);
1261
+ };
1262
+ const confirmDateTime = () => {
1263
+ selectedValue = formatDateTime(selYear, selMonth, selDay, hour, minute);
1264
+ onChange?.(selectedValue);
1265
+ setOpen(false);
1266
+ };
1267
+ const grid = getCalendarGrid(viewYear, viewMonth);
1268
+ const weekdays = [L.w0, L.w1, L.w2, L.w3, L.w4, L.w5, L.w6].some((v) => v) ? [L.w0, L.w1, L.w2, L.w3, L.w4, L.w5, L.w6] : getWeekdays();
1269
+ const headerBtn = (label, onClick) => h("button", { class: "wf-datepicker-header-btn", type: "button", onClick }, label);
1270
+ const header = h("div", { class: "wf-datepicker-header" }, [
1271
+ headerBtn("\u2039", prevMonth),
1272
+ h("span", { class: "wf-datepicker-header-title" }, `${viewYear}\u5E74${viewMonth + 1}\u6708`),
1273
+ headerBtn("\u203A", nextMonth)
1274
+ ]);
1275
+ const weekdayRow = h(
1276
+ "div",
1277
+ { class: "wf-datepicker-weekdays" },
1278
+ weekdays.map((w) => h("span", { class: "wf-datepicker-weekday" }, w))
1055
1279
  );
1056
- io.observe(el);
1057
- return () => {
1058
- io.disconnect();
1280
+ const gridRows = grid.map((row, ri) => h(
1281
+ "div",
1282
+ { class: "wf-datepicker-grid", key: `row-${ri}` },
1283
+ row.map((cell, ci) => {
1284
+ const classes = ["wf-datepicker-cell"];
1285
+ if (cell.isOtherMonth) classes.push("wf-datepicker-cell--other-month");
1286
+ if (cell.isToday) classes.push("wf-datepicker-cell--today");
1287
+ const dateStr = formatDate(cell.year, cell.month, cell.day);
1288
+ if (mode === "range") {
1289
+ if (dateStr === rangeStart || dateStr === rangeEnd) classes.push("wf-datepicker-cell--range-edge");
1290
+ else if (rangeStart && rangeEnd && dateStr > rangeStart && dateStr < rangeEnd) classes.push("wf-datepicker-cell--in-range");
1291
+ } else if (mode === "datetime") {
1292
+ if (selYear === cell.year && selMonth === cell.month && selDay === cell.day) classes.push("wf-datepicker-cell--selected");
1293
+ } else {
1294
+ if (dateStr === selectedValue) classes.push("wf-datepicker-cell--selected");
1295
+ }
1296
+ return h("button", {
1297
+ class: classes.join(" "),
1298
+ key: `${cell.year}-${cell.month}-${cell.day}`,
1299
+ type: "button",
1300
+ onClick: () => selectDate(cell)
1301
+ }, String(cell.day));
1302
+ })
1303
+ ));
1304
+ const calendarPanel = h("div", { class: "wf-datepicker-range-panel" }, [
1305
+ header,
1306
+ weekdayRow,
1307
+ ...gridRows
1308
+ ]);
1309
+ const handleKeyDown = (e) => {
1310
+ if (e.key === "Escape") setOpen(false);
1311
+ };
1312
+ const overlay = h("div", { class: "wf-datepicker-overlay", onMouseDown: () => setOpen(false) });
1313
+ let panel = null;
1314
+ if (isOpen) {
1315
+ if (mode === "time") {
1316
+ const hours = hourOptions();
1317
+ const minutes = minuteOptions();
1318
+ const timePanel = h("div", {
1319
+ style: { top: pos.top, left: pos.left, width: pos.width },
1320
+ class: "wf-time-picker",
1321
+ role: "dialog",
1322
+ onKeyDown: handleKeyDown,
1323
+ onMouseDown: (e) => e.stopPropagation()
1324
+ }, [
1325
+ h("div", { class: "wf-time-body" }, [
1326
+ h("div", { class: "wf-time-col" }, [
1327
+ h("div", { class: "wf-time-col-label" }, L.hour ?? "\u65F6"),
1328
+ h(
1329
+ "div",
1330
+ { class: "wf-time-opt-list" },
1331
+ hours.map((hv) => h("button", {
1332
+ class: `wf-time-opt${hv === hour ? " wf-time-opt--selected" : ""}`,
1333
+ type: "button",
1334
+ key: hv,
1335
+ onClick: () => {
1336
+ hour = hv;
1337
+ ctx.ui.render();
1338
+ }
1339
+ }, String(hv).padStart(2, "0")))
1340
+ )
1341
+ ]),
1342
+ h("div", { class: "wf-time-col" }, [
1343
+ h("div", { class: "wf-time-col-label" }, L.minute ?? "\u5206"),
1344
+ h(
1345
+ "div",
1346
+ { class: "wf-time-opt-list" },
1347
+ minutes.map((mv) => h("button", {
1348
+ class: `wf-time-opt${mv === minute ? " wf-time-opt--selected" : ""}`,
1349
+ type: "button",
1350
+ key: mv,
1351
+ onClick: () => {
1352
+ minute = mv;
1353
+ ctx.ui.render();
1354
+ }
1355
+ }, String(mv).padStart(2, "0")))
1356
+ )
1357
+ ])
1358
+ ]),
1359
+ h("div", { class: "wf-time-footer" }, [
1360
+ h("button", { class: "wf-datepicker-footer-btn", type: "button", onClick: () => setOpen(false) }, L.cancel ?? "\u53D6\u6D88"),
1361
+ h("button", { class: "wf-datepicker-footer-btn", type: "button", onClick: confirmTime }, L.confirm ?? "\u786E\u5B9A")
1362
+ ])
1363
+ ]);
1364
+ panel = [overlay, timePanel];
1365
+ } else if (mode === "range") {
1366
+ const nextM = viewMonth === 11 ? 0 : viewMonth + 1;
1367
+ const nextY = viewMonth === 11 ? viewYear + 1 : viewYear;
1368
+ const nextGrid = getCalendarGrid(nextY, nextM);
1369
+ const rangeWrap = h("div", {
1370
+ style: { top: pos.top, left: pos.left },
1371
+ class: "wf-datepicker-range-wrap",
1372
+ onMouseDown: (e) => e.stopPropagation()
1373
+ }, [
1374
+ h("div", { class: "wf-datepicker-range-panel" }, [
1375
+ h("div", { class: "wf-datepicker-header" }, [
1376
+ headerBtn("\u2039", prevMonth),
1377
+ h("span", { class: "wf-datepicker-header-title" }, `${viewYear}\u5E74${viewMonth + 1}\u6708`),
1378
+ h("span", { class: "wf-datepicker-header-title" })
1379
+ ]),
1380
+ weekdayRow,
1381
+ ...gridRows
1382
+ ]),
1383
+ h("div", { class: "wf-datepicker-range-panel" }, [
1384
+ h("div", { class: "wf-datepicker-header" }, [
1385
+ h("span", { class: "wf-datepicker-header-title" }),
1386
+ h("span", { class: "wf-datepicker-header-title" }, `${nextY}\u5E74${nextM + 1}\u6708`),
1387
+ headerBtn("\u203A", nextMonth)
1388
+ ]),
1389
+ h("div", { class: "wf-datepicker-weekdays" }, weekdays.map((w) => h("span", { class: "wf-datepicker-weekday" }, w))),
1390
+ ...nextGrid.map((row, ri) => h(
1391
+ "div",
1392
+ { class: "wf-datepicker-grid", key: `row-${ri}` },
1393
+ row.map((cell) => {
1394
+ const dateStr = formatDate(cell.year, cell.month, cell.day);
1395
+ const cls = ["wf-datepicker-cell"];
1396
+ if (cell.isOtherMonth) cls.push("wf-datepicker-cell--other-month");
1397
+ if (cell.isToday) cls.push("wf-datepicker-cell--today");
1398
+ if (dateStr === rangeStart || dateStr === rangeEnd) cls.push("wf-datepicker-cell--range-edge");
1399
+ else if (rangeStart && rangeEnd && dateStr > rangeStart && dateStr < rangeEnd) cls.push("wf-datepicker-cell--in-range");
1400
+ return h("button", {
1401
+ class: cls.join(" "),
1402
+ key: dateStr,
1403
+ type: "button",
1404
+ onClick: () => selectDate(cell)
1405
+ }, String(cell.day));
1406
+ })
1407
+ ))
1408
+ ])
1409
+ ]);
1410
+ panel = [overlay, rangeWrap];
1411
+ } else {
1412
+ const content = [calendarPanel];
1413
+ if (mode === "datetime") {
1414
+ content.push(h("div", { class: "wf-datetime-time" }, [
1415
+ h("span", { class: "wf-datetime-time-label" }, (L.time ?? "\u65F6\u95F4") + "\uFF1A"),
1416
+ h("div", { class: "wf-datetime-time-select" }, [
1417
+ h("select", {
1418
+ class: "wf-datetime-select",
1419
+ value: hour,
1420
+ onChange: (e) => {
1421
+ hour = parseInt(e.target.value);
1422
+ ctx.ui.render();
1423
+ }
1424
+ }, hourOptions().map((hv) => h("option", { value: hv, key: hv }, String(hv).padStart(2, "0")))),
1425
+ h("span", { class: "wf-datetime-sep" }, ":"),
1426
+ h("select", {
1427
+ class: "wf-datetime-select",
1428
+ value: minute,
1429
+ onChange: (e) => {
1430
+ minute = parseInt(e.target.value);
1431
+ ctx.ui.render();
1432
+ }
1433
+ }, minuteOptions().map((mv) => h("option", { value: mv, key: mv }, String(mv).padStart(2, "0"))))
1434
+ ])
1435
+ ]));
1436
+ content.push(h("div", { class: "wf-time-footer" }, [
1437
+ h("button", { class: "wf-datepicker-footer-btn", type: "button", onClick: confirmDateTime }, L.confirm ?? "\u786E\u5B9A")
1438
+ ]));
1439
+ }
1440
+ const dp = h("div", {
1441
+ style: { top: pos.top, left: pos.left, width: pos.width },
1442
+ class: "wf-datepicker-dropdown",
1443
+ role: "dialog",
1444
+ onKeyDown: handleKeyDown,
1445
+ onMouseDown: (e) => e.stopPropagation()
1446
+ }, content);
1447
+ panel = [overlay, dp];
1448
+ }
1449
+ }
1450
+ const portalContent = isOpen ? createPortal(panel, "dp-calendar") : null;
1451
+ const displayValue = value ?? selectedValue ?? "";
1452
+ return h("div", { class: `wf-datepicker${disabled ? " wf-datepicker--disabled" : ""}` }, [
1453
+ h("input", {
1454
+ class: "wf-datepicker-input",
1455
+ type: "text",
1456
+ placeholder,
1457
+ value: displayValue || "",
1458
+ readonly: true,
1459
+ disabled,
1460
+ onClick: toggle
1461
+ }),
1462
+ portalContent
1463
+ ].filter(Boolean));
1464
+ };
1465
+ };
1466
+
1467
+ // src/components/Chart/chart-utils.ts
1468
+ function scaleLinear(domain, range) {
1469
+ const fn = ((v) => {
1470
+ const t = (v - domain[0]) / (domain[1] - domain[0]);
1471
+ return range[0] + t * (range[1] - range[0]);
1472
+ });
1473
+ fn.domain = domain;
1474
+ fn.range = range;
1475
+ fn.invert = (v) => {
1476
+ const t = (v - range[0]) / (range[1] - range[0]);
1477
+ return domain[0] + t * (domain[1] - domain[0]);
1478
+ };
1479
+ return fn;
1480
+ }
1481
+ function linePath(data, xScale, yScale) {
1482
+ if (data.length === 0) return "";
1483
+ return data.map((d, i) => {
1484
+ const x = xScale(i);
1485
+ const y = yScale(d.value);
1486
+ return i === 0 ? `M${x},${y}` : `L${x},${y}`;
1487
+ }).join(" ");
1488
+ }
1489
+ function areaPath(data, xScale, yScale, yBase) {
1490
+ if (data.length === 0) return "";
1491
+ const pts = data.map((d, i) => {
1492
+ const x = xScale(i);
1493
+ const y = yScale(d.value);
1494
+ return `${x},${y}`;
1495
+ });
1496
+ const firstX = xScale(0);
1497
+ const lastX = xScale(data.length - 1);
1498
+ return `M${firstX},${yBase}L${pts.join("L")}L${lastX},${yBase}Z`;
1499
+ }
1500
+ function barRects(data, xScale, yScale, barWidth) {
1501
+ const bw = barWidth ?? Math.max(4, (xScale.range[1] - xScale.range[0]) / data.length * 0.6);
1502
+ return data.map((d, i) => ({
1503
+ x: xScale(i) - bw / 2,
1504
+ y: yScale(Math.max(0, d.value)),
1505
+ width: bw,
1506
+ height: Math.abs(yScale(d.value) - yScale(0)),
1507
+ color: d.color ?? getDefaultColor(i),
1508
+ label: d.label,
1509
+ value: d.value
1510
+ }));
1511
+ }
1512
+ function pieArcs(data, cx, cy, radius) {
1513
+ const total = data.reduce((s, d) => s + Math.abs(d.value), 0);
1514
+ if (total === 0) return [];
1515
+ let startAngle = -Math.PI / 2;
1516
+ return data.map((d, i) => {
1517
+ const angle = Math.abs(d.value) / total * Math.PI * 2;
1518
+ const endAngle = startAngle + angle;
1519
+ const arc = createArc(cx, cy, radius, startAngle, endAngle);
1520
+ const midAngle = startAngle + angle / 2;
1521
+ startAngle = endAngle;
1522
+ return {
1523
+ d: arc,
1524
+ color: d.color ?? getDefaultColor(i),
1525
+ label: d.label,
1526
+ value: d.value,
1527
+ centroid: {
1528
+ x: cx + Math.cos(midAngle) * radius * 0.6,
1529
+ y: cy + Math.sin(midAngle) * radius * 0.6
1530
+ }
1531
+ };
1532
+ });
1533
+ }
1534
+ function createArc(cx, cy, r, start, end) {
1535
+ const x1 = cx + r * Math.cos(start);
1536
+ const y1 = cy + r * Math.sin(start);
1537
+ const x2 = cx + r * Math.cos(end);
1538
+ const y2 = cy + r * Math.sin(end);
1539
+ const large = end - start > Math.PI ? 1 : 0;
1540
+ return `M${cx},${cy}L${x1},${y1}A${r},${r} 0 ${large} 1 ${x2},${y2}Z`;
1541
+ }
1542
+ var COLORS2 = ["#3b82f6", "#ef4444", "#22c55e", "#f59e0b", "#8b5cf6", "#ec4899", "#06b6d4", "#84cc16"];
1543
+ function getDefaultColor(index) {
1544
+ return COLORS2[index % COLORS2.length];
1545
+ }
1546
+ function getYTicks(yScale, tickCount = 5) {
1547
+ const [d0, d1] = yScale.domain;
1548
+ const step = (d1 - d0) / tickCount;
1549
+ const ticks = [];
1550
+ for (let i = 0; i <= tickCount; i++) {
1551
+ const v = d0 + step * i;
1552
+ ticks.push({ value: v, y: yScale(v), label: formatTick(v) });
1553
+ }
1554
+ return ticks;
1555
+ }
1556
+ function formatTick(v) {
1557
+ if (Math.abs(v) >= 1e6) return (v / 1e6).toFixed(1) + "M";
1558
+ if (Math.abs(v) >= 1e3) return (v / 1e3).toFixed(1) + "k";
1559
+ return String(Math.round(v));
1560
+ }
1561
+
1562
+ // src/components/Chart/Chart.ts
1563
+ var Chart = (_props, ctx) => {
1564
+ let tooltip = null;
1565
+ return (props) => {
1566
+ const { type = "line", data, options = {}, title, area, className } = props;
1567
+ const W = options.width ?? 320;
1568
+ const H = options.height ?? 200;
1569
+ const pad = options.padding ?? 32;
1570
+ const cw = W - pad * 2;
1571
+ const ch = H - pad * 2;
1572
+ const values = data.map((d) => d.value);
1573
+ const minVal = Math.min(0, ...values);
1574
+ const maxVal = Math.max(...values);
1575
+ const valRange = maxVal - minVal || 1;
1576
+ const renderLine = () => {
1577
+ const n = Math.max(1, data.length - 1);
1578
+ const xScale = scaleLinear([-0.5, n + 0.5], [0, cw]);
1579
+ const yScale = scaleLinear([minVal, maxVal], [ch, 0]);
1580
+ const ticks = getYTicks(yScale);
1581
+ const lineD = linePath(data, xScale, yScale);
1582
+ const areaD = area ? areaPath(data, xScale, yScale, yScale(0)) : null;
1583
+ const dots = data.map((d, i) => {
1584
+ const cx = xScale(i) + pad;
1585
+ const cy = yScale(d.value) + pad;
1586
+ return h("circle", {
1587
+ key: `dot-${i}`,
1588
+ cx,
1589
+ cy,
1590
+ r: 3,
1591
+ fill: d.color ?? getDefaultColor(i),
1592
+ stroke: "#fff",
1593
+ "stroke-width": 1.5,
1594
+ style: { cursor: "pointer" },
1595
+ onMouseEnter: (e) => {
1596
+ const r = e.target.getBoundingClientRect();
1597
+ tooltip = { x: r.left, y: r.top - 8, label: d.label, value: d.value };
1598
+ ctx.ui.render();
1599
+ },
1600
+ onMouseLeave: () => {
1601
+ tooltip = null;
1602
+ ctx.ui.render();
1603
+ }
1604
+ });
1605
+ });
1606
+ return h("svg", { style: { width: "100%" }, height: H, viewBox: `0 0 ${W} ${H}` }, [
1607
+ ...ticks.map((t, i) => h("g", { key: `tick-${i}` }, [
1608
+ h("line", {
1609
+ x1: pad,
1610
+ y1: t.y + pad,
1611
+ x2: W - pad,
1612
+ y2: t.y + pad,
1613
+ stroke: "#e5e7eb",
1614
+ "stroke-width": 1
1615
+ }),
1616
+ h("text", {
1617
+ x: pad - 6,
1618
+ y: t.y + pad + 4,
1619
+ "text-anchor": "end",
1620
+ fill: "#6b7280",
1621
+ "font-size": "11",
1622
+ "font-family": "var(--wf-font-sans)"
1623
+ }, t.label)
1624
+ ])),
1625
+ ...areaD ? [h("path", {
1626
+ key: "area",
1627
+ d: areaD,
1628
+ fill: "#3b82f620",
1629
+ stroke: "none",
1630
+ transform: `translate(${pad},${pad})`
1631
+ })] : [],
1632
+ h("path", {
1633
+ key: "line",
1634
+ d: lineD,
1635
+ fill: "none",
1636
+ stroke: "#3b82f6",
1637
+ "stroke-width": 2,
1638
+ "stroke-linejoin": "round",
1639
+ "stroke-linecap": "round",
1640
+ transform: `translate(${pad},${pad})`
1641
+ }),
1642
+ ...data.map((d, i) => {
1643
+ const x = xScale(i) + pad;
1644
+ return h("text", {
1645
+ key: `xlabel-${i}`,
1646
+ x,
1647
+ y: H - pad + 14,
1648
+ "text-anchor": "middle",
1649
+ fill: "#6b7280",
1650
+ "font-size": "10",
1651
+ "font-family": "var(--wf-font-sans)"
1652
+ }, d.label);
1653
+ }),
1654
+ ...dots
1655
+ ]);
1656
+ };
1657
+ const renderBar = () => {
1658
+ const n = Math.max(1, data.length - 1);
1659
+ const xScale = scaleLinear([-0.5, n + 0.5], [0, cw]);
1660
+ const yScale = scaleLinear([minVal, maxVal], [ch, 0]);
1661
+ const ticks = getYTicks(yScale);
1662
+ const rects = barRects(data, xScale, yScale);
1663
+ return h("svg", { style: { width: "100%" }, height: H, viewBox: `0 0 ${W} ${H}` }, [
1664
+ ...ticks.map((t, i) => h("g", { key: `tick-${i}` }, [
1665
+ h("line", {
1666
+ x1: pad,
1667
+ y1: t.y + pad,
1668
+ x2: W - pad,
1669
+ y2: t.y + pad,
1670
+ stroke: "#e5e7eb",
1671
+ "stroke-width": 1
1672
+ }),
1673
+ h("text", {
1674
+ x: pad - 6,
1675
+ y: t.y + pad + 4,
1676
+ "text-anchor": "end",
1677
+ fill: "#6b7280",
1678
+ "font-size": "11",
1679
+ "font-family": "var(--wf-font-sans)"
1680
+ }, t.label)
1681
+ ])),
1682
+ ...rects.map((r, i) => h("rect", {
1683
+ key: `bar-${i}`,
1684
+ x: r.x + pad,
1685
+ y: r.y + pad,
1686
+ width: r.width,
1687
+ height: r.height,
1688
+ fill: r.color,
1689
+ rx: 2,
1690
+ onMouseEnter: (e) => {
1691
+ const rect = e.target.getBoundingClientRect();
1692
+ tooltip = { x: rect.left + rect.width / 2, y: rect.top - 8, label: r.label, value: r.value };
1693
+ ctx.ui.render();
1694
+ },
1695
+ onMouseLeave: () => {
1696
+ tooltip = null;
1697
+ ctx.ui.render();
1698
+ }
1699
+ })),
1700
+ ...data.map((d, i) => {
1701
+ const x = xScale(i) + pad;
1702
+ return h("text", {
1703
+ key: `xlabel-${i}`,
1704
+ x,
1705
+ y: H - pad + 14,
1706
+ "text-anchor": "middle",
1707
+ fill: "#6b7280",
1708
+ "font-size": "10",
1709
+ "font-family": "var(--wf-font-sans)"
1710
+ }, d.label);
1711
+ })
1712
+ ]);
1059
1713
  };
1714
+ const renderPie = () => {
1715
+ const cx = W / 2;
1716
+ const cy = H / 2;
1717
+ const radius = Math.min(cw, ch) / 2 - 4;
1718
+ const arcs = pieArcs(data, cx, cy, radius);
1719
+ return h("svg", { style: { width: "100%" }, height: H, viewBox: `0 0 ${W} ${H}` }, [
1720
+ ...arcs.map((a, i) => h("g", { key: `arc-${i}` }, [
1721
+ h("path", {
1722
+ d: a.d,
1723
+ fill: a.color,
1724
+ stroke: "#fff",
1725
+ "stroke-width": 1.5,
1726
+ onMouseEnter: (e) => {
1727
+ const r = e.target.getBoundingClientRect();
1728
+ tooltip = { x: r.left + r.width / 2, y: r.top - 8, label: a.label, value: a.value };
1729
+ ctx.ui.render();
1730
+ },
1731
+ onMouseLeave: () => {
1732
+ tooltip = null;
1733
+ ctx.ui.render();
1734
+ }
1735
+ }),
1736
+ ...a.value / data.reduce((s, d) => s + Math.abs(d.value), 0) > 0.05 ? [h("text", {
1737
+ x: a.centroid.x,
1738
+ y: a.centroid.y + 3,
1739
+ "text-anchor": "middle",
1740
+ fill: "#fff",
1741
+ "font-size": "11",
1742
+ "font-weight": "bold",
1743
+ "font-family": "var(--wf-font-sans)"
1744
+ }, `${Math.round(a.value / data.reduce((s, d) => s + Math.abs(d.value), 0) * 100)}%`)] : []
1745
+ ]))
1746
+ ]);
1747
+ };
1748
+ let chartContent;
1749
+ if (type === "bar") chartContent = renderBar();
1750
+ else if (type === "pie") chartContent = renderPie();
1751
+ else chartContent = renderLine();
1752
+ const legend = data.length > 1 ? h(
1753
+ "div",
1754
+ { class: "wf-chart-legend" },
1755
+ data.map((d, i) => h("span", { class: "wf-chart-legend-item", key: `leg-${i}` }, [
1756
+ h("span", { class: "wf-chart-legend-dot", style: { background: d.color ?? getDefaultColor(i) } }),
1757
+ h("span", { class: "wf-chart-legend-label" }, d.label)
1758
+ ]))
1759
+ ) : null;
1760
+ const tip = tooltip ? h("div", {
1761
+ class: "wf-chart-tooltip",
1762
+ style: { left: tooltip.x, top: tooltip.y }
1763
+ }, [
1764
+ h("div", { class: "wf-chart-tooltip-label" }, tooltip.label),
1765
+ h("div", { class: "wf-chart-tooltip-value" }, String(tooltip.value))
1766
+ ]) : null;
1767
+ return h("div", { class: `wf-chart${className ? " " + className : ""}` }, [
1768
+ title ? h("div", { class: "wf-chart-title" }, title) : null,
1769
+ chartContent,
1770
+ legend,
1771
+ tip
1772
+ ].filter(Boolean));
1060
1773
  };
1061
- if ($.inView) {
1062
- return h("div", { class: "wf-inview wf-inview--loaded" }, children);
1774
+ };
1775
+
1776
+ // src/components/Editor/tools/format.ts
1777
+ function queryFormats() {
1778
+ const f = {};
1779
+ try {
1780
+ f.bold = document.queryCommandState("bold");
1781
+ f.italic = document.queryCommandState("italic");
1782
+ f.underline = document.queryCommandState("underline");
1783
+ const block = document.queryCommandValue("formatBlock");
1784
+ f.h1 = block === "h1" || block === "H1";
1785
+ f.h2 = block === "h2" || block === "H2";
1786
+ f.h3 = block === "h3" || block === "H3";
1787
+ f.blockquote = block === "blockquote" || block === "BLOCKQUOTE";
1788
+ f.alignLeft = document.queryCommandState("justifyLeft");
1789
+ f.alignCenter = document.queryCommandState("justifyCenter");
1790
+ f.alignRight = document.queryCommandState("justifyRight");
1791
+ } catch {
1792
+ }
1793
+ return f;
1794
+ }
1795
+ function exec(cmd, value) {
1796
+ try {
1797
+ document.execCommand(cmd, false, value);
1798
+ } catch {
1799
+ }
1800
+ }
1801
+ function execFormat(item) {
1802
+ switch (item) {
1803
+ case "bold":
1804
+ exec("bold");
1805
+ break;
1806
+ case "italic":
1807
+ exec("italic");
1808
+ break;
1809
+ case "underline":
1810
+ exec("underline");
1811
+ break;
1812
+ case "h1":
1813
+ exec("formatBlock", "<h1>");
1814
+ break;
1815
+ case "h2":
1816
+ exec("formatBlock", "<h2>");
1817
+ break;
1818
+ case "h3":
1819
+ exec("formatBlock", "<h3>");
1820
+ break;
1821
+ case "ul":
1822
+ exec("insertUnorderedList");
1823
+ break;
1824
+ case "ol":
1825
+ exec("insertOrderedList");
1826
+ break;
1827
+ case "blockquote":
1828
+ exec("formatBlock", "<blockquote>");
1829
+ break;
1830
+ case "alignLeft":
1831
+ exec("justifyLeft");
1832
+ break;
1833
+ case "alignCenter":
1834
+ exec("justifyCenter");
1835
+ break;
1836
+ case "alignRight":
1837
+ exec("justifyRight");
1838
+ break;
1839
+ case "hr":
1840
+ exec("insertHorizontalRule");
1841
+ break;
1842
+ case "image":
1843
+ break;
1844
+ case "link":
1845
+ break;
1846
+ case "clear":
1847
+ exec("removeFormat");
1848
+ exec("formatBlock", "<div>");
1849
+ break;
1850
+ case "source":
1851
+ break;
1852
+ }
1853
+ }
1854
+
1855
+ // src/components/Editor/tools/toolbar.ts
1856
+ var DEFAULT_TOOLBAR = [
1857
+ "bold",
1858
+ "italic",
1859
+ "underline",
1860
+ "h1",
1861
+ "h2",
1862
+ "h3",
1863
+ "ul",
1864
+ "ol",
1865
+ "blockquote",
1866
+ "alignLeft",
1867
+ "alignCenter",
1868
+ "alignRight",
1869
+ "hr",
1870
+ "image",
1871
+ "table",
1872
+ "link",
1873
+ "clear",
1874
+ "source"
1875
+ ];
1876
+ var TOOLBAR_LABELS = {
1877
+ bold: "B",
1878
+ italic: "I",
1879
+ underline: "U",
1880
+ h1: "H1",
1881
+ h2: "H2",
1882
+ h3: "H3",
1883
+ ul: "\u25A1",
1884
+ ol: "1.",
1885
+ blockquote: "\u275D",
1886
+ alignLeft: "\u21E4",
1887
+ alignCenter: "\u21D4",
1888
+ alignRight: "\u21E5",
1889
+ hr: "\u2014",
1890
+ image: "\u{1F5BC}",
1891
+ table: "\u229E",
1892
+ link: "\u{1F517}",
1893
+ clear: "\u2715",
1894
+ source: "</>"
1895
+ };
1896
+ var TOOLBAR_TITLES = {
1897
+ bold: "\u52A0\u7C97 (Ctrl+B)",
1898
+ italic: "\u659C\u4F53 (Ctrl+I)",
1899
+ underline: "\u4E0B\u5212\u7EBF (Ctrl+U)",
1900
+ h1: "\u6807\u9898 1",
1901
+ h2: "\u6807\u9898 2",
1902
+ h3: "\u6807\u9898 3",
1903
+ ul: "\u65E0\u5E8F\u5217\u8868",
1904
+ ol: "\u6709\u5E8F\u5217\u8868",
1905
+ blockquote: "\u5F15\u7528",
1906
+ alignLeft: "\u5DE6\u5BF9\u9F50",
1907
+ alignCenter: "\u5C45\u4E2D",
1908
+ alignRight: "\u53F3\u5BF9\u9F50",
1909
+ hr: "\u5206\u5272\u7EBF",
1910
+ image: "\u63D2\u5165\u56FE\u7247",
1911
+ table: "\u63D2\u5165\u8868\u683C",
1912
+ link: "\u63D2\u5165\u94FE\u63A5",
1913
+ clear: "\u6E05\u9664\u683C\u5F0F",
1914
+ source: "\u6E90\u7801"
1915
+ };
1916
+ var GRP_FORMAT = ["bold", "italic", "underline"];
1917
+ var GRP_HEADING = ["h1", "h2", "h3"];
1918
+ var GRP_LIST = ["ul", "ol"];
1919
+ var GRP_BLOCK = ["blockquote", "alignLeft", "alignCenter", "alignRight", "hr"];
1920
+ var GRP_INSERT = ["image", "table", "link", "clear"];
1921
+ function needsSeparator(prev, item) {
1922
+ return GRP_FORMAT.includes(prev) && GRP_HEADING.includes(item) || GRP_HEADING.includes(prev) && GRP_LIST.includes(item) || GRP_LIST.includes(prev) && GRP_BLOCK.includes(item) || GRP_BLOCK.includes(prev) && GRP_INSERT.includes(item) || ["link", "clear"].includes(prev) && item === "source";
1923
+ }
1924
+ function renderToolbar(items, active, isSource, onItem, customRender) {
1925
+ const buttons = items.map((item) => {
1926
+ if (customRender?.[item]) return customRender[item](item);
1927
+ const isActive = item === "source" ? isSource : !!active[item];
1928
+ const isLink = item === "link";
1929
+ const cls = [
1930
+ "wf-editor-tb-btn",
1931
+ isActive && "wf-editor-tb-btn--active",
1932
+ isLink && "wf-editor-tb-btn--link"
1933
+ ].filter(Boolean).join(" ");
1934
+ return h("button", {
1935
+ key: item,
1936
+ class: cls,
1937
+ type: "button",
1938
+ title: TOOLBAR_TITLES[item],
1939
+ "aria-label": TOOLBAR_TITLES[item],
1940
+ "data-item": item,
1941
+ onClick: () => onItem(item)
1942
+ }, TOOLBAR_LABELS[item]);
1943
+ });
1944
+ const withSeparators = [];
1945
+ items.forEach((item, i) => {
1946
+ if (i > 0 && needsSeparator(items[i - 1], item)) {
1947
+ withSeparators.push(h("span", { class: "wf-editor-tb-sep", key: `sep-${i}` }));
1948
+ }
1949
+ withSeparators.push(buttons[i]);
1950
+ });
1951
+ return h("div", { class: "wf-editor-toolbar", role: "toolbar", "aria-label": "\u7F16\u8F91\u683C\u5F0F" }, withSeparators);
1952
+ }
1953
+
1954
+ // src/components/Editor/tools/table.ts
1955
+ var MAX = 6;
1956
+ function insertTable(rows, cols) {
1957
+ const tds = Array.from(
1958
+ { length: cols },
1959
+ (_, ci) => `<td${ci === 0 ? ' style="font-weight:var(--wf-font-weight-semibold,600)"' : ""}>&nbsp;</td>`
1960
+ ).join("");
1961
+ const rowsHtml = Array.from(
1962
+ { length: rows },
1963
+ (_, ri) => `<tr>${ri === 0 ? tds : tds.replace(/ style="[^"]*"/, "")}</tr>`
1964
+ ).join("");
1965
+ const html = `<div><table class="wf-editor-table"><tbody>${rowsHtml}</tbody></table></div>`;
1966
+ try {
1967
+ document.execCommand("insertHTML", false, html);
1968
+ } catch {
1063
1969
  }
1064
- const placeholderEl = placeholder !== void 0 ? placeholder : h("div", { class: "wf-inview-placeholder" });
1970
+ }
1971
+ function renderTableGrid(hoverRow, hoverCol, onSelect, onHover, onLeave) {
1972
+ const grid = h("div", {
1973
+ class: "wf-editor-table-grid",
1974
+ onMouseLeave: onLeave
1975
+ }, Array.from(
1976
+ { length: MAX },
1977
+ (_, ri) => h(
1978
+ "div",
1979
+ { class: "wf-editor-table-grid-row", key: `r${ri}` },
1980
+ Array.from({ length: MAX }, (_2, ci) => {
1981
+ const isHighlighted = ri <= hoverRow && ci <= hoverCol;
1982
+ return h("div", {
1983
+ class: `wf-editor-table-grid-cell${isHighlighted ? " wf-editor-table-grid-cell--active" : ""}`,
1984
+ key: `${ri}-${ci}`,
1985
+ onMouseEnter: () => onHover(ri, ci),
1986
+ onClick: () => onSelect(ri + 1, ci + 1)
1987
+ });
1988
+ })
1989
+ )
1990
+ ));
1991
+ const label = hoverRow >= 0 && hoverCol >= 0 ? `${hoverRow + 1} \xD7 ${hoverCol + 1} \u8868\u683C` : "\u9009\u62E9\u8868\u683C\u5927\u5C0F";
1065
1992
  return h("div", {
1066
- class: "wf-inview wf-inview--pending",
1067
- ref: sentinelRef
1068
- }, placeholderEl);
1993
+ class: "wf-editor-table-picker",
1994
+ onMouseDown: (e) => e.stopPropagation()
1995
+ }, [
1996
+ grid,
1997
+ h("div", { class: "wf-editor-table-picker-label" }, label)
1998
+ ]);
1999
+ }
2000
+
2001
+ // src/components/Editor/Editor.ts
2002
+ var Editor = (_props, ctx) => {
2003
+ let activeFormats = {};
2004
+ let showLinkInput = false;
2005
+ let linkUrl = "";
2006
+ let mode = "rich";
2007
+ let showImageInput = false;
2008
+ let imageUrl = "";
2009
+ let imageUploading = false;
2010
+ let showTableGrid = false;
2011
+ let tableHoverRow = -1;
2012
+ let tableHoverCol = -1;
2013
+ let sourceText = "";
2014
+ let editorEl;
2015
+ return (props) => {
2016
+ const { value = "", onChange, onUpload, placeholder = "", disabled = false, minHeight = "200px" } = props;
2017
+ const toolbarItems = props.toolbar ?? DEFAULT_TOOLBAR;
2018
+ const isRichMode = mode === "rich";
2019
+ const emitChange = (html) => {
2020
+ onChange?.(html);
2021
+ };
2022
+ const handleToolbarItem = (item) => {
2023
+ if (disabled) return;
2024
+ if (item === "source") {
2025
+ if (isRichMode) {
2026
+ sourceText = editorEl?.innerHTML ?? value;
2027
+ mode = "source";
2028
+ ctx.ui.render();
2029
+ } else {
2030
+ mode = "rich";
2031
+ activeFormats = {};
2032
+ ctx.ui.render();
2033
+ onChange?.(value);
2034
+ }
2035
+ return;
2036
+ }
2037
+ if (!isRichMode) return;
2038
+ if (item === "image") {
2039
+ showImageInput = true;
2040
+ imageUrl = "";
2041
+ ctx.ui.render();
2042
+ return;
2043
+ }
2044
+ if (item === "link") {
2045
+ const sel = window.getSelection();
2046
+ if (!sel || sel.isCollapsed) {
2047
+ showLinkInput = true;
2048
+ linkUrl = "";
2049
+ ctx.ui.render();
2050
+ return;
2051
+ }
2052
+ const existing = document.queryCommandState("createLink");
2053
+ if (existing) {
2054
+ exec("unlink");
2055
+ activeFormats = queryFormats();
2056
+ ctx.ui.render();
2057
+ } else {
2058
+ showLinkInput = true;
2059
+ linkUrl = "";
2060
+ ctx.ui.render();
2061
+ }
2062
+ return;
2063
+ }
2064
+ execFormat(item);
2065
+ activeFormats = queryFormats();
2066
+ ctx.ui.render();
2067
+ if (editorEl && onChange) emitChange(editorEl.innerHTML);
2068
+ };
2069
+ const confirmLink = (url) => {
2070
+ showLinkInput = false;
2071
+ ctx.ui.render();
2072
+ if (!url) return;
2073
+ if (editorEl) editorEl.focus();
2074
+ exec("createLink", url);
2075
+ activeFormats = queryFormats();
2076
+ if (editorEl && onChange) emitChange(editorEl.innerHTML);
2077
+ };
2078
+ const cancelLink = () => {
2079
+ showLinkInput = false;
2080
+ linkUrl = "";
2081
+ ctx.ui.render();
2082
+ };
2083
+ const insertImageFn = (url) => {
2084
+ if (!url) return;
2085
+ exec("insertImage", url);
2086
+ activeFormats = queryFormats();
2087
+ if (editorEl && onChange) emitChange(editorEl.innerHTML);
2088
+ };
2089
+ const handleImageFile = async (files) => {
2090
+ const file = files[0];
2091
+ if (!file) return;
2092
+ imageUploading = true;
2093
+ ctx.ui.render();
2094
+ try {
2095
+ const url = await onUpload(file);
2096
+ insertImageFn(url);
2097
+ showImageInput = false;
2098
+ imageUrl = "";
2099
+ ctx.ui.render();
2100
+ } catch {
2101
+ } finally {
2102
+ imageUploading = false;
2103
+ ctx.ui.render();
2104
+ }
2105
+ };
2106
+ const confirmImageUrl = (url) => {
2107
+ showImageInput = false;
2108
+ imageUrl = "";
2109
+ ctx.ui.render();
2110
+ if (editorEl) editorEl.focus();
2111
+ insertImageFn(url);
2112
+ };
2113
+ const cancelImage = () => {
2114
+ showImageInput = false;
2115
+ imageUrl = "";
2116
+ ctx.ui.render();
2117
+ };
2118
+ const handleTableSelect = (rows, cols) => {
2119
+ showTableGrid = false;
2120
+ tableHoverRow = -1;
2121
+ tableHoverCol = -1;
2122
+ ctx.ui.render();
2123
+ if (editorEl) editorEl.focus();
2124
+ insertTable(rows, cols);
2125
+ if (editorEl && onChange) emitChange(editorEl.innerHTML);
2126
+ };
2127
+ const handleTableHover = (row, col) => {
2128
+ tableHoverRow = row;
2129
+ tableHoverCol = col;
2130
+ ctx.ui.render();
2131
+ };
2132
+ const handleTableLeave = () => {
2133
+ tableHoverRow = -1;
2134
+ tableHoverCol = -1;
2135
+ ctx.ui.render();
2136
+ };
2137
+ const tableButton = h("button", {
2138
+ key: "table",
2139
+ class: "wf-editor-tb-btn",
2140
+ type: "button",
2141
+ title: "\u63D2\u5165\u8868\u683C",
2142
+ "aria-label": "\u63D2\u5165\u8868\u683C",
2143
+ "data-item": "table"
2144
+ }, "\u229E");
2145
+ const tableGrid = showTableGrid ? renderTableGrid(
2146
+ tableHoverRow,
2147
+ tableHoverCol,
2148
+ handleTableSelect,
2149
+ handleTableHover,
2150
+ handleTableLeave
2151
+ ) : null;
2152
+ const tablePopover = h(Popover, {
2153
+ key: "table",
2154
+ open: isRichMode && !!showTableGrid,
2155
+ onOpenChange: (v) => {
2156
+ showTableGrid = v;
2157
+ ctx.ui.render();
2158
+ },
2159
+ content: tableGrid
2160
+ }, tableButton);
2161
+ const handleRichInput = (e) => {
2162
+ if (disabled) return;
2163
+ emitChange(e.currentTarget.innerHTML);
2164
+ };
2165
+ const handleSourceInput = (e) => {
2166
+ const val = e.target.value;
2167
+ onChange?.(val);
2168
+ };
2169
+ const editorRef = (el) => {
2170
+ if (el) editorEl = el;
2171
+ return () => {
2172
+ editorEl = void 0;
2173
+ };
2174
+ };
2175
+ const handleKeyUp = (e) => {
2176
+ if (disabled || !isRichMode) return;
2177
+ const isFormatShortcut = (e.ctrlKey || e.metaKey) && ["b", "i", "u"].includes(e.key.toLowerCase());
2178
+ if (isFormatShortcut) {
2179
+ activeFormats = queryFormats();
2180
+ ctx.ui.render();
2181
+ if (editorEl && onChange) emitChange(editorEl.innerHTML);
2182
+ }
2183
+ };
2184
+ const handleMouseUp = () => {
2185
+ if (!isRichMode) return;
2186
+ activeFormats = queryFormats();
2187
+ ctx.ui.render();
2188
+ };
2189
+ const handleMouseDown = () => {
2190
+ let needsRender = false;
2191
+ if (showLinkInput) {
2192
+ showLinkInput = false;
2193
+ needsRender = true;
2194
+ }
2195
+ if (showImageInput) {
2196
+ showImageInput = false;
2197
+ needsRender = true;
2198
+ }
2199
+ if (needsRender) ctx.ui.render();
2200
+ };
2201
+ const linkModal = isRichMode && showLinkInput ? h(
2202
+ Modal,
2203
+ {
2204
+ open: true,
2205
+ title: "\u63D2\u5165\u94FE\u63A5",
2206
+ onClose: cancelLink,
2207
+ footer: [
2208
+ h("button", { class: "wf-btn wf-btn--ghost wf-btn--sm", type: "button", onClick: cancelLink }, "\u53D6\u6D88"),
2209
+ h("button", {
2210
+ class: "wf-btn wf-btn--primary wf-btn--sm",
2211
+ type: "button",
2212
+ onClick: () => {
2213
+ const input = document.querySelector("[data-editor-link-input]");
2214
+ confirmLink(input?.value ?? "");
2215
+ }
2216
+ }, "\u786E\u5B9A")
2217
+ ]
2218
+ },
2219
+ h("input", {
2220
+ type: "url",
2221
+ class: "wf-editor-link-input",
2222
+ placeholder: "https://...",
2223
+ value: linkUrl,
2224
+ "data-editor-link-input": true,
2225
+ onInput: (e) => {
2226
+ linkUrl = e.target.value;
2227
+ ctx.ui.render();
2228
+ },
2229
+ onKeyDown: (e) => {
2230
+ if (e.key === "Enter") confirmLink(e.target.value);
2231
+ if (e.key === "Escape") cancelLink();
2232
+ }
2233
+ })
2234
+ ) : null;
2235
+ const imageBodyChildren = [];
2236
+ if (onUpload) {
2237
+ imageBodyChildren.push(h(FileUpload, {
2238
+ accept: "image/*",
2239
+ multiple: false,
2240
+ disabled: imageUploading,
2241
+ onChange: handleImageFile
2242
+ }, h("div", { class: "wf-editor-img-zone" }, [
2243
+ h("span", { class: "wf-editor-img-zone-icon" }, "\u{1F5BC}"),
2244
+ h("span", { class: "wf-editor-img-zone-text" }, imageUploading ? "\u4E0A\u4F20\u4E2D..." : "\u70B9\u51FB\u6216\u62D6\u62FD\u4E0A\u4F20\u56FE\u7247")
2245
+ ])));
2246
+ imageBodyChildren.push(h("span", { class: "wf-editor-img-or" }, "\u6216"));
2247
+ }
2248
+ imageBodyChildren.push(h("input", {
2249
+ type: "url",
2250
+ class: "wf-editor-link-input",
2251
+ placeholder: onUpload ? "\u7C98\u8D34\u56FE\u7247\u94FE\u63A5" : "https://...",
2252
+ value: imageUrl,
2253
+ "data-image-input": true,
2254
+ disabled: imageUploading || void 0,
2255
+ onInput: (e) => {
2256
+ imageUrl = e.target.value;
2257
+ ctx.ui.render();
2258
+ },
2259
+ onKeyDown: (e) => {
2260
+ if (e.key === "Enter") confirmImageUrl(e.target.value);
2261
+ if (e.key === "Escape") cancelImage();
2262
+ }
2263
+ }));
2264
+ const imageModal = isRichMode && showImageInput ? h(
2265
+ Modal,
2266
+ {
2267
+ open: true,
2268
+ title: "\u63D2\u5165\u56FE\u7247",
2269
+ onClose: cancelImage,
2270
+ footer: [
2271
+ h("button", { class: "wf-btn wf-btn--ghost wf-btn--sm", type: "button", disabled: imageUploading || void 0, onClick: cancelImage }, "\u53D6\u6D88"),
2272
+ h("button", {
2273
+ class: "wf-btn wf-btn--primary wf-btn--sm",
2274
+ type: "button",
2275
+ disabled: imageUploading || void 0,
2276
+ onClick: () => {
2277
+ const input = document.querySelector("[data-image-input]");
2278
+ confirmImageUrl(input?.value ?? "");
2279
+ }
2280
+ }, onUpload ? "\u63D2\u5165" : "\u786E\u5B9A")
2281
+ ]
2282
+ },
2283
+ h("div", { class: "wf-stack", style: "gap:8px" }, imageBodyChildren)
2284
+ ) : null;
2285
+ let editorBody = null;
2286
+ if (isRichMode) {
2287
+ const editorClass = [
2288
+ "wf-editor-content",
2289
+ disabled && "wf-editor-content--disabled",
2290
+ placeholder && "wf-editor-content--has-placeholder"
2291
+ ].filter(Boolean).join(" ");
2292
+ editorBody = h("div", {
2293
+ class: editorClass,
2294
+ contentEditable: !disabled,
2295
+ innerHTML: isRichMode ? value : sourceText,
2296
+ "data-placeholder": placeholder || void 0,
2297
+ style: { minHeight },
2298
+ onInput: handleRichInput,
2299
+ onKeyUp: handleKeyUp,
2300
+ onMouseUp: handleMouseUp,
2301
+ onMouseDown: handleMouseDown,
2302
+ ref: editorRef
2303
+ });
2304
+ } else {
2305
+ editorBody = h("textarea", {
2306
+ class: "wf-editor-source",
2307
+ value,
2308
+ disabled,
2309
+ style: { minHeight },
2310
+ onInput: handleSourceInput
2311
+ });
2312
+ }
2313
+ const customRender = {
2314
+ table: () => tablePopover
2315
+ };
2316
+ return h("div", {
2317
+ class: `wf-editor${disabled ? " wf-editor--disabled" : ""}`
2318
+ }, [
2319
+ !disabled && toolbarItems.length > 0 ? renderToolbar(toolbarItems, activeFormats, !isRichMode, handleToolbarItem, customRender) : null,
2320
+ linkModal,
2321
+ imageModal,
2322
+ editorBody,
2323
+ h("input", { type: "hidden", value, "aria-hidden": "true" })
2324
+ ]);
2325
+ };
1069
2326
  };
1070
2327
  export {
1071
2328
  Accordion,
@@ -1075,10 +2332,13 @@ export {
1075
2332
  Breadcrumb,
1076
2333
  Button,
1077
2334
  Card,
2335
+ Chart,
1078
2336
  Checkbox,
2337
+ DatePicker,
1079
2338
  Divider,
1080
2339
  Drawer,
1081
2340
  Dropdown,
2341
+ Editor,
1082
2342
  EmptyState,
1083
2343
  Field,
1084
2344
  FileUpload,