-
Notifications
You must be signed in to change notification settings - Fork 142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: SingleComboBox の Story を見直し #5143
base: master
Are you sure you want to change the base?
Changes from all commits
a932cce
6d37238
6aa24f9
557c145
43d7c40
f366260
aea51be
91829c6
20bc809
0b6d0bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { SingleComboBox } from './SingleComboBox' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
/* eslint-disable smarthr/a11y-input-in-form-control */ | ||
import { useArgs } from '@storybook/preview-api' | ||
import { Meta, StoryObj } from '@storybook/react' | ||
import React, { useState } from 'react' | ||
|
||
import { FaCirclePlusIcon } from '../../../Icon' | ||
import { Stack } from '../../../Layout' | ||
import { Text } from '../../../Text' | ||
import { SingleComboBox } from '../SingleComboBox' | ||
|
||
// eslint-disable-next-line storybook/prefer-pascal-case | ||
export const defaultItems = { | ||
'option 1': { | ||
label: 'option 1', | ||
value: 'value-1', | ||
data: { | ||
option: 'option 1', | ||
}, | ||
}, | ||
'option 2': { | ||
label: 'option 2', | ||
value: 'value-2', | ||
data: { | ||
option: 'option 2', | ||
}, | ||
}, | ||
'option 3': { | ||
label: 'option 3', | ||
value: 'value-3', | ||
disabled: true, | ||
data: { | ||
option: 'option 3', | ||
}, | ||
}, | ||
'option 4': { | ||
label: 'option 4', | ||
value: 'value-4', | ||
data: { | ||
option: 'option 4', | ||
}, | ||
}, | ||
'option 5': { | ||
label: 'option 5', | ||
value: 'value-5', | ||
data: { | ||
option: 'option 5', | ||
}, | ||
}, | ||
'アイテムのラベルが長い場合(ダミーテキストダミーテキストダミーテキストダミーテキスト)': { | ||
label: 'アイテムのラベルが長い場合(ダミーテキストダミーテキストダミーテキストダミーテキスト)', | ||
value: 'value-6', | ||
data: { | ||
option: | ||
'アイテムのラベルが長い場合(ダミーテキストダミーテキストダミーテキストダミーテキスト)', | ||
}, | ||
}, | ||
アイテムのラベルがReactNodeの場合: { | ||
label: ( | ||
<Stack as="span" gap={0.25}> | ||
<span>アイテムのラベルがReactNodeの場合</span> | ||
<span>(ダミーテキストダミーテキストダミーテキストダミーテキスト)</span> | ||
</Stack> | ||
), | ||
value: 'value-7', | ||
data: { | ||
option: 'アイテムのラベルがReactNodeの場合', | ||
}, | ||
}, | ||
} | ||
|
||
// eslint-disable-next-line storybook/prefer-pascal-case | ||
export const prefixes = { なし: '', あり: <FaCirclePlusIcon /> } | ||
|
||
export default { | ||
title: 'Forms(フォーム)/SingleComboBox', | ||
component: SingleComboBox, | ||
render: (args) => { | ||
const [, setArgs] = useArgs() | ||
return ( | ||
<SingleComboBox | ||
{...args} | ||
onClearClick={() => setArgs({ selectedItem: null })} | ||
onSelect={(item) => setArgs({ selectedItem: item.data?.option })} | ||
/> | ||
) | ||
}, | ||
args: { | ||
items: Object.values(defaultItems), | ||
selectedItem: null, | ||
}, | ||
argTypes: { | ||
items: { control: 'object' }, | ||
selectedItem: { | ||
control: { type: 'select' }, | ||
options: Object.keys(defaultItems), | ||
mapping: defaultItems, | ||
}, | ||
defaultItem: { | ||
control: { type: 'select' }, | ||
options: Object.keys(defaultItems), | ||
mapping: defaultItems, | ||
}, | ||
prefix: { | ||
control: 'radio', | ||
options: Object.keys(prefixes), | ||
mapping: prefixes, | ||
}, | ||
dropdownHelpMessage: { | ||
control: { type: 'select' }, | ||
options: ['文字列', 'ReactNode'], | ||
mapping: { | ||
文字列: 'ヘルプメッセージ', | ||
ReactNode: <Text className="shr-text-danger">React Nodeを渡したメッセージ</Text>, | ||
}, | ||
}, | ||
}, | ||
parameters: { | ||
chromatic: { disableSnapshot: true }, | ||
}, | ||
excludeStories: ['defaultItems', 'prefixes'], | ||
} as Meta<typeof SingleComboBox<{ option: string }>> | ||
|
||
export const Playground: StoryObj<typeof SingleComboBox> = {} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nits] dropdownHelpMessage を Controls で編集しようとするとクラッシュしました。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @s-sasaki-0529 クラッシュするのは使いづらそうなので選択式に直しました! |
||
|
||
export const SelectedItem: StoryObj<typeof SingleComboBox> = { | ||
name: 'selectedItem', | ||
args: { | ||
selectedItem: defaultItems['option 2'], | ||
}, | ||
} | ||
|
||
export const DefaultItem: StoryObj<typeof SingleComboBox> = { | ||
uknmr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
name: 'defaultItem', | ||
render: (args) => { | ||
const [selectItem, setSelectItem] = useState(args.defaultItem) | ||
return ( | ||
<SingleComboBox | ||
{...args} | ||
selectedItem={selectItem ?? null} | ||
onSelect={(item) => setSelectItem(item)} | ||
/> | ||
) | ||
}, | ||
args: { | ||
defaultItem: defaultItems['option 4'], | ||
}, | ||
} | ||
|
||
export const Prefix: StoryObj<typeof SingleComboBox> = { | ||
name: 'prefix', | ||
render: (args) => ( | ||
<Stack gap={1}> | ||
<SingleComboBox {...args} prefix={prefixes['なし']} /> | ||
<SingleComboBox {...args} prefix={prefixes['あり']} /> | ||
</Stack> | ||
), | ||
} | ||
|
||
export const Disabled: StoryObj<typeof SingleComboBox> = { | ||
name: 'disabled', | ||
args: { | ||
disabled: true, | ||
}, | ||
} | ||
|
||
export const Error: StoryObj<typeof SingleComboBox> = { | ||
name: 'error', | ||
args: { | ||
error: true, | ||
}, | ||
} | ||
|
||
export const Creatable: StoryObj<typeof SingleComboBox> = { | ||
name: 'creatable', | ||
args: { | ||
creatable: true, | ||
dropdownHelpMessage: '新しいアイテムを追加できます。', | ||
}, | ||
} | ||
|
||
export const IsLoading: StoryObj<typeof SingleComboBox> = { | ||
name: 'isLoading', | ||
args: { | ||
isLoading: true, | ||
}, | ||
} | ||
|
||
export const Width: StoryObj<typeof SingleComboBox> = { | ||
name: 'width', | ||
args: { | ||
width: '20rem', | ||
}, | ||
} | ||
|
||
export const DropdownHelpMessage: StoryObj<typeof SingleComboBox> = { | ||
name: 'dropdownHelpMessage', | ||
args: { | ||
dropdownHelpMessage: 'ヘルプメッセージ', | ||
}, | ||
} | ||
|
||
export const DropdownWidth: StoryObj<typeof SingleComboBox> = { | ||
name: 'dropdownWidth', | ||
args: { | ||
dropdownWidth: '30rem', | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* eslint-disable smarthr/a11y-input-in-form-control */ | ||
import { Meta, StoryObj } from '@storybook/react' | ||
import { userEvent, within } from '@storybook/test' | ||
import React from 'react' | ||
|
||
import { Stack } from '../../../Layout' | ||
import { SingleComboBox } from '../SingleComboBox' | ||
|
||
import { defaultItems, prefixes } from './SingleComboBox.stories' | ||
|
||
/* pict singleComboBox.pict | ||
* disabled error width prefix selectedItem | ||
* false false なし なし あり | ||
* false true あり あり なし | ||
* true true あり なし あり | ||
* true false あり あり なし | ||
* true true なし なし なし | ||
* true false なし あり あり | ||
*/ | ||
|
||
const _cases: Array<Omit<Parameters<typeof SingleComboBox>[0], 'items'>> = [ | ||
{ | ||
disabled: false, | ||
error: false, | ||
width: undefined, | ||
prefix: undefined, | ||
selectedItem: defaultItems['option 1'], | ||
}, | ||
{ disabled: false, error: true, width: '15em', prefix: prefixes['あり'], selectedItem: null }, | ||
{ | ||
disabled: true, | ||
error: true, | ||
width: '15em', | ||
prefix: undefined, | ||
selectedItem: | ||
defaultItems[ | ||
'アイテムのラベルが長い場合(ダミーテキストダミーテキストダミーテキストダミーテキスト)' | ||
], | ||
}, | ||
{ disabled: true, error: false, width: '15em', prefix: prefixes['あり'], selectedItem: null }, | ||
{ disabled: true, error: true, width: undefined, prefix: undefined, selectedItem: null }, | ||
{ | ||
disabled: true, | ||
error: false, | ||
width: undefined, | ||
prefix: prefixes['あり'], | ||
selectedItem: defaultItems['アイテムのラベルがReactNodeの場合'], | ||
}, | ||
] | ||
|
||
const playSingle = async ({ canvasElement }: { canvasElement: HTMLElement }) => { | ||
const canvas = within(canvasElement) | ||
const textboxes = await canvas.findAllByRole('combobox') | ||
await textboxes[textboxes.length - 1].focus() | ||
const body = canvasElement.ownerDocument.body | ||
const option = await within(body).findByText('option 1') | ||
await userEvent.hover(option) | ||
const helpMessage = await within(body).findAllByText('入力でフィルタリングできます。') | ||
await userEvent.click(helpMessage[0]) // カーソルの点滅によるVRTのフレーキーを避けるためにフォーカスを移動する | ||
} | ||
|
||
export default { | ||
title: 'Forms(フォーム)/SingleComboBox/VRT', | ||
component: SingleComboBox, | ||
render: (args) => ( | ||
<Stack align="flex-start" gap={2} className="shr-h-screen"> | ||
{_cases.map((props, i) => ( | ||
<SingleComboBox {...args} {...props} items={Object.values(defaultItems)} key={i} /> | ||
))} | ||
<SingleComboBox | ||
{...args} | ||
name="default" | ||
items={Object.values(defaultItems)} | ||
dropdownHelpMessage="入力でフィルタリングできます。" | ||
selectedItem={null} | ||
/> | ||
</Stack> | ||
), | ||
play: playSingle, | ||
parameters: { | ||
withTheming: true, | ||
chromatic: { disableSnapshot: false }, | ||
}, | ||
tags: ['!autodocs', 'skip-test-runner'], | ||
} as Meta<typeof SingleComboBox> | ||
|
||
export const VRT: StoryObj<typeof SingleComboBox> = {} | ||
|
||
export const VRTForcedColors: StoryObj<typeof SingleComboBox> = { | ||
...VRT, | ||
parameters: { | ||
chromatic: { forcedColors: 'active' }, | ||
}, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nits]
細かすぎますが、Controls 上でいずれかのアイテムを選択状態にしちゃうと、それをクリアする手段がなくなってちょっとだけ困りました (単にブラウザリロードしてもURLに状態が保持されちゃうので…。)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@s-sasaki-0529 消えた方が使い方がわかっていいかな〜と思ったので、消えたり選択できるようにしてしまいました!
20bc809