@nocobase/client-v2 2.1.0-alpha.46 → 2.1.0-alpha.47

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 (30) hide show
  1. package/es/collection-manager/filter-operators/index.d.ts +1 -0
  2. package/es/components/form/filter/CollectionFilterItem.d.ts +5 -1
  3. package/es/components/form/filter/FilterValueInput.d.ts +5 -0
  4. package/es/flow/internal/utils/operatorSchemaHelper.d.ts +26 -3
  5. package/es/flow/models/blocks/filter-manager/utils.d.ts +23 -1
  6. package/es/index.mjs +77 -77
  7. package/lib/index.js +82 -82
  8. package/package.json +7 -7
  9. package/src/__tests__/browserChecker.test.ts +103 -0
  10. package/src/__tests__/dataSourceRuntime.test.tsx +22 -1
  11. package/src/collection-field-interface/CollectionFieldInterface.ts +14 -7
  12. package/src/collection-manager/filter-operators/index.ts +29 -2
  13. package/src/components/form/filter/CollectionFilterItem.tsx +10 -2
  14. package/src/components/form/filter/FilterValueInput.tsx +27 -2
  15. package/src/components/form/filter/__tests__/FilterValueInput.test.tsx +39 -0
  16. package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +369 -2
  17. package/src/flow/actions/linkageRules.tsx +53 -0
  18. package/src/flow/components/DefaultValue.tsx +14 -8
  19. package/src/flow/components/FieldAssignValueInput.tsx +6 -10
  20. package/src/flow/components/filter/LinkageFilterItem.tsx +4 -3
  21. package/src/flow/components/filter/VariableFilterItem.tsx +5 -4
  22. package/src/flow/internal/utils/operatorSchemaHelper.ts +112 -5
  23. package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +13 -11
  24. package/src/flow/models/blocks/filter-manager/__tests__/getDefaultOperator.test.ts +35 -1
  25. package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/customizeFilterRender.test.tsx +148 -0
  26. package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/defaultOperator.test.tsx +85 -0
  27. package/src/flow/models/blocks/filter-manager/flow-actions/customizeFilterRender.tsx +14 -44
  28. package/src/flow/models/blocks/filter-manager/flow-actions/defaultOperator.tsx +3 -5
  29. package/src/flow/models/blocks/filter-manager/flow-actions/operatorComponentProps.tsx +2 -12
  30. package/src/flow/models/blocks/filter-manager/utils.ts +143 -4
@@ -9,9 +9,15 @@
9
9
 
10
10
  import React from 'react';
11
11
  import { fireEvent, render, screen } from '@testing-library/react';
12
- import { FlowSettingsContextProvider } from '@nocobase/flow-engine';
12
+ import { FlowEngine, FlowModel, FlowSettingsContextProvider } from '@nocobase/flow-engine';
13
13
  import { describe, expect, it, vi } from 'vitest';
14
- import { fieldLinkageRules, linkageSetFieldProps, subFormLinkageSetFieldProps } from '../linkageRules';
14
+ import {
15
+ fieldLinkageRules,
16
+ linkageAssignField,
17
+ linkageSetFieldProps,
18
+ subFormFieldLinkageRules,
19
+ subFormLinkageSetFieldProps,
20
+ } from '../linkageRules';
15
21
 
