diff --git a/src/components/Button/Button.spec.tsx b/src/components/Button/Button.spec.tsx new file mode 100644 index 00000000..5acc876c --- /dev/null +++ b/src/components/Button/Button.spec.tsx @@ -0,0 +1,12 @@ +import { render } from '@testing-library/react'; +import { createRef } from 'react'; +import { Button } from './Button'; + +describe('Button', () => { + it('access to DOM through ref prop', () => { + const ref = createRef(); + render(); + expect(ref.current).not.toBeNull(); + expect(ref.current?.tagName).toBe('BUTTON'); + }); +}); diff --git a/src/components/Checkbox/Checkbox.spec.tsx b/src/components/Checkbox/Checkbox.spec.tsx new file mode 100644 index 00000000..6df80e91 --- /dev/null +++ b/src/components/Checkbox/Checkbox.spec.tsx @@ -0,0 +1,17 @@ +import { render } from '@testing-library/react'; +import { createRef } from 'react'; +import { Checkbox } from './Checkbox'; + +describe('Checkbox', () => { + it('access to DOM through ref prop', () => { + const ref = createRef(); + render( + + Test + , + ); + expect(ref.current).not.toBeNull(); + expect(ref.current?.tagName).toBe('INPUT'); + expect(ref.current?.type).toBe('checkbox'); + }); +}); diff --git a/src/stories/Checkbox.stories.tsx b/src/components/Checkbox/Checkbox.stories.tsx similarity index 98% rename from src/stories/Checkbox.stories.tsx rename to src/components/Checkbox/Checkbox.stories.tsx index dfec6200..f0f6fdf4 100644 --- a/src/stories/Checkbox.stories.tsx +++ b/src/components/Checkbox/Checkbox.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryObj } from '@storybook/react'; import { useState, useCallback } from 'react'; -import { Checkbox, CheckboxGroup, Stack } from '../'; +import { Checkbox, CheckboxGroup, Stack } from '../../index'; import type { ChangeEventHandler } from 'react'; export default { diff --git a/src/components/Checkbox/Checkbox.tsx b/src/components/Checkbox/Checkbox.tsx index 265e842d..1e9bffea 100644 --- a/src/components/Checkbox/Checkbox.tsx +++ b/src/components/Checkbox/Checkbox.tsx @@ -2,8 +2,9 @@ import { CheckAIcon } from '@ubie/ubie-icons'; import clsx from 'clsx'; -import { FC, InputHTMLAttributes } from 'react'; +import { forwardRef } from 'react'; import styles from './Checkbox.module.css'; +import type { InputHTMLAttributes } from 'react'; type Props = { /** @@ -29,14 +30,16 @@ type Props = { onChange?: InputHTMLAttributes['onChange']; } & Omit, 'size' | 'value' | 'children' | 'onChange'>; -export const Checkbox: FC = ({ size = 'medium', children, ...otherProps }) => { +export const Checkbox = forwardRef(({ size = 'medium', children, ...otherProps }, ref) => { return ( ); -}; +}); + +Checkbox.displayName = 'Checkbox'; diff --git a/src/components/CheckboxGroup/CheckboxGroup.spec.tsx b/src/components/CheckboxGroup/CheckboxGroup.spec.tsx new file mode 100644 index 00000000..77300544 --- /dev/null +++ b/src/components/CheckboxGroup/CheckboxGroup.spec.tsx @@ -0,0 +1,17 @@ +import { render } from '@testing-library/react'; +import { createRef } from 'react'; +import { CheckboxGroup } from './CheckboxGroup'; + +describe('CheckboxGroup', () => { + it('access to DOM through ref prop', () => { + const ref = createRef(); + render( + +

Test

+

Test

+
, + ); + expect(ref.current).not.toBeNull(); + expect(ref.current?.tagName).toBe('FIELDSET'); + }); +}); diff --git a/src/components/CheckboxGroup/CheckboxGroup.tsx b/src/components/CheckboxGroup/CheckboxGroup.tsx index 0a2aface..3061d4fc 100644 --- a/src/components/CheckboxGroup/CheckboxGroup.tsx +++ b/src/components/CheckboxGroup/CheckboxGroup.tsx @@ -1,46 +1,34 @@ 'use client'; +import { forwardRef } from 'react'; import styles from './CheckboxGroup.module.css'; import { RequiredLabel } from '../../sharedComponents/RequiredLabel/RequiredLabel'; -import { CustomDataAttributeProps } from '../../types/attributes'; // 追加したインポート +import { CustomDataAttributeProps } from '../../types/attributes'; import { Checkbox } from '../Checkbox/Checkbox'; import { Flex } from '../Flex/Flex'; -import type { FC, ReactElement } from 'react'; +import type { ReactElement } from 'react'; export type Props = { children: ReactElement[]; - /** - * チェックボックスグループの見出し(legend要素) - */ label: string; - /** - * 必須マークを表示するか - * 注意: trueとしてもinput要素のrequired属性は付与されません - */ showRequiredLabel?: boolean; - /** - * チェックボックスの配置方向 - * @default column - */ direction?: 'column' | 'row'; } & CustomDataAttributeProps; -export const CheckboxGroup: FC = ({ - children, - label, - showRequiredLabel, - direction = 'column', - ...otherProps -}) => { - return ( -
- - {label} - {showRequiredLabel && } - - - {children} - -
- ); -}; +export const CheckboxGroup = forwardRef( + ({ children, label, showRequiredLabel, direction = 'column', ...otherProps }, ref) => { + return ( +
+ + {label} + {showRequiredLabel && } + + + {children} + +
+ ); + }, +); + +CheckboxGroup.displayName = 'CheckboxGroup'; diff --git a/src/components/ErrorMessage/ErrorMessage.spec.tsx b/src/components/ErrorMessage/ErrorMessage.spec.tsx new file mode 100644 index 00000000..c50e1263 --- /dev/null +++ b/src/components/ErrorMessage/ErrorMessage.spec.tsx @@ -0,0 +1,12 @@ +import { render } from '@testing-library/react'; +import { createRef } from 'react'; +import { ErrorMessage } from './ErrorMessage'; + +describe('ErrorMessage', () => { + it('access to DOM through ref prop', () => { + const ref = createRef(); + render(Test); + expect(ref.current).not.toBeNull(); + expect(ref.current?.tagName).toBe('P'); + }); +}); diff --git a/src/components/ErrorMessage/ErrorMessage.tsx b/src/components/ErrorMessage/ErrorMessage.tsx index 749cba7e..9c5b7cf7 100644 --- a/src/components/ErrorMessage/ErrorMessage.tsx +++ b/src/components/ErrorMessage/ErrorMessage.tsx @@ -1,15 +1,18 @@ 'use client'; +import { forwardRef } from 'react'; import styles from './ErrorMessage.module.css'; -import { CustomDataAttributeProps } from '../../types/attributes'; // 追加したインポート -import type { FC, ReactNode } from 'react'; +import { CustomDataAttributeProps } from '../../types/attributes'; +import type { ReactNode } from 'react'; type Props = { children: ReactNode; } & CustomDataAttributeProps; -export const ErrorMessage: FC = ({ children, ...otherProps }) => ( -

+export const ErrorMessage = forwardRef(({ children, ...otherProps }, ref) => ( +

{children}

-); +)); + +ErrorMessage.displayName = 'ErrorMessage'; diff --git a/src/components/Input/Input.spec.tsx b/src/components/Input/Input.spec.tsx new file mode 100644 index 00000000..e71bf6f9 --- /dev/null +++ b/src/components/Input/Input.spec.tsx @@ -0,0 +1,14 @@ +import { render } from '@testing-library/react'; +import { createRef } from 'react'; +import { Input } from './Input'; + +describe('Input', () => { + it('access to DOM through ref prop', () => { + const ref = createRef(); + + render(); + expect(ref.current).not.toBeNull(); + expect(ref.current?.tagName).toBe('INPUT'); + expect(ref.current?.type).toBe('text'); + }); +}); diff --git a/src/components/Input/Input.tsx b/src/components/Input/Input.tsx index 7f47dc74..f251d9e1 100644 --- a/src/components/Input/Input.tsx +++ b/src/components/Input/Input.tsx @@ -1,7 +1,7 @@ 'use client'; import { clsx } from 'clsx'; -import { FC, forwardRef, InputHTMLAttributes } from 'react'; +import { forwardRef, InputHTMLAttributes } from 'react'; import styles from './Input.module.css'; import { CustomDataAttributeProps } from '../../types/attributes'; // 追加したインポート @@ -18,7 +18,7 @@ type Props = { } & Omit, 'invalid' | 'value'> & CustomDataAttributeProps; -export const Input: FC = forwardRef(({ isInvalid, ...props }, ref) => { +export const Input = forwardRef(({ isInvalid, ...props }, ref) => { const className = clsx({ [styles.isInvalid]: isInvalid && !props.disabled }, styles.input, props.className); return ; diff --git a/src/components/RadioButton/RadioButton.spec.tsx b/src/components/RadioButton/RadioButton.spec.tsx new file mode 100644 index 00000000..008f8e24 --- /dev/null +++ b/src/components/RadioButton/RadioButton.spec.tsx @@ -0,0 +1,25 @@ +import { render } from '@testing-library/react'; +import { createRef } from 'react'; +import { RadioButton } from './RadioButton'; + +describe('RadioButton', () => { + it('access to DOM through ref prop', () => { + const ref = createRef(); + render( + { + /**/ + }} + checked={false} + > + Test + , + ); + expect(ref.current).not.toBeNull(); + expect(ref.current?.tagName).toBe('INPUT'); + expect(ref.current?.type).toBe('radio'); + }); +}); diff --git a/src/components/RadioButton/RadioButton.tsx b/src/components/RadioButton/RadioButton.tsx index 370d47c2..4cfbe8ea 100644 --- a/src/components/RadioButton/RadioButton.tsx +++ b/src/components/RadioButton/RadioButton.tsx @@ -1,7 +1,7 @@ 'use client'; import clsx from 'clsx'; -import { FC, InputHTMLAttributes } from 'react'; +import { forwardRef, type InputHTMLAttributes } from 'react'; import styles from './RadioButton.module.css'; import { CustomDataAttributeProps } from '../../types/attributes'; @@ -29,30 +29,27 @@ type Props = { } & RadioProps & CustomDataAttributeProps; -export const RadioButton: FC = ({ - size = 'medium', - checked, - onChange, - value, - name, - children, - ...otherProps -}) => { - return ( -
- -
- ); -}; +export const RadioButton = forwardRef( + ({ size = 'medium', checked, onChange, value, name, children, ...otherProps }, ref) => { + return ( +
+ +
+ ); + }, +); + +RadioButton.displayName = 'RadioButton'; diff --git a/src/components/RadioGroup/RadioGroup.spec.tsx b/src/components/RadioGroup/RadioGroup.spec.tsx new file mode 100644 index 00000000..5ad09b1e --- /dev/null +++ b/src/components/RadioGroup/RadioGroup.spec.tsx @@ -0,0 +1,17 @@ +import { render } from '@testing-library/react'; +import { createRef } from 'react'; +import { RadioGroup } from './RadioGroup'; + +describe('RadioGroup', () => { + it('access to DOM through ref prop', () => { + const ref = createRef(); + render( + +

Test

+

Test

+
, + ); + expect(ref.current).not.toBeNull(); + expect(ref.current?.tagName).toBe('FIELDSET'); + }); +}); diff --git a/src/components/RadioGroup/RadioGroup.tsx b/src/components/RadioGroup/RadioGroup.tsx index 695f2b9f..8c4bf754 100644 --- a/src/components/RadioGroup/RadioGroup.tsx +++ b/src/components/RadioGroup/RadioGroup.tsx @@ -1,12 +1,13 @@ 'use client'; +import { forwardRef } from 'react'; import styles from './RadioGroup.module.css'; import { RequiredLabel } from '../../sharedComponents/RequiredLabel/RequiredLabel'; import { CustomDataAttributeProps } from '../../types/attributes'; // 追加したインポート import { Flex } from '../Flex/Flex'; import { RadioButton } from '../RadioButton/RadioButton'; import { RadioCard } from '../RadioCard/RadioCard'; -import type { FC, ReactElement } from 'react'; +import type { ReactElement } from 'react'; type RadioComponent = ReactElement | ReactElement; @@ -28,29 +29,27 @@ export type Props = { direction?: 'column' | 'row'; } & CustomDataAttributeProps; -export const RadioGroup: FC = ({ - children, - label, - showRequiredLabel = false, - direction = 'column', - ...otherProps -}) => { - const childrenIsCard = children.some((child) => child.type === RadioCard); - const childenIsBlock = direction === 'row' || (childrenIsCard && direction === 'column'); +export const RadioGroup = forwardRef( + ({ children, label, showRequiredLabel = false, direction = 'column', ...otherProps }, ref) => { + const childrenIsCard = children.some((child) => child.type === RadioCard); + const childenIsBlock = direction === 'row' || (childrenIsCard && direction === 'column'); - return ( -
- - {label} - {showRequiredLabel && } - - - {children} - -
- ); -}; + return ( +
+ + {label} + {showRequiredLabel && } + + + {children} + +
+ ); + }, +); + +RadioGroup.displayName = 'RadioGroup'; diff --git a/src/components/Select/Select.spec.tsx b/src/components/Select/Select.spec.tsx new file mode 100644 index 00000000..adc24947 --- /dev/null +++ b/src/components/Select/Select.spec.tsx @@ -0,0 +1,12 @@ +import { render } from '@testing-library/react'; +import { createRef } from 'react'; +import { Select } from './Select'; + +describe('Select', () => { + it('access to DOM through ref prop', () => { + const ref = createRef(); + render(); + expect(ref.current).not.toBeNull(); + expect(ref.current?.tagName).toBe('SELECT'); + }); +}); diff --git a/src/components/Select/Select.tsx b/src/components/Select/Select.tsx index 5f961f5c..f21dffb1 100644 --- a/src/components/Select/Select.tsx +++ b/src/components/Select/Select.tsx @@ -2,7 +2,7 @@ import { UnfoldMoreIcon } from '@ubie/ubie-icons'; import clsx from 'clsx'; -import { FC, forwardRef, InputHTMLAttributes } from 'react'; +import { forwardRef, InputHTMLAttributes } from 'react'; import styles from './Select.module.css'; import { CustomDataAttributeProps } from '../../types/attributes'; @@ -27,7 +27,7 @@ type Props = CustomDataAttributeProps & { className?: string; } & Omit, 'id' | 'disabled'>; -const Select: FC = forwardRef( +const Select = forwardRef( ({ isInvalid = false, disabled = false, children, className, ...props }, ref) => { return (
diff --git a/src/components/TextArea/TextArea.spec.tsx b/src/components/TextArea/TextArea.spec.tsx new file mode 100644 index 00000000..77df7d89 --- /dev/null +++ b/src/components/TextArea/TextArea.spec.tsx @@ -0,0 +1,17 @@ +import { render } from '@testing-library/react'; +import { createRef } from 'react'; +import { TextArea } from './TextArea'; + +describe('TextArea', () => { + it('access to DOM through ref prop', () => { + const ref = createRef(); + + render( + , + ); + expect(ref.current).not.toBeNull(); + expect(ref.current?.tagName).toBe('TEXTAREA'); + }); +}); diff --git a/src/components/TextArea/TextArea.tsx b/src/components/TextArea/TextArea.tsx index 3ad79714..6ff1c5fa 100644 --- a/src/components/TextArea/TextArea.tsx +++ b/src/components/TextArea/TextArea.tsx @@ -1,9 +1,10 @@ 'use client'; import clsx from 'clsx'; -import { FC, TextareaHTMLAttributes } from 'react'; +import { forwardRef } from 'react'; import styles from './TextArea.module.css'; import { CustomDataAttributeProps } from '../../types/attributes'; +import type { TextareaHTMLAttributes } from 'react'; type Props = { /** @@ -23,8 +24,10 @@ type Props = { } & Omit, 'value'> & CustomDataAttributeProps; -export const TextArea: FC = ({ isInvalid = false, className, ...props }) => { +export const TextArea = forwardRef(({ isInvalid = false, className, ...props }, ref) => { const _className = clsx({ [styles.isInvalid]: isInvalid }, styles.textArea, className); - return