@octax-app/hot-date-react 0.0.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.
package/README.md ADDED
@@ -0,0 +1,246 @@
1
+ # hot-date-react
2
+
3
+ React wrapper for [**@stolinski/hot-date**](https://github.com/stolinski/hot-date) — a natural language date input web component. Type anything: "next friday", "tomorrow to after tomorrow", "between jan 1 and feb 28", and get a clean ISO date back.
4
+
5
+ ## Demo
6
+
7
+ **[Live demo →](https://packages.octax.cloud/hot-date-react)**
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @octax-app/hot-date-react
13
+ ```
14
+
15
+ > **Peer dependencies:** React ≥ 18
16
+
17
+ ## Quick Start
18
+
19
+ ```tsx
20
+ import { HotDate } from '@octax-app/hot-date-react/react';
21
+
22
+ function MyForm() {
23
+ return (
24
+ <HotDate
25
+ placeholder="e.g. next friday, tomorrow"
26
+ onChange={(value) => console.log(value)}
27
+ />
28
+ );
29
+ }
30
+ ```
31
+
32
+ ## Usage Examples
33
+
34
+ ### Point date (default)
35
+
36
+ ```tsx
37
+ <HotDate
38
+ dateType="point"
39
+ onChange={(value) => console.log(value)}
40
+ // value: "2026-06-13"
41
+ />
42
+ ```
43
+
44
+ ### Range picker
45
+
46
+ ```tsx
47
+ <HotDate
48
+ dateType="range"
49
+ onChange={(value) => console.log(value)}
50
+ // value: ["2026-06-01", "2026-06-30"]
51
+ />
52
+ ```
53
+
54
+ ### Custom output format
55
+
56
+ ```tsx
57
+ <HotDate
58
+ format="MM/DD/YYYY"
59
+ onChange={(value) => console.log(value)}
60
+ // value: "06/13/2026"
61
+ />
62
+ ```
63
+
64
+ Tokens are case-insensitive: `YYYY`/`yyyy`, `MM`/`mm`, `DD`/`dd`, `YY`/`yy`, `M`/`m`, `D`/`d`.
65
+
66
+ For ranges, `onChange` returns `[formattedStart, formattedEnd]`.
67
+
68
+ When the input loses focus after a value is committed, the field displays the formatted value. When focused again, it restores the raw natural-language input for editing.
69
+
70
+ ### Date constraints
71
+
72
+ Both `Date` objects and `"YYYY-MM-DD"` strings are accepted. The output value is always a string.
73
+
74
+ ```tsx
75
+ // Using JS Date objects
76
+ <HotDate
77
+ startDate={new Date()}
78
+ endDate={new Date(Date.now() + 30 * 86400000)}
79
+ onChange={(value) => console.log(value)} // value: "2026-06-13" (string)
80
+ />
81
+
82
+ // Using ISO strings
83
+ <HotDate
84
+ startDate="2026-01-01"
85
+ endDate="2026-12-31"
86
+ onChange={(value) => console.log(value)}
87
+ />
88
+ ```
89
+
90
+ Dates outside the `startDate`/`endDate` window are rejected at the parser level.
91
+
92
+ ### Bring your own CSS
93
+
94
+ The component renders as a plain browser input by default — no decorative styles are applied. Use `className` and `::part()` to style it, or pass Tailwind classes via `classNames`.
95
+
96
+ ```tsx
97
+ <HotDate className="my-picker" />
98
+ ```
99
+
100
+ ```css
101
+ /* Use ::part() to style shadow DOM elements */
102
+ .my-picker::part(input) {
103
+ border: 2px solid #6366f1;
104
+ border-radius: 8px;
105
+ padding: 0.5rem 0.75rem;
106
+ font-family: monospace;
107
+ }
108
+ .my-picker::part(ghost) {
109
+ padding: 0.5rem 0.75rem;
110
+ }
111
+ ```
112
+
113
+ ### Per-part class names (Tailwind-friendly)
114
+
115
+ Use `classNames` to apply classes directly to shadow DOM elements. External stylesheets — including Tailwind — are automatically mirrored into the shadow root, so utility classes work out of the box.
116
+
117
+ Each key accepts a **string** or a **function** that receives the current component state as an object:
118
+
119
+ ```tsx
120
+ <HotDate
121
+ classNames={{
122
+ input: ({ active, focused, error }) =>
123
+ `border rounded px-3 py-2 w-full
124
+ ${focused ? "ring-2 ring-indigo-500" : ""}
125
+ ${active ? "border-green-500" : "border-gray-300"}
126
+ ${error ? "border-red-500" : ""}`,
127
+ ghost: "text-gray-400",
128
+ hint: "opacity-50",
129
+ }}
130
+ error={hasError}
131
+ />
132
+ ```
133
+
134
+ The function signature for any `classNames` entry:
135
+
136
+ ```ts
137
+ (props: {
138
+ active: boolean; // true when input has a resolved valid date
139
+ disabled: boolean; // true when the disabled prop is set
140
+ focused: boolean; // true when the input currently has focus
141
+ error: boolean; // true when the error prop is set
142
+ success: boolean; // true when the success prop is set
143
+ }) => string
144
+ ```
145
+
146
+ The keys map to shadow DOM parts:
147
+
148
+ | Key | Part | Element |
149
+ | --- | --- | --- |
150
+ | `input` | `part="input"` | The `<input>` element |
151
+ | `ghost` | `part="ghost"` | The suggestion overlay |
152
+ | `hint` | `part="hint"` | The `Tab` hint chip |
153
+
154
+ ### Controlled value
155
+
156
+ ```tsx
157
+ const [date, setDate] = useState<string | null>(null);
158
+
159
+ <HotDate
160
+ value={date}
161
+ onChange={(v) => setDate(typeof v === 'string' ? v : null)}
162
+ />
163
+ ```
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.
166
+
167
+ ## Props
168
+
169
+ | Prop | Type | Default | Description |
170
+ | --- | --- | --- | --- |
171
+ | `value` | `string \| null` | — | Controlled canonical value (`YYYY-MM-DD` or `YYYY-MM-DD/YYYY-MM-DD`) |
172
+ | `onChange` | `(value: string \| [string, string] \| null) => void` | — | Fires on every valid parse. Range returns `[start, end]`. |
173
+ | `onCommit` | `(value: string \| [string, string] \| null) => void` | — | Fires on Enter key commit. |
174
+ | `onClear` | `() => void` | — | Fires when input is cleared. |
175
+ | `format` | `string` | `"YYYY-MM-DD"` | Output format. Tokens: `YYYY MM DD YY M D` (case-insensitive). |
176
+ | `dateType` | `"point" \| "range"` | `"point"` | Restrict input to single date or range. |
177
+ | `startDate` | `Date \| string` | — | Minimum date. Accepts a JS `Date` or `"YYYY-MM-DD"` string. |
178
+ | `endDate` | `Date \| string` | — | Maximum date. Accepts a JS `Date` or `"YYYY-MM-DD"` string. |
179
+ | `className` | `string` | — | CSS class on the host element. |
180
+ | `style` | `React.CSSProperties` | — | Inline styles on the host element. |
181
+ | `placeholder` | `string` | `"type anything..."` | Input placeholder text. |
182
+ | `timezone` | `string` | system timezone | IANA timezone (e.g. `"America/New_York"`). |
183
+ | `locale` | `string` | `navigator.language` | BCP-47 locale (e.g. `"en-US"`). |
184
+ | `weekStart` | `"sunday" \| "monday" \| "tuesday" \| "wednesday" \| "thursday" \| "friday" \| "saturday"` | `"monday"` | First day of week for relative expressions. |
185
+ | `disabled` | `boolean` | `false` | Disable the input. |
186
+ | `required` | `boolean` | `false` | Participates in form validation. |
187
+ | `name` | `string` | — | Form field name. |
188
+ | `showHint` | `boolean` | `true` | Show the Tab autocomplete hint. |
189
+ | `error` | `boolean` | `false` | Passes `error: true` into `classNames` functions. |
190
+ | `success` | `boolean` | `false` | Passes `success: true` into `classNames` functions. |
191
+ | `classNames` | `ClassNamesConfig` | — | Per-part class names. Each value is a `string` or `(props) => string`. Keys: `input`, `ghost`, `hint`. |
192
+
193
+ ## Output Format
194
+
195
+ | `dateType` | `format` not set | `format="MM/DD/YYYY"` |
196
+ | --- | --- | --- |
197
+ | `"point"` | `"2026-06-13"` | `"06/13/2026"` |
198
+ | `"range"` | `["2026-06-01", "2026-06-30"]` | `["06/01/2026", "06/30/2026"]` |
199
+
200
+ ## Keyboard
201
+
202
+ | Key | Action |
203
+ | --- | --- |
204
+ | `Tab` | Accept the active autocomplete suggestion (pressing Tab again after accepting moves focus normally) |
205
+ | `Enter` | Commit the current value |
206
+ | `↑` / `↓` | Cycle through suggestions |
207
+ | `Escape` | Reset active suggestion |
208
+
209
+ ## Styling with `::part()`
210
+
211
+ The shadow DOM exposes these CSS parts:
212
+
213
+ | Part | Element |
214
+ | --- | --- |
215
+ | `input` | The `<input>` element |
216
+ | `ghost` | The suggestion overlay |
217
+ | `hint` | The `Tab` hint `<kbd>` chip |
218
+
219
+ ```css
220
+ hot-date::part(input) { font-size: 1rem; border-radius: 8px; }
221
+ hot-date::part(ghost) { padding: 0 0.75rem; }
222
+ ```
223
+
224
+ ## Natural Language Examples
225
+
226
+ ```
227
+ tomorrow
228
+ next friday
229
+ in 3 days
230
+ christmas
231
+ after tomorrow
232
+ jan to feb
233
+ this week
234
+ tomorrow to after tomorrow
235
+ between 5/15/2026 and 6/13/2026
236
+ 3 days before christmas
237
+ 9 days after christmas until new years
238
+ ```
239
+
240
+ ## Credits
241
+
242
+ Built on top of [**@stolinski/hot-date**](https://github.com/stolinski/hot-date) by [Scott Tolinski](https://github.com/stolinski) — the natural language date parsing engine and web component that powers this React wrapper.
243
+
244
+ ## License
245
+
246
+ MIT