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

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
@@ -162,16 +162,55 @@ const [date, setDate] = useState<string | null>(null);
162
162
  />
163
163
  ```
164
164
 
165
- When a `value` is set, it appears as a human-readable label on the right side of the input (the ghost resolution area). The text field stays empty for natural typing. On blur, the field shows the formatted value; on focus, it restores the raw input.
165
+ When `value` is provided the input renders in display mode showing the formatted date while unfocused. Clicking into it restores the natural-language input for editing. On blur it returns to display mode automatically.
166
+
167
+ ### Uncontrolled with a default value
168
+
169
+ ```tsx
170
+ <HotDate
171
+ defaultValue="2026-06-13"
172
+ onChange={(v) => console.log(v)}
173
+ />
174
+ ```
175
+
176
+ `defaultValue` sets the initial value on mount and immediately enters display mode, but the component is uncontrolled after that — React does not drive subsequent updates.
177
+
178
+ ### Event callbacks
179
+
180
+ ```tsx
181
+ <HotDate
182
+ onFocus={(e) => console.log('focused', e)}
183
+ onBlur={(e) => console.log('blurred', e)}
184
+ onKeyDown={(e) => console.log('key', e.key)}
185
+ onInput={(rawValue) => console.log('typing', rawValue)}
186
+ onPaste={(e) => console.log('pasted')}
187
+ onClick={(e) => console.log('clicked')}
188
+ onMouseEnter={(e) => console.log('mouse in')}
189
+ onMouseLeave={(e) => console.log('mouse out')}
190
+ />
191
+ ```
166
192
 
167
193
  ## Props
168
194
 
169
195
  | Prop | Type | Default | Description |
170
196
  | --- | --- | --- | --- |
171
- | `value` | `string \| null` | — | Controlled canonical value (`YYYY-MM-DD` or `YYYY-MM-DD/YYYY-MM-DD`) |
197
+ | `value` | `string \| null` | — | Controlled canonical value (`YYYY-MM-DD` or `YYYY-MM-DD/YYYY-MM-DD`). Enters display mode while unfocused. |
198
+ | `defaultValue` | `string \| null` | — | Uncontrolled initial value. Mounts in display mode; React does not drive updates after mount. |
172
199
  | `onChange` | `(value: string \| [string, string] \| null) => void` | — | Fires on every valid parse. Range returns `[start, end]`. |
173
200
  | `onCommit` | `(value: string \| [string, string] \| null) => void` | — | Fires on Enter key commit. |
174
201
  | `onClear` | `() => void` | — | Fires when input is cleared. |
202
+ | `onFocus` | `(e: FocusEvent) => void` | — | Fires when the input gains focus. |
203
+ | `onBlur` | `(e: FocusEvent) => void` | — | Fires when the input loses focus. |
204
+ | `onKeyDown` | `(e: KeyboardEvent) => void` | — | Fires on keydown. |
205
+ | `onKeyUp` | `(e: KeyboardEvent) => void` | — | Fires on keyup. |
206
+ | `onInput` | `(rawValue: string) => void` | — | Fires on every keystroke with the raw typed string. |
207
+ | `onPaste` | `(e: ClipboardEvent) => void` | — | Fires when content is pasted into the input. |
208
+ | `onClick` | `(e: MouseEvent) => void` | — | Fires on click. |
209
+ | `onMouseEnter` | `(e: MouseEvent) => void` | — | Fires when the mouse enters the component. |
210
+ | `onMouseLeave` | `(e: MouseEvent) => void` | — | Fires when the mouse leaves the component. |
211
+ | `onMouseDown` | `(e: MouseEvent) => void` | — | Fires on mousedown. |
212
+ | `onMouseUp` | `(e: MouseEvent) => void` | — | Fires on mouseup. |
213
+ | `onMouseMove` | `(e: MouseEvent) => void` | — | Fires on mousemove. |
175
214
  | `format` | `string` | `"YYYY-MM-DD"` | Output format. Tokens: `YYYY MM DD YY M D` (case-insensitive). |
176
215
  | `dateType` | `"point" \| "range"` | `"point"` | Restrict input to single date or range. |
177
216
  | `startDate` | `Date \| string` | — | Minimum date. Accepts a JS `Date` or `"YYYY-MM-DD"` string. |
@@ -78,7 +78,7 @@ function y(e) {
78
78
  return /^\d+$/.test(t) ? Number(t) : l[t] ?? null;
79
79
  }
80
80
  //#endregion
81
- //#region node_modules/.pnpm/@js-temporal+polyfill@0.4.4/node_modules/@js-temporal/polyfill/dist/index.esm.js
81
+ //#region node_modules/@js-temporal/polyfill/dist/index.esm.js
82
82
  var b = /* @__PURE__ */ c((/* @__PURE__ */ o(((e, t) => {
83
83
  (function(n, r) {
84
84
  typeof e == "object" && t !== void 0 ? t.exports = r() : typeof define == "function" && define.amd ? define(r) : (n ||= self, n.JSBI = r());
@@ -8805,6 +8805,7 @@ var Gc = class extends HTMLElement {
8805
8805
  parser = new Pc();
8806
8806
  internals;
8807
8807
  styleObserver = null;
8808
+ fieldElement;
8808
8809
  inputElement;
8809
8810
  ghostElement;
8810
8811
  ghostTypedElement;
@@ -8822,12 +8823,15 @@ var Gc = class extends HTMLElement {
8822
8823
  super(), this.attachShadow({ mode: "open" }), this.shadowRoot?.append(Wc().content.cloneNode(!0));
8823
8824
  let e = this.shadowRoot;
8824
8825
  if (!e) throw Error("Unable to create shadow root.");
8825
- this.inputElement = e.querySelector("input") ?? document.createElement("input"), this.ghostElement = e.querySelector(".ghost") ?? document.createElement("div"), this.ghostTypedElement = e.querySelector(".ghost-typed") ?? document.createElement("span"), this.ghostTailElement = e.querySelector(".ghost-tail") ?? document.createElement("span"), this.ghostHintElement = e.querySelector(".ghost-hint") ?? document.createElement("kbd"), this.ghostResolutionElement = e.querySelector(".ghost-resolution") ?? document.createElement("span"), this.ambiguityElement = document.createElement("div"), this.ambiguityElement.setAttribute("slot", "ambiguity"), this.ambiguityElement.hidden = !0, this.internals = typeof this.attachInternals == "function" ? this.attachInternals() : null, this.bindEvents();
8826
+ this.fieldElement = e.querySelector(".field") ?? document.createElement("div"), this.inputElement = e.querySelector("input") ?? document.createElement("input"), this.ghostElement = e.querySelector(".ghost") ?? document.createElement("div"), this.ghostTypedElement = e.querySelector(".ghost-typed") ?? document.createElement("span"), this.ghostTailElement = e.querySelector(".ghost-tail") ?? document.createElement("span"), this.ghostHintElement = e.querySelector(".ghost-hint") ?? document.createElement("kbd"), this.ghostResolutionElement = e.querySelector(".ghost-resolution") ?? document.createElement("span"), this.ambiguityElement = document.createElement("div"), this.ambiguityElement.setAttribute("slot", "ambiguity"), this.ambiguityElement.hidden = !0, this.internals = typeof this.attachInternals == "function" ? this.attachInternals() : null, this.bindEvents();
8826
8827
  }
8827
8828
  connectedCallback() {
8828
8829
  this.ambiguityElement.parentNode !== this && this.append(this.ambiguityElement), this.updateStyles(), this.syncExternalStyles(), this.updateHintVisibility(), this.syncInputPresentation(), this.parseAndRender(), this.styleObserver || (this.styleObserver = new MutationObserver(() => this.syncExternalStyles()), this.styleObserver.observe(document.head, {
8829
8830
  childList: !0,
8830
8831
  subtree: !0
8832
+ }), this.styleObserver.observe(document.documentElement, {
8833
+ attributes: !0,
8834
+ attributeFilter: ["class"]
8831
8835
  }));
8832
8836
  }
8833
8837
  disconnectedCallback() {
@@ -8911,6 +8915,9 @@ var Gc = class extends HTMLElement {
8911
8915
  focus() {
8912
8916
  this.inputElement.focus();
8913
8917
  }
8918
+ forceDisplayMode(e) {
8919
+ e ? (this.isDisplayMode = !0, this.inputElement.value = this.formatValue(e), this.ghostElement.hidden = !0) : (this.isDisplayMode = !1, this.inputElement.value = this.rawInputValue, this.ghostElement.hidden = !1, this.renderGhost());
8920
+ }
8914
8921
  clear() {
8915
8922
  this.isDisplayMode = !1, this.ghostElement.hidden = !1, this.rawInputValue = "", this.committedValue = null, this.removeAttribute("value"), this.internals?.setFormValue(""), this.activeSuggestionIndexValue = 0, this.syncInputPresentation(), this.parseAndRender(), this.emit("clear", {});
8916
8923
  }
@@ -8973,26 +8980,28 @@ var Gc = class extends HTMLElement {
8973
8980
  }
8974
8981
  syncExternalStyles() {
8975
8982
  if (!this.shadowRoot) return;
8983
+ let e = Array.from(document.documentElement.classList);
8984
+ this.fieldElement.className = "field" + (e.length ? " " + e.join(" ") : "");
8976
8985
  try {
8977
8986
  document.adoptedStyleSheets.length > 0 && (this.shadowRoot.adoptedStyleSheets = [...document.adoptedStyleSheets]);
8978
8987
  } catch {}
8979
- let e = new Set(Array.from(this.shadowRoot.querySelectorAll("link[data-ext]")).map((e) => e.href));
8980
- document.querySelectorAll("link[rel=\"stylesheet\"]").forEach((t) => {
8981
- if (!e.has(t.href)) {
8982
- let e = document.createElement("link");
8983
- e.rel = "stylesheet", e.href = t.href, e.dataset.ext = "", this.shadowRoot.append(e);
8988
+ let t = new Set(Array.from(this.shadowRoot.querySelectorAll("link[data-ext]")).map((e) => e.href));
8989
+ document.querySelectorAll("link[rel=\"stylesheet\"]").forEach((e) => {
8990
+ if (!t.has(e.href)) {
8991
+ let t = document.createElement("link");
8992
+ t.rel = "stylesheet", t.href = e.href, t.dataset.ext = "", this.shadowRoot.append(t);
8984
8993
  }
8985
8994
  });
8986
- let t = Array.from(document.head.querySelectorAll("style")), n = Array.from(this.shadowRoot.querySelectorAll("style[data-ext-style]"));
8987
- t.forEach((e, t) => {
8988
- let r = e.textContent ?? "";
8989
- if (n[t]) n[t].textContent !== r && (n[t].textContent = r);
8995
+ let n = Array.from(document.head.querySelectorAll("style")), r = Array.from(this.shadowRoot.querySelectorAll("style[data-ext-style]"));
8996
+ n.forEach((e, t) => {
8997
+ let n = e.textContent ?? "";
8998
+ if (r[t]) r[t].textContent !== n && (r[t].textContent = n);
8990
8999
  else {
8991
9000
  let e = document.createElement("style");
8992
- e.dataset.extStyle = "", e.textContent = r, this.shadowRoot.append(e);
9001
+ e.dataset.extStyle = "", e.textContent = n, this.shadowRoot.append(e);
8993
9002
  }
8994
9003
  });
8995
- for (let e = t.length; e < n.length; e++) n[e].remove();
9004
+ for (let e = n.length; e < r.length; e++) r[e].remove();
8996
9005
  requestAnimationFrame(() => {
8997
9006
  let e = window.getComputedStyle(this.inputElement);
8998
9007
  this.ghostElement.style.font = e.font;
@@ -1,4 +1,4 @@
1
- import { t as e } from "./hot-date-CE4exKZT.js";
1
+ import { t as e } from "./hot-date-DIgUxVss.js";
2
2
  import { useEffect as t, useRef as n, useState as r } from "react";
3
3
  import { jsx as i } from "react/jsx-runtime";
4
4
  //#region src/react/format.ts
@@ -71,80 +71,110 @@ 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, onChange: a, onCommit: s, onClear: c, format: l, dateType: p = "point", startDate: m, endDate: h, className: g, style: _, placeholder: v, timezone: y, locale: b, weekStart: x, disabled: S, required: C, name: w, showHint: T, error: E, success: D, classNames: O }) {
75
- let k = n(null), [A, j] = r(!!e), [M, N] = r(!1), P = T ?? !0;
76
- return t(() => {
77
- let e = k.current;
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;
76
+ t(() => {
77
+ let e = H.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", v), n("timezone", y), n("locale", b), n("week-start", x), n("start-date", f(m)), n("end-date", f(h)), n("mode", p), n("format", l), t("disabled", !!S), t("required", !!C), t("hide-hint", !P), n("name", w);
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);
85
85
  }, [
86
- v,
87
- y,
88
- b,
89
- x,
90
- m,
91
- h,
92
- p,
93
- l,
94
- S,
95
- C,
96
- w,
97
- P
98
- ]), t(() => {
99
- let t = k.current;
86
+ j,
87
+ M,
88
+ N,
89
+ P,
90
+ D,
91
+ O,
92
+ E,
93
+ T,
94
+ F,
95
+ I,
96
+ L,
97
+ q
98
+ ]);
99
+ let J = n(a);
100
+ return t(() => {
101
+ let e = H.current, t = J.current;
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));
105
+ }, []), t(() => {
106
+ let t = H.current;
100
107
  if (!t || e === void 0) return;
101
- let n = e ? l ? o(e, l) ?? e : e : null;
102
- t.value = n, j(!!n), n ? t.setAttribute("display-value", u(n)) : t.removeAttribute("display-value");
103
- }, [e, l]), t(() => {
104
- let e = k.current;
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));
110
+ }, [
111
+ e,
112
+ T,
113
+ G
114
+ ]), t(() => {
115
+ let e = H.current;
105
116
  if (!e) return;
106
- let t = (e) => {
117
+ let t = e.shadowRoot?.querySelector("input") ?? null, n = (e) => {
118
+ let t = e.detail;
119
+ W(!!t.value), s?.(d(t.value, T));
120
+ }, r = (e) => {
107
121
  let t = e.detail;
108
- j(!!t.value), a?.(d(t.value, l));
109
- }, n = (e) => {
122
+ c?.(d(t.value, T));
123
+ }, i = () => {
124
+ W(!1), l?.();
125
+ }, a = (e) => {
126
+ K(!0), p?.(e);
127
+ }, o = (e) => {
128
+ K(!1), m?.(e);
129
+ }, u = (e) => h?.(e), f = (e) => g?.(e), E = (e) => {
110
130
  let t = e.detail;
111
- s?.(d(t.value, l));
112
- }, r = () => {
113
- j(!1), c?.();
114
- }, i = () => N(!0), o = () => N(!1);
115
- return e.addEventListener("value-change", t), e.addEventListener("value-commit", n), e.addEventListener("clear", r), e.addEventListener("focusin", i), e.addEventListener("focusout", o), () => {
116
- e.removeEventListener("value-change", t), e.removeEventListener("value-commit", n), e.removeEventListener("clear", r), e.removeEventListener("focusin", i), e.removeEventListener("focusout", o);
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);
117
135
  };
118
136
  }, [
119
- a,
120
137
  s,
121
138
  c,
122
- l
139
+ l,
140
+ p,
141
+ m,
142
+ h,
143
+ g,
144
+ _,
145
+ v,
146
+ y,
147
+ b,
148
+ x,
149
+ S,
150
+ C,
151
+ w,
152
+ T
123
153
  ]), t(() => {
124
- let e = k.current;
154
+ let e = H.current;
125
155
  if (!e) return;
126
156
  let t = (e) => e ? typeof e == "function" ? e({
127
- active: A,
128
- disabled: !!S,
129
- focused: M,
130
- error: !!E,
131
- success: !!D
157
+ active: U,
158
+ disabled: !!F,
159
+ focused: G,
160
+ error: !!z,
161
+ success: !!B
132
162
  }) : e : null, n = (n, r) => {
133
163
  let i = t(r);
134
164
  i ? e.setAttribute(n, i) : e.removeAttribute(n);
135
165
  };
136
- n("part-class-input", O?.input), n("part-class-ghost", O?.ghost), n("part-class-hint", O?.hint);
166
+ n("part-class-input", V?.input), n("part-class-ghost", V?.ghost), n("part-class-hint", V?.hint);
137
167
  }, [
138
- O,
139
- A,
140
- M,
141
- S,
142
- E,
143
- D
168
+ V,
169
+ U,
170
+ G,
171
+ F,
172
+ z,
173
+ B
144
174
  ]), /* @__PURE__ */ i("hot-date", {
145
- ref: k,
146
- class: g,
147
- style: _
175
+ ref: H,
176
+ class: k,
177
+ style: A
148
178
  });
149
179
  }
150
180
  //#endregion
@@ -5,6 +5,7 @@ export declare class HotDateElement extends HTMLElement {
5
5
  private readonly parser;
6
6
  private readonly internals;
7
7
  private styleObserver;
8
+ private readonly fieldElement;
8
9
  private readonly inputElement;
9
10
  private readonly ghostElement;
10
11
  private readonly ghostTypedElement;
@@ -33,6 +34,7 @@ export declare class HotDateElement extends HTMLElement {
33
34
  get suggestions(): CompletionSuggestion[];
34
35
  get activeSuggestionIndex(): number;
35
36
  focus(): void;
37
+ forceDisplayMode(canonical: string | null): void;
36
38
  clear(): void;
37
39
  confirm(): boolean;
38
40
  acceptSuggestion(index?: number): boolean;
package/dist/hot-date.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as e } from "./hot-date-CE4exKZT.js";
1
+ import { t as e } from "./hot-date-DIgUxVss.js";
2
2
  export { e as HotDateElement };
@@ -14,9 +14,22 @@ export interface ClassNamesConfig {
14
14
  type WEEK_START_MAP = 'sunday' | 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday';
15
15
  export interface HotDateProps {
16
16
  value?: string | null;
17
+ defaultValue?: string | null;
17
18
  onChange?: (value: string | [string, string] | null) => void;
18
19
  onCommit?: (value: string | [string, string] | null) => void;
19
20
  onClear?: () => void;
21
+ onFocus?: (e: FocusEvent) => void;
22
+ onBlur?: (e: FocusEvent) => void;
23
+ onKeyDown?: (e: KeyboardEvent) => void;
24
+ onKeyUp?: (e: KeyboardEvent) => void;
25
+ onInput?: (rawValue: string) => void;
26
+ onPaste?: (e: ClipboardEvent) => void;
27
+ onClick?: (e: MouseEvent) => void;
28
+ onMouseEnter?: (e: MouseEvent) => void;
29
+ onMouseLeave?: (e: MouseEvent) => void;
30
+ onMouseDown?: (e: MouseEvent) => void;
31
+ onMouseUp?: (e: MouseEvent) => void;
32
+ onMouseMove?: (e: MouseEvent) => void;
20
33
  format?: string;
21
34
  dateType?: "point" | "range";
22
35
  startDate?: Date | string;
@@ -63,5 +76,5 @@ declare module "react" {
63
76
  }
64
77
  }
65
78
  }
66
- export declare function HotDate({ value, onChange, onCommit, onClear, format, dateType, startDate, endDate, className, style, placeholder, timezone, locale, weekStart, disabled, required, name, showHint, error, success, classNames, }: HotDateProps): import("react/jsx-runtime").JSX.Element;
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;
67
80
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@octax-app/hot-date-react",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
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",