@octax-app/hot-date-react 0.0.8 → 0.0.9

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/README.md CHANGED
@@ -187,6 +187,25 @@ When `value` is provided the input renders in display mode — showing the forma
187
187
  onClick={(e) => console.log('clicked')}
188
188
  onMouseEnter={(e) => console.log('mouse in')}
189
189
  onMouseLeave={(e) => console.log('mouse out')}
190
+ onError={(err) => console.log(err)} // "Date is outside the allowed range." | undefined
191
+ />
192
+ ```
193
+
194
+ ### Error handling
195
+
196
+ `onError` fires whenever the typed input is invalid — out of range, wrong mode, or unparseable. It fires with `undefined` when the error clears (user types a valid date or empties the field). Only fires when the error state actually changes, not on every keystroke.
197
+
198
+ ```tsx
199
+ <HotDate
200
+ endDate={new Date()} // today is the latest allowed date
201
+ onError={(err) => {
202
+ if (err) setErrorMsg(err); // e.g. "Date is outside the allowed range."
203
+ else setErrorMsg(""); // cleared
204
+ }}
205
+ onChange={(value) => {
206
+ // value is "" when nothing is selected, "YYYY-MM-DD" when valid
207
+ setValue(value as string);
208
+ }}
190
209
  />
191
210
  ```
192
211
 
@@ -196,9 +215,10 @@ When `value` is provided the input renders in display mode — showing the forma
196
215
  | --- | --- | --- | --- |
197
216
  | `value` | `string \| null` | — | Controlled canonical value (`YYYY-MM-DD` or `YYYY-MM-DD/YYYY-MM-DD`). Enters display mode while unfocused. |
198
217
  | `defaultValue` | `string \| null` | — | Uncontrolled initial value. Mounts in display mode; React does not drive updates after mount. |
199
- | `onChange` | `(value: string \| [string, string] \| null) => void` | — | Fires on every valid parse. Range returns `[start, end]`. |
200
- | `onCommit` | `(value: string \| [string, string] \| null) => void` | — | Fires on Enter key commit. |
218
+ | `onChange` | `(value: string \| [string, string]) => void` | — | Fires on every valid parse. Returns `""` when no value. Range returns `[start, end]`. |
219
+ | `onCommit` | `(value: string \| [string, string]) => void` | — | Fires on Enter key commit. Returns `""` when no value. |
201
220
  | `onClear` | `() => void` | — | Fires when input is cleared. |
221
+ | `onError` | `(error: string \| undefined) => void` | — | Fires when input is invalid (out of range, unparseable, wrong mode). Fires `undefined` when the error clears. Only fires on state change, not every keystroke. |
202
222
  | `onFocus` | `(e: FocusEvent) => void` | — | Fires when the input gains focus. |
203
223
  | `onBlur` | `(e: FocusEvent) => void` | — | Fires when the input loses focus. |
204
224
  | `onKeyDown` | `(e: KeyboardEvent) => void` | — | Fires on keydown. |
@@ -58,7 +58,7 @@ function u(e) {
58
58
  return l(e);
59
59
  }
60
60
  function d(e, t) {
61
- if (!e) return null;
61
+ if (!e) return "";
62
62
  if (e.includes("/")) {
63
63
  let [n, r] = e.split("/"), i = t ?? "YYYY-MM-DD";
64
64
  return [s(n, i), s(r, i)];
@@ -71,67 +71,70 @@ typeof customElements < "u" && (customElements.get("hot-date") || customElements
71
71
  function f(e) {
72
72
  if (e !== void 0) return typeof e == "string" ? e : `${e.getFullYear()}-${String(e.getMonth() + 1).padStart(2, "0")}-${String(e.getDate()).padStart(2, "0")}`;
73
73
  }
74
- function p({ value: e, defaultValue: a, onChange: s, onCommit: c, onClear: l, onFocus: p, onBlur: m, onKeyDown: h, onKeyUp: g, onInput: _, onPaste: v, onClick: y, onMouseEnter: b, onMouseLeave: x, onMouseDown: S, onMouseUp: C, onMouseMove: w, format: T, dateType: E = "point", startDate: D, endDate: O, className: k, style: A, placeholder: j, timezone: M, locale: N, weekStart: P, disabled: F, required: I, name: L, showHint: R, error: z, success: B, classNames: V }) {
75
- let H = n(null), [U, W] = r(!!e), [G, K] = r(!1), q = R ?? !0;
74
+ function p({ value: e, defaultValue: a, onChange: s, onCommit: c, onClear: l, onError: p, onFocus: m, onBlur: h, onKeyDown: g, onKeyUp: _, onInput: v, onPaste: y, onClick: b, onMouseEnter: x, onMouseLeave: S, onMouseDown: C, onMouseUp: w, onMouseMove: T, format: E, dateType: D = "point", startDate: O, endDate: k, className: A, style: j, placeholder: M, timezone: N, locale: P, weekStart: F, disabled: I, required: L, name: R, showHint: z, error: B, success: V, classNames: H }) {
75
+ let U = n(null), [W, G] = r(!!e), [K, q] = r(!1), J = n(void 0), Y = z ?? !0;
76
76
  t(() => {
77
- let e = H.current;
77
+ let e = U.current;
78
78
  if (!e) return;
79
79
  let t = (t, n) => {
80
80
  n ? e.setAttribute(t, "") : e.removeAttribute(t);
81
81
  }, n = (t, n) => {
82
82
  n == null ? e.removeAttribute(t) : e.setAttribute(t, n);
83
83
  };
84
- n("placeholder", j), n("timezone", M), n("locale", N), n("week-start", P), n("start-date", f(D)), n("end-date", f(O)), n("mode", E), n("format", T), t("disabled", !!F), t("required", !!I), t("hide-hint", !q), n("name", L);
84
+ n("placeholder", M), n("timezone", N), n("locale", P), n("week-start", F), n("start-date", f(O)), n("end-date", f(k)), n("mode", D), n("format", E), t("disabled", !!I), t("required", !!L), t("hide-hint", !Y), n("name", R);
85
85
  }, [
86
- j,
87
86
  M,
88
87
  N,
89
88
  P,
90
- D,
89
+ F,
91
90
  O,
91
+ k,
92
+ D,
92
93
  E,
93
- T,
94
- F,
95
94
  I,
96
95
  L,
97
- q
96
+ R,
97
+ Y
98
98
  ]);
99
- let J = n(a);
99
+ let X = n(a);
100
100
  return t(() => {
101
- let e = H.current, t = J.current;
101
+ let e = U.current, t = X.current;
102
102
  if (!e || t == null) return;
103
- let n = T ? o(t, T) ?? t : t;
104
- e.value = n, W(!!n), n && (e.setAttribute("display-value", u(n)), e.forceDisplayMode?.(n));
103
+ let n = E ? o(t, E) ?? t : t;
104
+ e.value = n, G(!!n), n && (e.setAttribute("display-value", u(n)), e.forceDisplayMode?.(n));
105
105
  }, []), t(() => {
106
- let t = H.current;
106
+ let t = U.current;
107
107
  if (!t || e === void 0) return;
108
- let n = e ? T ? o(e, T) ?? e : e : null;
109
- t.value = n, W(!!n), n ? (t.setAttribute("display-value", u(n)), G || t.forceDisplayMode?.(n)) : (t.removeAttribute("display-value"), G || t.forceDisplayMode?.(null));
108
+ let n = e ? E ? o(e, E) ?? e : e : null;
109
+ t.value = n, G(!!n), n ? (t.setAttribute("display-value", u(n)), K || t.forceDisplayMode?.(n)) : (t.removeAttribute("display-value"), K || t.forceDisplayMode?.(null));
110
110
  }, [
111
111
  e,
112
- T,
113
- G
112
+ E,
113
+ K
114
114
  ]), t(() => {
115
- let e = H.current;
115
+ let e = U.current;
116
116
  if (!e) return;
117
117
  let t = e.shadowRoot?.querySelector("input") ?? null, n = (e) => {
118
118
  let t = e.detail;
119
- W(!!t.value), s?.(d(t.value, T));
119
+ G(!!t.value), s?.(d(t.value, E));
120
120
  }, r = (e) => {
121
121
  let t = e.detail;
122
- c?.(d(t.value, T));
122
+ c?.(d(t.value, E));
123
123
  }, i = () => {
124
- W(!1), l?.();
124
+ G(!1), l?.();
125
125
  }, a = (e) => {
126
- K(!0), p?.(e);
126
+ q(!0), m?.(e);
127
127
  }, o = (e) => {
128
- K(!1), m?.(e);
129
- }, u = (e) => h?.(e), f = (e) => g?.(e), E = (e) => {
128
+ q(!1), h?.(e);
129
+ }, u = (e) => g?.(e), f = (e) => _?.(e), D = (e) => {
130
130
  let t = e.detail;
131
- _?.(t.rawInput);
132
- }, D = (e) => v?.(e), O = (e) => y?.(e), k = (e) => b?.(e), A = (e) => x?.(e), j = (e) => S?.(e), M = (e) => C?.(e), N = (e) => w?.(e);
133
- return e.addEventListener("value-change", n), e.addEventListener("value-commit", r), e.addEventListener("clear", i), e.addEventListener("focusin", a), e.addEventListener("focusout", o), e.addEventListener("raw-input-change", E), e.addEventListener("click", O), e.addEventListener("mouseenter", k), e.addEventListener("mouseleave", A), e.addEventListener("mousedown", j), e.addEventListener("mouseup", M), e.addEventListener("mousemove", N), t?.addEventListener("keydown", u), t?.addEventListener("keyup", f), t?.addEventListener("paste", D), () => {
134
- e.removeEventListener("value-change", n), e.removeEventListener("value-commit", r), e.removeEventListener("clear", i), e.removeEventListener("focusin", a), e.removeEventListener("focusout", o), e.removeEventListener("raw-input-change", E), e.removeEventListener("click", O), e.removeEventListener("mouseenter", k), e.removeEventListener("mouseleave", A), e.removeEventListener("mousedown", j), e.removeEventListener("mouseup", M), e.removeEventListener("mousemove", N), t?.removeEventListener("keydown", u), t?.removeEventListener("keyup", f), t?.removeEventListener("paste", D);
131
+ v?.(t.rawInput);
132
+ }, O = (e) => {
133
+ let { status: t, parseResult: n } = e.detail, r = t === "invalid" && n.rawInput ? n.errors[0] ?? "Invalid date" : void 0;
134
+ r !== J.current && (J.current = r, p?.(r));
135
+ }, k = (e) => y?.(e), A = (e) => b?.(e), j = (e) => x?.(e), M = (e) => S?.(e), N = (e) => C?.(e), P = (e) => w?.(e), F = (e) => T?.(e);
136
+ return e.addEventListener("value-change", n), e.addEventListener("value-commit", r), e.addEventListener("clear", i), e.addEventListener("focusin", a), e.addEventListener("focusout", o), e.addEventListener("raw-input-change", D), e.addEventListener("parse-change", O), e.addEventListener("click", A), e.addEventListener("mouseenter", j), e.addEventListener("mouseleave", M), e.addEventListener("mousedown", N), e.addEventListener("mouseup", P), e.addEventListener("mousemove", F), t?.addEventListener("keydown", u), t?.addEventListener("keyup", f), t?.addEventListener("paste", k), () => {
137
+ e.removeEventListener("value-change", n), e.removeEventListener("value-commit", r), e.removeEventListener("clear", i), e.removeEventListener("focusin", a), e.removeEventListener("focusout", o), e.removeEventListener("raw-input-change", D), e.removeEventListener("parse-change", O), e.removeEventListener("click", A), e.removeEventListener("mouseenter", j), e.removeEventListener("mouseleave", M), e.removeEventListener("mousedown", N), e.removeEventListener("mouseup", P), e.removeEventListener("mousemove", F), t?.removeEventListener("keydown", u), t?.removeEventListener("keyup", f), t?.removeEventListener("paste", k);
135
138
  };
136
139
  }, [
137
140
  s,
@@ -149,32 +152,33 @@ function p({ value: e, defaultValue: a, onChange: s, onCommit: c, onClear: l, on
149
152
  S,
150
153
  C,
151
154
  w,
152
- T
155
+ T,
156
+ E
153
157
  ]), t(() => {
154
- let e = H.current;
158
+ let e = U.current;
155
159
  if (!e) return;
156
160
  let t = (e) => e ? typeof e == "function" ? e({
157
- active: U,
158
- disabled: !!F,
159
- focused: G,
160
- error: !!z,
161
- success: !!B
161
+ active: W,
162
+ disabled: !!I,
163
+ focused: K,
164
+ error: !!B,
165
+ success: !!V
162
166
  }) : e : null, n = (n, r) => {
163
167
  let i = t(r);
164
168
  i ? e.setAttribute(n, i) : e.removeAttribute(n);
165
169
  };
166
- n("part-class-input", V?.input), n("part-class-ghost", V?.ghost), n("part-class-hint", V?.hint);
170
+ n("part-class-input", H?.input), n("part-class-ghost", H?.ghost), n("part-class-hint", H?.hint);
167
171
  }, [
168
- V,
169
- U,
170
- G,
171
- F,
172
- z,
173
- B
172
+ H,
173
+ W,
174
+ K,
175
+ I,
176
+ B,
177
+ V
174
178
  ]), /* @__PURE__ */ i("hot-date", {
175
- ref: H,
176
- class: k,
177
- style: A
179
+ ref: U,
180
+ class: A,
181
+ style: j
178
182
  });
179
183
  }
180
184
  //#endregion
@@ -15,9 +15,10 @@ type WEEK_START_MAP = 'sunday' | 'monday' | 'tuesday' | 'wednesday' | 'thursday'
15
15
  export interface HotDateProps {
16
16
  value?: string | null;
17
17
  defaultValue?: string | null;
18
- onChange?: (value: string | [string, string] | null) => void;
19
- onCommit?: (value: string | [string, string] | null) => void;
18
+ onChange?: (value: string | [string, string]) => void;
19
+ onCommit?: (value: string | [string, string]) => void;
20
20
  onClear?: () => void;
21
+ onError?: (error: string | undefined) => void;
21
22
  onFocus?: (e: FocusEvent) => void;
22
23
  onBlur?: (e: FocusEvent) => void;
23
24
  onKeyDown?: (e: KeyboardEvent) => void;
@@ -76,5 +77,5 @@ declare module "react" {
76
77
  }
77
78
  }
78
79
  }
79
- export declare function HotDate({ value, defaultValue, onChange, onCommit, onClear, onFocus, onBlur, onKeyDown, onKeyUp, onInput, onPaste, onClick, onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onMouseMove, format, dateType, startDate, endDate, className, style, placeholder, timezone, locale, weekStart, disabled, required, name, showHint, error, success, classNames, }: HotDateProps): import("react/jsx-runtime").JSX.Element;
80
+ export declare function HotDate({ value, defaultValue, onChange, onCommit, onClear, onError, onFocus, onBlur, onKeyDown, onKeyUp, onInput, onPaste, onClick, onMouseEnter, onMouseLeave, onMouseDown, onMouseUp, onMouseMove, format, dateType, startDate, endDate, className, style, placeholder, timezone, locale, weekStart, disabled, required, name, showHint, error, success, classNames, }: HotDateProps): import("react/jsx-runtime").JSX.Element;
80
81
  export {};
@@ -1,3 +1,3 @@
1
1
  export declare function parseFormatToIso(formatted: string, format: string): string | null;
2
2
  export declare function formatDisplayValue(canonical: string | null): string;
3
- export declare function applyFormat(canonical: string | null, format?: string): string | [string, string] | null;
3
+ export declare function applyFormat(canonical: string | null, format?: string): string | [string, string];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@octax-app/hot-date-react",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "React wrapper for the hot-date natural language date input web component.",
5
5
  "type": "module",
6
6
  "main": "./dist/hot-date-react.js",