kanto-ds 1.6.1 → 1.7.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.
Files changed (65) hide show
  1. package/README.md +52 -4
  2. package/dist/cdn/kanto.min.js +6619 -0
  3. package/dist/chunks/{floating-B33g-M_1.js → floating-C9RLa6cZ.js} +2 -2
  4. package/dist/chunks/floating-C9RLa6cZ.js.map +1 -0
  5. package/dist/components/forms/kt-date-input/kt-date-input.js +1 -1
  6. package/dist/components/forms/kt-date-picker/kt-date-picker.js +1 -1
  7. package/dist/components/forms/kt-input/kt-input.js +1 -1
  8. package/dist/components/forms/kt-input-menu/kt-input-menu.js +1 -1
  9. package/dist/components/forms/kt-multi-select/kt-multi-select.js +1 -1
  10. package/dist/components/forms/kt-select/kt-select.js +1 -1
  11. package/dist/components/overlays/kt-dropdown/kt-dropdown.js +1 -1
  12. package/dist/docs/kt-alert.md +52 -0
  13. package/dist/docs/kt-avatar.md +46 -0
  14. package/dist/docs/kt-badge.md +104 -0
  15. package/dist/docs/kt-breadcrumb.md +53 -0
  16. package/dist/docs/kt-button.md +72 -0
  17. package/dist/docs/kt-calendar.md +98 -0
  18. package/dist/docs/kt-card.md +93 -0
  19. package/dist/docs/kt-chart.md +230 -0
  20. package/dist/docs/kt-checkbox.md +65 -0
  21. package/dist/docs/kt-code.md +88 -0
  22. package/dist/docs/kt-collapsible.md +50 -0
  23. package/dist/docs/kt-confirm-dialog.md +52 -0
  24. package/dist/docs/kt-date-input.md +97 -0
  25. package/dist/docs/kt-date-picker.md +116 -0
  26. package/dist/docs/kt-drag-drop.md +85 -0
  27. package/dist/docs/kt-dropdown.md +65 -0
  28. package/dist/docs/kt-empty-state.md +36 -0
  29. package/dist/docs/kt-form.md +93 -0
  30. package/dist/docs/kt-header.md +100 -0
  31. package/dist/docs/kt-icon.md +68 -0
  32. package/dist/docs/kt-input-menu.md +90 -0
  33. package/dist/docs/kt-input.md +137 -0
  34. package/dist/docs/kt-kbd.md +44 -0
  35. package/dist/docs/kt-label-input.md +54 -0
  36. package/dist/docs/kt-meter.md +79 -0
  37. package/dist/docs/kt-modal.md +62 -0
  38. package/dist/docs/kt-multi-select.md +115 -0
  39. package/dist/docs/kt-page-header.md +53 -0
  40. package/dist/docs/kt-pagination.md +36 -0
  41. package/dist/docs/kt-progress-bar.md +66 -0
  42. package/dist/docs/kt-radio-group.md +73 -0
  43. package/dist/docs/kt-segmented-control.md +70 -0
  44. package/dist/docs/kt-select.md +80 -0
  45. package/dist/docs/kt-side-panel.md +59 -0
  46. package/dist/docs/kt-skeleton.md +46 -0
  47. package/dist/docs/kt-split-button.md +105 -0
  48. package/dist/docs/kt-stat.md +57 -0
  49. package/dist/docs/kt-sub-menu-navigation.md +118 -0
  50. package/dist/docs/kt-table.md +179 -0
  51. package/dist/docs/kt-tabs.md +87 -0
  52. package/dist/docs/kt-textarea.md +59 -0
  53. package/dist/docs/kt-time-input.md +88 -0
  54. package/dist/docs/kt-timeline.md +63 -0
  55. package/dist/docs/kt-toast-container.md +69 -0
  56. package/dist/docs/kt-toast.md +41 -0
  57. package/dist/docs/kt-toggle-button-group.md +67 -0
  58. package/dist/docs/kt-toggle-button.md +52 -0
  59. package/dist/docs/kt-toggle.md +47 -0
  60. package/dist/docs/kt-tooltip.md +68 -0
  61. package/dist/internal/floating.d.ts +4 -0
  62. package/dist/tokens/colors.css +5 -2
  63. package/dist/web-types.json +1 -1
  64. package/package.json +23 -5
  65. package/dist/chunks/floating-B33g-M_1.js.map +0 -1
