@tfdesign/b-end 1.0.6 → 1.0.8

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.
@@ -125,12 +125,34 @@ import fullScreenPageJsxRaw from './components/FullScreenPage.jsx?raw';
125
125
  /** 预览用:切换「初始开/关」时通过 key 重挂载,避免 defaultChecked 仅在 mount 生效 */
126
126
  function SwitchPreview({ variant = 'brand', defaultChecked, disabled }) {
127
127
  return (
128
- <Switch
129
- key={`sw-${defaultChecked}-${disabled}`}
130
- variant={variant}
131
- defaultChecked={defaultChecked}
132
- disabled={disabled}
133
- />
128
+ <FormControlPreviewWidth>
129
+ <Switch
130
+ key={`sw-${defaultChecked}-${disabled}`}
131
+ variant={variant}
132
+ defaultChecked={defaultChecked}
133
+ disabled={disabled}
134
+ />
135
+ </FormControlPreviewWidth>
136
+ );
137
+ }
138
+
139
+ const FORM_CONTROL_PREVIEW_WIDTH_STYLE = {
140
+ width: 'min(300px, 100%)',
141
+ maxWidth: '100%',
142
+ };
143
+
144
+ const FORM_CONTROL_PREVIEW_ITEM_STYLE = {
145
+ ...FORM_CONTROL_PREVIEW_WIDTH_STYLE,
146
+ display: 'flex',
147
+ justifyContent: 'center',
148
+ };
149
+
150
+ /** 仅用于体服 AI 设计平台预览画布,不改变组件自身规范或运行时默认宽度。 */
151
+ function FormControlPreviewWidth({ children, style }) {
152
+ return (
153
+ <div style={{ ...FORM_CONTROL_PREVIEW_WIDTH_STYLE, ...style }}>
154
+ {children}
155
+ </div>
134
156
  );
135
157
  }
136
158
 
@@ -351,16 +373,18 @@ function formatUsageLiteral(value) {
351
373
  /** 预览用:key 保证切换配置时非受控 defaultValue 生效 */
352
374
  function SliderPreview({ min, max, step, defaultValue, showTooltip, marks, disabled, initialKey }) {
353
375
  return (
354
- <Slider
355
- key={`sl-${initialKey}-${min}-${max}-${step}-${Boolean(marks)}-${disabled}-${JSON.stringify(defaultValue)}`}
356
- min={min}
357
- max={max}
358
- step={step}
359
- defaultValue={defaultValue}
360
- showTooltip={showTooltip}
361
- marks={marks}
362
- disabled={disabled}
363
- />
376
+ <FormControlPreviewWidth>
377
+ <Slider
378
+ key={`sl-${initialKey}-${min}-${max}-${step}-${Boolean(marks)}-${disabled}-${JSON.stringify(defaultValue)}`}
379
+ min={min}
380
+ max={max}
381
+ step={step}
382
+ defaultValue={defaultValue}
383
+ showTooltip={showTooltip}
384
+ marks={marks}
385
+ disabled={disabled}
386
+ />
387
+ </FormControlPreviewWidth>
364
388
  );
365
389
  }
366
390
 
@@ -409,24 +433,6 @@ const TEXTAREA_MULTI_SUGGESTION_GROUPS = [
409
433
  ],
410
434
  ];
411
435
 
412
- const TAGINPUT_AI_SUGGESTION_GROUPS = [
413
- [
414
- ['改签', '门店变更'],
415
- ['退款', '售后处理'],
416
- ['物流异常', '催办'],
417
- ],
418
- [
419
- ['优惠券', '核销异常'],
420
- ['客服回访', '待跟进'],
421
- ['资损风险', '升级处理'],
422
- ],
423
- [
424
- ['履约异常', '商家侧'],
425
- ['平台规则', '需复核'],
426
- ['用户反馈', '已记录'],
427
- ],
428
- ];
429
-
430
436
  /** 预览用:key 随「填充 / 超长演示」切换重置非受控初值 */
