@moneyforward/mfui-components 3.35.0 → 3.36.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/DataTable/DataTable.d.ts +50 -0
- package/dist/src/DataTable/DataTable.js +44 -0
- package/dist/src/DataTable/DataTableFilterButton/DataTableFilterButton.d.ts +6 -0
- package/dist/src/DataTable/DataTableFilterButton/DataTableFilterButton.js +63 -0
- package/dist/src/DataTable/DataTableFilterButton/DataTableFilterButton.types.d.ts +49 -0
- package/dist/src/DataTable/DataTableFilterButton/DataTableFilterButton.types.js +1 -0
- package/dist/src/DataTable/DataTableFilterButton/index.d.ts +2 -0
- package/dist/src/DataTable/DataTableFilterButton/index.js +1 -0
- package/dist/src/DataTable/DataTableHeaderCell/DataTableHeaderCell.js +6 -2
- package/dist/src/DataTable/DataTableHeaderCell/DataTableHeaderCell.types.d.ts +23 -1
- package/dist/src/DataTable/DataTableSortButton/DataTableSortButton.d.ts +4 -0
- package/dist/src/DataTable/DataTableSortButton/DataTableSortButton.js +17 -0
- package/dist/src/DataTable/DataTableSortButton/DataTableSortButton.types.d.ts +25 -0
- package/dist/src/DataTable/DataTableSortButton/DataTableSortButton.types.js +1 -0
- package/dist/src/DataTable/DataTableSortButton/index.d.ts +2 -0
- package/dist/src/DataTable/DataTableSortButton/index.js +1 -0
- package/dist/src/DataTable/index.d.ts +2 -0
- package/dist/src/DateTimeSelection/DatePicker/DatePickerDateCell/DatePickerDateCell.js +3 -0
- package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerPopover/DateRangePickerCalendar/DateRangePickerDateCell.d.ts +2 -2
- package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerPopover/DateRangePickerCalendar/DateRangePickerDateCell.js +5 -2
- package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerTrigger/DateRangePickerTrigger.js +3 -2
- package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerTrigger/DateRangePickerTrigger.types.d.ts +17 -0
- package/dist/src/DateTimeSelection/FilterDateRangePicker/DateRangePickerContent/DateRangePickerContent.js +3 -1
- package/dist/src/DateTimeSelection/FilterDateRangePicker/FilterDateRangePicker.types.d.ts +2 -1
- package/dist/src/DateTimeSelection/FilterMonthPicker/FilterMonthPicker.types.d.ts +2 -1
- package/dist/src/DateTimeSelection/FilterMonthPicker/MonthPickerPopover/MonthPickerPopover.js +2 -1
- package/dist/src/DateTimeSelection/MonthRangePicker/MonthRangePickerMonthCell/MonthRangePickerMonthCell.d.ts +1 -0
- package/dist/src/DateTimeSelection/MonthRangePicker/MonthRangePickerMonthCell/MonthRangePickerMonthCell.js +11 -8
- package/dist/src/DateTimeSelection/MonthRangePicker/MonthRangePickerMonthCell/constants.d.ts +7 -15
- package/dist/src/DateTimeSelection/MonthRangePicker/MonthRangePickerMonthCell/constants.js +26 -13
- package/dist/src/DateTimeSelection/TimePicker/TimePicker.d.ts +2 -0
- package/dist/src/DateTimeSelection/TimePicker/TimePicker.js +3 -2
- package/dist/src/DateTimeSelection/TimePicker/TimePicker.types.d.ts +27 -0
- package/dist/src/DateTimeSelection/shared/BasePicker/BasePicker.js +4 -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/BaseRangePicker.d.ts +1 -1
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePicker.js +4 -4
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePicker.types.d.ts +33 -1
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerPopover/BaseRangePickerCalendar/BaseRangePickerDateCell.d.ts +2 -2
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerPopover/BaseRangePickerCalendar/BaseRangePickerDateCell.js +15 -36
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerPopover/BaseRangePickerCalendar/index.d.ts +0 -1
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerPopover/BaseRangePickerCalendar/index.js +0 -1
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerPopover/BaseRangePickerPopover.js +2 -1
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerTrigger/BaseRangePickerTrigger.js +3 -2
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerTrigger/BaseRangePickerTrigger.types.d.ts +17 -0
- package/dist/src/DateTimeSelection/shared/accessibility/constants.d.ts +7 -16
- package/dist/src/DateTimeSelection/shared/accessibility/constants.js +30 -14
- package/dist/src/DateTimeSelection/shared/accessibility/generateDateLabel.d.ts +6 -1
- package/dist/src/DateTimeSelection/shared/accessibility/generateDateLabel.js +14 -8
- package/dist/src/DeterminateProgressIndicator/DeterminateProgressIndicator.d.ts +18 -0
- package/dist/src/DeterminateProgressIndicator/DeterminateProgressIndicator.js +20 -0
- package/dist/src/DeterminateProgressIndicator/DeterminateProgressIndicator.types.d.ts +41 -0
- package/dist/src/DeterminateProgressIndicator/DeterminateProgressIndicator.types.js +1 -0
- package/dist/src/DeterminateProgressIndicator/index.d.ts +2 -0
- package/dist/src/DeterminateProgressIndicator/index.js +1 -0
- package/dist/src/FilterSelectBox/FilterSelectBox.types.d.ts +1 -1
- package/dist/src/MultipleFilterSelectBox/MultipleFilterSelectBox.types.d.ts +1 -1
- package/dist/src/MultipleSelectBox/MultipleSelectBox.d.ts +1 -1
- package/dist/src/MultipleSelectBox/MultipleSelectBox.js +2 -2
- package/dist/src/MultipleSelectBox/MultipleSelectBox.types.d.ts +1 -1
- package/dist/src/MultipleSelectBox/MultipleSelectBoxTrigger/MultipleSelectBoxTrigger.js +2 -2
- package/dist/src/MultipleSelectBox/MultipleSelectBoxTrigger/MultipleSelectBoxTrigger.types.d.ts +39 -1
- package/dist/src/Popover/Popover.js +1 -1
- package/dist/src/Popover/Popover.types.d.ts +1 -1
- package/dist/src/SelectBox/SelectBox.d.ts +1 -1
- package/dist/src/SelectBox/SelectBox.js +3 -3
- package/dist/src/SelectBox/SelectBox.types.d.ts +31 -1
- package/dist/src/TextBox/TextBox.d.ts +2 -1
- package/dist/src/TextBox/TextBox.js +4 -3
- package/dist/src/TextBox/TextBox.types.d.ts +26 -0
- package/dist/src/Textarea/Textarea.d.ts +2 -1
- package/dist/src/Textarea/Textarea.js +11 -3
- package/dist/src/Textarea/Textarea.types.d.ts +26 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/styled-system/recipes/base-range-picker-trigger-slot-recipe.d.ts +1 -0
- package/dist/styled-system/recipes/base-range-picker-trigger-slot-recipe.js +5 -0
- package/dist/styled-system/recipes/data-table-filter-button-slot-recipe.d.ts +33 -0
- package/dist/styled-system/recipes/data-table-filter-button-slot-recipe.js +43 -0
- package/dist/styled-system/recipes/data-table-header-cell-slot-recipe.d.ts +3 -2
- package/dist/styled-system/recipes/data-table-header-cell-slot-recipe.js +69 -1
- package/dist/styled-system/recipes/data-table-sort-button-slot-recipe.d.ts +33 -0
- package/dist/styled-system/recipes/data-table-sort-button-slot-recipe.js +35 -0
- package/dist/styled-system/recipes/determinate-progress-indicator-slot-recipe.d.ts +36 -0
- package/dist/styled-system/recipes/determinate-progress-indicator-slot-recipe.js +61 -0
- package/dist/styled-system/recipes/index.d.ts +3 -0
- package/dist/styled-system/recipes/index.js +3 -0
- package/dist/styled-system/recipes/text-box-slot-recipe.d.ts +4 -0
- package/dist/styled-system/recipes/text-box-slot-recipe.js +8 -2
- package/dist/styled-system/recipes/textarea-slot-recipe.d.ts +4 -0
- package/dist/styled-system/recipes/textarea-slot-recipe.js +6 -0
- package/dist/styled-system/recipes/time-picker-slot-recipe.d.ts +4 -0
- package/dist/styled-system/recipes/time-picker-slot-recipe.js +8 -2
- package/dist/styles.css +265 -10
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +11 -11
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerPopover/BaseRangePickerCalendar/constants.d.ts +0 -18
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerPopover/BaseRangePickerCalendar/constants.js +0 -18
|
@@ -281,4 +281,54 @@ export declare const DataTable: import("react").ForwardRefExoticComponent<Omit<D
|
|
|
281
281
|
* ```
|
|
282
282
|
*/
|
|
283
283
|
Row: import("react").ForwardRefExoticComponent<Omit<import("./DataTableRow").DataTableRowProps, "ref"> & import("react").RefAttributes<HTMLTableRowElement>>;
|
|
284
|
+
/**
|
|
285
|
+
* The `DataTableFilterButton` component.
|
|
286
|
+
* An icon-only filter button intended to be placed in the `actions` of `DataTable.HeaderCell`.
|
|
287
|
+
*
|
|
288
|
+
* It extends the props of `IconButton` except `children`. The filter icon
|
|
289
|
+
* (outline / filled) is switched internally based on the `filtered` prop, and the button is
|
|
290
|
+
* internally wired as the trigger of a `Popover` rendering `renderContent` — consumers only
|
|
291
|
+
* provide the filter state and the popover content.
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
*
|
|
295
|
+
* ```tsx
|
|
296
|
+
* <DataTable.HeaderCell
|
|
297
|
+
* actions={
|
|
298
|
+
* <DataTable.FilterButton filtered={isFiltered} renderContent={() => <FilterOptions />} />
|
|
299
|
+
* }
|
|
300
|
+
* >
|
|
301
|
+
* Name
|
|
302
|
+
* </DataTable.HeaderCell>
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
305
|
+
FilterButton: import("react").ForwardRefExoticComponent<Omit<import("..").IconButtonProps, "aria-label" | "children" | "customLinkComponent" | "href" | "target"> & {
|
|
306
|
+
'aria-label'?: import("..").IconButtonProps['aria-label'];
|
|
307
|
+
popoverProps?: Pick<import("react").ComponentPropsWithoutRef<'div'>, 'aria-label' | 'aria-labelledby'>;
|
|
308
|
+
filtered?: boolean;
|
|
309
|
+
renderContent: import("..").PopoverProps['renderContent'];
|
|
310
|
+
} & import("react").RefAttributes<HTMLButtonElement>>;
|
|
311
|
+
/**
|
|
312
|
+
* The `DataTableSortButton` component.
|
|
313
|
+
* An icon-only sort button intended to be placed in the `actions` of `DataTable.HeaderCell`.
|
|
314
|
+
*
|
|
315
|
+
* It extends the props of `IconButton` except `children` — the sort icon
|
|
316
|
+
* (unsorted / ascending / descending) is switched internally based on the `sortOrder` prop,
|
|
317
|
+
* so consumers only provide the behavior (e.g. `onClick`).
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
*
|
|
321
|
+
* ```tsx
|
|
322
|
+
* <DataTable.HeaderCell
|
|
323
|
+
* sortOrder={sortOrder}
|
|
324
|
+
* actions={<DataTable.SortButton sortOrder={sortOrder} onClick={handleSort} />}
|
|
325
|
+
* >
|
|
326
|
+
* Age
|
|
327
|
+
* </DataTable.HeaderCell>
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
330
|
+
SortButton: import("react").ForwardRefExoticComponent<Omit<import("..").IconButtonProps, "aria-label" | "children"> & {
|
|
331
|
+
'aria-label'?: import("..").IconButtonProps['aria-label'];
|
|
332
|
+
sortOrder?: 'ascending' | 'descending';
|
|
333
|
+
} & import("react").RefAttributes<HTMLAnchorElement | HTMLButtonElement>>;
|
|
284
334
|
};
|
|
@@ -8,7 +8,9 @@ import { DataTableCell } from './DataTableCell';
|
|
|
8
8
|
import { DataTableHeader } from './DataTableHeader';
|
|
9
9
|
import { DataTableHeaderCell } from './DataTableHeaderCell';
|
|
10
10
|
import { DataTableHeaderRow } from './DataTableHeaderRow';
|
|
11
|
+
import { DataTableFilterButton } from './DataTableFilterButton';
|
|
11
12
|
import { DataTableRow } from './DataTableRow';
|
|
13
|
+
import { DataTableSortButton } from './DataTableSortButton';
|
|
12
14
|
import { cx } from '../../styled-system/css';
|
|
13
15
|
import { isComponentOrWrapped } from '../utilities/react/isComponentOrWrapped';
|
|
14
16
|
const Base = forwardRef(({ className, size = 'medium', enableRowSelection = false, fixedHeader = false, showVerticalBorder = false, leftFixedColumnIndex, rightFixedColumnIndex, layout = 'default', wrapperProps, loading = false, emptyStateSlot, children, ...props }, ref) => {
|
|
@@ -324,4 +326,46 @@ export const DataTable = Object.assign(Base, {
|
|
|
324
326
|
* ```
|
|
325
327
|
*/
|
|
326
328
|
Row: DataTableRow,
|
|
329
|
+
/**
|
|
330
|
+
* The `DataTableFilterButton` component.
|
|
331
|
+
* An icon-only filter button intended to be placed in the `actions` of `DataTable.HeaderCell`.
|
|
332
|
+
*
|
|
333
|
+
* It extends the props of `IconButton` except `children`. The filter icon
|
|
334
|
+
* (outline / filled) is switched internally based on the `filtered` prop, and the button is
|
|
335
|
+
* internally wired as the trigger of a `Popover` rendering `renderContent` — consumers only
|
|
336
|
+
* provide the filter state and the popover content.
|
|
337
|
+
*
|
|
338
|
+
* @example
|
|
339
|
+
*
|
|
340
|
+
* ```tsx
|
|
341
|
+
* <DataTable.HeaderCell
|
|
342
|
+
* actions={
|
|
343
|
+
* <DataTable.FilterButton filtered={isFiltered} renderContent={() => <FilterOptions />} />
|
|
344
|
+
* }
|
|
345
|
+
* >
|
|
346
|
+
* Name
|
|
347
|
+
* </DataTable.HeaderCell>
|
|
348
|
+
* ```
|
|
349
|
+
*/
|
|
350
|
+
FilterButton: DataTableFilterButton,
|
|
351
|
+
/**
|
|
352
|
+
* The `DataTableSortButton` component.
|
|
353
|
+
* An icon-only sort button intended to be placed in the `actions` of `DataTable.HeaderCell`.
|
|
354
|
+
*
|
|
355
|
+
* It extends the props of `IconButton` except `children` — the sort icon
|
|
356
|
+
* (unsorted / ascending / descending) is switched internally based on the `sortOrder` prop,
|
|
357
|
+
* so consumers only provide the behavior (e.g. `onClick`).
|
|
358
|
+
*
|
|
359
|
+
* @example
|
|
360
|
+
*
|
|
361
|
+
* ```tsx
|
|
362
|
+
* <DataTable.HeaderCell
|
|
363
|
+
* sortOrder={sortOrder}
|
|
364
|
+
* actions={<DataTable.SortButton sortOrder={sortOrder} onClick={handleSort} />}
|
|
365
|
+
* >
|
|
366
|
+
* Age
|
|
367
|
+
* </DataTable.HeaderCell>
|
|
368
|
+
* ```
|
|
369
|
+
*/
|
|
370
|
+
SortButton: DataTableSortButton,
|
|
327
371
|
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const DataTableFilterButton: import("react").ForwardRefExoticComponent<Omit<import("../..").IconButtonProps, "aria-label" | "children" | "customLinkComponent" | "href" | "target"> & {
|
|
2
|
+
'aria-label'?: import("../..").IconButtonProps['aria-label'];
|
|
3
|
+
popoverProps?: Pick<import("react").ComponentPropsWithoutRef<'div'>, 'aria-label' | 'aria-labelledby'>;
|
|
4
|
+
filtered?: boolean;
|
|
5
|
+
renderContent: import("../..").PopoverProps['renderContent'];
|
|
6
|
+
} & import("react").RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Filter, FilterOn } from '@moneyforward/mfui-icons-react';
|
|
3
|
+
import { forwardRef, useCallback, useId, useRef } from 'react';
|
|
4
|
+
import { dataTableFilterButtonSlotRecipe } from '../../../styled-system/recipes';
|
|
5
|
+
import { IconButton } from '../../IconButton';
|
|
6
|
+
import { Popover } from '../../Popover';
|
|
7
|
+
import { getFocusableNodes } from '../../utilities/dom/getFocusableNodes';
|
|
8
|
+
import { mergeRefs } from '../../utilities/dom/mergeRefs';
|
|
9
|
+
import { useFocusTrap } from '../../utilities/dom/useFocusTrap';
|
|
10
|
+
import { cx } from '../../../styled-system/css';
|
|
11
|
+
export const DataTableFilterButton = forwardRef(({ filtered = false, renderContent, 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedBy, popoverProps, onClick, onKeyDown, onBlur, className, ...props }, ref) => {
|
|
12
|
+
const filteredDescriptionId = useId();
|
|
13
|
+
const popoverContentId = useId();
|
|
14
|
+
const triggerRef = useRef(null);
|
|
15
|
+
const triggerLabel = ariaLabel ?? '絞り込み';
|
|
16
|
+
const dialogLabel = popoverProps?.['aria-label'] ?? '絞り込み条件';
|
|
17
|
+
const describedBy = [ariaDescribedBy, filtered ? filteredDescriptionId : undefined].filter(Boolean).join(' ');
|
|
18
|
+
const classes = dataTableFilterButtonSlotRecipe({ filtered });
|
|
19
|
+
const { handleOnKeyDown: handleFocusTrapKeyDown } = useFocusTrap({
|
|
20
|
+
onPressingTabOnNotFocusableElement: (event) => {
|
|
21
|
+
const nodes = getFocusableNodes(event.currentTarget);
|
|
22
|
+
const focusableNodeAfterFocusingNode = nodes.find((element) =>
|
|
23
|
+
// eslint-disable-next-line no-bitwise
|
|
24
|
+
element.compareDocumentPosition(event.target) & Node.DOCUMENT_POSITION_PRECEDING);
|
|
25
|
+
(focusableNodeAfterFocusingNode ?? nodes.at(0))?.focus();
|
|
26
|
+
event.preventDefault();
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
// Focus the dialog container itself (tabIndex={-1}) on open — not its first control —
|
|
30
|
+
// so opening with the mouse and with the keyboard behave the same: the first Tab always
|
|
31
|
+
// moves into the first control.
|
|
32
|
+
const focusInitialElement = useCallback((node) => {
|
|
33
|
+
node?.focus();
|
|
34
|
+
}, []);
|
|
35
|
+
return (_jsx(Popover
|
|
36
|
+
// handleTriggerKeyDown is intentionally not wired: arrow-key opening belongs to
|
|
37
|
+
// menu/listbox patterns, while this trigger opens a dialog.
|
|
38
|
+
, {
|
|
39
|
+
// handleTriggerKeyDown is intentionally not wired: arrow-key opening belongs to
|
|
40
|
+
// menu/listbox patterns, while this trigger opens a dialog.
|
|
41
|
+
renderTrigger: ({ setTriggerRef, togglePopover, closePopover, isPopoverOpen, handleTriggerBlur }) => (_jsxs(_Fragment, { children: [_jsx(IconButton, { ref: mergeRefs(ref, setTriggerRef, triggerRef), ...props, className: cx(classes.root, 'mfui-DataTableFilterButton__root', className), "aria-label": triggerLabel, "aria-describedby": describedBy || undefined, "aria-haspopup": "dialog", "aria-expanded": isPopoverOpen, "aria-controls": popoverContentId, onClick: (event) => {
|
|
42
|
+
togglePopover(event);
|
|
43
|
+
onClick?.(event);
|
|
44
|
+
}, onKeyDown: (event) => {
|
|
45
|
+
// The popover's own Escape handler lives on the portaled content, so it never
|
|
46
|
+
// sees a keydown fired on the trigger (e.g. after Shift+Tab back while open).
|
|
47
|
+
if (event.key === 'Escape' && isPopoverOpen) {
|
|
48
|
+
event.stopPropagation();
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
closePopover(event);
|
|
51
|
+
}
|
|
52
|
+
onKeyDown?.(event);
|
|
53
|
+
}, onBlur: (event) => {
|
|
54
|
+
handleTriggerBlur(event);
|
|
55
|
+
onBlur?.(event);
|
|
56
|
+
}, children: filtered ? _jsx(FilterOn, {}) : _jsx(Filter, {}) }), filtered ? (_jsx("span", { id: filteredDescriptionId, className: cx(classes.filteredDescription, 'mfui-DataTableFilterButton__filteredDescription'), children: "\u9069\u7528\u4E2D" })) : null] })), renderContent: (options) => (_jsx("div", { ref: focusInitialElement, role: "dialog", "aria-label": dialogLabel, "aria-labelledby": popoverProps?.['aria-labelledby'], tabIndex: -1, className: cx(classes.dialog, 'mfui-DataTableFilterButton__dialog'), onKeyDown: handleFocusTrapKeyDown, children: renderContent(options) })), contentProps: { id: popoverContentId }, enableAutoFocusOnPopover: false, onClose: (event) => {
|
|
57
|
+
// Keep Escape focus restoration scoped to the filter button instead of changing the shared Popover.
|
|
58
|
+
if (event && 'key' in event && event.key === 'Escape') {
|
|
59
|
+
triggerRef.current?.focus();
|
|
60
|
+
}
|
|
61
|
+
} }));
|
|
62
|
+
});
|
|
63
|
+
DataTableFilterButton.displayName = 'DataTableFilterButton';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type ComponentPropsWithoutRef } from 'react';
|
|
2
|
+
import { type IconButtonProps } from '../../IconButton';
|
|
3
|
+
import { type PopoverProps } from '../../Popover';
|
|
4
|
+
/**
|
|
5
|
+
* The props for the `DataTableFilterButton` component.
|
|
6
|
+
*
|
|
7
|
+
* It extends the props of `IconButton` except `children` — the filter icon is
|
|
8
|
+
* rendered internally based on `filtered`, and the button is internally wired as
|
|
9
|
+
* the trigger of a `Popover` rendering `renderContent`. The link-related props
|
|
10
|
+
* (`href`, `customLinkComponent`, `target`) are also excluded: the trigger is
|
|
11
|
+
* always rendered as a `<button>` because a link cannot carry the disclosure
|
|
12
|
+
* semantics (`aria-haspopup` / `aria-expanded`).
|
|
13
|
+
*/
|
|
14
|
+
export type DataTableFilterButtonProps = Omit<IconButtonProps, 'children' | 'aria-label' | 'href' | 'customLinkComponent' | 'target'> & {
|
|
15
|
+
/**
|
|
16
|
+
* The accessible name of the filter button.
|
|
17
|
+
* Override this value to provide a label specific to the column being filtered
|
|
18
|
+
* (e.g. `担当者で絞り込む`).
|
|
19
|
+
*
|
|
20
|
+
* @default '絞り込み'
|
|
21
|
+
*/
|
|
22
|
+
'aria-label'?: IconButtonProps['aria-label'];
|
|
23
|
+
/**
|
|
24
|
+
* Props applied to the filter popover that the button opens.
|
|
25
|
+
* `aria-label` and `aria-labelledby` name its dialog element (`aria-labelledby` can
|
|
26
|
+
* reference a visible title rendered inside `renderContent`). When neither is
|
|
27
|
+
* provided, the dialog is named `絞り込み条件`.
|
|
28
|
+
*/
|
|
29
|
+
popoverProps?: Pick<ComponentPropsWithoutRef<'div'>, 'aria-label' | 'aria-labelledby'>;
|
|
30
|
+
/**
|
|
31
|
+
* Whether the column is currently filtered.
|
|
32
|
+
* The filter icon is switched internally according to this value:
|
|
33
|
+
*
|
|
34
|
+
* - `false`: outline filter icon
|
|
35
|
+
* - `true`: filled filter icon
|
|
36
|
+
*
|
|
37
|
+
* When `true`, the button is associated with an `適用中` description
|
|
38
|
+
* so the filtered state is exposed to assistive technologies without changing its accessible name.
|
|
39
|
+
*
|
|
40
|
+
* @default false
|
|
41
|
+
*/
|
|
42
|
+
filtered?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* The content of the filter popover (e.g. a list of checkboxes for the column values).
|
|
45
|
+
* The popover itself — trigger wiring, positioning, and open/close behavior — is
|
|
46
|
+
* handled internally.
|
|
47
|
+
*/
|
|
48
|
+
renderContent: PopoverProps['renderContent'];
|
|
49
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DataTableFilterButton } from './DataTableFilterButton';
|
|
@@ -9,7 +9,7 @@ import { cx } from '../../../styled-system/css';
|
|
|
9
9
|
import { useFixedColumns } from '../../utilities/dom/useFixedColumns';
|
|
10
10
|
import { handleCheckboxCellClick } from '../utils/handleCheckbox';
|
|
11
11
|
import { mergeRefs } from '../../utilities/dom/mergeRefs';
|
|
12
|
-
export const DataTableHeaderCell = forwardRef(({ children, type = 'text', sortButtonProps, sortOrder, ascendingIconProps, descendingIconProps, unsortedIconProps, className, columnIndex, disabled = false, ...props }, ref) => {
|
|
12
|
+
export const DataTableHeaderCell = forwardRef(({ children, type = 'text', sortButtonProps, sortOrder, actions, ascendingIconProps, descendingIconProps, unsortedIconProps, className, columnIndex, disabled = false, ...props }, ref) => {
|
|
13
13
|
const { size, leftFixedColumnIndex, rightFixedColumnIndex, enableRowSelection, showVerticalBorder } = useDataTableContext();
|
|
14
14
|
const { cellRef, isFixedColumn, isEdgeFixedColumn, fixedPositionStyles } = useFixedColumns({
|
|
15
15
|
enableRowSelection,
|
|
@@ -20,6 +20,7 @@ export const DataTableHeaderCell = forwardRef(({ children, type = 'text', sortBu
|
|
|
20
20
|
const classes = dataTableHeaderCellSlotRecipe({
|
|
21
21
|
size,
|
|
22
22
|
type,
|
|
23
|
+
hasActions: Boolean(actions),
|
|
23
24
|
fixedColumn: isFixedColumn,
|
|
24
25
|
edgeFixedColumn: isEdgeFixedColumn,
|
|
25
26
|
isCheckboxCell: enableRowSelection && columnIndex === 0,
|
|
@@ -53,7 +54,10 @@ export const DataTableHeaderCell = forwardRef(({ children, type = 'text', sortBu
|
|
|
53
54
|
return (_jsx("div", { className: cx(classes.headerCell, 'mfui-DataTableHeaderCell__headerCell',
|
|
54
55
|
/* TODO: Remove in v5.0.0 */ 'mfui-DataGridHeaderCell__headerCell'), children: isStringChild ? _jsx(Typography, { variant: "strongBody", children: children }) : children }));
|
|
55
56
|
})();
|
|
57
|
+
// Actions are rendered as siblings of the sort button (never inside it)
|
|
58
|
+
// to avoid nesting interactive elements.
|
|
59
|
+
const cellContentWithActions = actions ? (_jsxs("div", { className: cx(classes.container, 'mfui-DataTableHeaderCell__container'), children: [cellContent, _jsx("div", { className: cx(classes.actionsContainer, 'mfui-DataTableHeaderCell__actionsContainer'), children: actions })] })) : (cellContent);
|
|
56
60
|
return (_jsx("th", { ref: mergeRefs(ref, cellRef), className: cx(classes.root, 'mfui-DataTableHeaderCell__root',
|
|
57
|
-
/* TODO: Remove in v5.0.0 */ 'mfui-DataGridHeaderCell__root', className), "aria-sort": sortOrder, style: fixedPositionStyles, ...props, children:
|
|
61
|
+
/* TODO: Remove in v5.0.0 */ 'mfui-DataGridHeaderCell__root', className), "aria-sort": sortOrder, style: fixedPositionStyles, ...props, children: cellContentWithActions }));
|
|
58
62
|
});
|
|
59
63
|
DataTableHeaderCell.displayName = 'DataTableHeaderCell';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ComponentPropsWithRef, type ComponentPropsWithoutRef } from 'react';
|
|
1
|
+
import { type ComponentPropsWithRef, type ComponentPropsWithoutRef, type ReactNode } from 'react';
|
|
2
2
|
import { type CellDataType } from '../DataTable.types';
|
|
3
3
|
/**
|
|
4
4
|
* The props for the `DataTableHeaderCell` component.
|
|
@@ -61,6 +61,28 @@ export type DataTableHeaderCellProps = {
|
|
|
61
61
|
* @default undefined
|
|
62
62
|
*/
|
|
63
63
|
sortOrder?: 'ascending' | 'descending';
|
|
64
|
+
/**
|
|
65
|
+
* Action elements (e.g. `IconButton`) displayed at the right side of the header cell.
|
|
66
|
+
*
|
|
67
|
+
* The actions are rendered as siblings of the sort button, not inside it,
|
|
68
|
+
* so interactive elements are never nested even when used together with sorting.
|
|
69
|
+
*
|
|
70
|
+
* @default undefined
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```tsx
|
|
74
|
+
* <DataTable.HeaderCell
|
|
75
|
+
* actions={
|
|
76
|
+
* <IconButton aria-label="絞り込み">
|
|
77
|
+
* <Filter />
|
|
78
|
+
* </IconButton>
|
|
79
|
+
* }
|
|
80
|
+
* >
|
|
81
|
+
* Name
|
|
82
|
+
* </DataTable.HeaderCell>
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
actions?: ReactNode;
|
|
64
86
|
/**
|
|
65
87
|
* **Do not pass this prop manually.**
|
|
66
88
|
*
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const DataTableSortButton: import("react").ForwardRefExoticComponent<Omit<import("../..").IconButtonProps, "aria-label" | "children"> & {
|
|
2
|
+
'aria-label'?: import("../..").IconButtonProps['aria-label'];
|
|
3
|
+
sortOrder?: 'ascending' | 'descending';
|
|
4
|
+
} & import("react").RefAttributes<HTMLAnchorElement | HTMLButtonElement>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { SortAscending, SortDescending, SortUnsorted } from '@moneyforward/mfui-icons-react';
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
import { IconButton } from '../../IconButton';
|
|
5
|
+
import { dataTableSortButtonSlotRecipe } from '../../../styled-system/recipes';
|
|
6
|
+
import { cx } from '../../../styled-system/css';
|
|
7
|
+
export const DataTableSortButton = forwardRef(({ sortOrder, 'aria-label': ariaLabel = '並び替え', className, ...props }, ref) => {
|
|
8
|
+
const classes = dataTableSortButtonSlotRecipe({ sorted: Boolean(sortOrder) });
|
|
9
|
+
const sortIcon = (() => {
|
|
10
|
+
if (!sortOrder) {
|
|
11
|
+
return _jsx(SortUnsorted, {});
|
|
12
|
+
}
|
|
13
|
+
return sortOrder === 'ascending' ? _jsx(SortAscending, {}) : _jsx(SortDescending, {});
|
|
14
|
+
})();
|
|
15
|
+
return (_jsx(IconButton, { ref: ref, "aria-label": ariaLabel, className: cx(classes.root, 'mfui-DataTableSortButton__root', className), ...props, children: sortIcon }));
|
|
16
|
+
});
|
|
17
|
+
DataTableSortButton.displayName = 'DataTableSortButton';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type IconButtonProps } from '../../IconButton';
|
|
2
|
+
/**
|
|
3
|
+
* The props for the `DataTableSortButton` component.
|
|
4
|
+
*
|
|
5
|
+
* It extends the props of `IconButton` except `children` — the sort icon is
|
|
6
|
+
* rendered internally based on `sortOrder`.
|
|
7
|
+
*/
|
|
8
|
+
export type DataTableSortButtonProps = Omit<IconButtonProps, 'children' | 'aria-label'> & {
|
|
9
|
+
/**
|
|
10
|
+
* The accessible name of the sort button.
|
|
11
|
+
* Override this value to provide a label specific to the column being sorted.
|
|
12
|
+
*
|
|
13
|
+
* @default '並び替え'
|
|
14
|
+
*/
|
|
15
|
+
'aria-label'?: IconButtonProps['aria-label'];
|
|
16
|
+
/**
|
|
17
|
+
* The current sort order of the column.
|
|
18
|
+
* The sort icon is switched internally according to this value:
|
|
19
|
+
*
|
|
20
|
+
* - `undefined`: unsorted icon
|
|
21
|
+
* - `'ascending'`: ascending icon
|
|
22
|
+
* - `'descending'`: descending icon
|
|
23
|
+
*/
|
|
24
|
+
sortOrder?: 'ascending' | 'descending';
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DataTableSortButton } from './DataTableSortButton';
|
|
@@ -6,4 +6,6 @@ export type { DataTableCellProps } from './DataTableCell';
|
|
|
6
6
|
export type { DataTableHeaderProps } from './DataTableHeader';
|
|
7
7
|
export type { DataTableHeaderCellProps } from './DataTableHeaderCell';
|
|
8
8
|
export type { DataTableHeaderRowProps } from './DataTableHeaderRow';
|
|
9
|
+
export type { DataTableFilterButtonProps } from './DataTableFilterButton';
|
|
9
10
|
export type { DataTableRowProps } from './DataTableRow';
|
|
11
|
+
export type { DataTableSortButtonProps } from './DataTableSortButton';
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useCallback } from 'react';
|
|
3
3
|
import dayjs from 'dayjs';
|
|
4
4
|
import { useBasePickerContext } from '../../shared/BasePicker/BasePickerProvider';
|
|
5
|
+
import { useCalendarLocale } from '../../shared/CalendarLocale/CalendarLocaleContext';
|
|
5
6
|
import { DateCell } from '../../shared/DateCell';
|
|
6
7
|
import { getDateAriaAttributes } from '../../shared/accessibility';
|
|
7
8
|
/**
|
|
@@ -14,10 +15,12 @@ import { getDateAriaAttributes } from '../../shared/accessibility';
|
|
|
14
15
|
*/
|
|
15
16
|
export function DatePickerDateCell({ date, selected, disabled, onKeyDown, ...otherProps }) {
|
|
16
17
|
const { viewingValue, setViewingValue, setPendingFocusDate } = useBasePickerContext();
|
|
18
|
+
const calendarLocale = useCalendarLocale();
|
|
17
19
|
const ariaAttributes = getDateAriaAttributes({
|
|
18
20
|
date,
|
|
19
21
|
selected,
|
|
20
22
|
disabled,
|
|
23
|
+
locale: calendarLocale,
|
|
21
24
|
});
|
|
22
25
|
const handleKeyDown = useCallback((event) => {
|
|
23
26
|
const { key, currentTarget } = event;
|
|
@@ -6,7 +6,7 @@ export type DateRangePickerDateCellProps = DateCellProps & {
|
|
|
6
6
|
isRangeEnd?: boolean;
|
|
7
7
|
};
|
|
8
8
|
/**
|
|
9
|
-
* DateRangePicker-specific DateCell component with enhanced accessibility
|
|
10
|
-
*
|
|
9
|
+
* DateRangePicker-specific DateCell component with enhanced accessibility.
|
|
10
|
+
* Provides locale-aware labels and range-specific context.
|
|
11
11
|
*/
|
|
12
12
|
export declare function DateRangePickerDateCell({ date, selected, inRange, disabled, isRangeStart, isRangeEnd, ...rest }: DateRangePickerDateCellProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { DateCell } from '../../../shared/DateCell';
|
|
3
|
+
import { useCalendarLocale } from '../../../shared/CalendarLocale/CalendarLocaleContext';
|
|
3
4
|
import { getDateAriaAttributes } from '../../../shared/accessibility';
|
|
4
5
|
/**
|
|
5
|
-
* DateRangePicker-specific DateCell component with enhanced accessibility
|
|
6
|
-
*
|
|
6
|
+
* DateRangePicker-specific DateCell component with enhanced accessibility.
|
|
7
|
+
* Provides locale-aware labels and range-specific context.
|
|
7
8
|
*/
|
|
8
9
|
export function DateRangePickerDateCell({ date, selected, inRange, disabled, isRangeStart, isRangeEnd, ...rest }) {
|
|
10
|
+
const calendarLocale = useCalendarLocale();
|
|
9
11
|
const ariaAttributes = getDateAriaAttributes({
|
|
10
12
|
date,
|
|
11
13
|
selected,
|
|
@@ -13,6 +15,7 @@ export function DateRangePickerDateCell({ date, selected, inRange, disabled, isR
|
|
|
13
15
|
disabled,
|
|
14
16
|
isRangeStart,
|
|
15
17
|
isRangeEnd,
|
|
18
|
+
locale: calendarLocale,
|
|
16
19
|
});
|
|
17
20
|
return (_jsx(DateCell, { ...rest, date: date, selected: selected, inRange: inRange, disabled: disabled, ...ariaAttributes }));
|
|
18
21
|
}
|
package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerTrigger/DateRangePickerTrigger.js
CHANGED
|
@@ -16,7 +16,7 @@ import { useDateRangeTriggerInputClick } from './hooks/useDateRangeTriggerInputC
|
|
|
16
16
|
* Trigger component for DateRangePicker
|
|
17
17
|
* Handles the display and interaction of the date range input field
|
|
18
18
|
*/
|
|
19
|
-
export const DateRangePickerTrigger = forwardRef(({ enableClearValue = false, invalid = false, size = 'medium', disabled = false, wrapperProps = {}, clearButtonProps = {}, startInputProps = {}, endInputProps = {}, calendarButtonProps = {}, startInputRef, endInputRef, popoverOpenFunction, format = 'YYYY-MM-DD', ...props }, ref) => {
|
|
19
|
+
export const DateRangePickerTrigger = forwardRef(({ enableClearValue = false, invalid = false, caution = false, size = 'medium', disabled = false, wrapperProps = {}, clearButtonProps = {}, startInputProps = {}, endInputProps = {}, calendarButtonProps = {}, startInputRef, endInputRef, popoverOpenFunction, format = 'YYYY-MM-DD', ...props }, ref) => {
|
|
20
20
|
const { toggle, disableAutoOpen } = useDateRangePickerContext();
|
|
21
21
|
const { handleInputClick } = useDateRangeTriggerInputClick(disableAutoOpen ?? false, popoverOpenFunction);
|
|
22
22
|
const { onClick: onClickClearButton, 'aria-label': clearAriaLabel = LOCALE.CLEAR_BUTTON_LABEL } = clearButtonProps;
|
|
@@ -35,7 +35,8 @@ export const DateRangePickerTrigger = forwardRef(({ enableClearValue = false, in
|
|
|
35
35
|
const { placeholder: startPlaceholder = LOCALE.START_DATE_PLACEHOLDER } = startInputProps;
|
|
36
36
|
const { placeholder: endPlaceholder = LOCALE.END_DATE_PLACEHOLDER } = endInputProps;
|
|
37
37
|
const shouldShowClearButton = enableClearValue && (enhancedStartInputProps.value || enhancedEndInputProps.value);
|
|
38
|
-
|
|
38
|
+
// The error state takes precedence over the caution state
|
|
39
|
+
const classes = baseRangePickerTriggerSlotRecipe({ invalid, caution: caution && !invalid, disabled, size });
|
|
39
40
|
const handleClickClearButton = useCallback((event) => {
|
|
40
41
|
handleClear();
|
|
41
42
|
onClickClearButton?.(event);
|
|
@@ -11,6 +11,23 @@ export type DateRangePickerTriggerProps = {
|
|
|
11
11
|
* @default false
|
|
12
12
|
*/
|
|
13
13
|
invalid?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Whether the inputs need the user's attention while still being submittable.
|
|
16
|
+
*
|
|
17
|
+
* This changes the border color only, so you must also render an adjacent
|
|
18
|
+
* `<HelpMessage messageType="caution">` describing the concern — color alone does not
|
|
19
|
+
* convey the state (WCAG 2.2 1.4.1).
|
|
20
|
+
*
|
|
21
|
+
* Associate that `HelpMessage` with both inputs via `startInputProps['aria-describedby']`
|
|
22
|
+
* and `endInputProps['aria-describedby']` so screen readers announce it on focus, and give
|
|
23
|
+
* it `role="status"` so it is also announced the moment it appears while focus is already
|
|
24
|
+
* inside one of the inputs.
|
|
25
|
+
*
|
|
26
|
+
* Ignored while `invalid` is `true`, because the error state takes precedence.
|
|
27
|
+
*
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
caution?: boolean;
|
|
14
31
|
/**
|
|
15
32
|
* Whether to enable the clear functionality
|
|
16
33
|
*
|
|
@@ -10,6 +10,7 @@ import { cx } from '../../../../styled-system/css';
|
|
|
10
10
|
import { dayjs } from '../../../utilities/date/dayjs';
|
|
11
11
|
import { DateRangePickerPopover } from '../../DateRangePicker/DateRangePickerPopover';
|
|
12
12
|
import { CalendarLocaleProvider } from '../../shared/CalendarLocale/CalendarLocaleContext';
|
|
13
|
+
import { getBaseRangePickerTriggerLabel } from '../../shared/BaseRangePicker/BaseRangePickerTrigger/constants';
|
|
13
14
|
import { useBaseRangePickerContext } from '../../shared/BaseRangePicker/BaseRangePickerProvider';
|
|
14
15
|
/**
|
|
15
16
|
* Internal component that accesses BaseRangePickerContext for display and clear handling.
|
|
@@ -29,5 +30,6 @@ export function InternalDateRangePickerContent({ classes, triggerRef, dialogId,
|
|
|
29
30
|
const dateToFocus = startDate ?? endDate ?? new Date();
|
|
30
31
|
setPendingFocusDate(dayjs(dateToFocus).format('YYYY-MM-DD'));
|
|
31
32
|
}, [startDate, endDate, setPendingFocusDate]);
|
|
32
|
-
return (_jsx(Popover, { open: isCalendarOpen, targetDOMNode: targetDOMNode, minWidth: "min-content", allowedPlacements: ['bottom-start', 'top-start'], renderTrigger: ({ setTriggerRef, togglePopover, handleTriggerKeyDown, handleTriggerBlur }) => (_jsxs("div", { ref: setTriggerRef, "data-selected": hasValue, className: cx(classes.wrapper, 'mfui-FilterDateRangePicker__wrapper'), children: [_jsx(FocusIndicator, { children: _jsxs("button", { ref: triggerRef, type: "button", disabled: disabled, className: cx(classes.trigger, 'mfui-FilterDateRangePicker__trigger', className), "data-selected": hasValue, "data-mfui-has-clear-button": enableClearButton ? hasValue : null, "aria-controls": dialogId, "aria-expanded": isCalendarOpen, "aria-haspopup": "dialog", onClick: togglePopover, onKeyDown: handleTriggerKeyDown, onBlur: handleTriggerBlur, children: [_jsx("span", { className: cx(classes.content, 'mfui-FilterDateRangePicker__content'), "data-mfui-content": "filter-date-range-picker-display-value", children: hasValue ? (_jsxs(Typography, { variant: "strongBody", children: [_jsx("span", { "data-mfui-content": "filter-date-range-picker-label", children: `${label}:` }), _jsx("span", { "data-mfui-content": "filter-date-range-picker-value", children: formattedValue })] })) : (_jsx(Typography, { variant: "controlLabel", children: _jsx("span", { "data-mfui-content": "filter-date-range-picker-label", children: label }) })) }), _jsx("span", { className: cx(classes.calendarIcon, 'mfui-FilterDateRangePicker__calendarIcon'), children: _jsx(CalendarIcon, { "aria-hidden": true }) })] }) }), enableClearButton && hasValue ? (_jsx("div", { className: cx(classes.clearButtonWrapper, 'mfui-FilterDateRangePicker__clearButtonWrapper'), children: _jsx(ClearButton, { "aria-label": clearButtonProps?.['aria-label'] ??
|
|
33
|
+
return (_jsx(Popover, { open: isCalendarOpen, targetDOMNode: targetDOMNode, minWidth: "min-content", allowedPlacements: ['bottom-start', 'top-start'], renderTrigger: ({ setTriggerRef, togglePopover, handleTriggerKeyDown, handleTriggerBlur }) => (_jsxs("div", { ref: setTriggerRef, "data-selected": hasValue, className: cx(classes.wrapper, 'mfui-FilterDateRangePicker__wrapper'), children: [_jsx(FocusIndicator, { children: _jsxs("button", { ref: triggerRef, type: "button", disabled: disabled, className: cx(classes.trigger, 'mfui-FilterDateRangePicker__trigger', className), "data-selected": hasValue, "data-mfui-has-clear-button": enableClearButton ? hasValue : null, "aria-controls": dialogId, "aria-expanded": isCalendarOpen, "aria-haspopup": "dialog", onClick: togglePopover, onKeyDown: handleTriggerKeyDown, onBlur: handleTriggerBlur, children: [_jsx("span", { className: cx(classes.content, 'mfui-FilterDateRangePicker__content'), "data-mfui-content": "filter-date-range-picker-display-value", children: hasValue ? (_jsxs(Typography, { variant: "strongBody", children: [_jsx("span", { "data-mfui-content": "filter-date-range-picker-label", children: `${label}:` }), _jsx("span", { "data-mfui-content": "filter-date-range-picker-value", children: formattedValue })] })) : (_jsx(Typography, { variant: "controlLabel", children: _jsx("span", { "data-mfui-content": "filter-date-range-picker-label", children: label }) })) }), _jsx("span", { className: cx(classes.calendarIcon, 'mfui-FilterDateRangePicker__calendarIcon'), children: _jsx(CalendarIcon, { "aria-hidden": true }) })] }) }), enableClearButton && hasValue ? (_jsx("div", { className: cx(classes.clearButtonWrapper, 'mfui-FilterDateRangePicker__clearButtonWrapper'), children: _jsx(ClearButton, { "aria-label": clearButtonProps?.['aria-label'] ??
|
|
34
|
+
getBaseRangePickerTriggerLabel('CLEAR_BUTTON_LABEL', calendarLocale), "data-mfui-content": "filter-date-range-picker-clear-button", disabled: disabled, onClick: handleTriggerClear }) })) : null] })), renderContent: () => (_jsx("div", { id: dialogId, role: "dialog", "aria-label": label, className: cx(classes.popoverWrapper, 'mfui-FilterDateRangePicker__popoverWrapper'), children: _jsx(CalendarLocaleProvider, { value: calendarLocale, children: _jsx(DateRangePickerPopover, {}) }) })), onOpenStateChanged: toggleCalendar, onOpen: handlePopoverOpen }));
|
|
33
35
|
}
|
|
@@ -48,7 +48,8 @@ export type FilterDateRangePickerProps = {
|
|
|
48
48
|
/**
|
|
49
49
|
* Props for the clear button.
|
|
50
50
|
*
|
|
51
|
-
* @property aria-label - The alternative text for the clear button.
|
|
51
|
+
* @property aria-label - The alternative text for the clear button.
|
|
52
|
+
* Default follows `calendarLocale` ('値をクリアする' for 'ja', 'Clear value' for 'en').
|
|
52
53
|
*/
|
|
53
54
|
clearButtonProps?: {
|
|
54
55
|
'aria-label'?: string;
|
|
@@ -45,7 +45,8 @@ export type FilterMonthPickerProps = {
|
|
|
45
45
|
/**
|
|
46
46
|
* Props for the clear button.
|
|
47
47
|
*
|
|
48
|
-
* @property aria-label - The alternative text for the clear button.
|
|
48
|
+
* @property aria-label - The alternative text for the clear button.
|
|
49
|
+
* Default follows `calendarLocale` ('値をクリアする' for 'ja', 'Clear value' for 'en').
|
|
49
50
|
*/
|
|
50
51
|
clearButtonProps?: {
|
|
51
52
|
'aria-label'?: string;
|
package/dist/src/DateTimeSelection/FilterMonthPicker/MonthPickerPopover/MonthPickerPopover.js
CHANGED
|
@@ -10,6 +10,7 @@ import { cx } from '../../../../styled-system/css';
|
|
|
10
10
|
import { dayjs } from '../../../utilities/date/dayjs';
|
|
11
11
|
import { MonthPickerPanel } from '../../MonthPicker/MonthPickerPanel/MonthPickerPanel';
|
|
12
12
|
import { CalendarLocaleProvider } from '../../shared/CalendarLocale/CalendarLocaleContext';
|
|
13
|
+
import { getBasePickerLabel } from '../../shared/BasePicker/constants';
|
|
13
14
|
import { useBasePickerContext } from '../../shared/BasePicker/BasePickerProvider';
|
|
14
15
|
import { useFocusTrap } from '../../../utilities/dom/useFocusTrap';
|
|
15
16
|
import { getFocusableNodes } from '../../../utilities/dom/getFocusableNodes';
|
|
@@ -39,7 +40,7 @@ export function InternalMonthPickerPopover({ currentValue, defaultValue, isPicke
|
|
|
39
40
|
setViewingValue(monthToFocus);
|
|
40
41
|
setPendingFocusDate(dayjs(monthToFocus).format(MONTH_BASE_FORMAT));
|
|
41
42
|
}, [currentValue, defaultValue, setViewingValue, setPendingFocusDate]);
|
|
42
|
-
return (_jsx(Popover, { open: isPickerOpen, targetDOMNode: targetDOMNode, renderTrigger: ({ setTriggerRef, togglePopover, handleTriggerKeyDown, handleTriggerBlur }) => (_jsxs("div", { ref: setTriggerRef, "data-selected": hasValue, className: cx(classes.wrapper, 'mfui-FilterMonthPicker__wrapper'), children: [_jsx(FocusIndicator, { children: _jsxs("button", { ref: triggerRef, type: "button", disabled: disabled, className: cx(classes.trigger, 'mfui-FilterMonthPicker__trigger', className), "data-selected": hasValue, "data-mfui-has-clear-button": enableClearButton ? hasValue : null, "aria-controls": dialogId, "aria-expanded": isPickerOpen, "aria-haspopup": "dialog", onClick: togglePopover, onKeyDown: handleTriggerKeyDown, onBlur: handleTriggerBlur, children: [_jsx("span", { className: cx(classes.content, 'mfui-FilterMonthPicker__content'), "data-mfui-content": "filter-month-picker-display-value", children: hasValue ? (_jsxs(Typography, { variant: "strongBody", children: [_jsx("span", { "data-mfui-content": "filter-month-picker-label", children: `${label}:` }), _jsx("span", { "data-mfui-content": "filter-month-picker-value", children: formattedValue })] })) : (_jsx(Typography, { variant: "controlLabel", children: _jsx("span", { "data-mfui-content": "filter-month-picker-label", children: label }) })) }), _jsx("span", { className: cx(classes.calendarIcon, 'mfui-FilterMonthPicker__calendarIcon'), children: _jsx(CalendarIcon, { "aria-hidden": true }) })] }) }), enableClearButton && hasValue ? (_jsx("div", { className: cx(classes.clearButtonWrapper, 'mfui-FilterMonthPicker__clearButtonWrapper'), children: _jsx(ClearButton, { "aria-label": clearButtonProps?.['aria-label'] ?? '
|
|
43
|
+
return (_jsx(Popover, { open: isPickerOpen, targetDOMNode: targetDOMNode, renderTrigger: ({ setTriggerRef, togglePopover, handleTriggerKeyDown, handleTriggerBlur }) => (_jsxs("div", { ref: setTriggerRef, "data-selected": hasValue, className: cx(classes.wrapper, 'mfui-FilterMonthPicker__wrapper'), children: [_jsx(FocusIndicator, { children: _jsxs("button", { ref: triggerRef, type: "button", disabled: disabled, className: cx(classes.trigger, 'mfui-FilterMonthPicker__trigger', className), "data-selected": hasValue, "data-mfui-has-clear-button": enableClearButton ? hasValue : null, "aria-controls": dialogId, "aria-expanded": isPickerOpen, "aria-haspopup": "dialog", onClick: togglePopover, onKeyDown: handleTriggerKeyDown, onBlur: handleTriggerBlur, children: [_jsx("span", { className: cx(classes.content, 'mfui-FilterMonthPicker__content'), "data-mfui-content": "filter-month-picker-display-value", children: hasValue ? (_jsxs(Typography, { variant: "strongBody", children: [_jsx("span", { "data-mfui-content": "filter-month-picker-label", children: `${label}:` }), _jsx("span", { "data-mfui-content": "filter-month-picker-value", children: formattedValue })] })) : (_jsx(Typography, { variant: "controlLabel", children: _jsx("span", { "data-mfui-content": "filter-month-picker-label", children: label }) })) }), _jsx("span", { className: cx(classes.calendarIcon, 'mfui-FilterMonthPicker__calendarIcon'), children: _jsx(CalendarIcon, { "aria-hidden": true }) })] }) }), enableClearButton && hasValue ? (_jsx("div", { className: cx(classes.clearButtonWrapper, 'mfui-FilterMonthPicker__clearButtonWrapper'), children: _jsx(ClearButton, { "aria-label": clearButtonProps?.['aria-label'] ?? getBasePickerLabel('CLEAR_VALUE', calendarLocale), "data-mfui-content": "filter-month-picker-clear-button", disabled: disabled, onClick: handleClear }) })) : null] })), renderContent: () => (_jsx("div", { id: dialogId, role: "dialog", "aria-label": label, className: "mfui-FilterMonthPicker__popoverWrapper", onKeyDown: handleOnKeyDown, children: _jsx(CalendarLocaleProvider, { value: calendarLocale, children: _jsx(MonthPickerPanel, { viewingValue: viewingValue, setViewingValue: setViewingValue, value: currentValue, minMonth: minMonth, maxMonth: maxMonth, checkDisabledMonth: checkDisabledMonth, onChange: (date) => {
|
|
43
44
|
handleValueChange(date);
|
|
44
45
|
} }) }) })), minWidth: "min-content", allowedPlacements: ['bottom-start', 'top-start'], onOpenStateChanged: togglePicker, onOpen: handlePopoverOpen }));
|
|
45
46
|
}
|
|
@@ -6,6 +6,7 @@ import { getMonthCellMonthFormat } from '../../shared/utilities/monthCellMonthFo
|
|
|
6
6
|
import { dayjs } from '../../../utilities/date/dayjs';
|
|
7
7
|
import { MONTH_RANGE_PICKER_A11Y_LABELS } from './constants';
|
|
8
8
|
import 'dayjs/locale/en';
|
|
9
|
+
import 'dayjs/locale/ja';
|
|
9
10
|
/**
|
|
10
11
|
* MonthRangePickerMonthCell component that wraps MonthCell with range selection visual states.
|
|
11
12
|
*
|
|
@@ -26,26 +27,28 @@ export function MonthRangePickerMonthCell({ isInRange, isRangeStart, isRangeEnd,
|
|
|
26
27
|
const monthFormat = useMemo(() => getMonthCellMonthFormat(calendarLocale, monthCellProps.date), [calendarLocale, monthCellProps.date]);
|
|
27
28
|
// Create accessible label for range selection
|
|
28
29
|
const accessibleLabel = useMemo(() => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
// Fall back to 'ja' so an unknown locale from untyped consumers cannot crash the calendar
|
|
31
|
+
const safeLocale = calendarLocale in MONTH_RANGE_PICKER_A11Y_LABELS ? calendarLocale : 'ja';
|
|
32
|
+
const labels = MONTH_RANGE_PICKER_A11Y_LABELS[safeLocale];
|
|
33
|
+
// Pin the dayjs locale per call so the output does not depend on the global dayjs locale
|
|
34
|
+
const monthText = dayjs(monthCellProps.date).locale(safeLocale).format('MMMM YYYY');
|
|
32
35
|
const statusParts = [];
|
|
33
36
|
if (monthCellProps.disabled) {
|
|
34
|
-
statusParts.push(
|
|
37
|
+
statusParts.push(labels.UNAVAILABLE);
|
|
35
38
|
}
|
|
36
39
|
else if (selected) {
|
|
37
40
|
if (isRangeStart) {
|
|
38
|
-
statusParts.push(
|
|
41
|
+
statusParts.push(labels.RANGE_START);
|
|
39
42
|
}
|
|
40
43
|
else if (isRangeEnd) {
|
|
41
|
-
statusParts.push(
|
|
44
|
+
statusParts.push(labels.RANGE_END);
|
|
42
45
|
}
|
|
43
46
|
else {
|
|
44
|
-
statusParts.push(
|
|
47
|
+
statusParts.push(labels.SELECTED);
|
|
45
48
|
}
|
|
46
49
|
}
|
|
47
50
|
else if (isInRange) {
|
|
48
|
-
statusParts.push(
|
|
51
|
+
statusParts.push(labels.IN_RANGE);
|
|
49
52
|
}
|
|
50
53
|
return statusParts.length > 0 ? `${monthText}, ${statusParts.join(', ')}` : monthText;
|
|
51
54
|
}, [calendarLocale, monthCellProps.date, monthCellProps.disabled, selected, isInRange, isRangeStart, isRangeEnd]);
|