@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.
- package/dist/cjs/Form/demo/layout.js +4 -14
- package/dist/cjs/Form/style/index.less +32 -8
- package/dist/cjs/Grid/item.js +2 -1
- package/dist/cjs/Select/demo/orphan.d.ts +3 -0
- package/dist/cjs/Select/demo/orphan.js +78 -0
- package/dist/cjs/Select/interface.d.ts +11 -0
- package/dist/cjs/Select/select.js +18 -5
- package/dist/cjs/Selector/interface.d.ts +11 -0
- package/dist/cjs/Selector/selector.js +51 -16
- package/dist/cjs/Table/tbody/index.js +2 -2
- package/dist/cjs/Tabs/demo/type.js +23 -1
- package/dist/cjs/Tabs/hooks/useActiveBar.d.ts +2 -1
- package/dist/cjs/Tabs/hooks/useActiveBar.js +7 -3
- package/dist/cjs/Tabs/style/index.less +24 -14
- package/dist/cjs/Tabs/tab-header/index.js +2 -1
- package/dist/cjs/Tabs/tab-header/tab-header-title.js +1 -0
- package/dist/cjs/Tag/style/index.less +9 -9
- package/dist/cjs/style/color.css +1 -0
- package/dist/cjs/style/mobile.css +5 -0
- package/dist/cjs/style/size.css +6 -3
- package/dist/cjs/style/themes.css +1 -1
- package/dist/cjs/style/variables.css +8 -4
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/Form/demo/layout.js +10 -10
- package/dist/esm/Form/style/index.less +32 -8
- package/dist/esm/Grid/item.js +2 -1
- package/dist/esm/Select/demo/orphan.d.ts +3 -0
- package/dist/esm/Select/demo/orphan.js +77 -0
- package/dist/esm/Select/interface.d.ts +11 -0
- package/dist/esm/Select/select.js +22 -6
- package/dist/esm/Selector/interface.d.ts +11 -0
- package/dist/esm/Selector/selector.js +34 -10
- package/dist/esm/Table/tbody/index.js +3 -2
- package/dist/esm/Tabs/demo/type.js +15 -4
- package/dist/esm/Tabs/hooks/useActiveBar.d.ts +2 -1
- package/dist/esm/Tabs/hooks/useActiveBar.js +7 -3
- package/dist/esm/Tabs/style/index.less +24 -14
- package/dist/esm/Tabs/tab-header/index.js +2 -1
- package/dist/esm/Tabs/tab-header/tab-header-title.js +1 -0
- package/dist/esm/Tag/style/index.less +9 -9
- package/dist/esm/style/color.css +1 -0
- package/dist/esm/style/mobile.css +5 -0
- package/dist/esm/style/size.css +6 -3
- package/dist/esm/style/themes.css +1 -1
- package/dist/esm/style/variables.css +8 -4
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/umd/yee-c.min.css +2 -2
- package/dist/umd/yee-c.min.js +1 -1
- package/package.json +1 -1
- package/src/Form/demo/layout.tsx +7 -12
- package/src/Form/style/index.less +32 -8
- package/src/Grid/item.tsx +2 -1
- package/src/Select/demo/orphan.tsx +61 -0
- package/src/Select/index.en-US.md +3 -0
- package/src/Select/index.zh-CN.md +3 -0
- package/src/Select/interface.ts +11 -0
- package/src/Select/select.tsx +19 -3
- package/src/Selector/interface.ts +11 -0
- package/src/Selector/selector.tsx +56 -25
- package/src/Table/tbody/index.tsx +5 -3
- package/src/Tabs/demo/type.tsx +21 -2
- package/src/Tabs/hooks/useActiveBar.ts +8 -4
- package/src/Tabs/style/index.less +24 -14
- package/src/Tabs/tab-header/index.tsx +2 -1
- package/src/Tabs/tab-header/tab-header-title.tsx +1 -0
- package/src/Tag/style/index.less +9 -9
- package/src/style/color.css +1 -0
- package/src/style/mobile.css +5 -0
- package/src/style/size.css +6 -3
- package/src/version.ts +1 -1
package/package.json
CHANGED
package/src/Form/demo/layout.tsx
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
17
|
+
/>
|
|
19
18
|
|
|
20
19
|
<br />
|
|
21
20
|
<br />
|
|
22
21
|
|
|
23
|
-
<Form
|
|
24
|
-
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
display: flex;
|
|
8
|
-
}
|
|
32
|
+
.horizontal-layout();
|
|
33
|
+
}
|
|
9
34
|
|
|
10
|
-
|
|
11
|
-
|
|
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` |
|
package/src/Select/interface.ts
CHANGED
|
@@ -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
|
*/
|
package/src/Select/select.tsx
CHANGED
|
@@ -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 = (
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
:
|
|
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
|
|
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`}>
|
|
63
|
+
<BodyWrapper className={`${prefixCls}-tbody`}>
|
|
64
|
+
{getRenderRows()}
|
|
65
|
+
</BodyWrapper>
|
|
64
66
|
);
|
|
65
67
|
|
|
66
68
|
return tbody;
|
package/src/Tabs/demo/type.tsx
CHANGED
|
@@ -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
|
|
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-
|
|
54
|
+
@{pls}-nav-track {
|
|
55
55
|
height: 100%;
|
|
56
|
-
padding: var(--yee-tabs-vertical-nav-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
355
|
-
|
|
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-
|
|
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-
|
|
165
|
+
className={clsx(`${prefixCls}-nav-track`, classNames?.track)}
|
|
165
166
|
style={styles?.track}
|
|
166
167
|
ref={navContainer}
|
|
167
168
|
>
|
package/src/Tag/style/index.less
CHANGED
|
@@ -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
|
}
|