431
437
  function TextAreaPreview({
432
438
  variant = 'default',
@@ -465,23 +471,25 @@ function TextAreaPreview({
465
471
  }, [hasMultiSuggestions, hasSingleSuggestion]);
466
472
 
467
473
  return (
468
- <TextArea
469
- key={`textarea-${variant}-${fillMode}-${countOverflow}-${disabled}-${status}-${resize}-${fillHeight}-${minRowsSafe}`}
470
- variant={variant}
471
- minRows={minRowsSafe}
472
- status={status}
473
- disabled={disabled}
474
- placeholder={isCodeVariant ? '请输入 System Prompt、JSON 或代码' : '请输入'}
475
- defaultValue={defaultValue}
476
- showCount={showCountDemo}
477
- {...(showCountDemo ? { maxLength: 140, enforceMaxLength } : {})}
478
- resize={resize}
479
- fillHeight={fillHeight}
480
- aiSuggestion={hasSingleSuggestion ? TEXTAREA_SINGLE_SUGGESTIONS[singleIndex] : undefined}
481
- aiSuggestions={hasMultiSuggestions ? TEXTAREA_MULTI_SUGGESTION_GROUPS[multiIndex] : undefined}
482
- onRefreshAiSuggestions={hasSingleSuggestion || hasMultiSuggestions ? handleRefresh : undefined}
483
- className={fillHeight ? 'flex-1 min-h-0 w-full' : (isCodeVariant ? 'w-[520px]' : '')}
484
- />
474
+ <FormControlPreviewWidth>
475
+ <TextArea
476
+ key={`textarea-${variant}-${fillMode}-${countOverflow}-${disabled}-${status}-${resize}-${fillHeight}-${minRowsSafe}`}
477
+ variant={variant}
478
+ minRows={minRowsSafe}
479
+ status={status}
480
+ disabled={disabled}
481
+ placeholder={isCodeVariant ? '请输入 System Prompt、JSON 或代码' : '请输入'}
482
+ defaultValue={defaultValue}
483
+ showCount={showCountDemo}
484
+ {...(showCountDemo ? { maxLength: 140, enforceMaxLength } : {})}
485
+ resize={resize}
486
+ fillHeight={fillHeight}
487
+ aiSuggestion={hasSingleSuggestion ? TEXTAREA_SINGLE_SUGGESTIONS[singleIndex] : undefined}
488
+ aiSuggestions={hasMultiSuggestions ? TEXTAREA_MULTI_SUGGESTION_GROUPS[multiIndex] : undefined}
489
+ onRefreshAiSuggestions={hasSingleSuggestion || hasMultiSuggestions ? handleRefresh : undefined}
490
+ className={fillHeight ? 'flex-1 min-h-0 w-full' : ''}
491
+ />
492
+ </FormControlPreviewWidth>
485
493
  );
486
494
  }
487
495
 
@@ -503,12 +511,14 @@ function InputPreview(props) {
503
511
  }, [hasMultiSuggestions, hasSingleSuggestion]);
504
512
 
505
513
  return (
506
- <Input
507
- {...rest}
508
- aiSuggestion={hasSingleSuggestion ? INPUT_SINGLE_SUGGESTIONS[singleIndex] : undefined}
509
- aiSuggestions={hasMultiSuggestions ? INPUT_MULTI_SUGGESTION_GROUPS[multiIndex] : undefined}
510
- onRefreshAiSuggestions={hasSingleSuggestion || hasMultiSuggestions ? handleRefresh : undefined}
511
- />
514
+ <FormControlPreviewWidth>
515
+ <Input
516
+ {...rest}
517
+ aiSuggestion={hasSingleSuggestion ? INPUT_SINGLE_SUGGESTIONS[singleIndex] : undefined}
518
+ aiSuggestions={hasMultiSuggestions ? INPUT_MULTI_SUGGESTION_GROUPS[multiIndex] : undefined}
519
+ onRefreshAiSuggestions={hasSingleSuggestion || hasMultiSuggestions ? handleRefresh : undefined}
520
+ />
521
+ </FormControlPreviewWidth>
512
522
  );
513
523
  }
514
524
 
