Skip to content

Commit 2cda99f

Browse files
committed
feat(ui): add group renderer
1 parent 7e3d257 commit 2cda99f

12 files changed

Lines changed: 242 additions & 137 deletions

File tree

packages/ui/src/components/checkbox/Checkbox.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { DBaseInput } from '../_base-input';
1111
import { useFormControl } from '../form';
1212
import { useComponentConfig, usePrefixConfig } from '../root';
1313
import { DCheckboxGroup } from './CheckboxGroup';
14+
import { DCheckboxGroupRenderer } from './CheckboxGroupRenderer';
1415

1516
export interface DCheckboxProps extends React.HTMLAttributes<HTMLElement> {
1617
dRef?: {
@@ -28,6 +29,7 @@ const { COMPONENT_NAME } = registerComponentMate({ COMPONENT_NAME: 'DCheckbox' a
2829
export const DCheckbox: {
2930
(props: DCheckboxProps): JSX.Element | null;
3031
Group: typeof DCheckboxGroup;
32+
GroupRenderer: typeof DCheckboxGroupRenderer;
3133
} = (props) => {
3234
const {
3335
children,
@@ -98,3 +100,4 @@ export const DCheckbox: {
98100
};
99101

100102
DCheckbox.Group = DCheckboxGroup;
103+
DCheckbox.GroupRenderer = DCheckboxGroupRenderer;
Lines changed: 20 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
import type { DId } from '../../utils/types';
22
import type { DFormControl } from '../form';
3+
import type { DCheckboxItem } from './CheckboxGroupRenderer';
34

45
import { getClassName } from '@react-devui/utils';
56

6-
import { useGeneralContext, useDValue } from '../../hooks';
7-
import { cloneHTMLElement, registerComponentMate } from '../../utils';
8-
import { useFormControl } from '../form';
7+
import { registerComponentMate } from '../../utils';
98
import { useComponentConfig, usePrefixConfig } from '../root';
10-
import { DCheckbox } from './Checkbox';
9+
import { DCheckboxGroupRenderer } from './CheckboxGroupRenderer';
1110

12-
export interface DCheckboxItem<V extends DId> {
13-
label: React.ReactNode;
14-
value: V;
15-
disabled?: boolean;
16-
}
1711
export interface DCheckboxGroupProps<V extends DId> extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {
1812
dFormControl?: DFormControl;
1913
dModel?: V[];
@@ -38,48 +32,26 @@ export function DCheckboxGroup<V extends DId>(props: DCheckboxGroupProps<V>): JS
3832

3933
//#region Context
4034
const dPrefix = usePrefixConfig();
41-
const { gDisabled } = useGeneralContext();
4235
//#endregion
4336

44-
const formControlInject = useFormControl(dFormControl);
45-
const [value, changeValue] = useDValue<V[]>([], dModel, onModelChange, undefined, formControlInject);
46-
47-
const disabled = dDisabled || gDisabled || dFormControl?.control.disabled;
48-
4937
return (
50-
<div
51-
{...restProps}
52-
className={getClassName(restProps.className, `${dPrefix}checkbox-group`, {
53-
[`${dPrefix}checkbox-group--vertical`]: dVertical,
54-
})}
55-
role="group"
56-
>
57-
{dList.map((item, index) => (
58-
<DCheckbox
59-
key={item.value}
60-
dDisabled={item.disabled || disabled}
61-
dInputRender={(el) =>
62-
cloneHTMLElement(el, {
63-
['data-form-item-label-for' as string]: index === 0,
64-
})
65-
}
66-
dModel={value.includes(item.value)}
67-
onModelChange={(checked) => {
68-
changeValue((draft) => {
69-
if (checked) {
70-
draft.push(item.value);
71-
} else {
72-
draft.splice(
73-
draft.findIndex((v) => v === item.value),
74-
1
75-
);
76-
}
77-
});
78-
}}
38+
<DCheckboxGroupRenderer
39+
dFormControl={dFormControl}
40+
dList={dList}
41+
dModel={dModel}
42+
dDisabled={dDisabled}
43+
dRender={(nodes) => (
44+
<div
45+
{...restProps}
46+
className={getClassName(restProps.className, `${dPrefix}checkbox-group`, {
47+
[`${dPrefix}checkbox-group--vertical`]: dVertical,
48+
})}
49+
role="group"
7950
>
80-
{item.label}
81-
</DCheckbox>
82-
))}
83-
</div>
51+
{nodes}
52+
</div>
53+
)}
54+
onModelChange={onModelChange}
55+
/>
8456
);
8557
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import type { DId } from '../../utils/types';
2+
import type { DFormControl } from '../form';
3+
4+
import { useGeneralContext, useDValue } from '../../hooks';
5+
import { cloneHTMLElement, registerComponentMate } from '../../utils';
6+
import { useFormControl } from '../form';
7+
import { useComponentConfig } from '../root';
8+
import { DCheckbox } from './Checkbox';
9+
10+
export interface DCheckboxItem<V extends DId> {
11+
label: React.ReactNode;
12+
value: V;
13+
disabled?: boolean;
14+
}
15+
export interface DCheckboxGroupRendererProps<V extends DId> {
16+
dFormControl?: DFormControl;
17+
dModel?: V[];
18+
dList: DCheckboxItem<V>[];
19+
dDisabled?: boolean;
20+
dRender: (nodes: React.ReactElement[]) => JSX.Element | null;
21+
onModelChange?: (values: V[]) => void;
22+
}
23+
24+
const { COMPONENT_NAME } = registerComponentMate({ COMPONENT_NAME: 'DCheckbox.GroupRenderer' as const });
25+
export function DCheckboxGroupRenderer<V extends DId>(props: DCheckboxGroupRendererProps<V>): JSX.Element | null {
26+
const { dFormControl, dList, dModel, dDisabled = false, dRender, onModelChange } = useComponentConfig(COMPONENT_NAME, props);
27+
28+
//#region Context
29+
const { gDisabled } = useGeneralContext();
30+
//#endregion
31+
32+
const formControlInject = useFormControl(dFormControl);
33+
const [value, changeValue] = useDValue<V[]>([], dModel, onModelChange, undefined, formControlInject);
34+
35+
const disabled = dDisabled || gDisabled || dFormControl?.control.disabled;
36+
37+
return dRender(
38+
dList.map((item, index) => (
39+
<DCheckbox
40+
key={item.value}
41+
dDisabled={item.disabled || disabled}
42+
dInputRender={(el) =>
43+
cloneHTMLElement(el, {
44+
['data-form-item-label-for' as string]: index === 0,
45+
})
46+
}
47+
dModel={value.includes(item.value)}
48+
onModelChange={(checked) => {
49+
changeValue((draft) => {
50+
if (checked) {
51+
draft.push(item.value);
52+
} else {
53+
draft.splice(
54+
draft.findIndex((v) => v === item.value),
55+
1
56+
);
57+
}
58+
});
59+
}}
60+
>
61+
{item.label}
62+
</DCheckbox>
63+
))
64+
);
65+
}

packages/ui/src/components/checkbox/demos/2.Group.md

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,43 +13,34 @@ You can choose more than one.
1313
可选择多个。
1414

1515
```tsx
16-
import { useState } from 'react';
16+
import React from 'react';
1717

1818
import { DCheckbox } from '@react-devui/ui';
1919

20+
const list = [1, 2, 3].map((n) => ({
21+
label: `Checkbox ${n}`,
22+
value: n,
23+
disabled: n === 2,
24+
}));
2025
export default function Demo() {
21-
const [value, setValue] = useState([2]);
22-
2326
return (
2427
<>
25-
<DCheckbox.Group
26-
dList={[1, 2, 3].map((n) => ({
27-
label: `Checkbox ${n}`,
28-
value: n,
29-
}))}
30-
dModel={value}
31-
onModelChange={setValue}
32-
/>
28+
<DCheckbox.Group dList={list} />
3329
<br />
34-
<DCheckbox.Group
35-
dList={[1, 2, 3].map((n) => ({
36-
label: `Checkbox ${n}`,
37-
value: n,
38-
}))}
39-
dModel={value}
40-
dDisabled
41-
onModelChange={setValue}
42-
/>
30+
<DCheckbox.Group dList={list} dDisabled />
4331
<br />
44-
<DCheckbox.Group
45-
dList={[1, 2, 3].map((n) => ({
46-
label: `Checkbox ${n}`,
47-
value: n,
48-
}))}
49-
dModel={value}
50-
dVertical
51-
onModelChange={setValue}
32+
<DCheckbox.GroupRenderer
33+
dList={list}
34+
dRender={(nodes) => (
35+
<div className="row g-2">
36+
{React.Children.map(nodes, (node) => (
37+
<div className="col-12 col-md-6 col-lg-4">{node}</div>
38+
))}
39+
</div>
40+
)}
5241
/>
42+
<br />
43+
<DCheckbox.Group dList={list} dVertical />
5344
</>
5445
);
5546
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './Checkbox';
22
export * from './CheckboxGroup';
3+
export * from './CheckboxGroupRenderer';

packages/ui/src/components/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export { DCard } from './card';
3131
export type { DCascaderProps } from './cascader';
3232
export { DCascader } from './cascader';
3333

34-
export type { DCheckboxProps, DCheckboxGroupProps } from './checkbox';
34+
export type { DCheckboxProps, DCheckboxGroupProps, DCheckboxGroupRendererProps } from './checkbox';
3535
export { DCheckbox } from './checkbox';
3636

3737
export type { DComposeProps, DComposeItemProps } from './compose';
@@ -79,7 +79,7 @@ export { DPopover } from './popover';
7979
export type { DProgressProps } from './progress';
8080
export { DProgress } from './progress';
8181

82-
export type { DRadioProps, DRadioGroupProps } from './radio';
82+
export type { DRadioProps, DRadioGroupProps, DRadioGroupRendererProps } from './radio';
8383
export { DRadio } from './radio';
8484

8585
export type { DRatingProps } from './rating';

packages/ui/src/components/radio/Radio.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { DFocusVisible } from '../_focus-visible';
1414
import { useFormControl } from '../form';
1515
import { useComponentConfig, usePrefixConfig } from '../root';
1616
import { DRadioGroup } from './RadioGroup';
17+
import { DRadioGroupRenderer } from './RadioGroupRenderer';
1718

1819
export interface DRadioProps extends React.HTMLAttributes<HTMLElement> {
1920
dRef?: {
@@ -34,6 +35,7 @@ const { COMPONENT_NAME } = registerComponentMate({ COMPONENT_NAME: 'DRadio' as c
3435
export const DRadio: {
3536
(props: DRadioProps): JSX.Element | null;
3637
Group: typeof DRadioGroup;
38+
GroupRenderer: typeof DRadioGroupRenderer;
3739
} = (props) => {
3840
const {
3941
children,
@@ -131,3 +133,4 @@ export const DRadio: {
131133
};
132134

133135
DRadio.Group = DRadioGroup;
136+
DRadio.GroupRenderer = DRadioGroupRenderer;

0 commit comments

Comments
 (0)