Skip to content
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: MultiComboBox の Story を見直し #5180

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a932cce
docs: SingleComboBox の Story を見直し
misako0927 Nov 27, 2024
6d37238
refactor: 不要な関数等を削除
misako0927 Nov 27, 2024
6aa24f9
refactor: 不要なループを削除
misako0927 Nov 27, 2024
557c145
Merge branch 'master' into SHRUI-1127-improve-SingleComboBox-Story
misako0927 Nov 27, 2024
567c16a
refactor: ディレクトリ変更
misako0927 Nov 28, 2024
43d7c40
chore: calenderのflakyを解消する
misako0927 Nov 28, 2024
f366260
fix: 指摘修正
misako0927 Nov 28, 2024
aea51be
fix: defaultItemが反映されるようにする
misako0927 Nov 29, 2024
4fec96d
Merge branch 'SHRUI-1127-improve-SingleComboBox-Story' into SHRUI-112…
misako0927 Nov 29, 2024
9e6b9e3
docs(MultiComboBox): Story を見直し
misako0927 Dec 5, 2024
91829c6
Merge branch 'master' into SHRUI-1127-improve-SingleComboBox-Story
misako0927 Dec 9, 2024
20bc809
docs: 選択したアイテムを消したりできるようにする
misako0927 Dec 10, 2024
0b6d0bb
docs: dropdownHelpMessageを選択式にする
misako0927 Dec 10, 2024
fd2b725
Merge branch 'master' into SHRUI-1127-improve-SingleComboBox-Story
misako0927 Dec 13, 2024
ad25eaa
Merge branch 'SHRUI-1127-improve-SingleComboBox-Story' into SHRUI-112…
misako0927 Dec 13, 2024
03ee75e
docs: MultiComboBoxのStoryで値の選択・解除がargsと連動するようにする
misako0927 Dec 13, 2024
fccd3f9
docs: MultiComboBoxのStoryでdropdownHelpMessageを編集する際にクラッシュしないようにする
misako0927 Dec 13, 2024
5fce516
fix: ファイル名の大文字小文字の変換が反映されていない問題を修正
misako0927 Dec 13, 2024
c535c52
Merge branch 'master' into SHRUI-1126-MultiComboBox-Story
misako0927 Dec 13, 2024
8f25146
fix: play functionが落ちていた問題修正
misako0927 Dec 24, 2024
7790aa0
fix: disableSnapshotの設定が間違っていたので修正
misako0927 Dec 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import { userEvent } from '@storybook/test'
import { render, screen } from '@testing-library/react'
import React, { ComponentProps, act } from 'react'

import { FormControl } from '../FormControl'
import { FormControl } from '../../FormControl'

import { MultiComboBox } from './MultiComboBox'
import { SingleComboBox } from './SingleComboBox'