16
22
  const createSubFormFieldModel = ({
17
23
  uid,
@@ -335,6 +341,110 @@ describe('subFormLinkageSetFieldProps action', () => {
335
341
  expect(row0CollectedModel.hidden).toBe(false);
336
342
  expect(row1CollectedModel.hidden).toBe(true);
337
343
  });
344
+
345
+ it('should clear the current row value when a subform list field is hidden without reserving value', async () => {
346
+ const setFormValues = vi.fn(async () => undefined);
347
+ const form = {
348
+ getFieldValue: vi.fn((path: Array<string | number>) => {
349
+ if (JSON.stringify(path) === JSON.stringify(['items', 0, 'a'])) {
350
+ return 'row value';
351
+ }
352
+ return undefined;
353
+ }),
354
+ setFieldValue: vi.fn(),
355
+ };
356
+ const engine = new FlowEngine();
357
+
358
+ const rowGridFork = new FlowModel({ uid: 'row-grid-fork', flowEngine: engine }) as any;
359
+ rowGridFork.hidden = false;
360
+ rowGridFork.context.defineProperty('fieldKey', { value: ['items:0'] });
361
+ rowGridFork.context.defineProperty('fieldIndex', { value: ['items:0'] });
362
+ rowGridFork.context.defineProperty('form', { value: form });
363
+ rowGridFork.context.defineProperty('setFormValues', { value: setFormValues });
364
+ rowGridFork.context.defineProperty('app', {
365
+ value: {
366
+ jsonLogic: {
367
+ apply: () => true,
368
+ },
369
+ },
370
+ });
371
+ rowGridFork.getAction = vi.fn((name: string) => {
372
+ if (name === 'subFormLinkageSetFieldProps') {
373
+ return subFormLinkageSetFieldProps;
374
+ }
375
+ });
376
+
377
+ const targetFieldFork: any = {
378
+ uid: 'field-a',
379
+ isFork: true,
380
+ hidden: false,
381
+ props: {},
382
+ context: {
383
+ fieldIndex: ['items:0'],
384
+ },
385
+ getStepParams: vi.fn((flowKey: string, stepKey: string) => {
386
+ if (flowKey === 'fieldSettings' && stepKey === 'init') {
387
+ return { fieldPath: 'a' };
388
+ }
389
+ }),
390
+ setProps(key: any, value?: any) {
391
+ if (typeof key === 'string') {
392
+ this.props[key] = value;
393
+ } else {
394
+ this.props = { ...this.props, ...key };
395
+ }
396
+ },
397
+ };
398
+
399
+ const formItemModel: any = {
400
+ uid: 'field-a',
401
+ getFork: vi.fn((key: string) => (key === 'items:0:field-a' ? targetFieldFork : undefined)),
402
+ };
403
+
404
+ engine.getModel = vi.fn((uid: string) => (uid === 'field-a' ? formItemModel : undefined)) as any;
405
+
406
+ await subFormFieldLinkageRules.handler(
407
+ {
408
+ model: {
409
+ hidden: false,
410
+ subModels: {
411
+ grid: {
412
+ forks: [rowGridFork],
413
+ },
414
+ },
415
+ },
416
+ flowKey: 'eventSettings',
417
+ } as any,
418
+ {
419
+ value: [
420
+ {
421
+ key: 'rule-1',
422
+ enable: true,
423
+ condition: { logic: '$and', items: [] },
424
+ actions: [
425
+ {
426
+ name: 'subFormLinkageSetFieldProps',
427
+ params: {
428
+ value: {
429
+ fields: ['field-a'],
430
+ state: 'hidden',
431
+ },
432
+ },
433
+ },
434
+ ],
435
+ },
436
+ ],
437
+ },
438
+ );
439
+
440
+ expect(form.getFieldValue).toHaveBeenCalledWith(['items', 0, 'a']);
441
+ expect(targetFieldFork.hidden).toBe(true);
442
+ expect(setFormValues).toHaveBeenCalledWith(
443
+ [{ path: ['items', 0, 'a'], value: undefined }],
444
+ expect.objectContaining({ source: 'linkage' }),
445
+ );
446
+ expect(form.setFieldValue).not.toHaveBeenCalled();
447
+ });
338
448
  });
339
449
 
