Skip to content

Commit

Permalink
feat(ui): add switch component
Browse files Browse the repository at this point in the history
  • Loading branch information
xiejay97 committed Jan 6, 2022
1 parent 5d12133 commit a214b9a
Show file tree
Hide file tree
Showing 45 changed files with 623 additions and 273 deletions.
22 changes: 22 additions & 0 deletions packages/site/src/app/configs/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,27 @@
]
}
]
},
{
"name": "check",
"list": [
{
"viewBox": "64 64 896 896",
"paths": [
"M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"
]
}
]
},
{
"name": "close",
"list": [
{
"viewBox": "64 64 896 896",
"paths": [
"M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
]
}
]
}
]
2 changes: 2 additions & 0 deletions packages/site/src/app/styles/_app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ h3 {
border-collapse: collapse;
border-spacing: 0;

word-break: break-all;

table-layout: fixed;

empty-cells: show;
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/components/_select-box/SelectBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ const SelectBox: React.ForwardRefRenderFunction<HTMLDivElement, DSelectBoxProps>
'is-expanded': dExpanded,
'is-disabled': disabled,
})}
role="button"
tabIndex={disabled ? undefined : tabIndex}
aria-disabled={disabled}
aria-haspopup="listbox"
Expand Down
6 changes: 3 additions & 3 deletions packages/ui/src/components/button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,17 @@ const Button: React.ForwardRefRenderFunction<DButtonRef, DButtonProps> = (props,
const buttonType = isUndefined(props.dType) ? buttonGroupType ?? dType : dType;
const theme = isUndefined(props.dTheme) ? buttonGroupTheme ?? dTheme : dTheme;
const size = dSize ?? gSize;
const _disabled = disabled || buttonGroupDisabled || gDisabled;
const _disabled = disabled || dLoading || buttonGroupDisabled || gDisabled;

const handleClick = useCallback(
(e) => {
onClick?.(e);

if (!dLoading && (buttonType === 'primary' || buttonType === 'secondary' || buttonType === 'outline' || buttonType === 'dashed')) {
if (buttonType === 'primary' || buttonType === 'secondary' || buttonType === 'outline' || buttonType === 'dashed') {
wave(e.currentTarget, `var(--${dPrefix}color-${theme})`);
}
},
[theme, dLoading, dPrefix, onClick, buttonType, wave]
[theme, dPrefix, onClick, buttonType, wave]
);

const buttonIcon = (loading: boolean, ref?: React.LegacyRef<HTMLSpanElement>) => (
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/button/demos/5.Loading.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title:
en-US: Loading
zh-Hant: 加载中状态
zh-Hant: 加载中
---

# en-US
Expand Down
41 changes: 16 additions & 25 deletions packages/ui/src/components/checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,28 @@ import { usePrefixConfig, useComponentConfig, useCustomContext, useTwoWayBinding
import { getClassName } from '../../utils';
import { DCheckboxGroupContext } from './CheckboxGroup';

export type DCheckboxRef = HTMLInputElement;

export interface DCheckboxProps extends React.HTMLAttributes<HTMLElement> {
dModel?: [boolean, Updater<boolean>?];
dFormControlName?: string;
dIndeterminate?: boolean;
dAriaControls?: string;
dSize?: 'smaller' | 'larger';
dDisabled?: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
dValue?: any;
dInputProps?: React.InputHTMLAttributes<HTMLInputElement>;
dInputRef?: React.LegacyRef<HTMLInputElement>;
onModelChange?: (checked: boolean) => void;
}

const Checkbox: React.ForwardRefRenderFunction<DCheckboxRef, DCheckboxProps> = (props, ref) => {
export function DCheckbox(props: DCheckboxProps) {
const {
dModel,
dFormControlName,
dIndeterminate = false,
dAriaControls,
dSize,
dDisabled = false,
dValue,
dInputProps,
dInputRef,
onModelChange,
id,
className,
children,
onChange,
Expand All @@ -39,63 +36,59 @@ const Checkbox: React.ForwardRefRenderFunction<DCheckboxRef, DCheckboxProps> = (

//#region Context
const dPrefix = usePrefixConfig();
const { gSize, gDisabled } = useGeneralState();
const { gDisabled } = useGeneralState();
const [{ updateCheckboxs, removeCheckboxs, checkboxGroupValue, onCheckedChange }, checkboxGroupContext] =
useCustomContext(DCheckboxGroupContext);
//#endregion

const uniqueId = useId();
const _id = id ?? `${dPrefix}checkbox-${uniqueId}`;
const _id = dInputProps?.id ?? `${dPrefix}checkbox-input-${uniqueId}`;

useStateBackflow(updateCheckboxs, removeCheckboxs, _id, dValue);

const inGroup = checkboxGroupContext !== null;

const [checked, changeChecked, { validateClassName, ariaAttribute, controlDisabled }] = useTwoWayBinding<boolean | undefined, boolean>(
const [checked, changeChecked, { ariaAttribute, controlDisabled }] = useTwoWayBinding<boolean | undefined, boolean>(
false,
dModel ?? (dIndeterminate ? [undefined] : inGroup ? [checkboxGroupValue?.includes(dValue) ?? false] : undefined),
onModelChange,
dFormControlName ? { formControlName: dFormControlName, id: _id } : undefined
);

const size = dSize ?? gSize;
const disabled = dDisabled || gDisabled || controlDisabled;

const handleChange = useCallback<React.ChangeEventHandler<HTMLInputElement>>(
(e) => {
onChange?.(e);

if (!disabled) {
changeChecked(dIndeterminate ? true : !checked);
if (inGroup) {
onCheckedChange?.(dValue, dIndeterminate ? true : !checked);
}
changeChecked(dIndeterminate ? true : !checked);
if (inGroup) {
onCheckedChange?.(dValue, dIndeterminate ? true : !checked);
}
},
[onChange, disabled, changeChecked, dIndeterminate, checked, inGroup, onCheckedChange, dValue]
[onChange, changeChecked, dIndeterminate, checked, inGroup, onCheckedChange, dValue]
);

return (
<div
{...restProps}
className={getClassName(className, `${dPrefix}checkbox`, {
[`${dPrefix}checkbox--${size}`]: size,
'is-indeterminate': dIndeterminate,
'is-checked': !dIndeterminate && checked,
'is-disabled': disabled,
})}
>
<div className={`${dPrefix}checkbox__input-wrapper`}>
<input
{...dInputProps}
{...ariaAttribute}
ref={ref}
ref={dInputRef}
id={_id}
className={getClassName(`${dPrefix}checkbox__input`, validateClassName)}
className={getClassName(dInputProps?.className, `${dPrefix}checkbox__input`)}
type="checkbox"
disabled={disabled}
aria-labelledby={`${dPrefix}checkbox-label-${uniqueId}`}
aria-checked={dIndeterminate ? 'mixed' : checked}
aria-controls={dAriaControls}
onChange={handleChange}
/>
{!dIndeterminate && checked && <div className={`${dPrefix}checkbox__tick`}></div>}
Expand All @@ -106,6 +99,4 @@ const Checkbox: React.ForwardRefRenderFunction<DCheckboxRef, DCheckboxProps> = (
</label>
</div>
);
};

export const DCheckbox = React.forwardRef(Checkbox);
}
25 changes: 9 additions & 16 deletions packages/ui/src/components/checkbox/CheckboxGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { DGeneralStateContextData } from '../../hooks/general-state';
import type { Updater } from '../../hooks/two-way-binding';

import React, { useCallback, useId, useLayoutEffect, useMemo } from 'react';
import React, { useCallback, useLayoutEffect, useMemo } from 'react';

import { usePrefixConfig, useComponentConfig, useTwoWayBinding, useGeneralState, DGeneralStateContext, useImmer } from '../../hooks';
import { getClassName } from '../../utils';
Expand All @@ -19,7 +19,6 @@ export const DCheckboxGroupContext = React.createContext<DCheckboxGroupContextDa
export interface DCheckboxGroupProps extends React.HTMLAttributes<HTMLDivElement> {
dModel?: [any[], Updater<any[]>?];
dFormControlName?: string;
dSize?: 'smaller' | 'larger';
dDisabled?: boolean;
dVertical?: boolean;
dIndeterminateLabel?: (checked: boolean | 'mixed') => React.ReactNode;
Expand All @@ -31,36 +30,30 @@ export function DCheckboxGroup(props: DCheckboxGroupProps) {
const {
dModel,
dFormControlName,
dSize,
dDisabled = false,
dVertical = false,
dIndeterminateLabel,
dIndeterminateRef,
onModelChange,
id,
className,
children,
...restProps
} = useComponentConfig(DCheckboxGroup.name, props);

//#region Context
const dPrefix = usePrefixConfig();
const { gSize, gDisabled } = useGeneralState();
const { gDisabled } = useGeneralState();
//#endregion

const uniqueId = useId();
const _id = id ?? `${dPrefix}checkbox-group-${uniqueId}`;

const [checkboxs, setCheckboxs] = useImmer(new Map<string, { id: string; value: any }>());

const [value, changeValue, { ariaAttribute, controlDisabled }] = useTwoWayBinding(
[],
dModel,
onModelChange,
dFormControlName ? { formControlName: dFormControlName, id: _id } : undefined
dFormControlName ? { formControlName: dFormControlName } : undefined
);

const size = dSize ?? gSize;
const disabled = dDisabled || gDisabled || controlDisabled;

const allLength = React.Children.count(children);
Expand All @@ -72,9 +65,11 @@ export function DCheckboxGroup(props: DCheckboxGroupProps) {
<DCheckbox
dModel={checked !== 'mixed' ? [checked] : undefined}
dIndeterminate={checked === 'mixed'}
dAriaControls={Array.from(checkboxs.values())
.map((item) => item.id)
.join(' ')}
dInputProps={{
'aria-controls': Array.from(checkboxs.values())
.map((item) => item.id)
.join(' '),
}}
onModelChange={() => {
checked === true ? changeValue([]) : changeValue(Array.from(checkboxs.values()).map((item) => item.value));
}}
Expand All @@ -92,10 +87,9 @@ export function DCheckboxGroup(props: DCheckboxGroupProps) {

const generalStateContextValue = useMemo<DGeneralStateContextData>(
() => ({
gSize: size,
gDisabled: disabled,
}),
[disabled, size]
[disabled]
);

const stateBackflow = useMemo<Pick<DCheckboxGroupContextData, 'updateCheckboxs' | 'removeCheckboxs'>>(
Expand Down Expand Up @@ -139,7 +133,6 @@ export function DCheckboxGroup(props: DCheckboxGroupProps) {
<div
{...restProps}
{...ariaAttribute}
id={_id}
className={getClassName(className, `${dPrefix}checkbox-group`, {
[`${dPrefix}checkbox-group--vertical`]: dVertical,
})}
Expand Down
11 changes: 2 additions & 9 deletions packages/ui/src/components/checkbox/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,13 @@ Extend `React.HTMLAttributes<HTMLElement>`.
| --- | --- | --- | --- |
| dModel | Manual control is checked | [boolean, Updater\<boolean\>?] | - |
| dIndeterminate | Is it partially checked | boolean | false |
| dAriaControls | [aria-controls](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-controls) | string | - |
| dSize | Set size | 'smaller' \| 'larger' | - |
| dDisabled | Whether to disable | boolean | false |
| dValue | Pass as an identifier in checkbox group | any | - |
| dInputProps | Attributes applied to the `input` element | React.InputHTMLAttributes\<HTMLInputElement\> | - |
| dInputRef | Pass a `ref` to the `input` element | React.LegacyRef\<HTMLInputElement\> | - |
| onModelChange | Selected change callback | `(checked: boolean) => void` | - |
<!-- prettier-ignore-end -->

### DCheckboxRef

```tsx
type DCheckboxRef = HTMLInputElement;
```

### DCheckboxGroupProps

Extend `React.HTMLAttributes<HTMLDivElement>`.
Expand All @@ -41,7 +35,6 @@ Extend `React.HTMLAttributes<HTMLDivElement>`.
| Property | Description | Type | Default |
| --- | --- | --- | --- |
| dModel | Manual control selection | [any[], Updater\<any[]\>?] | - |
| dSize | Checkbox group size | 'smaller' \| 'larger' | - |
| dDisabled | Whether to disable | boolean | false |
| dVertical | Vertical arrangement of checkbox group | boolean | false |
| dIndeterminateLabel | Partially checked label content | `(checked: boolean \| 'mixed') => React.ReactNode` | - |
Expand Down
11 changes: 2 additions & 9 deletions packages/ui/src/components/checkbox/README.zh-Hant.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,13 @@ title: 多选组
| --- | --- | --- | --- |
| dModel | 手动控制是否选中 | [boolean, Updater\<boolean\>?] | - |
| dIndeterminate | 是否为部分选中 | boolean | false |
| dAriaControls | [aria-controls](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-controls) | string | - |
| dSize | 设置尺寸 | 'smaller' \| 'larger' | - |
| dDisabled | 是否禁用 | boolean | false |
| dValue | 多选组中作为标识传递 | any | - |
| dInputProps | 应用于 `input` 元素的属性 | React.InputHTMLAttributes\<HTMLInputElement\> | - |
| dInputRef |`ref` 传递给 `input` 元素 | React.LegacyRef\<HTMLInputElement\> | - |
| onModelChange | 选中改变的回调 | `(checked: boolean) => void` | - |
<!-- prettier-ignore-end -->

### DCheckboxRef

```tsx
type DCheckboxRef = HTMLInputElement;
```

### DCheckboxGroupProps

继承 `React.HTMLAttributes<HTMLDivElement>`
Expand All @@ -40,7 +34,6 @@ type DCheckboxRef = HTMLInputElement;
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| dModel | 手动控制选择 | [any[], Updater\<any[]\>?] | - |
| dSize | 多选组尺寸 | 'smaller' \| 'larger' | - |
| dDisabled | 是否禁用 | boolean | false |
| dVertical | 多选组垂直排布 | boolean | false |
| dIndeterminateLabel | 部分选中的标签内容 | `(checked: boolean \| 'mixed') => React.ReactNode` | - |
Expand Down
23 changes: 8 additions & 15 deletions packages/ui/src/components/checkbox/demos/1.Basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,14 @@ import { DCheckbox } from '@react-devui/ui';

export default function Demo() {
return (
<>
<div className="app-demo-flex-container">
<DCheckbox dSize="smaller">Checkbox</DCheckbox>
<DCheckbox>Checkbox</DCheckbox>
<DCheckbox dSize="larger">Checkbox</DCheckbox>
</div>
<br />
<div className="app-demo-flex-container">
<DCheckbox dIndeterminate>Checkbox</DCheckbox>
<DCheckbox dDisabled>Checkbox Disabled</DCheckbox>
<DCheckbox dModel={[true]} dDisabled>
Checkbox Disabled
</DCheckbox>
</div>
</>
<div className="app-demo-flex-container">
<DCheckbox>Checkbox</DCheckbox>
<DCheckbox dIndeterminate>Checkbox</DCheckbox>
<DCheckbox dDisabled>Checkbox Disabled</DCheckbox>
<DCheckbox dModel={[true]} dDisabled>
Checkbox Disabled
</DCheckbox>
</div>
);
}
```

0 comments on commit a214b9a

Please sign in to comment.