@moneyforward/mfui-components 3.19.0 → 3.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/dist/src/CheckboxCard/CheckboxCard.js +1 -7
  2. package/dist/src/DateTimeSelection/DatePicker/DatePicker.js +2 -11
  3. package/dist/src/DateTimeSelection/DateRangePicker/DateRangePicker.d.ts +1 -1
  4. package/dist/src/DateTimeSelection/DateRangePicker/DateRangePicker.js +10 -2
  5. package/dist/src/DateTimeSelection/DateRangePicker/DateRangePicker.types.d.ts +14 -0
  6. package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerPopover/DateRangePickerPopover.js +13 -5
  7. package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerPopover/utilities/createDateRangePickerPopoverTestUtility.js +2 -2
  8. package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerProvider/DateRangePickerProvider.js +11 -12
  9. package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerTrigger/hooks/useDateRangeTriggerValueController.js +4 -3
  10. package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerTrigger/utilities/createDateRangePickerTriggerTestUtility.js +3 -1
  11. package/dist/src/DateTimeSelection/FilterDateRangePicker/DateRangePickerContent/DateRangePickerContent.d.ts +6 -0
  12. package/dist/src/DateTimeSelection/FilterDateRangePicker/DateRangePickerContent/DateRangePickerContent.js +33 -0
  13. package/dist/src/DateTimeSelection/FilterDateRangePicker/DateRangePickerContent/DateRangePickerContent.types.d.ts +17 -0
  14. package/dist/src/DateTimeSelection/FilterDateRangePicker/FilterDateRangePicker.d.ts +14 -0
  15. package/dist/src/DateTimeSelection/FilterDateRangePicker/FilterDateRangePicker.js +42 -0
  16. package/dist/src/DateTimeSelection/FilterDateRangePicker/FilterDateRangePicker.types.d.ts +78 -0
  17. package/dist/src/DateTimeSelection/FilterDateRangePicker/FilterDateRangePicker.types.js +1 -0
  18. package/dist/src/DateTimeSelection/FilterDateRangePicker/index.d.ts +2 -0
  19. package/dist/src/DateTimeSelection/FilterDateRangePicker/index.js +1 -0
  20. package/dist/src/DateTimeSelection/FilterMonthPicker/FilterMonthPicker.d.ts +14 -0
  21. package/dist/src/DateTimeSelection/FilterMonthPicker/FilterMonthPicker.js +75 -0
  22. package/dist/src/DateTimeSelection/FilterMonthPicker/FilterMonthPicker.types.d.ts +83 -0
  23. package/dist/src/DateTimeSelection/FilterMonthPicker/FilterMonthPicker.types.js +1 -0
  24. package/dist/src/DateTimeSelection/FilterMonthPicker/MonthPickerPopover/MonthPickerPopover.d.ts +6 -0
  25. package/dist/src/DateTimeSelection/FilterMonthPicker/MonthPickerPopover/MonthPickerPopover.js +45 -0
  26. package/dist/src/DateTimeSelection/FilterMonthPicker/MonthPickerPopover/MonthPickerPopover.types.d.ts +24 -0
  27. package/dist/src/DateTimeSelection/FilterMonthPicker/MonthPickerPopover/MonthPickerPopover.types.js +1 -0
  28. package/dist/src/DateTimeSelection/FilterMonthPicker/index.d.ts +2 -0
  29. package/dist/src/DateTimeSelection/FilterMonthPicker/index.js +1 -0
  30. package/dist/src/DateTimeSelection/FilterMonthRangePicker/FilterMonthRangePicker.d.ts +15 -0
  31. package/dist/src/DateTimeSelection/FilterMonthRangePicker/FilterMonthRangePicker.js +89 -0
  32. package/dist/src/DateTimeSelection/FilterMonthRangePicker/FilterMonthRangePicker.types.d.ts +75 -0
  33. package/dist/src/DateTimeSelection/FilterMonthRangePicker/FilterMonthRangePicker.types.js +1 -0
  34. package/dist/src/DateTimeSelection/FilterMonthRangePicker/MonthRangePickerPopover/MonthRangePickerPopover.d.ts +5 -0
  35. package/dist/src/DateTimeSelection/FilterMonthRangePicker/MonthRangePickerPopover/MonthRangePickerPopover.js +54 -0
  36. package/dist/src/DateTimeSelection/FilterMonthRangePicker/MonthRangePickerPopover/MonthRangePickerPopover.types.d.ts +19 -0
  37. package/dist/src/DateTimeSelection/FilterMonthRangePicker/MonthRangePickerPopover/MonthRangePickerPopover.types.js +1 -0
  38. package/dist/src/DateTimeSelection/FilterMonthRangePicker/index.d.ts +2 -0
  39. package/dist/src/DateTimeSelection/FilterMonthRangePicker/index.js +1 -0
  40. package/dist/src/DateTimeSelection/MonthPicker/MonthPicker.d.ts +1 -1
  41. package/dist/src/DateTimeSelection/MonthPicker/MonthPicker.js +10 -2
  42. package/dist/src/DateTimeSelection/MonthPicker/MonthPicker.types.d.ts +14 -0
  43. package/dist/src/DateTimeSelection/MonthPicker/MonthPickerPanel/MonthCell/MonthCell.js +2 -25
  44. package/dist/src/DateTimeSelection/MonthPicker/MonthPickerPanel/MonthPickerPanel.js +1 -1
  45. package/dist/src/DateTimeSelection/MonthRangePicker/MonthRangePicker.d.ts +1 -1
  46. package/dist/src/DateTimeSelection/MonthRangePicker/MonthRangePicker.js +14 -5
  47. package/dist/src/DateTimeSelection/MonthRangePicker/MonthRangePicker.types.d.ts +21 -0
  48. package/dist/src/DateTimeSelection/MonthRangePicker/MonthRangePickerMonthCell/MonthRangePickerMonthCell.d.ts +1 -0
  49. package/dist/src/DateTimeSelection/MonthRangePicker/MonthRangePickerMonthCell/MonthRangePickerMonthCell.js +10 -3
  50. package/dist/src/DateTimeSelection/MonthRangePicker/MonthRangePickerNavigation/MonthRangePickerNavigation.js +16 -3
  51. package/dist/src/DateTimeSelection/MonthRangePicker/MonthRangePickerPanel/MonthRangePickerPanel.js +3 -1
  52. package/dist/src/DateTimeSelection/TimePicker/TimePicker.d.ts +43 -0
  53. package/dist/src/DateTimeSelection/TimePicker/TimePicker.js +85 -0
  54. package/dist/src/DateTimeSelection/TimePicker/TimePicker.types.d.ts +61 -0
  55. package/dist/src/DateTimeSelection/TimePicker/TimePicker.types.js +1 -0
  56. package/dist/src/DateTimeSelection/TimePicker/constants.d.ts +4 -0
  57. package/dist/src/DateTimeSelection/TimePicker/constants.js +12 -0
  58. package/dist/src/DateTimeSelection/TimePicker/index.d.ts +2 -0
  59. package/dist/src/DateTimeSelection/TimePicker/index.js +1 -0
  60. package/dist/src/DateTimeSelection/index.d.ts +4 -0
  61. package/dist/src/DateTimeSelection/index.js +4 -0
  62. package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePicker.d.ts +1 -1
  63. package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePicker.js +26 -10
  64. package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePicker.types.d.ts +19 -0
  65. package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerProvider/BaseRangePickerProvider.js +40 -19
  66. package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerProvider/BaseRangePickerProvider.types.d.ts +19 -0
  67. package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerTrigger/BaseRangePickerTrigger.js +4 -6
  68. package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerTrigger/hooks/useDateRangeTriggerValueController.js +4 -3
  69. package/dist/src/DateTimeSelection/shared/CalendarLocale/CalendarLocaleContext.d.ts +1 -1
  70. package/dist/src/DateTimeSelection/shared/CalendarLocale/CalendarLocaleContext.js +1 -1
  71. package/dist/src/DateTimeSelection/shared/DayCell/DayCell.js +2 -3
  72. package/dist/src/DateTimeSelection/shared/MonthGrid/MonthGrid.js +3 -3
  73. package/dist/src/DateTimeSelection/shared/YearSelector/YearSelector.js +1 -1
  74. package/dist/src/DateTimeSelection/shared/utilities/dateParsing.js +27 -9
  75. package/dist/src/DateTimeSelection/shared/utilities/japaneseCalendar.d.ts +36 -8
  76. package/dist/src/DateTimeSelection/shared/utilities/japaneseCalendar.js +82 -15
  77. package/dist/src/DateTimeSelection/shared/utilities/monthCellMonthFormat.d.ts +14 -0
  78. package/dist/src/DateTimeSelection/shared/utilities/monthCellMonthFormat.js +35 -0
  79. package/dist/src/MultilineTextBox/index.d.ts +10 -2
  80. package/dist/src/MultilineTextBox/index.js +9 -1
  81. package/dist/src/MultipleSelectBox/MultipleSelectBoxTrigger/MultipleSelectBoxTrigger.js +1 -3
  82. package/dist/src/RadioButtonCard/RadioButtonCard.js +1 -7
  83. package/dist/src/TextBox/TextBox.js +2 -6
  84. package/dist/src/{MultilineTextBox/MultilineTextBox.d.ts → Textarea/Textarea.d.ts} +5 -2
  85. package/dist/src/{MultilineTextBox/MultilineTextBox.js → Textarea/Textarea.js} +9 -5
  86. package/dist/src/{MultilineTextBox/MultilineTextBox.types.d.ts → Textarea/Textarea.types.d.ts} +2 -2
  87. package/dist/src/Textarea/Textarea.types.js +1 -0
  88. package/dist/src/Textarea/index.d.ts +2 -0
  89. package/dist/src/Textarea/index.js +1 -0
  90. package/dist/src/Tooltip/Tooltip.js +12 -3
  91. package/dist/src/Typography/Typography.js +1 -3
  92. package/dist/src/index.d.ts +1 -0
  93. package/dist/src/index.js +1 -0
  94. package/dist/styled-system/recipes/filter-date-range-picker-slot-recipe.d.ts +33 -0
  95. package/dist/styled-system/recipes/filter-date-range-picker-slot-recipe.js +48 -0
  96. package/dist/styled-system/recipes/filter-month-picker-slot-recipe.d.ts +33 -0
  97. package/dist/styled-system/recipes/filter-month-picker-slot-recipe.js +44 -0
  98. package/dist/styled-system/recipes/filter-month-range-picker-slot-recipe.d.ts +33 -0
  99. package/dist/styled-system/recipes/filter-month-range-picker-slot-recipe.js +44 -0
  100. package/dist/styled-system/recipes/index.d.ts +5 -1
  101. package/dist/styled-system/recipes/index.js +5 -1
  102. package/dist/styled-system/recipes/textarea-slot-recipe.d.ts +52 -0
  103. package/dist/styled-system/recipes/textarea-slot-recipe.js +64 -0
  104. package/dist/styled-system/recipes/time-picker-slot-recipe.d.ts +44 -0
  105. package/dist/styled-system/recipes/time-picker-slot-recipe.js +62 -0
  106. package/dist/styles.css +601 -25
  107. package/dist/tsconfig.build.tsbuildinfo +1 -1
  108. package/package.json +13 -11
  109. package/dist/src/DateTimeSelection/shared/BasePicker/YearSelector/YearSelector.d.ts +0 -18
  110. package/dist/src/DateTimeSelection/shared/BasePicker/YearSelector/YearSelector.js +0 -36
  111. package/dist/styled-system/recipes/multiline-text-box-slot-recipe.d.ts +0 -52
  112. package/dist/styled-system/recipes/multiline-text-box-slot-recipe.js +0 -64
  113. /package/dist/src/{MultilineTextBox/MultilineTextBox.types.js → DateTimeSelection/FilterDateRangePicker/DateRangePickerContent/DateRangePickerContent.types.js} +0 -0