340
450
  describe('linkageSetFieldProps action', () => {
@@ -541,6 +651,263 @@ describe('linkageSetFieldProps action', () => {
541
651
  expect(form.setFieldValue).not.toHaveBeenCalled();
542
652
  });
543
653
 
654
+ it('should clear form value when a field is hidden without reserving value', async () => {
655
+ const setFormValues = vi.fn(async () => undefined);
656
+ const form = {
657
+ getFieldValue: vi.fn(() => '123'),
658
+ setFieldValue: vi.fn(),
659
+ };
660
+ const fieldModel: any = {
661
+ uid: 'name-field',
662
+ hidden: false,
663
+ context: { form },
664
+ props: {
665
+ label: 'Name',
666
+ },
667
+ getStepParams: vi.fn((flowKey: string, stepKey: string) => {
668
+ if (flowKey === 'fieldSettings' && stepKey === 'init') {
669
+ return { fieldPath: 'name' };
670
+ }
671
+ }),
672
+ setProps(key: any, value?: any) {
673
+ if (typeof key === 'string') {
674
+ this.props[key] = value;
675
+ } else {
676
+ this.props = { ...this.props, ...key };
677
+ }
678
+ },
679
+ };
680
+ const ctx: any = {
681
+ app: {
682
+ jsonLogic: {
683
+ apply: vi.fn(() => true),
684
+ },
685
+ },
686
+ model: {
687
+ context: { form },
688
+ subModels: {
689
+ grid: {
690
+ subModels: {
691
+ items: [fieldModel],
692
+ },
693
+ },
694
+ },
695
+ },
696
+ setFormValues,
697
+ getAction: (name: string) => (name === 'linkageSetFieldProps' ? linkageSetFieldProps : null),
698
+ resolveJsonTemplate: vi.fn(async (value) => value),
699
+ };
700
+
701
+ await fieldLinkageRules.handler(ctx, {
702
+ value: [
703
+ {
704
+ key: 'rule-1',
705
+ enable: true,
706
+ condition: { logic: '$and', items: [] },
707
+ actions: [
708
+ {
709
+ key: 'action-1',
710
+ name: 'linkageSetFieldProps',
711
+ params: {
712
+ value: {
713
+ fields: ['name-field'],
714
+ state: 'hidden',
715
+ },
716
+ },
717
+ },
718
+ ],
719
+ },
720
+ ],
721
+ });
722
+
723
+ expect(fieldModel.hidden).toBe(true);
724
+ expect(setFormValues).toHaveBeenCalledWith(
725
+ [{ path: ['name'], value: undefined }],
726
+ expect.objectContaining({ source: 'linkage' }),
727
+ );
728
+ expect(form.setFieldValue).not.toHaveBeenCalled();
729
+ });
730
+
731
+ it('should keep hidden clear after same-round assignment for the same field', async () => {
732
+ const formValues: { name?: string } = {};
733
+ const setFormValues = vi.fn(async (patches: Array<{ path: Array<string | number>; value: string | undefined }>) => {
734
+ for (const patch of patches) {
735
+ if (patch.path.length === 1 && patch.path[0] === 'name') {
736
+ formValues.name = patch.value;
737
+ }
738
+ }
739
+ });
740
+ const form = {
741
+ getFieldValue: vi.fn((path: Array<string | number>) => {
742
+ if (path.length === 1 && path[0] === 'name') {
743
+ return formValues.name;
744
+ }
745
+ return undefined;
746
+ }),
747
+ setFieldValue: vi.fn(),
748
+ };
749
+ const fieldModel: any = {
750
+ uid: 'name-field',
751
+ hidden: false,
752
+ context: { form },
753
+ props: {
754
+ label: 'Name',
755
+ },
756
+ getStepParams: vi.fn((flowKey: string, stepKey: string) => {
757
+ if (flowKey === 'fieldSettings' && stepKey === 'init') {
758
+ return { fieldPath: 'name' };
759
+ }
760
+ }),
761
+ setProps(key: any, value?: any) {
762
+ if (typeof key === 'string') {
763
+ this.props[key] = value;
764
+ } else {
765
+ this.props = { ...this.props, ...key };
766
+ }
767
+ },
768
+ };
769
+ const ctx: any = {
770
+ app: {
771
+ jsonLogic: {
772
+ apply: vi.fn(() => true),
773
+ },
774
+ },
775
+ model: {
776
+ context: { form },
777
+ subModels: {
778
+ grid: {
779
+ subModels: {
780
+ items: [fieldModel],
781
+ },
782
+ },
783
+ },
784
+ },
785
+ setFormValues,
786
+ getAction: (name: string) => {
787
+ if (name === 'linkageSetFieldProps') return linkageSetFieldProps;
788
+ if (name === 'linkageAssignField') return linkageAssignField;
789
+ return null;
790
+ },
791
+ resolveJsonTemplate: vi.fn(async (value) => value),
792
+ };
793
+
794
+ await fieldLinkageRules.handler(ctx, {
795
+ value: [
796
+ {
797
+ key: 'rule-1',
798
+ enable: true,
799
+ condition: { logic: '$and', items: [] },
800
+ actions: [
801
+ {
802
+ key: 'action-1',
803
+ name: 'linkageSetFieldProps',
804
+ params: {
805
+ value: {
806
+ fields: ['name-field'],
807
+ state: 'hidden',
808
+ },
809
+ },
810
+ },
811
+ {
812
+ key: 'action-2',
813
+ name: 'linkageAssignField',
814
+ params: {
815
+ value: [
816
+ {
817
+ key: 'assign-1',
818
+ enable: true,
819
+ targetPath: 'name',
820
+ value: 'assigned',
821
+ },
822
+ ],
823
+ },
824
+ },
825
+ ],
826
+ },
827
+ ],
828
+ });
829
+
830
+ expect(fieldModel.hidden).toBe(true);
831
+ expect(formValues.name).toBeUndefined();
832
+ expect(setFormValues).not.toHaveBeenCalled();
833
+ expect(form.setFieldValue).not.toHaveBeenCalled();
834
+ });
835
+
836
+ it('should not clear form value when a field is hidden with reserved value', async () => {
837
+ const setFormValues = vi.fn(async () => undefined);
838
+ const form = {
839
+ getFieldValue: vi.fn(() => '123'),
840
+ setFieldValue: vi.fn(),
841
+ };
842
+ const fieldModel: any = {
843
+ uid: 'name-field',
844
+ hidden: false,
845
+ context: { form },
846
+ props: {
847
+ label: 'Name',
848
+ },
849
+ getStepParams: vi.fn((flowKey: string, stepKey: string) => {
850
+ if (flowKey === 'fieldSettings' && stepKey === 'init') {
851
+ return { fieldPath: 'name' };
852
+ }
853
+ }),
854
+ setProps(key: any, value?: any) {
855
+ if (typeof key === 'string') {
856
+ this.props[key] = value;
857
+ } else {
858
+ this.props = { ...this.props, ...key };
859
+ }
860
+ },
861
+ };
862
+ const ctx: any = {
863
+ app: {
864
+ jsonLogic: {
865
+ apply: vi.fn(() => true),
866
+ },
867
+ },
868
+ model: {
869
+ context: { form },
870
+ subModels: {
871
+ grid: {
872
+ subModels: {
873
+ items: [fieldModel],
874
+ },
875
+ },
876
+ },
877
+ },
878
+ setFormValues,
879
+ getAction: (name: string) => (name === 'linkageSetFieldProps' ? linkageSetFieldProps : null),
880
+ resolveJsonTemplate: vi.fn(async (value) => value),
881
+ };
882
+
883
+ await fieldLinkageRules.handler(ctx, {
884
+ value: [
885
+ {
886
+ key: 'rule-1',
887
+ enable: true,
888
+ condition: { logic: '$and', items: [] },
889
+ actions: [
890
+ {
891
+ key: 'action-1',
892
+ name: 'linkageSetFieldProps',
893
+ params: {
894
+ value: {
895
+ fields: ['name-field'],
896
+ state: 'hiddenReservedValue',
897
+ },
898
+ },
899
+ },
900
+ ],
901
+ },
902
+ ],
903
+ });
904
+
905
+ expect(fieldModel.hidden).toBe(false);
906
+ expect(fieldModel.props.hidden).toBe(true);
907
+ expect(setFormValues).not.toHaveBeenCalled();
908
+ expect(form.setFieldValue).not.toHaveBeenCalled();
909
+ });
910
+
544
911
  it('should keep all options selectable after options were limited once', async () => {
545
912
  const fieldComponentModel: any = {
546
913
  uid: 'status-field-component',
@@ -1768,6 +1768,7 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
1768
1768
  const allModels: FlowModel[] = ctx.model.__allModels || (ctx.model.__allModels = []);
1769
1769
  const modelsToApply = new Set<FlowModel>(allModels);
1770
1770
  const patchPropsByModel = new Map<FlowModel, any>();
1771
+ const clearValueOnHiddenModelUids = new Set<string>();
1771
1772
  const directValuePatches: Array<{ path: Array<string | number>; value: any; whenEmpty?: boolean }> = [];
1772
1773
  const rootCollection = getCollectionFromModel((ctx.model as any)?.context?.blockModel ?? ctx.model);
1773
1774
  const isSafeToWriteAssociationSubpath = (namePath: any): boolean => {
@@ -1878,6 +1879,16 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
1878
1879
  ...(whenEmpty ? { whenEmpty: true } : {}),
1879
1880
  });
1880
1881
  };
1882
+ const removePendingFormValuePatches = (path: any) => {
1883
+ const resolvedPath = resolveNamePathForPatch(path);
1884
+ if (!resolvedPath) return;
1885
+ const resolvedPathKey = namePathToPathKey(resolvedPath);
1886
+ for (let i = directValuePatches.length - 1; i >= 0; i--) {
1887
+ if (namePathToPathKey(directValuePatches[i].path) === resolvedPathKey) {
1888
+ directValuePatches.splice(i, 1);
1889
+ }
1890
+ }
1891
+ };
1881
1892
 
1882
1893
  const getModelTargetPathForPatch = (model: any): string | null => {
1883
1894
  if (!model || typeof model !== 'object') return null;
@@ -1973,6 +1984,23 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
1973
1984
 
1974
1985
  return out;
1975
1986
  };
1987
+ const getModelTargetPathForHiddenClear = (model: any): string | Array<string | number> | null => {
1988
+ const fieldPathArray = normalizeNamePathForKey(model?.context?.fieldPathArray);
1989
+ const targetPath = getModelTargetPathForPatch(model);
1990
+ if (fieldPathArray) {
1991
+ const targetPathLastString = targetPath
1992
+ ? ([...parsePathString(targetPath)].reverse().find((seg) => typeof seg === 'string') as string | undefined)
1993
+ : undefined;
1994
+ const fieldPathArrayLastString = [...fieldPathArray].reverse().find((seg) => typeof seg === 'string');
1995
+ if (!targetPathLastString || targetPathLastString === fieldPathArrayLastString) {
1996
+ return fieldPathArray;
1997
+ }
1998
+ }
1999
+
2000
+ if (!targetPath) return null;
2001
+
2002
+ return resolveIndexedRelativePath(targetPath, model?.context?.fieldIndex) || targetPath;
2003
+ };
1976
2004
  const getModelTargetPathKeys = (model: any): Set<string> => {
1977
2005
  const keys = new Set<string>();
1978
2006
  const fieldPathArray = normalizeNamePathForKey(model?.context?.fieldPathArray);
@@ -2060,6 +2088,13 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
2060
2088
  ...props,
2061
2089
  });
2062
2090
 
2091
+ if (
2092
+ (action.name === 'linkageSetFieldProps' || action.name === 'subFormLinkageSetFieldProps') &&
2093
+ props?.hiddenModel === true
2094
+ ) {
2095
+ clearValueOnHiddenModelUids.add(model?.uid || String(model));
2096
+ }
2097
+
2063
2098
  if (allModels.indexOf(model) === -1) {
2064
2099
  allModels.push(model);
2065
2100
  }
@@ -2147,6 +2182,24 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
2147
2182
  }
2148
2183
  }
