@moneyforward/mfui-components 3.13.0 → 3.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -63,7 +63,7 @@ const AccordionTrigger = forwardRef(({ children, className, onClick, ...props },
63
63
  toggle();
64
64
  onClick?.(event);
65
65
  }, [onClick, toggle]);
66
- return (_jsx(FocusIndicator, { children: _jsxs("button", { ref: ref, className: cx(classes.trigger, 'mfui-Accordion__trigger', className), "aria-expanded": isOpen, "aria-controls": id, onClick: handleClick, ...props, children: [_jsx(Typography, { variant: "controlLabel", children: children }), isOpen ? _jsx(DisclosureBasicExpanded, {}) : _jsx(DisclosureBasicCollapsed, {})] }) }));
66
+ return (_jsx(FocusIndicator, { children: _jsxs("button", { ref: ref, className: cx(classes.trigger, 'mfui-Accordion__trigger', className), "aria-expanded": isOpen, "aria-controls": id, onClick: handleClick, ...props, children: [_jsx(Typography, { variant: "controlLabel", children: children }), isOpen ? _jsx(DisclosureBasicExpanded, { "aria-hidden": "true" }) : _jsx(DisclosureBasicCollapsed, { "aria-hidden": "true" })] }) }));
67
67
  });
68
68
  const AccordionTarget = forwardRef(({ children, className, style, ...props }, ref) => {
69
69
  const { size } = useAccordionContext();
@@ -31,14 +31,26 @@ import { MonthRangePickerPanel } from './MonthRangePickerPanel';
31
31
  */
32
32
  export function MonthRangePicker({ format = 'YYYY/MM', minMonth, maxMonth, startInputProps = {}, endInputProps = {}, initialDisplayedMonths, ...restProps }) {
33
33
  // MonthRangePicker panels are grouped by year (left = viewingYear, right = viewingYear + 1).
34
- // When `previousAndCurrent` is requested, we must shift by a full year so the left panel
35
- // shows the previous year instead of the current year.
36
- const initialViewingDate = initialDisplayedMonths === 'previousAndCurrent' && !restProps.value && !restProps.defaultValue
37
- ? (() => {
34
+ // When `previousAndCurrent` is requested, we shift by a full year so the left panel
35
+ // shows the previous year. This applies regardless of whether `value` is set.
36
+ const initialViewingDate = (() => {
37
+ if (initialDisplayedMonths !== 'previousAndCurrent') {
38
+ return;
39
+ }
40
+ const startDate = restProps.value?.[0] ?? restProps.defaultValue?.[0];
41
+ if (!startDate) {
42
+ // No value: show previous year relative to today
38
43
  const today = new Date();
39
44
  return new Date(today.getFullYear() - 1, 0, 1);
40
- })()
41
- : undefined;
45
+ }
46
+ const endDate = restProps.value?.[1] ?? restProps.defaultValue?.[1];
47
+ if (endDate && startDate.getFullYear() !== endDate.getFullYear()) {
48
+ // Value spans different years: provider handles it via the multi-month path
49
+ return;
50
+ }
51
+ // Same-year value + previousAndCurrent: show previous year on the left
52
+ return new Date(startDate.getFullYear() - 1, 0, 1);
53
+ })();
42
54
  return (_jsx(BaseRangePicker, { ...restProps, format: format, initialDisplayedMonths: initialDisplayedMonths, initialViewingDate: initialViewingDate, startInputProps: {
43
55
  placeholder: '開始月',
44
56
  ...startInputProps,
@@ -272,12 +272,15 @@ export type BaseRangePickerProps = {
272
272
  calendarLocale?: BasePickerProps['calendarLocale'];
273
273
  /**
274
274
  * Controls which months are initially displayed in the two-panel calendar view.
275
- * - `'currentAndNext'`: Shows current month on the left and next month on the right (default behavior).
276
- * - `'previousAndCurrent'`: Shows previous month on the left and current month on the right.
275
+ * - `'currentAndNext'`: Shows the value's start month on the left and the next month on the right.
276
+ * When no value is set, shows the current month on the left and next month on the right.
277
+ * - `'previousAndCurrent'`: Shows the month before the value's start month on the left and
278
+ * the value's start month on the right.
279
+ * When no value is set, shows the previous month on the left and current month on the right.
277
280
  * Useful for log date range selection where showing future months is not meaningful.
278
281
  *
279
- * This prop only affects the initial view when no `value` or `defaultValue` is provided.
280
- * When a `value` or `defaultValue` is set, the calendar will show the months containing the selected dates.
282
+ * When `value`/`defaultValue` spans two different months, the calendar always shows both selected
283
+ * months regardless of this setting.
281
284
  *
282
285
  * @default 'currentAndNext'
283
286
  *
@@ -285,6 +288,12 @@ export type BaseRangePickerProps = {
285
288
  * ```tsx
286
289
  * // Show previous month + current month for log date selection
287
290
  * <DateRangePicker initialDisplayedMonths="previousAndCurrent" />
291
+ *
292
+ * // With a value set: shows February (left) and March (right)
293
+ * <DateRangePicker
294
+ * initialDisplayedMonths="previousAndCurrent"
295
+ * value={[new Date(2024, 2, 1), new Date(2024, 2, 15)]}
296
+ * />
288
297
  * ```
289
298
  */
290
299
  initialDisplayedMonths?: 'currentAndNext' | 'previousAndCurrent';
@@ -293,7 +302,7 @@ export type BaseRangePickerProps = {
293
302
  * Use this when the component operates at a different granularity than months
294
303
  * (e.g., MonthRangePicker uses years for panel navigation).
295
304
  *
296
- * This prop only affects the initial view when no `value` or `defaultValue` is provided.
305
+ * Takes the highest priority in the `viewingMonth` computation.
297
306
  *
298
307
  * @internal
299
308
  */
@@ -11,6 +11,40 @@ const noop = () => { };
11
11
  function normalizeToFirstOfMonth(date) {
12
12
  return dayjs(date).startOf('month').toDate();
13
13
  }
14
+ /**
15
+ * Computes the initial viewing month for the dual-panel calendar.
16
+ *
17
+ * Priority:
18
+ * 1. `initialViewingDate` — explicit internal override (used by MonthRangePicker for year-level navigation)
19
+ * 2. `value`/`defaultValue` spans **different** months → use start month (both selected months visible)
20
+ * 3. `value`/`defaultValue` within a **single** month:
21
+ * - `previousAndCurrent` → start month − 1 month (left panel = month before value, right = value month)
22
+ * - `currentAndNext` → start month (left panel = value month, right = next month)
23
+ * 4. No value → `initialDisplayedMonths` relative to today
24
+ */
25
+ function computeInitialViewingMonth({ value, defaultValue, initialViewingDate, initialDisplayedMonths, today, }) {
26
+ if (initialViewingDate) {
27
+ return initialViewingDate;
28
+ }
29
+ const rangeStart = value?.[0] ?? defaultValue?.[0];
30
+ const rangeEnd = value?.[1] ?? defaultValue?.[1];
31
+ if (rangeStart) {
32
+ if (rangeEnd && !dayjs(rangeStart).isSame(rangeEnd, 'month')) {
33
+ // Spans different months: show start month on the left
34
+ return rangeStart;
35
+ }
36
+ // Single-month value: apply initialDisplayedMonths
37
+ if (initialDisplayedMonths === 'previousAndCurrent') {
38
+ return dayjs(rangeStart).subtract(1, 'month').toDate();
39
+ }
40
+ return rangeStart;
41
+ }
42
+ // No value: apply initialDisplayedMonths relative to today
43
+ if (initialDisplayedMonths === 'previousAndCurrent') {
44
+ return new Date(today.getFullYear(), today.getMonth() - 1, 1);
45
+ }
46
+ return new Date(today.getFullYear(), today.getMonth(), 1);
47
+ }
14
48
  /**
15
49
  * Checks if a date is outside the specified constraints
16
50
  *
@@ -73,12 +107,13 @@ const useBaseRangePickerContextValue = ({ value, defaultValue, disabled = false,
73
107
  const [startDateString, endDateString] = dateStrings;
74
108
  // Add viewingMonth state
75
109
  const today = useMemo(() => new Date(), []);
76
- const [viewingMonth, setViewingMonth] = useTransformedState(value?.[0] ??
77
- defaultValue?.[0] ??
78
- initialViewingDate ??
79
- (initialDisplayedMonths === 'previousAndCurrent'
80
- ? new Date(today.getFullYear(), today.getMonth() - 1, 1)
81
- : new Date(today.getFullYear(), today.getMonth(), 1)), normalizeToFirstOfMonth);
110
+ const [viewingMonth, setViewingMonth] = useTransformedState(computeInitialViewingMonth({
111
+ value,
112
+ defaultValue,
113
+ initialViewingDate,
114
+ initialDisplayedMonths,
115
+ today,
116
+ }), normalizeToFirstOfMonth);
82
117
  // --- Selection/Preview State and Logic ---
83
118
  const [selecting, setSelecting] = useState('start');
84
119
  const [temporaryStart, setTemporaryStart] = useState(startDate);
@@ -328,7 +328,7 @@ export const SelectBox = forwardRef((props, ref) => {
328
328
  return (_jsx(Popover, { open: isOptionPanelOpen, targetDOMNode: targetDOMNode, minWidth: popoverContentProps?.minWidth, maxHeight: popoverWrapperProps?.maxHeight, allowedPlacements: popoverContentProps?.allowedPlacements, enableConstrainedContentWidth: enableConstrainedPopoverWidth, renderContent: () => (_jsx("div", { ref: optionPanelRef, id: listBoxId, className: cx(classes.optionPanel, 'mfui-SelectBox__optionPanel', popoverContentProps?.className), tabIndex: -1, onKeyDown: handleKeyDownMenu, children: renderPopoverContent ? (renderPopoverContent({ searchNode, optionsNode })) : (_jsxs(_Fragment, { children: [searchNode, optionsNode] })) })), renderTrigger: ({ setTriggerRef, togglePopover, isPopoverOpen, handleTriggerKeyDown, handleTriggerBlur }) => (_jsxs("div", { ref: setTriggerRef, ...triggerWrapperProps, className: cx(classes.triggerWrapper, 'mfui-SelectBox__triggerWrapper', triggerWrapperProps?.className), children: [_jsx(FocusIndicator, { children: _jsxs("button", { ref: triggerRef, id: id, type: "button", role: "combobox", disabled: disabled, "aria-label": triggerProps?.['aria-label'], "aria-controls": listBoxId, "aria-expanded": isPopoverOpen, "aria-haspopup": "listbox", "aria-invalid": invalid, className: cx(classes.trigger, 'mfui-SelectBox__trigger', triggerProps?.className), "data-placeholder": !!placeholder && !localSelectedOption, "data-selected": !!localSelectedOption, "data-mfui-has-clear-button": showClearButton, onClick: togglePopover, onKeyDown: (event) => {
329
329
  handleTypeAhead(event.nativeEvent);
330
330
  handleTriggerKeyDown(event);
331
- }, onBlur: handleTriggerBlur, children: [_jsx("span", { "data-mfui-content": "select-box-trigger-display-value", children: renderTriggerLabel() }), _jsx(DropdownIcon, {}), _jsx("input", { ref: ref, type: "hidden", value: localSelectedOption?.value ?? '', name: name, disabled: disabled })] }) }), showClearButton ? (_jsx("div", { className: cx(classes.clearButtonWrapper, 'mfui-SelectBox__clearButtonWrapper'), children: _jsx(ClearButton, { size: size === 'small' ? 'small' : size === 'large' ? 'large' : 'default', "aria-label": clearButtonProps?.['aria-label'] ?? '値をクリアする', "data-mfui-content": "select-box-clear-button", onClick: (event) => {
331
+ }, onBlur: handleTriggerBlur, children: [_jsx("span", { "data-mfui-content": "select-box-trigger-display-value", children: renderTriggerLabel() }), _jsx(DropdownIcon, { "aria-hidden": "true", focusable: false }), _jsx("input", { ref: ref, type: "hidden", value: localSelectedOption?.value ?? '', name: name, disabled: disabled })] }) }), showClearButton ? (_jsx("div", { className: cx(classes.clearButtonWrapper, 'mfui-SelectBox__clearButtonWrapper'), children: _jsx(ClearButton, { size: size === 'small' ? 'small' : size === 'large' ? 'large' : 'default', "aria-label": clearButtonProps?.['aria-label'] ?? '値をクリアする', "data-mfui-content": "select-box-clear-button", onClick: (event) => {
332
332
  event.stopPropagation();
333
333
  handleClearValue();
334
334
  } }) })) : null] })), contentProps: { className: classes.popover }, enableAutoUnmount: enableAutoUnmount, onOpenStateChanged: toggleOptionPanel, onBlur: onBlur }));
package/dist/styles.css CHANGED
@@ -1326,6 +1326,8 @@
1326
1326
  background-color: var(--mfui-colors-mfui\.color\.neutral\.background\.none);
1327
1327
  color: var(--mfui-colors-mfui\.color\.base\.inverted-content\.none);
1328
1328
  box-shadow: var(--mfui-shadows-mfui\.elevation\.plus-1\.shadow-1);
1329
+ word-break: break-word;
1330
+ overflow-wrap: break-word;
1329
1331
  min-height: 24px;
1330
1332
  }
1331
1333
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moneyforward/mfui-components",
3
- "version": "3.13.0",
3
+ "version": "3.13.1",
4
4
  "description": "React UI Component Library for all Money Forward products",
5
5
  "repository": {
6
6
  "type": "git",
@@ -61,8 +61,8 @@
61
61
  "@floating-ui/react-dom": "^2.1.2",
62
62
  "@tanstack/react-virtual": "^3.13.18",
63
63
  "dayjs": "^1.11.13",
64
- "@moneyforward/mfui-icons-react": "^3.1.0",
65
- "@moneyforward/mfui-design-tokens": "^3.1.0"
64
+ "@moneyforward/mfui-design-tokens": "^3.1.0",
65
+ "@moneyforward/mfui-icons-react": "^3.1.0"
66
66
  },
67
67
  "scripts": {
68
68
  "prepare:panda": "panda codegen",