@zauru-sdk/components 6.19.2 → 6.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,17 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [6.20.0](https://github.com/intuitiva/zauru-typescript-sdk/compare/@zauru-sdk/components@6.19.2...@zauru-sdk/components@6.20.0) (2026-10-31)
7
+
8
+
9
+ ### Features
10
+
11
+ * **components:** permitir rechazar fechas no permitidas en FormDatePicker ([29715e8](https://github.com/intuitiva/zauru-typescript-sdk/commit/29715e89aabaf3099dbc1e396b06baca25db2438))
12
+
13
+
14
+
15
+
16
+
6
17
  ## [6.19.2](https://github.com/intuitiva/zauru-typescript-sdk/compare/@zauru-sdk/components@6.19.1...@zauru-sdk/components@6.19.2) (2026-10-31)
7
18
 
8
19
 
@@ -11,6 +11,8 @@ type Props = {
11
11
  disabled?: boolean;
12
12
  className?: string;
13
13
  required?: boolean;
14
+ isDateAllowed?: (value: string) => boolean;
15
+ onDateRejected?: (value: string) => void;
14
16
  };
15
17
  export declare const FormDatePicker: (props: Props) => import("react/jsx-runtime").JSX.Element;
16
18
  export {};
@@ -3,14 +3,16 @@ import { useEffect, useState } from "react";
3
3
  import { CalendarIconSVG, CloseSvgIcon, IdeaIconSVG } from "@zauru-sdk/icons";
4
4
  import { useFormContext } from "react-hook-form";
5
5
  export const FormDatePicker = (props) => {
6
- const { id, name, title, defaultValue = "", hint, helpText, onChange, tabIndex, disabled = false, className = "", isClearable = false, required = false, } = props;
6
+ const { id, name, title, defaultValue = "", hint, helpText, onChange, tabIndex, disabled = false, className = "", isClearable = false, required = false, isDateAllowed, onDateRejected, } = props;
7
+ const inputId = id ?? name;
7
8
  const [value, setValue] = useState(defaultValue);
9
+ const [rejectNonce, setRejectNonce] = useState(0);
8
10
  const [showTooltip, setShowTooltip] = useState(false);
9
- const { register: tempRegister, formState: { errors }, } = useFormContext() || { formState: {} }; // Obtener el contexto solo si existe
11
+ const { register: tempRegister, formState: { errors }, } = useFormContext() || { formState: {} };
10
12
  const error = errors ? errors[props.name ?? "-1"] : undefined;
11
13
  const register = tempRegister
12
14
  ? tempRegister(props.name ?? "-1", { required })
13
- : undefined; // Solo usar register si está disponible
15
+ : undefined;
14
16
  const color = error ? "red" : "gray";
15
17
  const isReadOnly = disabled;
16
18
  const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
@@ -19,15 +21,24 @@ export const FormDatePicker = (props) => {
19
21
  useEffect(() => {
20
22
  setValue(defaultValue);
21
23
  }, [defaultValue]);
24
+ const commitValue = (next, event) => {
25
+ setValue(next);
26
+ onChange && onChange(next);
27
+ if (event && register) {
28
+ register.onChange(event);
29
+ }
30
+ };
22
31
  const clearValue = () => {
23
- setValue("");
24
- onChange && onChange("");
32
+ commitValue("");
25
33
  };
26
- return (_jsxs("div", { className: showTooltip ? "relative z-50" : "relative", children: [title && (_jsxs("label", { htmlFor: error ? `${name}-error` : `${name}-success`, className: `block text-sm font-medium ${textColor} ${className}`, children: [title, required && _jsx("span", { className: "text-red-500", children: "*" })] })), _jsxs("div", { className: "flex relative items-center", children: [_jsx("div", { className: "absolute left-0 flex items-center pl-3 pointer-events-none", children: _jsx(CalendarIconSVG, {}) }), _jsx("input", { id: id, tabIndex: tabIndex, type: "date", value: value ?? "", pattern: "\\d{4}-\\d{2}-\\d{2}", className: `${bgColor} ${borderColor} ${textColor} text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 p-2.5`, ...(register ?? {}), name: name, onChange: (e) => {
27
- setValue(e.target.value);
28
- onChange && onChange(e.target.value);
29
- if (register) {
30
- register.onChange(e);
34
+ return (_jsxs("div", { className: showTooltip ? "relative z-50" : "relative", children: [title && (_jsxs("label", { htmlFor: inputId, className: `block text-sm font-medium ${textColor} ${className}`, children: [title, required && _jsx("span", { className: "text-red-500", children: "*" })] })), _jsxs("div", { className: "flex relative items-center", children: [_jsx("div", { className: "absolute left-0 flex items-center pl-3 pointer-events-none", children: _jsx(CalendarIconSVG, {}) }), _jsx("input", { id: inputId, tabIndex: tabIndex, type: "date", value: value ?? "", pattern: "\\d{4}-\\d{2}-\\d{2}", className: `${bgColor} ${borderColor} ${textColor} text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 p-2.5`, ...(register ?? {}), name: name, onChange: (e) => {
35
+ const next = e.target.value;
36
+ if (next && isDateAllowed && !isDateAllowed(next)) {
37
+ onDateRejected?.(next);
38
+ e.target.value = value ?? "";
39
+ setRejectNonce((nonce) => nonce + 1);
40
+ return;
31
41
  }
32
- } }), value && isClearable && (_jsx("button", { type: "button", onClick: clearValue, className: "absolute right-0 mr-10", children: _jsx(CloseSvgIcon, {}) })), helpText && (_jsx("div", { className: "flex items-center relative ml-3", children: _jsxs("div", { className: "relative cursor-pointer", onMouseEnter: () => setShowTooltip(true), onMouseLeave: () => setShowTooltip(false), children: [_jsx(IdeaIconSVG, {}), showTooltip && (_jsx("div", { className: "absolute -left-48 top-0 z-50 mt-8 p-2 bg-white border rounded shadow text-black", children: helpText }))] }) }))] }), error && (_jsxs("p", { className: `mt-2 text-sm text-${color}-600 dark:text-${color}-500`, children: [_jsx("span", { className: "font-medium", children: "Oops!" }), " ", error.message?.toString()] })), !error && hint && (_jsx("p", { className: `mt-2 italic text-sm text-${color}-500 dark:text-${color}-400`, children: hint }))] }));
42
+ commitValue(next, e);
43
+ } }, rejectNonce), value && isClearable && (_jsx("button", { type: "button", onClick: clearValue, className: "absolute right-0 mr-10", children: _jsx(CloseSvgIcon, {}) })), helpText && (_jsx("div", { className: "flex items-center relative ml-3", children: _jsxs("div", { className: "relative cursor-pointer", onMouseEnter: () => setShowTooltip(true), onMouseLeave: () => setShowTooltip(false), children: [_jsx(IdeaIconSVG, {}), showTooltip && (_jsx("div", { className: "absolute -left-48 top-0 z-50 mt-8 p-2 bg-white border rounded shadow text-black", children: helpText }))] }) }))] }), error && (_jsxs("p", { className: `mt-2 text-sm text-${color}-600 dark:text-${color}-500`, children: [_jsx("span", { className: "font-medium", children: "Oops!" }), " ", error.message?.toString()] })), !error && hint && (_jsx("p", { className: `mt-2 italic text-sm text-${color}-500 dark:text-${color}-400`, children: hint }))] }));
33
44
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zauru-sdk/components",
3
- "version": "6.19.2",
3
+ "version": "6.20.0",
4
4
  "description": "Componentes reutilizables en las WebApps de Zauru.",
5
5
  "main": "./dist/esm/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -62,5 +62,5 @@
62
62
  "styled-components": "^5.3.5",
63
63
  "zod": "^3.23.8"
64
64
  },
65
- "gitHead": "376b5afd123ab7078d3d92315a09d9a26ed12ea2"
65
+ "gitHead": "9fbc98b91a8ee4adffcdc639608b009e0088cb14"
66
66
  }
@@ -15,6 +15,8 @@ type Props = {
15
15
  disabled?: boolean;
16
16
  className?: string;
17
17
  required?: boolean;
18
+ isDateAllowed?: (value: string) => boolean;
19
+ onDateRejected?: (value: string) => void;
18
20
  };
19
21
 
20
22
  export const FormDatePicker = (props: Props) => {
@@ -31,18 +33,22 @@ export const FormDatePicker = (props: Props) => {
31
33
  className = "",
32
34
  isClearable = false,
33
35
  required = false,
36
+ isDateAllowed,
37
+ onDateRejected,
34
38
  } = props;
35
39
 
40
+ const inputId = id ?? name;
36
41
  const [value, setValue] = useState<string | null>(defaultValue);
42
+ const [rejectNonce, setRejectNonce] = useState(0);
37
43
  const [showTooltip, setShowTooltip] = useState<boolean>(false);
38
44
  const {
39
45
  register: tempRegister,
40
46
  formState: { errors },
41
- } = useFormContext() || { formState: {} }; // Obtener el contexto solo si existe
47
+ } = useFormContext() || { formState: {} };
42
48
  const error = errors ? errors[props.name ?? "-1"] : undefined;
43
49
  const register = tempRegister
44
50
  ? tempRegister(props.name ?? "-1", { required })
45
- : undefined; // Solo usar register si está disponible
51
+ : undefined;
46
52
 
47
53
  const color = error ? "red" : "gray";
48
54
 
@@ -55,16 +61,26 @@ export const FormDatePicker = (props: Props) => {
55
61
  setValue(defaultValue);
56
62
  }, [defaultValue]);
57
63
 
64
+ const commitValue = (
65
+ next: string,
66
+ event?: React.ChangeEvent<HTMLInputElement>,
67
+ ) => {
68
+ setValue(next);
69
+ onChange && onChange(next);
70
+ if (event && register) {
71
+ register.onChange(event);
72
+ }
73
+ };
74
+
58
75
  const clearValue = () => {
59
- setValue("");
60
- onChange && onChange("");
76
+ commitValue("");
61
77
  };
62
78
 
63
79
  return (
64
80
  <div className={showTooltip ? "relative z-50" : "relative"}>
65
81
  {title && (
66
82
  <label
67
- htmlFor={error ? `${name}-error` : `${name}-success`}
83
+ htmlFor={inputId}
68
84
  className={`block text-sm font-medium ${textColor} ${className}`}
69
85
  >
70
86
  {title}
@@ -76,7 +92,8 @@ export const FormDatePicker = (props: Props) => {
76
92
  <CalendarIconSVG />
77
93
  </div>
78
94
  <input
79
- id={id}
95
+ key={rejectNonce}
96
+ id={inputId}
80
97
  tabIndex={tabIndex}
81
98
  type="date"
82
99
  value={value ?? ""}
@@ -85,11 +102,14 @@ export const FormDatePicker = (props: Props) => {
85
102
  {...(register ?? {})}
86
103
  name={name}
87
104
  onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
88
- setValue(e.target.value);
89
- onChange && onChange(e.target.value);
90
- if (register) {
91
- register.onChange(e);
105
+ const next = e.target.value;
106
+ if (next && isDateAllowed && !isDateAllowed(next)) {
107
+ onDateRejected?.(next);
108
+ e.target.value = value ?? "";
109
+ setRejectNonce((nonce) => nonce + 1);
110
+ return;
92
111
  }
112
+ commitValue(next, e);
93
113
  }}
94
114
  ></input>
95
115
  {value && isClearable && (