From 833162b4601f630eba6316f48b5bd331b70da809 Mon Sep 17 00:00:00 2001 From: Qs-F Date: Tue, 19 Dec 2023 15:53:50 +0900 Subject: [PATCH 1/9] Add Tooltip component --- .../for-ui/src/tooltip/Tooltip.stories.tsx | 31 +++++++++++++++ packages/for-ui/src/tooltip/Tooltip.test.tsx | 38 +++++++++++++++++++ packages/for-ui/src/tooltip/Tooltip.tsx | 37 ++++++++++++++++++ packages/for-ui/src/tooltip/index.ts | 1 + 4 files changed, 107 insertions(+) create mode 100644 packages/for-ui/src/tooltip/Tooltip.stories.tsx create mode 100644 packages/for-ui/src/tooltip/Tooltip.test.tsx create mode 100644 packages/for-ui/src/tooltip/Tooltip.tsx create mode 100644 packages/for-ui/src/tooltip/index.ts diff --git a/packages/for-ui/src/tooltip/Tooltip.stories.tsx b/packages/for-ui/src/tooltip/Tooltip.stories.tsx new file mode 100644 index 00000000..81a24f73 --- /dev/null +++ b/packages/for-ui/src/tooltip/Tooltip.stories.tsx @@ -0,0 +1,31 @@ +import { forwardRef } from 'react'; +import { MdOutlineInfo } from 'react-icons/md'; +import { Meta, StoryObj } from '@storybook/react/types-6-0'; +import { Tooltip, TooltipFrame, TooltipProps } from './Tooltip'; + +type Story = StoryObj; + +const TooltipIcon = forwardRef((props, ref) => ( + + + +)); + +export default { + title: 'Feedback / Tooltip', + component: Tooltip, +} as Meta; + +export const Playground: Story = { + args: { + title: 'テキスト', + children: , + }, +}; + +export const FrameOnly: Story = { + args: { + title: 'テキスト', + }, + render: (props) => , +}; diff --git a/packages/for-ui/src/tooltip/Tooltip.test.tsx b/packages/for-ui/src/tooltip/Tooltip.test.tsx new file mode 100644 index 00000000..4608fff0 --- /dev/null +++ b/packages/for-ui/src/tooltip/Tooltip.test.tsx @@ -0,0 +1,38 @@ +import { ComponentPropsWithRef, forwardRef } from 'react'; +import { describe, expect, it } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { Tooltip } from './Tooltip'; + +const Trigger = forwardRef>((props, ref) => ( + +)); + +describe('Tooltip', () => { + it('has rendered children', async () => { + render( + + test + , + ); + expect(screen.getByText('test')).toBeInTheDocument(); + }); + it('has children with accessible description', async () => { + render( + + test + , + ); + expect(screen.getByText('test')).toHaveAccessibleDescription('テキスト'); + }); + it('is appeared when focusing trigger', async () => { + const user = userEvent.setup(); + render( + + test + , + ); + user.tab(); + expect(await screen.findByRole('tooltip')).toBeInTheDocument(); + }); +}); diff --git a/packages/for-ui/src/tooltip/Tooltip.tsx b/packages/for-ui/src/tooltip/Tooltip.tsx new file mode 100644 index 00000000..fc86b94b --- /dev/null +++ b/packages/for-ui/src/tooltip/Tooltip.tsx @@ -0,0 +1,37 @@ +import { ComponentPropsWithRef, FC, forwardRef } from 'react'; +import MuiTooltip, { TooltipProps as MuiTooltipProps } from '@mui/material/Tooltip'; +import { fsx } from '../system/fsx'; +import { PropsCascader } from '../system/PropsCascader'; +import { Text } from '../text'; + +export type TooltipProps = Pick & { + title: string; +}; + +export const TooltipFrame = forwardRef>( + ({ children, ...props }, ref) => ( + + {children} + + ), +); + +export const Tooltip: FC = ({ children, ...props }) => { + return ( + + {children} + + ); +}; diff --git a/packages/for-ui/src/tooltip/index.ts b/packages/for-ui/src/tooltip/index.ts new file mode 100644 index 00000000..7594a8f0 --- /dev/null +++ b/packages/for-ui/src/tooltip/index.ts @@ -0,0 +1 @@ +export * from './Tooltip'; From e16bcc20b63b82201e28586aefa8152ee2caa8f3 Mon Sep 17 00:00:00 2001 From: Qs-F Date: Tue, 19 Dec 2023 18:34:26 +0900 Subject: [PATCH 2/9] Fix a11y issues --- packages/for-ui/src/tooltip/Tooltip.test.tsx | 18 +++++++-------- packages/for-ui/src/tooltip/Tooltip.tsx | 23 ++++++++++++++++---- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/packages/for-ui/src/tooltip/Tooltip.test.tsx b/packages/for-ui/src/tooltip/Tooltip.test.tsx index 4608fff0..ed3e31ef 100644 --- a/packages/for-ui/src/tooltip/Tooltip.test.tsx +++ b/packages/for-ui/src/tooltip/Tooltip.test.tsx @@ -11,28 +11,28 @@ const Trigger = forwardRef>((prop describe('Tooltip', () => { it('has rendered children', async () => { render( - - test + + trigger , ); - expect(screen.getByText('test')).toBeInTheDocument(); + expect(await screen.findByText('trigger')).toBeInTheDocument(); }); it('has children with accessible description', async () => { render( - - test + + trigger , ); - expect(screen.getByText('test')).toHaveAccessibleDescription('テキスト'); + expect(await screen.findByText('trigger')).toHaveAccessibleDescription('description'); }); it('is appeared when focusing trigger', async () => { const user = userEvent.setup(); render( - - test + + trigger , ); - user.tab(); + await user.tab(); expect(await screen.findByRole('tooltip')).toBeInTheDocument(); }); }); diff --git a/packages/for-ui/src/tooltip/Tooltip.tsx b/packages/for-ui/src/tooltip/Tooltip.tsx index fc86b94b..94e63f1c 100644 --- a/packages/for-ui/src/tooltip/Tooltip.tsx +++ b/packages/for-ui/src/tooltip/Tooltip.tsx @@ -1,8 +1,9 @@ -import { ComponentPropsWithRef, FC, forwardRef } from 'react'; +import { ComponentPropsWithRef, FC, forwardRef, useId } from 'react'; import MuiTooltip, { TooltipProps as MuiTooltipProps } from '@mui/material/Tooltip'; import { fsx } from '../system/fsx'; import { PropsCascader } from '../system/PropsCascader'; import { Text } from '../text'; +import { prepareForSlot } from '../utils/prepareForSlot'; export type TooltipProps = Pick & { title: string; @@ -23,15 +24,29 @@ export const TooltipFrame = forwardRef = ({ children, ...props }) => { + const internalId = useId(); return ( - {children} + {children} ); }; From 8080e2dc27f08046d9122f4883d174bee19bcf5d Mon Sep 17 00:00:00 2001 From: Qs-F Date: Tue, 19 Dec 2023 18:35:06 +0900 Subject: [PATCH 3/9] Fix Text component to receive ref prop --- packages/for-ui/src/text/Text.tsx | 85 +++++++++++++++---------------- 1 file changed, 41 insertions(+), 44 deletions(-) diff --git a/packages/for-ui/src/text/Text.tsx b/packages/for-ui/src/text/Text.tsx index d65901a4..94f75d76 100644 --- a/packages/for-ui/src/text/Text.tsx +++ b/packages/for-ui/src/text/Text.tsx @@ -1,5 +1,6 @@ -import { ComponentPropsWithoutRef, ElementType, ReactNode } from 'react'; +import { ElementType, FC, forwardRef, ReactNode } from 'react'; import { fsx } from '../system/fsx'; +import { ComponentProps, Ref } from '../system/polyComponent'; type WithInherit = T | 'inherit'; @@ -33,52 +34,48 @@ const style = (size: WithInherit, weight: WithInherit, typeface: W ); }; -export type TextProps

= ComponentPropsWithoutRef

& { - /** - * レンダリングするコンポーネントを指定 (例: h1, p, strong) - * @default span - */ - as?: P; +export type TextProps = ComponentProps< + { + /** + * テキストのサイズを指定 + * @default inherit + */ + size?: WithInherit; - /** - * テキストのサイズを指定 - * @default inherit - */ - size?: WithInherit; + /** + * 表示するテキストのウェイトを指定 + * @default inherit + */ + weight?: WithInherit; - /** - * 表示するテキストのウェイトを指定 - * @default inherit - */ - weight?: WithInherit; + /** + * 表示する書体の種別を指定 + * @default inherit + */ + typeface?: WithInherit; - /** - * 表示する書体の種別を指定 - * @default inherit - */ - typeface?: WithInherit; + className?: string; - className?: string; + /** + * 文字列またはstrong等のコンポーネント (HTML的にvalidになるようにしてください) + */ + children: ReactNode; + }, + As +>; - /** - * 文字列またはstrong等のコンポーネント (HTML的にvalidになるようにしてください) - */ - children: ReactNode; -}; +type TextComponent = (props: TextProps) => ReturnType; -export const Text =

({ - as, - size = 'inherit', - weight = 'inherit', - typeface = 'inherit', - className, - children, - ...rests -}: TextProps

): JSX.Element => { - const Component = as || 'span'; - return ( - - {children} - - ); -}; +export const Text: TextComponent = forwardRef( + ( + { as, size = 'inherit', weight = 'inherit', typeface = 'inherit', className, children, ...rests }: TextProps, + ref: Ref, + ) => { + const Component = as || 'span'; + return ( + + {children} + + ); + }, +); From 0324b95d902987b90e51ed5d24bcd33c9b9c0d88 Mon Sep 17 00:00:00 2001 From: Qs-F Date: Tue, 19 Dec 2023 18:35:44 +0900 Subject: [PATCH 4/9] Add PropsCascader utility component --- packages/for-ui/src/system/PropsCascader.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 packages/for-ui/src/system/PropsCascader.tsx diff --git a/packages/for-ui/src/system/PropsCascader.tsx b/packages/for-ui/src/system/PropsCascader.tsx new file mode 100644 index 00000000..d3c24822 --- /dev/null +++ b/packages/for-ui/src/system/PropsCascader.tsx @@ -0,0 +1,18 @@ +import { Children, cloneElement, FC, ForwardedRef, forwardRef, HTMLAttributes, isValidElement, ReactNode } from 'react'; + +type PropsCascaderProps> = T & { + children: ReactNode; +}; + +type PropsCascaderComponent = >(props: PropsCascaderProps) => ReturnType; + +export const PropsCascader: PropsCascaderComponent = forwardRef( + >({ children, ...props }: PropsCascaderProps, ref: ForwardedRef) => { + return Children.map(children, (child: ReactNode) => { + if (!isValidElement(child)) { + return child; + } + return cloneElement(child, { ...props, ...child.props, ref }); + }); + }, +); From dd76f90a40b3488eaa5fad07f3174ebe2274bb5e Mon Sep 17 00:00:00 2001 From: Qs-F Date: Tue, 19 Dec 2023 18:36:12 +0900 Subject: [PATCH 5/9] Add prepareForSlot util from @mui/base --- packages/for-ui/src/utils/prepareForSlot.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 packages/for-ui/src/utils/prepareForSlot.tsx diff --git a/packages/for-ui/src/utils/prepareForSlot.tsx b/packages/for-ui/src/utils/prepareForSlot.tsx new file mode 100644 index 00000000..76bb774c --- /dev/null +++ b/packages/for-ui/src/utils/prepareForSlot.tsx @@ -0,0 +1,15 @@ +// Retrieved from https://github.com/mui/material-ui/blob/master/packages/mui-base/src/utils/prepareForSlot.tsx + +import * as React from 'react'; + +export function prepareForSlot(Component: ComponentType) { + type Props = React.ComponentProps; + + return React.forwardRef(function Slot(props, ref) { + const { ownerState: _, ...other } = props; + return React.createElement(Component, { + ...(other as Props), + ref, + }); + }); +} From d369a89206d1843ea162f9023cf742d925d8382d Mon Sep 17 00:00:00 2001 From: Qs-F Date: Tue, 19 Dec 2023 18:36:28 +0900 Subject: [PATCH 6/9] Add exports tooltip --- packages/for-ui/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/for-ui/src/index.ts b/packages/for-ui/src/index.ts index bb36427b..b62974b3 100644 --- a/packages/for-ui/src/index.ts +++ b/packages/for-ui/src/index.ts @@ -19,3 +19,4 @@ export * from './textArea'; export * from './textField'; export * from './tabs'; export * from './table'; +export * from './tooltip'; From 84d5acce308e9570882805611b745442c4571f61 Mon Sep 17 00:00:00 2001 From: Qs-F Date: Tue, 19 Dec 2023 18:36:42 +0900 Subject: [PATCH 7/9] Update deps lock file --- package-lock.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 23861d45..6ccaa9ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5709,11 +5709,14 @@ } }, "node_modules/@storybook/builder-webpack4/node_modules/watchpack/chokidar2": { - "version": "0.0.1", + "version": "2.0.0", "dev": true, "optional": true, "dependencies": { "chokidar": "^2.1.8" + }, + "engines": { + "node": "<8.10.0" } }, "node_modules/@storybook/builder-webpack4/node_modules/webpack": { From 3c3d14f422702d3394a1e22fe4f76eab507a93dd Mon Sep 17 00:00:00 2001 From: Qs-F Date: Wed, 20 Dec 2023 11:08:37 +0900 Subject: [PATCH 8/9] Fmt --- packages/for-ui/src/skeleton/Skeleton.stories.tsx | 2 +- packages/for-ui/src/system/PropsCascader.tsx | 5 ++++- packages/for-ui/src/tooltip/Tooltip.tsx | 4 +++- packages/for-ui/src/utils/prepareForSlot.tsx | 1 - 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/for-ui/src/skeleton/Skeleton.stories.tsx b/packages/for-ui/src/skeleton/Skeleton.stories.tsx index 4dce51c9..19f726a4 100644 --- a/packages/for-ui/src/skeleton/Skeleton.stories.tsx +++ b/packages/for-ui/src/skeleton/Skeleton.stories.tsx @@ -6,7 +6,7 @@ import { Text } from '../text'; import { Skeleton, SkeletonX } from './Skeleton'; export default { - title: 'Data Display / Skeleton', + title: 'Feedback / Skeleton', component: Skeleton, decorators: [ // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/for-ui/src/system/PropsCascader.tsx b/packages/for-ui/src/system/PropsCascader.tsx index d3c24822..5d1a74bd 100644 --- a/packages/for-ui/src/system/PropsCascader.tsx +++ b/packages/for-ui/src/system/PropsCascader.tsx @@ -7,7 +7,10 @@ type PropsCascaderProps> = T & { type PropsCascaderComponent = >(props: PropsCascaderProps) => ReturnType; export const PropsCascader: PropsCascaderComponent = forwardRef( - >({ children, ...props }: PropsCascaderProps, ref: ForwardedRef) => { + >( + { children, ...props }: PropsCascaderProps, + ref: ForwardedRef, + ) => { return Children.map(children, (child: ReactNode) => { if (!isValidElement(child)) { return child; diff --git a/packages/for-ui/src/tooltip/Tooltip.tsx b/packages/for-ui/src/tooltip/Tooltip.tsx index 94e63f1c..d7f8f21c 100644 --- a/packages/for-ui/src/tooltip/Tooltip.tsx +++ b/packages/for-ui/src/tooltip/Tooltip.tsx @@ -46,7 +46,9 @@ export const Tooltip: FC = ({ children, ...props }) => { }} {...props} > - {children} + + {children} + ); }; diff --git a/packages/for-ui/src/utils/prepareForSlot.tsx b/packages/for-ui/src/utils/prepareForSlot.tsx index 76bb774c..99b78054 100644 --- a/packages/for-ui/src/utils/prepareForSlot.tsx +++ b/packages/for-ui/src/utils/prepareForSlot.tsx @@ -1,5 +1,4 @@ // Retrieved from https://github.com/mui/material-ui/blob/master/packages/mui-base/src/utils/prepareForSlot.tsx - import * as React from 'react'; export function prepareForSlot(Component: ComponentType) { From c6731925f73b986b741ac43016e9ecfc10fbb8c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=9F=E3=81=B5=E3=81=BF?= Date: Wed, 20 Dec 2023 11:18:21 +0900 Subject: [PATCH 9/9] Add change log --- .changeset/orange-games-work.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/orange-games-work.md diff --git a/.changeset/orange-games-work.md b/.changeset/orange-games-work.md new file mode 100644 index 00000000..ae939ff3 --- /dev/null +++ b/.changeset/orange-games-work.md @@ -0,0 +1,5 @@ +--- +"@4design/for-ui": patch +--- + +feat: Tooltipを追加