2149
2184
 
2185
+ if (
2186
+ clearValueOnHiddenModelUids.has(uid) &&
2187
+ Object.prototype.hasOwnProperty.call(patchProps, 'hiddenModel') &&
2188
+ patchProps.hiddenModel === true
2189
+ ) {
2190
+ const targetPath = getModelTargetPathForHiddenClear(model);
2191
+ if (!targetPath) {
2192
+ console.warn('[linkageRules] Skip clearing hidden field value due to missing target path', {
2193
+ flowKey: ctx.flowKey,
2194
+ modelUid: ctx.model?.uid,
2195
+ targetUid: model?.uid,
2196
+ });
2197
+ } else {
2198
+ removePendingFormValuePatches(targetPath);
2199
+ addFormValuePatch({ path: targetPath, value: undefined });
2200
+ }
2201
+ }
2202
+
2150
2203
  model.__props = null;
2151
2204
  });
2152
2205
  hiddenStatePatches.forEach(({ model, hidden }) => {
@@ -31,7 +31,7 @@ import { FieldModel } from '../models';
31
31
  import { RecordSelectFieldModel } from '../models/fields/AssociationFieldModel';
32
32
  import { InputFieldModel } from '../models/fields/InputFieldModel';
33
33
  import { ensureOptionsFromUiSchemaEnumIfAbsent } from '../internal/utils/enumOptionsUtils';
34
- import { resolveOperatorComponent } from '../internal/utils/operatorSchemaHelper';
34
+ import { pickOperatorStyle as pickStyle, resolveOperatorComponent } from '../internal/utils/operatorSchemaHelper';
35
35
  import { RunJSValueEditor } from './RunJSValueEditor';
36
36
  import { buildDynamicNamePath } from '../models/blocks/form/dynamicNamePath';
37
37
 
@@ -592,7 +592,7 @@ export const DefaultValue = connect((props: Props) => {
592
592
  }
593
593
  }
594
594
  }
595
- }, [inputProps, value]);
595
+ }, [inputProps]);
596
596
  return (
597
597
  <div style={{ flexGrow: 1 }}>
598
598
  <FlowModelRenderer model={tempRoot} showFlowSettings={false} />
@@ -600,11 +600,13 @@ export const DefaultValue = connect((props: Props) => {
600
600
  );
601
601
  };
602
602
  return ConstantValueEditor;
603
- }, [tempRoot]);
603
+ }, [tempRoot, value]);
604
+
605
+ const modelOperator = (model as { operator?: string })?.operator;
604
606
 
