@moneyforward/mfui-components 3.30.0 → 3.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/src/Breadcrumbs/Breadcrumbs.d.ts +1 -0
  2. package/dist/src/Breadcrumbs/Breadcrumbs.js +2 -2
  3. package/dist/src/Breadcrumbs/Breadcrumbs.types.d.ts +7 -0
  4. package/dist/src/DataTable/DataTable.js +2 -2
  5. package/dist/src/DataTable/DataTable.types.d.ts +9 -0
  6. package/dist/src/DataTable/DataTableCell/DataTableCell.js +2 -1
  7. package/dist/src/DataTable/DataTableHeaderCell/DataTableHeaderCell.js +2 -1
  8. package/dist/src/DataTable/DataTableProvider.d.ts +2 -2
  9. package/dist/src/DataTable/DataTableProvider.js +4 -1
  10. package/dist/src/DataTable/DataTableRow/DataTableRow.js +34 -3
  11. package/dist/src/DateTimeSelection/shared/BasePicker/constants.d.ts +1 -1
  12. package/dist/src/DateTimeSelection/shared/BasePicker/constants.js +2 -0
  13. package/dist/src/DateTimeSelection/shared/YearSelector/YearSelector.js +7 -1
  14. package/dist/src/DropdownMenu/DropdownMenu.js +26 -2
  15. package/dist/src/DropdownMenu/DropdownMenuButtonTrigger.d.ts +2 -2
  16. package/dist/src/DropdownMenu/DropdownMenuContainer/DropdownMenuContainer.js +28 -3
  17. package/dist/src/DropdownMenu/DropdownMenuContainer/DropdownMenuContainer.types.d.ts +5 -2
  18. package/dist/src/DropdownMenu/DropdownMenuItem/DropdownMenuItem.d.ts +1 -1
  19. package/dist/src/DropdownMenu/DropdownMenuItem/DropdownMenuItem.js +18 -3
  20. package/dist/src/DropdownMenu/DropdownMenuItem/DropdownMenuItem.types.d.ts +6 -0
  21. package/dist/src/MainNavigation/BaseMainNavigation.d.ts +1 -1
  22. package/dist/src/MainNavigation/BaseMainNavigation.js +4 -2
  23. package/dist/src/MainNavigation/MainNavigation.js +2 -2
  24. package/dist/src/MainNavigation/MainNavigation.types.d.ts +18 -0
  25. package/dist/src/NumberBox/NumberBox.js +68 -21
  26. package/dist/src/SearchBox/SearchBox.js +18 -4
  27. package/dist/src/SidePane/SidePane.d.ts +3 -1
  28. package/dist/src/SidePane/SidePane.js +8 -4
  29. package/dist/src/SidePane/hooks/useSidePaneStateController.d.ts +7 -2
  30. package/dist/src/SidePane/hooks/useSidePaneStateController.js +11 -5
  31. package/dist/src/Tag/Tag.d.ts +1 -1
  32. package/dist/src/Tag/Tag.js +2 -2
  33. package/dist/src/Tag/Tag.types.d.ts +7 -0
  34. package/dist/src/Tooltip/hooks/usePopoverController.js +29 -14
  35. package/dist/styled-system/recipes/data-table-cell-slot-recipe.d.ts +1 -0
  36. package/dist/styled-system/recipes/data-table-cell-slot-recipe.js +4 -0
  37. package/dist/styled-system/recipes/data-table-header-cell-slot-recipe.d.ts +1 -0
  38. package/dist/styled-system/recipes/data-table-header-cell-slot-recipe.js +4 -0
  39. package/dist/styled-system/recipes/dropdown-menu-item-slot-recipe.d.ts +1 -1
  40. package/dist/styled-system/recipes/dropdown-menu-item-slot-recipe.js +12 -0
  41. package/dist/styles.css +76 -12
  42. package/package.json +2 -2
@@ -10,4 +10,5 @@ export declare const Breadcrumbs: import("react").ForwardRefExoticComponent<{
10
10
  items: import("./Breadcrumbs.types").BreadcrumbItem[];
11
11
  wrap?: boolean;
12
12
  customLinkComponent?: import("react").ElementType;
13
+ truncateButtonProps?: Pick<import("react").ComponentPropsWithoutRef<'button'>, 'aria-label'>;
13
14
  } & Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & import("react").RefAttributes<HTMLElement>>;
