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.
- package/README.md +96 -66
- package/dist/client/app.d.ts +2 -6
- package/dist/client/error-boundary.d.ts +2 -2
- package/dist/client/index.d.ts +3 -1
- package/dist/client/index.js +350 -147
- package/dist/client/locale/en_US.d.ts +15 -0
- package/dist/client/locale/zh_CN.d.ts +15 -0
- package/dist/client/popup.d.ts +19 -0
- package/dist/client/render.d.ts +3 -3
- package/dist/client/router.d.ts +1 -1
- package/dist/client/types.d.ts +11 -5
- package/dist/client/vnode.d.ts +11 -2
- package/dist/components/Chart/Chart.d.ts +15 -0
- package/dist/components/Chart/chart-utils.d.ts +53 -0
- package/dist/components/DatePicker/DatePicker.d.ts +18 -0
- package/dist/components/DatePicker/calendar-utils.d.ts +30 -0
- package/dist/components/Dropdown/Dropdown.d.ts +3 -0
- package/dist/components/Editor/Editor.d.ts +13 -0
- package/dist/components/Editor/tools/format.d.ts +10 -0
- package/dist/components/Editor/tools/table.d.ts +7 -0
- package/dist/components/Editor/tools/toolbar.d.ts +9 -0
- package/dist/components/Editor/tools/types.d.ts +15 -0
- package/dist/components/FileUpload/FileUpload.d.ts +3 -0
- package/dist/components/Img/Img.d.ts +0 -2
- package/dist/components/InView/InView.d.ts +2 -17
- package/dist/components/Popover/Popover.d.ts +2 -12
- package/dist/components/Skeleton/Skeleton.d.ts +0 -8
- package/dist/components/Tooltip/Tooltip.d.ts +5 -1
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.js +1603 -343
- package/dist/components/style.css +734 -153
- package/dist/layout/weifuwu-layout.css +14 -0
- package/package.json +2 -2
package/dist/components/index.js
CHANGED
|
@@ -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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
285
|
-
|
|
286
|
-
|
|
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
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
"
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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 = (
|
|
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
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 =
|
|
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 = (
|
|
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 = (
|
|
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
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
const
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
{ class: "wf-upload-
|
|
819
|
-
|
|
820
|
-
(
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
"
|
|
830
|
-
|
|
831
|
-
|
|
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
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
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/
|
|
842
|
-
|
|
843
|
-
const
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
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
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
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 = (
|
|
872
|
-
|
|
873
|
-
|
|
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
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
class:
|
|
925
|
-
|
|
926
|
-
"
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
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 = (
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
position = "bottom",
|
|
939
|
-
open
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
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 = (
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
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
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
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
|
-
|
|
1062
|
-
|
|
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)"' : ""}> </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
|
-
|
|
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-
|
|
1067
|
-
|
|
1068
|
-
},
|
|
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,
|