@farmzone/fz-react-ui 1.0.1 → 1.0.2

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/index.js CHANGED
@@ -909,7 +909,7 @@ var SELECT_BORDER_COLORS = {
909
909
  };
910
910
  function Select2(props) {
911
911
  const {
912
- containerClass,
912
+ containerClassName,
913
913
  options,
914
914
  placeholder = "\uC120\uD0DD\uD574 \uC8FC\uC138\uC694",
915
915
  triggerClassName,
@@ -939,7 +939,7 @@ function Select2(props) {
939
939
  onChange("");
940
940
  onReset?.();
941
941
  };
942
- return /* @__PURE__ */ jsxs("div", { className: cn("space-y-0.5", containerClass ?? "w-20"), children: [
942
+ return /* @__PURE__ */ jsxs("div", { className: cn("space-y-0.5", containerClassName ?? "w-30"), children: [
943
943
  label && /* @__PURE__ */ jsx(
944
944
  "label",
945
945
  {
@@ -1022,6 +1022,7 @@ function Radio(props) {
1022
1022
  checked,
1023
1023
  onChange,
1024
1024
  disabled = false,
1025
+ disabledMessage,
1025
1026
  checkColor = DEFAULT_CHECK_COLOR,
1026
1027
  unCheckColor = DEFAULT_UNCHECK_COLOR,
1027
1028
  labelClassName,
@@ -1070,23 +1071,29 @@ function Radio(props) {
1070
1071
  }
1071
1072
  )
1072
1073
  ] });
1074
+ const withTooltip = (node) => {
1075
+ if (!disabled || !disabledMessage) return node;
1076
+ return /* @__PURE__ */ jsx(Tooltip2, { content: disabledMessage, position: "bottom", asChild: true, sideOffset: 4, children: /* @__PURE__ */ jsx("span", { className: "inline-flex", children: node }) });
1077
+ };
1073
1078
  if (onChange !== void 0 && checked !== void 0) {
1074
- return /* @__PURE__ */ jsx(
1075
- RadioGroupPrimitive.Root,
1076
- {
1077
- name,
1078
- value: checked ? value : "",
1079
- onValueChange: (newValue) => {
1080
- if (newValue === value) {
1081
- onChange(value);
1082
- }
1083
- },
1084
- disabled,
1085
- children: control
1086
- }
1079
+ return withTooltip(
1080
+ /* @__PURE__ */ jsx(
1081
+ RadioGroupPrimitive.Root,
1082
+ {
1083
+ name,
1084
+ value: checked ? value : "",
1085
+ onValueChange: (newValue) => {
1086
+ if (newValue === value) {
1087
+ onChange(value);
1088
+ }
1089
+ },
1090
+ disabled,
1091
+ children: control
1092
+ }
1093
+ )
1087
1094
  );
1088
1095
  }
1089
- return control;
1096
+ return withTooltip(control);
1090
1097
  }
1091
1098
  function RadioGroup(props) {
1092
1099
  const {
@@ -1122,6 +1129,7 @@ function RadioGroup(props) {
1122
1129
  value: option.value,
1123
1130
  label: option.label,
1124
1131
  disabled: disabled || option.disabled,
1132
+ disabledMessage: option.disabled ? option.disabledMessage : void 0,
1125
1133
  checkColor,
1126
1134
  unCheckColor,
1127
1135
  labelClassName,
@@ -1926,6 +1934,28 @@ function parseLocalYmd(ymd) {
1926
1934
  if (dt.getFullYear() !== y || dt.getMonth() !== mo || dt.getDate() !== d) return null;
1927
1935
  return dt;
1928
1936
  }
1937
+ function canSelectToday(options) {
1938
+ const today = options.now ?? /* @__PURE__ */ new Date();
1939
+ const todayYmd = formatDate(today);
1940
+ if (options.maxDate && isCalendarDayAfterMax(today, options.maxDate)) {
1941
+ return false;
1942
+ }
1943
+ if (!options.range) {
1944
+ return true;
1945
+ }
1946
+ if (options.isSelectingEnd) {
1947
+ const start = options.rangeStart?.trim() ?? "";
1948
+ if (start.length === 10 && todayYmd < start) {
1949
+ return false;
1950
+ }
1951
+ return true;
1952
+ }
1953
+ const end = options.rangeEnd?.trim() ?? "";
1954
+ if (end.length === 10 && todayYmd > end) {
1955
+ return false;
1956
+ }
1957
+ return true;
1958
+ }
1929
1959
  function isCalendarDayAfterMax(date, maxYmd) {
1930
1960
  const max = parseLocalYmd(maxYmd);
1931
1961
  if (!max) return false;
@@ -1982,6 +2012,105 @@ function validateAndFormatInput(input) {
1982
2012
  }
1983
2013
  return `${year}-${month}-${day}`;
1984
2014
  }
2015
+
2016
+ // src/components/DatePicker/calendar/config/default.ts
2017
+ var DEFAULT_CALENDAR_YEAR_HALF_SPAN = 25;
2018
+ var CALENDAR_WEEKDAY_LABELS = ["\uC77C", "\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0"];
2019
+ var CALENDAR_RANGE_HINT = {
2020
+ start: "\uC2DC\uC791 \uB0A0\uC9DC\uB97C \uC120\uD0DD\uD558\uC138\uC694",
2021
+ end: "\uC885\uB8CC \uB0A0\uC9DC\uB97C \uC120\uD0DD\uD558\uC138\uC694"
2022
+ };
2023
+ var CALENDAR_PORTAL_Z_INDEX = Z_INDEX.CALENDAR_PORTAL;
2024
+ var CALENDAR_SELECT_CLASSNAMES = {
2025
+ containerClass: "w-20 shrink-0",
2026
+ triggerClassName: "h-8 px-2 py-1 text-sm cursor-pointer",
2027
+ contentClassName: "min-w-[5rem]"
2028
+ };
2029
+ var CALENDAR_PANEL_BASE_CLASS = "bg-white border border-gray-300 rounded-lg shadow-lg p-3 min-w-[280px]";
2030
+ var CALENDAR_PANEL_ANCHORED_CLASS = `${CALENDAR_PANEL_BASE_CLASS} absolute z-50`;
2031
+ var YEAR_SELECT_CONTENT_EXTRA_CLASS = "year-select-content custom-view-scrollbar max-h-50 overflow-y-auto";
2032
+ var YEAR_SELECT_OPEN_CONTENT_SELECTOR = ".year-select-content[data-state='open']";
2033
+ var SELECT_ITEM_CHECKED_SELECTOR = "[data-slot='select-item'][data-state='checked']";
2034
+
2035
+ // src/components/DatePicker/calendar/config/calendar.ts
2036
+ function parseYmdDateString(value) {
2037
+ if (value.length !== 10) return null;
2038
+ return parseLocalYmd(value);
2039
+ }
2040
+ function resolveCalendarYearBounds(anchorYear, calendarYearRange) {
2041
+ const fallbackMin = anchorYear - DEFAULT_CALENDAR_YEAR_HALF_SPAN;
2042
+ const fallbackMax = anchorYear + DEFAULT_CALENDAR_YEAR_HALF_SPAN;
2043
+ const rawMin = calendarYearRange?.minYear?.trim();
2044
+ const rawMax = calendarYearRange?.maxYear?.trim();
2045
+ if (rawMin === void 0 || rawMin === "" || rawMax === void 0 || rawMax === "") {
2046
+ return { minYear: fallbackMin, maxYear: fallbackMax };
2047
+ }
2048
+ const minParsed = Number.parseInt(rawMin, 10);
2049
+ const maxParsed = Number.parseInt(rawMax, 10);
2050
+ if (Number.isNaN(minParsed) || Number.isNaN(maxParsed) || minParsed > maxParsed) {
2051
+ return { minYear: fallbackMin, maxYear: fallbackMax };
2052
+ }
2053
+ return { minYear: minParsed, maxYear: maxParsed };
2054
+ }
2055
+ function buildCalendarYearSelectOptions(maxDate, anchorYear = (/* @__PURE__ */ new Date()).getFullYear(), calendarYearRange) {
2056
+ const { minYear, maxYear } = resolveCalendarYearBounds(anchorYear, calendarYearRange);
2057
+ const maxSelectableYear = maxDate ? parseLocalYmd(maxDate)?.getFullYear() ?? null : null;
2058
+ const options = [];
2059
+ for (let y = maxYear; y >= minYear; y--) {
2060
+ options.push({
2061
+ value: String(y),
2062
+ label: `${y}\uB144`,
2063
+ disabled: maxSelectableYear !== null && y > maxSelectableYear
2064
+ });
2065
+ }
2066
+ return options;
2067
+ }
2068
+ function buildCalendarMonthSelectOptions(viewYear, maxDate) {
2069
+ const maxDateParsed = maxDate ? parseLocalYmd(maxDate) : null;
2070
+ const maxYear = maxDateParsed?.getFullYear() ?? null;
2071
+ const maxMonth = maxDateParsed !== null && maxDateParsed !== void 0 ? maxDateParsed.getMonth() + 1 : null;
2072
+ const isMaxYear = maxYear !== null && viewYear === maxYear;
2073
+ const options = [];
2074
+ for (let m = 1; m <= 12; m++) {
2075
+ options.push({
2076
+ value: String(m),
2077
+ label: `${m}\uC6D4`,
2078
+ disabled: isMaxYear && maxMonth !== null && m > maxMonth
2079
+ });
2080
+ }
2081
+ return options;
2082
+ }
2083
+ function getCalendarMonthGrid(year, monthIndex) {
2084
+ const firstDay = new Date(year, monthIndex, 1);
2085
+ const daysInMonth = new Date(year, monthIndex + 1, 0).getDate();
2086
+ const leadingEmpty = firstDay.getDay();
2087
+ const totalCells = leadingEmpty + daysInMonth;
2088
+ const trailingEmpty = totalCells % 7 === 0 ? 0 : 7 - totalCells % 7;
2089
+ return { leadingEmpty, daysInMonth, trailingEmpty };
2090
+ }
2091
+ function disableNextCalendarMonth(year, monthIndex, maxDate) {
2092
+ if (maxDate === void 0) return false;
2093
+ return isCalendarDayAfterMax(new Date(year, monthIndex + 1, 1), maxDate);
2094
+ }
2095
+ function scrollOpenYearSelectCheckedIntoView() {
2096
+ requestAnimationFrame(() => {
2097
+ const root2 = document.querySelector(YEAR_SELECT_OPEN_CONTENT_SELECTOR);
2098
+ if (!(root2 instanceof HTMLElement)) return;
2099
+ const checkedItem = root2.querySelector(SELECT_ITEM_CHECKED_SELECTOR);
2100
+ if (!(checkedItem instanceof HTMLElement)) return;
2101
+ checkedItem.scrollIntoView({ block: "start" });
2102
+ });
2103
+ }
2104
+ function dayCellButtonClass(opts) {
2105
+ const { isToday, isSelected, isInRange, isRangeStart, isRangeEnd, interactiveDisabled } = opts;
2106
+ const parts = ["w-8 h-8 text-sm flex items-center justify-center rounded-2xl transition-colors"];
2107
+ if (isToday) parts.push("bg-gray-100");
2108
+ if (isSelected && !isToday) parts.push("bg-neutral-200 text-gray-700");
2109
+ if (isInRange && !isToday) parts.push("bg-gray-100/90");
2110
+ if ((isRangeStart || isRangeEnd) && !isToday) parts.push("bg-neutral-300 text-gray-700 opacity-100");
2111
+ parts.push(interactiveDisabled ? "opacity-20 cursor-not-allowed" : "hover:bg-blue-100 cursor-pointer");
2112
+ return parts.filter(Boolean).join(" ").trim();
2113
+ }
1985
2114
  function RenderCalendar(props) {
1986
2115
  const {
1987
2116
  currentDate,
@@ -1996,133 +2125,163 @@ function RenderCalendar(props) {
1996
2125
  goToNextMonth,
1997
2126
  onYearChange,
1998
2127
  onMonthChange,
2128
+ onSelectOpenChange,
1999
2129
  editDateSelect = true,
2000
2130
  datePosition = "bottom",
2001
- calendarSelectContainerClass
2131
+ maxDate,
2132
+ calendarYearRange,
2133
+ calendarSelectContainerClass,
2134
+ floating = false,
2135
+ showTodayButton = true
2002
2136
  } = props;
2003
2137
  const year = currentDate.getFullYear();
2004
- const month = currentDate.getMonth();
2005
- const firstDay = new Date(year, month, 1);
2006
- const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
2007
- const yearOptions = [];
2008
- for (let i = currentYear - 25; i <= currentYear + 20; i++) {
2009
- yearOptions.push({ value: i.toString(), label: `${i}\uB144` });
2010
- }
2011
- const monthOptions = [];
2012
- for (let i = 1; i <= 12; i++) {
2013
- monthOptions.push({ value: i.toString(), label: `${i}\uC6D4` });
2014
- }
2015
- const lastDay = new Date(year, month + 1, 0);
2016
- const startDate = new Date(firstDay);
2017
- startDate.setDate(startDate.getDate() - firstDay.getDay());
2018
- const endDate = new Date(lastDay);
2019
- endDate.setDate(endDate.getDate() + (6 - endDate.getDay()));
2020
- const totalDays = Math.ceil((endDate.getTime() - startDate.getTime()) / (1e3 * 60 * 60 * 24)) + 1;
2138
+ const monthIndex = currentDate.getMonth();
2139
+ const anchorYear = (/* @__PURE__ */ new Date()).getFullYear();
2140
+ const disableNextMonth = disableNextCalendarMonth(year, monthIndex, maxDate);
2141
+ const { leadingEmpty, daysInMonth, trailingEmpty } = getCalendarMonthGrid(year, monthIndex);
2142
+ const yearOptions = buildCalendarYearSelectOptions(maxDate, anchorYear, calendarYearRange);
2143
+ const monthOptions = buildCalendarMonthSelectOptions(year, maxDate);
2144
+ const todayFormatted = formatDate(/* @__PURE__ */ new Date());
2145
+ const selectedSingleYmd = range ? null : inputValue;
2146
+ const rangeStartYmd = rangeStart.trim();
2147
+ const rangeEndYmd = rangeEnd.trim();
2021
2148
  const days = [];
2022
- const currentDateFormatted = formatDate(/* @__PURE__ */ new Date());
2023
- const selectedDate = range ? null : inputValue;
2024
- const handleStopPropagation = (e) => e.stopPropagation();
2025
- const handleYearChange = (value) => onYearChange(parseInt(value));
2026
- const handleMonthChange = (value) => onMonthChange(parseInt(value) - 1);
2027
- for (let i = 0; i < totalDays; i++) {
2028
- const date = new Date(startDate);
2029
- date.setDate(startDate.getDate() + i);
2149
+ for (let i = 0; i < leadingEmpty; i++) {
2150
+ days.push(/* @__PURE__ */ jsx("div", { className: "size-8", "aria-hidden": true }, `lead-${i}`));
2151
+ }
2152
+ for (let d = 1; d <= daysInMonth; d++) {
2153
+ const date = new Date(year, monthIndex, d);
2030
2154
  const dateFormatted = formatDate(date);
2031
- const isToday = dateFormatted === currentDateFormatted;
2032
- const isSelected = dateFormatted === selectedDate;
2155
+ const isToday = dateFormatted === todayFormatted;
2156
+ const isSelected = dateFormatted === selectedSingleYmd;
2033
2157
  const isInRange = isDateInRange(date, range, rangeStart, rangeEnd);
2034
- const isRangeStart = range && dateFormatted === rangeStart;
2035
- const isRangeEnd = range && dateFormatted === rangeEnd;
2036
- const isCurrentMonth = date.getMonth() === month;
2037
- const rangeStartDate = new Date(rangeStart);
2038
- rangeStartDate.setDate(rangeStartDate.getDate() - 1);
2039
- const isDisabled = range && isSelectingEnd && rangeStart && date < rangeStartDate;
2158
+ const isRangeStartFlag = Boolean(range && dateFormatted === rangeStart);
2159
+ const isRangeEndFlag = Boolean(range && dateFormatted === rangeEnd);
2160
+ const isBeforeRangeStart = range && isSelectingEnd && rangeStartYmd.length === 10 && dateFormatted < rangeStartYmd;
2161
+ const isAfterRangeEnd = range && !isSelectingEnd && rangeEndYmd.length === 10 && dateFormatted > rangeEndYmd;
2162
+ const isGreyedForRange = Boolean(isBeforeRangeStart || isAfterRangeEnd);
2163
+ const isPastMax = maxDate ? isCalendarDayAfterMax(date, maxDate) : false;
2040
2164
  days.push(
2041
2165
  /* @__PURE__ */ jsx(
2042
2166
  "button",
2043
2167
  {
2168
+ type: "button",
2044
2169
  onClick: () => handleDateSelect(date),
2045
- disabled: isDisabled || false,
2046
- className: `
2047
- w-8 h-8 text-sm flex items-center justify-center rounded-2xl transition-colors
2048
- ${!isCurrentMonth ? "text-gray-300" : ""}
2049
- ${isToday ? "bg-gray-100 " : ""}
2050
- ${isInRange && !isToday ? "bg-gray-100/90" : ""}
2051
- ${isSelected && !isToday ? "bg-neutral-200 text-gray-700" : ""}
2052
- ${(isRangeStart || isRangeEnd) && !isToday ? "bg-neutral-300 text-gray-700 opacity-100" : ""}
2053
- ${isDisabled ? "opacity-20 cursor-not-allowed" : "hover:bg-blue-100 cursor-pointer"}
2054
- `,
2055
- children: date.getDate()
2170
+ disabled: isGreyedForRange || isPastMax,
2171
+ className: dayCellButtonClass({
2172
+ isToday,
2173
+ isSelected: Boolean(isSelected),
2174
+ isInRange,
2175
+ isRangeStart: isRangeStartFlag,
2176
+ isRangeEnd: isRangeEndFlag,
2177
+ interactiveDisabled: isGreyedForRange || isPastMax
2178
+ }),
2179
+ children: d
2056
2180
  },
2057
- i
2181
+ d
2058
2182
  )
2059
2183
  );
2060
2184
  }
2061
- const calendarPositionClass = range && calendarPosition === "end" ? "right-0" : "left-0";
2062
- const datePositionClass = datePosition === "top" ? "bottom-full mb-1" : "top-full mt-1";
2063
- return /* @__PURE__ */ jsxs(
2064
- "div",
2065
- {
2066
- className: `${datePositionClass} ${calendarPositionClass} bg-white border border-gray-300 rounded-lg shadow-lg p-3 z-50 min-w-[280px]`,
2067
- onClick: handleStopPropagation,
2068
- onMouseDown: handleStopPropagation,
2069
- children: [
2070
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1", children: [
2071
- /* @__PURE__ */ jsx("button", { onClick: goToPreviousMonth, className: "p-1 hover:bg-gray-100 rounded cursor-pointer", children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4 text-balck" }) }),
2072
- editDateSelect ? /* @__PURE__ */ jsxs(
2073
- "div",
2074
- {
2075
- className: "flex items-center gap-2",
2076
- onClick: handleStopPropagation,
2077
- onMouseDown: handleStopPropagation,
2078
- children: [
2079
- /* @__PURE__ */ jsx("div", { onClick: handleStopPropagation, onMouseDown: handleStopPropagation, children: /* @__PURE__ */ jsx(
2080
- Select2,
2081
- {
2082
- value: year.toString(),
2083
- options: yearOptions,
2084
- onChange: handleYearChange,
2085
- className: "cursor-pointer",
2086
- containerClass: calendarSelectContainerClass
2087
- }
2088
- ) }),
2089
- /* @__PURE__ */ jsx("div", { onClick: handleStopPropagation, onMouseDown: handleStopPropagation, children: /* @__PURE__ */ jsx(
2090
- Select2,
2091
- {
2092
- value: (month + 1).toString(),
2093
- options: monthOptions,
2094
- onChange: handleMonthChange,
2095
- className: "cursor-pointer",
2096
- containerClass: calendarSelectContainerClass
2097
- }
2098
- ) })
2099
- ]
2100
- }
2101
- ) : /* @__PURE__ */ jsxs("h3", { className: "text-lg font-semibold", children: [
2102
- year,
2103
- "\uB144 ",
2104
- month + 1,
2105
- "\uC6D4"
2106
- ] }),
2107
- /* @__PURE__ */ jsx("button", { onClick: goToNextMonth, className: "p-1 hover:bg-gray-100 rounded cursor-pointer", children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" }) })
2108
- ] }),
2109
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-1 mb-1", children: ["\uC77C", "\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0"].map((day) => /* @__PURE__ */ jsx("div", { className: "text-center text-sm font-medium text-gray-500 py-2 ", children: day }, day)) }),
2110
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-2", children: days })
2111
- ]
2112
- }
2113
- );
2114
- }
2115
-
2116
- // src/components/DatePicker/calendar/config/default.ts
2117
- var CALENDAR_PORTAL_Z_INDEX = Z_INDEX.CALENDAR_PORTAL;
2118
-
2119
- // src/components/DatePicker/calendar/config/calendar.ts
2120
- function parseYmdDateString(value) {
2121
- if (value.length !== 10) return null;
2122
- return parseLocalYmd(value);
2185
+ for (let i = 0; i < trailingEmpty; i++) {
2186
+ days.push(/* @__PURE__ */ jsx("div", { className: "size-8", "aria-hidden": true }, `trail-${i}`));
2187
+ }
2188
+ const calendarPositionClass = !floating && range && calendarPosition === "end" ? "right-0" : !floating ? "left-0" : "";
2189
+ const datePositionClass = floating ? "" : datePosition === "top" ? "bottom-full mb-1" : "top-full mt-1";
2190
+ const panelClass = floating ? CALENDAR_PANEL_BASE_CLASS : cn(CALENDAR_PANEL_ANCHORED_CLASS, datePositionClass, calendarPositionClass);
2191
+ const handleYearSelectOpenChange = (open) => {
2192
+ onSelectOpenChange?.(open);
2193
+ if (open) scrollOpenYearSelectCheckedIntoView();
2194
+ };
2195
+ const sel = CALENDAR_SELECT_CLASSNAMES;
2196
+ const containerClass = cn(sel.containerClass, calendarSelectContainerClass);
2197
+ const stopBubble = (e) => e.stopPropagation();
2198
+ const isTodaySelectable = canSelectToday({
2199
+ maxDate,
2200
+ range,
2201
+ isSelectingEnd,
2202
+ rangeStart,
2203
+ rangeEnd
2204
+ });
2205
+ return /* @__PURE__ */ jsxs("div", { className: panelClass, onClick: stopBubble, onMouseDown: stopBubble, children: [
2206
+ /* @__PURE__ */ jsxs("div", { className: "mb-1 flex items-center justify-between", children: [
2207
+ /* @__PURE__ */ jsx(
2208
+ "button",
2209
+ {
2210
+ type: "button",
2211
+ onClick: goToPreviousMonth,
2212
+ className: "cursor-pointer rounded p-1 hover:bg-gray-100",
2213
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" })
2214
+ }
2215
+ ),
2216
+ editDateSelect ? /* @__PURE__ */ jsxs(
2217
+ "div",
2218
+ {
2219
+ role: "presentation",
2220
+ className: "flex items-center gap-2",
2221
+ onClick: stopBubble,
2222
+ onMouseDown: stopBubble,
2223
+ children: [
2224
+ /* @__PURE__ */ jsx(
2225
+ Select2,
2226
+ {
2227
+ value: year.toString(),
2228
+ options: yearOptions,
2229
+ onChange: (value) => onYearChange(Number.parseInt(value, 10)),
2230
+ containerClassName: containerClass,
2231
+ triggerClassName: sel.triggerClassName,
2232
+ contentClassName: cn(YEAR_SELECT_CONTENT_EXTRA_CLASS, sel.contentClassName),
2233
+ disableScrollButtonEvents: true,
2234
+ onOpenChange: handleYearSelectOpenChange
2235
+ }
2236
+ ),
2237
+ /* @__PURE__ */ jsx(
2238
+ Select2,
2239
+ {
2240
+ value: (monthIndex + 1).toString(),
2241
+ options: monthOptions,
2242
+ onChange: (value) => onMonthChange(Number.parseInt(value, 10) - 1),
2243
+ containerClassName: containerClass,
2244
+ triggerClassName: sel.triggerClassName,
2245
+ contentClassName: sel.contentClassName,
2246
+ onOpenChange: (open) => onSelectOpenChange?.(open)
2247
+ }
2248
+ )
2249
+ ]
2250
+ }
2251
+ ) : /* @__PURE__ */ jsxs("h3", { className: "text-lg font-semibold", children: [
2252
+ year,
2253
+ "\uB144 ",
2254
+ monthIndex + 1,
2255
+ "\uC6D4"
2256
+ ] }),
2257
+ /* @__PURE__ */ jsx(
2258
+ "button",
2259
+ {
2260
+ type: "button",
2261
+ onClick: goToNextMonth,
2262
+ disabled: disableNextMonth,
2263
+ className: cn(
2264
+ "rounded p-1",
2265
+ disableNextMonth ? "cursor-not-allowed opacity-30" : "cursor-pointer hover:bg-gray-100"
2266
+ ),
2267
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })
2268
+ }
2269
+ )
2270
+ ] }),
2271
+ /* @__PURE__ */ jsx("div", { className: "mb-1 grid grid-cols-7 gap-1", children: CALENDAR_WEEKDAY_LABELS.map((day) => /* @__PURE__ */ jsx("div", { className: "py-2 text-center text-sm font-medium text-gray-500", children: day }, day)) }),
2272
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-2", children: days }),
2273
+ range && /* @__PURE__ */ jsx("div", { className: "mt-3 text-sm text-gray-600", children: /* @__PURE__ */ jsx("p", { className: "text-center", children: isSelectingEnd ? CALENDAR_RANGE_HINT.end : CALENDAR_RANGE_HINT.start }) }),
2274
+ showTodayButton && isTodaySelectable && /* @__PURE__ */ jsx("div", { className: "-mx-3 -mb-3 mt-3 flex items-center justify-center border-t border-gray-200 py-2", children: /* @__PURE__ */ jsx(
2275
+ "button",
2276
+ {
2277
+ type: "button",
2278
+ onClick: () => handleDateSelect(/* @__PURE__ */ new Date()),
2279
+ className: "cursor-pointer text-sm text-gray-800 hover:text-main",
2280
+ children: "Today"
2281
+ }
2282
+ ) })
2283
+ ] });
2123
2284
  }
2124
-
2125
- // src/components/DatePicker/calendar/hooks/useCalendarState.ts
2126
2285
  function useCalendarState(props) {
2127
2286
  const { datePosition = "bottom", disabled = false, calendarRef } = props;
2128
2287
  const [isCalendarOpen, setIsCalendarOpen] = useState(false);
@@ -2219,11 +2378,15 @@ function useFloatingCalendarPosition(anchorRef, isOpen2, placement, align = "sta
2219
2378
  setStyle({ ...base, top: rect.bottom + CALENDAR_GAP });
2220
2379
  }
2221
2380
  };
2381
+ const handleScroll = (e) => {
2382
+ if (e.target?.closest?.('[data-slot="select-content"]')) return;
2383
+ update();
2384
+ };
2222
2385
  update();
2223
- window.addEventListener("scroll", update, true);
2386
+ window.addEventListener("scroll", handleScroll, true);
2224
2387
  window.addEventListener("resize", update);
2225
2388
  return () => {
2226
- window.removeEventListener("scroll", update, true);
2389
+ window.removeEventListener("scroll", handleScroll, true);
2227
2390
  window.removeEventListener("resize", update);
2228
2391
  };
2229
2392
  }, [isOpen2, placement, align, anchorRef]);
@@ -6531,7 +6694,7 @@ function CascadingSelectFieldInner(props) {
6531
6694
  disabled,
6532
6695
  hasError,
6533
6696
  options: toSelectOptions(primaryOptions),
6534
- containerClass: firstSelectClass.containerClassName,
6697
+ containerClassName: firstSelectClass.containerClassName,
6535
6698
  triggerClassName: firstSelectClass.triggerClassName,
6536
6699
  canReset: true,
6537
6700
  onChange: (nextPrimary) => {
@@ -6548,7 +6711,7 @@ function CascadingSelectFieldInner(props) {
6548
6711
  disabled: disabled || !primary || secondaryOptions.length === 0,
6549
6712
  hasError,
6550
6713
  options: toSelectOptions(secondaryOptions),
6551
- containerClass: secondSelectClass.containerClassName,
6714
+ containerClassName: secondSelectClass.containerClassName,
6552
6715
  triggerClassName: secondSelectClass.triggerClassName,
6553
6716
  canReset: true,
6554
6717
  onChange: (nextSecondary) => {
@@ -6592,7 +6755,8 @@ function DateField(props) {
6592
6755
  readOnly = false,
6593
6756
  className = "w-40",
6594
6757
  datePosition = "bottom",
6595
- disableFutureDates = false
6758
+ disableFutureDates = false,
6759
+ calendarSelectContainerClass = "w-20"
6596
6760
  } = config;
6597
6761
  const maxDate = disableFutureDates ? formatDate(/* @__PURE__ */ new Date()) : void 0;
6598
6762
  if (readOnly) {
@@ -6609,7 +6773,8 @@ function DateField(props) {
6609
6773
  className: "w-full",
6610
6774
  validation: hasError,
6611
6775
  datePosition,
6612
- maxDate
6776
+ maxDate,
6777
+ calendarSelectContainerClass
6613
6778
  }
6614
6779
  ) });
6615
6780
  }
@@ -6799,7 +6964,9 @@ function RadioField(props) {
6799
6964
  containerClassName: cn2("justify-start", fieldControlWrapClass(className)),
6800
6965
  options: options.map((option) => ({
6801
6966
  label: option.label,
6802
- value: String(option.value)
6967
+ value: String(option.value),
6968
+ disabled: option.disabled,
6969
+ disabledMessage: option.disabledMessage
6803
6970
  }))
6804
6971
  }
6805
6972
  );
@@ -6837,7 +7004,7 @@ function SelectField(props) {
6837
7004
  disabled,
6838
7005
  hasError,
6839
7006
  options: selectOptions,
6840
- containerClass: "flex w-full min-w-0 max-w-full items-center",
7007
+ containerClassName: "flex w-full min-w-0 max-w-full items-center",
6841
7008
  className: "w-full min-w-0",
6842
7009
  triggerClassName: cn2(
6843
7010
  "h-8 w-full min-w-0 max-w-full rounded border bg-white px-2 py-1 text-sm shadow-none",
@@ -6949,11 +7116,12 @@ function SelectWithInputField(props) {
6949
7116
  disabled,
6950
7117
  hasError,
6951
7118
  options: toSelectOptions(options),
6952
- containerClass: selectClass.containerClassName,
7119
+ containerClassName: selectClass.containerClassName,
6953
7120
  triggerClassName: selectClass.triggerClassName,
6954
7121
  onChange: (nextPrefix) => {
6955
7122
  setSelectedPrefix(nextPrefix);
6956
7123
  updateCombined(nextPrefix, inputPart);
7124
+ onBlur();
6957
7125
  }
6958
7126
  }
6959
7127
  ),
@@ -7088,7 +7256,7 @@ function useBlurValidation(name, options) {
7088
7256
  (value, fieldOnChange) => {
7089
7257
  markHadValueIfFilled(value);
7090
7258
  fieldOnChange(value);
7091
- if (options.revalidateOnChange || shouldValidateEmptyOnChange(value)) {
7259
+ if (options.revalidateOnChange || options.validateEmptyOnChange && shouldValidateEmptyOnChange(value)) {
7092
7260
  void trigger(name);
7093
7261
  }
7094
7262
  void triggerRelatedFields();
@@ -7096,6 +7264,7 @@ function useBlurValidation(name, options) {
7096
7264
  [
7097
7265
  markHadValueIfFilled,
7098
7266
  options.revalidateOnChange,
7267
+ options.validateEmptyOnChange,
7099
7268
  shouldValidateEmptyOnChange,
7100
7269
  trigger,
7101
7270
  name,
@@ -7116,9 +7285,7 @@ var REVALIDATE_ON_CHANGE_TYPES = /* @__PURE__ */ new Set([
7116
7285
  "radio",
7117
7286
  "switch",
7118
7287
  "select",
7119
- "date",
7120
7288
  "cascading-select",
7121
- "select-with-input",
7122
7289
  "input-with-button",
7123
7290
  "address"
7124
7291
  ]);
@@ -7139,14 +7306,15 @@ function FormFieldRow(props) {
7139
7306
  const { control } = useFormContext();
7140
7307
  const { isSubmitted } = useFormState({ control });
7141
7308
  const { name, label, type = "input", required = false, renderCustomField, contentAlign = "left" } = config;
7309
+ const revalidateOnChange = REVALIDATE_ON_CHANGE_TYPES.has(type);
7142
7310
  const { handleBlur, handleChange } = useBlurValidation(name, {
7143
7311
  required,
7144
- revalidateOnChange: REVALIDATE_ON_CHANGE_TYPES.has(type),
7312
+ revalidateOnChange,
7313
+ validateEmptyOnChange: revalidateOnChange,
7145
7314
  revalidateFields: config.revalidateFields
7146
7315
  });
7147
7316
  const showError = Boolean(fieldState.error?.message) && (isSubmitted || fieldState.isTouched);
7148
7317
  const isTextarea = type === "textarea";
7149
- const revalidateOnChange = REVALIDATE_ON_CHANGE_TYPES.has(type);
7150
7318
  const wrappedField = wrapFieldHandlers(field, {
7151
7319
  onBlur: () => handleBlur(() => field.onBlur()),
7152
7320
  onChange: (value) => {
@@ -7251,6 +7419,7 @@ function rowPropsToFieldConfig(props) {
7251
7419
  canReset,
7252
7420
  datePosition,
7253
7421
  disableFutureDates,
7422
+ calendarSelectContainerClass,
7254
7423
  revalidateFields,
7255
7424
  renderCustomField,
7256
7425
  colspan,
@@ -7281,6 +7450,7 @@ function rowPropsToFieldConfig(props) {
7281
7450
  canReset,
7282
7451
  datePosition,
7283
7452
  disableFutureDates,
7453
+ calendarSelectContainerClass,
7284
7454
  revalidateFields,
7285
7455
  renderCustomField,
7286
7456
  colspan,
@@ -7440,14 +7610,7 @@ function PageFilter(props) {
7440
7610
  const rowGap2 = index !== 0 ? option.label ? gap : 5 : 0;
7441
7611
  switch (option.type) {
7442
7612
  case "input":
7443
- return /* @__PURE__ */ jsx(LabeledFilterOption, { label: option.label, gap: rowGap2, children: /* @__PURE__ */ jsx(
7444
- Input2,
7445
- {
7446
- placeholder: option.placeholder,
7447
- value: currentValue,
7448
- onChange: handleInputChange(optionKey)
7449
- }
7450
- ) }, String(optionKey));
7613
+ return /* @__PURE__ */ jsx(LabeledFilterOption, { label: option.label, gap: rowGap2, children: /* @__PURE__ */ jsx(Input2, { placeholder: option.placeholder, value: currentValue, onChange: handleInputChange(optionKey) }) }, String(optionKey));
7451
7614
  case "select":
7452
7615
  return /* @__PURE__ */ jsx(LabeledFilterOption, { label: option.label, gap: rowGap2, children: /* @__PURE__ */ jsx(
7453
7616
  Select2,
@@ -7455,7 +7618,8 @@ function PageFilter(props) {
7455
7618
  value: currentValue,
7456
7619
  onChange: handleSelectChange(optionKey),
7457
7620
  options: option.options,
7458
- placeholder: "\uC120\uD0DD\uD574\uC8FC\uC138\uC694"
7621
+ placeholder: "\uC120\uD0DD",
7622
+ containerClassName: option.containerClassName ?? "w-30"
7459
7623
  }
7460
7624
  ) }, String(optionKey));
7461
7625
  case "radio":