605
607
  // 文本类多关键词:根据已注册的 operator schema 渲染(用于默认值配置)
606
608
  React.useEffect(() => {
607
- const operator = (model as any)?.operator;
609
+ const operator = modelOperator;
608
610
  const fieldModel = tempRoot?.subModels?.fields?.[0];
609
611
  if (!operator || !fieldModel) return;
610
612
  const originalRender = fieldModel['__originalRender'] || fieldModel.render;
@@ -622,17 +624,21 @@ export const DefaultValue = connect((props: Props) => {
622
624
  <Comp
623
625
  {...fieldModel.props}
624
626
  {...xProps}
625
- style={{ width: '100%', ...(fieldModel.props as any)?.style, ...xProps?.style }}
627
+ style={{
628
+ width: '100%',
629
+ ...pickStyle((fieldModel.props as Record<string, unknown>)?.style),
630
+ ...pickStyle(xProps?.style),
631
+ }}
626
632
  />
627
633
  );
628
634
  } else if (typeof originalRender === 'function') {
629
635
  fieldModel.render = originalRender;
630
636
  }
631
- }, [model, tempRoot, (model as any)?.operator]);
637
+ }, [model, tempRoot, modelOperator]);
632
638
 
633
639
  // 根据操作符 schema 的 x-component-props 补全临时字段的输入属性(如多选)
