@enableai-base/ui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ui.cjs.js ADDED
@@ -0,0 +1,1387 @@
1
+ /**
2
+ * @enableai-base/ui v1.0.0
3
+ * (c) 2024-present Enableai
4
+ * @license Proprietary
5
+ **/
6
+ 'use strict';
7
+
8
+ Object.defineProperty(exports, '__esModule', { value: true });
9
+
10
+ var React = require('react');
11
+ var antd = require('antd');
12
+ var core = require('@enableai-base/core');
13
+ var core$1 = require('@enableai-sdk-common/core');
14
+ var icons = require('@ant-design/icons');
15
+ var color = require('@enableai-sdk-common/color');
16
+ var fontIconEnableaiBase = require('@enableai-fonts/font-icon-enableai-base');
17
+ var id = require('@enableai-sdk-common/id');
18
+ var reactHooks = require('@enableai-sdk-common/react-hooks');
19
+ var lodash = require('lodash');
20
+ var VirtualList = require('react-tiny-virtual-list');
21
+ var CryptoJS = require('crypto-js');
22
+ var sortable = require('@dnd-kit/sortable');
23
+ var utilities = require('@dnd-kit/utilities');
24
+ var core$2 = require('@dnd-kit/core');
25
+ var modifiers = require('@dnd-kit/modifiers');
26
+
27
+ const USER_POPOVER_WIDTH = 160;
28
+ const NAME_FONT_SIZE = 16;
29
+ const UserPopoverWrapper = ({ children }) => /* @__PURE__ */ React.createElement(antd.Flex, { style: { width: USER_POPOVER_WIDTH, justifyContent: "center" } }, children);
30
+ const SkeletonLine = ({ height, width }) => /* @__PURE__ */ React.createElement(
31
+ antd.Skeleton.Button,
32
+ {
33
+ active: true,
34
+ style: {
35
+ width,
36
+ height,
37
+ padding: 0,
38
+ minWidth: 0,
39
+ borderRadius: 2
40
+ }
41
+ }
42
+ );
43
+ const UserLoadingSkeleton = ({ fontSize }) => {
44
+ return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
45
+ "div",
46
+ {
47
+ style: {
48
+ display: "flex",
49
+ gap: 12,
50
+ alignItems: "center",
51
+ marginBottom: 8
52
+ }
53
+ },
54
+ /* @__PURE__ */ React.createElement(antd.Skeleton.Avatar, { size: 48, active: true, shape: "circle" }),
55
+ /* @__PURE__ */ React.createElement(
56
+ "div",
57
+ {
58
+ style: {
59
+ flex: 1,
60
+ display: "flex",
61
+ flexDirection: "column",
62
+ gap: 4,
63
+ overflow: "hidden"
64
+ }
65
+ },
66
+ /* @__PURE__ */ React.createElement(SkeletonLine, { height: NAME_FONT_SIZE, width: 80 }),
67
+ /* @__PURE__ */ React.createElement(SkeletonLine, { height: fontSize, width: 80 }),
68
+ /* @__PURE__ */ React.createElement(SkeletonLine, { height: fontSize, width: 80 })
69
+ )
70
+ ), /* @__PURE__ */ React.createElement(SkeletonLine, { height: fontSize, width: 140 }));
71
+ };
72
+ const AvatarPopoverContent = (props) => {
73
+ const { id, column, fontSize = 14 } = props;
74
+ const [value, setValue] = React.useState(null);
75
+ const [loading, setLoading] = React.useState(false);
76
+ React.useEffect(() => {
77
+ const fetchDetail = async () => {
78
+ if (column && id != null && typeof column.request === "function") {
79
+ try {
80
+ setLoading(true);
81
+ const v = await column.request(id);
82
+ setValue(v);
83
+ } catch (e) {
84
+ console.error("AvatarPopover fetchDetail error:", e);
85
+ setValue(null);
86
+ } finally {
87
+ setLoading(false);
88
+ }
89
+ } else {
90
+ setValue(null);
91
+ setLoading(false);
92
+ }
93
+ };
94
+ fetchDetail();
95
+ }, [id, column]);
96
+ const userContent = loading ? /* @__PURE__ */ React.createElement(UserPopoverWrapper, null, /* @__PURE__ */ React.createElement(UserLoadingSkeleton, { fontSize })) : /* @__PURE__ */ React.createElement(antd.Flex, { style: { minWidth: USER_POPOVER_WIDTH, justifyContent: "center" } }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
97
+ "div",
98
+ {
99
+ style: {
100
+ display: "flex",
101
+ gap: 12,
102
+ alignItems: "center",
103
+ marginBottom: 8
104
+ }
105
+ },
106
+ /* @__PURE__ */ React.createElement(
107
+ antd.Avatar,
108
+ {
109
+ size: 48,
110
+ src: value?.avatar,
111
+ style: { backgroundColor: value?.name === "\u65E0" ? "#D9D9D9" : core.getColorByStr(value?.name?.slice(-2)) }
112
+ },
113
+ value?.name ? value.name.split(-2) : "\u672A\u77E5"
114
+ ),
115
+ /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ React.createElement(
116
+ "div",
117
+ {
118
+ style: {
119
+ fontSize: NAME_FONT_SIZE,
120
+ fontWeight: 500,
121
+ marginBottom: 4
122
+ }
123
+ },
124
+ value?.name || "\u672A\u77E5"
125
+ ), /* @__PURE__ */ React.createElement("div", { style: { fontSize, color: "#666", marginBottom: 4 } }, value?.role || "\u6682\u65E0\u89D2\u8272\u4FE1\u606F"), value?.mobile && /* @__PURE__ */ React.createElement("div", { style: { fontSize, color: "#666" } }, value.mobile))
126
+ ), value?.status && /* @__PURE__ */ React.createElement("div", { style: { fontSize, color: "#333", marginLeft: 4 } }, /* @__PURE__ */ React.createElement(
127
+ antd.Badge,
128
+ {
129
+ color: value.status === "\u5728\u7EBF" ? "green" : "gray",
130
+ style: { margin: "0 4px", transform: "scale(1.5)" }
131
+ }
132
+ ), value.status)));
133
+ return userContent;
134
+ };
135
+
136
+ const BlinkButton = React.forwardRef(function BlinkButton2({ children, style, blinkInterval = 300, blinkTimes = 2, dimOpacity = 0.4, ...props }, ref) {
137
+ const [shine, setShine] = React.useState(true);
138
+ const aliveRef = React.useRef(true);
139
+ const runningRef = React.useRef(false);
140
+ React.useEffect(() => {
141
+ return () => {
142
+ aliveRef.current = false;
143
+ };
144
+ }, []);
145
+ const blink = React.useCallback(async () => {
146
+ if (runningRef.current) return;
147
+ runningRef.current = true;
148
+ try {
149
+ for (let i = 0; i < blinkTimes; i++) {
150
+ if (!aliveRef.current) return;
151
+ setShine(false);
152
+ await core$1.waitPromise(blinkInterval);
153
+ if (!aliveRef.current) return;
154
+ setShine(true);
155
+ await core$1.waitPromise(blinkInterval);
156
+ }
157
+ } finally {
158
+ runningRef.current = false;
159
+ }
160
+ }, [blinkInterval, blinkTimes]);
161
+ React.useImperativeHandle(ref, () => ({ blink }), [blink]);
162
+ const mergedStyle = React.useMemo(
163
+ () => ({
164
+ ...style,
165
+ opacity: shine ? 1 : dimOpacity
166
+ }),
167
+ [style, shine, dimOpacity]
168
+ );
169
+ return /* @__PURE__ */ React.createElement(antd.Button, { ...props, style: mergedStyle }, children);
170
+ });
171
+
172
+ const CustomTag = ({
173
+ label,
174
+ maxWidth = "100%",
175
+ color: color$1,
176
+ fontSize = 13,
177
+ closable = false,
178
+ onClose,
179
+ style = {},
180
+ className = "",
181
+ ...tagProps
182
+ }) => {
183
+ const textRef = React.useRef(null);
184
+ const [isOverflowed, setIsOverflowed] = React.useState(false);
185
+ const [isTooltipVisible, setIsTooltipVisible] = React.useState(false);
186
+ const fontColor = React.useMemo(() => color.getTextColorForBackground(color$1 || "#000000"), [color$1]);
187
+ React.useEffect(() => {
188
+ const checkOverflow = () => {
189
+ if (textRef.current) {
190
+ const element = textRef.current;
191
+ const isOverflowing = element.scrollWidth > element.clientWidth;
192
+ setIsOverflowed(isOverflowing);
193
+ }
194
+ };
195
+ checkOverflow();
196
+ window.addEventListener("resize", checkOverflow);
197
+ return () => window.removeEventListener("resize", checkOverflow);
198
+ }, [label, maxWidth]);
199
+ const tagStyle = React.useMemo(
200
+ () => ({
201
+ maxWidth,
202
+ overflow: "hidden",
203
+ textOverflow: "ellipsis",
204
+ whiteSpace: "nowrap",
205
+ borderRadius: "20px",
206
+ verticalAlign: "middle",
207
+ border: "unset",
208
+ color: fontColor,
209
+ backgroundColor: color$1,
210
+ ...style
211
+ }),
212
+ [maxWidth, fontColor, color$1, style]
213
+ );
214
+ const handleTooltipVisibleChange = (visible) => {
215
+ if (isOverflowed) {
216
+ setIsTooltipVisible(visible);
217
+ }
218
+ };
219
+ const tagContent = /* @__PURE__ */ React.createElement(
220
+ antd.Tag,
221
+ {
222
+ closable,
223
+ onClose,
224
+ closeIcon: /* @__PURE__ */ React.createElement(icons.CloseOutlined, { style: { fontSize: 10, color: fontColor } }),
225
+ style: tagStyle,
226
+ className: `custom-tag ${className}`,
227
+ ...tagProps
228
+ },
229
+ /* @__PURE__ */ React.createElement(
230
+ "span",
231
+ {
232
+ ref: textRef,
233
+ style: {
234
+ display: "inline-block",
235
+ maxWidth: `${closable ? "calc(100% - 17px)" : "100%"}`,
236
+ //17是图标宽度+图标间距
237
+ overflow: "hidden",
238
+ textOverflow: "ellipsis",
239
+ fontSize: `${fontSize}px`,
240
+ whiteSpace: "nowrap",
241
+ verticalAlign: "bottom"
242
+ }
243
+ },
244
+ label
245
+ )
246
+ );
247
+ if (isOverflowed) {
248
+ return /* @__PURE__ */ React.createElement(
249
+ antd.Tooltip,
250
+ {
251
+ title: label,
252
+ open: isTooltipVisible,
253
+ onOpenChange: handleTooltipVisibleChange,
254
+ mouseEnterDelay: 0.5,
255
+ styles: { root: { maxWidth: "400px", wordBreak: "break-all" } }
256
+ },
257
+ tagContent
258
+ );
259
+ }
260
+ return tagContent;
261
+ };
262
+
263
+ const ColorCheckboxGroup = ({ value = [], options = [], onChange, disabled }) => {
264
+ const innerValue = value.map((v) => v.value);
265
+ const handleChange = (checkedValues) => {
266
+ const next = options.filter((opt) => checkedValues.includes(opt.value));
267
+ onChange?.(next);
268
+ };
269
+ return /* @__PURE__ */ React.createElement(antd.Checkbox.Group, { value: innerValue, onChange: handleChange, disabled, className: "color-checkbox-group" }, options.map((option) => {
270
+ const checked = innerValue.includes(option.value);
271
+ return /* @__PURE__ */ React.createElement(
272
+ antd.Checkbox,
273
+ {
274
+ key: option.value,
275
+ value: option.value,
276
+ className: `color-checkbox-item ${checked ? "checked" : ""}`
277
+ },
278
+ /* @__PURE__ */ React.createElement(CustomTag, { color: option.color, className: "color-checkbox-tag", label: option.label })
279
+ );
280
+ }));
281
+ };
282
+
283
+ const ColorRadioGroup = ({ value = [], options = [], onChange, disabled }) => {
284
+ const innerValue = value[0]?.value;
285
+ const handleChange = (e) => {
286
+ const selected = options.find((opt) => opt.value === e.target.value);
287
+ onChange?.(selected ? [selected] : []);
288
+ };
289
+ return /* @__PURE__ */ React.createElement(antd.Radio.Group, { value: innerValue, onChange: handleChange, disabled, className: "color-radio-group" }, options.map((option) => {
290
+ const checked = option.value === innerValue;
291
+ return /* @__PURE__ */ React.createElement(antd.Radio, { key: option.value, value: option.value, className: `color-radio-item ${checked ? "checked" : ""}` }, /* @__PURE__ */ React.createElement(CustomTag, { color: option.color, className: "color-radio-tag", label: option.label }));
292
+ }));
293
+ };
294
+
295
+ const ColorPickerButton = ({ color: color$1, ...args }) => {
296
+ const iconColor = React.useMemo(() => color$1 ? color.getTextColorForBackground(color$1) : "var(--ant-color-text-base)", [color$1]);
297
+ return /* @__PURE__ */ React.createElement("div", { ...args }, /* @__PURE__ */ React.createElement("div", { className: `color-picker-button` }, /* @__PURE__ */ React.createElement("span", { className: "universe-icon", style: { backgroundColor: color$1, color: iconColor } }, /* @__PURE__ */ React.createElement(icons.CaretDownOutlined, null)), /* @__PURE__ */ React.createElement("div", { className: "color-picker-button-mask" }, " ")));
298
+ };
299
+
300
+ const FixedColorPanel = (_, { components: { Presets } }) => {
301
+ return /* @__PURE__ */ React.createElement(antd.Row, { justify: "space-between", wrap: false, className: "color-picker-panel" }, /* @__PURE__ */ React.createElement(Presets, null));
302
+ };
303
+
304
+ const presetColors = [
305
+ {
306
+ label: "group1",
307
+ key: "group1",
308
+ colors: [
309
+ "#ff7570",
310
+ "#ff811a",
311
+ "#ffc60a",
312
+ "#91ad00",
313
+ "#35bd4b",
314
+ "#2dbeab",
315
+ "#25b0e7",
316
+ "#7aa2ff",
317
+ "#eb78b8",
318
+ "#b791fa",
319
+ "#8f959e"
320
+ ]
321
+ },
322
+ {
323
+ label: "group2",
324
+ key: "group2",
325
+ colors: [
326
+ "#fee3e2",
327
+ "#fee7cd",
328
+ "#faedc2",
329
+ "#e3f0a3",
330
+ "#d0f5ce",
331
+ "#c4f2ec",
332
+ "#caeffc",
333
+ "#e0e9ff",
334
+ "#fee2f2",
335
+ "#efe6fe",
336
+ "#eff0f1"
337
+ ]
338
+ },
339
+ {
340
+ label: "group3",
341
+ key: "group3",
342
+ colors: [
343
+ "#fdc6c4",
344
+ "#fec48b",
345
+ "#fcdf7e",
346
+ "#c8dd5f",
347
+ "#95e599",
348
+ "#6fe8d8",
349
+ "#97dcfc",
350
+ "#c2d4ff",
351
+ "#f8c4e1",
352
+ "#dcc9fd",
353
+ "#dee0e3"
354
+ ]
355
+ },
356
+ {
357
+ label: "group4",
358
+ key: "group4",
359
+ colors: [
360
+ "#f54a45",
361
+ "#ed6d0c",
362
+ "#d99904",
363
+ "#7b9207",
364
+ "#32a645",
365
+ "#10a893",
366
+ "#1295ca",
367
+ "#5083fb",
368
+ "#df58a5",
369
+ "#9f6ff1",
370
+ "#646a73"
371
+ ]
372
+ },
373
+ {
374
+ label: "group5",
375
+ key: "group5",
376
+ colors: [
377
+ "#c02a26",
378
+ "#a44904",
379
+ "#865b03",
380
+ "#5c6d08",
381
+ "#1a7526",
382
+ "#067062",
383
+ "#076a94",
384
+ "#1456f0",
385
+ "#b82879",
386
+ "#7a35f0",
387
+ "#373c43"
388
+ ]
389
+ }
390
+ ];
391
+
392
+ const FixedColorPicker = ({ ...args }) => {
393
+ const [clonedPresetColor] = React.useState(() => lodash.cloneDeep(presetColors));
394
+ return /* @__PURE__ */ React.createElement(
395
+ antd.ColorPicker,
396
+ {
397
+ ...{
398
+ placement: "left",
399
+ panelRender: FixedColorPanel,
400
+ presets: clonedPresetColor,
401
+ ...args
402
+ }
403
+ },
404
+ /* @__PURE__ */ React.createElement(ColorPickerButton, { color: args.value })
405
+ );
406
+ };
407
+
408
+ const getRandomColor = () => {
409
+ const colors = presetColors.flatMap((group) => group.colors);
410
+ return colors[Math.floor(Math.random() * colors.length)];
411
+ };
412
+
413
+ const IconFont = ({ name, size = 16, color, className, style }) => {
414
+ const [iconClass, setIconClass] = React.useState("");
415
+ React.useEffect(() => {
416
+ fontIconEnableaiBase.initEnableAIBaseFontIcon().then(() => {
417
+ setIconClass(fontIconEnableaiBase.EnableAIBaseFontIcon.get(name));
418
+ });
419
+ }, [name]);
420
+ return /* @__PURE__ */ React.createElement(
421
+ "i",
422
+ {
423
+ className: [iconClass, className].filter(Boolean).join(" "),
424
+ style: { fontSize: size, color, ...style },
425
+ "aria-hidden": "true"
426
+ }
427
+ );
428
+ };
429
+
430
+ function isFocused(el) {
431
+ return !!el && document.activeElement === el;
432
+ }
433
+ function focusToEnd(el) {
434
+ el.focus();
435
+ const selection = window.getSelection();
436
+ if (!selection) return;
437
+ const range = document.createRange();
438
+ range.selectNodeContents(el);
439
+ range.collapse(false);
440
+ selection.removeAllRanges();
441
+ selection.addRange(range);
442
+ }
443
+
444
+ const LinkEdit = ({ value, onChange, disabled, styles, popoverStyles, placeholder }) => {
445
+ const [open, setOpen] = React.useState(false);
446
+ const [draft, setDraft] = React.useState(value);
447
+ React.useEffect(() => {
448
+ setDraft(value);
449
+ }, [value]);
450
+ const updateDraft = (key, v) => {
451
+ setDraft((prev) => ({
452
+ ...prev ?? {},
453
+ [key]: v
454
+ }));
455
+ };
456
+ const confirm = () => {
457
+ dispatchData(draft);
458
+ setOpen(false);
459
+ updateInputTitle(draft?.title ?? "");
460
+ };
461
+ const cancel = () => {
462
+ setDraft(value);
463
+ updateInputTitle(value?.title ?? "");
464
+ setOpen(false);
465
+ };
466
+ const dispatchData = React.useCallback(
467
+ (data) => {
468
+ const isTitleChange = !Object.is(value?.title, data?.title);
469
+ const isLinkChange = !Object.is(value?.url, data?.url);
470
+ if (isTitleChange || isLinkChange) onChange?.(data);
471
+ },
472
+ [onChange, value?.title, value?.url]
473
+ );
474
+ const inputTitleRef = React.useRef(value?.title ?? "");
475
+ const [hasTitle, setHasTitle] = React.useState(!!value?.title);
476
+ const updateInputTitle = React.useCallback((title, focus = false) => {
477
+ inputTitleRef.current = title;
478
+ setHasTitle(!!title.length);
479
+ if (focus) {
480
+ requestAnimationFrame(() => {
481
+ if (ref1.current && !isFocused(ref1.current)) focusToEnd(ref1.current);
482
+ if (ref2.current && !isFocused(ref2.current)) ref2.current.focus();
483
+ });
484
+ }
485
+ }, []);
486
+ const inputLink = React.useMemo(() => draft?.url, [draft?.url]);
487
+ const [inputRefreshKey, setInputRefreshKey] = React.useState(id.getUUID());
488
+ const editingRef = React.useRef(false);
489
+ const ref1 = React.useRef(null);
490
+ const ref2 = React.useRef(null);
491
+ React.useEffect(() => {
492
+ if (!editingRef.current) return;
493
+ if (ref1.current && !isFocused(ref1.current)) focusToEnd(ref1.current);
494
+ if (ref2.current) ref2.current.focus();
495
+ }, [hasTitle]);
496
+ const isComposingRef = React.useRef(false);
497
+ return /* @__PURE__ */ React.createElement(
498
+ antd.Popover,
499
+ {
500
+ open,
501
+ onOpenChange: (v) => {
502
+ if (!v) setOpen(v);
503
+ },
504
+ placement: "bottom",
505
+ trigger: ["click"],
506
+ arrow: false,
507
+ content: /* @__PURE__ */ React.createElement(antd.Flex, { style: { ...popoverStyles }, vertical: true, gap: 24 }, /* @__PURE__ */ React.createElement("div", { className: "link-editor-form-item" }, /* @__PURE__ */ React.createElement("div", { className: "item-label" }, "\u6587\u672C"), /* @__PURE__ */ React.createElement(antd.Input, { value: draft?.title, onChange: (e) => updateDraft("title", e.target.value) })), /* @__PURE__ */ React.createElement("div", { className: "link-editor-form-item" }, /* @__PURE__ */ React.createElement("div", { className: "item-label" }, "\u8D85\u94FE\u63A5"), /* @__PURE__ */ React.createElement(antd.Input, { value: draft?.url, onChange: (e) => updateDraft("url", e.target.value) })), /* @__PURE__ */ React.createElement(antd.Flex, { justify: "flex-end" }, /* @__PURE__ */ React.createElement(antd.Space, null, /* @__PURE__ */ React.createElement(antd.Button, { size: "small", onClick: cancel }, "\u53D6\u6D88"), /* @__PURE__ */ React.createElement(antd.Button, { size: "small", type: "primary", onClick: confirm }, "\u786E\u5B9A"))))
508
+ },
509
+ /* @__PURE__ */ React.createElement(
510
+ antd.Flex,
511
+ {
512
+ align: "center",
513
+ style: {
514
+ backgroundColor: core.COLOR_BG_CELL,
515
+ borderRadius: 0,
516
+ ...styles
517
+ }
518
+ },
519
+ hasTitle ? /* @__PURE__ */ React.createElement(
520
+ "div",
521
+ {
522
+ className: "link-editor-input content-editable-clear",
523
+ key: inputRefreshKey,
524
+ style: {
525
+ color: `${hasTitle ? "var(--ant-color-link)" : "var(--ant-color-text)"}`
526
+ },
527
+ onClick: (e) => {
528
+ if (e.nativeEvent.target?.nodeName === "DIV") {
529
+ if (ref1.current) {
530
+ editingRef.current = true;
531
+ focusToEnd(ref1.current);
532
+ }
533
+ }
534
+ }
535
+ },
536
+ /* @__PURE__ */ React.createElement(
537
+ "a",
538
+ {
539
+ ref: ref1,
540
+ contentEditable: !disabled,
541
+ suppressContentEditableWarning: true,
542
+ className: "link-editor-input-a content-editable-clear",
543
+ style: {
544
+ color: `${disabled ? "var(--ant-color-text-disabled)" : "var(--ant-color-link)"}`
545
+ },
546
+ onClick: () => window.open(inputLink),
547
+ onCompositionStart: () => {
548
+ isComposingRef.current = true;
549
+ },
550
+ onCompositionEnd: (e) => {
551
+ isComposingRef.current = false;
552
+ const text = e.currentTarget.innerText;
553
+ updateInputTitle(text, true);
554
+ },
555
+ onBlur: (e) => {
556
+ editingRef.current = false;
557
+ const title = e.currentTarget.innerText;
558
+ updateInputTitle(title);
559
+ dispatchData({ ...draft, title });
560
+ setInputRefreshKey(id.getUUID());
561
+ },
562
+ onInput: (e) => {
563
+ if (isComposingRef.current) return;
564
+ const result = e.currentTarget.innerText;
565
+ updateInputTitle(result, true);
566
+ },
567
+ href: inputLink
568
+ },
569
+ inputTitleRef.current
570
+ )
571
+ ) : /* @__PURE__ */ React.createElement(
572
+ "input",
573
+ {
574
+ disabled,
575
+ placeholder,
576
+ ref: ref2,
577
+ style: { flex: 1 },
578
+ className: "content-editable-clear link-editor-placeholder",
579
+ onCompositionStart: () => {
580
+ isComposingRef.current = true;
581
+ },
582
+ onCompositionEnd: (e) => {
583
+ isComposingRef.current = false;
584
+ const text = e.target.value;
585
+ updateInputTitle(text, true);
586
+ },
587
+ onInput: (e) => {
588
+ const input = e.target.value;
589
+ if (isComposingRef.current) return;
590
+ updateInputTitle(input, true);
591
+ },
592
+ onBlur: (e) => {
593
+ const title = e.currentTarget.innerText;
594
+ updateInputTitle(title);
595
+ dispatchData({ ...draft, title });
596
+ }
597
+ }
598
+ ),
599
+ /* @__PURE__ */ React.createElement(antd.Button, { disabled, type: "text", icon: /* @__PURE__ */ React.createElement(icons.LinkOutlined, null), onClick: () => setOpen((v) => !v) })
600
+ )
601
+ );
602
+ };
603
+
604
+ const OptionItem = ({
605
+ ref,
606
+ onRemove,
607
+ dispatch,
608
+ value,
609
+ onChange,
610
+ onEnterKeyUp,
611
+ style = {},
612
+ disabled
613
+ }) => {
614
+ const inputRef = React.useRef(null);
615
+ const { color, label } = value;
616
+ const { isDragging, attributes, listeners, setNodeRef, transform, transition } = sortable.useSortable({ id: value.value });
617
+ const listStyle = {
618
+ ...style,
619
+ transform: utilities.CSS.Translate.toString(transform),
620
+ transition,
621
+ ...isDragging ? { position: "relative", zIndex: 9999 } : {}
622
+ };
623
+ React.useImperativeHandle(ref, () => {
624
+ return {
625
+ focusInput() {
626
+ inputRef.current?.focus();
627
+ }
628
+ };
629
+ });
630
+ return /* @__PURE__ */ React.createElement(antd.Flex, { className: `option-item`, align: "center", style: listStyle, ref: setNodeRef, gap: "small" }, /* @__PURE__ */ React.createElement(icons.HolderOutlined, { className: "drag-point", ...attributes, ...listeners }), /* @__PURE__ */ React.createElement(
631
+ FixedColorPicker,
632
+ {
633
+ value: color,
634
+ disabled,
635
+ onChange: (colorValue) => {
636
+ const prev = value;
637
+ const next = { ...value, color: colorValue.toHexString() };
638
+ onChange(next);
639
+ if (dispatch) dispatch({ type: "edit-value", next, prev });
640
+ }
641
+ }
642
+ ), /* @__PURE__ */ React.createElement(
643
+ antd.Input,
644
+ {
645
+ ref: inputRef,
646
+ className: "option-item-input",
647
+ value: label,
648
+ disabled,
649
+ onChange: (event) => {
650
+ const prev = value;
651
+ const next = { ...value, label: event.target.value };
652
+ onChange(next);
653
+ if (dispatch) dispatch({ type: "edit-value", next, prev });
654
+ },
655
+ onPressEnter: (e) => {
656
+ e.preventDefault();
657
+ },
658
+ onKeyUp: (e) => {
659
+ if (e.code === "Enter") onEnterKeyUp(e);
660
+ }
661
+ }
662
+ ), !disabled && /* @__PURE__ */ React.createElement(
663
+ antd.Button,
664
+ {
665
+ className: "delete-button",
666
+ type: "text",
667
+ icon: /* @__PURE__ */ React.createElement(icons.CloseOutlined, { className: "delete-icon" }),
668
+ onClick: () => {
669
+ onRemove(value);
670
+ if (dispatch) dispatch({ type: "delete", prev: value, next: null });
671
+ }
672
+ }
673
+ ));
674
+ };
675
+
676
+ const OptionEditor = ({
677
+ initialValues,
678
+ onValuesChange,
679
+ virtualConfig = { height: 600 },
680
+ dispatch,
681
+ style = { width: "100%" },
682
+ disabled
683
+ }) => {
684
+ const lastInputNeedFocus = React.useRef(false);
685
+ const inputRefs = React.useRef([]);
686
+ const [virtualValues, setVirtualValues] = React.useState(
687
+ () => initialValues.map((item, index) => ({ ...item, ordinal: index }))
688
+ );
689
+ const updateVirtualValues = React.useCallback(
690
+ (values) => {
691
+ setVirtualValues(values);
692
+ if (onValuesChange) onValuesChange(values);
693
+ },
694
+ [onValuesChange]
695
+ );
696
+ const onItemChange = React.useCallback(
697
+ (value) => {
698
+ const newValues = virtualValues.map((item) => item.value === value.value ? value : item);
699
+ updateVirtualValues(newValues);
700
+ },
701
+ [virtualValues, updateVirtualValues]
702
+ );
703
+ const onItemRemove = React.useCallback(
704
+ ({ value }) => {
705
+ const newValues = virtualValues.filter((item) => item.value !== value);
706
+ updateVirtualValues(newValues);
707
+ },
708
+ [virtualValues, updateVirtualValues]
709
+ );
710
+ const onAddItem = React.useCallback(() => {
711
+ const id$1 = id.getUUID();
712
+ const newValues = [
713
+ ...virtualValues,
714
+ { value: id$1, color: getRandomColor(), label: ``, ordinal: virtualValues.length }
715
+ ];
716
+ updateVirtualValues(newValues);
717
+ if (dispatch) {
718
+ dispatch({ type: "add", prev: null, next: newValues[newValues.length - 1] });
719
+ }
720
+ }, [virtualValues, updateVirtualValues, dispatch]);
721
+ const onDragEnd = ({ active, over }) => {
722
+ if (active && over && active.id !== over.id) {
723
+ const activeIndex = virtualValues.findIndex((i) => i.value === active.id);
724
+ const overIndex = virtualValues.findIndex((i) => i.value === over.id);
725
+ const newValues = sortable.arrayMove(virtualValues, activeIndex, overIndex);
726
+ updateVirtualValues(newValues);
727
+ }
728
+ };
729
+ const sensors = core$2.useSensors(
730
+ core$2.useSensor(core$2.PointerSensor),
731
+ core$2.useSensor(core$2.KeyboardSensor, {
732
+ // Disable smooth scrolling in Cypress automated tests
733
+ scrollBehavior: "Cypress" in window ? "auto" : void 0,
734
+ coordinateGetter: sortable.sortableKeyboardCoordinates
735
+ })
736
+ );
737
+ const onEnterKeyUp = React.useCallback(
738
+ (value) => {
739
+ const { value: valueId } = value;
740
+ const last = virtualValues[virtualValues.length - 1];
741
+ if (last && last.value === valueId) onAddItem();
742
+ lastInputNeedFocus.current = true;
743
+ },
744
+ [onAddItem, virtualValues]
745
+ );
746
+ React.useEffect(() => {
747
+ if (lastInputNeedFocus.current) {
748
+ const lastValue = virtualValues[virtualValues.length - 1];
749
+ const lastInput = inputRefs.current[lastValue.ordinal];
750
+ if (lastInput) lastInput.focusInput();
751
+ lastInputNeedFocus.current = false;
752
+ }
753
+ }, [virtualValues]);
754
+ return /* @__PURE__ */ React.createElement(antd.Space, { direction: "vertical", className: "option-editor", style: { ...style } }, /* @__PURE__ */ React.createElement(antd.Flex, { className: `option-editor-title` }, /* @__PURE__ */ React.createElement(antd.Button, { type: "text", onClick: onAddItem, disabled }, /* @__PURE__ */ React.createElement(icons.PlusOutlined, null), "\u6DFB\u52A0\u9009\u9879")), /* @__PURE__ */ React.createElement(
755
+ core$2.DndContext,
756
+ {
757
+ onDragEnd,
758
+ sensors: disabled ? [] : sensors,
759
+ modifiers: [modifiers.restrictToVerticalAxis],
760
+ id: "list-drag-sorting-handler"
761
+ },
762
+ /* @__PURE__ */ React.createElement(sortable.SortableContext, { items: virtualValues.map((item) => item.value), strategy: sortable.verticalListSortingStrategy }, /* @__PURE__ */ React.createElement(
763
+ VirtualList,
764
+ {
765
+ className: "option-editor-list",
766
+ width: "100%",
767
+ height: virtualConfig.height ?? 600,
768
+ overscanCount: 10,
769
+ itemCount: virtualValues.length,
770
+ itemSize: 40,
771
+ scrollDirection: "vertical",
772
+ renderItem: (item) => {
773
+ const value = virtualValues[item.index];
774
+ return /* @__PURE__ */ React.createElement(
775
+ OptionItem,
776
+ {
777
+ ref: (e) => {
778
+ inputRefs.current[item.index] = e;
779
+ },
780
+ value,
781
+ dispatch,
782
+ onChange: onItemChange,
783
+ onRemove: onItemRemove,
784
+ style: item.style,
785
+ onEnterKeyUp: () => onEnterKeyUp(value),
786
+ key: value.value,
787
+ disabled
788
+ }
789
+ );
790
+ }
791
+ }
792
+ ))
793
+ ));
794
+ };
795
+
796
+ const OptionInput = ({
797
+ option,
798
+ optionPosition,
799
+ inputValue,
800
+ setInputValue,
801
+ updateOptionLabel
802
+ }) => {
803
+ const [isColorPickerOpen, setIsColorPickerOpen] = React.useState(false);
804
+ const inputRef = React.useRef(null);
805
+ reactHooks.useMount(() => {
806
+ inputRef.current?.focus();
807
+ });
808
+ return /* @__PURE__ */ React.createElement(
809
+ antd.Input,
810
+ {
811
+ type: "text",
812
+ ref: inputRef,
813
+ onClick: (e) => e.stopPropagation(),
814
+ style: { width: optionPosition.width, height: optionPosition.height },
815
+ suffix: /* @__PURE__ */ React.createElement(
816
+ "span",
817
+ {
818
+ onClick: (e) => {
819
+ e.stopPropagation();
820
+ }
821
+ },
822
+ /* @__PURE__ */ React.createElement(
823
+ FixedColorPicker,
824
+ {
825
+ value: option.color,
826
+ open: isColorPickerOpen,
827
+ rootClassName: "selector-color-picker",
828
+ onOpenChange: (value) => {
829
+ setIsColorPickerOpen(value);
830
+ },
831
+ onChange: (newColor) => {
832
+ setIsColorPickerOpen(false);
833
+ updateOptionLabel(inputValue, newColor.toHexString());
834
+ }
835
+ }
836
+ )
837
+ ),
838
+ value: inputValue,
839
+ onPressEnter: () => updateOptionLabel(inputValue),
840
+ onChange: (e) => setInputValue(e.target.value)
841
+ }
842
+ );
843
+ };
844
+
845
+ const COLOR_BG_OPTION_HOVER = "#1f232914";
846
+ const SelectOptionItem = ({
847
+ editValue,
848
+ option,
849
+ multiple = true,
850
+ onCreate,
851
+ onChange,
852
+ filterOptions,
853
+ onOptionChange,
854
+ onSelect,
855
+ fontSize = 13,
856
+ style
857
+ }) => {
858
+ const [isEdit, setIsEdit] = React.useState(false);
859
+ const [inputValue, setInputValue] = React.useState(option.label);
860
+ const [isHovered, setIsHovered] = React.useState(false);
861
+ const containerRef = React.useRef(null);
862
+ const [loading, setLoading] = React.useState(false);
863
+ const loadingRef = React.useRef(false);
864
+ const isExist = React.useMemo(
865
+ () => filterOptions.some((item) => inputValue.trim().toLowerCase() === item.label.toLowerCase()),
866
+ [filterOptions, inputValue]
867
+ );
868
+ const [optionPosition, setOptionPosition] = React.useState({
869
+ x: 0,
870
+ y: 0,
871
+ width: 0,
872
+ height: 0
873
+ });
874
+ const isSelected = React.useMemo(() => editValue.map((item) => item.value).includes(option.value), [editValue, option]);
875
+ const handleClose = React.useCallback(() => {
876
+ setIsEdit(false);
877
+ }, []);
878
+ const updateOptionLabel = (newLabel, newColor) => {
879
+ setIsEdit(false);
880
+ onOptionChange?.({ ...option, label: newLabel, color: newColor || option.color });
881
+ };
882
+ const createOptionLabel = () => {
883
+ if (!onCreate) {
884
+ handleItemSelect(option);
885
+ return;
886
+ }
887
+ if (loadingRef.current) return;
888
+ setLoading(true);
889
+ loadingRef.current = true;
890
+ onCreate(option).then((newOption) => {
891
+ handleItemSelect(newOption);
892
+ }).finally(() => {
893
+ setLoading(false);
894
+ loadingRef.current = false;
895
+ });
896
+ };
897
+ const handleItemSelect = React.useCallback(
898
+ (option2) => {
899
+ if (multiple) {
900
+ const newSelected = isSelected ? editValue : [...editValue, option2];
901
+ onChange?.(newSelected);
902
+ } else {
903
+ onChange?.([option2]);
904
+ }
905
+ onSelect?.(option2);
906
+ },
907
+ [multiple, onSelect, isSelected, editValue, onChange]
908
+ );
909
+ return /* @__PURE__ */ React.createElement(antd.Flex, { style: { padding: "0px 16px 0px 4px", ...style } }, /* @__PURE__ */ React.createElement(
910
+ antd.Flex,
911
+ {
912
+ ref: containerRef,
913
+ className: "option-item",
914
+ onMouseEnter: (e) => {
915
+ setIsHovered(true);
916
+ e.currentTarget.style.backgroundColor = COLOR_BG_OPTION_HOVER;
917
+ },
918
+ onMouseLeave: (e) => {
919
+ setIsHovered(false);
920
+ e.currentTarget.style.backgroundColor = "transparent";
921
+ },
922
+ onClick: () => {
923
+ if (!isExist) return createOptionLabel();
924
+ handleItemSelect(option);
925
+ }
926
+ },
927
+ !isExist ? /* @__PURE__ */ React.createElement(antd.Flex, { gap: 8, style: { width: "100%" } }, /* @__PURE__ */ React.createElement(antd.Spin, { spinning: loading }, /* @__PURE__ */ React.createElement(antd.Typography.Text, null, "\u521B\u5EFA\u9009\u9879"), /* @__PURE__ */ React.createElement(antd.Typography.Text, { strong: true }, option.label))) : /* @__PURE__ */ React.createElement(antd.Flex, { justify: "space-between", align: "center", style: { width: "100%" } }, /* @__PURE__ */ React.createElement(CustomTag, { color: option.color, label: option.label, fontSize }), isHovered && /* @__PURE__ */ React.createElement(
928
+ antd.Button,
929
+ {
930
+ className: "edit-button",
931
+ type: "text",
932
+ icon: /* @__PURE__ */ React.createElement(icons.EllipsisOutlined, { className: "edit-icon" }),
933
+ style: { width: 22, height: 22, marginRight: 8 },
934
+ onClick: (e) => {
935
+ e.stopPropagation();
936
+ setIsEdit(true);
937
+ setOptionPosition({
938
+ x: containerRef.current.getBoundingClientRect().left,
939
+ y: containerRef.current.getBoundingClientRect().top,
940
+ width: containerRef.current.getBoundingClientRect().width,
941
+ height: containerRef.current.getBoundingClientRect().height
942
+ });
943
+ }
944
+ }
945
+ ))
946
+ ), /* @__PURE__ */ React.createElement(
947
+ antd.Modal,
948
+ {
949
+ title: "",
950
+ afterClose: handleClose,
951
+ rootClassName: "option-item-modal",
952
+ open: isEdit,
953
+ footer: null,
954
+ width: optionPosition.width,
955
+ maskTransitionName: "",
956
+ transitionName: "",
957
+ closable: false,
958
+ maskClosable: true,
959
+ onCancel: () => updateOptionLabel(inputValue),
960
+ style: { top: optionPosition.y, left: optionPosition.x, transformOrigin: "top left", margin: "unset" }
961
+ },
962
+ /* @__PURE__ */ React.createElement(
963
+ OptionInput,
964
+ {
965
+ option,
966
+ optionPosition,
967
+ inputValue,
968
+ setInputValue,
969
+ updateOptionLabel
970
+ }
971
+ )
972
+ ));
973
+ };
974
+
975
+ const BORDER_SECONDARY_COLOR = "#f0f0f0";
976
+ const PopoverContent = ({
977
+ editValue,
978
+ popoverRef,
979
+ inputRef,
980
+ open,
981
+ width,
982
+ searchText,
983
+ filteredOptions,
984
+ listHeight,
985
+ itemHeight,
986
+ multiple,
987
+ handleSearch,
988
+ onChange,
989
+ onSelect,
990
+ onCreate,
991
+ onOptionChange,
992
+ fontSize
993
+ }) => {
994
+ const canCreate = React.useMemo(() => {
995
+ if (!searchText.trim()) return false;
996
+ const lowerSearch = searchText.trim().toLowerCase();
997
+ const res = filteredOptions.some((item) => item.label.toLowerCase() === lowerSearch);
998
+ return !res;
999
+ }, [filteredOptions, searchText]);
1000
+ const newOption = React.useMemo(() => {
1001
+ if (canCreate) {
1002
+ return { value: id.getUUID(), label: searchText, color: getRandomColor() };
1003
+ }
1004
+ return null;
1005
+ }, [searchText, canCreate]);
1006
+ React.useEffect(() => {
1007
+ if (open) {
1008
+ inputRef.current?.focus();
1009
+ }
1010
+ }, [open, inputRef]);
1011
+ return /* @__PURE__ */ React.createElement(
1012
+ "div",
1013
+ {
1014
+ ref: popoverRef,
1015
+ className: "select-editor-popover-content",
1016
+ style: {
1017
+ width
1018
+ }
1019
+ },
1020
+ /* @__PURE__ */ React.createElement("div", { style: { border: "none" } }, /* @__PURE__ */ React.createElement(
1021
+ antd.Input,
1022
+ {
1023
+ ref: inputRef,
1024
+ placeholder: "\u67E5\u627E\u6216\u521B\u5EFA\u9009\u9879",
1025
+ autoFocus: true,
1026
+ value: searchText,
1027
+ onChange: handleSearch,
1028
+ contentEditable: true
1029
+ }
1030
+ )),
1031
+ /* @__PURE__ */ React.createElement(
1032
+ "div",
1033
+ {
1034
+ className: "virtual-list-container",
1035
+ style: {
1036
+ height: listHeight,
1037
+ overflow: "hidden",
1038
+ borderTop: `1px solid ${BORDER_SECONDARY_COLOR}`
1039
+ }
1040
+ },
1041
+ /* @__PURE__ */ React.createElement(
1042
+ VirtualList,
1043
+ {
1044
+ width: "100%",
1045
+ height: listHeight,
1046
+ itemCount: !canCreate ? filteredOptions.length : filteredOptions.length + 1,
1047
+ itemSize: itemHeight,
1048
+ renderItem: ({ index, style }) => /* @__PURE__ */ React.createElement(
1049
+ SelectOptionItem,
1050
+ {
1051
+ filterOptions: filteredOptions,
1052
+ editValue,
1053
+ option: filteredOptions[index] ?? newOption,
1054
+ style,
1055
+ key: filteredOptions[index]?.value ?? newOption?.value,
1056
+ multiple,
1057
+ fontSize,
1058
+ onCreate,
1059
+ onChange,
1060
+ onSelect,
1061
+ onOptionChange
1062
+ }
1063
+ ),
1064
+ overscanCount: 5,
1065
+ style: { outline: "none" }
1066
+ }
1067
+ )
1068
+ )
1069
+ );
1070
+ };
1071
+
1072
+ const Select = ({
1073
+ listHeight = 300,
1074
+ itemHeight = 32,
1075
+ emptyText = "\u6682\u65E0\u6570\u636E",
1076
+ multiple = true,
1077
+ options = [],
1078
+ value: editValue = [],
1079
+ placeholder,
1080
+ width,
1081
+ onChange,
1082
+ onSelect,
1083
+ onOptionChange,
1084
+ onOptionCreate,
1085
+ fontSize = 13,
1086
+ onDeselect,
1087
+ tagAreaHeight,
1088
+ tagAreaStyle,
1089
+ showDownIcon = false
1090
+ }) => {
1091
+ const [searchText, setSearchText] = React.useState("");
1092
+ const popoverRef = React.useRef(null);
1093
+ const cellRef = React.useRef(null);
1094
+ const [open, setOpen] = React.useState(false);
1095
+ const inputRef = React.useRef(null);
1096
+ const filteredOptions = React.useMemo(() => {
1097
+ if (!searchText.trim()) return options;
1098
+ const lowerSearch = searchText.toLowerCase();
1099
+ const findOptions = options.filter((item) => item.label.toLowerCase().includes(lowerSearch));
1100
+ return findOptions;
1101
+ }, [options, searchText]);
1102
+ const selectedValue = React.useMemo(() => {
1103
+ if (!editValue.length) return [];
1104
+ const findItem = (item) => options.find((opt) => opt.value === item.value);
1105
+ return editValue.map((item) => findItem(item)).filter(Boolean);
1106
+ }, [editValue, options]);
1107
+ const handleCreate = async (option) => {
1108
+ const newOption = await onOptionCreate?.(option) ?? option;
1109
+ setSearchText("");
1110
+ return newOption;
1111
+ };
1112
+ const handleSearch = (e) => {
1113
+ setSearchText(e.target.value);
1114
+ };
1115
+ const handleSelect = (option) => {
1116
+ onSelect?.(option);
1117
+ if (inputRef.current) {
1118
+ inputRef.current.focus();
1119
+ }
1120
+ if (cellRef.current && !multiple) {
1121
+ cellRef.current.click();
1122
+ }
1123
+ };
1124
+ const handleDeselect = (option) => {
1125
+ setOpen(false);
1126
+ onDeselect?.(option);
1127
+ const filteredValue = editValue.filter((item) => item.value !== option.value);
1128
+ onChange?.(filteredValue);
1129
+ };
1130
+ React.useEffect(() => {
1131
+ if (cellRef.current) {
1132
+ cellRef.current.scrollTop = cellRef.current.scrollHeight;
1133
+ }
1134
+ }, [selectedValue]);
1135
+ return /* @__PURE__ */ React.createElement(
1136
+ antd.Popover,
1137
+ {
1138
+ trigger: "click",
1139
+ open,
1140
+ onOpenChange: setOpen,
1141
+ destroyOnHidden: true,
1142
+ content: /* @__PURE__ */ React.createElement(
1143
+ PopoverContent,
1144
+ {
1145
+ editValue: selectedValue,
1146
+ onChange,
1147
+ popoverRef,
1148
+ inputRef,
1149
+ width: width || 163,
1150
+ open,
1151
+ filteredOptions,
1152
+ searchText,
1153
+ handleSearch,
1154
+ listHeight,
1155
+ itemHeight,
1156
+ emptyText,
1157
+ multiple,
1158
+ onSelect: handleSelect,
1159
+ onCreate: handleCreate,
1160
+ onOptionChange,
1161
+ fontSize
1162
+ }
1163
+ ),
1164
+ rootClassName: "multi-select-editor-popover-root",
1165
+ className: "multi-select-editor-popover",
1166
+ arrow: false,
1167
+ align: {
1168
+ points: ["tl", "bl"],
1169
+ // tl(top-left): 将【pop弹窗】左上角 与 Input bl(bottom-left) 左下角对齐
1170
+ offset: [0, 10]
1171
+ }
1172
+ },
1173
+ /* @__PURE__ */ React.createElement(
1174
+ "div",
1175
+ {
1176
+ style: {
1177
+ maxHeight: 80,
1178
+ padding: "4px 0px 4px 8px",
1179
+ overflowY: "hidden",
1180
+ ...tagAreaStyle
1181
+ },
1182
+ className: "tag-area",
1183
+ onClick: (e) => {
1184
+ e.stopPropagation();
1185
+ e.preventDefault();
1186
+ }
1187
+ },
1188
+ /* @__PURE__ */ React.createElement(
1189
+ "div",
1190
+ {
1191
+ ref: cellRef,
1192
+ className: "tag-area-content",
1193
+ style: {
1194
+ minHeight: tagAreaHeight ? tagAreaHeight + 4 - 8 - 4 : "unset",
1195
+ maxHeight: 80 - 8 - 4,
1196
+ overflowY: "auto"
1197
+ }
1198
+ },
1199
+ placeholder && !selectedValue.length ? /* @__PURE__ */ React.createElement("div", { className: "placeholder" }, placeholder) : /* @__PURE__ */ React.createElement(antd.Flex, { gap: 8, align: "flex-start", style: { width: "100%" } }, /* @__PURE__ */ React.createElement(antd.Flex, { gap: 8, wrap: true, style: { width: showDownIcon ? "calc(100% - 32px)" : "100%" } }, selectedValue?.map((selectedItem) => /* @__PURE__ */ React.createElement(
1200
+ CustomTag,
1201
+ {
1202
+ label: selectedItem.label,
1203
+ color: selectedItem.color,
1204
+ key: selectedItem.value,
1205
+ closable: true,
1206
+ onClose: () => handleDeselect(selectedItem),
1207
+ fontSize
1208
+ }
1209
+ ))), showDownIcon && /* @__PURE__ */ React.createElement("div", { className: "icon-occupy" }))
1210
+ ),
1211
+ showDownIcon && /* @__PURE__ */ React.createElement(
1212
+ icons.CaretDownOutlined,
1213
+ {
1214
+ className: "caret-down-icon",
1215
+ style: { position: "absolute", right: 4, top: tagAreaHeight ? tagAreaHeight / 2 - 8 : 0 }
1216
+ }
1217
+ )
1218
+ )
1219
+ );
1220
+ };
1221
+
1222
+ const computeSHA256 = async (file) => {
1223
+ const buffer = await file.arrayBuffer();
1224
+ const wordArray = CryptoJS.lib.WordArray.create(buffer);
1225
+ const hash = CryptoJS.SHA256(wordArray);
1226
+ return hash.toString(CryptoJS.enc.Hex);
1227
+ };
1228
+
1229
+ const UploadListInner = (props) => {
1230
+ const {
1231
+ maxCount = 1,
1232
+ fileList: initialFileList = [],
1233
+ uploadProps,
1234
+ onChange,
1235
+ onPreview,
1236
+ accept,
1237
+ onRemove,
1238
+ beforeUpload,
1239
+ uploadFunction,
1240
+ disabled
1241
+ } = props;
1242
+ const [fileList, setFileList] = React.useState(initialFileList);
1243
+ return /* @__PURE__ */ React.createElement(
1244
+ antd.Upload,
1245
+ {
1246
+ name: "file",
1247
+ customRequest: async (options) => {
1248
+ const { file: fileInner, onSuccess, onError, onProgress } = options;
1249
+ const file = fileInner;
1250
+ try {
1251
+ const hash = await computeSHA256(file);
1252
+ const path = `upload/${hash}/${file.name}`;
1253
+ await uploadFunction({ file, type: file.type || "application/octet-stream" }, path, ({ percent }) => {
1254
+ onProgress?.({ percent });
1255
+ });
1256
+ onSuccess?.(path);
1257
+ } catch (err) {
1258
+ onError?.(err);
1259
+ }
1260
+ },
1261
+ fileList,
1262
+ onChange: (info) => {
1263
+ const newFileList = info.fileList.map((i) => {
1264
+ if (i.status === "done" && i.response) {
1265
+ return {
1266
+ ...i,
1267
+ url: i.response
1268
+ };
1269
+ }
1270
+ return i;
1271
+ });
1272
+ setFileList(newFileList);
1273
+ onChange?.(info);
1274
+ },
1275
+ onRemove: (file) => {
1276
+ const newFileList = fileList.filter((i) => i.uid !== file.uid);
1277
+ setFileList(newFileList);
1278
+ onRemove?.(file);
1279
+ },
1280
+ onPreview: (file) => {
1281
+ onPreview?.({
1282
+ name: file.name,
1283
+ path: file.url || ""
1284
+ });
1285
+ },
1286
+ maxCount,
1287
+ ...uploadProps,
1288
+ accept,
1289
+ beforeUpload
1290
+ },
1291
+ /* @__PURE__ */ React.createElement(antd.Button, { icon: /* @__PURE__ */ React.createElement(icons.UploadOutlined, null), disabled: disabled ? true : maxCount <= (fileList?.length || 0) }, "\u4E0A\u4F20")
1292
+ );
1293
+ };
1294
+
1295
+ const UploadList = ({
1296
+ onlyOne,
1297
+ value,
1298
+ accept = "",
1299
+ maxCount = 5,
1300
+ onChange,
1301
+ onPreview,
1302
+ uploadFunction,
1303
+ uploadProps,
1304
+ disabled
1305
+ }) => {
1306
+ const fileList = React.useMemo(() => {
1307
+ if (onlyOne) {
1308
+ if (!value || !value.length) return [];
1309
+ const fileName = value[0].name;
1310
+ return [
1311
+ {
1312
+ uid: "0",
1313
+ name: fileName,
1314
+ status: "done",
1315
+ url: value[0].path
1316
+ }
1317
+ ];
1318
+ } else {
1319
+ if (!value || !value.length) return [];
1320
+ return value.map((i, index) => {
1321
+ const fileName = i.name;
1322
+ return {
1323
+ uid: index.toString(),
1324
+ name: fileName,
1325
+ status: "done",
1326
+ url: i.path
1327
+ };
1328
+ });
1329
+ }
1330
+ }, [value, onlyOne]);
1331
+ const handleChange = (info) => {
1332
+ const { fileList: newFileList } = info;
1333
+ const files = [];
1334
+ newFileList.forEach((i) => {
1335
+ if (i.status === "done" && i.response) {
1336
+ files.push({
1337
+ name: i.name,
1338
+ path: i.response
1339
+ });
1340
+ } else if (i.status === "done" && i.url) {
1341
+ files.push({
1342
+ name: i.name,
1343
+ path: i.url || ""
1344
+ });
1345
+ }
1346
+ return i;
1347
+ });
1348
+ onChange?.(files);
1349
+ };
1350
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
1351
+ UploadListInner,
1352
+ {
1353
+ uploadProps,
1354
+ maxCount,
1355
+ fileList,
1356
+ onChange: handleChange,
1357
+ onPreview,
1358
+ uploadFunction,
1359
+ accept,
1360
+ disabled
1361
+ }
1362
+ ));
1363
+ };
1364
+
1365
+ exports.AvatarPopoverContent = AvatarPopoverContent;
1366
+ exports.BORDER_SECONDARY_COLOR = BORDER_SECONDARY_COLOR;
1367
+ exports.BlinkButton = BlinkButton;
1368
+ exports.COLOR_BG_OPTION_HOVER = COLOR_BG_OPTION_HOVER;
1369
+ exports.ColorCheckboxGroup = ColorCheckboxGroup;
1370
+ exports.ColorRadioGroup = ColorRadioGroup;
1371
+ exports.CustomTag = CustomTag;
1372
+ exports.FixedColorPicker = FixedColorPicker;
1373
+ exports.IconFont = IconFont;
1374
+ exports.LinkEdit = LinkEdit;
1375
+ exports.OptionEditor = OptionEditor;
1376
+ exports.OptionInput = OptionInput;
1377
+ exports.OptionItem = OptionItem;
1378
+ exports.PopoverContent = PopoverContent;
1379
+ exports.Select = Select;
1380
+ exports.SelectOptionItem = SelectOptionItem;
1381
+ exports.UploadList = UploadList;
1382
+ exports.UploadListInner = UploadListInner;
1383
+ exports.UserLoadingSkeleton = UserLoadingSkeleton;
1384
+ exports.computeSHA256 = computeSHA256;
1385
+ exports.focusToEnd = focusToEnd;
1386
+ exports.getRandomColor = getRandomColor;
1387
+ exports.isFocused = isFocused;