describe('SingleComboBox', () => {
beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ import { useId } from 'react'
import innerText from 'react-innertext'
import { tv } from 'tailwind-variants'

import { useOuterClick } from '../../hooks/useOuterClick'
import { genericsForwardRef } from '../../libs/util'
import { textColor } from '../../themes'
import { FaCaretDownIcon } from '../Icon'
import { useOuterClick } from '../../../hooks/useOuterClick'
import { genericsForwardRef } from '../../../libs/util'
import { textColor } from '../../../themes'
import { FaCaretDownIcon } from '../../Icon'
import { useFocusControl } from '../useFocusControl'
import { useListBox } from '../useListBox'
import { useOptions } from '../useOptions'

import { MultiSelectedItem } from './MultiSelectedItem'
import { hasParentElementByClassName } from './multiComboBoxHelper'
import { useFocusControl } from './useFocusControl'
import { useListBox } from './useListBox'
import { useOptions } from './useOptions'

import type { BaseProps, ComboBoxItem } from './types'
import type { DecoratorsType } from '../../types'
import type { DecoratorsType } from '../../../types'
import type { BaseProps, ComboBoxItem } from '../types'

type Props<T> = BaseProps<T> & {
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { tv } from 'tailwind-variants'

import { UnstyledButton } from '../Button'
import { Chip } from '../Chip'
import { FaTimesCircleIcon } from '../Icon'
import { UnstyledButton } from '../../Button'
import { Chip } from '../../Chip'
import { FaTimesCircleIcon } from '../../Icon'
import { ComboBoxItem } from '../types'

import { MultiSelectedItemTooltip } from './MultiSelectedItemTooltip'
import { ComboBoxItem } from './types'

export type Props<T> = {
item: ComboBoxItem<T> & { deletable?: boolean }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FC, PropsWithChildren, ReactNode } from 'react'

import { Tooltip } from '../Tooltip'
import { Tooltip } from '../../Tooltip'

type Props = PropsWithChildren<{
needsTooltip: boolean
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { MultiComboBox } from './MultiComboBox'
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/* eslint-disable smarthr/a11y-input-in-form-control */
import { useArgs } from '@storybook/preview-api'
import { Meta, StoryObj } from '@storybook/react'
import React from 'react'

import { Stack } from '../../../Layout'
import { Text } from '../../../Text'
import { MultiComboBox } from '../MultiComboBox'

// eslint-disable-next-line storybook/prefer-pascal-case
export const defaultItems = {
'option 1': {
label: 'option 1',
value: 'value-1',
data: {
name: 'test',
age: 23,
},
},
'option 2': {
label: 'option 2',
value: 'value-2',
data: {
name: 'test 2',
age: 34,
},
},
'option 3': {
label: 'option 3',
value: 'value-3',
disabled: true,
},
'option 4': {
label: 'option 4',
value: 'value-4',
},
'option 5': {
label: 'option 5',
value: 'value-5',
},
'アイテムのラベルが長い場合(ダミーテキストダミーテキストダミーテキストダミーテキスト)': {
label: 'アイテムのラベルが長い場合(ダミーテキストダミーテキストダミーテキストダミーテキスト)',
value: 'value-6',
},
アイテムのラベルがReactNodeの場合: {
label: (
<Stack as="span" gap={0.25}>
<span>アイテムのラベルがReactNodeの場合</span>
<span>(ダミーテキストダミーテキストダミーテキストダミーテキスト)</span>
</Stack>
),
value: 'value-7',
},
}

export default {
title: 'Forms(フォーム)/MultiComboBox',
component: MultiComboBox,
render: (args) => {
const [_, setArgs] = useArgs()
return (
<MultiComboBox
{...args}
onDelete={(item) =>
setArgs({
selectedItems: args.selectedItems.filter(
(selectedItem) => selectedItem.value !== item.value,
),
})
}
onSelect={(item) =>
setArgs({
selectedItems: [...args.selectedItems, item],
})
}
/>
)
},
args: {
items: Object.values(defaultItems),
selectedItems: [],
},
argTypes: {
items: { control: 'object' },
selectedItems: { control: 'object' },
dropdownHelpMessage: {
control: { type: 'select' },
options: ['文字列', 'ReactNode'],
mapping: {
文字列: 'ヘルプメッセージ',
ReactNode: <Text className="shr-text-danger">React Nodeを渡したメッセージ</Text>,
},
},
},
parameters: {
chromatic: { disableSnapshot: true },
},
excludeStories: ['defaultItems'],
} as Meta<typeof MultiComboBox<{ option: string }>>

export const Playground: StoryObj<typeof MultiComboBox> = {}

export const SelectedItems: StoryObj<typeof MultiComboBox> = {
name: 'selectedItems',
args: {
selectedItems: [defaultItems['option 1'], defaultItems['option 4']],
},
}

export const Disabled: StoryObj<typeof MultiComboBox> = {
name: 'disabled',
args: {
disabled: true,
},
}

export const Error: StoryObj<typeof MultiComboBox> = {
name: 'error',
args: {
error: true,
},
}

export const Creatable: StoryObj<typeof MultiComboBox> = {
name: 'creatable',
args: {
creatable: true,
dropdownHelpMessage: '新しいアイテムを追加できます。',
},
}

export const IsLoading: StoryObj<typeof MultiComboBox> = {
name: 'isLoading',
args: {
isLoading: true,
},
}

export const Width: StoryObj<typeof MultiComboBox> = {
name: 'width',
args: {
width: '20rem',
},
}

export const DropdownHelpMessage: StoryObj<typeof MultiComboBox> = {
name: 'dropdownHelpMessage',
args: {
dropdownHelpMessage: 'ヘルプメッセージ',
},
}

export const DropdownWidth: StoryObj<typeof MultiComboBox> = {
name: 'dropdownWidth',
args: {
dropdownWidth: '30rem',
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/* eslint-disable smarthr/a11y-input-in-form-control */
import { Meta, StoryObj } from '@storybook/react'
import { userEvent, within } from '@storybook/test'
import React, { useState } from 'react'

import { Stack } from '../../../Layout'
import { ComboBoxItem } from '../../types'
import { MultiComboBox } from '../MultiComboBox'

import { defaultItems } from './MultiComboBox.stories'

/*
* pict multiComboBox.pict
* disabled error width selectedItems
* false true なし なし
* false false あり 複数
* true true あり 一つ
* false false なし 一つ
* true true なし 複数
* true false あり なし
*/

const _cases: Array<Omit<Parameters<typeof MultiComboBox>[0], 'items'>> = [
{ disabled: false, error: true, width: undefined, selectedItems: [] },
{
disabled: false,
error: false,
width: '15em',
selectedItems: [defaultItems['option 1'], defaultItems['option 4']],
},
{ disabled: true, error: true, width: '15em', selectedItems: [defaultItems['option 3']] },
{
disabled: false,
error: false,
width: undefined,
selectedItems: [defaultItems['アイテムのラベルがReactNodeの場合']],
},
{
disabled: true,
error: true,
width: undefined,
selectedItems: [
defaultItems['option 2'],
defaultItems[
'アイテムのラベルが長い場合(ダミーテキストダミーテキストダミーテキストダミーテキスト)'
],
],
},
{ disabled: true, error: false, width: '15em', selectedItems: [] },
]

const waitForRAF = () =>
new Promise<void>((resolve) => {
requestAnimationFrame(() => {
resolve()
})
})
const playMulti = async ({ canvasElement }: { canvasElement: HTMLElement }) => {
const canvas = within(canvasElement)
const comboboxes = await canvas.findAllByRole('combobox')
comboboxes[comboboxes.length - 1].focus()
const body = canvasElement.ownerDocument.body
const option1 = await within(body).findByRole('option', { name: 'option 1' })
await userEvent.click(option1)
await waitForRAF()
const option2 = await within(body).findByRole('option', { name: 'option 2' })
await userEvent.click(option2)
await waitForRAF()
const helpMessage = await within(body).findAllByText('入力でフィルタリングできます。')
await userEvent.click(helpMessage[0]) // カーソルの点滅によるVRTのフレーキーを避けるためにフォーカスを移動する
}

export default {
title: 'Forms(フォーム)/MultiComboBox/VRT',
component: MultiComboBox,
render: (args) => {
const items = Object.values(defaultItems)
const [selectedItems, setSelectedItems] = useState<Array<ComboBoxItem<unknown>>>([])
return (
<Stack align="flex-start" gap={2} className="shr-h-screen">
{_cases.map((props, i) => (
<MultiComboBox {...args} {...props} items={items} key={i} />
))}
<MultiComboBox
{...args}
name="default"
items={items}
dropdownHelpMessage="入力でフィルタリングできます。"
selectedItems={selectedItems}
onChangeSelected={(its) => setSelectedItems(its)}
/>
</Stack>
)
},
play: playMulti,
parameters: {
withTheming: true,
chromatic: { disableSnapshot: false },
},
tags: ['!autodocs', 'skip-test-runner'],
} as Meta<typeof MultiComboBox>

export const VRT: StoryObj<typeof MultiComboBox> = {}

export const VRTForcedColors: StoryObj<typeof MultiComboBox> = {
...VRT,
parameters: {
chromatic: { forcedColors: 'active' },
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
disabled: true, false
error: true, false
width: あり, なし
selectedItems: 一つ, 複数, なし
Loading
Loading