@moneyforward/mfui-components 3.29.1 → 3.31.1
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.
- package/dist/src/Button/Button.d.ts +4 -4
- package/dist/src/CheckboxCard/CheckboxCard.d.ts +2 -2
- package/dist/src/CheckboxCard/CheckboxCard.js +1 -1
- package/dist/src/DataTable/DataTable.js +2 -2
- package/dist/src/DataTable/DataTable.types.d.ts +9 -0
- package/dist/src/DataTable/DataTableCell/DataTableCell.js +3 -2
- package/dist/src/DataTable/DataTableHeaderCell/DataTableHeaderCell.js +2 -1
- package/dist/src/DataTable/DataTableProvider.d.ts +2 -2
- package/dist/src/DataTable/DataTableProvider.js +4 -1
- package/dist/src/DataTable/DataTableRow/DataTableRow.js +34 -3
- package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerProvider/DateRangePickerProvider.d.ts +2 -2
- package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerTrigger/constants.d.ts +4 -4
- package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerTrigger/hooks/useDateRangeTriggerInputClick.d.ts +1 -1
- package/dist/src/DateTimeSelection/DateRangePicker/utilities/createDateRangePickerTestUtility.d.ts +1 -1
- package/dist/src/DateTimeSelection/MonthRangePicker/MonthRangePickerMonthCell/constants.d.ts +5 -5
- package/dist/src/DateTimeSelection/TimePicker/TimePicker.d.ts +9 -9
- package/dist/src/DateTimeSelection/shared/BasePicker/basePickerUtilities/useBasePickerValueController.d.ts +1 -1
- package/dist/src/DateTimeSelection/shared/BasePicker/constants.d.ts +1 -1
- package/dist/src/DateTimeSelection/shared/BasePicker/constants.js +2 -0
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerPopover/BaseRangePickerCalendar/constants.d.ts +6 -6
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerProvider/BaseRangePickerProvider.d.ts +2 -2
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerTrigger/BaseRangePickerTrigger.js +1 -1
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerTrigger/hooks/useDateRangeTriggerInputClick.d.ts +1 -1
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/utilities/createBaseRangePickerTestUtility.d.ts +1 -1
- package/dist/src/DateTimeSelection/shared/YearSelector/YearSelector.js +7 -1
- package/dist/src/DateTimeSelection/shared/accessibility/constants.d.ts +6 -6
- package/dist/src/Dialog/Dialog.d.ts +4 -4
- package/dist/src/Disclosure/Disclosure.d.ts +21 -10
- package/dist/src/DropdownMenu/DropdownMenu.d.ts +3 -3
- package/dist/src/DropdownMenu/DropdownMenu.js +26 -2
- package/dist/src/DropdownMenu/DropdownMenuButtonTrigger.d.ts +2 -2
- package/dist/src/DropdownMenu/DropdownMenuContainer/DropdownMenuContainer.js +28 -3
- package/dist/src/DropdownMenu/DropdownMenuContainer/DropdownMenuContainer.types.d.ts +5 -2
- package/dist/src/DropdownMenu/DropdownMenuItem/DropdownMenuItem.d.ts +1 -1
- package/dist/src/DropdownMenu/DropdownMenuItem/DropdownMenuItem.js +29 -6
- package/dist/src/DropdownMenu/DropdownMenuItem/DropdownMenuItem.types.d.ts +6 -0
- package/dist/src/EmbeddedSidePane/EmbeddedSidePane.d.ts +1 -1
- package/dist/src/FileBox/FileBox.d.ts +4 -4
- package/dist/src/FileBox/FileBox.js +1 -1
- package/dist/src/FileDropZone/FileDropZone.d.ts +4 -4
- package/dist/src/FileDropZone/utils/fileHelpers.d.ts +3 -3
- package/dist/src/FilterTrigger/FilterTrigger.d.ts +2 -2
- package/dist/src/Heading/Heading.d.ts +2 -2
- package/dist/src/HelpMessage/HelpMessage.d.ts +3 -3
- package/dist/src/IconButton/IconButton.d.ts +6 -6
- package/dist/src/KeyValue/KeyValue.d.ts +2 -2
- package/dist/src/MainNavigation/BaseMainNavigation.d.ts +1 -1
- package/dist/src/MainNavigation/BaseMainNavigation.js +4 -2
- package/dist/src/MainNavigation/MainNavigation.js +3 -3
- package/dist/src/MainNavigation/MainNavigation.types.d.ts +18 -0
- package/dist/src/MultipleSelectBox/MultipleSelectBox.js +1 -1
- package/dist/src/MultipleSelectBox/hooks/useApplyControls.d.ts +1 -1
- package/dist/src/MultipleSelectBox/hooks/useSelectedValues.d.ts +1 -1
- package/dist/src/NumberBox/NumberBox.d.ts +1 -1
- package/dist/src/NumberBox/NumberBox.js +68 -21
- package/dist/src/Pagination/ItemsCount/ItemsCount.js +1 -1
- package/dist/src/Popover/Popover.js +1 -1
- package/dist/src/RadioButton/RadioButton.d.ts +1 -1
- package/dist/src/RadioButtonCard/RadioButtonCard.d.ts +2 -2
- package/dist/src/RadioButtonCard/RadioButtonCard.js +1 -1
- package/dist/src/RadioGroup/RadioGroup.d.ts +1 -1
- package/dist/src/SearchBox/SearchBox.js +18 -4
- package/dist/src/SectionMessage/SectionMessage.d.ts +5 -5
- package/dist/src/SectionMessage/SectionMessage.js +11 -4
- package/dist/src/SectionMessage/SectionMessage.types.d.ts +4 -4
- package/dist/src/SelectBox/SelectBox.js +1 -1
- package/dist/src/SelectBox/SelectBoxOption.js +1 -1
- package/dist/src/SelectBox/SelectBoxOptionGroup.js +1 -1
- package/dist/src/SidePane/SidePane.d.ts +9 -7
- package/dist/src/SidePane/SidePane.js +8 -4
- package/dist/src/SidePane/hooks/useSidePaneStateController.d.ts +7 -2
- package/dist/src/SidePane/hooks/useSidePaneStateController.js +11 -5
- package/dist/src/Sidebar/Sidebar.d.ts +10 -1
- package/dist/src/Sidebar/Sidebar.js +40 -10
- package/dist/src/Sidebar/Sidebar.types.d.ts +39 -2
- package/dist/src/Sidebar/SidebarContext.d.ts +3 -0
- package/dist/src/Sidebar/SidebarContext.js +2 -0
- package/dist/src/Sidebar/SidebarMenuHeading/SidebarMenuHeading.d.ts +49 -0
- package/dist/src/Sidebar/SidebarMenuHeading/SidebarMenuHeading.js +113 -0
- package/dist/src/Sidebar/SidebarMenuHeading/SidebarMenuHeading.types.d.ts +36 -0
- package/dist/src/Sidebar/SidebarMenuHeading/SidebarMenuHeading.types.js +1 -0
- package/dist/src/Sidebar/SidebarMenuHeading/index.d.ts +2 -0
- package/dist/src/Sidebar/SidebarMenuHeading/index.js +1 -0
- package/dist/src/Sidebar/SidebarNavigationItem.js +6 -3
- package/dist/src/Sidebar/hooks/useSidebarResize.d.ts +2 -1
- package/dist/src/Sidebar/hooks/useSidebarResize.js +31 -3
- package/dist/src/Sidebar/index.d.ts +2 -1
- package/dist/src/Stack/Stack.d.ts +5 -5
- package/dist/src/StatusLabel/StatusLabel.d.ts +2 -2
- package/dist/src/Stepper/Step/Step.js +1 -1
- package/dist/src/SubNavigation/SubNavigation.js +1 -1
- package/dist/src/Tag/Tag.d.ts +1 -1
- package/dist/src/Tag/Tag.js +2 -2
- package/dist/src/Tag/Tag.types.d.ts +7 -0
- package/dist/src/TextBox/TextBox.d.ts +6 -6
- package/dist/src/TextLink/TextLink.d.ts +2 -2
- package/dist/src/Textarea/Textarea.d.ts +4 -4
- package/dist/src/Toast/Toast.d.ts +3 -3
- package/dist/src/Toast/Toast.js +9 -5
- package/dist/src/Toast/Toast.types.d.ts +3 -5
- package/dist/src/Toast/api/toast.d.ts +18 -2
- package/dist/src/Tooltip/Tooltip.d.ts +3 -3
- package/dist/src/Tooltip/Tooltip.js +1 -1
- package/dist/src/Tooltip/Tooltip.types.d.ts +2 -0
- package/dist/src/Tooltip/hooks/useTooltipDisplayController.js +14 -2
- package/dist/src/utilities/dom/dispatchNativeInputValueWithEvent.d.ts +1 -1
- package/dist/src/utilities/dom/useFocusTrap.d.ts +1 -1
- package/dist/src/utilities/react/useIsomorphicLayoutEffect.d.ts +2 -2
- package/dist/styled-system/css/conditions.d.ts +3 -3
- package/dist/styled-system/helpers.d.ts +36 -35
- package/dist/styled-system/jsx/factory-helper.d.ts +4 -4
- package/dist/styled-system/recipes/create-recipe.d.ts +2 -2
- package/dist/styled-system/recipes/data-table-cell-slot-recipe.d.ts +1 -0
- package/dist/styled-system/recipes/data-table-cell-slot-recipe.js +4 -0
- package/dist/styled-system/recipes/data-table-header-cell-slot-recipe.d.ts +1 -0
- package/dist/styled-system/recipes/data-table-header-cell-slot-recipe.js +4 -0
- package/dist/styled-system/recipes/dropdown-menu-item-slot-recipe.d.ts +1 -1
- package/dist/styled-system/recipes/dropdown-menu-item-slot-recipe.js +12 -0
- package/dist/styled-system/recipes/index.d.ts +2 -1
- package/dist/styled-system/recipes/index.js +1 -0
- package/dist/styled-system/recipes/section-message-slot-recipe.d.ts +1 -1
- package/dist/styled-system/recipes/section-message-slot-recipe.js +3 -1
- package/dist/styled-system/recipes/sidebar-menu-heading-slot-recipe.d.ts +33 -0
- package/dist/styled-system/recipes/sidebar-menu-heading-slot-recipe.js +44 -0
- package/dist/styled-system/recipes/sidebar-slot-recipe.d.ts +1 -1
- package/dist/styled-system/recipes/sidebar-slot-recipe.js +4 -0
- package/dist/styles.css +158 -14
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +11 -11
|
@@ -8,8 +8,8 @@ import { type RadioButtonCardResponsiveSlot } from './RadioButtonCard.types';
|
|
|
8
8
|
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio
|
|
9
9
|
*/
|
|
10
10
|
export declare const RadioButtonCard: import("react").ForwardRefExoticComponent<{
|
|
11
|
-
layout?: import("../../styled-system/recipes").RadioButtonCardSlotRecipeVariant[
|
|
11
|
+
layout?: import("../../styled-system/recipes").RadioButtonCardSlotRecipeVariant['layout'];
|
|
12
12
|
label: string;
|
|
13
13
|
renderDetailsSlot?: RadioButtonCardResponsiveSlot | import("./RadioButtonCard.types").RadioButtonCardRenderDetailsSlot;
|
|
14
|
-
disableResponsive?: import("../../styled-system/recipes").RadioButtonCardSlotRecipeVariant[
|
|
14
|
+
disableResponsive?: import("../../styled-system/recipes").RadioButtonCardSlotRecipeVariant['disableResponsive'];
|
|
15
15
|
} & Omit<import("..").RadioButtonProps, "label"> & import("react").RefAttributes<HTMLInputElement>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef, useMemo } from 'react';
|
|
3
3
|
import { cx } from '../../styled-system/css';
|
|
4
4
|
import { FocusIndicator } from '../FocusIndicator';
|
|
@@ -10,4 +10,4 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div
|
|
12
12
|
*/
|
|
13
|
-
export declare const RadioGroup: import("react").ForwardRefExoticComponent<Pick<import("..").RadioButtonProps, "
|
|
13
|
+
export declare const RadioGroup: import("react").ForwardRefExoticComponent<Pick<import("..").RadioButtonProps, "defaultValue" | "disabled" | "name" | "onChange" | "value"> & Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "onChange"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -14,10 +14,24 @@ import { normalizeFullWidth } from '../utilities/string/normalizeFullWidth';
|
|
|
14
14
|
export const SearchBox = forwardRef(({ className, normalizeFullWidth: shouldNormalizeFullWidth = false, onChange, ...rest }, ref) => {
|
|
15
15
|
const handleChange = useCallback((event) => {
|
|
16
16
|
if (shouldNormalizeFullWidth) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
-
|
|
17
|
+
const { value, selectionStart } = event.target;
|
|
18
|
+
const normalizedValue = normalizeFullWidth(value);
|
|
19
|
+
// Only rewrite the native input when normalization actually changes the value.
|
|
20
|
+
// Assigning to `value` resets the caret to the end even when the string is
|
|
21
|
+
// unchanged, so skipping the no-op assignment keeps the caret in place while
|
|
22
|
+
// the user edits mid-string.
|
|
23
|
+
if (normalizedValue !== value) {
|
|
24
|
+
// Map the caret by normalizing only the text before it. This keeps the caret
|
|
25
|
+
// correct even when normalization changes the string length (e.g. `パ` -> `パ`).
|
|
26
|
+
const caretPosition = selectionStart === null
|
|
27
|
+
? normalizedValue.length
|
|
28
|
+
: normalizeFullWidth(value.slice(0, selectionStart)).length;
|
|
29
|
+
// Rewrite the native input so the displayed value reflects the normalization
|
|
30
|
+
// and the consumer's onChange sees the canonical half-width / composed-kana form.
|
|
31
|
+
// eslint-disable-next-line no-param-reassign
|
|
32
|
+
event.target.value = normalizedValue;
|
|
33
|
+
event.target.setSelectionRange(caretPosition, caretPosition);
|
|
34
|
+
}
|
|
21
35
|
}
|
|
22
36
|
onChange?.(event);
|
|
23
37
|
}, [shouldNormalizeFullWidth, onChange]);
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div
|
|
10
10
|
*/
|
|
11
11
|
export declare const SectionMessage: import("react").ForwardRefExoticComponent<{
|
|
12
|
-
messageType?: import("../../styled-system/recipes").SectionMessageSlotRecipeVariant[
|
|
13
|
-
region?: import("../../styled-system/recipes").SectionMessageSlotRecipeVariant[
|
|
12
|
+
messageType?: import("../../styled-system/recipes").SectionMessageSlotRecipeVariant['messageType'];
|
|
13
|
+
region?: import("../../styled-system/recipes").SectionMessageSlotRecipeVariant['region'];
|
|
14
14
|
actionSlot?: import("react").ReactNode;
|
|
15
|
-
onClose?: import("..").IconButtonProps[
|
|
15
|
+
onClose?: import("..").IconButtonProps['onClick'];
|
|
16
16
|
children?: import("react").ReactNode;
|
|
17
|
-
statusIconProps?: Pick<import("react").ComponentPropsWithoutRef<
|
|
18
|
-
closeButtonProps?: Pick<import("react").ComponentPropsWithoutRef<
|
|
17
|
+
statusIconProps?: Pick<import("react").ComponentPropsWithoutRef<'svg'>, 'aria-label'>;
|
|
18
|
+
closeButtonProps?: Pick<import("react").ComponentPropsWithoutRef<'svg'>, 'aria-label'>;
|
|
19
19
|
disableResponsive?: boolean;
|
|
20
20
|
} & Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef } from 'react';
|
|
3
|
-
import { Error, Approval, Caution, Close } from '@moneyforward/mfui-icons-react';
|
|
3
|
+
import { Error, Approval, Caution, Close, Pending } from '@moneyforward/mfui-icons-react';
|
|
4
4
|
import { cx } from '../../styled-system/css';
|
|
5
5
|
import { sectionMessageSlotRecipe } from '../../styled-system/recipes';
|
|
6
6
|
import { IconButton } from '../IconButton';
|
|
7
|
+
import { ProgressIndicator } from '../ProgressIndicator';
|
|
7
8
|
import { Typography } from '../Typography';
|
|
8
9
|
/**
|
|
9
10
|
* The SectionMessage component is used to display an inline message inside a page or some container.
|
|
@@ -21,11 +22,17 @@ export const SectionMessage = forwardRef(({ messageType = 'neutral', region = 'i
|
|
|
21
22
|
region,
|
|
22
23
|
disableResponsive,
|
|
23
24
|
});
|
|
25
|
+
// The status is conveyed by the message content itself, so the status icon is decorative
|
|
26
|
+
// and hidden from assistive technology unless a label is explicitly provided.
|
|
27
|
+
const statusIconLabel = statusIconProps?.['aria-label'];
|
|
28
|
+
const statusIconA11yProps = statusIconLabel === undefined ? { 'aria-hidden': true } : { 'aria-label': statusIconLabel };
|
|
24
29
|
const StatusIcon = {
|
|
25
30
|
neutral: null,
|
|
26
|
-
success: (_jsx(Approval, {
|
|
27
|
-
error:
|
|
28
|
-
caution: (_jsx(Caution, {
|
|
31
|
+
success: (_jsx(Approval, { ...statusIconA11yProps, className: cx(classes.statusIcon, 'mfui-SectionMessage__statusIcon') })),
|
|
32
|
+
error: _jsx(Error, { ...statusIconA11yProps, className: cx(classes.statusIcon, 'mfui-SectionMessage__statusIcon') }),
|
|
33
|
+
caution: (_jsx(Caution, { ...statusIconA11yProps, className: cx(classes.statusIcon, 'mfui-SectionMessage__statusIcon') })),
|
|
34
|
+
busy: _jsx(Pending, { ...statusIconA11yProps, className: cx(classes.statusIcon, 'mfui-SectionMessage__statusIcon') }),
|
|
35
|
+
progress: (_jsx(ProgressIndicator, { role: "img", ...statusIconA11yProps, className: cx(classes.statusIcon, 'mfui-SectionMessage__statusIcon') })),
|
|
29
36
|
}[messageType];
|
|
30
37
|
const contentIsString = typeof children === 'string';
|
|
31
38
|
return (_jsxs("div", { ref: ref, className: cx(classes.root, 'mfui-SectionMessage__root', className), ...props, role: "alert", children: [_jsxs("div", { className: cx(classes.topSection, 'mfui-SectionMessage__topSection'), children: [_jsxs("div", { className: cx(classes.content, 'mfui-SectionMessage__content'), children: [StatusIcon, contentIsString ? _jsx(Typography, { variant: "body", children: children }) : children] }), _jsxs("div", { className: cx(classes.rightSection, 'mfui-SectionMessage__rightSection'), children: [_jsx("div", { className: cx(classes.actionSlot, classes.desktopActionSlot, 'mfui-SectionMessage__actionSlot'), "data-mfui-content": "SectionMessage-action-slot-desktop", children: actionSlot }), onClose ? (_jsx(IconButton, { "aria-label": closeButtonProps?.['aria-label'] ?? '閉じる', onClick: onClose, children: _jsx(Close, { "aria-hidden": true, className: cx(classes.closeIcon, 'mfui-SectionMessage__closeIcon') }) })) : null] })] }), actionSlot && !disableResponsive ? (_jsx("div", { className: cx(classes.actionSlot, classes.mobileActionSlot, 'mfui-SectionMessage__actionSlot'), "data-mfui-content": "SectionMessage-action-slot-mobile", children: actionSlot })) : null] }));
|
|
@@ -35,10 +35,10 @@ export type SectionMessageProps = {
|
|
|
35
35
|
/**
|
|
36
36
|
* Props for the status icon.
|
|
37
37
|
*
|
|
38
|
-
* @property aria-label - The text alternative for the status icon.
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
38
|
+
* @property aria-label - The text alternative for the status icon.
|
|
39
|
+
* By default, the status icon is decorative and hidden from assistive technology (`aria-hidden`),
|
|
40
|
+
* because the message content itself conveys the status.
|
|
41
|
+
* Pass an `aria-label` only when the icon needs to be announced.
|
|
42
42
|
*/
|
|
43
43
|
statusIconProps?: Pick<ComponentPropsWithoutRef<'svg'>, 'aria-label'>;
|
|
44
44
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import React, { forwardRef, useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import { Dropdown as DropdownIcon, Error } from '@moneyforward/mfui-icons-react';
|
|
5
5
|
import { ClearButton } from '../shared/ClearButton';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { memo, useMemo, useCallback } from 'react';
|
|
4
4
|
import { Current } from '@moneyforward/mfui-icons-react';
|
|
5
5
|
import { FocusIndicator } from '../FocusIndicator';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { memo } from 'react';
|
|
4
4
|
import { Typography } from '../Typography';
|
|
5
5
|
import { SelectBoxOptionComponent } from './SelectBoxOption';
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The general purpose SidePane component.
|
|
3
|
-
* This component extends the props of `<div>` element
|
|
3
|
+
* This component extends the props of `<div>` element. The extended props and `ref` are
|
|
4
|
+
* applied to the root overlay element covering the viewport, while `role="dialog"` (and
|
|
5
|
+
* `aria-modal="true"` when `enableModal` is set) are set on the inner pane window element.
|
|
4
6
|
*
|
|
5
7
|
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog
|
|
6
8
|
*/
|
|
@@ -9,22 +11,22 @@ export declare const SidePane: import("react").ForwardRefExoticComponent<{
|
|
|
9
11
|
title?: string;
|
|
10
12
|
renderHeading?: (options: import("./SidePane.types").SidePaneRenderOptions) => import("react").ReactNode;
|
|
11
13
|
actionSlot?: import("react").ReactNode;
|
|
12
|
-
position?: import("../../styled-system/recipes").SidePaneSlotRecipeVariant[
|
|
14
|
+
position?: import("../../styled-system/recipes").SidePaneSlotRecipeVariant['position'];
|
|
13
15
|
closeButtonProps?: {
|
|
14
16
|
isCollapseIcon?: boolean;
|
|
15
|
-
} & Pick<import("react").ComponentPropsWithoutRef<
|
|
17
|
+
} & Pick<import("react").ComponentPropsWithoutRef<'button'>, 'aria-label'>;
|
|
16
18
|
targetDOMNode?: HTMLElement | null;
|
|
17
19
|
enableModal?: boolean;
|
|
18
20
|
disableBackdropClose?: boolean;
|
|
19
21
|
enableAutoUnmount?: boolean;
|
|
20
|
-
formFooterProps?: Pick<import("..").FormFooterProps,
|
|
21
|
-
position?: import("..").FormFooterProps[
|
|
22
|
+
formFooterProps?: Pick<import("..").FormFooterProps, 'optionsSlot' | 'actionsSlot'> & {
|
|
23
|
+
position?: import("..").FormFooterProps['position'];
|
|
22
24
|
};
|
|
23
25
|
insideProps?: {
|
|
24
26
|
className?: string;
|
|
25
27
|
};
|
|
26
28
|
open?: boolean;
|
|
27
29
|
onClose?: import("./SidePane.types").OnCloseFunction;
|
|
28
|
-
} & Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "
|
|
29
|
-
ref?: (import("react").
|
|
30
|
+
} & Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "onClose" | "open"> & {
|
|
31
|
+
ref?: (import("react").RefCallback<HTMLDivElement | null> | import("react").RefObject<HTMLDivElement | null> | null) | undefined;
|
|
30
32
|
} & import("react").Attributes>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useCallback, useMemo } from 'react';
|
|
3
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
4
4
|
import { Close, PaneExpansionToRight, PaneExpansionToLeft } from '@moneyforward/mfui-icons-react';
|
|
5
5
|
import { cx } from '../../styled-system/css';
|
|
6
6
|
import { Heading } from '../Heading';
|
|
@@ -13,16 +13,20 @@ import { Portal, TargetDomNodeProvider, useAutomaticTargetDomNode } from '../Por
|
|
|
13
13
|
import { FormFooter } from '../FormFooter';
|
|
14
14
|
/**
|
|
15
15
|
* The general purpose SidePane component.
|
|
16
|
-
* This component extends the props of `<div>` element
|
|
16
|
+
* This component extends the props of `<div>` element. The extended props and `ref` are
|
|
17
|
+
* applied to the root overlay element covering the viewport, while `role="dialog"` (and
|
|
18
|
+
* `aria-modal="true"` when `enableModal` is set) are set on the inner pane window element.
|
|
17
19
|
*
|
|
18
20
|
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog
|
|
19
21
|
*/
|
|
20
22
|
export const SidePane = compatibleForwardRef(({ open, title, renderHeading, onClose, className, children, actionSlot, formFooterProps, position = 'right', enableModal = false, enableAutoUnmount = true, disableBackdropClose = false, closeButtonProps, targetDOMNode, insideProps, ...props }, ref) => {
|
|
21
23
|
const classes = sidePaneSlotRecipe({ position, nonModal: !enableModal });
|
|
24
|
+
const [insideElement, setInsideElement] = useState(null);
|
|
22
25
|
const { localOpen, handleCloseSidePane, handleStopCloseSidePane, sidePaneElement, setSidePaneElement } = useSidePaneStateController({
|
|
23
26
|
open,
|
|
24
27
|
onClose,
|
|
25
28
|
ref,
|
|
29
|
+
insideElement,
|
|
26
30
|
});
|
|
27
31
|
const handleBackdropClick = useCallback(() => {
|
|
28
32
|
if (!disableBackdropClose) {
|
|
@@ -56,8 +60,8 @@ export const SidePane = compatibleForwardRef(({ open, title, renderHeading, onCl
|
|
|
56
60
|
const shouldRenderContent = enableAutoUnmount ? localOpen : true;
|
|
57
61
|
const resolvedFormFooterPosition = formFooterProps?.position ?? 'sticky';
|
|
58
62
|
const headingNode = title ? (_jsx(Heading, { variant: "pageHeading2", tag: "h2", children: title })) : null;
|
|
59
|
-
return (_jsx(TargetDomNodeProvider, { targetDomNode: sidePaneElement, children: shouldRenderContent ? (_jsx(Portal, { targetDOMNode: targetElement, children: _jsxs("div", { ref: setSidePaneElement,
|
|
63
|
+
return (_jsx(TargetDomNodeProvider, { targetDomNode: sidePaneElement, children: shouldRenderContent ? (_jsx(Portal, { targetDOMNode: targetElement, children: _jsxs("div", { ref: setSidePaneElement, ...props, className: cx(classes.root, 'mfui-SidePane__root', className), style: {
|
|
60
64
|
...props.style,
|
|
61
65
|
...(!enableAutoUnmount && !localOpen && { display: 'none' }),
|
|
62
|
-
}, onKeyDown: handleOnKeyDown, children: [enableModal ? (_jsx("div", { "data-mfui-content": "backdrop", className: cx(classes.backdrop, 'mfui-SidePane__backdrop'), onClick: handleBackdropClick })) : null, _jsxs("div", { "data-mfui-content": "inside", className: cx(classes.inside, 'mfui-SidePane__inside', insideProps?.className), onClick: handleStopCloseSidePane, children: [_jsxs("header", { className: cx(classes.header, 'mfui-SidePane__header'), children: [renderHeading ? (renderHeading({ headingNode })) : (_jsx("div", { className: cx(classes.title, 'mfui-SidePane__title'), children: headingNode })), _jsxs("div", { className: cx(classes.actionSlotWrapper, 'mfui-SidePane__actionSlotWrapper'), children: [!!actionSlot && (_jsx("div", { className: cx(classes.actionSlot, 'mfui-SidePane__actionSlot'), children: actionSlot })), _jsx("div", { className: cx(classes.closeButtonWrapper, 'mfui-SidePane__closeButtonWrapper'), children: _jsx(IconButton, { "aria-label": closeButtonProps?.['aria-label'] ?? '閉じる', onClick: handleCloseSidePane, children: closeButtonIcon }) })] })] }), _jsxs("main", { className: cx(classes.content, 'mfui-SidePane__content'), children: [_jsx("div", { className: cx(classes.contentBody, 'mfui-SidePane__contentBody'), children: children }), resolvedFormFooterPosition === 'stacking' ? (_jsx("div", { className: cx(classes.footer, 'mfui-SidePane__footer'), children: _jsx(FormFooter, { sectionPosition: "fill", ...formFooterProps, position: resolvedFormFooterPosition }) })) : null] }), formFooterProps && resolvedFormFooterPosition !== 'stacking' ? (_jsx("div", { className: cx(classes.footer, 'mfui-SidePane__footer'), children: _jsx(FormFooter, { sectionPosition: "fill", ...formFooterProps, position: resolvedFormFooterPosition }) })) : null] })] }) })) : null }));
|
|
66
|
+
}, onKeyDown: handleOnKeyDown, children: [enableModal ? (_jsx("div", { "data-mfui-content": "backdrop", className: cx(classes.backdrop, 'mfui-SidePane__backdrop'), onClick: handleBackdropClick })) : null, _jsxs("div", { ref: setInsideElement, role: "dialog", "aria-modal": enableModal ? 'true' : undefined, tabIndex: -1, "data-mfui-content": "inside", className: cx(classes.inside, 'mfui-SidePane__inside', insideProps?.className), onClick: handleStopCloseSidePane, children: [_jsxs("header", { className: cx(classes.header, 'mfui-SidePane__header'), children: [renderHeading ? (renderHeading({ headingNode })) : (_jsx("div", { className: cx(classes.title, 'mfui-SidePane__title'), children: headingNode })), _jsxs("div", { className: cx(classes.actionSlotWrapper, 'mfui-SidePane__actionSlotWrapper'), children: [!!actionSlot && (_jsx("div", { className: cx(classes.actionSlot, 'mfui-SidePane__actionSlot'), children: actionSlot })), _jsx("div", { className: cx(classes.closeButtonWrapper, 'mfui-SidePane__closeButtonWrapper'), children: _jsx(IconButton, { "aria-label": closeButtonProps?.['aria-label'] ?? '閉じる', onClick: handleCloseSidePane, children: closeButtonIcon }) })] })] }), _jsxs("main", { className: cx(classes.content, 'mfui-SidePane__content'), children: [_jsx("div", { className: cx(classes.contentBody, 'mfui-SidePane__contentBody'), children: children }), resolvedFormFooterPosition === 'stacking' ? (_jsx("div", { className: cx(classes.footer, 'mfui-SidePane__footer'), children: _jsx(FormFooter, { sectionPosition: "fill", ...formFooterProps, position: resolvedFormFooterPosition }) })) : null] }), formFooterProps && resolvedFormFooterPosition !== 'stacking' ? (_jsx("div", { className: cx(classes.footer, 'mfui-SidePane__footer'), children: _jsx(FormFooter, { sectionPosition: "fill", ...formFooterProps, position: resolvedFormFooterPosition }) })) : null] })] }) })) : null }));
|
|
63
67
|
});
|
|
@@ -3,6 +3,7 @@ type UseSidePaneStateController = {
|
|
|
3
3
|
open?: boolean;
|
|
4
4
|
onClose?: () => void;
|
|
5
5
|
ref?: ForwardedRef<HTMLDivElement | null>;
|
|
6
|
+
insideElement?: HTMLElement | null;
|
|
6
7
|
};
|
|
7
8
|
/**
|
|
8
9
|
* Custom hook to control the open/close state of a SidePane.
|
|
@@ -15,9 +16,13 @@ type UseSidePaneStateController = {
|
|
|
15
16
|
*
|
|
16
17
|
* @param options.onClose - Callback function to execute when closing the SidePane.
|
|
17
18
|
*
|
|
18
|
-
* @
|
|
19
|
+
* @param options.insideElement - The pane window element with `role="dialog"`. It receives
|
|
20
|
+
* default focus when the SidePane opens, keeping focus inside the `aria-modal` boundary.
|
|
21
|
+
*
|
|
22
|
+
* @returns Object containing the local open state, close/click handlers, and a callback
|
|
23
|
+
* ref (`setSidePaneElement`) to attach to the root overlay element.
|
|
19
24
|
*/
|
|
20
|
-
export declare function useSidePaneStateController({ open, onClose, ref }: UseSidePaneStateController): {
|
|
25
|
+
export declare function useSidePaneStateController({ open, onClose, ref, insideElement }: UseSidePaneStateController): {
|
|
21
26
|
localOpen: boolean | undefined;
|
|
22
27
|
handleCloseSidePane: () => void;
|
|
23
28
|
handleStopCloseSidePane: (event: React.MouseEvent<HTMLDivElement>) => void;
|
|
@@ -12,9 +12,13 @@ import { useSidePaneOpenStateWithAnimation } from './useSidePaneOpenStateWithAni
|
|
|
12
12
|
*
|
|
13
13
|
* @param options.onClose - Callback function to execute when closing the SidePane.
|
|
14
14
|
*
|
|
15
|
-
* @
|
|
15
|
+
* @param options.insideElement - The pane window element with `role="dialog"`. It receives
|
|
16
|
+
* default focus when the SidePane opens, keeping focus inside the `aria-modal` boundary.
|
|
17
|
+
*
|
|
18
|
+
* @returns Object containing the local open state, close/click handlers, and a callback
|
|
19
|
+
* ref (`setSidePaneElement`) to attach to the root overlay element.
|
|
16
20
|
*/
|
|
17
|
-
export function useSidePaneStateController({ open, onClose, ref }) {
|
|
21
|
+
export function useSidePaneStateController({ open, onClose, ref, insideElement }) {
|
|
18
22
|
const [sidePaneElement, setSidePaneElement] = useState(null);
|
|
19
23
|
const { localOpen, openSidePane, closeSidePane } = useSidePaneOpenStateWithAnimation({ open, sidePaneElement });
|
|
20
24
|
const setSidePaneElementRef = useCallback((element) => {
|
|
@@ -49,12 +53,14 @@ export function useSidePaneStateController({ open, onClose, ref }) {
|
|
|
49
53
|
const handleStopCloseSidePane = useCallback((event) => {
|
|
50
54
|
event.stopPropagation();
|
|
51
55
|
}, []);
|
|
52
|
-
// Autofocus to the
|
|
56
|
+
// Autofocus to the pane window (`role="dialog"` element) when it opens.
|
|
57
|
+
// Screen readers honor `aria-modal` only when focus is on the `role="dialog"`
|
|
58
|
+
// element or its descendants, so the root wrapper must not be the focus target.
|
|
53
59
|
useEffect(() => {
|
|
54
60
|
if (!localOpen)
|
|
55
61
|
return;
|
|
56
|
-
sidePaneElement?.focus();
|
|
57
|
-
}, [sidePaneElement, localOpen]);
|
|
62
|
+
(insideElement ?? sidePaneElement)?.focus();
|
|
63
|
+
}, [insideElement, sidePaneElement, localOpen]);
|
|
58
64
|
return {
|
|
59
65
|
localOpen,
|
|
60
66
|
handleCloseSidePane,
|
|
@@ -2,8 +2,9 @@ import { type SidebarProps } from './Sidebar.types';
|
|
|
2
2
|
import { SidebarServiceMenu } from './SidebarServiceMenu';
|
|
3
3
|
import { SidebarTenantMenu } from './SidebarTenantMenu';
|
|
4
4
|
import { SidebarUserMenu } from './SidebarUserMenu';
|
|
5
|
+
import { SidebarTenantMenuHeading, SidebarUserMenuHeading } from './SidebarMenuHeading';
|
|
5
6
|
import { SidebarNavigationItem } from './SidebarNavigationItem';
|
|
6
|
-
declare function SidebarBase({ className, logoSlot, mainNavigationItems, extraNavigationSlot, footerSlot, serviceMenuSlot, footerIconMenuSlot, tenantSlot, userSlot, minWidth, maxWidth, defaultWidth, onWidthChange, mainNavigationLabel, extraNavigationLabel, resizeHandleLabel, }: SidebarProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
declare function SidebarBase({ className, logoSlot, mainNavigationItems, extraNavigationSlot, footerSlot, serviceMenuSlot, footerIconMenuSlot, tenantSlot, userSlot, minWidth, maxWidth, defaultWidth, onWidthChange, enableCollapsible, isCollapsed: controlledIsCollapsed, onCollapsedChange, collapseButtonLabel, expandButtonLabel, mainNavigationLabel, extraNavigationLabel, resizeHandleLabel, }: SidebarProps): import("react/jsx-runtime").JSX.Element;
|
|
7
8
|
/**
|
|
8
9
|
* The sidebar component.
|
|
9
10
|
* A navigation layout component that combines a logo header, a navigation area,
|
|
@@ -20,6 +21,10 @@ declare function SidebarBase({ className, logoSlot, mainNavigationItems, extraNa
|
|
|
20
21
|
* - `Sidebar.ServiceMenu` — the header service menu trigger, intended to wrap a list of services.
|
|
21
22
|
* - `Sidebar.TenantMenu` — the footer tenant (business) name and its menu.
|
|
22
23
|
* - `Sidebar.UserMenu` — the footer user (account) name and its menu.
|
|
24
|
+
* - `Sidebar.TenantMenuHeading` — the heading block inside `Sidebar.TenantMenu`: the tenant name and
|
|
25
|
+
* its identification-number row (optionally copyable to the clipboard).
|
|
26
|
+
* - `Sidebar.UserMenuHeading` — the heading block inside `Sidebar.UserMenu`: the user name and
|
|
27
|
+
* its identification-number row (optionally copyable to the clipboard).
|
|
23
28
|
*
|
|
24
29
|
* @example
|
|
25
30
|
* ```tsx
|
|
@@ -59,5 +64,9 @@ export declare const Sidebar: typeof SidebarBase & {
|
|
|
59
64
|
TenantMenu: typeof SidebarTenantMenu;
|
|
60
65
|
/** @see {@link SidebarUserMenu} */
|
|
61
66
|
UserMenu: typeof SidebarUserMenu;
|
|
67
|
+
/** @see {@link SidebarTenantMenuHeading} */
|
|
68
|
+
TenantMenuHeading: typeof SidebarTenantMenuHeading;
|
|
69
|
+
/** @see {@link SidebarUserMenuHeading} */
|
|
70
|
+
UserMenuHeading: typeof SidebarUserMenuHeading;
|
|
62
71
|
};
|
|
63
72
|
export {};
|
|
@@ -1,28 +1,50 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { SidebarController } from '@moneyforward/mfui-icons-react';
|
|
4
|
+
import { useId, useMemo, useState } from 'react';
|
|
3
5
|
import { cx } from '../../styled-system/css';
|
|
4
6
|
import { sidebarSlotRecipe } from '../../styled-system/recipes';
|
|
7
|
+
import { IconButton } from '../IconButton';
|
|
8
|
+
import { Tooltip } from '../Tooltip';
|
|
5
9
|
import { SidebarServiceMenu } from './SidebarServiceMenu';
|
|
6
10
|
import { SidebarTenantMenu } from './SidebarTenantMenu';
|
|
7
11
|
import { SidebarUserMenu } from './SidebarUserMenu';
|
|
12
|
+
import { SidebarTenantMenuHeading, SidebarUserMenuHeading } from './SidebarMenuHeading';
|
|
8
13
|
import { SidebarNavigationItem } from './SidebarNavigationItem';
|
|
14
|
+
import { SidebarContext } from './SidebarContext';
|
|
9
15
|
import { useSidebarResize } from './hooks/useSidebarResize';
|
|
10
|
-
function SidebarBase({ className, logoSlot, mainNavigationItems, extraNavigationSlot, footerSlot, serviceMenuSlot, footerIconMenuSlot, tenantSlot, userSlot, minWidth, maxWidth, defaultWidth, onWidthChange, mainNavigationLabel = 'メインナビゲーション', extraNavigationLabel = '追加ナビゲーション', resizeHandleLabel = 'サイドバーの幅を調整', }) {
|
|
16
|
+
function SidebarBase({ className, logoSlot, mainNavigationItems, extraNavigationSlot, footerSlot, serviceMenuSlot, footerIconMenuSlot, tenantSlot, userSlot, minWidth, maxWidth, defaultWidth, onWidthChange, enableCollapsible = false, isCollapsed: controlledIsCollapsed, onCollapsedChange, collapseButtonLabel = 'ナビゲーションを折りたたむ', expandButtonLabel = 'ナビゲーションを拡げる', mainNavigationLabel = 'メインナビゲーション', extraNavigationLabel = '追加ナビゲーション', resizeHandleLabel = 'サイドバーの幅を調整', }) {
|
|
17
|
+
const [localIsCollapsed, setLocalIsCollapsed] = useState(controlledIsCollapsed ?? false);
|
|
18
|
+
const isControlled = controlledIsCollapsed !== undefined;
|
|
19
|
+
const isCollapsed = enableCollapsible ? (isControlled ? controlledIsCollapsed : localIsCollapsed) : false;
|
|
20
|
+
const navId = useId();
|
|
11
21
|
const classes = sidebarSlotRecipe();
|
|
12
22
|
const { width, minWidth: resolvedMinWidth, maxWidth: resolvedMaxWidth, rootRef, isDragging, handlePointerDown, handleKeyDown, } = useSidebarResize({
|
|
13
23
|
minWidth,
|
|
14
24
|
maxWidth,
|
|
15
25
|
defaultWidth,
|
|
16
26
|
onWidthChange,
|
|
27
|
+
isCollapsed,
|
|
17
28
|
});
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
const hasMainNavigation = !!mainNavigationItems?.length;
|
|
30
|
+
const toggleButtonLabel = isCollapsed ? expandButtonLabel : collapseButtonLabel;
|
|
31
|
+
const contextValue = useMemo(() => ({ isCollapsed }), [isCollapsed]);
|
|
32
|
+
const handleToggle = () => {
|
|
33
|
+
const next = !isCollapsed;
|
|
34
|
+
if (!isControlled) {
|
|
35
|
+
setLocalIsCollapsed(next);
|
|
36
|
+
}
|
|
37
|
+
onCollapsedChange?.(next);
|
|
38
|
+
};
|
|
39
|
+
return (_jsx(SidebarContext.Provider, { value: contextValue, children: _jsxs("div", { ref: rootRef, className: cx(classes.root, 'mfui-Sidebar__root', className), style: { width: `${String(width)}px` }, "data-mfui-collapsed": isCollapsed ? true : undefined, "data-mfui-dragging": isDragging ? true : undefined, children: [_jsxs("header", { className: cx(classes.header, 'mfui-Sidebar__header'), children: [_jsx("div", { className: cx(classes.leftPane, 'mfui-Sidebar__leftPane'), children: !isCollapsed ? (_jsxs(_Fragment, { children: [serviceMenuSlot ? (_jsx("div", { className: cx(classes.serviceMenu, 'mfui-Sidebar__serviceMenu'), children: serviceMenuSlot })) : null, _jsx("div", { className: cx(classes.logo, 'mfui-Sidebar__logo'), children: logoSlot })] })) : null }), enableCollapsible ? (_jsx("div", { className: cx(classes.rightPane, 'mfui-Sidebar__rightPane'), children: _jsx(SidebarToggleButton, { isCollapsed: isCollapsed, ariaLabel: toggleButtonLabel, navId: hasMainNavigation ? navId : undefined, onClick: handleToggle }) })) : null] }), _jsxs("div", { className: cx(classes.navigationWrapper, 'mfui-Sidebar__navigationWrapper'), children: [hasMainNavigation ? (_jsx("nav", { id: navId, "aria-label": mainNavigationLabel, className: cx(classes.mainNavigation, 'mfui-Sidebar__mainNavigation'), children: _jsx("ul", { className: cx(classes.navigationList, 'mfui-Sidebar__navigationList'), children: mainNavigationItems.map((item, index) => {
|
|
40
|
+
if ('type' in item) {
|
|
41
|
+
return (_jsx("li", { "aria-hidden": "true", className: cx(classes.navigationDivider, 'mfui-Sidebar__navigationDivider') }, index));
|
|
42
|
+
}
|
|
43
|
+
return _jsx(SidebarNavigationItem, { ...item }, index);
|
|
44
|
+
}) }) })) : null, extraNavigationSlot ? (_jsx("nav", { "aria-label": extraNavigationLabel, className: cx(classes.extraNavigation, 'mfui-Sidebar__extraNavigation'), children: extraNavigationSlot })) : null] }), _jsxs("div", { className: cx(classes.footer, 'mfui-Sidebar__footer'), children: [footerSlot ? _jsx("div", { className: cx(classes.footerSlot, 'mfui-Sidebar__footerSlot'), children: footerSlot }) : null, _jsx("div", { className: cx(classes.footerIconMenu, 'mfui-Sidebar__footerIconMenu'), children: typeof footerIconMenuSlot === 'function' ? footerIconMenuSlot({ isCollapsed }) : footerIconMenuSlot }), !isCollapsed && (tenantSlot || userSlot) ? (_jsxs("div", { className: cx(classes.footerUserIdMenu, 'mfui-Sidebar__footerUserIdMenu'), children: [tenantSlot ? (_jsx("div", { className: cx(classes.footerUserIdMenuItem, 'mfui-Sidebar__footerUserIdMenuItem'), children: tenantSlot })) : null, userSlot ? (_jsx("div", { className: cx(classes.footerUserIdMenuItem, 'mfui-Sidebar__footerUserIdMenuItem'), children: userSlot })) : null] })) : null] }), _jsx("div", { "data-mfui-handle": true, "data-mfui-dragging": isDragging ? true : undefined, "data-mfui-collapsed": isCollapsed ? true : undefined, role: isCollapsed ? undefined : 'separator', "aria-orientation": isCollapsed ? undefined : 'vertical', "aria-label": isCollapsed ? undefined : resizeHandleLabel, "aria-valuenow": isCollapsed ? undefined : width, "aria-valuemin": isCollapsed ? undefined : resolvedMinWidth, "aria-valuemax": isCollapsed ? undefined : resolvedMaxWidth, tabIndex: isCollapsed ? -1 : 0, className: cx(classes.handle, 'mfui-Sidebar__handle'), onPointerDown: handlePointerDown, onKeyDown: handleKeyDown })] }) }));
|
|
45
|
+
}
|
|
46
|
+
function SidebarToggleButton({ isCollapsed, ariaLabel, navId, onClick, }) {
|
|
47
|
+
return (_jsx(Tooltip, { content: ariaLabel, placement: isCollapsed ? 'right' : 'bottom', children: _jsx(IconButton, { "aria-pressed": !isCollapsed, "aria-controls": navId, "aria-label": ariaLabel, className: "mfui-Sidebar__toggleButton", onClick: onClick, children: _jsx(SidebarController, { "aria-hidden": true }) }) }));
|
|
26
48
|
}
|
|
27
49
|
/**
|
|
28
50
|
* The sidebar component.
|
|
@@ -40,6 +62,10 @@ function SidebarBase({ className, logoSlot, mainNavigationItems, extraNavigation
|
|
|
40
62
|
* - `Sidebar.ServiceMenu` — the header service menu trigger, intended to wrap a list of services.
|
|
41
63
|
* - `Sidebar.TenantMenu` — the footer tenant (business) name and its menu.
|
|
42
64
|
* - `Sidebar.UserMenu` — the footer user (account) name and its menu.
|
|
65
|
+
* - `Sidebar.TenantMenuHeading` — the heading block inside `Sidebar.TenantMenu`: the tenant name and
|
|
66
|
+
* its identification-number row (optionally copyable to the clipboard).
|
|
67
|
+
* - `Sidebar.UserMenuHeading` — the heading block inside `Sidebar.UserMenu`: the user name and
|
|
68
|
+
* its identification-number row (optionally copyable to the clipboard).
|
|
43
69
|
*
|
|
44
70
|
* @example
|
|
45
71
|
* ```tsx
|
|
@@ -79,4 +105,8 @@ export const Sidebar = Object.assign(SidebarBase, {
|
|
|
79
105
|
TenantMenu: SidebarTenantMenu,
|
|
80
106
|
/** @see {@link SidebarUserMenu} */
|
|
81
107
|
UserMenu: SidebarUserMenu,
|
|
108
|
+
/** @see {@link SidebarTenantMenuHeading} */
|
|
109
|
+
TenantMenuHeading: SidebarTenantMenuHeading,
|
|
110
|
+
/** @see {@link SidebarUserMenuHeading} */
|
|
111
|
+
UserMenuHeading: SidebarUserMenuHeading,
|
|
82
112
|
});
|
|
@@ -54,6 +54,12 @@ export type SidebarNavigationDivider = {
|
|
|
54
54
|
type: 'divider';
|
|
55
55
|
};
|
|
56
56
|
export type SidebarNavigationEntry = SidebarNavigationItem | SidebarNavigationDivider;
|
|
57
|
+
export type SidebarFooterIconMenuSlotState = {
|
|
58
|
+
/**
|
|
59
|
+
* Whether the sidebar is currently collapsed.
|
|
60
|
+
*/
|
|
61
|
+
isCollapsed: boolean;
|
|
62
|
+
};
|
|
57
63
|
export type SidebarProps = {
|
|
58
64
|
/**
|
|
59
65
|
* Additional class names to apply to the component.
|
|
@@ -85,9 +91,10 @@ export type SidebarProps = {
|
|
|
85
91
|
serviceMenuSlot: ReactNode;
|
|
86
92
|
/**
|
|
87
93
|
* Elements to be displayed in the footer icon menu area.
|
|
88
|
-
*
|
|
94
|
+
* Pass a function to adapt the content to the current collapsed state, such as switching tooltip placement.
|
|
95
|
+
* The plain node form still works for static content.
|
|
89
96
|
*/
|
|
90
|
-
footerIconMenuSlot: ReactNode;
|
|
97
|
+
footerIconMenuSlot: ReactNode | ((state: SidebarFooterIconMenuSlotState) => ReactNode);
|
|
91
98
|
/**
|
|
92
99
|
* Elements to be displayed below the footer icon menu.
|
|
93
100
|
* Intended for the tenant (business) name and its menu.
|
|
@@ -121,6 +128,36 @@ export type SidebarProps = {
|
|
|
121
128
|
* Use this to persist the value in your own storage (e.g. via an API call).
|
|
122
129
|
*/
|
|
123
130
|
onWidthChange: (width: number) => void;
|
|
131
|
+
/**
|
|
132
|
+
* Whether the sidebar can be collapsed to an icon-only rail.
|
|
133
|
+
* When `true`, a toggle button is rendered in the header.
|
|
134
|
+
*
|
|
135
|
+
* @default false
|
|
136
|
+
*/
|
|
137
|
+
enableCollapsible?: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* The collapsed state of the sidebar (controlled).
|
|
140
|
+
* When provided, the component behaves as a controlled component.
|
|
141
|
+
* Only effective when `enableCollapsible` is `true`.
|
|
142
|
+
*/
|
|
143
|
+
isCollapsed?: boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Called when the collapse toggle is clicked with the new collapsed state.
|
|
146
|
+
* Only called when `enableCollapsible` is `true`.
|
|
147
|
+
*/
|
|
148
|
+
onCollapsedChange?: (isCollapsed: boolean) => void;
|
|
149
|
+
/**
|
|
150
|
+
* Accessible name for the toggle button when expanded (clicking will collapse).
|
|
151
|
+
*
|
|
152
|
+
* @default 'ナビゲーションを折りたたむ'
|
|
153
|
+
*/
|
|
154
|
+
collapseButtonLabel?: string;
|
|
155
|
+
/**
|
|
156
|
+
* Accessible name for the toggle button when collapsed (clicking will expand).
|
|
157
|
+
*
|
|
158
|
+
* @default 'ナビゲーションを拡げる'
|
|
159
|
+
*/
|
|
160
|
+
expandButtonLabel?: string;
|
|
124
161
|
/**
|
|
125
162
|
* The accessible name for the primary navigation landmark.
|
|
126
163
|
*
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type SidebarTenantMenuHeadingProps, type SidebarUserMenuHeadingProps } from './SidebarMenuHeading.types';
|
|
2
|
+
/**
|
|
3
|
+
* The heading block of the Sidebar tenant menu: the tenant name heading and the
|
|
4
|
+
* identification-number row. Place it as the first child of `Sidebar.TenantMenu`.
|
|
5
|
+
*
|
|
6
|
+
* Pass the `copy` prop to make the identification-number row copy its value to the clipboard,
|
|
7
|
+
* with a tooltip and a screen-reader announcement. The feedback after copying reads `コピーしました`
|
|
8
|
+
* by default and can be changed via `copy.copiedLabel`. Without `copy`, the row is static text.
|
|
9
|
+
*
|
|
10
|
+
* @param props - The props of the `Sidebar.TenantMenuHeading` component.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* <Sidebar.TenantMenu name="株式会社サンプル" tooltipLabel="事業者">
|
|
15
|
+
* <Sidebar.TenantMenuHeading
|
|
16
|
+
* name="株式会社サンプル"
|
|
17
|
+
* identificationNumber="事業者番号:0123-4567"
|
|
18
|
+
* copy={{ text: '0123-4567', label: '事業者番号をコピーする' }}
|
|
19
|
+
* />
|
|
20
|
+
* <DropdownMenu.Divider />
|
|
21
|
+
* <DropdownMenu.Item href="https://example.com">事業者設定</DropdownMenu.Item>
|
|
22
|
+
* </Sidebar.TenantMenu>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function SidebarTenantMenuHeading(props: SidebarTenantMenuHeadingProps): import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
/**
|
|
27
|
+
* The heading block of the Sidebar user menu: the user (account) name heading and the
|
|
28
|
+
* identification-number row. Place it as the first child of `Sidebar.UserMenu`.
|
|
29
|
+
*
|
|
30
|
+
* Pass the `copy` prop to make the identification-number row copy its value to the clipboard,
|
|
31
|
+
* with a tooltip and a screen-reader announcement. The feedback after copying reads `コピーしました`
|
|
32
|
+
* by default and can be changed via `copy.copiedLabel`. Without `copy`, the row is static text.
|
|
33
|
+
*
|
|
34
|
+
* @param props - The props of the `Sidebar.UserMenuHeading` component.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```tsx
|
|
38
|
+
* <Sidebar.UserMenu name="山田 太郎" tooltipLabel="アカウント">
|
|
39
|
+
* <Sidebar.UserMenuHeading
|
|
40
|
+
* name="山田 太郎"
|
|
41
|
+
* identificationNumber="従業員番号:1234"
|
|
42
|
+
* copy={{ text: '1234', label: '従業員番号をコピーする' }}
|
|
43
|
+
* />
|
|
44
|
+
* <DropdownMenu.Divider />
|
|
45
|
+
* <DropdownMenu.Item onClick={handleLogout}>ログアウト</DropdownMenu.Item>
|
|
46
|
+
* </Sidebar.UserMenu>
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function SidebarUserMenuHeading(props: SidebarUserMenuHeadingProps): import("react/jsx-runtime").JSX.Element;
|