@ceed/cds 1.5.4 → 1.5.6-next.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.
@@ -1,6 +1,8 @@
1
1
  export declare const getCalendarDates: (date: Date) => (number | undefined)[][];
2
2
  export declare const getYearName: (date: Date, locale: string) => string;
3
- export declare const getMonthName: (date: Date, locale: string) => string;
3
+ export declare const getMonthName: (date: Date, locale: string, options?: {
4
+ hideYear?: boolean;
5
+ }) => string;
4
6
  export declare const getMonthNameFromIndex: (index: number, locale: string) => string;
5
7
  /**
6
8
  * 일~토 / Sun ~ Sat 같은 요일 이름을 가져옵니다.
@@ -20,6 +20,8 @@ interface BaseMonthPickerProps {
20
20
  disableFuture?: boolean;
21
21
  disablePast?: boolean;
22
22
  format?: string;
23
+ displayFormat?: string;
24
+ locale?: string;
23
25
  }
24
26
  export type MonthPickerProps = BaseMonthPickerProps & Omit<React.ComponentProps<typeof Input>, "onChange" | "value" | "defaultValue">;
25
27
  declare const MonthPicker: React.ForwardRefExoticComponent<Omit<MonthPickerProps, "ref"> & React.RefAttributes<HTMLInputElement>>;
@@ -1,3 +1,3 @@
1
1
  export declare function useControlledState<T>(controlledValue: T | undefined, defaultValue: T, onChange?: (value: T) => void, options?: {
2
2
  disableStrict?: boolean;
3
- }): [T, (value: T | ((prev: T) => T)) => void];
3
+ }): [T, (value: T | ((prev: T) => T)) => void, boolean];
package/dist/index.cjs CHANGED
@@ -408,25 +408,26 @@ var IconButton_default = IconButton;
408
408
  var import_react5 = require("react");
409
409
  function useControlledState(controlledValue, defaultValue, onChange, options) {
410
410
  const { current: isControlled } = (0, import_react5.useRef)(controlledValue !== void 0);
411
- const [displayValue, setDisplayValue] = (0, import_react5.useState)(
411
+ const [internalValue, setInternalValue] = (0, import_react5.useState)(
412
412
  controlledValue ?? defaultValue
413
413
  );
414
+ const displayValue = isControlled ? controlledValue : internalValue;
414
415
  (0, import_react5.useEffect)(() => {
415
416
  if (isControlled) {
416
- setDisplayValue(controlledValue ?? defaultValue);
417
+ setInternalValue(controlledValue);
417
418
  }
418
- }, [controlledValue, defaultValue, isControlled]);
419
+ }, [isControlled, controlledValue]);
419
420
  const handleChange = (0, import_react5.useCallback)(
420
421
  (value) => {
421
422
  const newValue = typeof value === "function" ? value(displayValue) : value;
422
- if (options?.disableStrict || !isControlled) {
423
- setDisplayValue(newValue);
423
+ if (!isControlled) {
424
+ setInternalValue(newValue);
424
425
  }
425
426
  onChange?.(newValue);
426
427
  },
427
- [isControlled, onChange, displayValue, options]
428
+ [isControlled, onChange, displayValue]
428
429
  );
429
- return [displayValue, handleChange];
430
+ return [displayValue, handleChange, isControlled];
430
431
  }
431
432
 
432
433
  // src/components/Autocomplete/Autocomplete.tsx
@@ -851,8 +852,11 @@ var getCalendarDates = (date) => {
851
852
  var getYearName = (date, locale) => {
852
853
  return date.toLocaleString(locale, { year: "numeric" });
853
854
  };
854
- var getMonthName = (date, locale) => {
855
- return date.toLocaleString(locale, { year: "numeric", month: "long" });
855
+ var getMonthName = (date, locale, options) => {
856
+ return date.toLocaleString(locale, {
857
+ month: "long",
858
+ ...options?.hideYear ? {} : { year: "numeric" }
859
+ });
856
860
  };
857
861
  var getMonthNameFromIndex = (index, locale) => {
858
862
  return new Date(0, index).toLocaleString(locale, { month: "short" });
@@ -4538,7 +4542,6 @@ MenuButton.displayName = "MenuButton";
4538
4542
 
4539
4543
  // src/components/MonthPicker/MonthPicker.tsx
4540
4544
  var import_react33 = __toESM(require("react"));
4541
- var import_react_imask3 = require("react-imask");
4542
4545
  var import_CalendarToday3 = __toESM(require("@mui/icons-material/CalendarToday"));
4543
4546
  var import_joy46 = require("@mui/joy");
4544
4547
  var import_base4 = require("@mui/base");
@@ -4564,60 +4567,35 @@ var MonthPickerRoot = (0, import_joy46.styled)("div", {
4564
4567
  })({
4565
4568
  width: "100%"
4566
4569
  });
4567
- var formatValueString3 = (date, format) => {
4568
- let month = `${date.getMonth() + 1}`;
4569
- const year = date.getFullYear();
4570
- if (Number(month) < 10) month = "0" + month;
4571
- return format.replace(/YYYY/g, year.toString()).replace(/MM/g, month);
4572
- };
4573
- var formatToPattern3 = (format) => {
4574
- return format.replace(/YYYY/g, "Y").replace(/MM/g, "M").replace(/[^YM\s]/g, (match) => `${match}\``);
4570
+ var formatValueString3 = (date, format, locale = "default") => {
4571
+ const year = date.getFullYear().toString();
4572
+ const month = (date.getMonth() + 1).toString().padStart(2, "0");
4573
+ const monthName = getMonthName(date, locale, { hideYear: true });
4574
+ const day = "01";
4575
+ return format.replace(/MMMM/g, monthName).replace(/MM/g, month).replace(/DD/g, day).replace(/YYYY/g, year);
4575
4576
  };
4576
- function parseDate3(dateString) {
4577
+ function parseDate3(dateString, format) {
4578
+ const dateParts = dateString.split(/[-./\s]/);
4579
+ const formatParts = format.split(/[-./\s]/);
4580
+ if (formatParts.length !== dateParts.length) {
4581
+ throw new Error("Invalid date string or format");
4582
+ }
4577
4583
  let month, year;
4578
- const cleanDateString = dateString.replace(/[^\d]/g, "");
4579
- if (dateString.match(/\d{1,2}.\d{4}/)) {
4580
- month = cleanDateString.slice(0, 2);
4581
- year = cleanDateString.slice(2);
4582
- } else if (dateString.match(/\d{4}.\d{1,2}/)) {
4583
- year = cleanDateString.slice(0, 4);
4584
- month = cleanDateString.slice(4);
4584
+ const day = 1;
4585
+ for (let i = 0; i < formatParts.length; i++) {
4586
+ const value = parseInt(dateParts[i], 10);
4587
+ switch (formatParts[i]) {
4588
+ case "MM":
4589
+ month = value - 1;
4590
+ break;
4591
+ case "YYYY":
4592
+ year = value;
4593
+ break;
4594
+ }
4585
4595
  }
4586
- const date = /* @__PURE__ */ new Date(`${year}/${month}`);
4587
- return date;
4596
+ const result = new Date(year, month, day);
4597
+ return result;
4588
4598
  }
