@rainbow-oh/yee-c 0.6.1 → 0.6.3

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 (72) hide show
  1. package/dist/cjs/Form/demo/layout.js +4 -14
  2. package/dist/cjs/Form/style/index.less +32 -8
  3. package/dist/cjs/Grid/item.js +2 -1
  4. package/dist/cjs/Select/demo/orphan.d.ts +3 -0
  5. package/dist/cjs/Select/demo/orphan.js +78 -0
  6. package/dist/cjs/Select/interface.d.ts +11 -0
  7. package/dist/cjs/Select/select.js +18 -5
  8. package/dist/cjs/Selector/interface.d.ts +11 -0
  9. package/dist/cjs/Selector/selector.js +51 -16
  10. package/dist/cjs/Table/tbody/index.js +2 -2
  11. package/dist/cjs/Tabs/demo/type.js +23 -1
  12. package/dist/cjs/Tabs/hooks/useActiveBar.d.ts +2 -1
  13. package/dist/cjs/Tabs/hooks/useActiveBar.js +7 -3
  14. package/dist/cjs/Tabs/style/index.less +24 -14
  15. package/dist/cjs/Tabs/tab-header/index.js +2 -1
  16. package/dist/cjs/Tabs/tab-header/tab-header-title.js +1 -0
  17. package/dist/cjs/Tag/style/index.less +9 -9
  18. package/dist/cjs/style/color.css +1 -0
  19. package/dist/cjs/style/mobile.css +5 -0
  20. package/dist/cjs/style/size.css +6 -3
  21. package/dist/cjs/style/themes.css +1 -1
  22. package/dist/cjs/style/variables.css +8 -4
  23. package/dist/cjs/version.d.ts +1 -1
  24. package/dist/cjs/version.js +1 -1
  25. package/dist/esm/Form/demo/layout.js +10 -10
  26. package/dist/esm/Form/style/index.less +32 -8
  27. package/dist/esm/Grid/item.js +2 -1
  28. package/dist/esm/Select/demo/orphan.d.ts +3 -0
  29. package/dist/esm/Select/demo/orphan.js +77 -0
  30. package/dist/esm/Select/interface.d.ts +11 -0
  31. package/dist/esm/Select/select.js +22 -6
  32. package/dist/esm/Selector/interface.d.ts +11 -0
  33. package/dist/esm/Selector/selector.js +34 -10
  34. package/dist/esm/Table/tbody/index.js +3 -2
  35. package/dist/esm/Tabs/demo/type.js +15 -4
  36. package/dist/esm/Tabs/hooks/useActiveBar.d.ts +2 -1
  37. package/dist/esm/Tabs/hooks/useActiveBar.js +7 -3
  38. package/dist/esm/Tabs/style/index.less +24 -14
  39. package/dist/esm/Tabs/tab-header/index.js +2 -1
  40. package/dist/esm/Tabs/tab-header/tab-header-title.js +1 -0
  41. package/dist/esm/Tag/style/index.less +9 -9
  42. package/dist/esm/style/color.css +1 -0
  43. package/dist/esm/style/mobile.css +5 -0
  44. package/dist/esm/style/size.css +6 -3
  45. package/dist/esm/style/themes.css +1 -1
  46. package/dist/esm/style/variables.css +8 -4
  47. package/dist/esm/version.d.ts +1 -1
  48. package/dist/esm/version.js +1 -1
  49. package/dist/umd/yee-c.min.css +2 -2
  50. package/dist/umd/yee-c.min.js +1 -1
  51. package/package.json +1 -1
  52. package/src/Form/demo/layout.tsx +7 -12
  53. package/src/Form/style/index.less +32 -8
  54. package/src/Grid/item.tsx +2 -1
  55. package/src/Select/demo/orphan.tsx +61 -0
  56. package/src/Select/index.en-US.md +3 -0
  57. package/src/Select/index.zh-CN.md +3 -0
  58. package/src/Select/interface.ts +11 -0
  59. package/src/Select/select.tsx +19 -3
  60. package/src/Selector/interface.ts +11 -0
  61. package/src/Selector/selector.tsx +56 -25
  62. package/src/Table/tbody/index.tsx +5 -3
  63. package/src/Tabs/demo/type.tsx +21 -2
  64. package/src/Tabs/hooks/useActiveBar.ts +8 -4
  65. package/src/Tabs/style/index.less +24 -14
  66. package/src/Tabs/tab-header/index.tsx +2 -1
  67. package/src/Tabs/tab-header/tab-header-title.tsx +1 -0
  68. package/src/Tag/style/index.less +9 -9
  69. package/src/style/color.css +1 -0
  70. package/src/style/mobile.css +5 -0
  71. package/src/style/size.css +6 -3
  72. package/src/version.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rainbow-oh/yee-c",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "yee basic components",
