From 467c6d832165fae9b0b0330a5a2102db7478aa1d Mon Sep 17 00:00:00 2001 From: Xiao Yijun Date: Fri, 28 Apr 2023 12:05:24 +0800 Subject: [PATCH] feat(console): add `CheckboxGroup` (#3745) --- .../Checkbox/{ => Checkbox}/index.module.scss | 0 .../components/Checkbox/Checkbox/index.tsx | 111 +++++++++++++++++ .../Checkbox/CheckboxGroup/index.module.scss | 7 ++ .../Checkbox/CheckboxGroup/index.tsx | 52 ++++++++ .../console/src/components/Checkbox/index.tsx | 114 +----------------- 5 files changed, 172 insertions(+), 112 deletions(-) rename packages/console/src/components/Checkbox/{ => Checkbox}/index.module.scss (100%) create mode 100644 packages/console/src/components/Checkbox/Checkbox/index.tsx create mode 100644 packages/console/src/components/Checkbox/CheckboxGroup/index.module.scss create mode 100644 packages/console/src/components/Checkbox/CheckboxGroup/index.tsx diff --git a/packages/console/src/components/Checkbox/index.module.scss b/packages/console/src/components/Checkbox/Checkbox/index.module.scss similarity index 100% rename from packages/console/src/components/Checkbox/index.module.scss rename to packages/console/src/components/Checkbox/Checkbox/index.module.scss diff --git a/packages/console/src/components/Checkbox/Checkbox/index.tsx b/packages/console/src/components/Checkbox/Checkbox/index.tsx new file mode 100644 index 000000000..af3bd6854 --- /dev/null +++ b/packages/console/src/components/Checkbox/Checkbox/index.tsx @@ -0,0 +1,111 @@ +import classNames from 'classnames'; +import type { ReactNode } from 'react'; +import { useLayoutEffect, useState } from 'react'; + +import { Tooltip } from '@/components/Tip'; +import { onKeyDownHandler } from '@/utils/a11y'; + +import * as styles from './index.module.scss'; + +type Props = { + /* eslint-disable react/boolean-prop-naming */ + checked: boolean; + disabled?: boolean; + indeterminate?: boolean; + /* eslint-enable react/boolean-prop-naming */ + onChange: (value: boolean) => void; + label?: ReactNode; + className?: string; + tooltip?: ReactNode; +}; + +function Checkbox({ + checked, + disabled = false, + indeterminate, + onChange, + label, + className, + tooltip, +}: Props) { + const [isIndeterminate, setIsIndeterminate] = useState(indeterminate); + + useLayoutEffect(() => { + setIsIndeterminate(indeterminate); + }, [indeterminate]); + + const handleChange = () => { + if (disabled) { + return; + } + + if (isIndeterminate) { + onChange(false); + } + + setIsIndeterminate(false); + onChange(!checked); + }; + + return ( +
+
+ + + + {checked && !isIndeterminate && ( + + )} + {isIndeterminate && ( + + )} + {!checked && !isIndeterminate && ( + + )} + + + {label && {label}} +
+
+ ); +} + +export default Checkbox; diff --git a/packages/console/src/components/Checkbox/CheckboxGroup/index.module.scss b/packages/console/src/components/Checkbox/CheckboxGroup/index.module.scss new file mode 100644 index 000000000..b3985b56e --- /dev/null +++ b/packages/console/src/components/Checkbox/CheckboxGroup/index.module.scss @@ -0,0 +1,7 @@ +@use '@/scss/underscore' as _; + +.group { + > div:not(:last-child) { + margin-bottom: _.unit(3); + } +} diff --git a/packages/console/src/components/Checkbox/CheckboxGroup/index.tsx b/packages/console/src/components/Checkbox/CheckboxGroup/index.tsx new file mode 100644 index 000000000..696e53ab2 --- /dev/null +++ b/packages/console/src/components/Checkbox/CheckboxGroup/index.tsx @@ -0,0 +1,52 @@ +import { type AdminConsoleKey } from '@logto/phrases'; +import classNames from 'classnames'; + +import DynamicT from '@/components/DynamicT'; + +import Checkbox from '../Checkbox'; + +import * as styles from './index.module.scss'; + +type Option = { + title: AdminConsoleKey; + value: T; +}; + +type Props = { + options: Array>; + value: T[]; + onChange: (value: T[]) => void; + className?: string; +}; + +function CheckboxGroup({ + options, + value: checkedValues, + onChange, + className, +}: Props) { + const toggleValue = (value: T) => { + onChange( + checkedValues.includes(value) + ? checkedValues.filter((selected) => selected !== value) + : [...checkedValues, value] + ); + }; + + return ( +
+ {options.map(({ title, value }) => ( + } + checked={checkedValues.includes(value)} + onChange={() => { + toggleValue(value); + }} + /> + ))} +
+ ); +} + +export default CheckboxGroup; diff --git a/packages/console/src/components/Checkbox/index.tsx b/packages/console/src/components/Checkbox/index.tsx index 7aefc66ef..eb56e1d79 100644 --- a/packages/console/src/components/Checkbox/index.tsx +++ b/packages/console/src/components/Checkbox/index.tsx @@ -1,112 +1,2 @@ -import classNames from 'classnames'; -import type { ReactNode } from 'react'; -import { useLayoutEffect, useState } from 'react'; - -import { onKeyDownHandler } from '@/utils/a11y'; - -import { Tooltip } from '../Tip'; - -import * as styles from './index.module.scss'; - -type Props = { - /* eslint-disable react/boolean-prop-naming */ - checked: boolean; - disabled?: boolean; - indeterminate?: boolean; - /* eslint-enable react/boolean-prop-naming */ - onChange: (value: boolean) => void; - label?: ReactNode; - className?: string; - tooltip?: ReactNode; -}; - -function Checkbox({ - checked, - disabled = false, - indeterminate, - onChange, - label, - className, - tooltip, -}: Props) { - const [isIndeterminate, setIsIndeterminate] = useState(indeterminate); - - useLayoutEffect(() => { - setIsIndeterminate(indeterminate); - }, [indeterminate]); - - const handleChange = () => { - if (disabled) { - return; - } - - if (isIndeterminate) { - onChange(false); - } - - setIsIndeterminate(false); - onChange(!checked); - }; - - return ( -
-
- - - - {checked && !isIndeterminate && ( - - )} - {isIndeterminate && ( - - )} - {!checked && !isIndeterminate && ( - - )} - - - {label && {label}} -
-
- ); -} - -export default Checkbox; +export { default } from './Checkbox'; +export { default as CheckboxGroup } from './CheckboxGroup';