@@ -1,5 +1,6 @@
1
1
  import { useMemo } from 'react';
2
2
  import { dayjs } from '../../../../../utilities/date/dayjs';
3
+ import { parseInputDate } from '../../../utilities/dateParsing';
3
4
  import { useBaseRangePickerContext } from '../../BaseRangePickerProvider';
4
5
  const createInputProps = (baseProps, value, format, onStringChange, onDateChange, otherDate, isDateDisabled) => ({
5
6
  ...baseProps,
@@ -15,12 +16,12 @@ const createInputProps = (baseProps, value, format, onStringChange, onDateChange
15
16
  if (event.defaultPrevented)
16
17
  return;
17
18
  baseProps.onBlur?.(event);
18
- const dateValue = dayjs(value, format, true);
19
- if (!dateValue.isValid()) {
19
+ const parseResult = parseInputDate(value, format);
20
+ if (!parseResult.isValid || !parseResult.result) {
20
21
  onDateChange(undefined, otherDate);
21
22
  return;
22
23
  }
23
- const currentDate = dateValue.startOf('day').toDate();
24
+ const currentDate = dayjs(parseResult.result).startOf('day').toDate();
24
25
  // Check if the date is disabled due to constraints
25
26
  if (isDateDisabled?.(currentDate)) {
26
27
  // Clear the input if the date violates constraints
@@ -5,4 +5,4 @@ export declare function CalendarLocaleProvider({ value, children, }: {
5
5
  value: CalendarLocaleContextValue;
6
6
  children: React.ReactNode;
7
7
  }): import("react/jsx-runtime").JSX.Element;
8
- export declare function useCalendarLocale(): CalendarLocaleContextValue;
8
+ export declare function useCalendarLocale(): NonNullable<CalendarLocaleContextValue>;
@@ -6,5 +6,5 @@ export function CalendarLocaleProvider({ value, children, }) {
6
6
  return _jsx(CalendarLocaleContext.Provider, { value: value, children: children });
7
7
  }
8
8
  export function useCalendarLocale() {
9
- return useContext(CalendarLocaleContext);
9
+ return useContext(CalendarLocaleContext) ?? 'ja';
10
10
  }
@@ -10,8 +10,7 @@ import { useCalendarLocale } from '../CalendarLocale/CalendarLocaleContext';
10
10
  export function DayCell({ day }) {
11
11
  const calendarLocale = useCalendarLocale();
12
12
  const classNames = dayCellSlotRecipe();
13
- const safeLocale = calendarLocale ?? 'ja';
14
- const abbreviation = DAY_ABBREVIATIONS[safeLocale][day];
15
- const fullName = DAY_FULL_NAMES[safeLocale][day];
13
+ const abbreviation = DAY_ABBREVIATIONS[calendarLocale][day];
14
+ const fullName = DAY_FULL_NAMES[calendarLocale][day];
16
15
  return (_jsx("div", { className: cx(classNames.root, 'mfui-DayCell__root'), "aria-label": fullName, children: _jsx(Typography, { "aria-hidden": true, variant: "contentHeading", className: cx(classNames.label, 'mfui-DayCell__label'), children: abbreviation }) }));
17
16
  }
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import React, { useEffect } from 'react';
2
+ import React, { useLayoutEffect } from 'react';
3
3
  import { monthGridSlotRecipe } from '../../../../styled-system/recipes';
4
4
  import { cx } from '../../../../styled-system/css';
5
5
  /**
@@ -28,8 +28,8 @@ export function MonthGrid({ year, selectedMonth, minMonth, maxMonth, checkDisabl
28
28
  const firstTabbableIndex = monthStates.find(({ disabled }) => !disabled)?.month ?? -1;
29
29
  return { monthStates, firstTabbableIndex };
30
30
  }, [months, year, minMonth, maxMonth, checkDisabledMonth]);
31
- // Handle pending focus
32
- useEffect(() => {
31
+ // Handle pending focus before paint so the focused month cell matches keyboard / popover-open flows.
32
+ useLayoutEffect(() => {
33
33
  if (!pendingFocusMonth)
34
34
  return;
35
35
  const targetCell = document.querySelector(`[data-mfui-month="${pendingFocusMonth}"]`);
@@ -16,7 +16,7 @@ export function YearSelector({ value, onChange, filterYear, triggerProps, trigge
16
16
  const year = MINIMUM_VIEWABLE_YEAR + i;
17
17
  let label;
18
18
  if (displayJapaneseCalendar) {
19
- label = yearToEraLabel(year, calendarLocale ?? 'ja');
19
+ label = yearToEraLabel(year, calendarLocale);
20
20
  }
21
21
  else if (calendarLocale === 'ja') {
22
22
  label = `${String(year)}年`;
@@ -20,16 +20,23 @@ export function parseInputDate(inputString, format) {
20
20
  // Use the refined Japanese era detection from japaneseCalendar utility
21
21
  const hasJapaneseEra = isJapaneseEraFormat(inputString);
22
22
  if (hasJapaneseEra) {
23
- // Try Japanese calendar parsing for era formats
24
- try {
25
- const jpResult = warekiToDate(inputString);
26
- if (jpResult.isValid) {
27
- return { isValid: true, result: jpResult.result };
23
+ // Skip month-only wareki parsing when the format requires a day component.
24
+ // e.g. "令和7年1月" should not parse for YYYY/MM/DD — the user hasn't typed the day yet.
25
+ const isMonthOnlyEra = inputString.trimEnd().endsWith('月');
26
+ const formatRequiresDay = format.includes('D');
27
+ const shouldTryWareki = !(isMonthOnlyEra && formatRequiresDay);
28
+ if (shouldTryWareki) {
29
+ // Try Japanese calendar parsing for era formats
30
+ try {
31
+ const jpResult = warekiToDate(inputString);
32
+ if (jpResult.isValid) {
33
+ return { isValid: true, result: jpResult.result };
34
+ }
35
+ }
36
+ catch (error) {
37
+ // If Japanese calendar parsing fails, fall back to dayjs
38
+ console.warn('Japanese calendar parsing failed:', error);
28
39
  }
29
- }
30
- catch (error) {
31
- // If Japanese calendar parsing fails, fall back to dayjs
32
- console.warn('Japanese calendar parsing failed:', error);
33
40
  }
34
41
  }
35
42
  // Try dayjs parsing for Western calendar format first
@@ -37,6 +44,17 @@ export function parseInputDate(inputString, format) {
37
44
  if (dayjsResult.isValid()) {
38
45
  return { isValid: true, result: dayjsResult.toDate() };
39
46
  }
47
+ // Fall back to single-digit month/day tokens when the format uses two-digit tokens (MM/DD).
48
+ // For example, "2026/6/6" fails with "YYYY/MM/DD" but succeeds with "YYYY/M/D".
49
+ // Strict mode is intentional here: it ensures YYYY matches exactly 4 digits, preventing
50
+ // format-mismatch inputs like "31/12/2023" from accidentally passing via native Date fallback.
51
+ const yyyymdFormat = format.replaceAll(/\bMM\b/g, 'M').replaceAll(/\bDD\b/g, 'D');
52
+ if (yyyymdFormat !== format) {
53
+ const yyyymdResult = dayjs(inputString, yyyymdFormat, true);
54
+ if (yyyymdResult.isValid()) {
55
+ return { isValid: true, result: yyyymdResult.toDate() };
56
+ }
57
+ }
40
58
  // Fall back to YYYYMMDD format (8-digit number without delimiters) if the specified format fails
41
59
  // This allows inputs like "20251215" to be parsed even when format is "YYYY-MM-DD"
42
60
  if (/^\d{8}$/.test(inputString)) {
@@ -1,8 +1,8 @@
1
- declare const REIWA: "\u4EE4\u548C";
2
- declare const HEISEI: "\u5E73\u6210";
3
- declare const SHOWA: "\u662D\u548C";
4
- declare const TAISHO: "\u5927\u6B63";
5
- declare const MEIJI: "\u660E\u6CBB";
1
+ declare const REIWA = "\u4EE4\u548C";
2
+ declare const HEISEI = "\u5E73\u6210";
3
+ declare const SHOWA = "\u662D\u548C";
4
+ declare const TAISHO = "\u5927\u6B63";
5
+ declare const MEIJI = "\u660E\u6CBB";
6
6
  type Geongo = typeof REIWA | typeof HEISEI | typeof SHOWA | typeof TAISHO | typeof MEIJI;
7
7
  declare const WAREKI_START_YEARS: {
8
8
  readonly r: 2019;
@@ -64,13 +64,41 @@ export declare function isJapaneseEraFormat(inputString: string): boolean;
64
64
  export declare function yearToEraLabel(year: number, locale: 'ja' | 'en'): string;
65
65
  /**
66
66
  * Formats a Date to a short English era string for display in the DatePicker trigger input.
67
- * Format: "{EraName} {eraYear}/{month}/{day}" (e.g., "Reiwa 7/12/25").
68
- * For pre-Meiji dates (year < 1868): falls back to the Gregorian year (e.g., "1867/12/25").
67
+ * Format: "{EraName} {eraYear}/{MM}/{DD}" (e.g., "Reiwa 7/03/06").
68
+ * For pre-Meiji dates (year < 1868): falls back to the Gregorian year (e.g., "1867/03/06").
69
69
  *
70
70
  * @param date - The date to format
71
71
  *
72
- * @returns Short English era string (e.g., "Reiwa 7/12/25")
72
+ * @returns Short English era string (e.g., "Reiwa 7/03/06")
73
73
  */
74
74
  export declare function dateToEnglishEraShort(date: Date): string;
75
+ /**
76
+ * Formats a Date to a short English era string for display in the MonthPicker trigger input.
77
+ * Format: "{EraName} {eraYear}/{MM}" (e.g., "Reiwa 7/03").
78
+ * For pre-Meiji dates (year < 1868): falls back to the Gregorian year (e.g., "1867/03").
79
+ *
80
+ * @param date - The date to format
81
+ *
82
+ * @returns Short English era month string (e.g., "Reiwa 7/03")
83
+ */
84
+ export declare function dateToEnglishEraMonthShort(date: Date): string;
85
+ /**
86
+ * Formats a Date to a Japanese-era string with day precision (e.g., "令和7年3月6日").
87
+ * Uses the platform's built-in `ja-JP-u-ca-japanese` calendar.
88
+ *
89
+ * @param date - The date to format
90
+ *
91
+ * @returns Japanese era string with day (e.g., "令和7年3月6日")
92
+ */
93
+ export declare function dateToJapaneseEra(date: Date): string;
94
+ /**
95
+ * Formats a Date to a Japanese-era string with month precision (e.g., "令和7年3月").
96
+ * Uses the platform's built-in `ja-JP-u-ca-japanese` calendar.
97
+ *
98
+ * @param date - The date to format
99
+ *
100
+ * @returns Japanese era month string (e.g., "令和7年3月")
101
+ */
102
+ export declare function dateToJapaneseEraMonth(date: Date): string;
75
103
  export { warekiReg, dateToWareki, fullWidthToHalfWidth, selectGengo, WAREKI_START_YEARS };
76
104
  export type { WarekiResult };
@@ -38,8 +38,8 @@ const WAREKI_START_YEARS = {
38
38
  const warekiReg = {
39
39
  // Western calendar: supports full-width numbers and flexible separators
40
40
  dateString: new RegExp(String.raw `^([0-90-9]{4})${WESTERN_SEPARATOR}([0-90-9]{1,2})${WESTERN_SEPARATOR}([0-90-9]{1,2})(?:[\s.]([0-90-9]{2}):([0-90-9]{2}))?$`),
41
- // Japanese era: supports both traditional (H12年2月12日) and Western-style (H12.2.12) formats
42
- wareki: new RegExp(String.raw `^(${Object.keys(WAREKI_START_YEARS).join('|')})(元|[0-90-9]{1,2})(?:年([0-90-9]{1,2})月([0-90-9]{1,2})日|[./-]([0-90-9]{1,2})[./-]([0-90-9]{1,2}))$`),
41
+ // Japanese era: supports traditional (H12年2月12日), Western-style (H12.2.12), and month-only (H12年2月) formats
42
+ wareki: new RegExp(String.raw `^(${Object.keys(WAREKI_START_YEARS).join('|')})(元|[0-90-9]{1,2})(?:年([0-90-9]{1,2})月([0-90-9]{1,2})日|[./-]([0-90-9]{1,2})[./-]([0-90-9]{1,2})|年([0-90-9]{1,2})月)$`),
43
43
  // Era detection for both traditional and Western-style formats
44
44
  eraDetection: /^(?:令和|平成|昭和|大正|明治|[rhstmRHSTM])(?:元|[0-90-9]{1,2})(?:年|[./-])/,
45
45
  };
@@ -137,11 +137,12 @@ export function warekiToDate(wareki) {
137
137
  const baseYear = WAREKI_START_YEARS[matchedWareki[1]];
138
138
  // Handle "元" (first year) and regular years
139
139
  const eraYear = matchedWareki[2] === '元' ? 1 : Number(matchedWareki[2]);
140
- // Handle both traditional (年月日) and Western-style (./- separators) formats
140
+ // Handle traditional (年月日), Western-style (./- separators), and month-only (年月) formats
141
141
  // Traditional format: groups 3,4 (month, day)
142
142
  // Western format: groups 5,6 (month, day)
143
- const month = Number(matchedWareki[3] || matchedWareki[5]);
144
- const day = Number(matchedWareki[4] || matchedWareki[6]);
143
+ // Month-only format: group 7 (month), day defaults to 1
144
+ const month = Number(matchedWareki[3] || matchedWareki[5] || matchedWareki[7]);
145
+ const day = matchedWareki[7] !== undefined ? 1 : Number(matchedWareki[4] || matchedWareki[6]);
145
146
  // Validation: ensure era year is reasonable (1-200 years per era)
146
147
  if (eraYear < 1 || eraYear > 200) {
147
148
  return {
@@ -240,24 +241,90 @@ export function yearToEraLabel(year, locale) {
240
241
  return `${gengo}${eraYear === 1 ? '元' : String(eraYear)}年`;
241
242
  }
242
243
  /**
243
- * Formats a Date to a short English era string for display in the DatePicker trigger input.
244
- * Format: "{EraName} {eraYear}/{month}/{day}" (e.g., "Reiwa 7/12/25").
245
- * For pre-Meiji dates (year < 1868): falls back to the Gregorian year (e.g., "1867/12/25").
244
+ * Internal helper used by `dateToEnglishEraShort` and `dateToEnglishEraMonthShort`.
245
+ * Pre-Meiji dates (year < 1868) fall back to the Gregorian year.
246
246
  *
247
247
  * @param date - The date to format
248
248
  *
249
- * @returns Short English era string (e.g., "Reiwa 7/12/25")
249
+ * @param options - Format options. `includeDay: true` produces "{Era} {Y}/{MM}/{DD}";
250
+ * `includeDay: false` produces "{Era} {Y}/{MM}" and resolves the era using day 1.
251
+ *
252
+ * @returns Formatted English era string
250
253
  */
251
- export function dateToEnglishEraShort(date) {
254
+ function dateToEnglishEra(date, { includeDay }) {
252
255
  const year = date.getFullYear();
253
- const month = date.getMonth() + 1;
254
- const day = date.getDate();
256
+ const monthNum = date.getMonth() + 1;
257
+ const dayNum = date.getDate();
258
+ const month = String(monthNum).padStart(2, '0');
259
+ const daySuffix = includeDay ? `/${String(dayNum).padStart(2, '0')}` : '';
255
260
  if (year < MEIJI_START_YEAR) {
256
- return `${String(year)}/${String(month)}/${String(day)}`;
261
+ return `${String(year)}/${month}${daySuffix}`;
257
262
  }
258
- const gengo = selectGengo(year, month, day);
263
+ // Month-only outputs resolve the era using day 1, which means the transition month
264
+ // keeps the older era label (e.g., Dec 1926 → Taisho 15/12, not Showa 1/12).
265
+ const gengo = selectGengo(year, monthNum, includeDay ? dayNum : 1);
259
266
  const eraYear = year - WAREKI_START_YEARS[gengo] + 1;
260
- return `${ERA_NAMES_EN[gengo]} ${String(eraYear)}/${String(month)}/${String(day)}`;
267
+ return `${ERA_NAMES_EN[gengo]} ${String(eraYear)}/${month}${daySuffix}`;
268
+ }
269
+ /**
270
+ * Formats a Date to a short English era string for display in the DatePicker trigger input.
271
+ * Format: "{EraName} {eraYear}/{MM}/{DD}" (e.g., "Reiwa 7/03/06").
272
+ * For pre-Meiji dates (year < 1868): falls back to the Gregorian year (e.g., "1867/03/06").
273
+ *
274
+ * @param date - The date to format
275
+ *
276
+ * @returns Short English era string (e.g., "Reiwa 7/03/06")
277
+ */
278
+ export function dateToEnglishEraShort(date) {
279
+ return dateToEnglishEra(date, { includeDay: true });
280
+ }
281
+ /**
282
+ * Formats a Date to a short English era string for display in the MonthPicker trigger input.
283
+ * Format: "{EraName} {eraYear}/{MM}" (e.g., "Reiwa 7/03").
284
+ * For pre-Meiji dates (year < 1868): falls back to the Gregorian year (e.g., "1867/03").
285
+ *
286
+ * @param date - The date to format
287
+ *
288
+ * @returns Short English era month string (e.g., "Reiwa 7/03")
289
+ */
290
+ export function dateToEnglishEraMonthShort(date) {
291
+ return dateToEnglishEra(date, { includeDay: false });
292
+ }
293
+ // Cached Intl formatters for the Japanese era (wareki) — module-level so the
294
+ // formatter instances are reused across components instead of being created
295
+ // inside each `useMemo`.
296
+ const japaneseEraDateFormatter = new Intl.DateTimeFormat('ja-JP-u-ca-japanese', {
297
+ era: 'long',
298
+ year: 'numeric',
299
+ month: 'narrow',
300
+ day: 'numeric',
301
+ });
302
+ const japaneseEraMonthFormatter = new Intl.DateTimeFormat('ja-JP-u-ca-japanese', {
303
+ era: 'long',
304
+ year: 'numeric',
305
+ month: 'narrow',
306
+ });
307
+ /**
308
+ * Formats a Date to a Japanese-era string with day precision (e.g., "令和7年3月6日").
309
+ * Uses the platform's built-in `ja-JP-u-ca-japanese` calendar.
310
+ *
311
+ * @param date - The date to format
312
+ *
313
+ * @returns Japanese era string with day (e.g., "令和7年3月6日")
314
+ */
315
+ export function dateToJapaneseEra(date) {
316
+ return japaneseEraDateFormatter.format(date);
317
+ }
318
+ /**
319
+ * Formats a Date to a Japanese-era string with month precision (e.g., "令和7年3月").
320
+ * Uses the platform's built-in `ja-JP-u-ca-japanese` calendar.
321
+ *
322
+ * @param date - The date to format
323
+ *
324
+ * @returns Japanese era month string (e.g., "令和7年3月")
325
+ */
326
+ export function dateToJapaneseEraMonth(date) {
327
+ return japaneseEraMonthFormatter.format(date);
261
328
  }
262
329
  // Export the utility functions and constants
263
330
  export { warekiReg, dateToWareki, fullWidthToHalfWidth, selectGengo, WAREKI_START_YEARS };
@@ -0,0 +1,14 @@
1
+ import { type BasePickerProps } from '../BasePicker/BasePicker.types';
2
+ /**
3
+ * dayjs format string for the visible month label in {@link MonthCell} (`monthLabel`),
4
+ * based on calendar locale (Japanese `M月` vs English three-letter abbreviations).
5
+ *
6
+ * @param calendarLocale - The calendar locale (`'ja'` or `'en'`) — selects between
7
+ * Japanese (`M月`) and English (`[Jan]`–`[Dec]`) abbreviations
8
+ *
9
+ * @param date - The date whose month index selects the English abbreviation.
10
+ * Only consulted when `calendarLocale === 'en'`.
11
+ *
12
+ * @returns A dayjs-compatible format string for the month label
13
+ */
14
+ export declare function getMonthCellMonthFormat(calendarLocale: BasePickerProps['calendarLocale'], date: Date): string;
@@ -0,0 +1,35 @@
1
+ // English month abbreviations wrapped in square brackets to escape them in dayjs format strings
2
+ const ENGLISH_MONTH_ABBREVIATIONS = [
3
+ '[Jan]',
4
+ '[Feb]',
5
+ '[Mar]',
6
+ '[Apr]',
7
+ '[May]',
8
+ '[Jun]',
9
+ '[Jul]',
10
+ '[Aug]',
11
+ '[Sep]',
12
+ '[Oct]',
13
+ '[Nov]',
14
+ '[Dec]',
15
+ ];
16
+ /**
17
+ * dayjs format string for the visible month label in {@link MonthCell} (`monthLabel`),
18
+ * based on calendar locale (Japanese `M月` vs English three-letter abbreviations).
19
+ *
20
+ * @param calendarLocale - The calendar locale (`'ja'` or `'en'`) — selects between
21
+ * Japanese (`M月`) and English (`[Jan]`–`[Dec]`) abbreviations
22
+ *
23
+ * @param date - The date whose month index selects the English abbreviation.
24
+ * Only consulted when `calendarLocale === 'en'`.
25
+ *
26
+ * @returns A dayjs-compatible format string for the month label
27
+ */
28
+ export function getMonthCellMonthFormat(calendarLocale, date) {
29
+ if (calendarLocale === 'en') {
30
+ // Date.getMonth() always returns 0–11, so the array access is safe.
31
+ const monthIndex = date.getMonth();
32
+ return ENGLISH_MONTH_ABBREVIATIONS[monthIndex];
33
+ }
34
+ return 'M月';
35
+ }
@@ -1,2 +1,10 @@
1
- export { MultilineTextBox } from './MultilineTextBox';
2
- export { MultilineTextBoxProps } from './MultilineTextBox.types';
1
+ /**
2
+ * MultilineTextBox backward compatibility re-exports.
3
+ *
4
+ * MultilineTextBox has been renamed to Textarea.
5
+ * Please migrate to Textarea. MultilineTextBox will be removed in a future major version (v5.0.0).
6
+ *
7
+ * @see Textarea
8
+ */
9
+ export { Textarea as MultilineTextBox } from '../Textarea';
10
+ export type { TextareaProps as MultilineTextBoxProps } from '../Textarea';
@@ -1 +1,9 @@
1
- export { MultilineTextBox } from './MultilineTextBox';
1
+ /**
2
+ * MultilineTextBox backward compatibility re-exports.
3
+ *
4
+ * MultilineTextBox has been renamed to Textarea.
5
+ * Please migrate to Textarea. MultilineTextBox will be removed in a future major version (v5.0.0).
6
+ *
7
+ * @see Textarea
8
+ */
9
+ export { Textarea as MultilineTextBox } from '../Textarea';
@@ -48,8 +48,6 @@ placeholder, renderDisplayValue, updateSelectedValues, clearButtonProps, disable
48
48
  .map((option) => option.value)
49
49
  .filter((v) => v != null)
50
50
  .map(String);
51
- return (
52
- // use div element instead of button element to prevent the nested button element when the selected options are rendered as tag list
53
- _jsx(FocusIndicator, { children: _jsxs("div", { ref: wrapperRef, className: cx(classes.wrapper, 'mfui-MultipleSelectBoxTrigger__wrapper', triggerWrapperProps?.className), children: [_jsx("button", { ref: mergeRefs(ref, triggerRef), type: "button", role: "combobox", "aria-controls": listBoxId, "aria-expanded": isOptionPanelOpen, "aria-haspopup": "listbox", "aria-invalid": invalid, value: selectedValues, disabled: disabled, onKeyDown: onKeyDown, onBlur: onBlur, ...rest, ...triggerProps, className: cx(classes.trigger, 'mfui-MultipleSelectBoxTrigger__trigger', triggerProps?.className) }), _jsx("input", { type: "hidden", name: name, value: selectedValues }), _jsx("div", { className: cx(classes.displayValues, 'mfui-MultipleSelectBoxTrigger__displayValues'), "data-mfui-content": "multiple-select-box-trigger-display-values", children: renderer() }), selectedOptions.length > 0 && !disabled && !disableClearButton ? (_jsx("div", { className: cx(classes.clearButtonContainer, 'mfui-MultipleSelectBoxTrigger__clearButtonContainer'), children: _jsx(ClearButton, { size: size === 'small' ? 'small' : 'default', className: cx(classes.clearButton, 'mfui-MultipleSelectBoxTrigger__clearButton'), "aria-label": clearButtonProps?.['aria-label'] ?? '値をクリアする', "data-mfui-content": "multiple-select-box-clear-button", onClick: handleClearValue }) })) : null, _jsx("div", { className: cx(classes.dropdownIconContainer, 'mfui-MultipleSelectBoxTrigger__dropdownIconContainer'), children: _jsx(DropdownIcon, { className: cx(classes.dropdownIcon, 'mfui-MultipleSelectBoxTrigger__dropdownIcon') }) })] }) }));
51
+ return (_jsx(FocusIndicator, { children: _jsxs("div", { ref: wrapperRef, className: cx(classes.wrapper, 'mfui-MultipleSelectBoxTrigger__wrapper', triggerWrapperProps?.className), children: [_jsx("button", { ref: mergeRefs(ref, triggerRef), type: "button", role: "combobox", "aria-controls": listBoxId, "aria-expanded": isOptionPanelOpen, "aria-haspopup": "listbox", "aria-invalid": invalid, value: selectedValues, disabled: disabled, onKeyDown: onKeyDown, onBlur: onBlur, ...rest, ...triggerProps, className: cx(classes.trigger, 'mfui-MultipleSelectBoxTrigger__trigger', triggerProps?.className) }), _jsx("input", { type: "hidden", name: name, value: selectedValues }), _jsx("div", { className: cx(classes.displayValues, 'mfui-MultipleSelectBoxTrigger__displayValues'), "data-mfui-content": "multiple-select-box-trigger-display-values", children: renderer() }), selectedOptions.length > 0 && !disabled && !disableClearButton ? (_jsx("div", { className: cx(classes.clearButtonContainer, 'mfui-MultipleSelectBoxTrigger__clearButtonContainer'), children: _jsx(ClearButton, { size: size === 'small' ? 'small' : 'default', className: cx(classes.clearButton, 'mfui-MultipleSelectBoxTrigger__clearButton'), "aria-label": clearButtonProps?.['aria-label'] ?? '値をクリアする', "data-mfui-content": "multiple-select-box-clear-button", onClick: handleClearValue }) })) : null, _jsx("div", { className: cx(classes.dropdownIconContainer, 'mfui-MultipleSelectBoxTrigger__dropdownIconContainer'), children: _jsx(DropdownIcon, { className: cx(classes.dropdownIcon, 'mfui-MultipleSelectBoxTrigger__dropdownIcon') }) })] }) }));
54
52
  }
55
53
  export const MultipleSelectBoxTrigger = forwardRef(MultipleSelectBoxTriggerInner);
@@ -28,11 +28,5 @@ export const RadioButtonCard = forwardRef(({ label, layout = 'vertical', renderD
28
28
  disableResponsive,
29
29
  isResponsive: Boolean(responsiveSlot.narrowViewport),
30
30
  });
31
- return (_jsxs("div", { className: cx(classes.root, 'mfui-RadioButtonCard__root', className), children: [_jsx(FocusIndicator, { disableNestedFocus: true, children: _jsxs(Typography, { variant: "label", className: cx(classes.inputWrapper, 'mfui-RadioButtonCard__inputWrapper'), as: "label", htmlFor: props.id, children: [_jsx(RadioButton, { ref: ref, ...props, className: cx(classes.input, 'mfui-RadioButtonCard__input') }), _jsx("span", { className: cx(classes.label, 'mfui-RadioButtonCard__label'), children: label })] }) }), responsiveSlot.narrowViewport && disableResponsive ? (
32
- /* When responsive is disabled, render single element but with both contents using CSS for switching */
33
- _jsxs(_Fragment, { children: [_jsx("div", { "data-mfui-content": "details", className: cx(classes.details, classes.detailsWide, 'mfui-RadioButtonCard__details'), children: responsiveSlot.base(radioButtonState) }), _jsx("div", { "data-mfui-content": "details", className: cx(classes.details, classes.detailsNarrow, 'mfui-RadioButtonCard__details'), children: responsiveSlot.narrowViewport(radioButtonState) })] })) : responsiveSlot.narrowViewport ? (
34
- /* When responsive is enabled, render separate wide/narrow elements */
35
- _jsxs(_Fragment, { children: [_jsx("div", { "data-mfui-content": "details", className: cx(classes.details, classes.detailsWide, 'mfui-RadioButtonCard__details'), children: responsiveSlot.base(radioButtonState) }), _jsx("div", { "data-mfui-content": "details", className: cx(classes.details, classes.detailsNarrow, 'mfui-RadioButtonCard__details'), children: responsiveSlot.narrowViewport(radioButtonState) })] })) : responsiveSlot.base ? (
36
- /* For function-based renderDetailsSlot or ResponsiveSlot with only base, use single details element */
37
- _jsx("div", { "data-mfui-content": "details", className: cx(classes.details, 'mfui-RadioButtonCard__details'), children: responsiveSlot.base(radioButtonState) })) : null] }));
31
+ return (_jsxs("div", { className: cx(classes.root, 'mfui-RadioButtonCard__root', className), children: [_jsx(FocusIndicator, { disableNestedFocus: true, children: _jsxs(Typography, { variant: "label", className: cx(classes.inputWrapper, 'mfui-RadioButtonCard__inputWrapper'), as: "label", htmlFor: props.id, children: [_jsx(RadioButton, { ref: ref, ...props, className: cx(classes.input, 'mfui-RadioButtonCard__input') }), _jsx("span", { className: cx(classes.label, 'mfui-RadioButtonCard__label'), children: label })] }) }), responsiveSlot.narrowViewport && disableResponsive ? (_jsxs(_Fragment, { children: [_jsx("div", { "data-mfui-content": "details", className: cx(classes.details, classes.detailsWide, 'mfui-RadioButtonCard__details'), children: responsiveSlot.base(radioButtonState) }), _jsx("div", { "data-mfui-content": "details", className: cx(classes.details, classes.detailsNarrow, 'mfui-RadioButtonCard__details'), children: responsiveSlot.narrowViewport(radioButtonState) })] })) : responsiveSlot.narrowViewport ? (_jsxs(_Fragment, { children: [_jsx("div", { "data-mfui-content": "details", className: cx(classes.details, classes.detailsWide, 'mfui-RadioButtonCard__details'), children: responsiveSlot.base(radioButtonState) }), _jsx("div", { "data-mfui-content": "details", className: cx(classes.details, classes.detailsNarrow, 'mfui-RadioButtonCard__details'), children: responsiveSlot.narrowViewport(radioButtonState) })] })) : responsiveSlot.base ? (_jsx("div", { "data-mfui-content": "details", className: cx(classes.details, 'mfui-RadioButtonCard__details'), children: responsiveSlot.base(radioButtonState) })) : null] }));
38
32
  });
@@ -41,11 +41,7 @@ export const TextBox = forwardRef(({ enableClearButton = false, onClear, invalid
41
41
  }, [onClear, shouldUseTouchDeviceMode]);
42
42
  // Get the display value for touch device mode
43
43
  const displayValue = (inputProps.value ?? inputProps.defaultValue ?? '');
44
- return shouldUseTouchDeviceMode ? (
45
- // Touch device: wrapper + hidden input + display div
46
- _jsxs("div", { ...wrapperProps, className: cx(classes.root, 'mfui-TextBox__root', wrapperProps.className), children: [_jsx("input", { type: "hidden", value: displayValue, name: inputProps.name }), prefixSlot ? _jsx("div", { className: cx(classes.prefix, 'mfui-TextBox__prefix'), children: prefixSlot }) : null, _jsx("div", { className: cx(classes.input, 'mfui-TextBox__input'), children: displayValue || inputProps.placeholder }), shouldShowClearButton ? (_jsx(ClearButton, { size: textBoxSize === 'small' ? 'small' : textBoxSize === 'large' ? 'large' : 'default', "aria-label": clearButtonProps?.['aria-label'] ?? '値をクリアする', className: cx(classes.clearButton, 'mfui-TextBox__clearButton'), disabled: disabled, onClick: (event) => {
44
+ return shouldUseTouchDeviceMode ? (_jsxs("div", { ...wrapperProps, className: cx(classes.root, 'mfui-TextBox__root', wrapperProps.className), children: [_jsx("input", { type: "hidden", value: displayValue, name: inputProps.name }), prefixSlot ? _jsx("div", { className: cx(classes.prefix, 'mfui-TextBox__prefix'), children: prefixSlot }) : null, _jsx("div", { className: cx(classes.input, 'mfui-TextBox__input'), children: displayValue || inputProps.placeholder }), shouldShowClearButton ? (_jsx(ClearButton, { size: textBoxSize === 'small' ? 'small' : textBoxSize === 'large' ? 'large' : 'default', "aria-label": clearButtonProps?.['aria-label'] ?? '値をクリアする', className: cx(classes.clearButton, 'mfui-TextBox__clearButton'), disabled: disabled, onClick: (event) => {
47
45
  onClear?.(event);
48
- } })) : null, suffixSlot ? _jsx("div", { className: cx(classes.suffix, 'mfui-TextBox__suffix'), children: suffixSlot }) : null] })) : (
49
- // Desktop: Standard input with FocusIndicator
50
- _jsx(FocusIndicator, { children: _jsxs("div", { ...wrapperProps, className: cx(classes.root, 'mfui-TextBox__root', wrapperProps.className), children: [prefixSlot ? _jsx("div", { className: cx(classes.prefix, 'mfui-TextBox__prefix'), children: prefixSlot }) : null, _jsx("input", { ref: mergedInputRef, disabled: disabled, ...inputProps, className: cx(classes.input, 'mfui-TextBox__input', inputProps.className), onChange: handleChange, onInput: handleInput }), shouldShowClearButton ? (_jsx(ClearButton, { size: textBoxSize === 'small' ? 'small' : textBoxSize === 'large' ? 'large' : 'default', "aria-label": clearButtonProps?.['aria-label'] ?? '値をクリアする', className: cx(classes.clearButton, 'mfui-TextBox__clearButton'), disabled: disabled, onClick: onClickClear })) : null, suffixSlot ? _jsx("div", { className: cx(classes.suffix, 'mfui-TextBox__suffix'), children: suffixSlot }) : null] }) }));
46
+ } })) : null, suffixSlot ? _jsx("div", { className: cx(classes.suffix, 'mfui-TextBox__suffix'), children: suffixSlot }) : null] })) : (_jsx(FocusIndicator, { children: _jsxs("div", { ...wrapperProps, className: cx(classes.root, 'mfui-TextBox__root', wrapperProps.className), children: [prefixSlot ? _jsx("div", { className: cx(classes.prefix, 'mfui-TextBox__prefix'), children: prefixSlot }) : null, _jsx("input", { ref: mergedInputRef, disabled: disabled, ...inputProps, className: cx(classes.input, 'mfui-TextBox__input', inputProps.className), onChange: handleChange, onInput: handleInput }), shouldShowClearButton ? (_jsx(ClearButton, { size: textBoxSize === 'small' ? 'small' : textBoxSize === 'large' ? 'large' : 'default', "aria-label": clearButtonProps?.['aria-label'] ?? '値をクリアする', className: cx(classes.clearButton, 'mfui-TextBox__clearButton'), disabled: disabled, onClick: onClickClear })) : null, suffixSlot ? _jsx("div", { className: cx(classes.suffix, 'mfui-TextBox__suffix'), children: suffixSlot }) : null] }) }));
51
47
  });
@@ -1,12 +1,15 @@
1
1
  /**
2
- * The general-purpose TextBox component.
2
+ * The general-purpose Textarea component.
3
3
  * This component switches the variants of looks and behaviors depends on the props: size, invalid, disabled.
4
4
  *
5
5
  * Also extends the props of `<textarea>` element
6
6
  *
7
+ * > **Migration note**: `MultilineTextBox` has been renamed to `Textarea`.
8
+ * > Please migrate to `Textarea`. `MultilineTextBox` will be removed in a future major version (v5.0.0).
9
+ *
7
10
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea
8
11
  */
9
- export declare const MultilineTextBox: import("react").ForwardRefExoticComponent<{
12
+ export declare const Textarea: import("react").ForwardRefExoticComponent<{
10
13
  invalid?: import("../../styled-system/recipes").TextBoxSlotRecipeVariant["invalid"];
11
14
  size?: import("../../styled-system/recipes").TextBoxSlotRecipeVariant["size"];
12
15
  disabled?: import("../../styled-system/recipes").TextBoxSlotRecipeVariant["disabled"];
@@ -1,22 +1,25 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { forwardRef, useRef, useCallback, useEffect } from 'react';
3
3
  import { cx } from '../../styled-system/css';
4
- import { multilineTextBoxSlotRecipe } from '../../styled-system/recipes';
4
+ import { textareaSlotRecipe } from '../../styled-system/recipes';
5
5
  import { FocusIndicator } from '../FocusIndicator';
6
6
  import { mergeRefs } from '../utilities/dom/mergeRefs';
7
7
  /**
8
- * The general-purpose TextBox component.
8
+ * The general-purpose Textarea component.
9
9
  * This component switches the variants of looks and behaviors depends on the props: size, invalid, disabled.
10
10
  *
11
11
  * Also extends the props of `<textarea>` element
12
12
  *
13
+ * > **Migration note**: `MultilineTextBox` has been renamed to `Textarea`.
14
+ * > Please migrate to `Textarea`. `MultilineTextBox` will be removed in a future major version (v5.0.0).
15
+ *
13
16
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea
14
17
  */
15
- export const MultilineTextBox = forwardRef(({ invalid = false, size = 'medium', disabled = false, rows = 1, enableAutoResize = false, resize = 'both', onChange, ...props }, ref) => {
18
+ export const Textarea = forwardRef(({ invalid = false, size = 'medium', disabled = false, rows = 1, enableAutoResize = false, resize = 'both', onChange, ...props }, ref) => {
16
19
  const localRef = useRef(null);
17
20
  // When enableAutoResize is true, force resize to 'none' to prevent conflicts
18
21
  const effectiveResize = enableAutoResize ? 'none' : resize;
19
- const classes = multilineTextBoxSlotRecipe({ size, disabled, invalid, enableAutoResize, resize: effectiveResize });
22
+ const classes = textareaSlotRecipe({ size, disabled, invalid, enableAutoResize, resize: effectiveResize });
20
23
  const adjustHeight = useCallback(() => {
21
24
  if (!enableAutoResize || !localRef.current)
22
25
  return;
@@ -47,5 +50,6 @@ export const MultilineTextBox = forwardRef(({ invalid = false, size = 'medium',
47
50
  adjustHeight();
48
51
  }
49
52
  }, [enableAutoResize, adjustHeight]);
50
- return (_jsx(FocusIndicator, { children: _jsx("textarea", { ref: mergeRefs(ref, localRef), ...props, rows: rows, className: cx(classes.root, 'mfui-MultilineTextBox__root', props.className), disabled: disabled, onChange: handleChange }) }));
53
+ return (_jsx(FocusIndicator, { children: _jsx("textarea", { ref: mergeRefs(ref, localRef), ...props, rows: rows, className: cx(classes.root, 'mfui-Textarea__root',
54
+ /* TODO: Remove in v5.0.0 */ 'mfui-MultilineTextBox__root', props.className), disabled: disabled, onChange: handleChange }) }));
51
55
  });
@@ -1,9 +1,9 @@
1
1
  import { type ComponentPropsWithoutRef } from 'react';
2
2
  import { type TextBoxSlotRecipeVariant } from '../../styled-system/recipes';
3
3
  /**
4
- * The props for the MultilineTextBox component.
4
+ * The props for the Textarea component.
5
5
  */
6
- export type MultilineTextBoxProps = {
6
+ export type TextareaProps = {
7
7
  /**
8
8
  * Whether the textarea is invalid or not.
9
9
  * This will change the style of the text box.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export { Textarea } from './Textarea';
2
+ export type { TextareaProps } from './Textarea.types';
@@ -0,0 +1 @@
1
+ export { Textarea } from './Textarea';
@@ -79,7 +79,16 @@ export const Tooltip = forwardRef(({ children, open, onOpenStateChanged, content
79
79
  }, [calculatedOpen, closeImmediate]);
80
80
  const triggerRef = mergeRefs(setTriggerReference, rootRef, ref);
81
81
  const classes = tooltipSlotRecipe();
82
- return (_jsxs(_Fragment, { children: [_jsx("div", { ref: triggerRef, ...wrapperProps, className: cx(classes.root, 'mfui-Tooltip__root', className), ...rootAttributes, children: isValidElement(children) ? (cloneElement(children, calculatedOpen && !hideFromScreenReader
83
- ? { 'aria-describedby': tooltipId }
84
- : undefined)) : (_jsx("span", { ...(calculatedOpen && !hideFromScreenReader ? { 'aria-describedby': tooltipId } : undefined), children: children })) }), calculatedOpen ? (_jsx(Portal, { targetDOMNode: targetElement, children: _jsxs("div", { ref: setTooltipReference, className: cx(classes.tooltip, 'mfui-Tooltip__tooltip', contentProps?.className), role: "tooltip", id: tooltipId, "aria-hidden": hideFromScreenReader ? true : undefined, style: { maxWidth, ...tooltipStyles }, ...tooltipAttributes, children: [typeof content === 'string' ? _jsx(Typography, { variant: "helpMessage", children: content }) : content, _jsx(ArrowIcon, { ref: arrowRef, "aria-hidden": true, placement: calculatedPlacement, className: cx(classes.arrow, 'mfui-Tooltip__arrow'), style: arrowStyles })] }) })) : null] }));
82
+ const ariaDescribedBy = !hideFromScreenReader && content != null ? tooltipId : undefined;
83
+ return (_jsxs(_Fragment, { children: [_jsx("div", { ref: triggerRef, ...wrapperProps, className: cx(classes.root, 'mfui-Tooltip__root', className), ...rootAttributes, children: isValidElement(children) ? (cloneElement(children, ariaDescribedBy ? { 'aria-describedby': ariaDescribedBy } : undefined)) : (_jsx("span", { ...(ariaDescribedBy ? { 'aria-describedby': ariaDescribedBy } : undefined), children: children })) }), !calculatedOpen && !hideFromScreenReader && content != null && (_jsx(Portal, { targetDOMNode: targetElement, children: _jsx("div", { "data-mfui-tooltip-hidden": true, id: tooltipId, style: {
84
+ position: 'absolute',
85
+ width: '1px',
86
+ height: '1px',
87
+ padding: 0,
88
+ margin: '-1px',
89
+ overflow: 'hidden',
90
+ clip: 'rect(0, 0, 0, 0)',
91
+ whiteSpace: 'nowrap',
92
+ borderWidth: 0,
93
+ }, children: content }) })), calculatedOpen ? (_jsx(Portal, { targetDOMNode: targetElement, children: _jsxs("div", { ref: setTooltipReference, className: cx(classes.tooltip, 'mfui-Tooltip__tooltip', contentProps?.className), role: "tooltip", id: tooltipId, "aria-hidden": hideFromScreenReader ? true : undefined, style: { maxWidth, ...tooltipStyles }, ...tooltipAttributes, children: [typeof content === 'string' ? _jsx(Typography, { variant: "helpMessage", children: content }) : content, _jsx(ArrowIcon, { ref: arrowRef, "aria-hidden": true, placement: calculatedPlacement, className: cx(classes.arrow, 'mfui-Tooltip__arrow'), style: arrowStyles })] }) })) : null] }));
85
94
  });
@@ -21,9 +21,7 @@ function InternalTypography(props, ref) {
21
21
  return variant.startsWith('strong') ? 'strong' : 'span';
22
22
  }, [variant, tag, rest.href]);
23
23
  const classes = typographySlotRecipe({ variant });
24
- return (
25
- // @ts-expect-error Ignore the error for ref due to the complexion.
26
- _jsx(Tag, { ref: ref, ...rest, className: cx(classes.root, 'mfui-Typography__root', className), children: children }));
24
+ return (_jsx(Tag, { ref: ref, ...rest, className: cx(classes.root, 'mfui-Typography__root', className), children: children }));
27
25
  }
28
26
  /**
29
27
  *
@@ -50,6 +50,7 @@ export * from './StatusLabel';
50
50
  export * from './SubNavigation';
51
51
  export * from './Tabs';
52
52
  export * from './Tag';
53
+ export * from './Textarea';
53
54
  export * from './TextBox';
54
55
  export * from './TextLink';
55
56
  export * from './Toast';
package/dist/src/index.js CHANGED
@@ -50,6 +50,7 @@ export * from './StatusLabel';
50
50
  export * from './SubNavigation';
51
51
  export * from './Tabs';
52
52
  export * from './Tag';
53
+ export * from './Textarea';
53
54
  export * from './TextBox';
54
55
  export * from './TextLink';
55
56
  export * from './Toast';