@enableai-base/form 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.
@@ -0,0 +1,710 @@
1
+ /**
2
+ * @enableai-base/form v1.0.0
3
+ * (c) 2024-present Enableai
4
+ * @license Proprietary
5
+ **/
6
+ import React, { useMemo, useState, useEffect, useCallback, useRef, useImperativeHandle, forwardRef } from 'react';
7
+ import { Divider, Flex, Select, DatePicker, Input, Spin, Form, Button, Switch, Popover } from 'antd';
8
+ import { ProFormItem, ProForm } from '@ant-design/pro-components';
9
+ import { OptionEditor, IconFont, BlinkButton } from '@enableai-base/ui';
10
+ import { useMount, useDebounce } from '@enableai-sdk-common/react-hooks';
11
+ import { isEqual } from 'lodash';
12
+ import dayjs from 'dayjs';
13
+ import ReactMonacoEditor, { loader } from '@monaco-editor/react';
14
+ import { formatValue, TOOL_ICON, parseDateFormat, inferShowTimeFromFormat, TZ_LABEL } from '@enableai-base/core';
15
+ import { RightOutlined } from '@ant-design/icons';
16
+ import timezone from 'dayjs/plugin/timezone';
17
+ import utc from 'dayjs/plugin/utc';
18
+ import { BaseModal } from '@enableai-sdk-ui/base-modal';
19
+
20
+ const FeatureCustomOptions = ({ features, onChange, freeze }) => {
21
+ useMount(() => {
22
+ if (!features.options) onChange({ options: [] });
23
+ });
24
+ const initialValues = useMemo(() => {
25
+ return Array.isArray(features?.options) ? features?.options : [];
26
+ }, [features?.options]);
27
+ const [height, setHeight] = useState(0);
28
+ useEffect(() => {
29
+ const initHeight = initialValues.length >= 4 ? 160 : initialValues.length * 40;
30
+ if (height !== initHeight) {
31
+ setHeight(initHeight);
32
+ }
33
+ }, [height, initialValues, setHeight]);
34
+ const debounceChange = useDebounce(onChange, 500);
35
+ const onValuesChange = (values) => {
36
+ if (values.length === initialValues.length) {
37
+ debounceChange({ options: values });
38
+ } else {
39
+ onChange({ options: values });
40
+ }
41
+ };
42
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Divider, { className: "custom-form-divider" }), /* @__PURE__ */ React.createElement(ProFormItem, { className: "custom-form-item", key: "options", name: "options", label: "\u9009\u9879\u5185\u5BB9" }), /* @__PURE__ */ React.createElement(Flex, { className: "custom-options-container" }, /* @__PURE__ */ React.createElement(
43
+ OptionEditor,
44
+ {
45
+ initialValues,
46
+ onValuesChange,
47
+ virtualConfig: { height },
48
+ disabled: freeze
49
+ }
50
+ )));
51
+ };
52
+
53
+ const FeatureDateFormat = ({ features, onChange }) => {
54
+ useMount(() => {
55
+ if (!features.dateFormat) onChange({ dateFormat: "YYYY/MM/DD" });
56
+ });
57
+ return /* @__PURE__ */ React.createElement(ProFormItem, { key: "dateFormat", name: "dateFormat", label: "\u65E5\u671F\u683C\u5F0F" }, /* @__PURE__ */ React.createElement(
58
+ Select,
59
+ {
60
+ style: { width: "100%" },
61
+ options: [
62
+ { label: "2025/01/30", value: "YYYY/MM/DD" },
63
+ { label: "2025/01/30 14:00 (GMT+8)", value: "YYYY/MM/DD HH:mm (GMT+8)" },
64
+ { label: "2025/01/30 14:00", value: "YYYY/MM/DD HH:mm" },
65
+ { label: "2025-01-30", value: "YYYY-MM-DD" },
66
+ { label: "2025-01-30 14:00", value: "YYYY-MM-DD HH:mm" },
67
+ { label: "2025-01-30 14:00 (GMT+8)", value: "YYYY-MM-DD HH:mm (GMT+8)" },
68
+ { label: "01-30", value: "MM-DD" },
69
+ { label: "30/01/2025", value: "DD/MM/YYYY" },
70
+ { label: "01/30/2025", value: "MM/DD/YYYY" }
71
+ ]
72
+ }
73
+ ));
74
+ };
75
+
76
+ const CustomDatePickerV2 = ({ formatType, onChangeDate }) => {
77
+ const hasGMTLabel = formatType?.includes("GMT+");
78
+ const GMTLabel = "GMT+8";
79
+ const pureFormat = formatType?.replace(` (GMT+8)`, "") ?? "YYYY-MM-DD";
80
+ const customFormat = (value) => {
81
+ return `${value.format(pureFormat)}${hasGMTLabel ? ` (${GMTLabel})` : ""} `;
82
+ };
83
+ return /* @__PURE__ */ React.createElement(
84
+ DatePicker,
85
+ {
86
+ style: { width: "100%" },
87
+ className: "column-setting-date-picker",
88
+ showTime: pureFormat.includes("HH:mm") ? { format: pureFormat } : false,
89
+ format: customFormat,
90
+ key: "datePicker",
91
+ placement: "bottomLeft",
92
+ onChange: (date) => {
93
+ if (date) {
94
+ onChangeDate(date);
95
+ }
96
+ },
97
+ onOk: (date) => {
98
+ if (date) {
99
+ onChangeDate(date);
100
+ }
101
+ }
102
+ }
103
+ );
104
+ };
105
+
106
+ const CREATE_DATE$1 = "record_create_date";
107
+ const FeatureDefaultDateV2 = ({ features, onChange }) => {
108
+ const formatType = features?.dateFormat || "YYYY/MM/DD";
109
+ const initialValue = features?.defaultValue;
110
+ const isCreateDate = initialValue === CREATE_DATE$1;
111
+ const [date, setDate] = useState(null);
112
+ const debouncedOnChange = useDebounce(onChange);
113
+ const onChangeDate = useCallback(
114
+ (selected) => {
115
+ const time = selected.format(formatType);
116
+ setDate(selected);
117
+ debouncedOnChange({ defaultValue: time });
118
+ },
119
+ [formatType, debouncedOnChange]
120
+ );
121
+ useEffect(() => {
122
+ if (isCreateDate) return;
123
+ let dateValue = "";
124
+ if (!date) {
125
+ const date2 = dayjs(initialValue + "");
126
+ dateValue = date2.format(formatType);
127
+ } else {
128
+ dateValue = date.format(formatType);
129
+ }
130
+ if (dateValue === "Invalid Date") {
131
+ onChange({ defaultValue: void 0 });
132
+ } else if (dateValue !== initialValue) {
133
+ onChange({ defaultValue: dateValue });
134
+ }
135
+ }, [formatType]);
136
+ useEffect(() => {
137
+ return () => {
138
+ onChange({ defaultValue: "" });
139
+ };
140
+ }, []);
141
+ return /* @__PURE__ */ React.createElement(ProFormItem, { key: "defaultValue", name: "defaultValue", label: "\u9ED8\u8BA4\u503C" }, /* @__PURE__ */ React.createElement(CustomDatePickerV2, { onChangeDate, formatType }));
142
+ };
143
+
144
+ const FeatureDefaultInput = ({ onChange }) => {
145
+ useEffect(() => {
146
+ return () => {
147
+ onChange({ defaultValue: void 0 });
148
+ };
149
+ }, []);
150
+ return /* @__PURE__ */ React.createElement(ProFormItem, { key: "defaultValue", name: "defaultValue", label: "\u9ED8\u8BA4\u503C" }, /* @__PURE__ */ React.createElement(Input, { placeholder: "\u8BF7\u8F93\u5165\u5185\u5BB9" }));
151
+ };
152
+
153
+ loader.config({
154
+ paths: {
155
+ // vs: '/monaco-assets/vs',
156
+ }
157
+ // 'vs/nls': { availableLanguages: { '*': 'zh-cn' } },
158
+ });
159
+ const FeatureDefaultJson = ({ features, onChange }) => {
160
+ const initialValue = features?.defaultValue;
161
+ const monacoEditorRef = useRef(null);
162
+ const monacoRef = useRef(null);
163
+ useEffect(() => {
164
+ return () => {
165
+ onChange({ defaultValue: void 0 });
166
+ };
167
+ }, []);
168
+ const format = () => {
169
+ monacoEditorRef.current?.getAction("editor.action.formatDocument")?.run();
170
+ };
171
+ return /* @__PURE__ */ React.createElement(ProFormItem, { key: "defaultValue", name: "defaultValue", label: "\u9ED8\u8BA4\u503C" }, /* @__PURE__ */ React.createElement("div", { style: { position: "relative", width: "100%", height: "302px", border: "1px solid #6c6c6c" } }, /* @__PURE__ */ React.createElement(
172
+ ReactMonacoEditor,
173
+ {
174
+ height: "300px",
175
+ defaultLanguage: "json",
176
+ value: initialValue,
177
+ loading: /* @__PURE__ */ React.createElement(Spin, null),
178
+ theme: "light",
179
+ onChange: (value) => {
180
+ onChange({ defaultValue: value });
181
+ },
182
+ beforeMount: (monaco) => {
183
+ monacoRef.current = monaco;
184
+ monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
185
+ validate: true,
186
+ schemas: [
187
+ {
188
+ uri: "test-schema",
189
+ fileMatch: ["*"],
190
+ schema: {
191
+ $schema: "http://json-schema.org/draft-07/schema#",
192
+ type: "object"
193
+ }
194
+ }
195
+ ]
196
+ });
197
+ format();
198
+ },
199
+ onMount: (monacoEditor) => {
200
+ monacoEditorRef.current = monacoEditor;
201
+ format();
202
+ },
203
+ options: {
204
+ lineNumbers: "off",
205
+ minimap: { enabled: false }
206
+ }
207
+ }
208
+ )));
209
+ };
210
+
211
+ const sanitizeInput = (value) => {
212
+ let sanitized = value.replace(/[^\d.-]/g, "");
213
+ const parts = sanitized.split(".");
214
+ if (parts.length > 2) sanitized = parts[0] + "." + parts.slice(1).join("");
215
+ if (sanitized.includes("-") && sanitized.indexOf("-") > 0) sanitized = sanitized.replace(/-/g, "");
216
+ return sanitized;
217
+ };
218
+ const FeatureDefaultNumber = ({ features, onChange }) => {
219
+ const formatType = features?.numberFormat || "integer";
220
+ const initialValue = features?.defaultValue;
221
+ const [rawValue, setRawValue] = useState("");
222
+ const [displayValue, setDisplayValue] = useState("");
223
+ const [isFocused, setIsFocused] = useState(false);
224
+ const debounceOnChange = useDebounce(onChange, 300);
225
+ const onChangeInput = (e) => {
226
+ const input = sanitizeInput(e.target.value);
227
+ setRawValue(input);
228
+ debounceOnChange({ defaultValue: input });
229
+ if (isFocused) setDisplayValue(input);
230
+ };
231
+ const onFocus = () => {
232
+ setIsFocused(true);
233
+ setDisplayValue(rawValue);
234
+ };
235
+ const onBlur = () => {
236
+ setIsFocused(false);
237
+ setDisplayValue(formatValue(rawValue, formatType));
238
+ };
239
+ useEffect(() => {
240
+ if (typeof initialValue !== "string") return;
241
+ const input = sanitizeInput(initialValue);
242
+ setRawValue(input);
243
+ if (!isFocused) setDisplayValue(formatValue(input, formatType));
244
+ }, [formatType]);
245
+ useEffect(() => {
246
+ return () => {
247
+ onChange({ defaultValue: void 0 });
248
+ };
249
+ }, []);
250
+ return /* @__PURE__ */ React.createElement(ProFormItem, { key: "defaultValue", name: "defaultValue", label: "\u9ED8\u8BA4\u503C" }, /* @__PURE__ */ React.createElement(Input, { placeholder: "\u8BF7\u8F93\u5165\u6570\u5B57", value: displayValue, onChange: onChangeInput, onFocus, onBlur }));
251
+ };
252
+
253
+ const FeatureDefaultSelect = ({ tableConfig, features, onChange }) => {
254
+ const mode = useMemo(() => {
255
+ const custom = tableConfig?.customOptions;
256
+ return typeof custom === "object" && custom.multiSelect ? "multiple" : "single";
257
+ }, [tableConfig]);
258
+ const options = useMemo(
259
+ () => Array.isArray(features?.options) ? features.options.map((opt) => ({ ...opt, label: opt.label || " " })) : [],
260
+ [features?.options]
261
+ );
262
+ useEffect(() => {
263
+ const defaultValue = features?.defaultValue;
264
+ if (!defaultValue) return;
265
+ const optionIdSet = new Set(options.map((opt) => opt.value));
266
+ const resetDefault = (value) => {
267
+ onChange({ defaultValue: value });
268
+ };
269
+ if (!Array.isArray(defaultValue) || !defaultValue.every((v) => typeof v === "string")) {
270
+ return resetDefault(void 0);
271
+ }
272
+ let filtered = defaultValue.filter((id) => optionIdSet.has(id));
273
+ if (mode === "single") filtered = filtered.slice(filtered.length - 1);
274
+ if (filtered.length !== defaultValue.length) {
275
+ resetDefault(filtered);
276
+ }
277
+ }, [mode, features?.defaultValue, options, onChange]);
278
+ const handleChange = (value) => {
279
+ if (mode === "single") {
280
+ onChange({ defaultValue: value.slice(value.length - 1) });
281
+ } else {
282
+ onChange({ defaultValue: value });
283
+ }
284
+ };
285
+ useEffect(() => {
286
+ return () => {
287
+ onChange({ defaultValue: void 0 });
288
+ };
289
+ }, []);
290
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ProFormItem, { className: "custom-form-item", key: "defaultValue", name: "defaultValue", label: "\u9ED8\u8BA4\u503C" }), /* @__PURE__ */ React.createElement(
291
+ Select,
292
+ {
293
+ className: "custom-form-container",
294
+ mode: "multiple",
295
+ value: features?.defaultValue,
296
+ fieldNames: { label: "label", value: "value" },
297
+ style: { width: "100%" },
298
+ placeholder: "\u8BF7\u9009\u62E9\u9009\u9879",
299
+ onChange: handleChange,
300
+ options
301
+ }
302
+ ));
303
+ };
304
+
305
+ const FeatureDefaultField = ({ tableConfig, features, onChange }) => {
306
+ const Component = useMemo(() => {
307
+ let DefaultComponent;
308
+ if (tableConfig.customOptions) {
309
+ DefaultComponent = FeatureDefaultSelect;
310
+ } else if (tableConfig.date) {
311
+ DefaultComponent = FeatureDefaultDateV2;
312
+ } else if (tableConfig.numberSelect) {
313
+ DefaultComponent = FeatureDefaultNumber;
314
+ } else if (tableConfig.json) {
315
+ DefaultComponent = FeatureDefaultJson;
316
+ } else {
317
+ DefaultComponent = FeatureDefaultInput;
318
+ }
319
+ return DefaultComponent;
320
+ }, [tableConfig]);
321
+ return /* @__PURE__ */ React.createElement(Component, { features, onChange, tableConfig });
322
+ };
323
+
324
+ const FeatureNumberFormat = ({ features, onChange }) => {
325
+ useMount(() => {
326
+ if (!features.numberFormat) onChange({ numberFormat: "integer" });
327
+ });
328
+ return /* @__PURE__ */ React.createElement(ProFormItem, { key: "numberFormat", name: "numberFormat", label: "\u6570\u5B57\u683C\u5F0F" }, /* @__PURE__ */ React.createElement(
329
+ Select,
330
+ {
331
+ style: { width: "100%" },
332
+ options: [
333
+ {
334
+ label: "\u6574\u6570",
335
+ value: "integer"
336
+ },
337
+ {
338
+ label: "\u5343\u5206\u4F4D",
339
+ value: "thousands_separator"
340
+ },
341
+ {
342
+ label: "\u5343\u5206\u4F4D(\u5C0F\u6570\u70B9)",
343
+ value: "thousands_separator_decimal"
344
+ },
345
+ {
346
+ label: "\u4FDD\u75591\u4F4D\u5C0F\u6570",
347
+ value: "one_decimal_decimal"
348
+ },
349
+ {
350
+ label: "\u4FDD\u75592\u4F4D\u5C0F\u6570",
351
+ value: "two_decimal_decimal"
352
+ },
353
+ {
354
+ label: "\u4FDD\u75593\u4F4D\u5C0F\u6570",
355
+ value: "three_decimal_decimal"
356
+ },
357
+ {
358
+ label: "\u4FDD\u75594\u4F4D\u5C0F\u6570",
359
+ value: "four_decimal_decimal"
360
+ },
361
+ {
362
+ label: "\u4FDD\u75595\u4F4D\u5C0F\u6570",
363
+ value: "five_decimal_decimal"
364
+ },
365
+ {
366
+ label: "\u4FDD\u75596\u4F4D\u5C0F\u6570",
367
+ value: "six_decimal_decimal"
368
+ },
369
+ {
370
+ label: "\u767E\u5206\u6BD4",
371
+ value: "percentage"
372
+ },
373
+ {
374
+ label: "\u767E\u5206\u6BD4(\u5C0F\u6570\u70B9)",
375
+ value: "percentage_decimal"
376
+ }
377
+ ]
378
+ }
379
+ ));
380
+ };
381
+
382
+ const FeatureTypeSelect = ({ feature, tools, selectProps }) => {
383
+ const options = useMemo(() => {
384
+ if (!tools) return [];
385
+ return tools.map((item) => ({
386
+ ...item,
387
+ label: /* @__PURE__ */ React.createElement(Flex, { gap: 4, align: "center" }, /* @__PURE__ */ React.createElement(IconFont, { name: TOOL_ICON[item.value], size: 16, color: "#000" }), item.label)
388
+ }));
389
+ }, [tools]);
390
+ return /* @__PURE__ */ React.createElement(ProFormItem, { key: feature.name, name: feature.name, label: feature.label }, /* @__PURE__ */ React.createElement(Select, { style: { width: "100%" }, options, ...selectProps }));
391
+ };
392
+
393
+ const FeatureField = ({ features, tools, onChange, selectProps, freeze }) => {
394
+ const tableConfig = useMemo(() => {
395
+ if (!tools) return void 0;
396
+ return tools.find((item) => item.value === Number(features["type"]))?.table;
397
+ }, [features, tools]);
398
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
399
+ FeatureTypeSelect,
400
+ {
401
+ feature: { name: "type", label: "\u5B57\u6BB5\u7C7B\u578B", value: 29 },
402
+ tools,
403
+ selectProps
404
+ }
405
+ ), tableConfig?.customOptions && /* @__PURE__ */ React.createElement(FeatureCustomOptions, { features, onChange, freeze }), tableConfig?.date && /* @__PURE__ */ React.createElement(FeatureDateFormat, { features, onChange }), tableConfig?.numberSelect && /* @__PURE__ */ React.createElement(FeatureNumberFormat, { features, onChange }), tableConfig?.defaultValue && /* @__PURE__ */ React.createElement(FeatureDefaultField, { tableConfig, features, onChange }));
406
+ };
407
+
408
+ const FeatureInput = ({ feature, freeze }) => {
409
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ProFormItem, { key: feature.name, name: feature.name, label: feature.label }, /* @__PURE__ */ React.createElement(Input, { disabled: freeze })));
410
+ };
411
+
412
+ const ColumnFieldFrom = ({
413
+ formRef,
414
+ selectProps,
415
+ columnId,
416
+ tools,
417
+ initValues,
418
+ onFinish,
419
+ onCancel,
420
+ freeze,
421
+ bodyRef
422
+ }) => {
423
+ const [form] = Form.useForm();
424
+ const [fields, setFields] = useState(initValues);
425
+ const blinkRef = useRef(null);
426
+ const isModifiedRef = useRef(false);
427
+ const [loading, setLoading] = useState(false);
428
+ useEffect(() => {
429
+ form.setFieldsValue(initValues);
430
+ setFields(initValues);
431
+ }, [form, initValues]);
432
+ const onChange = (changed) => {
433
+ form.setFieldsValue(changed);
434
+ const oldValues = initValues;
435
+ const newValues = form.getFieldsValue();
436
+ setFields(newValues);
437
+ const isModified = !isEqual(newValues, oldValues);
438
+ isModifiedRef.current = isModified;
439
+ };
440
+ const onValuesChange = useDebounce(onChange, 200);
441
+ const checkChange = () => {
442
+ if (isModifiedRef.current) blinkRef.current?.blink();
443
+ return isModifiedRef.current;
444
+ };
445
+ useImperativeHandle(formRef, () => {
446
+ return {
447
+ checkChange
448
+ };
449
+ });
450
+ return /* @__PURE__ */ React.createElement(
451
+ ProForm,
452
+ {
453
+ id: columnId,
454
+ form,
455
+ className: "column-setting-form",
456
+ formKey: "column-setting-form",
457
+ style: { width: "100%" },
458
+ initialValues: initValues,
459
+ onValuesChange,
460
+ onFinish: async (values) => {
461
+ setLoading(true);
462
+ try {
463
+ return await onFinish(values);
464
+ } finally {
465
+ setLoading(false);
466
+ }
467
+ },
468
+ submitter: {
469
+ render: false
470
+ }
471
+ },
472
+ /* @__PURE__ */ React.createElement("div", { ref: bodyRef }, /* @__PURE__ */ React.createElement(
473
+ FeatureInput,
474
+ {
475
+ feature: {
476
+ name: "title",
477
+ value: " ",
478
+ label: "\u6807\u9898"
479
+ },
480
+ freeze
481
+ }
482
+ ), /* @__PURE__ */ React.createElement(FeatureField, { features: fields, tools, onChange, selectProps, freeze })),
483
+ /* @__PURE__ */ React.createElement(ProForm.Item, { className: "form-button-container footer" }, /* @__PURE__ */ React.createElement(Flex, { gap: 8, align: "center", justify: "end" }, /* @__PURE__ */ React.createElement(Button, { type: "default", disabled: loading, onClick: onCancel }, /* @__PURE__ */ React.createElement("span", null, "\u53D6\u6D88")), /* @__PURE__ */ React.createElement(BlinkButton, { type: "primary", htmlType: "submit", ref: blinkRef, loading }, /* @__PURE__ */ React.createElement("span", null, "\u786E\u8BA4"))))
484
+ );
485
+ };
486
+
487
+ const FeatureFileFormat = ({ features, onChange, freeze, type }) => {
488
+ useMount(() => {
489
+ if (!features.fileFormat) onChange({ fileFormat: "image" });
490
+ });
491
+ return /* @__PURE__ */ React.createElement(ProFormItem, { key: "fileFormat", name: "fileFormat", label: "\u9644\u4EF6\u683C\u5F0F" }, /* @__PURE__ */ React.createElement(
492
+ Select,
493
+ {
494
+ style: { width: "100%" },
495
+ disabled: freeze || type === "update",
496
+ options: [
497
+ {
498
+ label: "\u56FE\u7247",
499
+ value: "image"
500
+ },
501
+ {
502
+ label: "\u6587\u6863",
503
+ value: "document"
504
+ },
505
+ {
506
+ label: "\u89C6\u9891",
507
+ value: "video"
508
+ }
509
+ ]
510
+ }
511
+ ));
512
+ };
513
+
514
+ const FeaturePeople = ({ features, onChange }) => {
515
+ useMount(() => {
516
+ if (!features.allowMultiPeople) onChange({ allowMultiPeople: false });
517
+ });
518
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ProFormItem, { key: "allowMultiPeople", name: "allowMultiPeople", label: "\u5141\u8BB8\u6DFB\u52A0\u591A\u4E2A\u6210\u5458" }, /* @__PURE__ */ React.createElement(Switch, null)));
519
+ };
520
+
521
+ const CustomDatePicker = ({ formatType = "YYYY-MM-DD", onChangeDate }) => {
522
+ const [showDatePicker, setShowDatePicker] = useState(false);
523
+ const { baseFormat, showGmt8 } = parseDateFormat(formatType);
524
+ const showTimeConfig = inferShowTimeFromFormat(baseFormat);
525
+ return /* @__PURE__ */ React.createElement(
526
+ Popover,
527
+ {
528
+ trigger: "hover",
529
+ open: showDatePicker,
530
+ className: "date-panel-popover",
531
+ rootClassName: "date-panel-popover-root",
532
+ onOpenChange: setShowDatePicker,
533
+ placement: "right",
534
+ mouseEnterDelay: 0,
535
+ mouseLeaveDelay: 0.15,
536
+ content: /* @__PURE__ */ React.createElement(
537
+ DatePicker,
538
+ {
539
+ style: { width: formatType?.includes("HH:mm") ? "401px" : "288px" },
540
+ className: "column-setting-date-picker",
541
+ format: (date) => {
542
+ if (!date) return "";
543
+ const text = date.format(baseFormat);
544
+ return showGmt8 ? `${text} (${TZ_LABEL})` : text;
545
+ },
546
+ showTime: showTimeConfig,
547
+ key: "datePicker",
548
+ autoFocus: true,
549
+ open: true,
550
+ placement: "topRight",
551
+ getPopupContainer: (trigger) => trigger,
552
+ onChange: (date) => {
553
+ if (date) {
554
+ onChangeDate(date.format(baseFormat));
555
+ }
556
+ setShowDatePicker(false);
557
+ },
558
+ onOk: (date) => {
559
+ if (date) {
560
+ onChangeDate(date.format(baseFormat));
561
+ }
562
+ setShowDatePicker(false);
563
+ }
564
+ }
565
+ )
566
+ },
567
+ /* @__PURE__ */ React.createElement(
568
+ Flex,
569
+ {
570
+ style: { width: "100%", height: 22 },
571
+ onClick: (e) => {
572
+ e.stopPropagation();
573
+ }
574
+ },
575
+ /* @__PURE__ */ React.createElement(Flex, { style: { width: "100%", height: "100%" }, justify: "space-between" }, /* @__PURE__ */ React.createElement("div", null, "\u8BF7\u9009\u62E9\u5177\u4F53\u65E5\u671F"), /* @__PURE__ */ React.createElement(RightOutlined, null))
576
+ )
577
+ );
578
+ };
579
+
580
+ const CREATE_DATE = "record_create_date";
581
+ const FeatureDefaultDate = ({ features, onChange }) => {
582
+ const formatType = features?.dateFormat || "YYYY/MM/DD";
583
+ const initialValue = features?.defaultValue;
584
+ const isCreateDate = initialValue === CREATE_DATE;
585
+ const [date, setDate] = useState(null);
586
+ const [value, setValue] = useState(void 0);
587
+ const [open, setOpen] = useState(false);
588
+ const { showGmt8, baseFormat } = parseDateFormat(formatType);
589
+ const debouncedOnChange = useDebounce(onChange);
590
+ const onChangeDate = useCallback(
591
+ (selected) => {
592
+ setDate(dayjs(selected));
593
+ setValue(selected);
594
+ setOpen(false);
595
+ debouncedOnChange({ defaultValue: selected });
596
+ },
597
+ [debouncedOnChange]
598
+ );
599
+ useEffect(() => {
600
+ if (isCreateDate) return;
601
+ let dateValue = "";
602
+ if (!date) {
603
+ const date2 = dayjs(initialValue + "");
604
+ dateValue = date2.format(baseFormat);
605
+ } else {
606
+ dateValue = date.format(baseFormat);
607
+ }
608
+ if (dateValue === "Invalid Date") {
609
+ onChange({ defaultValue: void 0 });
610
+ } else if (dateValue !== initialValue) {
611
+ onChange({ defaultValue: dateValue });
612
+ setValue(dateValue);
613
+ }
614
+ }, [baseFormat]);
615
+ const handleSelectChange = (value2) => {
616
+ if (value2 === CREATE_DATE) {
617
+ setValue(value2);
618
+ setOpen(false);
619
+ }
620
+ };
621
+ useEffect(() => {
622
+ return () => {
623
+ onChange({ defaultValue: "" });
624
+ };
625
+ }, []);
626
+ return /* @__PURE__ */ React.createElement(ProFormItem, { key: "defaultValue", name: "defaultValue", label: "\u9ED8\u8BA4\u503C" }, /* @__PURE__ */ React.createElement(
627
+ Select,
628
+ {
629
+ style: { width: "100%" },
630
+ placeholder: "\u8BF7\u9009\u62E9\u65E5\u671F",
631
+ open,
632
+ value: showGmt8 && value ? value + ` (${TZ_LABEL})` : value,
633
+ onOpenChange: setOpen,
634
+ onChange: handleSelectChange,
635
+ options: [
636
+ { label: "\u6DFB\u52A0\u65B0\u8BB0\u5F55\u7684\u521B\u5EFA\u65F6\u95F4", value: CREATE_DATE },
637
+ { label: /* @__PURE__ */ React.createElement(CustomDatePicker, { onChangeDate, formatType }), value: "date_specific" }
638
+ ]
639
+ }
640
+ ));
641
+ };
642
+
643
+ dayjs.extend(utc);
644
+ dayjs.extend(timezone);
645
+ const getCurrentGMTLabel = () => {
646
+ const offsetMinutes = dayjs().utcOffset();
647
+ const offsetHours = offsetMinutes / 60;
648
+ return `GMT${offsetHours >= 0 ? "+" : ""}${offsetHours}`;
649
+ };
650
+
651
+ const ColumnSettingModal = forwardRef(
652
+ ({
653
+ selectProps,
654
+ columnId,
655
+ offsetParent,
656
+ width = 320,
657
+ isOpen = false,
658
+ position,
659
+ tools,
660
+ initValues,
661
+ className,
662
+ onClose,
663
+ onFinish,
664
+ onPositionChange,
665
+ contentRef,
666
+ bodyRef,
667
+ freeze
668
+ }, ref) => {
669
+ const formRef = useRef(null);
670
+ const onCancel = () => {
671
+ if (onClose) onClose();
672
+ };
673
+ useImperativeHandle(ref, () => {
674
+ return {
675
+ formRef: formRef.current
676
+ };
677
+ });
678
+ return /* @__PURE__ */ React.createElement(
679
+ BaseModal,
680
+ {
681
+ offsetParent,
682
+ width,
683
+ open: isOpen,
684
+ onClose,
685
+ value: position,
686
+ onChange: onPositionChange,
687
+ className: `column-setting-modal ${className}`
688
+ },
689
+ /* @__PURE__ */ React.createElement(Flex, { className: "field-form-container", onClick: (e) => e.stopPropagation(), ref: contentRef }, isOpen && /* @__PURE__ */ React.createElement(
690
+ ColumnFieldFrom,
691
+ {
692
+ bodyRef,
693
+ formRef,
694
+ columnId,
695
+ tools,
696
+ initValues,
697
+ onFinish: (values) => onFinish(values).then((success) => {
698
+ if (success && onClose) onClose();
699
+ return success;
700
+ }),
701
+ onCancel,
702
+ selectProps,
703
+ freeze
704
+ }
705
+ ))
706
+ );
707
+ }
708
+ );
709
+
710
+ export { ColumnFieldFrom, ColumnSettingModal, CustomDatePicker, CustomDatePickerV2, FeatureCustomOptions, FeatureDateFormat, FeatureDefaultDate, FeatureDefaultDateV2, FeatureDefaultField, FeatureDefaultInput, FeatureDefaultJson, FeatureDefaultNumber, FeatureDefaultSelect, FeatureField, FeatureFileFormat, FeatureInput, FeatureNumberFormat, FeaturePeople, FeatureTypeSelect, getCurrentGMTLabel };