@nocobase/client-v2 2.2.0-beta.9 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/es/APIClient.d.ts +13 -3
  2. package/es/BaseApplication.d.ts +1 -0
  3. package/es/collection-field-interface/CollectionFieldInterface.d.ts +1 -0
  4. package/es/collection-field-interface/CollectionFieldInterfaceManager.d.ts +1 -0
  5. package/es/components/category-tabs/SortableCategoryTabs.d.ts +55 -0
  6. package/es/components/category-tabs/index.d.ts +9 -0
  7. package/es/components/form/ScanInput/useCodeScanner.d.ts +3 -2
  8. package/es/components/form/TypedVariableInput.d.ts +31 -5
  9. package/es/components/form/filter/CollectionFilter.d.ts +2 -0
  10. package/es/components/form/filter/CollectionFilterItem.d.ts +11 -1
  11. package/es/components/form/filter/CollectionFilterPanel.d.ts +2 -0
  12. package/es/components/form/filter/index.d.ts +2 -0
  13. package/es/components/form/filter/useFilterActionProps.d.ts +2 -0
  14. package/es/components/index.d.ts +1 -0
  15. package/es/flow/actions/index.d.ts +1 -1
  16. package/es/flow/actions/linkageRules.d.ts +27 -0
  17. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +1 -0
  18. package/es/flow/components/FieldAssignExactDatePicker.d.ts +1 -0
  19. package/es/flow/components/FieldAssignValueInput.d.ts +7 -24
  20. package/es/flow/components/FlowRoute.d.ts +2 -2
  21. package/es/flow/components/RunJSValueEditor.d.ts +1 -0
  22. package/es/flow/components/field-value-variable/DateVariableEditor.d.ts +24 -0
  23. package/es/flow/components/field-value-variable/FieldValueVariableInput.d.ts +31 -0
  24. package/es/flow/components/field-value-variable/dateValue.d.ts +36 -0
  25. package/es/flow/components/field-value-variable/index.d.ts +11 -0
  26. package/es/flow/components/filter/FilterGroup.d.ts +1 -0
  27. package/es/flow/components/filter/VariableFilterItem.d.ts +6 -1
  28. package/es/flow/components/placeholders/BlockPlaceholder.d.ts +1 -0
  29. package/es/flow/index.d.ts +1 -0
  30. package/es/flow/internal/registerDeviceTypeContext.d.ts +10 -0
  31. package/es/flow/internal/utils/operatorSchemaHelper.d.ts +2 -2
  32. package/es/flow/models/actions/UpdateRecordActionUtils.d.ts +8 -2
  33. package/es/flow/models/base/ActionModelCore.d.ts +4 -2
  34. package/es/flow/models/base/BlockGridModel.d.ts +3 -0
  35. package/es/flow/models/base/CollectionBlockModel.d.ts +3 -0
  36. package/es/flow/models/base/PageModel/PageModel.d.ts +12 -0
  37. package/es/flow/models/base/PageModel/PageModelTabBar.d.ts +22 -0
  38. package/es/flow/models/base/PageModel/PageTabModel.d.ts +12 -0
  39. package/es/flow/models/blocks/details/DetailsBlockModel.d.ts +3 -0
  40. package/es/flow/models/blocks/filter-form/FilterFormGridModel.d.ts +1 -0
  41. package/es/flow/models/blocks/filter-form/FilterFormSubmitActionModel.d.ts +3 -1
  42. package/es/flow/models/blocks/form/FormBlockModel.d.ts +7 -0
  43. package/es/flow/models/blocks/form/FormGridModel.d.ts +6 -0
  44. package/es/flow/models/blocks/form/QuickEditFormModel.d.ts +17 -2
  45. package/es/flow/models/blocks/form/value-runtime/rules.d.ts +1 -0
  46. package/es/flow/models/blocks/table/JSColumnModel.d.ts +2 -0
  47. package/es/flow/models/blocks/table/TableBlockModel.d.ts +1 -0
  48. package/es/flow/models/blocks/table/TableColumnModel.d.ts +12 -0
  49. package/es/flow/models/blocks/table/utils.d.ts +1 -0
  50. package/es/flow/models/fields/AssociationFieldModel/RecordPickerFieldModel.d.ts +2 -1
  51. package/es/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.d.ts +0 -17
  52. package/es/flow/models/fields/AssociationFieldModel/recordSelectShared.d.ts +41 -0
  53. package/es/flow/models/fields/DateTimeFieldModel/dateLimit.d.ts +15 -7
  54. package/es/flow-compat/fieldValidationConstants.d.ts +1 -1
  55. package/es/flow-compat/passwordUtils.d.ts +1 -1
  56. package/es/flow-compat/routeTypes.d.ts +1 -0
  57. package/es/index.d.ts +5 -0
  58. package/es/index.mjs +199 -161
  59. package/es/ui-operation/index.d.ts +15 -0
  60. package/es/ui-operation/ui-operation-codec.d.ts +10 -0
  61. package/es/utils/getRouteRuntimeVersion.d.ts +23 -0
  62. package/es/utils/index.d.ts +1 -0
  63. package/lib/index.js +215 -177
  64. package/lib/locale/languageCodes.js +3 -1
  65. package/package.json +9 -7
  66. package/src/APIClient.ts +90 -7
  67. package/src/Application.tsx +7 -1
  68. package/src/BaseApplication.tsx +11 -6
  69. package/src/__tests__/APIClient.test.tsx +58 -0
  70. package/src/__tests__/app.test.tsx +73 -0
  71. package/src/__tests__/browserChecker.test.ts +61 -0
  72. package/src/__tests__/getRouteRuntimeVersion.test.ts +68 -0
  73. package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +35 -2
  74. package/src/__tests__/settings-center.test.tsx +270 -6
  75. package/src/acl/ACLProvider.tsx +2 -0
  76. package/src/acl/__tests__/ACLProvider.test.tsx +92 -0
  77. package/src/collection-field-interface/CollectionFieldInterface.ts +1 -0
  78. package/src/collection-field-interface/CollectionFieldInterfaceManager.ts +1 -0
  79. package/src/collection-manager/field-validation.ts +1 -1
  80. package/src/components/README.md +7 -1
  81. package/src/components/README.zh-CN.md +6 -1
  82. package/src/components/category-tabs/SortableCategoryTabs.tsx +210 -0
  83. package/src/components/category-tabs/index.ts +10 -0
  84. package/src/components/form/JsonTextArea.tsx +4 -0
  85. package/src/components/form/ScanInput/CodeScanner.tsx +79 -35
  86. package/src/components/form/ScanInput/__tests__/CodeScanner.test.tsx +101 -0
  87. package/src/components/form/ScanInput/__tests__/useCodeScanner.test.tsx +284 -11
  88. package/src/components/form/ScanInput/useCodeScanner.ts +332 -24
  89. package/src/components/form/TypedVariableInput.tsx +452 -101
  90. package/src/components/form/__tests__/TypedVariableInput.test.tsx +364 -12
  91. package/src/components/form/filter/CollectionFilter.tsx +4 -0
  92. package/src/components/form/filter/CollectionFilterItem.tsx +36 -9
  93. package/src/components/form/filter/CollectionFilterPanel.tsx +4 -0
  94. package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +55 -0
  95. package/src/components/form/filter/__tests__/useFilterActionProps.test.tsx +95 -0
  96. package/src/components/form/filter/index.ts +2 -0
  97. package/src/components/form/filter/useFilterActionProps.ts +37 -6
  98. package/src/components/form/table/Table.tsx +81 -6
  99. package/src/components/form/table/__tests__/Table.columnWidth.test.tsx +433 -0
  100. package/src/components/index.ts +1 -0
  101. package/src/flow/FlowPage.tsx +9 -1
  102. package/src/flow/__tests__/FlowPage.test.tsx +50 -3
  103. package/src/flow/__tests__/FlowRoute.test.tsx +128 -10
  104. package/src/flow/__tests__/PluginFlowEngine.test.ts +58 -0
  105. package/src/flow/actions/__tests__/actionLinkageRules.forkProps.test.ts +314 -0
  106. package/src/flow/actions/__tests__/dataScopeFormValueClear.test.ts +102 -0
  107. package/src/flow/actions/__tests__/linkageRules.actionStates.test.ts +33 -0
  108. package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +72 -0
  109. package/src/flow/actions/__tests__/linkageRules.tab.test.ts +171 -0
  110. package/src/flow/actions/__tests__/linkageRulesRefresh.test.ts +7 -3
  111. package/src/flow/actions/index.ts +2 -0
  112. package/src/flow/actions/linkageRules.tsx +144 -26
  113. package/src/flow/actions/linkageRulesRefresh.tsx +2 -6
  114. package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +0 -1
  115. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.tsx +78 -59
  116. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +253 -6
  117. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +228 -0
  118. package/src/flow/common/Markdown/style.ts +4 -0
  119. package/src/flow/components/BlockItemCard.tsx +2 -2
  120. package/src/flow/components/FieldAssignExactDatePicker.tsx +25 -11
  121. package/src/flow/components/FieldAssignValueInput.tsx +72 -584
  122. package/src/flow/components/FlowRoute.tsx +78 -32
  123. package/src/flow/components/RunJSValueEditor.tsx +9 -1
  124. package/src/flow/components/__tests__/FieldAssignValueInput.context.test.tsx +216 -0
  125. package/src/flow/components/field-value-variable/DateVariableEditor.tsx +181 -0
  126. package/src/flow/components/field-value-variable/FieldValueVariableInput.tsx +326 -0
  127. package/src/flow/components/field-value-variable/__tests__/FieldValueVariableInput.test.tsx +380 -0
  128. package/src/flow/components/field-value-variable/dateValue.ts +223 -0
  129. package/src/flow/components/field-value-variable/index.ts +12 -0
  130. package/src/flow/components/filter/FilterGroup.tsx +33 -5
  131. package/src/flow/components/filter/VariableFilterItem.tsx +170 -13
  132. package/src/flow/components/filter/__tests__/FilterGroup.test.tsx +45 -0
  133. package/src/flow/components/filter/__tests__/VariableFilterItem.leftMetaTree.test.tsx +9 -0
  134. package/src/flow/components/filter/__tests__/VariableFilterItem.test.tsx +195 -1
  135. package/src/flow/components/placeholders/BlockPlaceholder.tsx +70 -23
  136. package/src/flow/components/placeholders/__tests__/BlockPlaceholder.test.tsx +57 -7
  137. package/src/flow/index.ts +3 -0
  138. package/src/flow/internal/registerDeviceTypeContext.ts +39 -0
  139. package/src/flow/internal/utils/operatorSchemaHelper.ts +3 -2
  140. package/src/flow/models/actions/UpdateRecordActionModel.tsx +18 -1
  141. package/src/flow/models/actions/UpdateRecordActionUtils.ts +18 -6
  142. package/src/flow/models/actions/__tests__/UpdateRecordActionModel.test.ts +76 -4
  143. package/src/flow/models/base/ActionModelCore.tsx +11 -2
  144. package/src/flow/models/base/BlockGridModel.tsx +26 -0
  145. package/src/flow/models/base/CollectionBlockModel.tsx +38 -3
  146. package/src/flow/models/base/PageModel/PageModel.tsx +387 -53
  147. package/src/flow/models/base/PageModel/PageModelTabBar.tsx +114 -0
  148. package/src/flow/models/base/PageModel/PageTabModel.tsx +249 -18
  149. package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +790 -10
  150. package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.module-isolation.test.tsx +130 -0
  151. package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.test.tsx +118 -0
  152. package/src/flow/models/base/PageModel/__tests__/PageTabModel.test.ts +1075 -7
  153. package/src/flow/models/base/__tests__/ActionModelCore.render.test.tsx +49 -0
  154. package/src/flow/models/base/__tests__/BlockGridModel.selectSceneActivation.test.ts +124 -0
  155. package/src/flow/models/base/__tests__/CollectionBlockModel.addAppends.test.ts +41 -0
  156. package/src/flow/models/base/__tests__/CollectionBlockModel.initialBeforeRenderRefresh.test.ts +125 -9
  157. package/src/flow/models/blocks/assign-form/AssignFormItemModel.tsx +28 -53
  158. package/src/flow/models/blocks/details/DetailsBlockModel.tsx +8 -3
  159. package/src/flow/models/blocks/details/__tests__/DetailsBlockModel.initialPaginationChangeRefresh.test.ts +32 -1
  160. package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +28 -3
  161. package/src/flow/models/blocks/filter-form/FilterFormGridModel.tsx +36 -5
  162. package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +155 -25
  163. package/src/flow/models/blocks/filter-form/FilterFormSubmitActionModel.tsx +57 -4
  164. package/src/flow/models/blocks/filter-form/__tests__/FilterFormGridModel.onModelCreated.test.ts +174 -1
  165. package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.defineChildren.test.ts +395 -1
  166. package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.getFilterValue.test.ts +72 -0
  167. package/src/flow/models/blocks/filter-form/__tests__/FilterFormSubmitActionModel.lifecycle.test.ts +90 -0
  168. package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +66 -4
  169. package/src/flow/models/blocks/filter-manager/FilterManager.ts +5 -0
  170. package/src/flow/models/blocks/filter-manager/__tests__/FilterManager.test.ts +40 -0
  171. package/src/flow/models/blocks/form/FormBlockModel.tsx +47 -0
  172. package/src/flow/models/blocks/form/FormGridModel.tsx +4 -0
  173. package/src/flow/models/blocks/form/QuickEditFormModel.tsx +189 -36
  174. package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +8 -2
  175. package/src/flow/models/blocks/form/__tests__/QuickEditFormModel.quickEdit.test.ts +350 -2
  176. package/src/flow/models/blocks/form/__tests__/runJsFormSubmit.test.ts +131 -0
  177. package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +435 -0
  178. package/src/flow/models/blocks/form/value-runtime/rules.ts +67 -14
  179. package/src/flow/models/blocks/form/value-runtime/runtime.ts +43 -19
  180. package/src/flow/models/blocks/js-block/JSBlock.tsx +1 -1
  181. package/src/flow/models/blocks/table/JSColumnModel.tsx +10 -1
  182. package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +2 -1
  183. package/src/flow/models/blocks/table/TableBlockModel.tsx +29 -3
  184. package/src/flow/models/blocks/table/TableColumnModel.tsx +48 -9
  185. package/src/flow/models/blocks/table/__tests__/JSColumnModel.test.tsx +52 -5
  186. package/src/flow/models/blocks/table/__tests__/TableBlockModel.filterReset.test.ts +78 -0
  187. package/src/flow/models/blocks/table/__tests__/TableBlockModel.quickEditRefresh.test.ts +12 -0
  188. package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +33 -0
  189. package/src/flow/models/blocks/table/utils.ts +7 -0
  190. package/src/flow/models/fields/AssociationFieldModel/CascadeSelectFieldModel.tsx +33 -1
  191. package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +10 -1
  192. package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/__tests__/popupContext.test.ts +120 -0
  193. package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/actions/PopupSubTableEditActionModel.tsx +10 -2
  194. package/src/flow/models/fields/AssociationFieldModel/RecordPickerFieldModel.tsx +24 -1
  195. package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +9 -136
  196. package/src/flow/models/fields/AssociationFieldModel/__tests__/RecordPickerFieldModel.itemContext.test.ts +167 -3
  197. package/src/flow/models/fields/AssociationFieldModel/recordSelectShared.tsx +156 -0
  198. package/src/flow/models/fields/DateTimeFieldModel/__tests__/DateTimeNoTzFieldModel.dateLimit.test.tsx +149 -0
  199. package/src/flow/models/fields/DateTimeFieldModel/dateLimit.ts +149 -113
  200. package/src/flow/models/fields/DisplayNumberFieldModel.tsx +1 -1
  201. package/src/flow/models/fields/JsonFieldModel.tsx +31 -8
  202. package/src/flow/models/fields/NumberFieldModel.tsx +1 -1
  203. package/src/flow/models/fields/VariableFieldFormModel.tsx +3 -3
  204. package/src/flow/models/fields/__tests__/DisplayNumberFieldModel.test.ts +33 -0
  205. package/src/flow/models/fields/__tests__/JsonFieldModel.test.ts +82 -0
  206. package/src/flow/models/fields/__tests__/NumberFieldModel.test.tsx +47 -0
  207. package/src/flow/models/fields/__tests__/VariableFieldFormModel.test.tsx +51 -0
  208. package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +26 -10
  209. package/src/flow/models/fields/mobile-components/MobileSelect.tsx +51 -14
  210. package/src/flow/models/fields/mobile-components/__tests__/MobileSelect.test.tsx +139 -13
  211. package/src/flow/utils/dataScopeFormValueClear.ts +4 -3
  212. package/src/flow-compat/fieldValidationConstants.ts +1 -1
  213. package/src/flow-compat/routeTypes.ts +1 -0
  214. package/src/index.ts +5 -0
  215. package/src/layout-manager/LayoutContentRoute.tsx +2 -1
  216. package/src/layout-manager/LayoutRoute.tsx +2 -1
  217. package/src/layout-manager/__tests__/LayoutRoute.test.tsx +87 -1
  218. package/src/locale/languageCodes.ts +3 -1
  219. package/src/nocobase-buildin-plugin/index.tsx +12 -0
  220. package/src/settings-center/AdminSettingsLayout.tsx +23 -2
  221. package/src/ui-operation/index.ts +33 -0
  222. package/src/ui-operation/ui-operation-codec.ts +54 -0
  223. package/src/utils/getRouteRuntimeVersion.ts +185 -0
  224. package/src/utils/index.tsx +1 -0
