@moneyforward/mfui-components 4.3.1 → 4.5.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.
- package/dist/src/Accordion/Accordion.d.ts +21 -1
- package/dist/src/Accordion/Accordion.js +28 -4
- package/dist/src/Accordion/Accordion.types.d.ts +21 -0
- package/dist/src/Breadcrumbs/Breadcrumbs.js +1 -1
- package/dist/src/CheckboxCard/CheckboxCard.js +3 -1
- package/dist/src/DataTable/DataTable.js +9 -2
- package/dist/src/DataTable/DataTable.types.d.ts +15 -0
- package/dist/src/DataTable/DataTableHeaderRow/DataTableHeaderRow.js +3 -1
- package/dist/src/DataTable/DataTableHeaderRow/DataTableHeaderRow.types.d.ts +19 -1
- package/dist/src/DataTable/DataTableRow/DataTableRow.js +4 -1
- package/dist/src/DataTable/DataTableRow/DataTableRow.types.d.ts +23 -1
- package/dist/src/DateTimeSelection/DatePicker/DatePickerDateCell/index.d.ts +1 -1
- package/dist/src/DateTimeSelection/DatePicker/DatePickerDateCell/index.js +0 -1
- package/dist/src/DateTimeSelection/shared/CalendarGrid/CalendarGrid.js +1 -3
- package/dist/src/Dialog/Dialog.d.ts +1 -1
- package/dist/src/Dialog/Dialog.types.d.ts +1 -1
- package/dist/src/MainNavigation/BaseMainNavigation.d.ts +1 -1
- package/dist/src/MainNavigation/BaseMainNavigation.js +2 -2
- package/dist/src/MainNavigation/MainNavigation.js +2 -1
- package/dist/src/MainNavigation/MainNavigation.types.d.ts +9 -0
- package/dist/src/MainNavigation/NarrowViewportMainNavigation.js +2 -2
- package/dist/src/MultipleSelectBox/MultipleSelectBox.js +27 -18
- package/dist/src/MultipleSelectBox/hooks/useInitialFocusOnOptionPanelOpen.js +1 -1
- package/dist/src/NavigationList/NavigationListItem/NavigationListItem.d.ts +3 -0
- package/dist/src/NavigationList/NavigationListItem/NavigationListItem.js +6 -2
- package/dist/src/NavigationList/NavigationListItem/NavigationListItem.types.d.ts +2 -1
- package/dist/src/NumberBox/NumberBox.d.ts +5 -0
- package/dist/src/NumberBox/NumberBox.js +53 -2
- package/dist/src/NumberBox/NumberBox.types.d.ts +35 -0
- package/dist/src/Pagination/Pagination.js +4 -1
- package/dist/src/Popover/Popover.js +1 -2
- package/dist/src/RadioButtonCard/RadioButtonCard.js +3 -1
- package/dist/src/SelectBox/SelectBox.js +20 -11
- package/dist/src/SelectBox/utils/getFlatOptions.js +1 -1
- package/dist/src/SidePane/SidePane.js +87 -7
- package/dist/src/SidePane/SidePane.types.d.ts +39 -0
- package/dist/src/SubNavigation/SubNavigation.d.ts +10 -1
- package/dist/src/SubNavigation/SubNavigation.js +14 -3
- package/dist/src/SubNavigation/SubNavigation.types.d.ts +27 -1
- package/dist/src/Tabs/hooks/useTabRegistry.js +5 -5
- package/dist/src/ToggleSwitch/index.d.ts +1 -1
- package/dist/src/ToggleSwitch/index.js +0 -1
- package/dist/src/utilities/dom/containsAcrossShadowRoots.d.ts +21 -0
- package/dist/src/utilities/dom/containsAcrossShadowRoots.js +33 -0
- package/dist/src/utilities/dom/useFocusTrap.js +1 -1
- package/dist/src/utilities/dom/useTableEdgeCellMarkers.d.ts +56 -0
- package/dist/src/utilities/dom/useTableEdgeCellMarkers.js +223 -0
- package/dist/styled-system/recipes/data-table-cell-slot-recipe.js +4 -2
- package/dist/styles.css +20 -4
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- /package/dist/src/{MultipleSelectBox/utils → utilities/dom}/getDeepActiveElement.d.ts +0 -0
- /package/dist/src/{MultipleSelectBox/utils → utilities/dom}/getDeepActiveElement.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type AccordionProps, type AccordionItemProps } from './Accordion.types';
|
|
2
2
|
declare function AccordionBase({ children, size, width, defaultOpenItems }: AccordionProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
-
declare function AccordionItem({ children, id, enableAutoUnmount }: AccordionItemProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
declare function AccordionItem({ children, id, enableAutoUnmount, open, onOpenStateChanged }: AccordionItemProps): import("react/jsx-runtime").JSX.Element;
|
|
4
4
|
/**
|
|
5
5
|
* The `Accordion` component.
|
|
6
6
|
*
|
|
@@ -24,6 +24,26 @@ declare function AccordionItem({ children, id, enableAutoUnmount }: AccordionIte
|
|
|
24
24
|
* </Accordion.Item>
|
|
25
25
|
* </Accordion>
|
|
26
26
|
* ```
|
|
27
|
+
*
|
|
28
|
+
* Each `Accordion.Item` can also be controlled with the `open` and `onOpenStateChanged` props, which lets a trigger
|
|
29
|
+
* outside the Accordion tree drive it. In that case you own the `aria-expanded` and `aria-controls` attributes of
|
|
30
|
+
* your own trigger, and `enableAutoUnmount={false}` keeps the collapsed content mounted.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```jsx
|
|
34
|
+
* const [isOpen, setIsOpen] = useState(false);
|
|
35
|
+
*
|
|
36
|
+
* <>
|
|
37
|
+
* <button type="button" aria-expanded={isOpen} aria-controls="accordion-1" onClick={() => setIsOpen(!isOpen)}>
|
|
38
|
+
* Toggle
|
|
39
|
+
* </button>
|
|
40
|
+
* <Accordion>
|
|
41
|
+
* <Accordion.Item id="accordion-1" open={isOpen} enableAutoUnmount={false}>
|
|
42
|
+
* <Accordion.Target>Content for section 1</Accordion.Target>
|
|
43
|
+
* </Accordion.Item>
|
|
44
|
+
* </Accordion>
|
|
45
|
+
* </>
|
|
46
|
+
* ```
|
|
27
47
|
*/
|
|
28
48
|
export declare const Accordion: typeof AccordionBase & {
|
|
29
49
|
/**
|
|
@@ -41,12 +41,16 @@ function AccordionBase({ children, size = 'medium', width, defaultOpenItems = []
|
|
|
41
41
|
};
|
|
42
42
|
return (_jsx("div", { style: containerStyle, children: _jsx(AccordionContext.Provider, { value: contextValue, children: children }) }));
|
|
43
43
|
}
|
|
44
|
-
function AccordionItem({ children, id, enableAutoUnmount = true }) {
|
|
44
|
+
function AccordionItem({ children, id, enableAutoUnmount = true, open, onOpenStateChanged }) {
|
|
45
45
|
const { openItems, toggleItem } = useAccordionContext();
|
|
46
|
-
const
|
|
46
|
+
const isControlled = open !== undefined;
|
|
47
|
+
const isOpen = open ?? openItems[id] ?? false;
|
|
47
48
|
const toggle = useCallback(() => {
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
if (!isControlled) {
|
|
50
|
+
toggleItem(id);
|
|
51
|
+
}
|
|
52
|
+
onOpenStateChanged?.(!isOpen);
|
|
53
|
+
}, [isControlled, toggleItem, id, onOpenStateChanged, isOpen]);
|
|
50
54
|
const contextValue = useMemo(() => ({
|
|
51
55
|
isOpen,
|
|
52
56
|
toggle,
|
|
@@ -100,6 +104,26 @@ const AccordionTarget = forwardRef(({ children, className, style, ...props }, re
|
|
|
100
104
|
* </Accordion.Item>
|
|
101
105
|
* </Accordion>
|
|
102
106
|
* ```
|
|
107
|
+
*
|
|
108
|
+
* Each `Accordion.Item` can also be controlled with the `open` and `onOpenStateChanged` props, which lets a trigger
|
|
109
|
+
* outside the Accordion tree drive it. In that case you own the `aria-expanded` and `aria-controls` attributes of
|
|
110
|
+
* your own trigger, and `enableAutoUnmount={false}` keeps the collapsed content mounted.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```jsx
|
|
114
|
+
* const [isOpen, setIsOpen] = useState(false);
|
|
115
|
+
*
|
|
116
|
+
* <>
|
|
117
|
+
* <button type="button" aria-expanded={isOpen} aria-controls="accordion-1" onClick={() => setIsOpen(!isOpen)}>
|
|
118
|
+
* Toggle
|
|
119
|
+
* </button>
|
|
120
|
+
* <Accordion>
|
|
121
|
+
* <Accordion.Item id="accordion-1" open={isOpen} enableAutoUnmount={false}>
|
|
122
|
+
* <Accordion.Target>Content for section 1</Accordion.Target>
|
|
123
|
+
* </Accordion.Item>
|
|
124
|
+
* </Accordion>
|
|
125
|
+
* </>
|
|
126
|
+
* ```
|
|
103
127
|
*/
|
|
104
128
|
export const Accordion = Object.assign(AccordionBase, {
|
|
105
129
|
/**
|
|
@@ -42,6 +42,27 @@ export type AccordionItemProps = {
|
|
|
42
42
|
* @default true
|
|
43
43
|
*/
|
|
44
44
|
enableAutoUnmount?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* The open state of this accordion item.
|
|
47
|
+
* You only need to use this prop if you want to control the item programmatically, for example when the trigger
|
|
48
|
+
* lives outside the Accordion tree. While this prop is defined, it takes precedence over the `defaultOpenItems` of
|
|
49
|
+
* the Accordion and over the internal state, so you have to update it yourself in response to
|
|
50
|
+
* `onOpenStateChanged`. Supply it consistently: do not switch an item between controlled and uncontrolled.
|
|
51
|
+
*
|
|
52
|
+
* When you drive the item from your own trigger outside the Accordion, you own its `aria-expanded` and
|
|
53
|
+
* `aria-controls` attributes. `Accordion.Target` renders the item `id` as its DOM `id`, so
|
|
54
|
+
* `aria-controls={id}` points at it. Note that with the default `enableAutoUnmount` the target is unmounted
|
|
55
|
+
* while collapsed, so `aria-controls` refers to an element that does not exist yet; set
|
|
56
|
+
* `enableAutoUnmount={false}` to keep the target in the DOM.
|
|
57
|
+
*/
|
|
58
|
+
open?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Callback fired when the open state of this accordion item is toggled by `Accordion.Trigger`.
|
|
61
|
+
* It is called in both controlled and uncontrolled mode.
|
|
62
|
+
*
|
|
63
|
+
* @param open - The new open state of the accordion item.
|
|
64
|
+
*/
|
|
65
|
+
onOpenStateChanged?: (open: boolean) => void;
|
|
45
66
|
};
|
|
46
67
|
/**
|
|
47
68
|
* Props for the Accordion.Trigger component
|
|
@@ -102,7 +102,7 @@ export const Breadcrumbs = forwardRef(({ items, wrap = false, customLinkComponen
|
|
|
102
102
|
if (wrap || !listRef.current)
|
|
103
103
|
return;
|
|
104
104
|
const observer = new ResizeObserver((entries) => {
|
|
105
|
-
const entry = entries
|
|
105
|
+
const [entry] = entries;
|
|
106
106
|
if (entry) {
|
|
107
107
|
setContainerWidth(entry.contentRect.width);
|
|
108
108
|
}
|
|
@@ -29,5 +29,7 @@ export const CheckboxCard = forwardRef(({ label, layout = 'vertical', renderDeta
|
|
|
29
29
|
disableResponsive,
|
|
30
30
|
isResponsive: Boolean(responsiveSlot.narrowViewport),
|
|
31
31
|
});
|
|
32
|
-
return (_jsxs("div", { className: cx(classes.root, 'mfui-CheckboxCard__root', className), children: [_jsx(FocusIndicator, { disableNestedFocus: true, children: _jsxs(Typography, { variant: "label", className: cx(classes.inputWrapper, 'mfui-CheckboxCard__inputWrapper'), as: "label", htmlFor: props.id, children: [_jsx(Checkbox, { ref: ref, ...props, className: cx(classes.input, 'mfui-CheckboxCard__input') }), _jsx("span", { className: cx(classes.label, 'mfui-CheckboxCard__label'), children: label })] }) }), responsiveSlot.narrowViewport
|
|
32
|
+
return (_jsxs("div", { className: cx(classes.root, 'mfui-CheckboxCard__root', className), children: [_jsx(FocusIndicator, { disableNestedFocus: true, children: _jsxs(Typography, { variant: "label", className: cx(classes.inputWrapper, 'mfui-CheckboxCard__inputWrapper'), as: "label", htmlFor: props.id, children: [_jsx(Checkbox, { ref: ref, ...props, className: cx(classes.input, 'mfui-CheckboxCard__input') }), _jsx("span", { className: cx(classes.label, 'mfui-CheckboxCard__label'), children: label })] }) }), responsiveSlot.narrowViewport ? (_jsxs(_Fragment, { children: [_jsx("div", { "data-mfui-content": "details", className: cx(classes.details, classes.detailsWide, 'mfui-CheckboxCard__details'), children: responsiveSlot.base(checkboxState) }), _jsx("div", { "data-mfui-content": "details", className: cx(classes.details, classes.detailsNarrow, 'mfui-CheckboxCard__details'), children: responsiveSlot.narrowViewport(checkboxState) })] })) : (
|
|
33
|
+
/* For function-based renderDetailsSlot or ResponsiveSlot with only base, use single details element */
|
|
34
|
+
responsiveSlot.base && (_jsx("div", { "data-mfui-content": "details", className: cx(classes.details, 'mfui-CheckboxCard__details'), children: responsiveSlot.base(checkboxState) })))] }));
|
|
33
35
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Children, isValidElement, useMemo, forwardRef } from 'react';
|
|
3
|
+
import { Children, isValidElement, useMemo, useRef, forwardRef } from 'react';
|
|
4
4
|
import { DataTableProvider } from './DataTableProvider';
|
|
5
5
|
import { dataTableSlotRecipe } from '../../styled-system/recipes';
|
|
6
6
|
import { DataTableBody } from './DataTableBody';
|
|
@@ -13,8 +13,15 @@ import { DataTableRow } from './DataTableRow';
|
|
|
13
13
|
import { DataTableSortButton } from './DataTableSortButton';
|
|
14
14
|
import { cx } from '../../styled-system/css';
|
|
15
15
|
import { isComponentOrWrapped } from '../utilities/react/isComponentOrWrapped';
|
|
16
|
+
import { mergeRefs } from '../utilities/dom/mergeRefs';
|
|
17
|
+
import { useTableEdgeCellMarkers } from '../utilities/dom/useTableEdgeCellMarkers';
|
|
16
18
|
const Base = forwardRef(({ className, size = 'medium', enableRowSelection = false, enableRowClickSelection = false, fixedHeader = false, showVerticalBorder = false, leftFixedColumnIndex, rightFixedColumnIndex, layout = 'default', wrapperProps, loading = false, emptyStateSlot, children, ...props }, ref) => {
|
|
17
19
|
const classes = dataTableSlotRecipe({ layout });
|
|
20
|
+
const tableRef = useRef(null);
|
|
21
|
+
// `:first-child` / `:last-child` cannot tell which grid column a cell renders in, so the
|
|
22
|
+
// table-edge spacing of the cell recipes misfires on the rows a `rowSpan` extends into.
|
|
23
|
+
// This marks the displaced cells so that spacing can be cancelled on them.
|
|
24
|
+
useTableEdgeCellMarkers(tableRef);
|
|
18
25
|
// Check if DataTable has any rows by looking for DataTable.Body with DataTable.Row children
|
|
19
26
|
const hasRows = useMemo(() => {
|
|
20
27
|
if (loading)
|
|
@@ -39,7 +46,7 @@ const Base = forwardRef(({ className, size = 'medium', enableRowSelection = fals
|
|
|
39
46
|
}, [children, loading]);
|
|
40
47
|
const shouldShowEmptyState = !hasRows && !!emptyStateSlot && !loading;
|
|
41
48
|
return (_jsx(DataTableProvider, { size: size, enableRowSelection: enableRowSelection, enableRowClickSelection: enableRowClickSelection, fixedHeader: fixedHeader, showVerticalBorder: showVerticalBorder, leftFixedColumnIndex: leftFixedColumnIndex, rightFixedColumnIndex: rightFixedColumnIndex, loading: loading, layout: layout, children: _jsxs("div", { ...wrapperProps, className: cx(classes.wrapper, 'mfui-DataTable__wrapper',
|
|
42
|
-
/* TODO: Remove in v5.0.0 */ 'mfui-DataGrid__wrapper', wrapperProps?.className), children: [_jsx("table", { ref: ref, className: cx(classes.table, 'mfui-DataTable__table',
|
|
49
|
+
/* TODO: Remove in v5.0.0 */ 'mfui-DataGrid__wrapper', wrapperProps?.className), children: [_jsx("table", { ref: mergeRefs(ref, tableRef), className: cx(classes.table, 'mfui-DataTable__table',
|
|
43
50
|
/* TODO: Remove in v5.0.0 */ 'mfui-DataGrid__table', className), ...props, children: children }), shouldShowEmptyState ? (_jsx("div", { className: cx(classes.emptyState, 'mfui-DataTable__emptyState',
|
|
44
51
|
/* TODO: Remove in v5.0.0 */ 'mfui-DataGrid__emptyState'), role: "status", "aria-live": "polite", children: emptyStateSlot })) : null] }) }));
|
|
45
52
|
});
|
|
@@ -9,6 +9,15 @@ import { type DataTableSlotRecipeVariant } from '../../styled-system/recipes';
|
|
|
9
9
|
* - `amount`: Right-aligned numeric content (amounts, balances, etc.)
|
|
10
10
|
*/
|
|
11
11
|
export type CellDataType = 'text' | 'amount';
|
|
12
|
+
/**
|
|
13
|
+
* The function that wraps the built-in selection checkbox of `DataTable.HeaderRow` or `DataTable.Row`.
|
|
14
|
+
*
|
|
15
|
+
* It receives the selection checkbox element and returns the content to render in the checkbox cell.
|
|
16
|
+
* The returned content must contain the passed element, because the row owns the checkbox itself.
|
|
17
|
+
*
|
|
18
|
+
* @param checkbox - The built-in selection checkbox element.
|
|
19
|
+
*/
|
|
20
|
+
export type DataTableSelectionCheckboxWrapper = (checkbox: ReactNode) => ReactNode;
|
|
12
21
|
/**
|
|
13
22
|
* The props for the `DataTable` component.
|
|
14
23
|
*
|
|
@@ -81,6 +90,9 @@ export type DataTableProps = {
|
|
|
81
90
|
* If the fixed column width might be changed with any interaction, such as disclosure, removing row or translating,
|
|
82
91
|
* please add `table-layout: fixed` to the DataTable and specify the width of the each column.
|
|
83
92
|
*
|
|
93
|
+
* **Not supported together with merged cells.** The index is counted in source order, which a
|
|
94
|
+
* `colSpan` / `rowSpan` shifts, so the fixed column is resolved on the wrong cells.
|
|
95
|
+
*
|
|
84
96
|
* @default undefined
|
|
85
97
|
*/
|
|
86
98
|
leftFixedColumnIndex?: number;
|
|
@@ -91,6 +103,9 @@ export type DataTableProps = {
|
|
|
91
103
|
* If the fixed column width might be changed with any interaction, such as disclosure, removing row or translating,
|
|
92
104
|
* please add `table-layout: fixed` to the DataTable and specify the width of the each column.
|
|
93
105
|
*
|
|
106
|
+
* **Not supported together with merged cells.** The index is counted in source order, which a
|
|
107
|
+
* `colSpan` / `rowSpan` shifts, so the fixed column is resolved on the wrong cells.
|
|
108
|
+
*
|
|
94
109
|
* @default undefined
|
|
95
110
|
*/
|
|
96
111
|
rightFixedColumnIndex?: number;
|
|
@@ -9,13 +9,15 @@ import { isComponentOrWrapped } from '../../utilities/react/isComponentOrWrapped
|
|
|
9
9
|
export const DataTableHeaderRow = forwardRef(({ children, checkboxProps, className, ...props }, ref) => {
|
|
10
10
|
const { enableRowSelection, setNumberColumns } = useDataTableContext();
|
|
11
11
|
const classes = dataTableHeaderRowSlotRecipe();
|
|
12
|
+
// Building the element before wrapping keeps everything the header row owns on the Checkbox itself.
|
|
13
|
+
const selectionCheckbox = (_jsx(Checkbox, { checked: checkboxProps?.checked, indeterminate: checkboxProps?.indeterminate, "aria-label": checkboxProps?.['aria-label'] ?? 'すべての行を選択', disabled: checkboxProps?.disabled, onChange: checkboxProps?.onChange, onClick: checkboxProps?.onClick }));
|
|
12
14
|
// Count the number of header cells
|
|
13
15
|
useEffect(() => {
|
|
14
16
|
const headerCells = Children.toArray(children).filter((child) => isValidElement(child) && isComponentOrWrapped(child, DataTableHeaderCell));
|
|
15
17
|
setNumberColumns(headerCells.length);
|
|
16
18
|
}, [children, enableRowSelection, setNumberColumns]);
|
|
17
19
|
return (_jsxs("tr", { className: cx(classes.root, 'mfui-DataTableHeaderRow__root',
|
|
18
|
-
/* TODO: Remove in v5.0.0 */ 'mfui-DataGridHeaderRow__root', className), ...props, ref: ref, children: [enableRowSelection ? (_jsx(DataTableHeaderCell, { columnIndex: 0, disabled: checkboxProps?.disabled, children:
|
|
20
|
+
/* TODO: Remove in v5.0.0 */ 'mfui-DataGridHeaderRow__root', className), ...props, ref: ref, children: [enableRowSelection ? (_jsx(DataTableHeaderCell, { columnIndex: 0, disabled: checkboxProps?.disabled, children: checkboxProps?.wrapper ? checkboxProps.wrapper(selectionCheckbox) : selectionCheckbox })) : null, Children.map(children, (child, index) => {
|
|
19
21
|
if (!isValidElement(child)) {
|
|
20
22
|
return child;
|
|
21
23
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ComponentPropsWithRef } from 'react';
|
|
2
2
|
import { type CheckboxProps } from '../../Checkbox';
|
|
3
|
+
import { type DataTableSelectionCheckboxWrapper } from '../DataTable.types';
|
|
3
4
|
/**
|
|
4
5
|
* The props for the `DataTableHeaderRow` component.
|
|
5
6
|
*
|
|
@@ -24,6 +25,23 @@ export type DataTableHeaderRowProps = {
|
|
|
24
25
|
* @property onClick - The handler called when the checkbox is clicked (for event propagation control).
|
|
25
26
|
*
|
|
26
27
|
* @property disabled - Whether the checkbox is disabled.
|
|
28
|
+
*
|
|
29
|
+
* @property wrapper - The function that wraps the checkbox, for example with the `Tooltip` component.
|
|
30
|
+
* It receives the checkbox element and must render it as it is, because the header row owns the checkbox itself.
|
|
31
|
+
* Keep the `Tooltip` component with its default `trigger` (`['hover', 'focus']`) so that keyboard users can also
|
|
32
|
+
* read the content; a tooltip opened by a click would duplicate the action of the checkbox.
|
|
33
|
+
* When the content restates the accessible name of the checkbox, pass `hideFromScreenReader` to the `Tooltip`
|
|
34
|
+
* component to avoid announcing the same information twice.
|
|
35
|
+
*
|
|
36
|
+
* ```tsx
|
|
37
|
+
* <DataTable.HeaderRow
|
|
38
|
+
* checkboxProps={{
|
|
39
|
+
* wrapper: (checkbox) => <Tooltip content="すべて選択">{checkbox}</Tooltip>,
|
|
40
|
+
* }}
|
|
41
|
+
* >
|
|
42
|
+
* ```
|
|
27
43
|
*/
|
|
28
|
-
checkboxProps?: Pick<CheckboxProps, 'aria-label' | 'checked' | 'indeterminate' | 'onChange' | 'disabled' | 'onClick'
|
|
44
|
+
checkboxProps?: Pick<CheckboxProps, 'aria-label' | 'checked' | 'indeterminate' | 'onChange' | 'disabled' | 'onClick'> & {
|
|
45
|
+
wrapper?: DataTableSelectionCheckboxWrapper;
|
|
46
|
+
};
|
|
29
47
|
} & ComponentPropsWithRef<'tr'>;
|
|
@@ -62,6 +62,9 @@ export const DataTableRow = forwardRef(({ children, disabled = false, highlighte
|
|
|
62
62
|
const toggleSelectionByRowInteraction = () => {
|
|
63
63
|
selectionCheckboxRef.current?.click();
|
|
64
64
|
};
|
|
65
|
+
// Building the element before wrapping keeps everything the row owns on the Checkbox itself, so that the
|
|
66
|
+
// ref-based toggle and the recipe selectors keep working with a consumer-supplied wrapper in between.
|
|
67
|
+
const selectionCheckbox = (_jsx(Checkbox, { ref: selectionCheckboxRef, className: cx(classes.selectionCheckbox, 'mfui-DataTableRow__selectionCheckbox'), checked: checkboxProps?.checked, "aria-label": checkboxProps?.['aria-label'] ?? '行を選択', disabled: disabled || checkboxProps?.disabled, tabIndex: isRowClickSelectable ? -1 : undefined, onChange: checkboxProps?.onChange, onClick: checkboxProps?.onClick }));
|
|
65
68
|
const handleClickRow = (event) => {
|
|
66
69
|
if (disabled || isClickFromNestedInteractiveElement(event)) {
|
|
67
70
|
return;
|
|
@@ -84,7 +87,7 @@ export const DataTableRow = forwardRef(({ children, disabled = false, highlighte
|
|
|
84
87
|
return (_jsxs("tr", { ref: ref, className: cx(classes.root, 'mfui-DataTableRow__root',
|
|
85
88
|
/* TODO: Remove in v5.0.0 */ 'mfui-DataGridRow__root', className), ...(ariaExpanded !== undefined && { 'aria-expanded': ariaExpanded }), ...props,
|
|
86
89
|
// When the row is clickable, the role should be 'button' in order to allow screen readers to understand the row is clickable.
|
|
87
|
-
role: isInteractive ? 'button' : 'row', tabIndex: isInteractive ? 0 : undefined, ...(disabled && { 'aria-disabled': disabled }), onClick: handleClickRow, onKeyDown: handleKeyDownRow, children: [isSelectable ? (_jsx(DataTableCell, { columnIndex: 0, isRowHighlighted: isRowHighlighted, disabled: disabled, children:
|
|
90
|
+
role: isInteractive ? 'button' : 'row', tabIndex: isInteractive ? 0 : undefined, ...(disabled && { 'aria-disabled': disabled }), onClick: handleClickRow, onKeyDown: handleKeyDownRow, children: [isSelectable ? (_jsx(DataTableCell, { columnIndex: 0, isRowHighlighted: isRowHighlighted, disabled: disabled, children: checkboxProps?.wrapper ? checkboxProps.wrapper(selectionCheckbox) : selectionCheckbox })) : null, Children.map(children, (child, index) => {
|
|
88
91
|
if (!isValidElement(child)) {
|
|
89
92
|
return child;
|
|
90
93
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ComponentPropsWithRef } from 'react';
|
|
2
2
|
import { type CheckboxProps } from '../../Checkbox';
|
|
3
|
+
import { type DataTableSelectionCheckboxWrapper } from '../DataTable.types';
|
|
3
4
|
/**
|
|
4
5
|
* The props for the `DataTableRow` component.
|
|
5
6
|
*
|
|
@@ -38,8 +39,29 @@ export type DataTableRowProps = {
|
|
|
38
39
|
* @property onClick - The handler called when the checkbox is clicked (for event propagation control).
|
|
39
40
|
*
|
|
40
41
|
* @property disabled - Whether the checkbox is disabled.
|
|
42
|
+
*
|
|
43
|
+
* @property wrapper - The function that wraps the checkbox, for example with the `Tooltip` component.
|
|
44
|
+
* It receives the checkbox element and must render it as it is, because the row owns the checkbox itself.
|
|
45
|
+
* Keep the `Tooltip` component with its default `trigger` (`['hover', 'focus']`) so that keyboard users can also
|
|
46
|
+
* read the content; a tooltip opened by a click would duplicate the action of the checkbox.
|
|
47
|
+
* When the content restates the accessible name of the checkbox, pass `hideFromScreenReader` to the `Tooltip`
|
|
48
|
+
* component to avoid announcing the same information twice.
|
|
49
|
+
*
|
|
50
|
+
* Note that when the `enableRowClickSelection` prop of the `DataTable` component is `true`, the checkbox is removed
|
|
51
|
+
* from the tab order and the focusable element is the row, which is outside the wrapper. A tooltip in the wrapper is
|
|
52
|
+
* then opened by hover only, so do not put information that keyboard users need in it in that case.
|
|
53
|
+
*
|
|
54
|
+
* ```tsx
|
|
55
|
+
* <DataTable.Row
|
|
56
|
+
* checkboxProps={{
|
|
57
|
+
* wrapper: (checkbox) => <Tooltip content="この行を選択">{checkbox}</Tooltip>,
|
|
58
|
+
* }}
|
|
59
|
+
* >
|
|
60
|
+
* ```
|
|
41
61
|
*/
|
|
42
|
-
checkboxProps?: Pick<CheckboxProps, 'aria-label' | 'checked' | 'onChange' | 'disabled' | 'onClick'
|
|
62
|
+
checkboxProps?: Pick<CheckboxProps, 'aria-label' | 'checked' | 'onChange' | 'disabled' | 'onClick'> & {
|
|
63
|
+
wrapper?: DataTableSelectionCheckboxWrapper;
|
|
64
|
+
};
|
|
43
65
|
/**
|
|
44
66
|
* The callback function that is called when the row is clicked.
|
|
45
67
|
* If provided, the row can be focused and the focus indicator is displayed.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from './DatePickerDateCell';
|
|
2
|
-
export * from './DatePickerDateCell.types';
|
|
2
|
+
export type * from './DatePickerDateCell.types';
|
|
@@ -57,7 +57,7 @@ export function CalendarGrid({ viewingValue, minDate, maxDate, checkDisabledDate
|
|
|
57
57
|
let tabbableDateIndex = -1;
|
|
58
58
|
// First, try to find the selected date if it exists and is not disabled
|
|
59
59
|
if (value) {
|
|
60
|
-
tabbableDateIndex = newDates.findIndex((dateItem) => dateItem
|
|
60
|
+
tabbableDateIndex = newDates.findIndex((dateItem) => dateItem?.selected && !dateItem.disabled);
|
|
61
61
|
}
|
|
62
62
|
// If no selected date or selected date is disabled, try today's date
|
|
63
63
|
if (tabbableDateIndex === -1) {
|
|
@@ -101,8 +101,6 @@ export function CalendarGrid({ viewingValue, minDate, maxDate, checkDisabledDate
|
|
|
101
101
|
.map((_, index) => ((weekStart + index) % 7))
|
|
102
102
|
.map((weekday) => (_jsx(DayCell, { day: weekday }, weekday))), computedPropsForDates.map((dateItem, index) => {
|
|
103
103
|
// All props are generated internally and guaranteed to have required fields
|
|
104
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
105
|
-
// @ts-ignore
|
|
106
104
|
if (!dateItem) {
|
|
107
105
|
return (_jsx("div", { className: cx(classes.emptyDateCell, 'mfui-CalendarGrid__emptyDateCell') }, `empty-date-${String(index)}`));
|
|
108
106
|
}
|
|
@@ -19,6 +19,6 @@ export declare const Dialog: import("react").ForwardRefExoticComponent<{
|
|
|
19
19
|
enableAutoUnmount?: boolean;
|
|
20
20
|
disableBackdropClose?: boolean;
|
|
21
21
|
customFocusElement?: import("react").RefObject<HTMLElement | null> | HTMLElement | null;
|
|
22
|
-
} & Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "onClose" | "open"> & {
|
|
22
|
+
} & Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "onClose" | "open" | "title"> & {
|
|
23
23
|
ref?: (import("react").RefCallback<HTMLDivElement> | import("react").RefObject<HTMLDivElement | null> | null) | undefined;
|
|
24
24
|
} & import("react").Attributes>;
|
|
@@ -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, nestedNavigationDisplay, width, customLinkComponent, disableResponsive, isCollapsed: controlledIsCollapsed, onCollapsedChange, collapseButtonProps, expandButtonProps, }: MainNavigationProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare function BaseMainNavigation({ className, featureShortcut, navigationItems, navLandmarkLabel, enableCollapsible, nestedNavigationDisplay, 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, nestedNavigationDisplay = 'accordion', width = 'normal', customLinkComponent, disableResponsive, isCollapsed: controlledIsCollapsed, onCollapsedChange, collapseButtonProps, expandButtonProps, }) {
|
|
16
|
+
export function BaseMainNavigation({ className, featureShortcut, navigationItems, navLandmarkLabel, enableCollapsible = false, nestedNavigationDisplay = 'accordion', 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;
|
|
@@ -31,7 +31,7 @@ export function BaseMainNavigation({ className, featureShortcut, navigationItems
|
|
|
31
31
|
const toggleButtonLabel = isCollapsed
|
|
32
32
|
? (expandButtonProps?.label ?? 'ナビゲーションを拡げる')
|
|
33
33
|
: (collapseButtonProps?.label ?? 'ナビゲーションを折りたたむ');
|
|
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) => {
|
|
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, "aria-label": navLandmarkLabel, className: cx(classes.nav, 'mfui-BaseMainNavigation__nav'), children: [_jsx("ul", { className: cx(classes.list, 'mfui-BaseMainNavigation__list'), children: navigationItems.map((navigation, index) => {
|
|
35
35
|
const isGroupLabel = navigation.children && 'isGroupLabel' in navigation && navigation.isGroupLabel;
|
|
36
36
|
const isGroupMenu = 'isGroupMenu' in navigation && navigation.isGroupMenu;
|
|
37
37
|
if (isGroupLabel || isGroupMenu) {
|
|
@@ -12,11 +12,12 @@ import { NarrowViewportMainNavigation } from './NarrowViewportMainNavigation';
|
|
|
12
12
|
* `MainNavigation` is intended to be paired with `GlobalHeader`. If you need a self-contained
|
|
13
13
|
* layout that already includes both header and navigation features, use `Sidebar` instead.
|
|
14
14
|
*/
|
|
15
|
-
export const MainNavigation = forwardRef(({ className, featureShortcut, navigationItems, disableResponsive = false, width = 'normal', customLinkComponent, enableCollapsible, nestedNavigationDisplay, isCollapsed, onCollapsedChange, collapseButtonProps, expandButtonProps, }, ref) => {
|
|
15
|
+
export const MainNavigation = forwardRef(({ className, featureShortcut, navigationItems, navLandmarkLabel = 'メイン', disableResponsive = false, width = 'normal', customLinkComponent, enableCollapsible, nestedNavigationDisplay, isCollapsed, onCollapsedChange, collapseButtonProps, expandButtonProps, }, ref) => {
|
|
16
16
|
const commonProps = {
|
|
17
17
|
className,
|
|
18
18
|
featureShortcut,
|
|
19
19
|
navigationItems,
|
|
20
|
+
navLandmarkLabel,
|
|
20
21
|
width,
|
|
21
22
|
customLinkComponent,
|
|
22
23
|
};
|
|
@@ -186,6 +186,15 @@ export type MainNavigationProps = {
|
|
|
186
186
|
* The navigation items.
|
|
187
187
|
*/
|
|
188
188
|
navigationItems: NavigationItem[];
|
|
189
|
+
/**
|
|
190
|
+
* The accessible name for the navigation landmark, applied as `aria-label` to both the sidebar `<nav>`
|
|
191
|
+
* and the narrow viewport drawer `<nav>`.
|
|
192
|
+
*
|
|
193
|
+
* Avoid including the role name (e.g. 'ナビゲーション'); assistive technology already announces it.
|
|
194
|
+
*
|
|
195
|
+
* @default 'メイン'
|
|
196
|
+
*/
|
|
197
|
+
navLandmarkLabel?: string;
|
|
189
198
|
/**
|
|
190
199
|
* Whether the navigation is collapsible.
|
|
191
200
|
*
|
|
@@ -13,7 +13,7 @@ import { Portal } from '../Portal';
|
|
|
13
13
|
* The component for the main navigation on the narrow viewport.
|
|
14
14
|
* This component must only be used in MainNavigation.tsx, do not export it.
|
|
15
15
|
*/
|
|
16
|
-
export const NarrowViewportMainNavigation = forwardRef(({ className, featureShortcut, navigationItems, width = 'normal', customLinkComponent }, ref) => {
|
|
16
|
+
export const NarrowViewportMainNavigation = forwardRef(({ className, featureShortcut, navigationItems, navLandmarkLabel, width = 'normal', customLinkComponent }, ref) => {
|
|
17
17
|
const classes = narrowViewportMainNavigationSlotRecipe({ width });
|
|
18
18
|
const InternalLinkTag = customLinkComponent ?? 'a';
|
|
19
19
|
const navId = useId();
|
|
@@ -48,7 +48,7 @@ export const NarrowViewportMainNavigation = forwardRef(({ className, featureShor
|
|
|
48
48
|
}
|
|
49
49
|
return (_jsx(Portal, { children: _jsxs("div", { ref: dialogRef, role: "dialog", className: cx(classes.root, 'mfui-NarrowViewportMainNavigation__root', className), tabIndex: -1, onKeyDown: handleOnKeyDown, children: [_jsx("div", { "data-mfui-content": "backdrop", className: cx(classes.backdrop, 'mfui-NarrowViewportMainNavigation__backdrop'), onClick: handleCloseMainNavigation }), _jsxs("div", { "data-mfui-content": "inside", className: cx(classes.container, 'mfui-NarrowViewportMainNavigation__container'), onClick: (event) => {
|
|
50
50
|
event.stopPropagation();
|
|
51
|
-
}, children: [featureShortcut ? (_jsx("div", { className: cx(classes.featureShortcut, 'mfui-NarrowViewportMainNavigation__featureShortcut'), children: _jsx(FocusIndicator, { children: _jsx(NavigationLink, { tag: InternalLinkTag, isExternal: featureShortcut.isExternal, href: featureShortcut.href, className: cx(classes.featureShortcutAnchor, 'mfui-NarrowViewportMainNavigation__featureShortcutAnchor'), onClick: handleCloseMainNavigation, children: _jsx(Typography, { variant: "controlLabel", children: featureShortcut.label }) }) }) })) : null, _jsxs("nav", { className: cx(classes.nav, 'mfui-NarrowViewportMainNavigation__nav'), children: [_jsx("ul", { className: cx(classes.list, 'mfui-NarrowViewportMainNavigation__list'), children: navigationItems.map((navigation, index) => {
|
|
51
|
+
}, children: [featureShortcut ? (_jsx("div", { className: cx(classes.featureShortcut, 'mfui-NarrowViewportMainNavigation__featureShortcut'), children: _jsx(FocusIndicator, { children: _jsx(NavigationLink, { tag: InternalLinkTag, isExternal: featureShortcut.isExternal, href: featureShortcut.href, className: cx(classes.featureShortcutAnchor, 'mfui-NarrowViewportMainNavigation__featureShortcutAnchor'), onClick: handleCloseMainNavigation, children: _jsx(Typography, { variant: "controlLabel", children: featureShortcut.label }) }) }) })) : null, _jsxs("nav", { "aria-label": navLandmarkLabel, className: cx(classes.nav, 'mfui-NarrowViewportMainNavigation__nav'), children: [_jsx("ul", { className: cx(classes.list, 'mfui-NarrowViewportMainNavigation__list'), children: navigationItems.map((navigation, index) => {
|
|
52
52
|
const isGroupLabel = navigation.children && 'isGroupLabel' in navigation && navigation.isGroupLabel;
|
|
53
53
|
if (isGroupLabel) {
|
|
54
54
|
return null;
|
|
@@ -339,29 +339,38 @@ placeholder, emptyMessage, disabled, invalid, required, caution, targetDOMNode,
|
|
|
339
339
|
`${String(localSelectedValuesSet.size)}件選択中`) })) : null;
|
|
340
340
|
const applyControlsNode = enableApplyControls ? (_jsxs(HStack, { gap: "horizontal.0-1of2", children: [_jsx(Button, { ref: cancelButtonRef, size: "small", priority: "secondary", onClick: handleCancelButtonClick, children: cancelButtonProps?.label ?? 'キャンセル' }), _jsx(Button, { ref: applyButtonRef, size: "small", priority: "primary", onClick: handleApplyButtonClick, children: applyButtonProps?.label ?? '適用' })] })) : null;
|
|
341
341
|
const resolvedNotFoundMessage = typeof notFoundMessage === 'function' ? notFoundMessage(searchText.trim()) : notFoundMessage;
|
|
342
|
+
// Early returns rather than a four-level ternary: the branches are mutually exclusive
|
|
343
|
+
// and each returns a different shape (skeletons, virtualized rows, options, or the
|
|
344
|
+
// empty message).
|
|
345
|
+
const renderListContent = () => {
|
|
346
|
+
if (loading) {
|
|
347
|
+
return Array.from({ length: SKELETON_ITEM_COUNT }).map((_, index) => (_jsx("li", { className: cx(classes.skeletonItem, 'mfui-MultipleSelectBox__skeletonItem'), children: _jsx(Skeleton, {}) }, index)));
|
|
348
|
+
}
|
|
349
|
+
if (isVirtualized && virtualItems.length > 0) {
|
|
350
|
+
return renderVirtualizedItems();
|
|
351
|
+
}
|
|
352
|
+
if (filteredOptions.length > 0) {
|
|
353
|
+
return [
|
|
354
|
+
...renderNonVirtualizedItems(),
|
|
355
|
+
!isVirtualized && renderInfiniteScrollLoading(),
|
|
356
|
+
!isVirtualized && renderInfiniteScrollError(),
|
|
357
|
+
].filter(Boolean);
|
|
358
|
+
}
|
|
359
|
+
return [
|
|
360
|
+
_jsx("li", { className: cx(classes.emptyMessage, 'mfui-MultipleSelectBox__emptyMessage'), children: _jsx(Typography, { variant: "body", children: enableSearchOptions && searchText && resolvedNotFoundMessage
|
|
361
|
+
? resolvedNotFoundMessage
|
|
362
|
+
: options.length > 0
|
|
363
|
+
? resolvedNotFoundMessage
|
|
364
|
+
: emptyMessage }) }, "empty"),
|
|
365
|
+
!isVirtualized && renderInfiniteScrollError(),
|
|
366
|
+
].filter(Boolean);
|
|
367
|
+
};
|
|
342
368
|
const optionsNode = (_jsxs("div", { ref: scrollWrapperRef, className: cx(classes.scrollWrapper, 'mfui-MultipleSelectBox__scrollWrapper'), onScroll: enableInfiniteScroll ? handleInfiniteScroll : undefined, children: [_jsx("ul", { ref: listBoxRef, role: "listbox", id: listBoxId, className: cx(classes.listBox, 'mfui-MultipleSelectBox__listBox'), tabIndex: -1, style: isVirtualized && totalSize > 0
|
|
343
369
|
? {
|
|
344
370
|
height: `${String(totalSize)}px`,
|
|
345
371
|
position: 'relative',
|
|
346
372
|
}
|
|
347
|
-
: undefined, children:
|
|
348
|
-
? Array.from({ length: SKELETON_ITEM_COUNT }).map((_, index) => (_jsx("li", { className: cx(classes.skeletonItem, 'mfui-MultipleSelectBox__skeletonItem'), children: _jsx(Skeleton, {}) }, index)))
|
|
349
|
-
: isVirtualized && virtualItems.length > 0
|
|
350
|
-
? renderVirtualizedItems()
|
|
351
|
-
: filteredOptions.length > 0
|
|
352
|
-
? [
|
|
353
|
-
...renderNonVirtualizedItems(),
|
|
354
|
-
!isVirtualized && renderInfiniteScrollLoading(),
|
|
355
|
-
!isVirtualized && renderInfiniteScrollError(),
|
|
356
|
-
].filter(Boolean)
|
|
357
|
-
: [
|
|
358
|
-
_jsx("li", { className: cx(classes.emptyMessage, 'mfui-MultipleSelectBox__emptyMessage'), children: _jsx(Typography, { variant: "body", children: enableSearchOptions && searchText && resolvedNotFoundMessage
|
|
359
|
-
? resolvedNotFoundMessage
|
|
360
|
-
: options.length > 0
|
|
361
|
-
? resolvedNotFoundMessage
|
|
362
|
-
: emptyMessage }) }, "empty"),
|
|
363
|
-
!isVirtualized && renderInfiniteScrollError(),
|
|
364
|
-
].filter(Boolean) }), isVirtualized ? renderInfiniteScrollLoading() : null, isVirtualized ? renderInfiniteScrollError('div') : null, _jsx(OptionGroupLabelDescriptions, { groups: rendersHiddenGroupLabels ? optionGroupLabels : [] })] }));
|
|
373
|
+
: undefined, children: renderListContent() }), isVirtualized ? renderInfiniteScrollLoading() : null, isVirtualized ? renderInfiniteScrollError('div') : null, _jsx(OptionGroupLabelDescriptions, { groups: rendersHiddenGroupLabels ? optionGroupLabels : [] })] }));
|
|
365
374
|
const createOptionAreaNode = isCreateOptionVisible ? (_jsxs("div", { className: cx(classes.createOptionArea, 'mfui-MultipleSelectBox__createOptionArea'), children: [_jsxs("button", { "data-mfui-content": "create-new-option", type: "button", className: cx(classes.createOptionButton, 'mfui-MultipleSelectBox__createOptionButton'), disabled: isCreating, onClick: handleCreateOption, children: [_jsx(Add, { "aria-hidden": true }), createOptionProps?.renderLabel?.(searchText.trim()) ?? (_jsxs(_Fragment, { children: [_jsx(Typography, { variant: "strongBody", children: searchText.trim() }), _jsx(Typography, { variant: "body", children: "\u3092\u8FFD\u52A0" })] }))] }), createError ? (_jsx("div", { className: cx(classes.createOptionErrorMessage, 'mfui-MultipleSelectBox__createOptionErrorMessage'), children: _jsx(HelpMessage, { messageType: "error", children: createOptionProps?.renderErrorMessage?.(searchText.trim()) ??
|
|
366
375
|
`${searchText.trim()}を追加できませんでした。` }) })) : null] })) : null;
|
|
367
376
|
return (_jsx(Popover, { renderTrigger: ({ setTriggerRef, togglePopover, handleTriggerKeyDown, handleTriggerBlur }) => (_jsx(MultipleSelectBoxTrigger, { ref: triggerRef, wrapperRef: setTriggerRef, selectedOptions: localSelectedOptions, id: id, disabled: disabled, triggerProps: triggerProps, triggerWrapperProps: triggerWrapperProps, name: name,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
|
-
import { getDeepActiveElement } from '
|
|
2
|
+
import { getDeepActiveElement } from '../../utilities/dom/getDeepActiveElement';
|
|
3
3
|
import { isSelectableOption } from '../utils/isSelectableOption';
|
|
4
4
|
/**
|
|
5
5
|
* Control the focus when the option panel is opened.
|
|
@@ -6,5 +6,8 @@ import { type NavigationListItemProps } from './NavigationListItem.types';
|
|
|
6
6
|
* If the href prop is provided, the item will be rendered as an anchor element.
|
|
7
7
|
* If the onClick prop is provided (without href), it will be rendered as a button element.
|
|
8
8
|
* Otherwise, it will be rendered as a div element and not interactive.
|
|
9
|
+
*
|
|
10
|
+
* The trailing navigation indicator is displayed whenever the item can be activated,
|
|
11
|
+
* that is when either the href or the onClick prop is provided.
|
|
9
12
|
*/
|
|
10
13
|
export declare const NavigationListItem: import("react").ForwardRefExoticComponent<NavigationListItemProps & import("react").RefAttributes<HTMLLIElement>>;
|
|
@@ -16,6 +16,9 @@ const ARIA_DISABLED_PROPS = { 'aria-disabled': true, 'data-mfui-disabled': '' };
|
|
|
16
16
|
* If the href prop is provided, the item will be rendered as an anchor element.
|
|
17
17
|
* If the onClick prop is provided (without href), it will be rendered as a button element.
|
|
18
18
|
* Otherwise, it will be rendered as a div element and not interactive.
|
|
19
|
+
*
|
|
20
|
+
* The trailing navigation indicator is displayed whenever the item can be activated,
|
|
21
|
+
* that is when either the href or the onClick prop is provided.
|
|
19
22
|
*/
|
|
20
23
|
export const NavigationListItem = forwardRef(({ title, icon, description, leadingContent, href, target, customLinkComponent, onClick, disabled, className, ...rest }, ref) => {
|
|
21
24
|
const classes = navigationListItemSlotRecipe();
|
|
@@ -26,7 +29,8 @@ export const NavigationListItem = forwardRef(({ title, icon, description, leadin
|
|
|
26
29
|
return 'button';
|
|
27
30
|
return 'div';
|
|
28
31
|
}, [href, customLinkComponent, onClick]);
|
|
29
|
-
const
|
|
32
|
+
const isActivatable = href !== undefined || onClick !== undefined;
|
|
33
|
+
const isInteractive = isActivatable && !disabled;
|
|
30
34
|
const resolvedHref = disabled ? undefined : href;
|
|
31
35
|
const disabledProps = useMemo(() => {
|
|
32
36
|
if (!disabled)
|
|
@@ -35,6 +39,6 @@ export const NavigationListItem = forwardRef(({ title, icon, description, leadin
|
|
|
35
39
|
return BUTTON_DISABLED_PROPS;
|
|
36
40
|
return ARIA_DISABLED_PROPS;
|
|
37
41
|
}, [disabled, onClick, href]);
|
|
38
|
-
const innerElement = (_jsx(FocusIndicator, { hideWhiteBorder: true, position: "inside", children: _jsxs(Tag, { ...rest, href: resolvedHref, target: target, type: href === undefined && onClick !== undefined ? 'button' : undefined, "data-mfui-focusable": isInteractive, className: cx(classes.root, 'mfui-NavigationListItem__root', className), onClick: disabled ? undefined : onClick, ...disabledProps, children: [leadingContent != null ? (_jsx("span", { className: cx(classes.leading, 'mfui-NavigationListItem__leading'), children: leadingContent })) : null, _jsxs("span", { className: cx(classes.content, 'mfui-NavigationListItem__content'), children: [_jsxs("span", { className: cx(classes.title, 'mfui-NavigationListItem__title'), children: [icon != null ? (_jsx("span", { className: cx(classes.titleIcon, 'mfui-NavigationListItem__titleIcon'), children: icon })) : null, _jsx(Typography, { variant: "contentHeading", children: title })] }), description != null ? _jsx(Typography, { variant: "body", children: description }) : null] }),
|
|
42
|
+
const innerElement = (_jsx(FocusIndicator, { hideWhiteBorder: true, position: "inside", children: _jsxs(Tag, { ...rest, href: resolvedHref, target: target, type: href === undefined && onClick !== undefined ? 'button' : undefined, "data-mfui-focusable": isInteractive, className: cx(classes.root, 'mfui-NavigationListItem__root', className), onClick: disabled ? undefined : onClick, ...disabledProps, children: [leadingContent != null ? (_jsx("span", { className: cx(classes.leading, 'mfui-NavigationListItem__leading'), children: leadingContent })) : null, _jsxs("span", { className: cx(classes.content, 'mfui-NavigationListItem__content'), children: [_jsxs("span", { className: cx(classes.title, 'mfui-NavigationListItem__title'), children: [icon != null ? (_jsx("span", { className: cx(classes.titleIcon, 'mfui-NavigationListItem__titleIcon'), children: icon })) : null, _jsx(Typography, { variant: "contentHeading", children: title })] }), description != null ? _jsx(Typography, { variant: "body", children: description }) : null] }), isActivatable ? (_jsx("span", { className: cx(classes.trailing, 'mfui-NavigationListItem__trailing'), children: _jsx(NavigationToDetail, { "aria-hidden": true }) })) : null] }) }));
|
|
39
43
|
return _jsx("li", { ref: ref, children: innerElement });
|
|
40
44
|
});
|
|
@@ -25,7 +25,8 @@ type ButtonProps = {
|
|
|
25
25
|
customLinkComponent?: undefined;
|
|
26
26
|
/**
|
|
27
27
|
* The click handler for the navigation item.
|
|
28
|
-
* When provided without href, the item is rendered as a button element
|
|
28
|
+
* When provided without href, the item is rendered as a button element
|
|
29
|
+
* and displays the same trailing navigation indicator as an anchor item.
|
|
29
30
|
*/
|
|
30
31
|
onClick: ComponentPropsWithoutRef<'button'>['onClick'];
|
|
31
32
|
/**
|
|
@@ -5,8 +5,13 @@ import React from 'react';
|
|
|
5
5
|
* and ignores invalid characters.
|
|
6
6
|
*
|
|
7
7
|
* The `onChange` callback receives the raw numeric string without commas.
|
|
8
|
+
*
|
|
9
|
+
* `maxIntegerDigits` and `decimalPlaces` cap how much the user can enter. Edits that would
|
|
10
|
+
* exceed either limit are silently rejected, so state the limit in an adjacent `HelpMessage`.
|
|
8
11
|
*/
|
|
9
12
|
export declare const NumberBox: React.ForwardRefExoticComponent<Omit<import("..").TextBoxProps, "onChange" | "prefixSlot" | "suffixSlot"> & {
|
|
10
13
|
onChange?: (value: string) => void;
|
|
11
14
|
textAlign?: 'left' | 'right';
|
|
15
|
+
maxIntegerDigits?: number;
|
|
16
|
+
decimalPlaces?: number;
|
|
12
17
|
} & React.RefAttributes<HTMLInputElement>>;
|