634
640
  React.useEffect(() => {
635
- const operator = (model as any)?.operator;
641
+ const operator = modelOperator;
636
642
  const fieldModel = tempRoot?.subModels?.fields?.[0];
637
643
  if (!fieldModel || !operator) return;
638
644
  const ops = model.collectionField?.filterable?.operators || [];
@@ -641,7 +647,7 @@ export const DefaultValue = connect((props: Props) => {
641
647
  if (xComponentProps) {
642
648
  fieldModel.setProps(xComponentProps);
643
649
  }
644
- }, [model, tempRoot, (model as any)?.operator]);
650
+ }, [model, tempRoot, modelOperator]);
645
651
 
646
652
  const NullComponent = useMemo(() => {
647
653
  function NullValuePlaceholder() {
@@ -36,7 +36,7 @@ import {
36
36
  isToManyAssociationField,
37
37
  } from '../internal/utils/modelUtils';
38
38
  import { RunJSValueEditor } from './RunJSValueEditor';
39
- import { resolveOperatorComponent } from '../internal/utils/operatorSchemaHelper';
39
+ import { pickOperatorStyle as pickStyle, resolveOperatorComponent } from '../internal/utils/operatorSchemaHelper';
40
40
  import { InputFieldModel } from '../models/fields/InputFieldModel';
41
41
  import { normalizeFilterValueByOperator } from '../models/blocks/filter-form/valueNormalization';
42
42
  import { FieldAssignExactDatePicker, type ExactDatePickerMode } from './FieldAssignExactDatePicker';
@@ -354,14 +354,6 @@ type ResolvedFieldContext = {
354
354
  collectionField: CollectionField | null;
355
355
  };
356
356
 
357
- function isPlainObject(value: unknown): value is Record<string, unknown> {
358
- return !!value && typeof value === 'object' && !Array.isArray(value);
359
- }
360
-
361
- function pickStyle(value: unknown): React.CSSProperties | undefined {
362
- return isPlainObject(value) ? (value as React.CSSProperties) : undefined;
363
- }
364
-
365
357
  function withFullWidthStyle(style?: React.CSSProperties): React.CSSProperties {
366
358
  return { ...style, width: '100%', minWidth: 0 };
367
359
  }
@@ -1175,7 +1167,11 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1175
1167
  <Comp
1176
1168
  {...fieldModel.props}
1177
1169
  {...xProps}
1178
- style={{ width: '100%', ...(fieldModel.props as any)?.style, ...xProps?.style }}
1170
+ style={{
1171
+ width: '100%',
1172
+ ...pickStyle((fieldModel.props as Record<string, unknown>)?.style),
1173
+ ...pickStyle(xProps?.style),
1174
+ }}
1179
1175
  />
1180
1176
  );
1181
1177
  rewrapReactiveRender(fieldModel);
@@ -29,7 +29,7 @@ import {
29
29
  UiSchemaEnumItem,
30
30
  } from '../../internal/utils/enumOptionsUtils';
31
31
  import { mergeItemMetaTreeForAssignValue } from '../FieldAssignValueInput';
32
- import { resolveOperatorComponent } from '../../internal/utils/operatorSchemaHelper';
32
+ import { pickOperatorStyle as pickStyle, resolveOperatorComponent } from '../../internal/utils/operatorSchemaHelper';
33
33
  import { limitAssociationMetaTree } from './metaTreeAssociationDepth';
34
34
 
35
35
  const { DateFilterDynamicComponent: DateFilterDynamicComponentLazy } = lazy(
@@ -354,7 +354,8 @@ export const LinkageFilterItem: React.FC<LinkageFilterItemProps> = observer((pro
354
354
  return (inputProps: { value?: any; onChange?: (v: any) => void } & Record<string, any>) => {
355
355
  const { value: inputValue, onChange, ...rest } = inputProps || {};
356
356
  const nextProps = { ...componentProps };
357
- if ((!nextProps?.options || nextProps?.options.length === 0) && enumOptions.length > 0) {
357
+ const options = Array.isArray(nextProps.options) ? nextProps.options : undefined;
358
+ if ((!options || options.length === 0) && enumOptions.length > 0) {
358
359
  nextProps.options = enumOptions;
359
360
  }
360
361
  const normalizedValue = Array.isArray(inputValue)
@@ -372,7 +373,7 @@ export const LinkageFilterItem: React.FC<LinkageFilterItemProps> = observer((pro
372
373
  {...rest}
373
374
  value={normalizedValue}
374
375
  onChange={onChange}
375
- style={{ width: 200, ...(nextProps?.style || {}), ...(rest?.style || {}) }}
376
+ style={{ width: 200, ...pickStyle(nextProps.style), ...pickStyle(rest?.style) }}
376
377
  />
377
378
  );
378
379
 
@@ -26,7 +26,7 @@ import {
26
26
  import _ from 'lodash';
27
27
  import { NumberPicker } from '@formily/antd-v5';
28
28
  import { enumToOptions, normalizeSelectRenderValue, UiSchemaEnumItem } from '../../internal/utils/enumOptionsUtils';
29
- import { resolveOperatorComponent } from '../../internal/utils/operatorSchemaHelper';
29
+ import { pickOperatorStyle as pickStyle, resolveOperatorComponent } from '../../internal/utils/operatorSchemaHelper';
30
30
  import { limitAssociationMetaTree } from './metaTreeAssociationDepth';
31
31
 
32
32
  const { DateFilterDynamicComponent: DateFilterDynamicComponentLazy } = lazy(
@@ -495,14 +495,15 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
495
495
  if (resolved && supportKeyword) {
496
496
  const { Comp, props: xProps } = resolved;
497
497
  const nextProps = { ...xProps };
498
- if ((!nextProps?.options || nextProps?.options.length === 0) && enumOptions?.length) {
498
+ const options = Array.isArray(nextProps.options) ? nextProps.options : undefined;
499
+ if ((!options || options.length === 0) && enumOptions?.length) {
499
500
  nextProps.options = enumOptions;
500
501
  }
501
502
  const style = {
502
503
  flex: '1 1 40%',
503
504
  minWidth: 160,
504
505
  maxWidth: '100%',
505
- ...(nextProps?.style || {}),
506
+ ...pickStyle(nextProps.style),
506
507
  };
507
508
  const normalized =
508
509
  Array.isArray(rightValue) && rightValue.every((v) => typeof v === 'string' || typeof v === 'number')
@@ -517,7 +518,7 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
517
518
  <div style={style}>
518
519
  <Comp
519
520
  {...nextProps}
520
- style={{ width: '100%', ...(nextProps?.style || {}) }}
521
+ style={{ width: '100%', ...pickStyle(nextProps.style) }}
521
522
  value={normalized}
522
523
  onChange={(vals: any) => setRightValue(vals)}
523
524
  />