@@ -517,17 +527,43 @@ function InputNumberPreview({ content = 'empty', buttonMode = 'outer', disabled
517
527
  const defaultValue = content === 'filled' ? 12 : undefined;
518
528
  const innerButtons = buttonMode === 'inner';
519
529
  return (
520
- <InputNumber
521
- key={`input-number-${content}-${buttonMode}-${disabled}-${status}`}
522
- status={status}
523
- disabled={disabled}
524
- innerButtons={innerButtons}
525
- defaultValue={defaultValue}
526
- min={0}
527
- max={99}
528
- step={1}
529
- placeholder="请输入"
530
- />
530
+ <FormControlPreviewWidth>
531
+ <InputNumber
532
+ key={`input-number-${content}-${buttonMode}-${disabled}-${status}`}
533
+ status={status}
534
+ disabled={disabled}
535
+ innerButtons={innerButtons}
536
+ defaultValue={defaultValue}
537
+ min={0}
538
+ max={99}
539
+ step={1}
540
+ placeholder="请输入"
541
+ />
542
+ </FormControlPreviewWidth>
543
+ );
544
+ }
545
+
546
+ function UploadPreview({ __previewKey, ...props }) {
547
+ return (
548
+ <FormControlPreviewWidth>
549
+ <Upload key={__previewKey} {...props} />
550
+ </FormControlPreviewWidth>
551
+ );
552
+ }
553
+
554
+ function DatePickerPreview(props) {
555
+ return (
556
+ <FormControlPreviewWidth>
557
+ <DatePicker {...props} />
558
+ </FormControlPreviewWidth>
559
+ );
560
+ }
561
+
562
+ function TimePickerPreview(props) {
563
+ return (
564
+ <FormControlPreviewWidth>
565
+ <TimePicker {...props} />
566
+ </FormControlPreviewWidth>
531
567
  );
532
568
  }
533
569
 
@@ -612,17 +648,19 @@ const CHATBUBBLE_PRESET_TIMESTAMPS = {
612
648
  function RadioPreview({ variant, layout, disabled, initialKey }) {
613
649
  const defaultValue = initialKey === 'a' ? 'a' : initialKey === 'b' ? 'b' : undefined;
614
650
  return (
615
- <RadioGroup
616
- key={`rp-${variant}-${layout}-${disabled}-${initialKey}`}
617
- variant={variant}
618
- layout={layout}
619
- disabled={disabled}
620
- defaultValue={defaultValue}
621
- >
622
- <Radio value="a">选项 A</Radio>
623
- <Radio value="b">选项 B</Radio>
624
- <Radio value="c" disabled>选项 C(单项禁用)</Radio>
625
- </RadioGroup>
651
+ <FormControlPreviewWidth>
652
+ <RadioGroup
653
+ key={`rp-${variant}-${layout}-${disabled}-${initialKey}`}
654
+ variant={variant}
655
+ layout={layout}
656
+ disabled={disabled}
657
+ defaultValue={defaultValue}
658
+ >
659
+ <Radio value="a">选项 A</Radio>
660
+ <Radio value="b">选项 B</Radio>
661
+ <Radio value="c" disabled>选项 C(单项禁用)</Radio>
662
+ </RadioGroup>
663
+ </FormControlPreviewWidth>
626
664
  );
627
665
  }
628
666
 
@@ -630,33 +668,37 @@ function RadioPreview({ variant, layout, disabled, initialKey }) {
630
668
  function CheckboxPreview({ variant, size, layout, disabled, initialKey, previewMode }) {
631
669
  if (previewMode === 'indeterminate') {
632
670
  return (
633
- <Checkbox
634
- key={`cb-ind-${variant}-${size}-${disabled}`}
635
- variant={variant}
636
- size={size}
637
- disabled={disabled}
638
- indeterminate
639
- >
640
- 半选状态(树形父级)
641
- </Checkbox>
671
+ <FormControlPreviewWidth>
672
+ <Checkbox
673
+ key={`cb-ind-${variant}-${size}-${disabled}`}
674
+ variant={variant}
675
+ size={size}
676
+ disabled={disabled}
677
+ indeterminate
678
+ >
679
+ 半选状态(树形父级)
680
+ </Checkbox>
681
+ </FormControlPreviewWidth>
642
682
  );
643
683
  }
644
684
  let defaultValue = [];
645
685
  if (initialKey === 'a') defaultValue = ['a'];
646
686
  else if (initialKey === 'ab') defaultValue = ['a', 'b'];
647
687
  return (
648
- <CheckboxGroup
649
- key={`cbg-${variant}-${size}-${layout}-${disabled}-${initialKey}`}
650
- variant={variant}
651
- size={size}
652
- layout={layout}
653
- disabled={disabled}
654
- defaultValue={defaultValue}
655
- >
656
- <Checkbox value="a">选项 A</Checkbox>
657
- <Checkbox value="b">选项 B</Checkbox>
658
- <Checkbox value="c" disabled>选项 C(单项禁用)</Checkbox>
659
- </CheckboxGroup>
688
+ <FormControlPreviewWidth>
689
+ <CheckboxGroup
690
+ key={`cbg-${variant}-${size}-${layout}-${disabled}-${initialKey}`}
691
+ variant={variant}
692
+ size={size}
693
+ layout={layout}
694
+ disabled={disabled}
695
+ defaultValue={defaultValue}
696
+ >
697
+ <Checkbox value="a">选项 A</Checkbox>
698
+ <Checkbox value="b">选项 B</Checkbox>
699
+ <Checkbox value="c" disabled>选项 C(单项禁用)</Checkbox>
700
+ </CheckboxGroup>
701
+ </FormControlPreviewWidth>
660
702
  );
661
703
  }
662
704
 
@@ -687,7 +729,7 @@ function SelectPreview({ status, disabled, initial, optionMode, selectType, aiSu
687
729
  }, [hasMultiSuggestions, hasSingleSuggestion]);
688
730
 
689
731
  return (
690
- <div className="w-[300px] max-w-full">
732
+ <FormControlPreviewWidth>
691
733
  <Select
692
734
  key={`selp-${selectType}-${initial}-${optionMode}-${disabled}-${status}`}
693
735
  mode={isTagSelect ? 'tag' : 'default'}
@@ -701,7 +743,7 @@ function SelectPreview({ status, disabled, initial, optionMode, selectType, aiSu
701
743
  aiSuggestions={!isTagSelect && hasMultiSuggestions ? SELECT_AI_MULTI_SUGGESTION_GROUPS[multiIndex] : undefined}
702
744
  onRefreshAiSuggestions={!isTagSelect && (hasSingleSuggestion || hasMultiSuggestions) ? handleRefresh : undefined}
703
745
  />
704
- </div>
746
+ </FormControlPreviewWidth>
705
747
  );
706
748
  }
707
749
 
@@ -825,26 +867,22 @@ function buildFormFieldAtomProps(fieldType, enums, controlValues = {}) {
825
867
  return {};
826
868
  }
827
869
 
828
- function TagInputPreview({ content, widthMode, disabled, status, tagVariant, tagSize, showAiSuggestions = true }) {
870
+ function TagInputPreview({ content, widthMode, disabled, status, tagVariant, tagSize }) {
829
871
  const defaultValue = content === 'filled' ? TAGINPUT_SAMPLE_TAGS : [];
830
- const widthClass = widthMode === 'narrow' ? '!w-[220px]' : widthMode === 'wide' ? '!w-[420px]' : '';
831
- const [suggestionIndex, setSuggestionIndex] = useState(0);
832
- const handleRefresh = useCallback(() => {
833
- setSuggestionIndex((prev) => (prev + 1) % TAGINPUT_AI_SUGGESTION_GROUPS.length);
834
- }, []);
872
+ const widthClass = widthMode === 'narrow' ? '!w-[220px] max-w-full' : widthMode === 'wide' ? '!w-[420px] max-w-full' : '';
835
873
  return (
836
- <TagInput
837
- key={`tag-input-${content}-${widthMode}-${disabled}-${status}-${tagVariant}-${tagSize}`}
838
- status={status}
839
- disabled={disabled}
840
- defaultValue={defaultValue}
841
- placeholder="请输入"
842
- tagVariant={tagVariant}
843
- tagSize={tagSize}
844
- aiSuggestions={showAiSuggestions ? TAGINPUT_AI_SUGGESTION_GROUPS[suggestionIndex] : undefined}
845
- onRefreshAiSuggestions={showAiSuggestions ? handleRefresh : undefined}
846
- className={widthClass}
847
- />
874
+ <FormControlPreviewWidth>
875
+ <TagInput
876
+ key={`tag-input-${content}-${widthMode}-${disabled}-${status}-${tagVariant}-${tagSize}`}
877
+ status={status}
878
+ disabled={disabled}
879
+ defaultValue={defaultValue}
880
+ placeholder="请输入"
881
+ tagVariant={tagVariant}
882
+ tagSize={tagSize}
883
+ className={widthClass}
884
+ />
885
+ </FormControlPreviewWidth>
848
886
  );
849
887
  }
850
888
 
@@ -918,7 +956,7 @@ function FormPreview({
918
956
  }))
919
957
  : baseItems;
920
958
 
921
- return (
959
+ const preview = (
922
960
  <Form
923
961
  key={`form-${previewMode}-${fieldType}-${labelPosition}-${helpMode}-${validationState}-${size}-${labelOptional}-${labelRequired}-${labelAi}-${labelHelp}-${JSON.stringify(fieldAtomProps || {})}`}
924
962
  layout="vertical"
@@ -933,6 +971,10 @@ function FormPreview({
933
971
  className={previewMode === 'all' ? '!gap-10' : ''}
934
972
  />
935
973
  );
974
+
975
+ return previewMode === 'all'
976
+ ? preview
977
+ : <FormControlPreviewWidth>{preview}</FormControlPreviewWidth>;
936
978
  }
937
979
 
938
980
  export const PREVIEW_REGISTRY = {
@@ -2541,13 +2583,22 @@ export const PREVIEW_REGISTRY = {
2541
2583
  padding: '48px',
2542
2584
  }),
2543
2585
 
2544
- getPreviewItemStyle: ({ controlValues }) => ({
2545
- width: controlValues.previewMode === 'all' ? 'max-content' : 'auto',
2546
- minWidth: controlValues.previewMode === 'all' ? '300px' : undefined,
2547
- display: 'flex',
2548
- alignItems: controlValues.previewMode === 'all' ? 'flex-start' : 'center',
2549
- justifyContent: controlValues.previewMode === 'all' ? 'flex-start' : 'center',
2550
- }),
2586
+ getPreviewItemStyle: ({ controlValues }) => {
2587
+ if (controlValues.previewMode === 'all') {
2588
+ return {
2589
+ width: 'max-content',
2590
+ minWidth: '300px',
2591
+ display: 'flex',
2592
+ alignItems: 'flex-start',
2593
+ justifyContent: 'flex-start',
2594
+ };
2595
+ }
2596
+
2597
+ return {
2598
+ ...FORM_CONTROL_PREVIEW_ITEM_STYLE,
2599
+ alignItems: 'center',
2600
+ };
2601
+ },
2551
2602
 
2552
2603
  controls: [
2553
2604
  {
@@ -3674,7 +3725,7 @@ export const PREVIEW_REGISTRY = {
3674
3725
  },
3675
3726
  },
3676
3727
  upload: {
3677
- component: Upload,
3728
+ component: UploadPreview,
3678
3729
  tokenMap: UPLOAD_TOKEN_MAP,
3679
3730
  jsxSource: uploadJsxRaw,
3680
3731
 
@@ -3764,7 +3815,7 @@ export const PREVIEW_REGISTRY = {
3764
3815
  },
3765
3816
 
3766
3817
  'date-picker': {
3767
- component: DatePicker,
3818
+ component: DatePickerPreview,
3768
3819
  tokenMap: DATEPICKER_TOKEN_MAP,
3769
3820
  jsxSource: datePickerJsxRaw,
3770
3821
 
@@ -3776,12 +3827,14 @@ export const PREVIEW_REGISTRY = {
3776
3827
 
3777
3828
  if (isOpen) {
3778
3829
  return {
3830
+ ...FORM_CONTROL_PREVIEW_ITEM_STYLE,
3779
3831
  transform: `translateY(-${Math.round((panelHeight + panelGap) / 2)}px)`,
3780
3832
  transition: 'transform 180ms ease',
3781
3833
  };
3782
3834
  }
3783
3835
 
3784
3836
  return {
3837
+ ...FORM_CONTROL_PREVIEW_ITEM_STYLE,
3785
3838
  transform: 'translateY(-56px)',
3786
3839
  transition: 'transform 180ms ease',
3787
3840
  };
@@ -3877,7 +3930,7 @@ export const PREVIEW_REGISTRY = {
3877
3930
  },
3878
3931
 
3879
3932
  'time-picker': {
3880
- component: TimePicker,
3933
+ component: TimePickerPreview,
3881
3934
  tokenMap: TIMEPICKER_TOKEN_MAP,
3882
3935
  jsxSource: timePickerJsxRaw,
3883
3936
 
@@ -3889,12 +3942,14 @@ export const PREVIEW_REGISTRY = {
3889
3942
 
3890
3943
  if (isOpen) {
3891
3944
  return {
3945
+ ...FORM_CONTROL_PREVIEW_ITEM_STYLE,
3892
3946
  transform: `translateY(-${Math.round((panelHeight + panelGap) / 2)}px)`,
3893
3947
  transition: 'transform 180ms ease',
3894
3948
  };
3895
3949
  }
3896
3950
 
3897
3951
  return {
3952
+ ...FORM_CONTROL_PREVIEW_ITEM_STYLE,
3898
3953
  transform: 'translateY(-56px)',
3899
3954
  transition: 'transform 180ms ease',
3900
3955
  };
@@ -4039,16 +4094,6 @@ export const PREVIEW_REGISTRY = {
4039
4094
  ],
4040
4095
  default: 'default',
4041
4096
  },
4042
- {
4043
- id: 'suggestionMode',
4044
- label: 'AI推荐',
4045
- type: 'seg',
4046
- options: [
4047
- { id: 'off', label: '隐藏' },
4048
- { id: 'on', label: '显示' },
4049
- ],
4050
- default: 'on',
4051
- },
4052
4097
  ],
4053
4098
 
4054
4099
  mapProps: (cv, enums) => ({
@@ -4059,7 +4104,6 @@ export const PREVIEW_REGISTRY = {
4059
4104
  status: enums.status || 'default',
4060
4105
  tagVariant: enums.tagVariant || 'grey',
4061
4106
  tagSize: enums.tagSize || 'm',
4062
- showAiSuggestions: (cv.suggestionMode || 'on') === 'on',
4063
4107
  }),
4064
4108
 
4065
4109
  generateUsage: (enums, cv) => {
@@ -4077,10 +4121,6 @@ export const PREVIEW_REGISTRY = {
4077
4121
  if (content === 'filled') {
4078
4122
  props.push('defaultValue={["标签", "标签", "标签", "标签", "标签", "标签"]}');
4079
4123
  }
4080
- if ((cv.suggestionMode || 'on') === 'on') {
4081
- props.push('aiSuggestions={[["改签", "门店变更"], ["退款", "售后处理"], ["物流异常", "催办"]]}');
4082
- props.push('onRefreshAiSuggestions={() => {}}');
4083
- }
4084
4124
 
4085
4125
  lines.push('');
4086
4126
  lines.push('<TagInput');
@@ -110,7 +110,7 @@ export const TOKEN_SIZE = {
110
110
  'icon-14': '14px',
111
111
  'control-sm': '24px',
112
112
  'control-md': '36px',
113
- 'input-width': '300px',
113
+ 'input-width': '100%',
114
114
  };
115
115
 
116
116
  export const TOKEN_LETTER_SPACING = {
package/src/index.d.ts CHANGED
@@ -909,14 +909,6 @@ export interface TagInputProps extends TfdsCommonProps {
909
909
  onChange?: (...args: any[]) => any;
910
910
  /** function, default: null */
911
911
  onRemove?: (...args: any[]) => any;
912
- /** array | string | object, default: null */
913
- aiSuggestion?: unknown;
914
- /** array, default: null */
915
- aiSuggestions?: unknown[];
916
- /** function, default: null */
917
- onAdoptSuggestion?: (...args: any[]) => any;
918
- /** function, default: null */
919
- onRefreshAiSuggestions?: (...args: any[]) => any;
920
912
  /** boolean, default: true */
921
913
  closable?: boolean;
922
914
  /** enum<brand | red | orange | yellow | green | cyan | blue | purple | pink | teal | grey | white>, default: "grey" */
package/theme.css CHANGED
@@ -317,7 +317,7 @@
317
317
  --size-icon-14: 14px;
318
318
  --size-control-sm: 24px;
319
319
  --size-control-md: 36px;
320
- --size-input-width: 300px;
320
+ --size-input-width: 100%;
321
321
 
322
322
  /* ── Shadows ── */
323
323
  --shadow-none: 0 0 #0000;