From 0438d23fd15ecfa302f208fad5e427c29914ee64 Mon Sep 17 00:00:00 2001 From: "hiroki.yokouchi" Date: Fri, 1 Nov 2024 11:58:33 +0900 Subject: [PATCH 1/2] feat: allow icon prop to be specified by name Signed-off-by: hiroki.yokouchi --- src/components/Button/Button.tsx | 8 +++---- src/components/Button/ButtonTypes.ts | 7 +++--- src/components/Button/LinkButton.tsx | 8 +++---- src/components/Button/useIcon.tsx | 16 +++++++++++++ src/components/Icon/Icon.tsx | 5 ++-- src/components/LinkCard/LinkCard.tsx | 12 ++++++++-- src/index.ts | 2 ++ src/stories/Button.stories.tsx | 34 ++++++++++++++++++++++++++++ src/stories/LinkButton.stories.tsx | 34 ++++++++++++++++++++++++++++ src/stories/LinkCard.stories.tsx | 11 +++++++++ src/types/icon.ts | 3 +++ 11 files changed, 124 insertions(+), 16 deletions(-) create mode 100644 src/components/Button/useIcon.tsx create mode 100644 src/types/icon.ts diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index d2d53344..ef81dee4 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -3,7 +3,7 @@ import { clsx } from 'clsx'; import { type CSSProperties, forwardRef } from 'react'; import styles from './Button.module.css'; -import { VariantIcon } from './VariantIcon'; +import { useIcon } from './useIcon'; import { marginVariables } from '../../utils/style'; import type { ButtonProps } from './ButtonTypes'; @@ -34,9 +34,9 @@ export const Button = forwardRef( }, ref, ) => { - const icon = _icon === 'default' ? : _icon; - const fixedIcon = _fixedIcon === 'default' ? : _fixedIcon; - const suffixIcon = _suffixIcon === 'default' ? : _suffixIcon; + const icon = useIcon(_icon, variant); + const fixedIcon = useIcon(_fixedIcon, variant); + const suffixIcon = useIcon(_suffixIcon, variant); const cls = clsx({ [styles.button]: true, [styles[variant]]: true, diff --git a/src/components/Button/ButtonTypes.ts b/src/components/Button/ButtonTypes.ts index 007cec30..96ba3b1a 100644 --- a/src/components/Button/ButtonTypes.ts +++ b/src/components/Button/ButtonTypes.ts @@ -1,4 +1,5 @@ import { CustomDataAttributeProps } from '../../types/attributes'; +import { IconName } from '../../types/icon'; import type { MarginProps } from '../../types/style'; import type { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactElement, ReactNode } from 'react'; @@ -34,15 +35,15 @@ export type BaseProps = { /** * アイコン */ - icon?: 'default' | ReactNode; + icon?: 'default' | ReactElement | IconName; /** * Fixedアイコン */ - fixedIcon?: 'default' | ReactNode; + fixedIcon?: 'default' | ReactElement | IconName; /** * 後方配置のアイコン */ - suffixIcon?: 'default' | ReactNode; + suffixIcon?: 'default' | ReactElement | IconName; /** * ラベルの折り返しを指定 */ diff --git a/src/components/Button/LinkButton.tsx b/src/components/Button/LinkButton.tsx index 5ca55d5c..96ce72ba 100644 --- a/src/components/Button/LinkButton.tsx +++ b/src/components/Button/LinkButton.tsx @@ -3,7 +3,7 @@ import clsx from 'clsx'; import { cloneElement, CSSProperties, forwardRef } from 'react'; import styles from './Button.module.css'; -import { VariantIcon } from './VariantIcon'; +import { useIcon } from './useIcon'; import { marginVariables } from '../../utils/style'; import type { LinkButtonProps } from './ButtonTypes'; import type { ReactNode } from 'react'; @@ -31,9 +31,9 @@ export const LinkButton = forwardRef( }, forwardedRef, ) => { - const icon = _icon === 'default' ? : _icon; - const fixedIcon = _fixedIcon === 'default' ? : _fixedIcon; - const suffixIcon = _suffixIcon === 'default' ? : _suffixIcon; + const icon = useIcon(_icon, variant); + const fixedIcon = useIcon(_fixedIcon, variant); + const suffixIcon = useIcon(_suffixIcon, variant); const cls = clsx({ [styles.button]: true, [styles[variant]]: true, diff --git a/src/components/Button/useIcon.tsx b/src/components/Button/useIcon.tsx new file mode 100644 index 00000000..85a54245 --- /dev/null +++ b/src/components/Button/useIcon.tsx @@ -0,0 +1,16 @@ +import { useMemo } from 'react'; +import { VariantIcon } from './VariantIcon'; +import { Icon } from '../Icon/Icon'; +import type { ButtonProps } from './ButtonTypes'; + +export function useIcon(icon: ButtonProps['icon'], variant: ButtonProps['variant']) { + return useMemo(() => { + if (icon === 'default') { + return ; + } else if (typeof icon === 'string') { + return ; + } else { + return icon; + } + }, [icon, variant]); +} diff --git a/src/components/Icon/Icon.tsx b/src/components/Icon/Icon.tsx index c4f300fd..152f559d 100644 --- a/src/components/Icon/Icon.tsx +++ b/src/components/Icon/Icon.tsx @@ -1,12 +1,11 @@ import * as Icons from '@ubie/ubie-icons'; import styles from './Icon.module.css'; import { CustomDataAttributeProps } from '../../types/attributes'; +import { IconName } from '../../types/icon'; import { TextColor } from '../../types/style'; import { colorVariable } from '../../utils/style'; import type { CSSProperties, FC } from 'react'; -type Icon = keyof typeof Icons; - type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl'; const toIconSizeEmValue = (size: IconSize): string => { @@ -38,7 +37,7 @@ type Props = { /** * アイコンの種類 */ - icon: Icon; + icon: IconName; /** * 色。指定しない場合はinheritとなり、親要素のcolorプロパティを継承します */ diff --git a/src/components/LinkCard/LinkCard.tsx b/src/components/LinkCard/LinkCard.tsx index 399ec253..f4890467 100644 --- a/src/components/LinkCard/LinkCard.tsx +++ b/src/components/LinkCard/LinkCard.tsx @@ -5,8 +5,12 @@ import clsx from 'clsx'; import { cloneElement, forwardRef, isValidElement } from 'react'; import styles from './LinkCard.module.css'; import { CustomDataAttributeProps } from '../../types/attributes'; +import { IconName } from '../../types/icon'; +import { Icon } from '../Icon/Icon'; import type { ComponentType, ReactElement, ReactNode } from 'react'; +type IconProp = ComponentType | ReactElement | IconName; + type Props = { /** * 遷移先URL @@ -37,7 +41,7 @@ type Props = { /** * アイコン */ - icon?: ComponentType | ReactElement; + icon?: IconProp; } & CustomDataAttributeProps; // ref https://github.com/microsoft/TypeScript/issues/53178 @@ -45,11 +49,15 @@ const _isValidElement = (el: ComponentType | ReactElement): el is ReactElement = return isValidElement(el); }; -const renderPropIcon = (icon: ComponentType | ReactElement) => { +const renderPropIcon = (icon: IconProp) => { if (icon == null) { return null; } + if (typeof icon === 'string') { + return ; + } + if (_isValidElement(icon)) { return icon; } diff --git a/src/index.ts b/src/index.ts index 6efe8909..5f5e5cfe 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,3 +30,5 @@ export { Text } from './components/Text/Text'; export { TextArea } from './components/TextArea/TextArea'; export { Stack } from './components/Stack/Stack'; export { Toggle } from './components/Toggle/Toggle'; + +export type { IconName } from './types/icon'; diff --git a/src/stories/Button.stories.tsx b/src/stories/Button.stories.tsx index 945259f9..2ca9dae8 100644 --- a/src/stories/Button.stories.tsx +++ b/src/stories/Button.stories.tsx @@ -92,6 +92,40 @@ export const WithIcon: Story = { + + +
Key specification
+
+
+ + + +
+
+
+ + +
Auth Icon
+
+
+ + + +
+
+
), args: defaultArgs, diff --git a/src/stories/LinkButton.stories.tsx b/src/stories/LinkButton.stories.tsx index 45e90c42..65ec52e4 100644 --- a/src/stories/LinkButton.stories.tsx +++ b/src/stories/LinkButton.stories.tsx @@ -96,6 +96,40 @@ export const WithIcon: Story = { + + +
Key specification
+
+
+ + Icon + + + Suffix Icon + + + Fixed Icon + +
+
+
+ + +
Auth Icon
+
+
+ + Icon + + + Suffix Icon + + + Fixed Icon + +
+
+
), }; diff --git a/src/stories/LinkCard.stories.tsx b/src/stories/LinkCard.stories.tsx index bff7252b..f870d018 100644 --- a/src/stories/LinkCard.stories.tsx +++ b/src/stories/LinkCard.stories.tsx @@ -67,3 +67,14 @@ export const CustomDataAttribute: Story = { 'data-test-id': 'link-card-custom-attribute', }, }; + +export const VariousWaysToSpecifyIcon: Story = { + render: (args) => ( + + + } title="RectElement" /> + + + ), + args: defaultArgs, +}; diff --git a/src/types/icon.ts b/src/types/icon.ts new file mode 100644 index 00000000..3ecd6ad1 --- /dev/null +++ b/src/types/icon.ts @@ -0,0 +1,3 @@ +import * as Icons from '@ubie/ubie-icons'; + +export type IconName = keyof typeof Icons; From 68ff171d9ded30b82489837f2a33866d1f0e2e7d Mon Sep 17 00:00:00 2001 From: "hiroki.yokouchi" Date: Fri, 1 Nov 2024 14:03:46 +0900 Subject: [PATCH 2/2] feat: change text Signed-off-by: hiroki.yokouchi --- src/stories/Button.stories.tsx | 2 +- src/stories/LinkButton.stories.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stories/Button.stories.tsx b/src/stories/Button.stories.tsx index 2ca9dae8..69a7a9a7 100644 --- a/src/stories/Button.stories.tsx +++ b/src/stories/Button.stories.tsx @@ -94,7 +94,7 @@ export const WithIcon: Story = { -
Key specification
+
Name specification