@@ -0,0 +1,230 @@
1
+ # `<kt-chart>`
2
+
3
+ A chart, drawn from the token layer: line, area and bar — stacked, sideways or
4
+ mixed — plus scatter, bubble, pie, doughnut, polar area and radar.
5
+
6
+ ```js
7
+ chart.labels = ['Jan', 'Feb', 'Mar', 'Apr'];
8
+ chart.series = [{ name: 'Revenue', values: [42, 58, 36, 71] }];
9
+ chart.format = (n) => `$${n.toLocaleString('en-US')}`;
10
+ ```
11
+
12
+ ```html
13
+ <kt-chart type="area" label="Revenue by month" height="220"></kt-chart>
14
+ ```
15
+
16
+ Every type shares one data model, one tooltip, one legend and one keyboard
17
+ model, so learning one chart is learning all of them.
18
+
19
+ ## Choosing a type
20
+
21
+ | Type | Use it for |
22
+ | -------------------- | ------------------------------------------------------------------------------------------ |
23
+ | `line` | A measure over time, where the shape of the change is the point |
24
+ | `area` | The same, when the size under the line matters — or, `stacked`, parts of a total over time |
25
+ | `bar` | Comparing categories |
26
+ | `bar` + `horizontal` | Long category names, or a ranking read top to bottom |
27
+ | `bar` + `stacked` | A total per category, split into parts |
28
+ | mixed | A measure in bars against a target or average as a line |
29
+ | `scatter` | Whether two measures move together |
30
+ | `bubble` | The same, with a third measure as size |
31
+ | `pie` | A few parts of one whole — past five slices, use a bar |
32
+ | `doughnut` | A pie with the total in the middle |
33
+ | `polar-area` | Cyclic categories compared by size |
34
+ | `radar` | A profile across several measures on the same scale |
35
+
36
+ ## The rules it keeps
37
+
38
+ **One value axis, always.** There is no second y-scale and there will not be:
39
+ two measures of different magnitude belong in two charts, or indexed to a common
40
+ base. A dual-axis chart lets you imply any correlation you like by sliding one
41
+ scale.
42
+
43
+ **Bars and areas start at zero.** Their size is their distance from zero, so a
44
+ bar axis that starts at 40 makes 50 look twice 45. Lines follow their data,
45
+ because a line is read by its shape. `min` and `max` override both — use them
46
+ knowingly.
47
+
48
+ **Area carries the value.** A bubble twice the value is twice the area, not
49
+ twice the radius, and a polar slice's radius is the square root of its value.
50
+ Anything else overstates the big ones.
51
+
52
+ **Slices are one distribution.** Pie, doughnut and polar area read `labels` as
53
+ the slices and the **first series** as their values. Comparing two
54
+ distributions is a stacked bar's job, not two pies'. Negative values are drawn
55
+ as nothing and kept, as written, in the table.
56
+
57
+ ## Colour
58
+
59
+ **One series takes the brand hue.** With nothing to tell apart there is no
60
+ identity to encode, and the title names it — so a lone series needs no legend
61
+ either, and does not get one.
62
+
63
+ **Two or more take the fixed categorical order** in `--chart-series-1…8`,
64
+ assigned by position and never cycled. A ninth series is not a generated hue —
65
+ fold it into "Other", or facet. Slices take the same order, by slice.
66
+
67
+ Those eight hues are kept clear of the semantic palette, so a line can never be
68
+ mistaken for a status. They are validated against Kanto's own card surface in
69
+ both themes: worst adjacent CVD ΔE 8.4, worst adjacent normal-vision ΔE 19.3.
70
+
71
+ **Colour follows the entity, not the rank.** Hiding a series from the legend
72
+ never repaints the others. If a filter removes one from the data, pass `color`
73
+ on the survivors so they keep the hue the reader learned:
74
+
75
+ ```js
76
+ chart.series = [{ name: 'Orders', values, color: 'var(--chart-series-2)' }];
77
+ ```
78
+
79
+ Separators — the gap between slices, the ring around a dot — are drawn in
80
+ `--surface-card`. Put the chart on a card surface and they read as the surface
81
+ showing through.
82
+
83
+ ## Stacked, sideways and mixed
84
+
85
+ ```html
86
+ <kt-chart type="bar" stacked></kt-chart>
87
+
88
+ <kt-chart type="bar" horizontal></kt-chart>
89
+ ```
90
+
91
+ `stacked` piles bars on bars and areas on areas; lines never stack. The tooltip
92
+ adds a total, and so does the table.
93
+
94
+ A series can be drawn as another mark with its own `type`. Lines are then placed
95
+ at the centre of each bar's band and drawn above the bars:
96
+
97
+ ```js
98
+ chart.type = 'bar';
99
+ chart.series = [
100
+ { name: 'Signups', values: [320, 410, 380] },
101
+ { name: 'Target', values: [400, 420, 440], type: 'line' },
102
+ ];
103
+ ```
104
+
105
+ `horizontal` applies only when every visible series is a bar.
106
+
107
+ ## Scatter and bubble
108
+
109
+ These take `points` instead of `values`, and no `labels`:
110
+
111
+ ```js
112
+ chart.type = 'bubble';
113
+ chart.series = [
114
+ {
115
+ name: 'Markets',
116
+ points: [
117
+ { x: 4, y: 18, r: 120, label: 'France' },
118
+ { x: 9, y: 24, r: 64, label: 'Germany' },
119
+ ],
120
+ },
121
+ ];
122
+ chart.format = (n) => `${n}%`; // y
123
+ chart.formatX = (n) => `${n}%`; // x
124
+ ```
125
+
126
+ Neither axis is forced through zero: a scatter plot is about how two measures
127
+ move together, and dragging the origin in crushes the cloud into a corner. A
128
+ `label` names the point in the tooltip and the table.
129
+
130
+ ## Hover and keyboard
131
+
132
+ The tooltip follows the pointer on every type: a whole category on line, area
133
+ and bar charts, the nearest point on scatter and bubble, a slice or a spoke on
134
+ radial charts. It opens above the mark, or beside it when there is no room —
135
+ never on top of what it describes.
136
+
137
+ The plot is focusable. **Arrow keys** walk the categories, slices or spokes;
138
+ on scatter and bubble, left and right walk the current series in x order and up
139
+ and down move between series. **Home** and **End** jump to the ends,
140
+ **Escape** lets go. The tooltip is a live region, so a keyboard move is
141
+ announced.
142
+
143
+ `kt-point-hover` reports every change, so a caption or a figure elsewhere on the
144
+ page can follow along.
145
+
146
+ ## The legend
147
+
148
+ It appears from two series up, and always for pie, doughnut and polar area,
149
+ whose slices need names. Each item is a toggle: pressing it hides the series or
150
+ slice and rescales the chart around what is left. `kt-series-toggle` is
151
+ cancelable, for a host that wants to decide. New data resets the legend.
152
+
153
+ ## The table is not optional
154
+
155
+ Every chart also renders its data as a `<table>`, visually hidden and pointed at
156
+ by the plot's `aria-describedby`. It is what a screen reader reads, and it is
157
+ the relief that four of the light-theme series hues require — they sit below 3:1
158
+ on a light surface, which is legal only with a text alternative.
159
+
160
+ `show-table` puts it on screen, which is often the right call in a report.
161
+
162
+ ## Smoothing is off
163
+
164
+ `smooth` draws lines and areas through a monotone cubic — one that never
165
+ overshoots the samples, unlike the cardinal spline most charts reach for, which
166
+ invents peaks that are not in the data.
167
+
168
+ It is still off by default, because a curve between two samples draws values
169
+ nobody measured. Turn it on when the underlying quantity really is continuous
170
+ and the reader knows it. A radar is always drawn straight: a closed curve has no
171
+ monotone version.
172
+
173
+ ## Motion
174
+
175
+ Marks enter once, when they first appear: bars grow from the baseline, lines
176
+ draw along their length, everything else fades in. Nothing moves on hover.
177
+ The token layer's reduced-motion block turns the entrance off.
178
+
179
+ ## API
180
+
181
+ | Property | Attribute | Type | Default |
182
+ | ------------- | -------------- | --------------------------- | --------- |
183
+ | `type` | `type` | `KtChartType` | `'area'` |
184
+ | `series` | — | `KtSeries[]` | `[]` |
185
+ | `labels` | — | `string[]` | `[]` |
186
+ | `height` | `height` | `number` | `200` |
187
+ | `format` | — | `(value: number) => string` | `String` |
188
+ | `formatX` | — | `(value: number) => string` | `String` |
189
+ | `stacked` | `stacked` | `boolean` | `false` |
190
+ | `horizontal` | `horizontal` | `boolean` | `false` |
191
+ | `smooth` | `smooth` | `boolean` | `false` |
192
+ | `min` | `min` | `number \| null` | `null` |
193
+ | `max` | `max` | `number \| null` | `null` |
194
+ | `noGrid` | `no-grid` | `boolean` | `false` |
195
+ | `noAxis` | `no-axis` | `boolean` | `false` |
196
+ | `showTable` | `show-table` | `boolean` | `false` |
197
+ | `centerLabel` | `center-label` | `string` | `'Total'` |
198
+ | `totalLabel` | `total-label` | `string` | `'Total'` |
199
+ | `label` | `label` | `string` | `''` |
200
+
201
+ ```ts
202
+ type KtChartType =
203
+ 'line' | 'area' | 'bar' | 'scatter' | 'bubble' | 'pie' | 'doughnut' | 'polar-area' | 'radar';
204
+
205
+ interface KtSeries {
206
+ name: string;
207
+ values?: number[]; // one per label
208
+ points?: KtPoint[]; // scatter and bubble
209
+ color?: string; // pins the hue
210
+ type?: 'line' | 'area' | 'bar'; // mixed charts
211
+ }
212
+
213
+ interface KtPoint {
214
+ x: number;
215
+ y: number;
216
+ r?: number; // bubble size, as a value
217
+ label?: string;
218
+ }
219
+ ```
220
+
221
+ | Event | Detail |
222
+ | ------------------ | ---------------------------------------------------------------------------------------------------- |
223
+ | `kt-point-hover` | `{ index, series }` — `index` −1 when nothing is active; `series` −1 unless scatter or bubble |
224
+ | `kt-series-toggle` | `{ series, hidden }` — a series index, or a slice index for pie, doughnut and polar area. Cancelable |
225
+
226
+ | Part | Description |
227
+ | -------- | -------------- |
228
+ | `svg` | The plot |
229
+ | `legend` | The legend |
230
+ | `table` | The data table |
@@ -0,0 +1,65 @@
1
+ # `<kt-checkbox>`
2
+
3
+ A checkbox: a choice that applies when the form is submitted.
4
+
5
+ ```html
6
+ <kt-checkbox name="updates" checked>Send me product updates</kt-checkbox>
7
+ <kt-checkbox name="terms" required>I accept the terms</kt-checkbox>
8
+ <kt-checkbox indeterminate>Select all</kt-checkbox>
9
+ <kt-checkbox disabled>Unavailable</kt-checkbox>
10
+ ```
11
+
12
+ ## Checkbox, toggle or radio
13
+
14
+ - **Checkbox** — the choice takes effect when the form is submitted, or it is
15
+ one of several independent choices in a list.
16
+ - **`<kt-toggle>`** — a setting that applies the moment it is flipped.
17
+ - **`<kt-radio-group>`** — exactly one choice among a few.
18
+
19
+ ## Built on the native input
20
+
21
+ Under the drawn box sits a real `<input type="checkbox">`, invisible but
22
+ covering it. The keyboard (Space), the click on the label, the indeterminate
23
+ state and what a screen reader announces all come from the platform, so they
24
+ behave exactly like every other checkbox the user has met.
25
+
26
+ The slotted text is the label: clicking it toggles the box, and it names the
27
+ checkbox for assistive technology. With nothing slotted — a checkbox in a table
28
+ row — give it a `label` instead.
29
+
30
+ ## Indeterminate
31
+
32
+ `indeterminate` draws a dash: neither checked nor unchecked, for a "select all"
33
+ over a partial selection. It is display state only, as on a native checkbox —
34
+ the first click clears it and checks the box.
35
+
36
+ ## In a form
37
+
38
+ A form control, like a native checkbox: it submits its `value` (default `on`)
39
+ under `name` when checked, and **nothing** when unchecked. `required` blocks
40
+ submission until it is checked, `error` shows a message and puts it in its
41
+ error state, and `form.reset()` puts back the initial state.
42
+
43
+ ## API
44
+
45
+ | Property | Attribute | Type | Default |
46
+ | --------------- | --------------- | -------------------------------- | ---------- |
47
+ | `checked` | `checked` | `boolean` | `false` |
48
+ | `indeterminate` | `indeterminate` | `boolean` | `false` |
49
+ | `disabled` | `disabled` | `boolean` | `false` |
50
+ | `required` | `required` | `boolean` | `false` |
51
+ | `size` | `size` | `'small' \| 'medium' \| 'large'` | `'medium'` |
52
+ | `name` | `name` | `string` | `''` |
53
+ | `value` | `value` | `string` | `'on'` |
54
+ | `label` | `label` | `string` | `''` |
55
+ | `error` | `error` | `string` | `''` |
56
+
57
+ | Event | Detail |
58
+ | ----------- | ---------------------- |
59
+ | `kt-change` | `{ checked: boolean }` |
60
+
61
+ | Part | Description |
62
+ | ------- | --------------------------- |
63
+ | `base` | The `<label>` around it all |
64
+ | `input` | The native checkbox |
65
+ | `box` | The drawn box |
@@ -0,0 +1,88 @@
1
+ # `<kt-code>`
2
+
3
+ A block of code on a recessed surface, with its language and a copy button.
4
+
5
+ ```html
6
+ <kt-code language="js" copy>const total = items.length;</kt-code>
7
+ <kt-code>npm install kanto-ds</kt-code>
8
+ ```
9
+
10
+ Set neither `language` nor `copy` and the header disappears entirely — a bare
11
+ block for a one-line command.
12
+
13
+ ## Highlighting is yours
14
+
15
+ The element owns the chrome — surface, language label, scrolling, copy — and
16
+ nothing else. Slot in whatever markup a highlighter produced:
17
+
18
+ ```js
19
+ import hljs from 'highlight.js/lib/core';
20
+
21
+ block.innerHTML = hljs.highlight(source, { language: 'ts' }).value;
22
+ ```
23
+
24
+ A design system that bundled a syntax highlighter would be choosing your bundle
25
+ size and your language set for you. This one does not, which is also why
26
+ `language` is purely a label: it says what the code is, it does not parse it.
27
+
28
+ Style the highlighter's classes from the token layer and they follow the theme:
29
+
30
+ ```css
31
+ .hljs-keyword {
32
+ color: var(--color-primary-base);
33
+ }
34
+ .hljs-string {
35
+ color: var(--color-success-base);
36
+ }
37
+ .hljs-comment {
38
+ color: var(--color-text-500);
39
+ }
40
+ ```
41
+
42
+ ## Against `<kt-badge variant="code">`
43
+
44
+ `<kt-badge variant="code">` is for a token inside a sentence — an identifier, a
45
+ property name, a custom property. `<kt-code>` is for a block. Both draw on
46
+ `--surface-code`, so they read as the same material at two scales.
47
+
48
+ ## Copying
49
+
50
+ `copy` adds the button; pressing it writes `code` — the block's plain text, with
51
+ the leading and trailing newlines a template literal leaves behind removed — and
52
+ confirms for a second and a half.
53
+
54
+ A clipboard that refuses, because permission was denied or the page is not on a
55
+ secure origin, is swallowed: failing loudly over a convenience button helps
56
+ nobody. `kt-copy` fires either way, so a caller that cares can tell.
57
+
58
+ ## Accessibility
59
+
60
+ The `<pre>` is a tab stop, because it scrolls: a block of code that can only be
61
+ scrolled with a pointer is unreadable without one. Give it a `label` when the
62
+ language alone does not say what it is.
63
+
64
+ ## API
65
+
66
+ | Property | Attribute | Type | Default |
67
+ | ---------- | ---------- | --------- | ------- |
68
+ | `language` | `language` | `string` | `''` |
69
+ | `copy` | `copy` | `boolean` | `false` |
70
+ | `label` | `label` | `string` | `''` |
71
+
72
+ | Getter | Returns |
73
+ | ------ | ---------------------------------------------- |
74
+ | `code` | The block's plain text, trimmed of blank edges |
75
+
76
+ | Event | Detail |
77
+ | --------- | ------------------ |
78
+ | `kt-copy` | `{ code: string }` |
79
+
80
+ | Slot | Description |
81
+ | --------- | -------------------------------------------- |
82
+ | _default_ | The code — plain text, or highlighted markup |
83
+
84
+ | Part | Description |
85
+ | -------- | --------------------- |
86
+ | `base` | The container |
87
+ | `header` | The language row |
88
+ | `pre` | The scrolling `<pre>` |
@@ -0,0 +1,50 @@
1
+ # `<kt-collapsible>`
2
+
3
+ A section that folds away.
4
+
5
+ ```html
6
+ <kt-collapsible heading="Notifications" open>
7
+ <kt-toggle checked>Email me about mentions</kt-toggle>
8
+ <kt-toggle>Email me a weekly digest</kt-toggle>
9
+ </kt-collapsible>
10
+ ```
11
+
12
+ ## Built on `<details>`
13
+
14
+ Which buys three things for free:
15
+
16
+ - It **works before the JavaScript loads** — the browser opens and closes it on
17
+ its own.
18
+ - **Find-in-page opens it.** A browser will expand a closed `<details>` to
19
+ reveal a match inside it; a div with a click handler hides that text forever.
20
+ - It needs **no ARIA of its own**. `<summary>` is already a button with the
21
+ right expanded state.
22
+
23
+ The default disclosure triangle is replaced with a chevron that rotates, which
24
+ is the only cosmetic liberty taken.
25
+
26
+ ## API
27
+
28
+ | Property | Attribute | Type | Default |
29
+ | --------- | --------- | --------- | ------- |
30
+ | `open` | `open` | `boolean` | `false` |
31
+ | `heading` | `heading` | `string` | `''` |
32
+ | `plain` | `plain` | `boolean` | `false` |
33
+
34
+ `plain` drops the bottom rule, for a collapsible that is not one of a stacked
35
+ list.
36
+
37
+ | Slot | Description |
38
+ | --------- | -------------------------------- |
39
+ | _default_ | The contents |
40
+ | `summary` | Replaces the `heading` attribute |
41
+
42
+ | Event | Detail |
43
+ | ----------- | ------------------- |
44
+ | `kt-toggle` | `{ open: boolean }` |
45
+
46
+ | Part | Description |
47
+ | --------- | ------------------ |
48
+ | `base` | The `<details>` |
49
+ | `summary` | The clickable row |
50
+ | `content` | The revealed panel |
@@ -0,0 +1,52 @@
1
+ # `<kt-confirm-dialog>`
2
+
3
+ A centred yes/no overlay for an action worth stopping to think about.
4
+
5
+ ```html
6
+ <kt-confirm-dialog
7
+ heading="Delete this entity?"
8
+ message="This action cannot be undone."
9
+ confirm-label="Delete"
10
+ ></kt-confirm-dialog>
11
+ ```
12
+
13
+ ```js
14
+ dialog.open = true;
15
+ dialog.addEventListener('kt-confirm', () => remove(entity));
16
+ dialog.addEventListener('kt-cancel', () => {});
17
+ ```
18
+
19
+ ## When
20
+
21
+ Destructive or irreversible work only. Editing belongs in a
22
+ `<kt-side-panel>`, which does not block the page behind it. A confirmation on
23
+ something reversible teaches people to dismiss confirmations.
24
+
25
+ ## Defaults that fail safe
26
+
27
+ `role="alertdialog"`, and **focus lands on Cancel**, not Confirm. A stray Enter
28
+ meant for whatever was behind the dialog should not delete anything.
29
+
30
+ Escape and a backdrop click both report `kt-cancel` — never `kt-confirm`.
31
+ `variant="danger"` (the default) gives the confirm button the solid red
32
+ treatment, the only place in Kanto that colour is used.
33
+
34
+ ## API
35
+
36
+ | Property | Attribute | Type | Default |
37
+ | -------------- | --------------- | ----------------------- | ----------------- |
38
+ | `open` | `open` | `boolean` | `false` |
39
+ | `heading` | `heading` | `string` | `'Are you sure?'` |
40
+ | `message` | `message` | `string` | `''` |
41
+ | `confirmLabel` | `confirm-label` | `string` | `'Confirm'` |
42
+ | `cancelLabel` | `cancel-label` | `string` | `'Cancel'` |
43
+ | `variant` | `variant` | `'danger' \| 'primary'` | `'danger'` |
44
+
45
+ | Event | Description |
46
+ | ------------ | -------------------------------------- |
47
+ | `kt-confirm` | Confirm pressed |
48
+ | `kt-cancel` | Dismissed — button, Escape or backdrop |
49
+
50
+ | Slot | Description |
51
+ | --------- | ----------------------------------------- |
52
+ | _default_ | Extra content between message and buttons |
@@ -0,0 +1,97 @@
1
+ # `<kt-date-input>`
2
+
3
+ A date typed into its parts — day, month and year, each its own segment.
4
+
5
+ ```html
6
+ <kt-date-input label="Date of birth" name="born" max="2026-12-31"></kt-date-input>
7
+ <kt-date-input label="Due date" calendar value="2026-09-25"></kt-date-input>
8
+ ```
9
+
10
+ Where [`<kt-date-picker>`](./kt-date-picker.md) leads with a
11
+ calendar, this field leads with the keyboard: a date of birth, a date already
12
+ on paper, a date in a table of a hundred rows. With `calendar` it gets a
13
+ calendar too, a button away.
14
+
15
+ ## The segments
16
+
17
+ The segments come in the order the reader's language writes a date, with its
18
+ separator: `25/09/2026` in London, `09/25/2026` in New York, `25.09.2026` in
19
+ Berlin. The locale is `locale` if set, else the page's `lang`, else the
20
+ browser's language. An empty segment shows what it wants — `dd`, `mm`, `yyyy`,
21
+ from `setStrings`.
22
+
23
+ The focus moves on as each segment fills, so a date is eight keystrokes:
24
+ `25092026`. A segment also moves on as soon as no other digit could follow — a
25
+ `4` in the day, a `2` in the month — and on a typed `/`, `.`, `-` or space.
26
+
27
+ | Key | Does |
28
+ | ------------- | ------------------------------------------------------------ |
29
+ | digits | fill the segment in focus |
30
+ | `↑` / `↓` | step the segment, wrapping; a day never past its month's end |
31
+ | `Home`/`End` | the segment's first or last value |
32
+ | `←` / `→` | the segment before or after |
33
+ | `Backspace` | erases a digit, then steps back to the segment before |
34
+ | `/` `.` `-` … | the next segment |
35
+
36
+ A year left at two digits is written out when the focus leaves it: `98` is
37
+ 1998, `30` is 2030. Everything else is turned away, so the field never holds
38
+ text that is not a date in the making.
39
+
40
+ ## ISO in and out
41
+
42
+ The value is ISO 8601 text, `2026-09-25`, and `null` until all three segments
43
+ are filled. `kt-change` fires when the date becomes complete, changes, or stops
44
+ being one — once per date, not per keystroke.
45
+
46
+ A date that does not exist — the 31st of February — or one outside
47
+ `min`/`max` puts the field in its error state, the message in a tooltip on the
48
+ alert icon, as `<kt-input>` does. The value is `null` and the form sees a
49
+ `badInput`.
50
+
51
+ ## The calendar option
52
+
53
+ With `calendar`, a button at the end of the field opens a
54
+ [`<kt-calendar>`](./kt-calendar.md) on the field's date, with the
55
+ focus in it. Choosing a day fills in the segments and closes it; `Escape`, or a
56
+ click outside, closes it and leaves the date as it was.
57
+
58
+ ## In a form
59
+
60
+ A form control: it submits the ISO value under `name`, and nothing while the
61
+ date is incomplete. `required` blocks submission while it is empty, `error`
62
+ shows a message, and `form.reset()` puts back the initial value.
63
+
64
+ ## API
65
+
66
+ | Property | Attribute | Type | Default |
67
+ | ---------- | ---------- | -------------------------------- | ------------------ |
68
+ | `value` | `value` | `string \| null` | `null` |
69
+ | `calendar` | `calendar` | `boolean` | `false` |
70
+ | `min` | `min` | `string` | `''` |
71
+ | `max` | `max` | `string` | `''` |
72
+ | `name` | `name` | `string` | `''` |
73
+ | `label` | `label` | `string` | `''` |
74
+ | `locale` | `locale` | `string` | page, then browser |
75
+ | `size` | `size` | `'small' \| 'medium' \| 'large'` | `'medium'` |
76
+ | `disabled` | `disabled` | `boolean` | `false` |
77
+ | `required` | `required` | `boolean` | `false` |
78
+ | `error` | `error` | `string` | `''` |
79
+
80
+ | Event | Detail |
81
+ | ----------- | ------------------------------------------------ |
82
+ | `kt-change` | `{ value: string \| null }` — ISO date or `null` |
83
+
84
+ | Part | Description |
85
+ | --------- | ------------------------------------ |
86
+ | `field` | The field |
87
+ | `segment` | A day, month or year segment |
88
+ | `trigger` | The calendar button, with `calendar` |
89
+ | `panel` | The calendar popup, with `calendar` |
90
+
91
+ ## Accessibility
92
+
93
+ The field is a `group` named by `label`. Each segment is a `spinbutton` named
94
+ "Day", "Month" or "Year", with its range and value, so a screen reader
95
+ announces "Month, 09" and `↑`/`↓` work as it expects. `Tab` walks the segments,
96
+ then the calendar button. On a phone, the segments bring up the numeric
97
+ keypad.