From e5976a05406d0431948e302d821a79db170dc664 Mon Sep 17 00:00:00 2001 From: KANAMORI Yu Date: Wed, 11 Sep 2024 14:33:29 +0900 Subject: [PATCH] =?UTF-8?q?chore:=20Revert=20"feat!:=20Combobox=20?= =?UTF-8?q?=E3=81=AE=20inputAttributes=20=E3=82=92=E6=B6=88=E3=81=97?= =?UTF-8?q?=E3=80=81input=20=E3=81=AB=E7=9B=B4=E6=8E=A5=E6=B8=A1=E3=81=99?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=E4=BF=AE=E6=AD=A3"=20(#4909)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/ComboBox/MultiComboBox.test.ts | 108 +++++++----------- .../ComboBox/SingleComboBox.test.ts | 61 ++++++---- .../src/components/ComboBox/MultiComboBox.tsx | 50 ++++++-- .../ComboBox/MultiCombobox.stories.tsx | 4 +- .../components/ComboBox/SingleComboBox.tsx | 55 ++++++--- .../ComboBox/SingleCombobox.stories.tsx | 4 +- .../components/FormControl/FormControl.tsx | 26 +++-- 7 files changed, 186 insertions(+), 122 deletions(-) diff --git a/packages/smarthr-ui/e2e/components/ComboBox/MultiComboBox.test.ts b/packages/smarthr-ui/e2e/components/ComboBox/MultiComboBox.test.ts index b7215e9a39..ba53ea3151 100644 --- a/packages/smarthr-ui/e2e/components/ComboBox/MultiComboBox.test.ts +++ b/packages/smarthr-ui/e2e/components/ComboBox/MultiComboBox.test.ts @@ -14,14 +14,15 @@ function elementWithId(id: string | null | undefined) { } test('アイテムの選択と選択解除ができること', async (t) => { - const combobox = Selector('[data-test=multi-combobox-default]') + const wrapper = Selector('[data-test=multi-combobox-default]') + const combobox = wrapper.find('input[role=combobox]') const comboboxControls = ((await combobox.getAttribute('aria-controls')) || '').split(' ') const listbox = elementWithId(comboboxControls[0]) const selectedItems = elementWithId(comboboxControls[1]) await t // コンボボックスをクリックするとテキストボックスがフォーカスされること - .click(combobox) + .click(wrapper) .expect(combobox.focused) .ok() // アイテムを選択できること @@ -45,13 +46,14 @@ test('アイテムの選択と選択解除ができること', async (t) => { }) test('リストボックスが開閉できること', async (t) => { - const combobox = Selector('[data-test=multi-combobox-default]') + const wrapper = Selector('[data-test=multi-combobox-default]') + const combobox = wrapper.find('input[role=combobox]') const comboboxControls = ((await combobox.getAttribute('aria-controls')) || '').split(' ') const listbox = elementWithId(comboboxControls[0]) await t // コンボボックスをクリックするとリストボックスが表示されること - .click(combobox) + .click(wrapper) .expect(listbox.visible) .ok() // 外側をクリックするとリストボックスが非表示になること @@ -59,13 +61,13 @@ test('リストボックスが開閉できること', async (t) => { .expect(listbox.visible) .notOk() // 再度リストボックスを開く - .click(combobox) + .click(wrapper) // リストボックス表示中に Escape キーを押下するとリストボックスが非表示になること .pressKey('esc') .expect(listbox.visible) .notOk() // 再度リストボックスを開く - .click(combobox) + .click(wrapper) // リストボックス表示中に Tab キーを押下するとリストボックスが非表示になること .pressKey('tab') .expect(listbox.visible) @@ -73,14 +75,15 @@ test('リストボックスが開閉できること', async (t) => { }) test('コンボボックスがフォーカスされていない時に選択解除ボタンを押下してもリストボックスが表示されないこと', async (t) => { - const combobox = Selector('[data-test=multi-combobox-default]') + const wrapper = Selector('[data-test=multi-combobox-default]') + const combobox = wrapper.find('input[role=combobox]') const comboboxControls = ((await combobox.getAttribute('aria-controls')) || '').split(' ') const listbox = elementWithId(comboboxControls[0]) const selectedItems = elementWithId(comboboxControls[1]) await t // アイテムを選択 - .click(combobox) + .click(wrapper) .click(listbox.find('.smarthr-ui-ComboBox-selectButton').withText('option 1')) // 外側をクリックしてフォーカスを外す .click('body', { offsetX: 0, offsetY: 0 }) @@ -91,7 +94,8 @@ test('コンボボックスがフォーカスされていない時に選択解 }) test('新しいアイテムを追加できること', async (t) => { - const combobox = Selector('[data-test=multi-combobox-creatable]') + const wrapper = Selector('[data-test=multi-combobox-creatable]') + const combobox = wrapper.find('input[role=combobox]') const comboboxControls = ((await combobox.getAttribute('aria-controls')) || '').split(' ') const listbox = elementWithId(comboboxControls[0]) const addButton = listbox.find('.smarthr-ui-ComboBox-addButton') @@ -99,7 +103,7 @@ test('新しいアイテムを追加できること', async (t) => { await t // 新しいアイテムを追加できること - .click(combobox) + .click(wrapper) .typeText(combobox, 'test new item') .click(addButton) .expect(selectedItems.withText('test new item').exists) @@ -109,25 +113,24 @@ test('新しいアイテムを追加できること', async (t) => { .expect(selectedItems.withText('test new item').exists) .notOk() // 新しく追加したアイテムがリストボックス内に存在すること - .click(combobox) + .click(wrapper) .expect(listbox.find('.smarthr-ui-ComboBox-selectButton').withText('test new item').exists) .ok() }) test('deletable でないコンボボックスアイテムは削除できないこと', async (t) => { - const combobox = Selector('[data-test=multi-combobox-undeletable]') + const wrapper = Selector('[data-test=multi-combobox-undeletable]') + const combobox = wrapper.find('input[role=combobox]') const comboboxControls = ((await combobox.getAttribute('aria-controls')) || '').split(' ') const listbox = elementWithId(comboboxControls[0]) await t // アイテムを選択 - .click(combobox) + .click(wrapper) .click(listbox.find('.smarthr-ui-ComboBox-selectButton').withText('option 1')) // 削除ボタンが表示されていない .expect( - combobox - .parent(0) - .sibling() + wrapper .find('.smarthr-ui-MultiComboBox-selectedItem') .withText('option 1') .find('.smarthr-ui-MultiComboBox-deleteButton').exists, @@ -135,35 +138,33 @@ test('deletable でないコンボボックスアイテムは削除できない .notOk() // Backspace キーで削除できないこと .pressKey('backspace') - .expect( - combobox - .parent(0) - .sibling() - .find('.smarthr-ui-MultiComboBox-selectedItem') - .withText('option 1').exists, - ) + .expect(wrapper.find('.smarthr-ui-MultiComboBox-selectedItem').withText('option 1').exists) .ok() }) test('disabled なコンボボックスではアイテムの選択と選択解除ができないこと', async (t) => { - const normalCombobox = Selector('[data-test=multi-combobox-default]') + const normal = Selector('[data-test=multi-combobox-default]') + const normalCombobox = normal.find('input[role=combobox]') const normalComboboxControls = ((await normalCombobox.getAttribute('aria-controls')) || '').split( ' ', ) const normalListbox = elementWithId(normalComboboxControls[0]) - const disabledCombobox = Selector('[data-test=multi-combobox-disabled]') + const disabled = Selector('[data-test=multi-combobox-disabled]') + const disabledCombobox = disabled.find('input[role=combobox]') const disabledComboboxControls = ( (await disabledCombobox.getAttribute('aria-controls')) || '' ).split(' ') + const disabledListbox = elementWithId(disabledComboboxControls[0]) const disabledSelectedItems = elementWithId(disabledComboboxControls[1]) await t - // disabled なコンボボックスが不可視であること - .expect(disabledCombobox.visible) + // disabled なコンボボックスをクリックしてもリストボックスは表示されないこと + .click(disabled) + .expect(disabledListbox.visible) .notOk() // 有効なコンボボックスでアイテム選択 - .click(normalCombobox) + .click(normal) .click(normalListbox.find('.smarthr-ui-ComboBox-selectButton').withText('option 1')) // disabled なコンボボックスの選択済みアイテムの削除ボタンが disabled であること .expect( @@ -176,23 +177,22 @@ test('disabled なコンボボックスではアイテムの選択と選択解 }) test('キーボードで選択済みアイテムリストが操作できること', async (t) => { - const combobox = Selector('[data-test=multi-combobox-default]') + const wrapper = Selector('[data-test=multi-combobox-default]') + const combobox = wrapper.find('input[role=combobox]') const comboboxControls = ((await combobox.getAttribute('aria-controls')) || '').split(' ') const listbox = elementWithId(comboboxControls[0]) const findOption = (label: string) => listbox.find('.smarthr-ui-ComboBox-selectButton').withText(label) const findDeleteButton = (label: string) => - combobox - .parent(0) - .sibling() + wrapper .find('.smarthr-ui-MultiComboBox-selectedItem') .withText(label) .find('.smarthr-ui-MultiComboBox-deleteButton') await t // アイテムを選択 - .click(combobox) + .click(wrapper) .click(findOption('option 1')) .click(findOption('option 2')) .click(findOption('option 5')) @@ -235,53 +235,32 @@ test('キーボードで選択済みアイテムリストが操作できるこ // 削除ボタンを操作できること .pressKey('left') .pressKey('enter') - .expect( - combobox - .parent(0) - .sibling() - .find('.smarthr-ui-MultiComboBox-selectedItem') - .withText('option 6').exists, - ) + .expect(wrapper.find('.smarthr-ui-MultiComboBox-selectedItem').withText('option 5').exists) .notOk() .pressKey('left') .pressKey('backspace') - .expect( - combobox - .parent(0) - .sibling() - .find('.smarthr-ui-MultiComboBox-selectedItem') - .withText('option 3').exists, - ) + .expect(wrapper.find('.smarthr-ui-MultiComboBox-selectedItem').withText('option 2').exists) .notOk() // テキストボックスにフォーカスがあたってる場合は Backspace で末尾のアイテムを削除できること .pressKey('backspace') - .expect( - combobox - .parent(0) - .sibling() - .find('.smarthr-ui-MultiComboBoxyy-selectedItem') - .withText('option 2').exists, - ) + .expect(wrapper.find('.smarthr-ui-MultiComboBoxyy-selectedItem').withText('option 1').exists) .notOk() // Backspace によって削除した末尾アイテムはテキスト化されるが、選択状態になっているので再度 Backspace でテキストも削除できること - .expect(combobox.value) + .expect(wrapper.find('.smarthr-ui-MultiComboBox-input').value) .eql('option 1') .pressKey('backspace') - .expect(combobox.value) + .expect(wrapper.find('.smarthr-ui-MultiComboBox-input').value) .eql('') }) test('キーボードでリストボックスが操作できること', async (t) => { - const combobox = Selector('[data-test=multi-combobox-default]') - const comboBoxSelected = combobox - .parent(0) - .sibling() - .find('.smarthr-ui-MultiComboBox-selectedItem') + const wrapper = Selector('[data-test=multi-combobox-default]') + const comboBoxSelected = wrapper.find('.smarthr-ui-MultiComboBox-selectedItem') await t // タブキーでフォーカスされたとき、テキストボックスがフォーカスされること .pressKey('tab') - .expect(combobox.focused) + .expect(wrapper.find('.smarthr-ui-MultiComboBox-input').focused) .ok() // アイテムが選択できること .pressKey('down') @@ -304,12 +283,13 @@ test('キーボードでリストボックスが操作できること', async (t }) test('部分的レンダリングしているアイテム数がスクロールにより順次増加すること', async (t) => { - const combobox = Selector('[data-test=multi-combobox-many]') + const wrapper = Selector('[data-test=multi-combobox-many]') + const combobox = wrapper.find('input[role=combobox]') const comboboxControls = ((await combobox.getAttribute('aria-controls')) || '').split(' ') const listbox = elementWithId(comboboxControls[0]) await t - .click(combobox) + .click(wrapper) .expect(listbox.find('.smarthr-ui-ComboBox-selectButton').count) .eql(100) .scroll(listbox, 'bottom') diff --git a/packages/smarthr-ui/e2e/components/ComboBox/SingleComboBox.test.ts b/packages/smarthr-ui/e2e/components/ComboBox/SingleComboBox.test.ts index efb2a73ec3..d9fc24cc3f 100644 --- a/packages/smarthr-ui/e2e/components/ComboBox/SingleComboBox.test.ts +++ b/packages/smarthr-ui/e2e/components/ComboBox/SingleComboBox.test.ts @@ -15,30 +15,32 @@ function elementWithId(id: string | null | undefined) { test('アイテムの選択と選択解除ができること', async (t) => { const combobox = Selector('[data-test=single-combobox-default]') - const listbox = elementWithId(await combobox.getAttribute('aria-controls')) - const clearButton = combobox.sibling().find('.smarthr-ui-SingleComboBox-clearButton') + const textbox = combobox.find('input[type=text]') + const listbox = elementWithId(await textbox.getAttribute('aria-controls')) + const clearButton = combobox.find('.smarthr-ui-SingleComboBox-clearButton') await t // コンボボックスをクリックするとテキストボックスがフォーカスされること .click(combobox) - .expect(combobox.focused) + .expect(textbox.focused) .ok() // アイテムを選択できること .click(listbox.find('.smarthr-ui-ComboBox-selectButton').withText('option 1')) - .expect(combobox.value) + .expect(textbox.value) .eql('option 1') // リストボックスが非表示になること .expect(listbox.visible) .notOk() // 選択したアイテムを選択解除できること .click(clearButton) - .expect(combobox.value) + .expect(textbox.value) .eql('') }) test('リストボックスが開閉できること', async (t) => { const combobox = Selector('[data-test=single-combobox-default]') - const listbox = elementWithId(await combobox.getAttribute('aria-controls')) + const textbox = combobox.find('input[type=text]') + const listbox = elementWithId(await textbox.getAttribute('aria-controls')) await t // コンボボックスをクリックするとリストボックスが表示されること @@ -65,8 +67,9 @@ test('リストボックスが開閉できること', async (t) => { test('コンボボックスがフォーカスされていない時に選択解除ボタンを押下してもリストボックスが表示されること', async (t) => { const combobox = Selector('[data-test=single-combobox-default]') - const listbox = elementWithId(await combobox.getAttribute('aria-controls')) - const clearButton = combobox.sibling().find('.smarthr-ui-SingleComboBox-clearButton') + const textbox = combobox.find('input[type=text]') + const listbox = elementWithId(await textbox.getAttribute('aria-controls')) + const clearButton = combobox.find('.smarthr-ui-SingleComboBox-clearButton') await t // アイテムを選択 @@ -82,20 +85,21 @@ test('コンボボックスがフォーカスされていない時に選択解 test('新しいアイテムを追加できること', async (t) => { const combobox = Selector('[data-test=single-combobox-creatable]') - const listbox = elementWithId(await combobox.getAttribute('aria-controls')) + const textbox = combobox.find('input[type=text]') + const listbox = elementWithId(await textbox.getAttribute('aria-controls')) const addButton = listbox.find('.smarthr-ui-ComboBox-addButton') - const clearButton = combobox.sibling().find('.smarthr-ui-SingleComboBox-clearButton') + const clearButton = combobox.find('.smarthr-ui-SingleComboBox-clearButton') await t // 新しいアイテムを追加できること .click(combobox) - .typeText(combobox, 'test new item') + .typeText(textbox, 'test new item') .click(addButton) - .expect(combobox.value) + .expect(textbox.value) .eql('test new item') // 選択したアイテムを選択解除できること .click(clearButton) - .expect(combobox.value) + .expect(textbox.value) .eql('') // 新しく追加したアイテムがリストボックス内に存在すること .click(combobox) @@ -104,45 +108,54 @@ test('新しいアイテムを追加できること', async (t) => { }) test('disabled なコンボボックスではアイテムの選択と選択解除ができないこと', async (t) => { - const normalCombobox = Selector('[data-test=single-combobox-default]') - const normalListbox = elementWithId(await normalCombobox.getAttribute('aria-controls')) - const disabledCombobox = Selector('[data-test=single-combobox-disabled]') - const disabledListbox = elementWithId(await disabledCombobox.getAttribute('aria-controls')) + const normal = Selector('[data-test=single-combobox-default]') + const normalTextbox = normal.find('input[type=text]') + const normalListbox = elementWithId(await normalTextbox.getAttribute('aria-controls')) + const disabled = Selector('[data-test=single-combobox-disabled]') + const disabledTextBox = disabled.find('input[type=text]') + const disabledListbox = elementWithId(await disabledTextBox.getAttribute('aria-controls')) await t // disabled なコンボボックスをクリックしてもリストボックスは表示されないこと - .click(disabledCombobox) + .click(disabled) .expect(disabledListbox.visible) .notOk() // 有効なコンボボックスでアイテム選択 - .click(normalCombobox) + .click(normal) .click(normalListbox.find('.smarthr-ui-ComboBox-selectButton').withText('option 1')) // disabled なコンボボックスにクリアボタンが表示されないこと - .expect(disabledCombobox.sibling().find('.smarthr-ui-SingleComboBox-clearButton').visible) + .expect(disabled.find('.smarthr-ui-SingleComboBox-clearButton').visible) .notOk() }) test('キーボードで操作できること', async (t) => { const combobox = Selector('[data-test=single-combobox-default]') + const comboboxInput = combobox.find('.smarthr-ui-Input-input') await t .pressKey('tab') - .expect(combobox.focused) + .expect(comboboxInput.focused) .ok() .pressKey('down') .pressKey('enter') - .expect(combobox.value) + .expect(comboboxInput.value) .eql('option 1') .pressKey('up') .pressKey('up') .pressKey('up') .pressKey('enter') - .expect(combobox.value) + .expect(comboboxInput.value) .eql('option 5') }) test('キーボードで操作しても親要素のformがsubmitされないこと', async (t) => { const combobox = Selector('[data-test=single-combobox-no-form-submit]') + const comboboxInput = combobox.find('.smarthr-ui-Input-input') - await t.pressKey('tab').pressKey('down').pressKey('enter').expect(combobox.value).eql('option 1') + await t + .pressKey('tab') + .pressKey('down') + .pressKey('enter') + .expect(comboboxInput.value) + .eql('option 1') }) diff --git a/packages/smarthr-ui/src/components/ComboBox/MultiComboBox.tsx b/packages/smarthr-ui/src/components/ComboBox/MultiComboBox.tsx index 867f8fc7b3..b1e188c3f6 100644 --- a/packages/smarthr-ui/src/components/ComboBox/MultiComboBox.tsx +++ b/packages/smarthr-ui/src/components/ComboBox/MultiComboBox.tsx @@ -1,7 +1,8 @@ import React, { - type ComponentPropsWithoutRef, - type KeyboardEvent, - type Ref, + ComponentPropsWithoutRef, + InputHTMLAttributes, + KeyboardEvent, + Ref, useCallback, useEffect, useImperativeHandle, @@ -20,11 +21,11 @@ import { FaCaretDownIcon } from '../Icon' import { MultiSelectedItem } from './MultiSelectedItem' import { hasParentElementByClassName } from './multiComboBoxHelper' +import { BaseProps, ComboBoxItem } from './types' import { useFocusControl } from './useFocusControl' import { useListBox } from './useListBox' import { useOptions } from './useOptions' -import type { BaseProps, ComboBoxItem } from './types' import type { DecoratorsType } from '../../types' type Props = BaseProps & { @@ -68,9 +69,37 @@ type Props = BaseProps & { * アイテムが選択されたときに選択済みかどうかを判定するコールバック関数/ */ isItemSelected?: (targetItem: ComboBoxItem, selectedItems: Array>) => boolean + + /** + * input 要素の属性 + */ + inputAttributes?: Omit< + InputHTMLAttributes, + | 'name' + | 'disabled' + | 'required' + | 'type' + | 'aria-activedescendant' + | 'aria-autocomplete' + | 'aria-controls' + | 'aria-disabled' + | 'aria-expanded' + | 'aria-haspopup' + | 'aria-invalid' + | 'className' + | 'onChange' + | 'onCompositionEnd' + | 'onCompositionStart' + | 'onFocus' + | 'onKeyDown' + | 'ref' + | 'role' + | 'tabIndex' + | 'value' + > } -type ElementProps = Omit, keyof Props> +type ElementProps = Omit, keyof Props> const SELECTED_LIST_ARIA_LABEL = '選択済みアイテム' @@ -144,7 +173,6 @@ const ActualMultiComboBox = ( error = false, creatable = false, placeholder = '', - autoComplete, dropdownHelpMessage, isLoading, selectedItemEllipsis, @@ -163,8 +191,9 @@ const ActualMultiComboBox = ( onKeyPress, decorators, isItemSelected, + inputAttributes, style, - ...rest + ...props }: Props & ElementProps, ref: Ref, ) => { @@ -387,7 +416,7 @@ const ActualMultiComboBox = ( // アイテムをキーボードで選択し、Enterを押すとinput上でEnterを押したことになるため、 // submitイベントが発生し、formが送信される場合がある const handleKeyPress = useCallback( - (e: React.KeyboardEvent) => { + (e: React.KeyboardEvent) => { e.key === 'Enter' && e.preventDefault() onKeyPress && onKeyPress(e) }, @@ -452,6 +481,7 @@ const ActualMultiComboBox = ( return (
(
( onCompositionStart={handleCompositionStartInput} onCompositionEnd={handleCompositionEndInput} onKeyDown={handleInputKeyDown} - autoComplete={autoComplete ?? 'off'} + autoComplete={inputAttributes?.autoComplete ?? 'off'} tabIndex={0} role="combobox" aria-activedescendant={activeOption?.id} diff --git a/packages/smarthr-ui/src/components/ComboBox/MultiCombobox.stories.tsx b/packages/smarthr-ui/src/components/ComboBox/MultiCombobox.stories.tsx index a102fe3493..0b65c0666f 100644 --- a/packages/smarthr-ui/src/components/ComboBox/MultiCombobox.stories.tsx +++ b/packages/smarthr-ui/src/components/ComboBox/MultiCombobox.stories.tsx @@ -164,7 +164,9 @@ export const MultiCombobox: StoryFn = () => { name="inputAttributes" items={items} selectedItems={selectedItems} - aria-label="inputAttributes" + inputAttributes={{ + 'aria-label': 'inputAttributes', + }} onDelete={handleDelete} onSelect={handleSelectItem} data-test="multi-combobox-disabled" diff --git a/packages/smarthr-ui/src/components/ComboBox/SingleComboBox.tsx b/packages/smarthr-ui/src/components/ComboBox/SingleComboBox.tsx index 7e8a82e3fd..de2a01074b 100644 --- a/packages/smarthr-ui/src/components/ComboBox/SingleComboBox.tsx +++ b/packages/smarthr-ui/src/components/ComboBox/SingleComboBox.tsx @@ -1,9 +1,9 @@ import React, { - type ChangeEvent, - type ComponentPropsWithoutRef, - type MouseEvent, - type ReactNode, - type Ref, + ChangeEvent, + ComponentPropsWithoutRef, + MouseEvent, + ReactNode, + Ref, useCallback, useEffect, useImperativeHandle, @@ -18,13 +18,13 @@ import { useClick } from '../../hooks/useClick' import { useTheme } from '../../hooks/useTailwindTheme' import { genericsForwardRef } from '../../libs/util' import { UnstyledButton } from '../Button' -import { FaCaretDownIcon, FaCircleXmarkIcon } from '../Icon' +import { FaCaretDownIcon, FaTimesCircleIcon } from '../Icon' import { Input } from '../Input' +import { BaseProps, ComboBoxItem } from './types' import { useListBox } from './useListBox' import { useOptions } from './useOptions' -import type { BaseProps, ComboBoxItem } from './types' import type { DecoratorsType } from '../../types' type Props = BaseProps & { @@ -67,9 +67,34 @@ type Props = BaseProps & { decorators?: DecoratorsType<'noResultText'> & { destroyButtonIconAlt?: (text: string) => string } + /** + * input 要素の属性 + */ + inputAttributes?: Omit< + React.ComponentProps, + | 'aria-activedescendant' + | 'aria-autocomplete' + | 'className' + | 'disabled' + | 'required' + | 'error' + | 'name' + | 'onChange' + | 'onClick' + | 'onCompositionEnd' + | 'onCompositionStart' + | 'onFocus' + | 'onKeyDown' + | 'placeholder' + | 'prefix' + | 'ref' + | 'suffix' + | 'type' + | 'value' + > } -type ElementProps = Omit, keyof Props> +type ElementProps = Omit, keyof Props> const DESTROY_BUTTON_TEXT = '削除' @@ -120,7 +145,6 @@ const ActualSingleComboBox = ( error = false, creatable = false, placeholder = '', - autoComplete, dropdownHelpMessage, isLoading, width, @@ -137,8 +161,9 @@ const ActualSingleComboBox = ( onBlur, onKeyPress, decorators, + inputAttributes, style, - ...rest + ...props }: Props & ElementProps, ref: Ref, ) => { @@ -305,7 +330,7 @@ const ActualSingleComboBox = ( // アイテムをキーボードで選択し、Enterを押すとinput上でEnterを押したことになるため、 // submitイベントが発生し、formが送信される場合がある const handleKeyPress = useCallback( - (e: React.KeyboardEvent) => { + (e: React.KeyboardEvent) => { e.key === 'Enter' && e.preventDefault() onKeyPress && onKeyPress(e) }, @@ -386,9 +411,9 @@ const ActualSingleComboBox = ( ]) return ( -
+
( ref={clearButtonRef} className={clearButtonStyle} > - ( onKeyDown={onKeyDownInput} onKeyPress={handleKeyPress} ref={inputRef} - autoComplete={autoComplete ?? 'off'} + autoComplete={inputAttributes?.autoComplete ?? 'off'} role="combobox" aria-haspopup="listbox" aria-controls={listBoxId} diff --git a/packages/smarthr-ui/src/components/ComboBox/SingleCombobox.stories.tsx b/packages/smarthr-ui/src/components/ComboBox/SingleCombobox.stories.tsx index 4595ff3c99..0383ef7890 100644 --- a/packages/smarthr-ui/src/components/ComboBox/SingleCombobox.stories.tsx +++ b/packages/smarthr-ui/src/components/ComboBox/SingleCombobox.stories.tsx @@ -169,10 +169,12 @@ export const SingleCombobox: StoryFn = () => { name="inputAttributes" items={items} selectedItem={selectedItem} + inputAttributes={{ + 'aria-label': 'inputAttributes', + }} onSelect={handleSelectItem} onClear={handleClear} data-test="single-combobox-disabled" - aria-label="inputAttributes" /> diff --git a/packages/smarthr-ui/src/components/FormControl/FormControl.tsx b/packages/smarthr-ui/src/components/FormControl/FormControl.tsx index 84d4fb121e..6aa23b42ab 100644 --- a/packages/smarthr-ui/src/components/FormControl/FormControl.tsx +++ b/packages/smarthr-ui/src/components/FormControl/FormControl.tsx @@ -1,9 +1,9 @@ import React, { - type ComponentProps, - type ComponentPropsWithoutRef, - type PropsWithChildren, - type ReactElement, - type ReactNode, + ComponentProps, + ComponentPropsWithoutRef, + PropsWithChildren, + ReactElement, + ReactNode, useMemo, } from 'react' import { isStyledComponent } from 'styled-components' @@ -25,7 +25,6 @@ import { TimePicker } from '../TimePicker' import { visuallyHiddenText } from '../VisuallyHiddenText/VisuallyHiddenText' import type { Gap } from '../../types' - type StatusLabelProps = ComponentProps type Props = PropsWithChildren<{ @@ -291,7 +290,11 @@ const decorateFirstInputElement = ( inputAttributes['aria-describedby'] = describedbyIds } - return React.cloneElement(child, inputAttributes) + if (isComboBoxElement(child)) { + return React.cloneElement(child, { inputAttributes }) + } else { + return React.cloneElement(child, inputAttributes) + } }) return decorate(children) @@ -335,5 +338,14 @@ const isInputElement = ( ) } +type ComboboxComponent = typeof SingleComboBox | typeof MultiComboBox + +const isComboBoxElement = ( + element: ReactElement, +): element is React.ReactComponentElement => { + const type = isStyledComponent(element.type) ? element.type.target : element.type + return type === SingleComboBox || type === MultiComboBox +} + export const FormControl: React.FC> = ActualFormControl