4589
- var TextMaskAdapter7 = import_react33.default.forwardRef(
4590
- function TextMaskAdapter8(props, ref) {
4591
- const { onChange, format, ...other } = props;
4592
- return /* @__PURE__ */ import_react33.default.createElement(
4593
- import_react_imask3.IMaskInput,
4594
- {
4595
- ...other,
4596
- inputRef: ref,
4597
- onAccept: (value) => onChange({ target: { name: props.name, value } }),
4598
- mask: Date,
4599
- pattern: formatToPattern3(format),
4600
- blocks: {
4601
- M: {
4602
- mask: import_react_imask3.IMask.MaskedRange,
4603
- from: 1,
4604
- to: 12,
4605
- maxLength: 2
4606
- },
4607
- Y: {
4608
- mask: import_react_imask3.IMask.MaskedRange,
4609
- from: 1900,
4610
- to: 9999
4611
- }
4612
- },
4613
- format: (date) => formatValueString3(date, format),
4614
- parse: parseDate3,
4615
- autofix: "pad",
4616
- overwrite: true
4617
- }
4618
- );
4619
- }
4620
- );
4621
4599
  var MonthPicker = (0, import_react33.forwardRef)(
4622
4600
  (inProps, ref) => {
4623
4601
  const props = (0, import_joy46.useThemeProps)({ props: inProps, name: "MonthPicker" });
@@ -4635,12 +4613,20 @@ var MonthPicker = (0, import_react33.forwardRef)(
4635
4613
  // NOTE: 스타일 관련된 props는 최상위 엘리먼트에 적용한다.
4636
4614
  sx,
4637
4615
  className,
4638
- format = "YYYY/MM",
4616
+ /**
4617
+ * NOTE: 현재 CalendarDate는 YYYY-MM-DD로 개발하고 있어 date를 포함하여 value를 관리한다.
4618
+ * @see https://ecubelabs.atlassian.net/wiki/spaces/SW/pages/1938784349/Date#CalendarDate
4619
+ * @see https://github.com/Ecube-Labs/hds/pull/145
4620
+ */
4621
+ format = "YYYY/MM/DD",
4622
+ displayFormat = "YYYY/MM",
4639
4623
  size,
4624
+ locale,
4640
4625
  ...innerProps
4641
4626
  } = props;
4642
4627
  const innerRef = (0, import_react33.useRef)(null);
4643
- const [value, setValue] = useControlledState(
4628
+ const buttonRef = (0, import_react33.useRef)(null);
4629
+ const [value, setValue, isControlled] = useControlledState(
4644
4630
  props.value,
4645
4631
  props.defaultValue || "",
4646
4632
  (0, import_react33.useCallback)(
@@ -4649,6 +4635,24 @@ var MonthPicker = (0, import_react33.forwardRef)(
4649
4635
  ),
4650
4636
  { disableStrict: true }
4651
4637
  );
4638
+ const getFormattedDisplayValue = (0, import_react33.useCallback)(
4639
+ (inputValue) => {
4640
+ if (!inputValue) return "";
4641
+ try {
4642
+ return formatValueString3(
4643
+ parseDate3(inputValue, format),
4644
+ displayFormat,
4645
+ locale
4646
+ );
4647
+ } catch (e) {
4648
+ return inputValue;
4649
+ }
4650
+ },
4651
+ [format, displayFormat, locale]
4652
+ );
4653
+ const [displayValue, setDisplayValue] = (0, import_react33.useState)(
4654
+ () => getFormattedDisplayValue(value)
4655
+ );
4652
4656
  const [anchorEl, setAnchorEl] = (0, import_react33.useState)(null);
4653
4657
  const open = Boolean(anchorEl);
4654
4658
  (0, import_react33.useEffect)(() => {
@@ -4659,11 +4663,18 @@ var MonthPicker = (0, import_react33.forwardRef)(
4659
4663
  (0, import_react33.useImperativeHandle)(ref, () => innerRef.current, [
4660
4664
  innerRef
4661
4665
  ]);
4666
+ (0, import_react33.useEffect)(() => {
4667
+ setDisplayValue(getFormattedDisplayValue(value));
4668
+ }, [value, getFormattedDisplayValue]);
4662
4669
  const handleChange = (0, import_react33.useCallback)(
4663
4670
  (event) => {
4664
- setValue(event.target.value);
4671
+ const newValue = event.target.value;
4672
+ setValue(newValue);
4673
+ if (!isControlled) {
4674
+ setDisplayValue(getFormattedDisplayValue(newValue));
4675
+ }
4665
4676
  },
4666
- [setValue]
4677
+ [setValue, getFormattedDisplayValue, isControlled]
4667
4678
  );
4668
4679
  const handleCalendarToggle = (0, import_react33.useCallback)(
4669
4680
  (event) => {
@@ -4672,6 +4683,13 @@ var MonthPicker = (0, import_react33.forwardRef)(
4672
4683
  },
4673
4684
  [anchorEl, setAnchorEl, innerRef]
4674
4685
  );
4686
+ const handleInputMouseDown = (0, import_react33.useCallback)(
4687
+ (event) => {
4688
+ event.preventDefault();
4689
+ buttonRef.current?.focus();
4690
+ },
4691
+ [buttonRef]
4692
+ );
4675
4693
  return /* @__PURE__ */ import_react33.default.createElement(MonthPickerRoot, null, /* @__PURE__ */ import_react33.default.createElement(import_base4.FocusTrap, { open: true }, /* @__PURE__ */ import_react33.default.createElement(import_react33.default.Fragment, null, /* @__PURE__ */ import_react33.default.createElement(
4676
4694
  Input_default,
4677
4695
  {
@@ -4679,13 +4697,21 @@ var MonthPicker = (0, import_react33.forwardRef)(
4679
4697
  color: error ? "danger" : innerProps.color,
4680
4698
  ref: innerRef,
4681
4699
  size,
4682
- value,
4683
- onChange: handleChange,
4684
- placeholder: format,
4700
+ value: displayValue,
4701
+ placeholder: displayFormat,
4685
4702
  disabled,
4686
4703
  required,
4687
4704
  slotProps: {
4688
- input: { component: TextMaskAdapter7, ref: innerRef, format }
4705
+ input: {
4706
+ ref: innerRef,
4707
+ format: displayFormat,
4708
+ sx: {
4709
+ "&:hover": {
4710
+ cursor: "default"
4711
+ }
4712
+ },
4713
+ onMouseDown: handleInputMouseDown
4714
+ }
4689
4715
  },
4690
4716
  error,
4691
4717
  className,
@@ -4697,12 +4723,14 @@ var MonthPicker = (0, import_react33.forwardRef)(
4697
4723
  endDecorator: /* @__PURE__ */ import_react33.default.createElement(
4698
4724
  IconButton_default,
4699
4725
  {
4726
+ ref: buttonRef,
4700
4727
  variant: "plain",
4701
4728
  onClick: handleCalendarToggle,
4702
4729
  "aria-label": "Toggle Calendar",
4703
4730
  "aria-controls": "month-picker-popper",
4704
4731
  "aria-haspopup": "dialog",
4705
- "aria-expanded": open
4732
+ "aria-expanded": open,
4733
+ disabled
4706
4734
  },
4707
4735
  /* @__PURE__ */ import_react33.default.createElement(import_CalendarToday3.default, null)
4708
4736
  ),
@@ -4738,7 +4766,7 @@ var MonthPicker = (0, import_react33.forwardRef)(
4738
4766
  handleChange({
4739
4767
  target: {
4740
4768
  name: props.name,
4741
- value: formatValueString3(date, format)
4769
+ value: formatValueString3(date, format, locale)
4742
4770
  }
4743
4771
  });
4744
4772
  setAnchorEl(null);
@@ -4746,7 +4774,8 @@ var MonthPicker = (0, import_react33.forwardRef)(
4746
4774
  minDate: minDate ? new Date(minDate) : void 0,
4747
4775
  maxDate: maxDate ? new Date(maxDate) : void 0,
4748
4776
  disableFuture,
4749
- disablePast
4777
+ disablePast,
4778
+ locale
4750
4779
  }
4751
4780
  ), /* @__PURE__ */ import_react33.default.createElement(
4752
4781
  DialogActions_default,
@@ -4780,7 +4809,7 @@ var MonthPicker = (0, import_react33.forwardRef)(
4780
4809
 
4781
4810
  // src/components/MonthRangePicker/MonthRangePicker.tsx
4782
4811
  var import_react34 = __toESM(require("react"));
4783
- var import_react_imask4 = require("react-imask");
4812
+ var import_react_imask3 = require("react-imask");
4784
4813
  var import_CalendarToday4 = __toESM(require("@mui/icons-material/CalendarToday"));
4785
4814
  var import_joy47 = require("@mui/joy");
4786
4815
  var import_base5 = require("@mui/base");
@@ -4834,29 +4863,29 @@ var parseDates2 = (str) => {
4834
4863
  const date2 = str.split(" - ")[1] || "";
4835
4864
  return [parseDate4(date1), parseDate4(date2)];
4836
4865
  };
4837
- var formatToPattern4 = (format) => {
4866
+ var formatToPattern3 = (format) => {
4838
4867
  return `${format} - ${format}`.replace(/YYYY/g, "Y").replace(/MM/g, "m").replace(/[^YMm\s]/g, (match) => `${match}\``);
4839
4868
  };
4840
- var TextMaskAdapter9 = import_react34.default.forwardRef(
4841
- function TextMaskAdapter10(props, ref) {
4869
+ var TextMaskAdapter7 = import_react34.default.forwardRef(
4870
+ function TextMaskAdapter8(props, ref) {
4842
4871
  const { onChange, format, ...other } = props;
4843
4872
  return /* @__PURE__ */ import_react34.default.createElement(
4844
- import_react_imask4.IMaskInput,
4873
+ import_react_imask3.IMaskInput,
4845
4874
  {
4846
4875
  ...other,
4847
4876
  inputRef: ref,
4848
4877
  onAccept: (value) => onChange({ target: { name: props.name, value } }),
4849
4878
  mask: Date,
4850
- pattern: formatToPattern4(format),
4879
+ pattern: formatToPattern3(format),
4851
4880
  blocks: {
4852
4881
  m: {
4853
- mask: import_react_imask4.IMask.MaskedRange,
4882
+ mask: import_react_imask3.IMask.MaskedRange,
4854
4883
  from: 1,
4855
4884
  to: 12,
4856
4885
  maxLength: 2
4857
4886
  },
4858
4887
  Y: {
4859
- mask: import_react_imask4.IMask.MaskedRange,
4888
+ mask: import_react_imask3.IMask.MaskedRange,
4860
4889
  from: 1900,
4861
4890
  to: 9999
4862
4891
  }
@@ -4948,7 +4977,7 @@ var MonthRangePicker = (0, import_react34.forwardRef)(
4948
4977
  required,
4949
4978
  placeholder: `${format} - ${format}`,
4950
4979
  slotProps: {
4951
- input: { component: TextMaskAdapter9, ref: innerRef, format }
4980
+ input: { component: TextMaskAdapter7, ref: innerRef, format }
4952
4981
  },
4953
4982
  error,
4954
4983
  className,
@@ -5149,8 +5178,8 @@ var padDecimal = (value, decimalScale) => {
5149
5178
  const [integer, decimal = ""] = `${value}`.split(".");
5150
5179
  return Number(`${integer}${decimal.padEnd(decimalScale, "0")}`);
5151
5180
  };
5152
- var TextMaskAdapter11 = import_react38.default.forwardRef(
5153
- function TextMaskAdapter12(props, ref) {
5181
+ var TextMaskAdapter9 = import_react38.default.forwardRef(
5182
+ function TextMaskAdapter10(props, ref) {
5154
5183
  const { onChange, min, max, ...innerProps } = props;
5155
5184
  return /* @__PURE__ */ import_react38.default.createElement(
5156
5185
  import_react_number_format2.NumericFormat,
@@ -5246,7 +5275,7 @@ var PercentageInput = import_react38.default.forwardRef(function PercentageInput
5246
5275
  helperText,
5247
5276
  slotProps: {
5248
5277
  input: {
5249
- component: TextMaskAdapter11,
5278
+ component: TextMaskAdapter9,
5250
5279
  "aria-label": innerProps["aria-label"],
5251
5280
  decimalScale: maxDecimalScale
5252
5281
  }