@@ -0,0 +1,326 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import {
11
+ isRunJSValue,
12
+ isVariableExpression,
13
+ parseCtxDateExpressionConfig,
14
+ parseValueToPath,
15
+ serializeCtxDateExpressionConfig,
16
+ tExpr,
17
+ VariableInput,
18
+ type CtxDateExpressionConfig,
19
+ type CtxDatePreset,
20
+ type MetaTreeNode,
21
+ type VariableInputProps,
22
+ } from '@nocobase/flow-engine';
23
+ import { dayjs } from '@nocobase/utils/client';
24
+ import type { Dayjs } from 'dayjs';
25
+ import React from 'react';
26
+ import { DateVariableEditor, getDefaultDateVariableFormat } from './DateVariableEditor';
27
+ import { normalizeDateVariableExactValue, type DateVariableComponentProps } from './dateValue';
28
+
29
+ const DATE_PRESET_NODES: Array<{ name: CtxDatePreset; title: string }> = [
30
+ { name: 'now', title: 'Now' },
31
+ { name: 'today', title: 'Today' },
32
+ { name: 'yesterday', title: 'Yesterday' },
33
+ { name: 'tomorrow', title: 'Tomorrow' },
34
+ { name: 'thisWeek', title: 'This Week' },
35
+ { name: 'lastWeek', title: 'Last Week' },
36
+ { name: 'nextWeek', title: 'Next Week' },
37
+ { name: 'thisMonth', title: 'This Month' },
38
+ { name: 'lastMonth', title: 'Last Month' },
39
+ { name: 'nextMonth', title: 'Next Month' },
40
+ { name: 'thisQuarter', title: 'This Quarter' },
41
+ { name: 'lastQuarter', title: 'Last Quarter' },
42
+ { name: 'nextQuarter', title: 'Next Quarter' },
43
+ { name: 'thisYear', title: 'This Year' },
44
+ { name: 'lastYear', title: 'Last Year' },
45
+ { name: 'nextYear', title: 'Next Year' },
46
+ ];
47
+
48
+ type ValueEditorComponent = React.ComponentType<{
49
+ value?: unknown;
50
+ onChange?: (value: unknown) => void;
51
+ style?: React.CSSProperties;
52
+ disabled?: boolean;
53
+ }>;
54
+
55
+ const DATE_VARIABLE_CONFIG_MARK = Symbol('field-value-date-variable-config');
56
+
57
+ type DateVariableEditConfig = CtxDateExpressionConfig & {
58
+ [DATE_VARIABLE_CONFIG_MARK]: 'editable' | 'restored';
59
+ };
60
+
61
+ export type FieldValueVariableInputProps = Omit<
62
+ VariableInputProps,
63
+ 'value' | 'onChange' | 'metaTree' | 'converters'
64
+ > & {
65
+ value?: unknown;
66
+ onChange: (value: unknown) => void;
67
+ baseMetaTree: MetaTreeNode[] | (() => MetaTreeNode[] | Promise<MetaTreeNode[]>);
68
+ constantComponent: ValueEditorComponent;
69
+ nullComponent: ValueEditorComponent;
70
+ runJSComponent: ValueEditorComponent;
71
+ isDateLikeField: boolean;
72
+ dateComponentProps: DateVariableComponentProps;
73
+ allowRunJS?: boolean;
74
+ converters?: VariableInputProps['converters'];
75
+ };
76
+
77
+ function createDateVariableEditConfig(
78
+ config: CtxDateExpressionConfig,
79
+ source: DateVariableEditConfig[typeof DATE_VARIABLE_CONFIG_MARK] = 'editable',
80
+ ): DateVariableEditConfig {
81
+ return { ...config, [DATE_VARIABLE_CONFIG_MARK]: source } as DateVariableEditConfig;
82
+ }
83
+
84
+ function isDateVariableEditConfig(value: unknown): value is DateVariableEditConfig {
85
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
86
+ const source = (value as Partial<DateVariableEditConfig>)[DATE_VARIABLE_CONFIG_MARK];
87
+ return source === 'editable' || source === 'restored';
88
+ }
89
+
90
+ function getDateNodeName(config: CtxDateExpressionConfig): string {
91
+ if (config.kind === 'exact') return 'exact';
92
+ if (config.kind === 'relative') return config.direction;
93
+ return config.preset;
94
+ }
95
+
96
+ function isDayjsValue(value: unknown): value is Dayjs {
97
+ return dayjs.isDayjs(value);
98
+ }
99
+
100
+ function createInitialDateConfig(
101
+ nodeName: string,
102
+ isDateLikeField: boolean,
103
+ componentProps: DateVariableComponentProps,
104
+ ): DateVariableEditConfig | undefined {
105
+ let config: CtxDateExpressionConfig | undefined;
106
+
107
+ if (nodeName === 'exact') {
108
+ const normalized = normalizeDateVariableExactValue(dayjs(), componentProps);
109
+ const value = isDayjsValue(normalized) ? normalized.format('YYYY-MM-DD') : String(normalized || '');
110
+ config = { kind: 'exact', value };
111
+ } else if (nodeName === 'past' || nodeName === 'next') {
112
+ config = { kind: 'relative', direction: nodeName, amount: 1, unit: 'day' };
113
+ } else if (
114
+ DATE_PRESET_NODES.some((item) => item.name === nodeName) &&
115
+ !(nodeName === 'now' && componentProps.exactNormalizeMode === 'date')
116
+ ) {
117
+ config = { kind: 'preset', preset: nodeName as CtxDatePreset };
118
+ }
119
+
120
+ if (!config) return undefined;
121
+ const initialConfig = isDateLikeField ? config : { ...config, format: getDefaultDateVariableFormat(config) };
122
+ return createDateVariableEditConfig(initialConfig);
123
+ }
124
+
125
+ function normalizeDateConfigForStore(
126
+ config: CtxDateExpressionConfig,
127
+ componentProps: DateVariableComponentProps,
128
+ omitFormat: boolean,
129
+ ): CtxDateExpressionConfig {
130
+ const rawFormat = typeof config.format === 'string' ? config.format : '';
131
+ const normalizedConfig = omitFormat
132
+ ? { ...config, format: undefined }
133
+ : { ...config, format: rawFormat.trim() ? rawFormat : getDefaultDateVariableFormat(config) };
134
+ if (normalizedConfig.kind !== 'exact') return normalizedConfig;
135
+ const normalized = normalizeDateVariableExactValue(normalizedConfig.value, componentProps);
136
+ if (Array.isArray(normalized)) {
137
+ return { ...normalizedConfig, value: [String(normalized[0]), String(normalized[1])] };
138
+ }
139
+ return { ...normalizedConfig, value: String(normalized || '') };
140
+ }
141
+
142
+ export const FieldValueVariableInput: React.FC<FieldValueVariableInputProps> = ({
143
+ value,
144
+ onChange,
145
+ baseMetaTree,
146
+ constantComponent: ConstantComponent,
147
+ nullComponent: NullComponent,
148
+ runJSComponent: RunJSComponent,
149
+ isDateLikeField,
150
+ dateComponentProps,
151
+ allowRunJS = true,
152
+ converters,
153
+ clearValue = '',
154
+ disabled = false,
155
+ ...variableInputProps
156
+ }) => {
157
+ const DateEditor = React.useMemo<ValueEditorComponent>(() => {
158
+ const Component: ValueEditorComponent = (props) => (
159
+ <DateVariableEditor
160
+ value={isDateVariableEditConfig(props.value) ? props.value : undefined}
161
+ onChange={(nextConfig) => props.onChange?.(createDateVariableEditConfig(nextConfig))}
162
+ isDateLikeField={isDateLikeField}
163
+ dateComponentProps={dateComponentProps}
164
+ style={props.style}
165
+ disabled={props.disabled}
166
+ />
167
+ );
168
+ return Component;
169
+ }, [dateComponentProps, isDateLikeField]);
170
+
171
+ const parsedDateConfig = parseCtxDateExpressionConfig(value);
172
+ const restoreLegacyNowForPureDate =
173
+ dateComponentProps.exactNormalizeMode === 'date' &&
174
+ parsedDateConfig?.kind === 'preset' &&
175
+ parsedDateConfig.preset === 'now';
176
+
177
+ const metaTree = React.useMemo<() => Promise<MetaTreeNode[]>>(() => {
178
+ return async () => {
179
+ const base = typeof baseMetaTree === 'function' ? await baseMetaTree() : baseMetaTree;
180
+ const presetNodes =
181
+ dateComponentProps.exactNormalizeMode === 'date' && !restoreLegacyNowForPureDate
182
+ ? DATE_PRESET_NODES.filter((item) => item.name !== 'now')
183
+ : DATE_PRESET_NODES;
184
+ const dateChildren: MetaTreeNode[] = [
185
+ {
186
+ title: tExpr('Exact day'),
187
+ name: 'exact',
188
+ type: 'date',
189
+ paths: ['date', 'exact'],
190
+ render: (props) => <DateEditor {...props} />,
191
+ },
192
+ {
193
+ title: tExpr('Past'),
194
+ name: 'past',
195
+ type: 'date',
196
+ paths: ['date', 'past'],
197
+ render: (props) => <DateEditor {...props} />,
198
+ },
199
+ {
200
+ title: tExpr('Next'),
201
+ name: 'next',
202
+ type: 'date',
203
+ paths: ['date', 'next'],
204
+ render: (props) => <DateEditor {...props} />,
205
+ },
206
+ ...presetNodes.map<MetaTreeNode>(({ name, title }) => ({
207
+ title: tExpr(title),
208
+ name,
209
+ type: 'date',
210
+ paths: ['date', name],
211
+ ...(name === 'now' && dateComponentProps.exactNormalizeMode === 'date'
212
+ ? { disabled: true, selectable: false }
213
+ : {}),
214
+ render: (props) => <DateEditor {...props} />,
215
+ })),
216
+ ];
217
+
218
+ const specialNodes: MetaTreeNode[] = [
219
+ {
220
+ title: tExpr('Constant'),
221
+ name: 'constant',
222
+ type: 'string',
223
+ paths: ['constant'],
224
+ render: (props) => <ConstantComponent {...props} />,
225
+ },
226
+ {
227
+ title: tExpr('Null'),
228
+ name: 'null',
229
+ type: 'object',
230
+ paths: ['null'],
231
+ render: (props) => <NullComponent {...props} />,
232
+ },
233
+ {
234
+ title: tExpr('Date'),
235
+ name: 'date',
236
+ type: 'date',
237
+ paths: ['date'],
238
+ selectable: false,
239
+ children: dateChildren,
240
+ },
241
+ ...(allowRunJS
242
+ ? [
243
+ {
244
+ title: tExpr('RunJS'),
245
+ name: 'runjs',
246
+ type: 'object',
247
+ paths: ['runjs'],
248
+ render: (props) => <RunJSComponent {...props} />,
249
+ } satisfies MetaTreeNode,
250
+ ]
251
+ : []),
252
+ ];
253
+ return [...specialNodes, ...(Array.isArray(base) ? base : [])];
254
+ };
255
+ }, [
256
+ ConstantComponent,
257
+ DateEditor,
258
+ NullComponent,
259
+ RunJSComponent,
260
+ allowRunJS,
261
+ baseMetaTree,
262
+ dateComponentProps.exactNormalizeMode,
263
+ restoreLegacyNowForPureDate,
264
+ ]);
265
+
266
+ const displayValue = parsedDateConfig ? createDateVariableEditConfig(parsedDateConfig, 'restored') : value;
267
+
268
+ const handleChange = React.useCallback(
269
+ (nextValue: unknown) => {
270
+ if (disabled) return;
271
+ if (!isDateVariableEditConfig(nextValue)) {
272
+ onChange(nextValue);
273
+ return;
274
+ }
275
+ if (nextValue[DATE_VARIABLE_CONFIG_MARK] === 'restored') return;
276
+ const normalized = normalizeDateConfigForStore(nextValue, dateComponentProps, isDateLikeField);
277
+ onChange(serializeCtxDateExpressionConfig(normalized) || '');
278
+ },
279
+ [dateComponentProps, disabled, isDateLikeField, onChange],
280
+ );
281
+
282
+ return (
283
+ <VariableInput
284
+ {...variableInputProps}
285
+ value={displayValue}
286
+ onChange={handleChange}
287
+ metaTree={metaTree}
288
+ clearValue={clearValue}
289
+ disabled={disabled}
290
+ converters={{
291
+ renderInputComponent: (meta) => {
292
+ const external = converters?.renderInputComponent?.(meta ?? null);
293
+ if (external) return external;
294
+ const firstPath = meta?.paths?.[0];
295
+ if (firstPath === 'constant') return ConstantComponent;
296
+ if (firstPath === 'null') return NullComponent;
297
+ if (firstPath === 'date') return DateEditor;
298
+ if (allowRunJS && firstPath === 'runjs') return RunJSComponent;
299
+ return null;
300
+ },
301
+ resolveValueFromPath: (item) => {
302
+ const external = converters?.resolveValueFromPath?.(item);
303
+ if (external !== undefined) return external;
304
+ const firstPath = item?.paths?.[0];
305
+ if (firstPath === 'constant') return '';
306
+ if (firstPath === 'null') return null;
307
+ if (firstPath === 'date') {
308
+ return createInitialDateConfig(item.paths[1], isDateLikeField, dateComponentProps);
309
+ }
310
+ if (allowRunJS && firstPath === 'runjs') return { code: '', version: 'v2' };
311
+ return undefined;
312
+ },
313
+ resolvePathFromValue: (currentValue) => {
314
+ const external = converters?.resolvePathFromValue?.(currentValue);
315
+ if (external !== undefined) return external;
316
+ if (currentValue === null) return ['null'];
317
+ if (allowRunJS && isRunJSValue(currentValue)) return ['runjs'];
318
+ if (isDateVariableEditConfig(currentValue)) return ['date', getDateNodeName(currentValue)];
319
+ return typeof currentValue === 'string' && isVariableExpression(currentValue)
320
+ ? parseValueToPath(currentValue)
321
+ : ['constant'];
322
+ },
323
+ }}
324
+ />
325
+ );
326
+ };