5
5
  "keywords": [
6
6
  "react",
@@ -1,31 +1,26 @@
1
1
  import { Button, Form, Grid, Input, Radio, Space } from '@rainbow-oh/yee-c';
2
- import React from 'react';
2
+ import React, { useState } from 'react';
3
3
 
4
4
  export default () => {
5
5
  const [form] = Form.useForm();
6
+ const [layout, setLayout] = useState<'vertical' | 'horizontal'>('vertical');
6
7
 
7
8
  return (
8
9
  <div>
9
10
  <Radio.Group
10
- defaultValue="vertical"
11
- onChange={(value) => {
12
- form.setFieldsValue({ layout: value });
13
- }}
11
+ value={layout}
12
+ onChange={(value) => setLayout(value as 'vertical' | 'horizontal')}
14
13
  options={[
15
14
  { value: 'vertical', label: 'Vertical' },
16
15
  { value: 'horizontal', label: 'Horizontal' },
17
16
  ]}
18
- ></Radio.Group>
17
+ />
19
18
 
20
19
  <br />
21
20
  <br />
22
21
 
23
- <Form
24
- form={form}
25
- initialValues={{ layout: 'vertical' }}
26
- layout="vertical"
27
- >
28
- <Grid cols={1}>
22
+ <Form form={form} initialValues={{}} layout={layout}>
23
+ <Grid cols={2}>
29
24
  <Form.Field name="name" label="Name" required>
30
25
  <Input placeholder="Please input your name" />
31
26
  </Form.Field>
@@ -1,16 +1,40 @@
1
1
  @pls: .yee-form;
2
2
 
3
+ // Horizontal form-item layout: label pinned left at a fixed width (right-
4
+ // aligned), control fills the remaining space. Shared by Form-level layout
5
+ // (ancestor .yee-form-horizontal cascades onto every item, including
6
+ // Field.Group) and Field-level layout (the item carries .yee-form-item-
7
+ // horizontal itself). Uses descendant selectors (not &) so the mixin expands
8
+ // correctly under either anchor.
9
+ .horizontal-layout() {
10
+ @{pls}-item-row {
11
+ display: flex;
12
+ align-items: flex-start;
13
+ gap: var(--yee-form-item-horizontal-label-gap, 12px);
14
+ }
15
+
16
+ @{pls}-item-label {
17
+ width: var(--yee-form-item-horizontal-label-width, 120px);
18
+ flex-shrink: 0;
19
+ margin-bottom: 0;
20
+ justify-content: flex-end;
21
+ }
22
+
23
+ @{pls}-item-control {
24
+ flex: 1;
25
+ min-width: 0;
26
+ }
27
+ }
28
+
3
29
  @{pls} {
30
+ // Form-level horizontal: cascades onto every descendant item.
4
31
  &-horizontal {
5
- @{pls}-item {
6
- &-row {
7
- display: flex;
8
- }
32
+ .horizontal-layout();
33
+ }
9
34
 
10
- &-label {
11
- margin-bottom: 0;
12
- }
13
- }
35
+ // Field-level horizontal: a single item opts in via layout="horizontal".
36
+ &-item-horizontal {
37
+ .horizontal-layout();
14
38
  }
15
39
 
16
40
  &-item {
package/src/Grid/item.tsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import clsx from 'clsx';
2
2
  import React from 'react';
3
+ import omit from '../utils/omit';
3
4
  import type { GridItemProps } from './interface';
4
5
 
5
6
  const Item: React.FC<GridItemProps> = (props) => {
@@ -15,7 +16,7 @@ const Item: React.FC<GridItemProps> = (props) => {
15
16
  <div
16
17
  className={clsx(`${prefixCls}-item`, className)}
17
18
  style={{ ...spanStyle, ...style }}
18
- {...rest}
19
+ {...omit(rest, ['colspan'])}
19
20
  >
20
21
  {children}
21
22
  </div>
@@ -0,0 +1,61 @@
1
+ import { Select, Space } from '@rainbow-oh/yee-c';
2
+ import React, { useState } from 'react';
3
+
4
+ const options = [
5
+ { label: 'Apple', value: 'apple' },
6
+ { label: 'Banana', value: 'banana' },
7
+ { label: 'Orange', value: 'orange' },
8
+ { label: 'Pineapple', value: 'pineapple' },
9
+ ];
10
+
11
+ // Inline style applied to an orphan value (a value not present in options)
12
+ const orphanStyle: React.CSSProperties = {
13
+ color: '#fa8c16',
14
+ fontStyle: 'italic',
15
+ textDecoration: 'underline dotted',
16
+ };
17
+
18
+ export default () => {
19
+ // 'mangox' is not in options → rendered as an orphan value
20
+ const [single, setSingle] = useState('mangox');
21
+ // 'durian' is not in options → rendered as an orphan tag alongside normal ones
22
+ const [multi, setMulti] = useState(['apple', 'durian', 'banana']);
23
+
24
+ return (
25
+ <Space direction="vertical" style={{ width: '100%' }}>
26
+ <div>
27
+ <div style={{ marginBottom: 8 }}>
28
+ Single — orphan value styled via <code>orphanStyle</code>
29
+ </div>
30
+ <Select
31
+ value={single}
32
+ onChange={(val) => setSingle(val as string)}
33
+ options={options}
34
+ orphanStyle={orphanStyle}
35
+ style={{ width: 300 }}
36
+ placeholder="Please select"
37
+ />
38
+ </div>
39
+ <div>
40
+ <div style={{ marginBottom: 8 }}>
41
+ Multiple — orphan tag styled via <code>orphanClassName</code>
42
+ </div>
43
+ <Select
44
+ mode="multiple"
45
+ value={multi}
46
+ onChange={(val) => setMulti(val as string[])}
47
+ options={options}
48
+ orphanClassName="demo-orphan-tag"
49
+ style={{ width: 300 }}
50
+ placeholder="Please select"
51
+ />
52
+ </div>
53
+ <style>{`
54
+ .demo-orphan-tag {
55
+ color: #fa541c;
56
+ font-style: italic;
57
+ }
58
+ `}</style>
59
+ </Space>
60
+ );
61
+ };
@@ -21,6 +21,7 @@ Select component for choosing from a set of options.
21
21
  <code src="./demo/multiple.tsx" title="Multiple" description="Multiple selection mode"></code>
22
22
  <code src="./demo/search.tsx" title="Search" description="Searchable Select"></code>
23
23
  <code src="./demo/tags.tsx" title="Tags" description="Tags mode Select"></code>
24
+ <code src="./demo/orphan.tsx" title="Orphan Value" description="Display and custom styling when the value is not in options"></code>
24
25
  <code src="./demo/virtual.tsx" title="Virtual Scroll" description="Virtual scrolling for large datasets (thousands of options)"></code>
25
26
 
26
27
  ## API
@@ -45,6 +46,8 @@ Select component for choosing from a set of options.
45
46
  | codeTableName | `string` | Code table name | - |
46
47
  | optionFilterProp | `string` | Property to filter by when searching | `label` |
47
48
  | optionLabelProp | `string \| (() => string)` | Property to display in the input box | - |
49
+ | orphanClassName | `string` | Extra class name for the displayed value when it is not in `options` (orphan value). An orphan value is shown as the raw value itself by default | - |
50
+ | orphanStyle | `React.CSSProperties` | Extra inline style for the displayed value when it is not in `options` (orphan value) | - |
48
51
  | onChange | `(value: string \| number \| Array<string \| number>, options?: Option \| undefined \| Option[]) => void` | Value change callback | - |
49
52
  | onFilter | `(value: string, options: Array<Option>) => Array<Option>` | Search callback | - |
50
53
  | virtual | `boolean` | Enable virtual scrolling. Only the options in the visible window are rendered, so the DOM node count stays constant regardless of the total. Recommended for hundreds or thousands of options | `false` |
@@ -21,6 +21,7 @@ toc: 'content'
21
21
  <code src="./demo/multiple.tsx" title="多选" description="多选模式"></code>
22
22
  <code src="./demo/search.tsx" title="可搜索" description="可搜索的Select"></code>
23
23
  <code src="./demo/tags.tsx" title="标签模式" description="标签模式的Select"></code>
24
+ <code src="./demo/orphan.tsx" title="孤儿值" description="value 不在 options 中时的显示与自定义样式"></code>
24
25
  <code src="./demo/virtual.tsx" title="虚拟滚动" description="大数据量(几千条)下的虚拟滚动"></code>
25
26
 
26
27
  ## API
@@ -45,6 +46,8 @@ toc: 'content'
45
46
  | codeTableName | `string` | 代码表 | - |
46
47
  | optionFilterProp | `string` | 搜索时对比的属性 | `label` |
47
48
  | optionLabelProp | `string \| (() => string)` | 回填到选择框里的属性 | - |
49
+ | orphanClassName | `string` | value 不在 options 中(孤儿值)时,给显示值追加的类名。孤儿值默认直接显示 value 本身 | - |
50
+ | orphanStyle | `React.CSSProperties` | value 不在 options 中(孤儿值)时,给显示值追加的行内样式 | - |
48
51
  | onChange | `(value: string \| number \| Array<string \| number>, options?: Option \| undefined \| Option[]) => void` | 值改变时的回调函数 | - |
49
52
  | onFilter | `(value: string, options: Array<Option>) => Array<Option>` | 搜索时的回调函数 | - |
50
53
  | virtual | `boolean` | 是否开启虚拟滚动。开启后仅渲染可视区内的选项,DOM 节点数与数据总量无关,适合成百上千条数据 | `false` |
@@ -95,6 +95,17 @@ export interface SelectProps
95
95
  * Property to backfill into the select box
96
96
  */
97
97
  optionLabelProp?: 'string' | (() => string);
98
+ /**
99
+ * Extra class name applied to the displayed value when it is not found
100
+ * in `options` (an "orphan" value). An orphan value is shown as the raw
101
+ * value itself; this lets you style it differently (e.g. to flag stale data).
102
+ */
103
+ orphanClassName?: string;
104
+ /**
105
+ * Extra inline style applied to the displayed value when it is not found
106
+ * in `options` (an "orphan" value).
107
+ */
108
+ orphanStyle?: React.CSSProperties;
98
109
  /**
99
110
  * Callback when value changes
100
111
  */
@@ -32,6 +32,8 @@ const Select = (baseprops: SelectProps) => {
32
32
  virtual,
33
33
  itemHeight,
34
34
  listHeight,
35
+ orphanClassName,
36
+ orphanStyle,
35
37
  ...rest
36
38
  } = props;
37
39
 
@@ -68,7 +70,9 @@ const Select = (baseprops: SelectProps) => {
68
70
  virtualApiRef.current?.scrollToIndex(index);
69
71
  }, []);
70
72
 
71
- const getOptions = (keys: string | number | Array<string | number>) => {
73
+ const getOptions = (
74
+ keys: string | number | Array<string | number>,
75
+ ) => {
72
76
  if (keys === '' || keys === null) {
73
77
  return undefined;
74
78
  }
@@ -76,10 +80,20 @@ const Select = (baseprops: SelectProps) => {
76
80
  if (keys.length === 0) {
77
81
  return [];
78
82
  }
79
- return options.filter((opt) => keys.includes(opt.value));
83
+ // 按 keys 顺序回填,找不到的 key 构造 label=value 的兜底项(孤儿值),
84
+ // 与 Selector 的显示保持一致,避免 onChange 第二参数丢值。
85
+ return keys.map((key) => {
86
+ const opt = options.find((o) => o.value === key);
87
+ return opt ?? { value: key, label: String(key) };
88
+ });
80
89
  }
81
90
 
82
- return options.find((opt) => opt.value === keys);
91
+ return (
92
+ options.find((opt) => opt.value === keys) ?? {
93
+ value: keys,
94
+ label: String(keys),
95
+ }
96
+ );
83
97
  };
84
98
 
85
99
  const handleSelect = (
@@ -193,6 +207,8 @@ const Select = (baseprops: SelectProps) => {
193
207
  onRemove={handleRemove as any}
194
208
  onSearch={handleSearch}
195
209
  onKeyDown={onKeyDown}
210
+ orphanClassName={orphanClassName}
211
+ orphanStyle={orphanStyle}
196
212
  />
197
213
  </Trigger>
198
214
  );
@@ -79,6 +79,17 @@ export interface PureSelectorProps {
79
79
  * Custom text displayed in the input
80
80
  */
81
81
  optionLabelProp?: string | ((option: TagType) => string);
82
+ /**
83
+ * Extra class name applied to the displayed value/tag when its key is not
84
+ * found in `options` (an "orphan" value). The orphan value is shown as the
85
+ * raw key itself; this lets you style it differently (e.g. to flag stale data).
86
+ */
87
+ orphanClassName?: string;
88
+ /**
89
+ * Extra inline style applied to the displayed value/tag when its key is not
90
+ * found in `options` (an "orphan" value).
91
+ */
92
+ orphanStyle?: React.CSSProperties;
82
93
 
83
94
  /**
84
95
  * Control the open state
@@ -37,6 +37,8 @@ const Selector = React.forwardRef(
37
37
  disabled,
38
38
  options = [],
39
39
  selectedKeys,
40
+ orphanClassName,
41
+ orphanStyle,
40
42
  allowClear = true,
41
43
  placeholder,
42
44
  closable = true,
@@ -60,17 +62,29 @@ const Selector = React.forwardRef(
60
62
  });
61
63
 
62
64
  const tags = useMemo(() => {
63
- return Array.isArray(options)
64
- ? options
65
- .filter((opt) => selectedKeys.includes(opt.value))
66
- .map((opt) => ({
67
- ...opt,
68
- children:
69
- typeof optionLabelProp === 'function'
70
- ? optionLabelProp(opt)
71
- : opt[optionLabelProp],
72
- }))
73
- : [];
65
+ if (!Array.isArray(options)) {
66
+ return [];
67
+ }
68
+ // 按 selectedKeys 顺序渲染;找不到的 key 作为孤儿值回退显示 value 本身
69
+ return selectedKeys.map((key) => {
70
+ const opt = options.find((o) => o.value === key);
71
+ if (opt) {
72
+ return {
73
+ ...opt,
74
+ children:
75
+ typeof optionLabelProp === 'function'
76
+ ? optionLabelProp(opt)
77
+ : opt[optionLabelProp],
78
+ _orphan: false,
79
+ };
80
+ }
81
+ return {
82
+ value: key,
83
+ label: String(key),
84
+ children: String(key),
85
+ _orphan: true,
86
+ };
87
+ });
74
88
  }, [options, selectedKeys, optionLabelProp]);
75
89
 
76
90
  const handleClick = () => {
@@ -148,37 +162,54 @@ const Selector = React.forwardRef(
148
162
 
149
163
  const renderContent = () => {
150
164
  if (multi) {
151
- return tags.map((item: TagType & { children: any }, index) => {
152
- const _closable =
153
- typeof closable === 'function' ? closable(item) : closable;
154
- return (
155
- <Tag
156
- {...item}
157
- closable={_closable}
158
- onClose={(e) => handleRemove(item, e)}
159
- key={item.value || index}
160
- />
161
- );
162
- });
165
+ return tags.map(
166
+ (item: TagType & { children: any; _orphan?: boolean }, index) => {
167
+ const { _orphan, ...tagRest } = item;
168
+ const _closable =
169
+ typeof closable === 'function' ? closable(item) : closable;
170
+ return (
171
+ <Tag
172
+ {...tagRest}
173
+ className={_orphan ? orphanClassName : undefined}
174
+ style={_orphan ? orphanStyle : undefined}
175
+ closable={_closable}
176
+ onClose={(e) => handleRemove(item, e)}
177
+ key={item.value || index}
178
+ />
179
+ );
180
+ },
181
+ );
163
182
  }
164
183
 
165
184
  const key = selectedKeys.length ? selectedKeys[0] : '';
166
185
  const opt = Array.isArray(options)
167
186
  ? options.find((opt) => opt.value === key)
168
187
  : null;
188
+ // 孤儿值:key 非空但在 options 中找不到时,回退显示 value 本身
189
+ const isOrphan = !opt && key !== '';
169
190
  const label = (
170
191
  opt
171
192
  ? typeof optionLabelProp === 'function'
172
193
  ? optionLabelProp(opt)
173
194
  : opt[optionLabelProp]
174
- : null
195
+ : isOrphan
196
+ ? String(key)
197
+ : null
175
198
  ) as React.ReactNode;
176
199
 
177
200
  return (
178
201
  <>
179
202
  {renderSearch()}
180
203
  {label && (
181
- <div className={`${prefixCls}-selection-item`}>{label}</div>
204
+ <div
205
+ className={clsx(
206
+ `${prefixCls}-selection-item`,
207
+ isOrphan && orphanClassName,
208
+ )}
209
+ style={isOrphan ? orphanStyle : undefined}
210
+ >
211
+ {label}
212
+ </div>
182
213
  )}
183
214
  </>
184
215
  );
@@ -6,7 +6,7 @@ import LazyRow from './lazy-row';
6
6
  import TableRow from './row';
7
7
 
8
8
  const TableBody: React.FC<TableBodyProps> = (props) => {
9
- const { columns, pageData, lazyLoad, ...rest } = props;
9
+ const { columns, pageData, lazyLoad, noData, ...rest } = props;
10
10
 
11
11
  const { prefixCls, components, rowKey } = React.useContext(TableCtx);
12
12
  const { locale } = useLocale();
@@ -15,7 +15,7 @@ const TableBody: React.FC<TableBodyProps> = (props) => {
15
15
  const empty = (
16
16
  <tbody className={`${prefixCls}-tbody`}>
17
17
  <tr className={`${prefixCls}-no-record`}>
18
- <td colSpan={999}>{tableLocale.emptyText}</td>
18
+ <td colSpan={999}>{noData ?? tableLocale.emptyText}</td>
19
19
  </tr>
20
20
  </tbody>
21
21
  );
@@ -60,7 +60,9 @@ const TableBody: React.FC<TableBodyProps> = (props) => {
60
60
  };
61
61
 
62
62
  const tbody = (
63
- <BodyWrapper className={`${prefixCls}-tbody`}>{getRenderRows()}</BodyWrapper>
63
+ <BodyWrapper className={`${prefixCls}-tbody`}>
64
+ {getRenderRows()}
65
+ </BodyWrapper>
64
66
  );
65
67
 
66
68
  return tbody;
@@ -1,4 +1,4 @@
1
- import { Tabs } from '@rainbow-oh/yee-c';
1
+ import { Box, Tabs } from '@rainbow-oh/yee-c';
2
2
  import React from 'react';
3
3
 
4
4
  export default () => {
@@ -20,5 +20,24 @@ export default () => {
20
20
  },
21
21
  ];
22
22
 
23
- return <Tabs defaultActiveKey="1" items={items} type="card" />;
23
+ return (
24
+ <Box
25
+ style={{
26
+ padding: 16,
27
+ backgroundColor: '#efefef',
28
+ }}
29
+ >
30
+ <Tabs
31
+ defaultActiveKey="1"
32
+ items={items}
33
+ type="card"
34
+ styles={{
35
+ content: {
36
+ padding: 24,
37
+ height: 120,
38
+ },
39
+ }}
40
+ />
41
+ </Box>
42
+ );
24
43
  };
@@ -5,6 +5,7 @@ interface UseActiveBarOptions {
5
5
  activeKey: string | number;
6
6
  activetab: React.RefObject<HTMLElement | null>;
7
7
  activebar: React.RefObject<HTMLDivElement | null>;
8
+ listEle: React.RefObject<HTMLDivElement | null>;
8
9
  enabled: boolean;
9
10
  }
10
11
 
@@ -13,6 +14,7 @@ export function useActiveBar({
13
14
  activeKey,
14
15
  activetab,
15
16
  activebar,
17
+ listEle,
16
18
  enabled,
17
19
  }: UseActiveBarOptions) {
18
20
  const rafIdRef = useRef<number>(0);
@@ -20,18 +22,20 @@ export function useActiveBar({
20
22
  const moveActiveBar = useCallback(() => {
21
23
  const bar = activebar.current;
22
24
  const tab = activetab.current;
25
+ const nav = listEle.current;
23
26
 
24
- if (!bar || !tab || !enabled) return;
27
+ if (!bar || !tab || !enabled || !nav) return;
25
28
 
26
29
  const rect = tab.getBoundingClientRect();
30
+ const listPaddingLeft = parseFloat(getComputedStyle(nav).paddingLeft) || 0;
31
+ const listPaddingTop = parseFloat(getComputedStyle(nav).paddingTop) || 0;
27
32
  const isHorizontal = direction === 'horizontal';
28
-
29
33
  if (isHorizontal) {
30
34
  bar.style.width = `${rect.width}px`;
31
- bar.style.transform = `translateX(${tab.offsetLeft}px)`;
35
+ bar.style.transform = `translateX(${tab.offsetLeft - listPaddingLeft}px)`;
32
36
  } else {
33
37
  bar.style.height = `${rect.height}px`;
34
- bar.style.transform = `translateY(${tab.offsetTop}px)`;
38
+ bar.style.transform = `translateY(${tab.offsetTop - listPaddingTop}px)`;
35
39
  }
36
40
  }, [direction, activetab, activebar, enabled]);
37
41
 
@@ -51,9 +51,9 @@
51
51
  padding: var(--yee-tabs-vertical-padding);
52
52
  overflow: hidden;
53
53
 
54
- @{pls}-nav-wrap {
54
+ @{pls}-nav-track {
55
55
  height: 100%;
56
- padding: var(--yee-tabs-vertical-nav-wrap-padding);
56
+ padding: var(--yee-tabs-vertical-nav-track-padding);
57
57
  overflow-y: auto;
58
58
  scrollbar-width: none;
59
59
  -ms-overflow-style: none;
@@ -109,9 +109,9 @@
109
109
  overflow: hidden;
110
110
  transition: transform 3s ease-in-out;
111
111
 
112
- &:not(@{pls}-card) {
113
- background-color: var(--yee-tabs-bg-color);
114
- }
112
+ // &:not(@{pls}-card) {
113
+ // background-color: var(--yee-tabs-bg-color);
114
+ // }
115
115
 
116
116
  &@{pls}-nav-wrapper-left,
117
117
  &@{pls}-nav-wrapper-right {
@@ -141,7 +141,7 @@
141
141
  }
142
142
 
143
143
  &.center {
144
- @{pls}-nav-wrap {
144
+ @{pls}-nav-track {
145
145
  justify-content: center;
146
146
  }
147
147
  }
@@ -261,7 +261,7 @@
261
261
  display: none;
262
262
  }
263
263
 
264
- @{pls}-nav-wrap {
264
+ @{pls}-nav-track {
265
265
  padding: 0;
266
266
  }
267
267
 
@@ -276,6 +276,16 @@
276
276
  background-color: var(--yee-tabs-card-bg-color);
277
277
  }
278
278
 
279
+ &@{pls}-top {
280
+ @{pls}-nav-wrapper {
281
+ border-bottom: none;
282
+ }
283
+ }
284
+
285
+ @{pls}-container {
286
+ background-color: var(--yee-tabs-conatiner-bg-color);
287
+ }
288
+
279
289
  &@{pls}-border-card {
280
290
  > @{pls}-nav-wrapper {
281
291
  bottom: var(--yee-tabs-card-border-bottom);
@@ -313,7 +323,7 @@
313
323
 
314
324
  @{pls}-editable-card,
315
325
  @{pls}-card {
316
- @{pls}-nav-wrap {
326
+ @{pls}-nav-track {
317
327
  padding: 0;
318
328
  }
319
329
 
@@ -344,16 +354,16 @@
344
354
  }
345
355
  }
346
356
 
347
- @{pls}-nav-wrap {
357
+ @{pls}-nav-track {
348
358
  position: relative;
349
359
  width: 100%;
350
360
  overflow: hidden;
351
361
  white-space: nowrap;
352
362
 
353
- &.is-scroll {
354
- width: var(--yee-tabs-nav-wrap-scroll-width);
355
- margin-left: var(--yee-tabs-nav-wrap-scroll-margin-left);
356
- }
363
+ // &.is-scroll {
364
+ // width: var(--yee-tabs-nav-track-scroll-width);
365
+ // margin-left: var(--yee-tabs-nav-track-scroll-margin-left);
366
+ // }
357
367
 
358
368
  &::-webkit-scrollbar {
359
369
  display: none;
@@ -513,7 +523,7 @@
513
523
  }
514
524
  }
515
525
 
516
- @{pls}-nav-wrap {
526
+ @{pls}-nav-track {
517
527
  padding: 0;
518
528
  }
519
529
  }
@@ -93,6 +93,7 @@ const TabHeader: React.FC<TabHeaderProps> = (props) => {
93
93
  activeKey,
94
94
  activetab,
95
95
  activebar,
96
+ listEle: navList,
96
97
  enabled: !type, // Only show active bar for non-card types
97
98
  });
98
99
 
@@ -161,7 +162,7 @@ const TabHeader: React.FC<TabHeaderProps> = (props) => {
161
162
 
162
163
  <TabHeaderCtx.Provider value={contextValue}>
163
164
  <div
164
- className={clsx(`${prefixCls}-nav-wrap`, classNames?.track)}
165
+ className={clsx(`${prefixCls}-nav-track`, classNames?.track)}
165
166
  style={styles?.track}
166
167
  ref={navContainer}
167
168
  >
@@ -181,6 +181,7 @@ const TabHeaderTitle: React.FC<TabsItemProps> = (props) => {
181
181
  <Button
182
182
  type="text"
183
183
  size="small"
184
+ className={`${prefixCls}-close`}
184
185
  icon={<X size={14} />}
185
186
  onClick={handleEdit}
186
187
  aria-label={`Close ${label}`}
@@ -149,15 +149,6 @@
149
149
  line-height: var(--yee-tag-large-height);
150
150
  }
151
151
 
152
- &-close {
153
- display: inline-flex;
154
- padding: 0;
155
- width: 16px;
156
- height: 16px;
157
- margin-left: var(--yee-tag-close-margin-left);
158
- cursor: pointer;
159
- }
160
-
161
152
  &-checkable {
162
153
  margin: var(--yee-tag-checkable-margin);
163
154
  color: var(--yee-tag-item-not-check-color);
@@ -177,4 +168,13 @@
177
168
  background-color: var(--yee-tag-item-check-active-bg-color);
178
169
  border-color: var(--yee-tag-item-check-active-border-color);
179
170
  }
171
+
172
+ & &-close {
173
+ display: inline-flex;
174
+ padding: 0;
175
+ width: 16px;
176
+ height: 16px;
177
+ margin-left: var(--yee-tag-close-margin-left);
178
+ cursor: pointer;
179
+ }
180
180
  }