Skip to content

Commit

Permalink
feat(ui): add group renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
xiejay97 committed Mar 17, 2023
1 parent 7e3d257 commit 2cda99f
Show file tree
Hide file tree
Showing 12 changed files with 242 additions and 137 deletions.
3 changes: 3 additions & 0 deletions packages/ui/src/components/checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { DBaseInput } from '../_base-input';
import { useFormControl } from '../form';
import { useComponentConfig, usePrefixConfig } from '../root';
import { DCheckboxGroup } from './CheckboxGroup';
import { DCheckboxGroupRenderer } from './CheckboxGroupRenderer';

export interface DCheckboxProps extends React.HTMLAttributes<HTMLElement> {
dRef?: {
Expand All @@ -28,6 +29,7 @@ const { COMPONENT_NAME } = registerComponentMate({ COMPONENT_NAME: 'DCheckbox' a
export const DCheckbox: {
(props: DCheckboxProps): JSX.Element | null;
Group: typeof DCheckboxGroup;
GroupRenderer: typeof DCheckboxGroupRenderer;
} = (props) => {
const {
children,
Expand Down Expand Up @@ -98,3 +100,4 @@ export const DCheckbox: {
};

DCheckbox.Group = DCheckboxGroup;
DCheckbox.GroupRenderer = DCheckboxGroupRenderer;
68 changes: 20 additions & 48 deletions packages/ui/src/components/checkbox/CheckboxGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import type { DId } from '../../utils/types';
import type { DFormControl } from '../form';
import type { DCheckboxItem } from './CheckboxGroupRenderer';

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

import { useGeneralContext, useDValue } from '../../hooks';
import { cloneHTMLElement, registerComponentMate } from '../../utils';
import { useFormControl } from '../form';
import { registerComponentMate } from '../../utils';
import { useComponentConfig, usePrefixConfig } from '../root';
import { DCheckbox } from './Checkbox';
import { DCheckboxGroupRenderer } from './CheckboxGroupRenderer';

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

//#region Context
const dPrefix = usePrefixConfig();
const { gDisabled } = useGeneralContext();
//#endregion

const formControlInject = useFormControl(dFormControl);
const [value, changeValue] = useDValue<V[]>([], dModel, onModelChange, undefined, formControlInject);

const disabled = dDisabled || gDisabled || dFormControl?.control.disabled;

return (
<div
{...restProps}
className={getClassName(restProps.className, `${dPrefix}checkbox-group`, {
[`${dPrefix}checkbox-group--vertical`]: dVertical,
})}
role="group"
>
{dList.map((item, index) => (
<DCheckbox
key={item.value}
dDisabled={item.disabled || disabled}
dInputRender={(el) =>
cloneHTMLElement(el, {
['data-form-item-label-for' as string]: index === 0,
})
}
dModel={value.includes(item.value)}
onModelChange={(checked) => {
changeValue((draft) => {
if (checked) {
draft.push(item.value);
} else {
draft.splice(
draft.findIndex((v) => v === item.value),
1
);
}
});
}}
<DCheckboxGroupRenderer
dFormControl={dFormControl}
dList={dList}
dModel={dModel}
dDisabled={dDisabled}
dRender={(nodes) => (
<div
{...restProps}
className={getClassName(restProps.className, `${dPrefix}checkbox-group`, {
[`${dPrefix}checkbox-group--vertical`]: dVertical,
})}
role="group"
>
{item.label}
</DCheckbox>
))}
</div>
{nodes}
</div>
)}
onModelChange={onModelChange}
/>
);
}
65 changes: 65 additions & 0 deletions packages/ui/src/components/checkbox/CheckboxGroupRenderer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type { DId } from '../../utils/types';
import type { DFormControl } from '../form';

import { useGeneralContext, useDValue } from '../../hooks';
import { cloneHTMLElement, registerComponentMate } from '../../utils';
import { useFormControl } from '../form';
import { useComponentConfig } from '../root';
import { DCheckbox } from './Checkbox';

export interface DCheckboxItem<V extends DId> {
label: React.ReactNode;
value: V;
disabled?: boolean;
}
export interface DCheckboxGroupRendererProps<V extends DId> {
dFormControl?: DFormControl;
dModel?: V[];
dList: DCheckboxItem<V>[];
dDisabled?: boolean;
dRender: (nodes: React.ReactElement[]) => JSX.Element | null;
onModelChange?: (values: V[]) => void;
}

const { COMPONENT_NAME } = registerComponentMate({ COMPONENT_NAME: 'DCheckbox.GroupRenderer' as const });
export function DCheckboxGroupRenderer<V extends DId>(props: DCheckboxGroupRendererProps<V>): JSX.Element | null {
const { dFormControl, dList, dModel, dDisabled = false, dRender, onModelChange } = useComponentConfig(COMPONENT_NAME, props);

//#region Context
const { gDisabled } = useGeneralContext();
//#endregion

const formControlInject = useFormControl(dFormControl);
const [value, changeValue] = useDValue<V[]>([], dModel, onModelChange, undefined, formControlInject);

const disabled = dDisabled || gDisabled || dFormControl?.control.disabled;

return dRender(
dList.map((item, index) => (
<DCheckbox
key={item.value}
dDisabled={item.disabled || disabled}
dInputRender={(el) =>
cloneHTMLElement(el, {
['data-form-item-label-for' as string]: index === 0,
})
}
dModel={value.includes(item.value)}
onModelChange={(checked) => {
changeValue((draft) => {
if (checked) {
draft.push(item.value);
} else {
draft.splice(
draft.findIndex((v) => v === item.value),
1
);
}
});
}}
>
{item.label}
</DCheckbox>
))
);
}
47 changes: 19 additions & 28 deletions packages/ui/src/components/checkbox/demos/2.Group.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,43 +13,34 @@ You can choose more than one.
可选择多个。

```tsx
import { useState } from 'react';
import React from 'react';

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

const list = [1, 2, 3].map((n) => ({
label: `Checkbox ${n}`,
value: n,
disabled: n === 2,
}));
export default function Demo() {
const [value, setValue] = useState([2]);

return (
<>
<DCheckbox.Group
dList={[1, 2, 3].map((n) => ({
label: `Checkbox ${n}`,
value: n,
}))}
dModel={value}
onModelChange={setValue}
/>
<DCheckbox.Group dList={list} />
<br />
<DCheckbox.Group
dList={[1, 2, 3].map((n) => ({
label: `Checkbox ${n}`,
value: n,
}))}
dModel={value}
dDisabled
onModelChange={setValue}
/>
<DCheckbox.Group dList={list} dDisabled />
<br />
<DCheckbox.Group
dList={[1, 2, 3].map((n) => ({
label: `Checkbox ${n}`,
value: n,
}))}
dModel={value}
dVertical
onModelChange={setValue}
<DCheckbox.GroupRenderer
dList={list}
dRender={(nodes) => (
<div className="row g-2">
{React.Children.map(nodes, (node) => (
<div className="col-12 col-md-6 col-lg-4">{node}</div>
))}
</div>
)}
/>
<br />
<DCheckbox.Group dList={list} dVertical />
</>
);
}
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/components/checkbox/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './Checkbox';
export * from './CheckboxGroup';
export * from './CheckboxGroupRenderer';
4 changes: 2 additions & 2 deletions packages/ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export { DCard } from './card';
export type { DCascaderProps } from './cascader';
export { DCascader } from './cascader';

export type { DCheckboxProps, DCheckboxGroupProps } from './checkbox';
export type { DCheckboxProps, DCheckboxGroupProps, DCheckboxGroupRendererProps } from './checkbox';
export { DCheckbox } from './checkbox';

export type { DComposeProps, DComposeItemProps } from './compose';
Expand Down Expand Up @@ -79,7 +79,7 @@ export { DPopover } from './popover';
export type { DProgressProps } from './progress';
export { DProgress } from './progress';

export type { DRadioProps, DRadioGroupProps } from './radio';
export type { DRadioProps, DRadioGroupProps, DRadioGroupRendererProps } from './radio';
export { DRadio } from './radio';

export type { DRatingProps } from './rating';
Expand Down
3 changes: 3 additions & 0 deletions packages/ui/src/components/radio/Radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { DFocusVisible } from '../_focus-visible';
import { useFormControl } from '../form';
import { useComponentConfig, usePrefixConfig } from '../root';
import { DRadioGroup } from './RadioGroup';
import { DRadioGroupRenderer } from './RadioGroupRenderer';

export interface DRadioProps extends React.HTMLAttributes<HTMLElement> {
dRef?: {
Expand All @@ -34,6 +35,7 @@ const { COMPONENT_NAME } = registerComponentMate({ COMPONENT_NAME: 'DRadio' as c
export const DRadio: {
(props: DRadioProps): JSX.Element | null;
Group: typeof DRadioGroup;
GroupRenderer: typeof DRadioGroupRenderer;
} = (props) => {
const {
children,
Expand Down Expand Up @@ -131,3 +133,4 @@ export const DRadio: {
};

DRadio.Group = DRadioGroup;
DRadio.GroupRenderer = DRadioGroupRenderer;

0 comments on commit 2cda99f

Please sign in to comment.