@@ -30,7 +30,7 @@ function Separator({ className }) {
30
30
  * when it has no `href`. If the last item has an `href`, it is rendered as a link and the
31
31
  * trail has no current-page item.
32
32
  */
33
- export const Breadcrumbs = forwardRef(({ items, wrap = false, customLinkComponent, className, 'aria-label': ariaLabel = '現在のページ位置', ...rest }, ref) => {
33
+ export const Breadcrumbs = forwardRef(({ items, wrap = false, customLinkComponent, className, 'aria-label': ariaLabel = '現在のページ位置', truncateButtonProps, ...rest }, ref) => {
34
34
  const classes = breadcrumbsSlotRecipe({ wrap });
35
35
  // Decompose items into logical groups:
36
36
  // - rootItem: items[0] (always shown, link)
@@ -159,7 +159,7 @@ export const Breadcrumbs = forwardRef(({ items, wrap = false, customLinkComponen
159
159
  setCurrentTruncated(!!(currentElement && currentElement.scrollWidth > currentElement.clientWidth));
160
160
  }, [containerWidth, collapsedCount, wrap]);
161
161
  const truncatedItems = middleItems.slice(0, collapsedCount);
162
- return (_jsx("nav", { ref: ref, className: cx(classes.root, className), "aria-label": ariaLabel, ...rest, children: _jsxs("ol", { ref: listRef, className: classes.list, "data-mfui-all-collapsed": allCollapsed ? true : undefined, children: [rootItem ? (_jsxs("li", { ref: rootItemLiRef, className: classes.item, style: allCollapsed && rootMinWidth !== undefined ? { minWidth: rootMinWidth } : undefined, children: [_jsx(Tooltip, { hideFromScreenReader: true, content: rootItem.label, disabled: !rootTruncated, placement: "bottom", style: TOOLTIP_TRIGGER_STYLE, children: _jsx(TextLink, { ref: rootLinkRef, href: rootItem.href, variant: "condensedBody", customLinkComponent: customLinkComponent, className: classes.linkText, children: rootItem.label }) }), _jsx(Separator, { className: classes.separator })] })) : null, collapsedCount > 0 ? (_jsxs("li", { className: classes.truncateItem, children: [_jsx(DropdownMenu, { label: "\u7701\u7565\u3055\u308C\u305F\u30A2\u30A4\u30C6\u30E0\u3092\u8868\u793A", icon: _jsx(MoreHorizontal, {}), triggerProps: {
162
+ return (_jsx("nav", { ref: ref, className: cx(classes.root, className), "aria-label": ariaLabel, ...rest, children: _jsxs("ol", { ref: listRef, className: classes.list, "data-mfui-all-collapsed": allCollapsed ? true : undefined, children: [rootItem ? (_jsxs("li", { ref: rootItemLiRef, className: classes.item, style: allCollapsed && rootMinWidth !== undefined ? { minWidth: rootMinWidth } : undefined, children: [_jsx(Tooltip, { hideFromScreenReader: true, content: rootItem.label, disabled: !rootTruncated, placement: "bottom", style: TOOLTIP_TRIGGER_STYLE, children: _jsx(TextLink, { ref: rootLinkRef, href: rootItem.href, variant: "condensedBody", customLinkComponent: customLinkComponent, className: classes.linkText, children: rootItem.label }) }), _jsx(Separator, { className: classes.separator })] })) : null, collapsedCount > 0 ? (_jsxs("li", { className: classes.truncateItem, children: [_jsx(DropdownMenu, { label: truncateButtonProps?.['aria-label'] ?? '省略されたアイテムを表示', icon: _jsx(MoreHorizontal, {}), triggerProps: {
163
163
  className: classes.truncateButton,
164
164
  }, children: truncatedItems.map((item, i) => item.href !== undefined ? (_jsx(DropdownMenu.Item, { href: item.href, customLinkComponent: customLinkComponent, children: item.label }, i)) : (_jsx(DropdownMenu.Item, { children: item.label }, i))) }), _jsx(Separator, { className: classes.separator })] })) : null, middleItems.map((item, i) => (_jsxs("li", { className: classes.item, style: i < collapsedCount ? { display: 'none' } : undefined, children: [_jsx(TextLink, { href: item.href, variant: "condensedBody", customLinkComponent: customLinkComponent, className: classes.linkText, children: item.label }), _jsx(Separator, { className: classes.separator })] }, i))), parentItem ? (_jsxs("li", { ref: parentItemLiRef, className: classes.item, style: allCollapsed && parentMinWidth !== undefined ? { minWidth: parentMinWidth } : undefined, children: [_jsx(Tooltip, { hideFromScreenReader: true, content: parentItem.label, disabled: !parentTruncated, placement: "bottom", style: TOOLTIP_TRIGGER_STYLE, children: _jsx(TextLink, { ref: parentLinkRef, href: parentItem.href, variant: "condensedBody", customLinkComponent: customLinkComponent, className: classes.linkText, children: parentItem.label }) }), _jsx(Separator, { className: classes.separator })] })) : null, currentItem ? (_jsx("li", { ref: currentItemLiRef, className: classes.item, "aria-current": lastItemIsCurrentPage ? 'page' : undefined, style: allCollapsed && currentMinWidth !== undefined ? { minWidth: currentMinWidth } : undefined, children: _jsx(Tooltip, { hideFromScreenReader: true, content: currentItem.label, disabled: !currentTruncated, placement: "bottom", style: TOOLTIP_TRIGGER_STYLE, children: lastItemIsCurrentPage ? (_jsx("span", { ref: currentItemRef, className: classes.currentItem, children: currentItem.label })) : (_jsx(TextLink, { ref: currentLinkRef, href: currentItem.href, variant: "condensedBody", customLinkComponent: customLinkComponent, className: classes.linkText, children: currentItem.label })) }) })) : null] }) }));
165
165
  });
@@ -32,4 +32,11 @@ export type BreadcrumbsProps = {
32
32
  * Also applied to truncated items in the DropdownMenu.
33
33
  */
34
34
  customLinkComponent?: ElementType;
35
+ /**
36
+ * The properties for the "…" button that opens the menu of truncated items.
37
+ * If this prop is not passed, the default values for each property will be applied.
38
+ *
39
+ * @property aria-label - The alternative text for the button. Override this to localize the label. default is '省略されたアイテムを表示'.
40
+ */
41
+ truncateButtonProps?: Pick<ComponentPropsWithoutRef<'button'>, 'aria-label'>;
35
42
  } & ComponentPropsWithoutRef<'nav'>;
@@ -11,7 +11,7 @@ import { DataTableHeaderRow } from './DataTableHeaderRow';
11
11
  import { DataTableRow } from './DataTableRow';
12
12
  import { cx } from '../../styled-system/css';
13
13
  import { isComponentOrWrapped } from '../utilities/react/isComponentOrWrapped';
14
- const Base = forwardRef(({ className, size = 'medium', enableRowSelection = false, fixedHeader = false, leftFixedColumnIndex, rightFixedColumnIndex, layout = 'default', wrapperProps, loading = false, emptyStateSlot, children, ...props }, ref) => {
14
+ const Base = forwardRef(({ className, size = 'medium', enableRowSelection = false, fixedHeader = false, showVerticalBorder = false, leftFixedColumnIndex, rightFixedColumnIndex, layout = 'default', wrapperProps, loading = false, emptyStateSlot, children, ...props }, ref) => {
15
15
  const classes = dataTableSlotRecipe({ layout });
16
16
  // Check if DataTable has any rows by looking for DataTable.Body with DataTable.Row children
17
17
  const hasRows = useMemo(() => {
@@ -36,7 +36,7 @@ const Base = forwardRef(({ className, size = 'medium', enableRowSelection = fals
36
36
  return false;
37
37
  }, [children, loading]);
38
38
  const shouldShowEmptyState = !hasRows && !!emptyStateSlot && !loading;
39
- return (_jsx(DataTableProvider, { size: size, enableRowSelection: enableRowSelection, fixedHeader: fixedHeader, leftFixedColumnIndex: leftFixedColumnIndex, rightFixedColumnIndex: rightFixedColumnIndex, loading: loading, layout: layout, children: _jsxs("div", { ...wrapperProps, className: cx(classes.wrapper, 'mfui-DataTable__wrapper',
39
+ return (_jsx(DataTableProvider, { size: size, enableRowSelection: enableRowSelection, fixedHeader: fixedHeader, showVerticalBorder: showVerticalBorder, leftFixedColumnIndex: leftFixedColumnIndex, rightFixedColumnIndex: rightFixedColumnIndex, loading: loading, layout: layout, children: _jsxs("div", { ...wrapperProps, className: cx(classes.wrapper, 'mfui-DataTable__wrapper',
40
40
  /* TODO: Remove in v5.0.0 */ 'mfui-DataGrid__wrapper', wrapperProps?.className), children: [_jsx("table", { ref: ref, className: cx(classes.table, 'mfui-DataTable__table',
41
41
  /* TODO: Remove in v5.0.0 */ 'mfui-DataGrid__table', className), ...props, children: children }), shouldShowEmptyState ? (_jsx("div", { className: cx(classes.emptyState, 'mfui-DataTable__emptyState',
42
42
  /* TODO: Remove in v5.0.0 */ 'mfui-DataGrid__emptyState'), role: "status", "aria-live": "polite", children: emptyStateSlot })) : null] }) }));
@@ -38,6 +38,15 @@ export type DataTableProps = {
38
38
  * @default false
39
39
  */
40
40
  fixedHeader?: boolean;
41
+ /**
42
+ * Whether to show vertical borders between columns.
43
+ * If `true`, a vertical border will be drawn between each column of the header and body.
44
+ *
45
+ * Enable this when using `colSpan` / `rowSpan` on cells to clarify the cell boundaries.
46
+ *
47
+ * @default false
48
+ */
49
+ showVerticalBorder?: boolean;
41
50
  /**
42
51
  * The layout of the data table.
43
52
  * It accepts `default` or `edge-to-edge`.
@@ -11,7 +11,7 @@ import { useFixedColumns } from '../../utilities/dom/useFixedColumns';
11
11
  import { handleCheckboxCellClick } from '../utils/handleCheckbox';
12
12
  import { mergeRefs } from '../../utilities/dom/mergeRefs';
13
13
  export const DataTableCell = forwardRef(({ onClickCell, children, type = 'text', className, isRowHighlighted, disabled = false, depth = 0, columnIndex, disclosureIconProps: nestingIconProps, style, ...props }, ref) => {
14
- const { size, leftFixedColumnIndex, rightFixedColumnIndex, loading, enableRowSelection, layout } = useDataTableContext();
14
+ const { size, leftFixedColumnIndex, rightFixedColumnIndex, loading, enableRowSelection, showVerticalBorder, layout, } = useDataTableContext();
15
15
  const { cellRef, isFixedColumn, isEdgeFixedColumn, fixedPositionStyles } = useFixedColumns({
16
16
  enableRowSelection,
17
17
  columnIndex,
@@ -25,6 +25,7 @@ export const DataTableCell = forwardRef(({ onClickCell, children, type = 'text',
25
25
  fixedColumn: isFixedColumn,
26
26
  edgeFixedColumn: isEdgeFixedColumn,
27
27
  isCheckboxCell: enableRowSelection && columnIndex === 0,
28
+ verticalBorder: showVerticalBorder,
28
29
  layout,
29
30
  });
30
31
  const handleClick = (event) => {
@@ -10,7 +10,7 @@ import { useFixedColumns } from '../../utilities/dom/useFixedColumns';
10
10
  import { handleCheckboxCellClick } from '../utils/handleCheckbox';
11
11
  import { mergeRefs } from '../../utilities/dom/mergeRefs';
12
12
  export const DataTableHeaderCell = forwardRef(({ children, type = 'text', sortButtonProps, sortOrder, ascendingIconProps, descendingIconProps, unsortedIconProps, className, columnIndex, disabled = false, ...props }, ref) => {
13
- const { size, leftFixedColumnIndex, rightFixedColumnIndex, enableRowSelection } = useDataTableContext();
13
+ const { size, leftFixedColumnIndex, rightFixedColumnIndex, enableRowSelection, showVerticalBorder } = useDataTableContext();
14
14
  const { cellRef, isFixedColumn, isEdgeFixedColumn, fixedPositionStyles } = useFixedColumns({
15
15
  enableRowSelection,
16
16
  columnIndex,
@@ -23,6 +23,7 @@ export const DataTableHeaderCell = forwardRef(({ children, type = 'text', sortBu
23
23
  fixedColumn: isFixedColumn,
24
24
  edgeFixedColumn: isEdgeFixedColumn,
25
25
  isCheckboxCell: enableRowSelection && columnIndex === 0,
26
+ verticalBorder: showVerticalBorder,
26
27
  });
27
28
  const isCheckboxCell = enableRowSelection && columnIndex === 0;
28
29
  const isStringChild = typeof children === 'string';
@@ -4,7 +4,7 @@ export type DataTableSize = 'small' | 'medium';
4
4
  /**
5
5
  * The props for the `DataTableContext` component.
6
6
  */
7
- export type DataTableContextProps = Pick<DataTableProps, 'size' | 'enableRowSelection' | 'fixedHeader' | 'leftFixedColumnIndex' | 'rightFixedColumnIndex' | 'loading' | 'layout'>;
7
+ export type DataTableContextProps = Pick<DataTableProps, 'size' | 'enableRowSelection' | 'fixedHeader' | 'showVerticalBorder' | 'leftFixedColumnIndex' | 'rightFixedColumnIndex' | 'loading' | 'layout'>;
8
8
  export type DataTableProviderValues = {
9
9
  numberColumns: number;
10
10
  setNumberColumns: (number: number) => void;
@@ -24,4 +24,4 @@ export declare const useDataTableContext: () => DataTableProviderValues;
24
24
  *
25
25
  * This should only be used in DataTable component.
26
26
  */
27
- export declare function DataTableProvider({ children, size, enableRowSelection, fixedHeader, leftFixedColumnIndex, rightFixedColumnIndex, loading, layout, }: PropsWithChildren<DataTableContextProps>): import("react/jsx-runtime").JSX.Element;
27
+ export declare function DataTableProvider({ children, size, enableRowSelection, fixedHeader, showVerticalBorder, leftFixedColumnIndex, rightFixedColumnIndex, loading, layout, }: PropsWithChildren<DataTableContextProps>): import("react/jsx-runtime").JSX.Element;
@@ -10,6 +10,7 @@ export const DataTableContext = createContext({
10
10
  size: 'medium',
11
11
  enableRowSelection: false,
12
12
  fixedHeader: false,
13
+ showVerticalBorder: false,
13
14
  leftFixedColumnIndex: undefined,
14
15
  rightFixedColumnIndex: undefined,
15
16
  layout: 'default',
@@ -27,12 +28,13 @@ export const useDataTableContext = () => useContext(DataTableContext);
27
28
  *
28
29
  * This should only be used in DataTable component.
29
30
  */
30
- export function DataTableProvider({ children, size = 'medium', enableRowSelection = false, fixedHeader = false, leftFixedColumnIndex, rightFixedColumnIndex, loading, layout = 'default', }) {
31
+ export function DataTableProvider({ children, size = 'medium', enableRowSelection = false, fixedHeader = false, showVerticalBorder = false, leftFixedColumnIndex, rightFixedColumnIndex, loading, layout = 'default', }) {
31
32
  const [numberColumns, setNumberColumns] = useState(0);
32
33
  const contextValue = useMemo(() => ({
33
34
  size,
34
35
  enableRowSelection,
35
36
  fixedHeader,
37
+ showVerticalBorder,
36
38
  leftFixedColumnIndex,
37
39
  rightFixedColumnIndex,
38
40
  loading,
@@ -43,6 +45,7 @@ export function DataTableProvider({ children, size = 'medium', enableRowSelectio
43
45
  size,
44
46
  enableRowSelection,
45
47
  fixedHeader,
48
+ showVerticalBorder,
46
49
  leftFixedColumnIndex,
47
50
  rightFixedColumnIndex,
48
51
  loading,
@@ -6,6 +6,36 @@ import { Checkbox } from '../../Checkbox';
6
6
  import { useDataTableContext } from '../DataTableProvider';
7
7
  import { cx } from '../../../styled-system/css';
8
8
  import { isComponentOrWrapped } from '../../utilities/react/isComponentOrWrapped';
9
+ const INTERACTIVE_ELEMENT_SELECTOR = [
10
+ 'a[href]',
11
+ 'button',
12
+ 'input',
13
+ 'select',
14
+ 'textarea',
15
+ 'label',
16
+ 'summary',
17
+ '[role="button"]',
18
+ '[role="link"]',
19
+ '[role="checkbox"]',
20
+ '[role="menuitem"]',
21
+ '[role="menuitemcheckbox"]',
22
+ '[role="menuitemradio"]',
23
+ '[role="option"]',
24
+ '[role="radio"]',
25
+ '[role="switch"]',
26
+ '[role="tab"]',
27
+ '[role="textbox"]',
28
+ '[contenteditable=""]',
29
+ '[contenteditable="true"]',
30
+ '[tabindex]:not([tabindex="-1"])',
31
+ ].join(',');
32
+ function isClickFromNestedInteractiveElement(event) {
33
+ if (!(event.target instanceof Element)) {
34
+ return false;
35
+ }
36
+ const interactiveElement = event.target.closest(INTERACTIVE_ELEMENT_SELECTOR);
37
+ return interactiveElement !== null && interactiveElement !== event.currentTarget;
38
+ }
9
39
  export const DataTableRow = forwardRef(({ children, disabled = false, highlighted, checkboxProps, className, onClickRow, selectable, ...props }, ref) => {
10
40
  const { enableRowSelection: contextEnableRowSelection, layout } = useDataTableContext();
11
41
  const isSelectable = selectable ?? contextEnableRowSelection;
@@ -24,12 +54,13 @@ export const DataTableRow = forwardRef(({ children, disabled = false, highlighte
24
54
  .find((cell) => cell.props.disclosureIconProps && !cell.props.onClickCell)?.props.disclosureIconProps;
25
55
  const ariaExpanded = isInteractive && disclosureIconProps ? (disclosureIconProps.isOpen ?? false) : undefined;
26
56
  const handleClickRow = (event) => {
27
- if (!disabled) {
28
- onClickRow?.(event);
57
+ if (disabled || isClickFromNestedInteractiveElement(event)) {
58
+ return;
29
59
  }
60
+ onClickRow?.(event);
30
61
  };
31
62
  const handleKeyDownRow = (event) => {
32
- if (!disabled && (event.key === 'Enter' || event.key === ' ')) {
63
+ if (!disabled && event.target === event.currentTarget && (event.key === 'Enter' || event.key === ' ')) {
33
64
  onClickRow?.(event);
34
65
  }
35
66
  };
@@ -8,7 +8,7 @@ export declare const LABEL_SELECT_MONTH = "\u6708\u3092\u9078\u629E";
8
8
  export declare const LABEL_OPEN_CALENDAR = "\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u958B\u304F";
9
9
  export declare const LABEL_CLOSE_CALENDAR = "\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u9589\u3058\u308B";
10
10
  export declare const LABEL_TODAY = "\u4ECA\u65E5";
11
- type LabelKey = 'GO_TO_PREV_MONTH' | 'GO_TO_NEXT_MONTH' | 'GO_TO_PREV_YEAR' | 'GO_TO_NEXT_YEAR' | 'SELECT_MONTH' | 'OPEN_CALENDAR' | 'CLOSE_CALENDAR' | 'TODAY';
11
+ type LabelKey = 'GO_TO_PREV_MONTH' | 'GO_TO_NEXT_MONTH' | 'GO_TO_PREV_YEAR' | 'GO_TO_NEXT_YEAR' | 'SELECT_MONTH' | 'SELECT_YEAR' | 'OPEN_CALENDAR' | 'CLOSE_CALENDAR' | 'TODAY';
12
12
  export declare const BASE_PICKER_LABELS: Record<NonNullable<BasePickerProps['calendarLocale']>, Record<LabelKey, string>>;
13
13
  export declare const DAY_ABBREVIATIONS: Record<NonNullable<BasePickerProps['calendarLocale']>, string[]>;
14
14
  export declare const DAY_FULL_NAMES: Record<NonNullable<BasePickerProps['calendarLocale']>, string[]>;
@@ -14,6 +14,7 @@ export const BASE_PICKER_LABELS = {
14
14
  GO_TO_PREV_YEAR: '前の年',
15
15
  GO_TO_NEXT_YEAR: '次の年',
16
16
  SELECT_MONTH: '月を選択',
17
+ SELECT_YEAR: '年を選択',
17
18
  OPEN_CALENDAR: 'カレンダーを開く',
18
19
  CLOSE_CALENDAR: 'カレンダーを閉じる',
19
20
  TODAY: '今日',
@@ -24,6 +25,7 @@ export const BASE_PICKER_LABELS = {
24
25
  GO_TO_PREV_YEAR: 'Previous year',
25
26
  GO_TO_NEXT_YEAR: 'Next year',
26
27
  SELECT_MONTH: 'Select month',
28
+ SELECT_YEAR: 'Select year',
27
29
  OPEN_CALENDAR: 'Open calendar',
28
30
  CLOSE_CALENDAR: 'Close calendar',
29
31
  TODAY: 'Today',
@@ -3,6 +3,7 @@ import { useCallback, useMemo } from 'react';
3
3
  import { SelectBox } from '../../../SelectBox';
4
4
  import { yearSelectorSlotRecipe } from '../../../../styled-system/recipes';
5
5
  import { MAXIMUM_VIEWABLE_YEAR, MINIMUM_VIEWABLE_YEAR } from './constants';
6
+ import { getBasePickerLabel } from '../BasePicker/constants';
6
7
  import { cx } from '../../../../styled-system/css';
7
8
  import { useCalendarLocale } from '../CalendarLocale/CalendarLocaleContext';
8
9
  import { useDisplayJapaneseCalendar } from '../CalendarLocale/DisplayJapaneseCalendarContext';
@@ -34,5 +35,10 @@ export function YearSelector({ value, onChange, filterYear, triggerProps, trigge
34
35
  }
35
36
  }, [onChange]);
36
37
  const classes = yearSelectorSlotRecipe();
37
- return (_jsx(SelectBox, { value: selectedOption, options: options, size: "small", targetDOMNode: targetDOMNode, enableAutoScrollToSelectedOption: { block: 'center', behavior: 'instant' }, popoverContentProps: { className: cx(classes.optionPanel, 'mfui-YearSelector__optionPanel') }, triggerProps: triggerProps, triggerWrapperProps: triggerWrapperProps, onChange: handleChange }));
38
+ return (_jsx(SelectBox, { value: selectedOption, options: options, size: "small", targetDOMNode: targetDOMNode, enableAutoScrollToSelectedOption: { block: 'center', behavior: 'instant' }, popoverContentProps: { className: cx(classes.optionPanel, 'mfui-YearSelector__optionPanel') }, triggerProps: {
39
+ // The trigger has role="combobox", which does not support naming from its
40
+ // content, so an explicit accessible name is required.
41
+ 'aria-label': getBasePickerLabel('SELECT_YEAR', calendarLocale),
42
+ ...triggerProps,
43
+ }, triggerWrapperProps: triggerWrapperProps, onChange: handleChange }));
38
44
  }
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import { useCallback, useState } from 'react';
3
+ import { useCallback, useRef, useState, } from 'react';
4
4
  import { DropdownMenuButtonTrigger } from './DropdownMenuButtonTrigger';
5
5
  import { DropdownMenuContainer } from './DropdownMenuContainer';
6
6
  import { DropdownMenuDivider } from './DropdownMenuDivider';
@@ -29,7 +29,15 @@ import { DropdownMenuHeading } from './DropdownMenuHeading';
29
29
  */
30
30
  export function DropdownMenu({ icon, label, children, triggerProps, tooltipLabel, tooltipPlacement, triggerMiddleTruncate, triggerTypographyVariant, menuPopoverProps, disabled, targetDOMNode, enableAutoUnmount, onOpenStateChanged, onBlur, }) {
31
31
  const [menuDefaultFocusPosition, setMenuDefaultFocusPosition] = useState('first');
32
+ // Tracks keyboard activation (Enter / Space) of the trigger. The resulting click event usually
33
+ // has `detail === 0`, but Safari reports keyboard-triggered clicks with `detail === 1`, so the
34
+ // keydown itself is recorded as the reliable signal.
35
+ const isTriggerActivatedByKeyboardRef = useRef(false);
32
36
  const handleTriggerKeyDownLocal = useCallback((event) => {
37
+ // The flag only survives from an Enter / Space keydown to its follow-up click; any other key
38
+ // invalidates the pending keyboard activation so the flag cannot linger when the click never
39
+ // fires.
40
+ isTriggerActivatedByKeyboardRef.current = event.key === 'Enter' || event.key === ' ';
33
41
  switch (event.key) {
34
42
  case 'ArrowDown':
35
43
  event.stopPropagation();
@@ -49,7 +57,23 @@ export function DropdownMenu({ icon, label, children, triggerProps, tooltipLabel
49
57
  handleTriggerKeyDownLocal(event);
50
58
  handleTriggerKeyDown(event);
51
59
  };
52
- return icon ? (_jsx(IconButton, { ref: setTriggerRef, "aria-expanded": isPopoverOpen, "aria-haspopup": "menu", disabled: disabled, onKeyDown: handleKeyDownCommon, onBlur: handleTriggerBlur, onClick: togglePopover, ...triggerProps, "aria-label": label, children: icon })) : (_jsx(DropdownMenuButtonTrigger, { label: label, tooltipLabel: tooltipLabel, tooltipPlacement: tooltipPlacement, triggerMiddleTruncate: triggerMiddleTruncate, triggerTypographyVariant: triggerTypographyVariant, triggerProps: triggerProps, disabled: disabled, isPopoverOpen: isPopoverOpen, setTriggerRef: setTriggerRef, togglePopover: togglePopover, handleTriggerKeyDown: handleKeyDownCommon, handleTriggerBlur: handleTriggerBlur }));
60
+ const handleBlurCommon = (event) => {
61
+ // Focus leaving the trigger invalidates any pending keyboard activation (e.g. a Space
62
+ // keydown whose follow-up click never fired), so a later mouse click cannot be
63
+ // misclassified as keyboard activation.
64
+ isTriggerActivatedByKeyboardRef.current = false;
65
+ handleTriggerBlur(event);
66
+ };
67
+ const handleTriggerClick = (event) => {
68
+ // Opening with the keyboard (Enter / Space) focuses the first item, following the
69
+ // WAI-ARIA menu button pattern. Opening with the mouse focuses no item; the menu
70
+ // container receives focus instead so that arrow keys still work.
71
+ const isKeyboardActivation = isTriggerActivatedByKeyboardRef.current || event.detail === 0;
72
+ isTriggerActivatedByKeyboardRef.current = false;
73
+ setMenuDefaultFocusPosition(isKeyboardActivation ? 'first' : 'none');
74
+ togglePopover(event);
75
+ };
76
+ return icon ? (_jsx(IconButton, { ref: setTriggerRef, "aria-expanded": isPopoverOpen, "aria-haspopup": "menu", disabled: disabled, onKeyDown: handleKeyDownCommon, onBlur: handleBlurCommon, onClick: handleTriggerClick, ...triggerProps, "aria-label": label, children: icon })) : (_jsx(DropdownMenuButtonTrigger, { label: label, tooltipLabel: tooltipLabel, tooltipPlacement: tooltipPlacement, triggerMiddleTruncate: triggerMiddleTruncate, triggerTypographyVariant: triggerTypographyVariant, triggerProps: triggerProps, disabled: disabled, isPopoverOpen: isPopoverOpen, setTriggerRef: setTriggerRef, togglePopover: handleTriggerClick, handleTriggerKeyDown: handleKeyDownCommon, handleTriggerBlur: handleBlurCommon }));
53
77
  }, renderContent: ({ closePopover }) => (_jsx(DropdownMenuProvider, { value: { closeMenuPopover: closePopover }, children: _jsx(DropdownMenuContainer, { defaultFocusItem: menuDefaultFocusPosition, onClose: closePopover, children: children }) })), enableAutoFocusOnPopover: false, enableAutoUnmount: enableAutoUnmount, contentProps: {
54
78
  className: cx(classes.popover, menuPopoverProps?.className),
55
79
  }, onBlur: onBlur, onOpenStateChanged: onOpenStateChanged }));
@@ -1,4 +1,4 @@
1
- import { type FocusEventHandler, type KeyboardEventHandler, type SyntheticEvent } from 'react';
1
+ import { type FocusEventHandler, type KeyboardEventHandler, type MouseEventHandler } from 'react';
2
2
  import { type ButtonProps } from '../Button';
3
3
  import { type DropdownMenuButtonTriggerProps } from './DropdownMenu.types';
4
4
  type DropdownMenuButtonTriggerComponentProps = DropdownMenuButtonTriggerProps & {
@@ -25,7 +25,7 @@ type DropdownMenuButtonTriggerComponentProps = DropdownMenuButtonTriggerProps &
25
25
  /**
26
26
  * Toggles the open state of the dropdown menu.
27
27
  */
28
- togglePopover: (event?: SyntheticEvent) => void;
28
+ togglePopover: MouseEventHandler<HTMLElement>;
29
29
  /**
30
30
  * Keyboard handler for the trigger (ArrowUp / ArrowDown focus behavior already merged in).
31
31
  */
@@ -11,14 +11,21 @@ import { dropdownMenuContainerSlotRecipe } from '../../../styled-system/recipes'
11
11
  export const DropdownMenuContainer = forwardRef(({ children, className, defaultFocusItem: defaultFocus = 'first', style, onClose }, ref) => {
12
12
  const classes = dropdownMenuContainerSlotRecipe();
13
13
  const menuContainerRef = useRef(null);
14
+ const getFocusableItems = useCallback(() => menuContainerRef.current?.querySelectorAll('[data-mfui-menu-item]:is([data-mfui-focusable=true])'), []);
14
15
  useEffect(() => {
15
- const focusableItems = menuContainerRef.current?.querySelectorAll('[data-mfui-menu-item]:is([data-mfui-focusable=true])');
16
+ if (defaultFocus === 'none') {
17
+ // No item should appear focused (e.g. the menu was opened with the mouse). Focus the
18
+ // container itself so keyboard interactions (Escape / ArrowDown / ArrowUp) keep working.
19
+ menuContainerRef.current?.focus({ preventScroll: true });
20
+ return;
21
+ }
22
+ const focusableItems = getFocusableItems();
16
23
  if (!focusableItems) {
17
24
  return;
18
25
  }
19
26
  const defaultFocusIndex = defaultFocus === 'first' ? 0 : focusableItems.length - 1;
20
27
  focusableItems[defaultFocusIndex]?.focus({ preventScroll: true });
21
- }, [defaultFocus]);
28
+ }, [defaultFocus, getFocusableItems]);
22
29
  const handleKeyDown = useCallback((event) => {
23
30
  switch (event.key) {
24
31
  case 'Escape':
@@ -27,7 +34,25 @@ export const DropdownMenuContainer = forwardRef(({ children, className, defaultF
27
34
  event.preventDefault();
28
35
  onClose();
29
36
  break;
37
+ case 'ArrowDown':
38
+ case 'ArrowUp': {
39
+ // Focused items handle arrow navigation themselves and stop propagation, so this
40
+ // branch only runs while the container itself is focused (defaultFocusItem 'none'):
41
+ // ArrowDown moves focus to the first item and ArrowUp to the last one.
42
+ if (event.target !== event.currentTarget) {
43
+ break;
44
+ }
45
+ event.stopPropagation();
46
+ event.preventDefault();
47
+ const focusableItems = getFocusableItems();
48
+ if (!focusableItems || focusableItems.length === 0) {
49
+ break;
50
+ }
51
+ const focusIndex = event.key === 'ArrowDown' ? 0 : focusableItems.length - 1;
52
+ focusableItems[focusIndex]?.focus();
53
+ break;
54
+ }
30
55
  }
31
- }, [onClose]);
56
+ }, [onClose, getFocusableItems]);
32
57
  return (_jsx("div", { ref: mergeRefs(ref, menuContainerRef), "data-mfui-menu-container": true, role: "menu", className: cx(classes.root, 'mfui-DropdownMenuContainer__root', className), tabIndex: -1, style: style, onKeyDown: handleKeyDown, children: children }));
33
58
  });
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The default focus position of the menu.
3
3
  */
4
- export type DropdownMenuDefaultFocusItem = 'first' | 'last';
4
+ export type DropdownMenuDefaultFocusItem = 'first' | 'last' | 'none';
5
5
  export type DropdownMenuContainerProps = {
6
6
  /**
7
7
  * The content of the component.
@@ -16,10 +16,13 @@ export type DropdownMenuContainerProps = {
16
16
  /**
17
17
  * The default focus position of the dropdown menu.
18
18
  *
19
- * It should be either 'first' or 'last'.
19
+ * It should be either 'first', 'last' or 'none'.
20
20
  *
21
21
  * If 'first', the first focusable item will be focused.
22
22
  * If 'last', the last focusable item will be focused.
23
+ * If 'none', no item will be focused; the menu container itself receives focus instead so that
24
+ * keyboard interactions (Escape / ArrowDown / ArrowUp) keep working. Use this when the menu is
25
+ * opened with a pointer, where visually focusing an item is not expected.
23
26
  *
24
27
  * @default 'first'
25
28
  */
@@ -12,4 +12,4 @@ import { type DropdownMenuItemProps } from './DropdownMenuItem.types';
12
12
  *
13
13
  * Otherwise, it will be rendered as a div element.
14
14
  */
15
- export declare function DropdownMenuItem({ children, className, href, target, customLinkComponent, onClick, disabled, 'aria-labelledby': ariaLabelledby, ...rest }: DropdownMenuItemProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function DropdownMenuItem({ children, className, href, target, customLinkComponent, onClick, disabled, disabledMessage, 'aria-labelledby': ariaLabelledby, 'aria-describedby': ariaDescribedby, ...rest }: DropdownMenuItemProps): import("react/jsx-runtime").JSX.Element;
@@ -1,6 +1,7 @@
1
1
  'use client';
2
- import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useCallback, useId, useMemo, useRef } from 'react';
4
+ import { Info } from '@moneyforward/mfui-icons-react';
4
5
  import { cx } from '../../../styled-system/css';
5
6
  import { FocusIndicator } from '../../FocusIndicator';
6
7
  import { dropdownMenuItemSlotRecipe } from '../../../styled-system/recipes';
@@ -19,7 +20,7 @@ import { useDropdownMenuContext } from '../DropdownMenuContext';
19
20
  *
20
21
  * Otherwise, it will be rendered as a div element.
21
22
  */
22
- export function DropdownMenuItem({ children, className, href, target, customLinkComponent, onClick, disabled, 'aria-labelledby': ariaLabelledby, ...rest }) {
23
+ export function DropdownMenuItem({ children, className, href, target, customLinkComponent, onClick, disabled, disabledMessage, 'aria-labelledby': ariaLabelledby, 'aria-describedby': ariaDescribedby, ...rest }) {
23
24
  const classes = dropdownMenuItemSlotRecipe();
24
25
  const { closeMenuPopover } = useDropdownMenuContext();
25
26
  const id = useId();
@@ -87,5 +88,19 @@ export function DropdownMenuItem({ children, className, href, target, customLink
87
88
  : disabled
88
89
  ? { 'aria-disabled': true, 'data-disabled': '' }
89
90
  : {};
90
- return (_jsx(FocusIndicator, { position: "inside", children: _jsx(Tag, { ...rest, ref: itemRef, ...(ariaLabelledby && { id }), "data-mfui-menu-item": true, role: "menuitem", className: cx(classes.root, 'mfui-DropdownMenuItem__root', className), tabIndex: -1, href: resolvedHref, target: target, "data-mfui-focusable": isFocusable, type: onClick ? 'button' : undefined, "aria-labelledby": ariaLabelledby ? `${ariaLabelledby} ${id}` : undefined, ...disabledProps, onKeyDown: handleKeyDown, onClick: isButton ? handleClick : undefined, children: typeof children === 'string' ? _jsx(Typography, { variant: "body", children: children }) : children }) }));
91
+ const showMessage = Boolean(disabled && disabledMessage);
92
+ const labelId = `${id}-label`;
93
+ const messageId = `${id}-message`;
94
+ const label = typeof children === 'string' ? _jsx(Typography, { variant: "body", children: children }) : children;
95
+ // With a message, the accessible name must reference only the label span so the message
96
+ // stays a description; without one, keep the existing self-reference via the item's own id.
97
+ const resolvedAriaLabelledby = showMessage
98
+ ? [ariaLabelledby, labelId].filter(Boolean).join(' ')
99
+ : ariaLabelledby
100
+ ? `${ariaLabelledby} ${id}`
101
+ : undefined;
102
+ const resolvedAriaDescribedby = showMessage
103
+ ? [ariaDescribedby, messageId].filter(Boolean).join(' ')
104
+ : ariaDescribedby;
105
+ return (_jsx(FocusIndicator, { position: "inside", children: _jsx(Tag, { ...rest, ref: itemRef, ...(ariaLabelledby && { id }), "data-mfui-menu-item": true, role: "menuitem", className: cx(classes.root, 'mfui-DropdownMenuItem__root', className), tabIndex: -1, href: resolvedHref, target: target, "data-mfui-focusable": isFocusable, type: onClick ? 'button' : undefined, "aria-labelledby": resolvedAriaLabelledby, "aria-describedby": resolvedAriaDescribedby, ...disabledProps, onKeyDown: handleKeyDown, onClick: isButton ? handleClick : undefined, children: showMessage ? (_jsxs("span", { className: cx(classes.content, 'mfui-DropdownMenuItem__content'), children: [_jsx("span", { id: labelId, children: label }), _jsxs("span", { id: messageId, className: cx(classes.disabledMessage, 'mfui-DropdownMenuItem__disabledMessage'), children: [_jsx(Info, { "aria-hidden": true, className: cx(classes.disabledMessageIcon, 'mfui-DropdownMenuItem__disabledMessageIcon') }), _jsx(Typography, { variant: "helpMessage", children: disabledMessage })] })] })) : (label) }) }));
91
106
  }
@@ -77,6 +77,12 @@ export type DropdownMenuItemProps = {
77
77
  * The class name to apply to the component.
78
78
  */
79
79
  className?: string;
80
+ /**
81
+ * An explanatory message displayed inline below the item label when the item is disabled.
82
+ * Rendered with an info icon. Ignored unless `disabled` is true.
83
+ * Exposed to screen readers as the item's accessible description (aria-describedby).
84
+ */
85
+ disabledMessage?: React.ReactNode;
80
86
  /**
81
87
  * The aria-labelledby attribute for accessibility.
82
88
  *
@@ -3,4 +3,4 @@ import { type MainNavigationProps } from './MainNavigation.types';
3
3
  * The component for the main navigation on the normal viewport.
4
4
  * This component must only be used in MainNavigation.tsx, do not export it.
5
5
  */
6
- export declare function BaseMainNavigation({ className, featureShortcut, navigationItems, enableCollapsible, width, customLinkComponent, disableResponsive, isCollapsed: controlledIsCollapsed, onCollapsedChange, }: MainNavigationProps): import("react/jsx-runtime").JSX.Element;
6
+ export declare function BaseMainNavigation({ className, featureShortcut, navigationItems, enableCollapsible, width, customLinkComponent, disableResponsive, isCollapsed: controlledIsCollapsed, onCollapsedChange, collapseButtonProps, expandButtonProps, }: MainNavigationProps): import("react/jsx-runtime").JSX.Element;
@@ -13,7 +13,7 @@ import { Popover } from '../Popover';
13
13
  * The component for the main navigation on the normal viewport.
14
14
  * This component must only be used in MainNavigation.tsx, do not export it.
15
15
  */
16
- export function BaseMainNavigation({ className, featureShortcut, navigationItems, enableCollapsible = false, width = 'normal', customLinkComponent, disableResponsive, isCollapsed: controlledIsCollapsed, onCollapsedChange, }) {
16
+ export function BaseMainNavigation({ className, featureShortcut, navigationItems, enableCollapsible = false, width = 'normal', customLinkComponent, disableResponsive, isCollapsed: controlledIsCollapsed, onCollapsedChange, collapseButtonProps, expandButtonProps, }) {
17
17
  const [localIsCollapsed, setLocalIsCollapsed] = useState(controlledIsCollapsed ?? false);
18
18
  const [openPopoverIndex, setOpenPopoverIndex] = useState(null);
19
19
  const isControlled = controlledIsCollapsed !== undefined;
@@ -28,7 +28,9 @@ export function BaseMainNavigation({ className, featureShortcut, navigationItems
28
28
  };
29
29
  const classes = baseMainNavigationSlotRecipe({ width, disableResponsive });
30
30
  const InternalLinkTag = customLinkComponent ?? 'a';
31
- const toggleButtonLabel = isCollapsed ? 'ナビゲーションを拡げる' : 'ナビゲーションを折りたたむ';
31
+ const toggleButtonLabel = isCollapsed
32
+ ? (expandButtonProps?.label ?? 'ナビゲーションを拡げる')
33
+ : (collapseButtonProps?.label ?? 'ナビゲーションを折りたたむ');
32
34
  return (_jsxs("div", { "data-mfui-collapsed": isCollapsed, className: cx(classes.root, 'mfui-BaseMainNavigation__root', className), children: [featureShortcut ? (_jsx("div", { className: cx(classes.featureShortcut, 'mfui-BaseMainNavigation__featureShortcut'), children: _jsx(FocusIndicator, { children: _jsx(NavigationLink, { tag: InternalLinkTag, isExternal: featureShortcut.isExternal, href: featureShortcut.href, className: cx(classes.featureShortcutAnchor, 'mfui-BaseMainNavigation__featureShortcutAnchor'), children: _jsx(Typography, { variant: "controlLabel", children: featureShortcut.label }) }) }) })) : null, _jsxs("nav", { id: navId, className: cx(classes.nav, 'mfui-BaseMainNavigation__nav'), children: [_jsx("ul", { className: cx(classes.list, 'mfui-BaseMainNavigation__list'), children: navigationItems.map((navigation, index) => {
33
35
  const isGroupLabel = navigation.children && 'isGroupLabel' in navigation && navigation.isGroupLabel;
34
36
  const isGroupMenu = 'isGroupMenu' in navigation && navigation.isGroupMenu;
@@ -9,7 +9,7 @@ import { NarrowViewportMainNavigation } from './NarrowViewportMainNavigation';
9
9
  * When the viewport is narrow, the navigation will be displayed as a drawer.
10
10
  * When the viewport is not narrow, the navigation will be displayed as a sidebar.
11
11
  */
12
- export const MainNavigation = forwardRef(({ className, featureShortcut, navigationItems, disableResponsive = false, width = 'normal', customLinkComponent, enableCollapsible, isCollapsed, onCollapsedChange, }, ref) => {
12
+ export const MainNavigation = forwardRef(({ className, featureShortcut, navigationItems, disableResponsive = false, width = 'normal', customLinkComponent, enableCollapsible, isCollapsed, onCollapsedChange, collapseButtonProps, expandButtonProps, }, ref) => {
13
13
  const commonProps = {
14
14
  className,
15
15
  featureShortcut,
@@ -17,5 +17,5 @@ export const MainNavigation = forwardRef(({ className, featureShortcut, navigati
17
17
  width,
18
18
  customLinkComponent,
19
19
  };
20
- return (_jsxs(_Fragment, { children: [_jsx(BaseMainNavigation, { ...commonProps, enableCollapsible: enableCollapsible, disableResponsive: disableResponsive, isCollapsed: isCollapsed, onCollapsedChange: onCollapsedChange }), !disableResponsive && _jsx(NarrowViewportMainNavigation, { ...commonProps, ref: ref })] }));
20
+ return (_jsxs(_Fragment, { children: [_jsx(BaseMainNavigation, { ...commonProps, enableCollapsible: enableCollapsible, disableResponsive: disableResponsive, isCollapsed: isCollapsed, onCollapsedChange: onCollapsedChange, collapseButtonProps: collapseButtonProps, expandButtonProps: expandButtonProps }), !disableResponsive && _jsx(NarrowViewportMainNavigation, { ...commonProps, ref: ref })] }));
21
21
  });
@@ -230,6 +230,24 @@ export type MainNavigationProps = {
230
230
  * This prop is only effective when `enableCollapsible` is `true`.
231
231
  */
232
232
  isCollapsed?: boolean;
233
+ /**
234
+ * The properties for the toggle button when the navigation is expanded (clicking will collapse).
235
+ * This prop is only effective when `enableCollapsible` is `true`.
236
+ *
237
+ * @property label - Accessible name for the toggle button. It is used for both the tooltip content and the `aria-label` of the toggle button. default is 'ナビゲーションを折りたたむ'.
238
+ */
239
+ collapseButtonProps?: {
240
+ label?: string;
241
+ };
242
+ /**
243
+ * The properties for the toggle button when the navigation is collapsed (clicking will expand).
244
+ * This prop is only effective when `enableCollapsible` is `true`.
245
+ *
246
+ * @property label - Accessible name for the toggle button. It is used for both the tooltip content and the `aria-label` of the toggle button. default is 'ナビゲーションを拡げる'.
247
+ */
248
+ expandButtonProps?: {
249
+ label?: string;
250
+ };
233
251
  /**
234
252
  * Callback function called when the collapsed state changes.
235
253
  * This is triggered when the toggle button is clicked.