@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 +246 -0
- package/dist/hot-date-CdRySQgv.js +9183 -0
- package/dist/hot-date-react.js +149 -0
- package/dist/hot-date.d.ts +64 -0
- package/dist/hot-date.js +2 -0
- package/dist/lib/parser/anchors.d.ts +13 -0
- package/dist/lib/parser/candidates.d.ts +23 -0
- package/dist/lib/parser/challenge-phrases.d.ts +1 -0
- package/dist/lib/parser/complete.d.ts +2 -0
- package/dist/lib/parser/endpoints.d.ts +10 -0
- package/dist/lib/parser/grammar.d.ts +21 -0
- package/dist/lib/parser/holidays.d.ts +1 -0
- package/dist/lib/parser/js-parser-engine.d.ts +5 -0
- package/dist/lib/parser/parser-engine.d.ts +4 -0
- package/dist/lib/parser/parser-types.d.ts +66 -0
- package/dist/lib/utils/date-utils.d.ts +46 -0
- package/dist/lib/utils/string-utils.d.ts +5 -0
- package/dist/react/HotDate.d.ts +68 -0
- package/dist/react/format.d.ts +3 -0
- package/dist/react/index.d.ts +3 -0
- package/package.json +76 -0
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
|