kanto-ds 1.6.0 → 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.
- package/README.md +56 -6
- package/dist/cdn/kanto.min.js +6619 -0
- package/dist/chunks/defaults-Cpeg13O5.js +68 -0
- package/dist/chunks/defaults-Cpeg13O5.js.map +1 -0
- package/dist/chunks/{floating-B33g-M_1.js → floating-C9RLa6cZ.js} +2 -2
- package/dist/chunks/floating-C9RLa6cZ.js.map +1 -0
- package/dist/components/core/kt-icon/kt-icon.js +1 -1
- package/dist/components/forms/kt-date-input/kt-date-input.js +1 -1
- package/dist/components/forms/kt-date-picker/kt-date-picker.js +1 -1
- package/dist/components/forms/kt-input/kt-input.js +1 -1
- package/dist/components/forms/kt-input-menu/kt-input-menu.js +1 -1
- package/dist/components/forms/kt-multi-select/kt-multi-select.js +1 -1
- package/dist/components/forms/kt-select/kt-select.js +1 -1
- package/dist/components/overlays/kt-dropdown/kt-dropdown.js +1 -1
- package/dist/docs/kt-alert.md +52 -0
- package/dist/docs/kt-avatar.md +46 -0
- package/dist/docs/kt-badge.md +104 -0
- package/dist/docs/kt-breadcrumb.md +53 -0
- package/dist/docs/kt-button.md +72 -0
- package/dist/docs/kt-calendar.md +98 -0
- package/dist/docs/kt-card.md +93 -0
- package/dist/docs/kt-chart.md +230 -0
- package/dist/docs/kt-checkbox.md +65 -0
- package/dist/docs/kt-code.md +88 -0
- package/dist/docs/kt-collapsible.md +50 -0
- package/dist/docs/kt-confirm-dialog.md +52 -0
- package/dist/docs/kt-date-input.md +97 -0
- package/dist/docs/kt-date-picker.md +116 -0
- package/dist/docs/kt-drag-drop.md +85 -0
- package/dist/docs/kt-dropdown.md +65 -0
- package/dist/docs/kt-empty-state.md +36 -0
- package/dist/docs/kt-form.md +93 -0
- package/dist/docs/kt-header.md +100 -0
- package/dist/docs/kt-icon.md +68 -0
- package/dist/docs/kt-input-menu.md +90 -0
- package/dist/docs/kt-input.md +137 -0
- package/dist/docs/kt-kbd.md +44 -0
- package/dist/docs/kt-label-input.md +54 -0
- package/dist/docs/kt-meter.md +79 -0
- package/dist/docs/kt-modal.md +62 -0
- package/dist/docs/kt-multi-select.md +115 -0
- package/dist/docs/kt-page-header.md +53 -0
- package/dist/docs/kt-pagination.md +36 -0
- package/dist/docs/kt-progress-bar.md +66 -0
- package/dist/docs/kt-radio-group.md +73 -0
- package/dist/docs/kt-segmented-control.md +70 -0
- package/dist/docs/kt-select.md +80 -0
- package/dist/docs/kt-side-panel.md +59 -0
- package/dist/docs/kt-skeleton.md +46 -0
- package/dist/docs/kt-split-button.md +105 -0
- package/dist/docs/kt-stat.md +57 -0
- package/dist/docs/kt-sub-menu-navigation.md +118 -0
- package/dist/docs/kt-table.md +179 -0
- package/dist/docs/kt-tabs.md +87 -0
- package/dist/docs/kt-textarea.md +59 -0
- package/dist/docs/kt-time-input.md +88 -0
- package/dist/docs/kt-timeline.md +63 -0
- package/dist/docs/kt-toast-container.md +69 -0
- package/dist/docs/kt-toast.md +41 -0
- package/dist/docs/kt-toggle-button-group.md +67 -0
- package/dist/docs/kt-toggle-button.md +52 -0
- package/dist/docs/kt-toggle.md +47 -0
- package/dist/docs/kt-tooltip.md +68 -0
- package/dist/icons/defaults.d.ts +9 -0
- package/dist/icons/index.js +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/floating.d.ts +4 -0
- package/dist/tokens/colors.css +5 -2
- package/dist/web-types.json +1 -1
- package/package.json +29 -6
- package/dist/chunks/defaults-CFrjqae2.js +0 -59
- package/dist/chunks/defaults-CFrjqae2.js.map +0 -1
- package/dist/chunks/floating-B33g-M_1.js.map +0 -1
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# `<kt-input>`
|
|
2
|
+
|
|
3
|
+
A single-line text field.
|
|
4
|
+
|
|
5
|
+
Kanto fields are borderless: a fill on `--color-dark-12` that gains a 2px
|
|
6
|
+
**outline** — grey on hover, primary on focus, danger on error. An outline sits
|
|
7
|
+
outside the box, so none of those states reflow the layout.
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<kt-input placeholder="Search everything..." icon="search"></kt-input>
|
|
11
|
+
<kt-input type="password" name="password"></kt-input>
|
|
12
|
+
<kt-input error="Invalid email address" value="not-an-address"></kt-input>
|
|
13
|
+
<kt-input size="small" placeholder="Filtrer"></kt-input>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Forms
|
|
17
|
+
|
|
18
|
+
`<kt-input>` is a form-associated custom element. It serialises into `FormData`
|
|
19
|
+
under its `name`, resets with the form, and reports validity like a native
|
|
20
|
+
input — no hidden mirror input, no manual wiring.
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<form>
|
|
24
|
+
<kt-input name="email" type="email" required></kt-input>
|
|
25
|
+
<kt-button type="submit">Send</kt-button>
|
|
26
|
+
</form>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
new FormData(form).get('email'); // the field's value
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Reading the value
|
|
34
|
+
|
|
35
|
+
`value` is a property, and a `value` attribute seeds it and becomes the reset
|
|
36
|
+
value. Listn for `kt-change` for a committed value, `kt-input` for every
|
|
37
|
+
keystroke:
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
input.addEventListener('kt-change', (e) => console.log(e.detail.value));
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The inner `change` event is stopped at the boundary rather than allowed to leak
|
|
44
|
+
out retargeted and untyped.
|
|
45
|
+
|
|
46
|
+
## Password and clear
|
|
47
|
+
|
|
48
|
+
`type="password"` adds a reveal toggle. Any non-empty field shows a clear
|
|
49
|
+
button, which rotates 90° on hover; set `clearable="false"` to suppress it.
|
|
50
|
+
Both are `tabindex="-1"` — they are conveniences for the mouse, and putting
|
|
51
|
+
them in the tab order would double the number of stops in a form.
|
|
52
|
+
|
|
53
|
+
## Phone mode
|
|
54
|
+
|
|
55
|
+
`type="tel"` adds a country picker: flag, dial code, and a searchable panel.
|
|
56
|
+
|
|
57
|
+
```html
|
|
58
|
+
<kt-input type="tel" name="phone" country="be"></kt-input>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`value` holds the **national digits only** — `612345678` — and the field
|
|
62
|
+
displays them grouped the way the country's `format` groups them
|
|
63
|
+
(`1 23 45 67 89` for France gives `6 12 34 56 78`). What the _form_ receives is
|
|
64
|
+
the full international number, `+33612345678`: submitting national digits
|
|
65
|
+
without the country would throw away the thing the user just picked.
|
|
66
|
+
|
|
67
|
+
A number typed with the country's trunk prefix — `06 12 34 56 78` after +33 —
|
|
68
|
+
puts the field in its error state: `+330612345678` does not exist. The message
|
|
69
|
+
shows in a tooltip on the alert icon — on hover, and while the field has focus
|
|
70
|
+
so it reaches keyboard users too, until Escape puts it away — is read out
|
|
71
|
+
through the control's description, and the form sees a `patternMismatch`. Countries where a leading 0
|
|
72
|
+
belongs to the number, like Italy, have no `trunkPrefix` and are never flagged.
|
|
73
|
+
An `error` set by the application wins over this check.
|
|
74
|
+
|
|
75
|
+
About 95 countries ship by default, sorted by name. Pass your own list to
|
|
76
|
+
narrow or widen it:
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
input.countries = [
|
|
80
|
+
{ id: 'fr', name: 'France', dialCode: '33', format: '1 23 45 67 89', trunkPrefix: '0' },
|
|
81
|
+
{ id: 'it', name: 'Italy', dialCode: '39', format: '312 345 6789' },
|
|
82
|
+
];
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Phone mode is reached **only** through `type="tel"`. Sniffing the placeholder,
|
|
86
|
+
the name or the icon for `/tel|phone/` instead would turn any field named
|
|
87
|
+
`telephone_verifie` into a country picker.
|
|
88
|
+
|
|
89
|
+
## Labelling
|
|
90
|
+
|
|
91
|
+
Wrap the field in `<kt-label-input>`, or give it a `label` when there is no
|
|
92
|
+
visible one:
|
|
93
|
+
|
|
94
|
+
```html
|
|
95
|
+
<kt-label-input label="Email address" required>
|
|
96
|
+
<kt-input name="email" type="email" required></kt-input>
|
|
97
|
+
</kt-label-input>
|
|
98
|
+
|
|
99
|
+
<kt-input label="Search" icon="search"></kt-input>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## API
|
|
103
|
+
|
|
104
|
+
| Property | Attribute | Type | Default |
|
|
105
|
+
| -------------- | -------------- | -------------------------------- | ---------- |
|
|
106
|
+
| `value` | `value` | `string` | `''` |
|
|
107
|
+
| `name` | `name` | `string` | `''` |
|
|
108
|
+
| `type` | `type` | `string` | `'text'` |
|
|
109
|
+
| `placeholder` | `placeholder` | `string` | `''` |
|
|
110
|
+
| `size` | `size` | `'small' \| 'medium' \| 'large'` | `'medium'` |
|
|
111
|
+
| `disabled` | `disabled` | `boolean` | `false` |
|
|
112
|
+
| `readonly` | `readonly` | `boolean` | `false` |
|
|
113
|
+
| `required` | `required` | `boolean` | `false` |
|
|
114
|
+
| `icon` | `icon` | `string` | `''` |
|
|
115
|
+
| `error` | `error` | `string` | `''` |
|
|
116
|
+
| `clearable` | `clearable` | `boolean` | `true` |
|
|
117
|
+
| `label` | `label` | `string` | `''` |
|
|
118
|
+
| `autocomplete` | `autocomplete` | `string` | `''` |
|
|
119
|
+
| `maxlength` | `maxlength` | `number` | — |
|
|
120
|
+
|
|
121
|
+
| Method | Description |
|
|
122
|
+
| ---------- | ---------------------------- |
|
|
123
|
+
| `focus()` | Focuses the inner input |
|
|
124
|
+
| `blur()` | Blurs it |
|
|
125
|
+
| `select()` | Selects the field's contents |
|
|
126
|
+
|
|
127
|
+
| Event | Detail | Fired when |
|
|
128
|
+
| ----------- | ------------------- | ---------------------------- |
|
|
129
|
+
| `kt-input` | `{ value: string }` | On every keystroke |
|
|
130
|
+
| `kt-change` | `{ value: string }` | On commit (blur or Enter) |
|
|
131
|
+
| `kt-clear` | — | The clear button was pressed |
|
|
132
|
+
|
|
133
|
+
| Part | Description |
|
|
134
|
+
| --------- | --------------------- |
|
|
135
|
+
| `base` | The field container |
|
|
136
|
+
| `control` | The native `<input>` |
|
|
137
|
+
| `actions` | The trailing icon row |
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# `<kt-kbd>`
|
|
2
|
+
|
|
3
|
+
A keyboard shortcut, rendered per platform.
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<kt-kbd keys="mod k"></kt-kbd>
|
|
7
|
+
<kt-kbd keys="ctrl shift p"></kt-kbd>
|
|
8
|
+
<kt-kbd>/</kt-kbd>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`mod k` shows `⌘ K` on a Mac and `Ctrl K` everywhere else. A shortcut printed
|
|
12
|
+
with the wrong modifier is worse than no shortcut at all — the reader tries it,
|
|
13
|
+
nothing happens, and they stop trusting the hints.
|
|
14
|
+
|
|
15
|
+
## `mod` versus `meta`
|
|
16
|
+
|
|
17
|
+
Reach for **`mod`**: it means "the primary shortcut modifier", which is Command
|
|
18
|
+
on a Mac and Control elsewhere.
|
|
19
|
+
|
|
20
|
+
`meta` stays honest — on Windows the Meta key really is the Windows key, so that
|
|
21
|
+
is what it prints. Most design systems quietly map `meta` to Ctrl and are wrong
|
|
22
|
+
about it on one platform.
|
|
23
|
+
|
|
24
|
+
| Key | Mac | Elsewhere |
|
|
25
|
+
| -------------------------------- | ----------- | ----------------------- |
|
|
26
|
+
| `mod` | ⌘ | Ctrl |
|
|
27
|
+
| `meta` | ⌘ | Win |
|
|
28
|
+
| `ctrl` | ⌃ | Ctrl |
|
|
29
|
+
| `alt` / `option` | ⌥ | Alt |
|
|
30
|
+
| `shift` | ⇧ | Shift |
|
|
31
|
+
| `enter` / `escape` / `backspace` | ↵ / esc / ⌫ | Enter / Esc / Backspace |
|
|
32
|
+
|
|
33
|
+
Anything else is passed through uppercased.
|
|
34
|
+
|
|
35
|
+
## API
|
|
36
|
+
|
|
37
|
+
| Property | Attribute | Type | Default |
|
|
38
|
+
| ---------- | ---------- | ---------------------------- | -------- |
|
|
39
|
+
| `keys` | `keys` | `string` (space-separated) | `''` |
|
|
40
|
+
| `platform` | `platform` | `'auto' \| 'mac' \| 'other'` | `'auto'` |
|
|
41
|
+
|
|
42
|
+
| Getter | Returns |
|
|
43
|
+
| -------- | ---------------------------------- |
|
|
44
|
+
| `labels` | The keys as they will be displayed |
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# `<kt-label-input>`
|
|
2
|
+
|
|
3
|
+
A label above a form control, with a red asterisk when it is required.
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<kt-label-input label="Email address" required>
|
|
7
|
+
<kt-input name="email" type="email" required></kt-input>
|
|
8
|
+
</kt-label-input>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Why it is not a `<label>`
|
|
12
|
+
|
|
13
|
+
Native label association does not cross a shadow boundary. `for="..."` needs the
|
|
14
|
+
control's id in the same tree, and wrapping a control in a `<label>` only works
|
|
15
|
+
when both are in that tree — a slotted `<kt-input>` is not.
|
|
16
|
+
|
|
17
|
+
So this element passes its text down to the slotted control's `label` property,
|
|
18
|
+
which the control turns into its own `aria-label`. Controls without that
|
|
19
|
+
property get `aria-label` set directly. Clicking the label focuses the control,
|
|
20
|
+
the way a real label does.
|
|
21
|
+
|
|
22
|
+
That means the asterisk is `aria-hidden`: screen readers get "required" from the
|
|
23
|
+
control's own `required` attribute, not from a decorative star in the label.
|
|
24
|
+
|
|
25
|
+
## Works with anything
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<kt-label-input label="Notes">
|
|
29
|
+
<kt-textarea maxlength="500"></kt-textarea>
|
|
30
|
+
</kt-label-input>
|
|
31
|
+
|
|
32
|
+
<kt-label-input label="Region">
|
|
33
|
+
<kt-select></kt-select>
|
|
34
|
+
</kt-label-input>
|
|
35
|
+
|
|
36
|
+
<kt-label-input label="File">
|
|
37
|
+
<input type="file" />
|
|
38
|
+
</kt-label-input>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## API
|
|
42
|
+
|
|
43
|
+
| Property | Attribute | Type | Default |
|
|
44
|
+
| ---------- | ---------- | --------- | ------- |
|
|
45
|
+
| `label` | `label` | `string` | `''` |
|
|
46
|
+
| `required` | `required` | `boolean` | `false` |
|
|
47
|
+
|
|
48
|
+
| Slot | Description |
|
|
49
|
+
| --------- | -------------------- |
|
|
50
|
+
| _default_ | The control to label |
|
|
51
|
+
|
|
52
|
+
| Part | Description |
|
|
53
|
+
| ------- | ------------- |
|
|
54
|
+
| `label` | The `<label>` |
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# `<kt-meter>`
|
|
2
|
+
|
|
3
|
+
How a fixed total is spent: storage by file type, a budget by category, seats by
|
|
4
|
+
role.
|
|
5
|
+
|
|
6
|
+
```html
|
|
7
|
+
<kt-meter label="Storage" used="25.8 GB used" total="of 983 GB" value="3"></kt-meter>
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
meter.segments = [
|
|
12
|
+
{ label: 'Documents', value: 16.14 },
|
|
13
|
+
{ label: 'Photos', value: 3.94 },
|
|
14
|
+
{ label: 'Other', value: 5.72 },
|
|
15
|
+
];
|
|
16
|
+
meter.max = 983;
|
|
17
|
+
meter.showLegend = true;
|
|
18
|
+
meter.format = (n) => `${n} GB`;
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Against `<kt-progress-bar>`
|
|
22
|
+
|
|
23
|
+
A progress bar answers **how far along**: it fills toward completion, and
|
|
24
|
+
reaching the end is good news — which is why it turns green there. A meter
|
|
25
|
+
answers **how it is divided**: it is full from the moment it renders, and
|
|
26
|
+
reaching the end is bad news.
|
|
27
|
+
|
|
28
|
+
Different question, different component. A bar that shows one and means the
|
|
29
|
+
other is a common way to mislead a reader, so the two are not a variant of each
|
|
30
|
+
other here.
|
|
31
|
+
|
|
32
|
+
## Segments and colour
|
|
33
|
+
|
|
34
|
+
Segments take `--chart-series-N` by position — the same fixed, never-cycled
|
|
35
|
+
order the charts use, so a category is the same colour in the meter and in the
|
|
36
|
+
chart beside it. Pass `color` to override one. Past eight, fold the tail into
|
|
37
|
+
an "Other" segment rather than starting the palette again under a new meaning.
|
|
38
|
+
|
|
39
|
+
Adjacent fills are separated by a 2px gap of the surface, so two segments of
|
|
40
|
+
similar hue still read as two.
|
|
41
|
+
|
|
42
|
+
Without `max`, segments are measured against their own sum and the bar is full.
|
|
43
|
+
With `max`, they are measured against it and the remainder stays empty — which
|
|
44
|
+
is what "25.8 GB of 983 GB" means.
|
|
45
|
+
|
|
46
|
+
## API
|
|
47
|
+
|
|
48
|
+
| Property | Attribute | Type | Default |
|
|
49
|
+
| ------------ | ------------- | --------------------------- | --------------- |
|
|
50
|
+
| `label` | `label` | `string` | `''` |
|
|
51
|
+
| `used` | `used` | `string` | `''` |
|
|
52
|
+
| `total` | `total` | `string` | `''` |
|
|
53
|
+
| `value` | `value` | `number` (0–100) | `0` |
|
|
54
|
+
| `segments` | — | `KtMeterSegment[]` | `[]` |
|
|
55
|
+
| `max` | `max` | `number` | `0` (their sum) |
|
|
56
|
+
| `showLegend` | `show-legend` | `boolean` | `false` |
|
|
57
|
+
| `format` | — | `(value: number) => string` | `String` |
|
|
58
|
+
|
|
59
|
+
`used` and `total` are free strings rather than numbers, because the caption is
|
|
60
|
+
prose — "25.8 GB used", "of 983 GB", "7 of 20 seats" — and formatting it is the
|
|
61
|
+
application's job, not the meter's.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
interface KtMeterSegment {
|
|
65
|
+
label: string;
|
|
66
|
+
value: number;
|
|
67
|
+
color?: string;
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
| CSS property | Description | Default |
|
|
72
|
+
| ------------------- | ---------------- | ------- |
|
|
73
|
+
| `--kt-meter-height` | The bar's height | `8px` |
|
|
74
|
+
|
|
75
|
+
| Part | Description |
|
|
76
|
+
| -------- | --------------- |
|
|
77
|
+
| `base` | The container |
|
|
78
|
+
| `track` | The bar |
|
|
79
|
+
| `legend` | The legend list |
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# `<kt-modal>`
|
|
2
|
+
|
|
3
|
+
A centred dialog for anything that is not a yes/no question.
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<kt-modal open heading="Compose" description="This goes to the whole team.">
|
|
7
|
+
<kt-textarea rows="6" placeholder="Write something..."></kt-textarea>
|
|
8
|
+
<kt-button slot="footer" variant="dark">Save draft</kt-button>
|
|
9
|
+
<kt-button slot="footer" icon="send">Send</kt-button>
|
|
10
|
+
</kt-modal>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Against `<kt-confirm-dialog>`
|
|
14
|
+
|
|
15
|
+
The confirm dialog asks one thing and offers two answers, and its defaults are
|
|
16
|
+
tuned for that — Cancel takes focus, the confirm button is red. This one holds
|
|
17
|
+
_content_: a compose window, a command palette, a picker. You choose the footer.
|
|
18
|
+
|
|
19
|
+
Both are native `<dialog>`s, so the top layer, focus containment, page
|
|
20
|
+
inertness and Escape come from the platform rather than from a focus trap that
|
|
21
|
+
leaks.
|
|
22
|
+
|
|
23
|
+
## Guarding unsaved work
|
|
24
|
+
|
|
25
|
+
`kt-close` is cancelable, and that covers Escape too:
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
modal.addEventListener('kt-close', (e) => {
|
|
29
|
+
if (!draft.dirty) return;
|
|
30
|
+
e.preventDefault();
|
|
31
|
+
confirmDiscard.open = true;
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`no-close-button` and `no-backdrop-close` narrow the ways out, but **Escape
|
|
36
|
+
always works**. A modal you cannot leave is a trap; cancelling `kt-close` is the
|
|
37
|
+
right way to guard one.
|
|
38
|
+
|
|
39
|
+
## API
|
|
40
|
+
|
|
41
|
+
| Property | Attribute | Type | Default |
|
|
42
|
+
| ----------------- | ------------------- | ------------------------------------------ | ---------- |
|
|
43
|
+
| `open` | `open` | `boolean` | `false` |
|
|
44
|
+
| `heading` | `heading` | `string` | `''` |
|
|
45
|
+
| `description` | `description` | `string` | `''` |
|
|
46
|
+
| `size` | `size` | `'small' \| 'medium' \| 'large' \| 'full'` | `'medium'` |
|
|
47
|
+
| `noCloseButton` | `no-close-button` | `boolean` | `false` |
|
|
48
|
+
| `noBackdropClose` | `no-backdrop-close` | `boolean` | `false` |
|
|
49
|
+
|
|
50
|
+
| Method | Description |
|
|
51
|
+
| ---------------- | ----------------------------------------- |
|
|
52
|
+
| `requestClose()` | Fires `kt-close`, closes unless cancelled |
|
|
53
|
+
|
|
54
|
+
| Slot | Description |
|
|
55
|
+
| --------- | -------------------------------- |
|
|
56
|
+
| _default_ | The body |
|
|
57
|
+
| `header` | Replaces the `heading` attribute |
|
|
58
|
+
| `footer` | Actions. Hidden when empty. |
|
|
59
|
+
|
|
60
|
+
| Event | Description |
|
|
61
|
+
| ---------- | -------------------------------- |
|
|
62
|
+
| `kt-close` | Dismissal requested. Cancelable. |
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# `<kt-multi-select>`
|
|
2
|
+
|
|
3
|
+
Several choices from a list: type to narrow it, pick as many as you need.
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<kt-multi-select label="Regions" placeholder="Any region"></kt-multi-select>
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
select.options = [
|
|
11
|
+
{ id: 'ne', label: 'North East' },
|
|
12
|
+
{ id: 'sw', label: 'South West' },
|
|
13
|
+
{ id: 'nw', label: 'North West' },
|
|
14
|
+
];
|
|
15
|
+
select.value = ['ne'];
|
|
16
|
+
|
|
17
|
+
select.addEventListener('kt-change', (e) => filter(e.detail.value));
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Against the alternatives
|
|
21
|
+
|
|
22
|
+
Reach for it when a filter takes several values from a list long enough to
|
|
23
|
+
search — regions, owners, tags. For two or three options that all fit on
|
|
24
|
+
screen, a `<kt-toggle-button-group multiple>` shows them without a click. For
|
|
25
|
+
one value, `<kt-input-menu>` or `<kt-select>`.
|
|
26
|
+
|
|
27
|
+
## One line, whatever is chosen
|
|
28
|
+
|
|
29
|
+
Each choice shows in the field as a chip: a fill set into the field, the same
|
|
30
|
+
distance from its top, bottom and left edge, with its own remove button — the
|
|
31
|
+
family of a chosen option, not an outlined tag. The field keeps to one line:
|
|
32
|
+
the chips that do not fit collapse into a quiet **+N** beside the ones that do,
|
|
33
|
+
or into "3 selected" when not one fits, so the field sits in a row of filters
|
|
34
|
+
without changing its height.
|
|
35
|
+
The open list shows every option, the chosen ones ticked — which is where the
|
|
36
|
+
hidden ones can be seen and taken out. Widen the field and more chips come
|
|
37
|
+
back.
|
|
38
|
+
|
|
39
|
+
## Choosing
|
|
40
|
+
|
|
41
|
+
The list stays open after each choice, since the point is to make several.
|
|
42
|
+
Clicking a chosen option, or pressing Enter on it, takes it out again; the
|
|
43
|
+
order of `value` is the order things were chosen. Disabled options can be seen
|
|
44
|
+
but not chosen.
|
|
45
|
+
|
|
46
|
+
`kt-change` fires with the whole new `value` and the matching `options`, not
|
|
47
|
+
the one that changed: a filter usually wants the full set.
|
|
48
|
+
|
|
49
|
+
## Server-side filtering
|
|
50
|
+
|
|
51
|
+
`kt-filter` fires on every keystroke, as on `<kt-input-menu>`: assign the
|
|
52
|
+
results to `options` and the list follows. Chosen values stay chosen while
|
|
53
|
+
their options are filtered out — a chip whose option is no longer in `options`
|
|
54
|
+
shows its id.
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
select.addEventListener('kt-filter', async (e) => {
|
|
58
|
+
select.options = await search(e.detail.query);
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## In a form
|
|
63
|
+
|
|
64
|
+
A form control, submitted like `<select multiple>`: one entry per chosen id
|
|
65
|
+
under `name`, and nothing at all while empty — read them with
|
|
66
|
+
`formData.getAll(name)`. `required` blocks submission until at least one value
|
|
67
|
+
is chosen, `form.reset()` puts back the values it started with, and a
|
|
68
|
+
`<fieldset disabled>` disables it.
|
|
69
|
+
|
|
70
|
+
## Accessibility
|
|
71
|
+
|
|
72
|
+
The field is an ARIA combobox over a listbox marked `aria-multiselectable`,
|
|
73
|
+
each option `aria-selected` when chosen. The number chosen is part of the
|
|
74
|
+
field's description ("2 selected"), since the chips may not all be visible.
|
|
75
|
+
Each chip's remove button is named after it — "Remove North East".
|
|
76
|
+
|
|
77
|
+
## Keyboard
|
|
78
|
+
|
|
79
|
+
| Key | Does |
|
|
80
|
+
| -------------- | -------------------------------------------------- |
|
|
81
|
+
| `↓` / `↑` | Opens the list, then moves the active option |
|
|
82
|
+
| `Home` / `End` | First / last match |
|
|
83
|
+
| `Enter` | Adds or removes the active option; the list stays |
|
|
84
|
+
| `Backspace` | In an empty field, removes the last chip |
|
|
85
|
+
| `Escape` | Closes and forgets the query, keeping every choice |
|
|
86
|
+
| `Tab` | Closes and moves on |
|
|
87
|
+
|
|
88
|
+
## API
|
|
89
|
+
|
|
90
|
+
| Property | Attribute | Type | Default |
|
|
91
|
+
| ------------- | ------------- | ---------------------- | --------------- |
|
|
92
|
+
| `options` | — | `KtOption[]` | `[]` |
|
|
93
|
+
| `value` | — | `(string \| number)[]` | `[]` |
|
|
94
|
+
| `placeholder` | `placeholder` | `string` | `''` |
|
|
95
|
+
| `name` | `name` | `string` | `''` |
|
|
96
|
+
| `disabled` | `disabled` | `boolean` | `false` |
|
|
97
|
+
| `required` | `required` | `boolean` | `false` |
|
|
98
|
+
| `error` | `error` | `string` | `''` |
|
|
99
|
+
| `label` | `label` | `string` | `''` |
|
|
100
|
+
| `emptyText` | `empty-text` | `string` | `'No options…'` |
|
|
101
|
+
|
|
102
|
+
`selectedOptions` (read-only) is the chosen options, in the order chosen.
|
|
103
|
+
|
|
104
|
+
| Event | Detail |
|
|
105
|
+
| ----------- | -------------------- |
|
|
106
|
+
| `kt-change` | `{ value, options }` |
|
|
107
|
+
| `kt-filter` | `{ query: string }` |
|
|
108
|
+
|
|
109
|
+
| Part | Description |
|
|
110
|
+
| --------- | -------------------- |
|
|
111
|
+
| `control` | The field |
|
|
112
|
+
| `chips` | The row of chips |
|
|
113
|
+
| `input` | The native `<input>` |
|
|
114
|
+
| `popup` | The option list |
|
|
115
|
+
| `option` | An option row |
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# `<kt-page-header>`
|
|
2
|
+
|
|
3
|
+
The block every screen opens with: an overline, a title, a sentence, and the
|
|
4
|
+
actions that belong to the page rather than to anything on it.
|
|
5
|
+
|
|
6
|
+
```html
|
|
7
|
+
<kt-page-header
|
|
8
|
+
eyebrow="Dashboard"
|
|
9
|
+
heading="Good evening"
|
|
10
|
+
description="An overview of your workspace: recent files, integrations and activity."
|
|
11
|
+
>
|
|
12
|
+
<kt-button slot="actions" variant="dark" icon="upload">Upload a file</kt-button>
|
|
13
|
+
<kt-button slot="actions" icon="plus">New document</kt-button>
|
|
14
|
+
</kt-page-header>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
It exists because it was being rebuilt on every screen, and the copies drifted:
|
|
18
|
+
different heading levels, different gaps, actions sometimes above the title and
|
|
19
|
+
sometimes beside it. None of those are decisions worth making twice.
|
|
20
|
+
|
|
21
|
+
## Two levels
|
|
22
|
+
|
|
23
|
+
`level="page"` (the default) renders an `<h1>` at display scale — one per
|
|
24
|
+
screen. `level="section"` renders an `<h2>` at body scale, for a region inside
|
|
25
|
+
a page, where the trailing action is usually a link onward rather than a button:
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<kt-page-header level="section" heading="Recently opened">
|
|
29
|
+
<a slot="actions" href="#/files">See all files</a>
|
|
30
|
+
</kt-page-header>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Both wrap on a narrow screen: the actions drop under the copy rather than
|
|
34
|
+
squeezing the title.
|
|
35
|
+
|
|
36
|
+
## API
|
|
37
|
+
|
|
38
|
+
| Property | Attribute | Type | Default |
|
|
39
|
+
| ------------- | ------------- | --------------------- | -------- |
|
|
40
|
+
| `eyebrow` | `eyebrow` | `string` | `''` |
|
|
41
|
+
| `heading` | `heading` | `string` | `''` |
|
|
42
|
+
| `description` | `description` | `string` | `''` |
|
|
43
|
+
| `level` | `level` | `'page' \| 'section'` | `'page'` |
|
|
44
|
+
|
|
45
|
+
| Slot | Description |
|
|
46
|
+
| --------- | ------------------------------------------- |
|
|
47
|
+
| _default_ | Extra content under the description |
|
|
48
|
+
| `actions` | Buttons or a link, trailing on wide screens |
|
|
49
|
+
|
|
50
|
+
| Part | Description |
|
|
51
|
+
| --------- | ------------------- |
|
|
52
|
+
| `base` | The container |
|
|
53
|
+
| `heading` | The heading element |
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# `<kt-pagination>`
|
|
2
|
+
|
|
3
|
+
Previous / next paging, with the position between them.
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<kt-pagination page="2" total-pages="7"></kt-pagination>
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
pager.addEventListener('kt-page-change', (e) => load(e.detail.page));
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`<kt-table>` uses it in its own footer; it is separate so a card list or a
|
|
14
|
+
gallery can page the same way a table does.
|
|
15
|
+
|
|
16
|
+
The page number is `aria-live="polite"`, so a change is announced without
|
|
17
|
+
interrupting whatever the reader is already working through. The element clamps
|
|
18
|
+
to the range: it will not emit a page below 1 or past `total-pages`.
|
|
19
|
+
|
|
20
|
+
## API
|
|
21
|
+
|
|
22
|
+
| Property | Attribute | Type | Default |
|
|
23
|
+
| ------------ | ------------- | -------- | -------------- |
|
|
24
|
+
| `page` | `page` | `number` | `1` |
|
|
25
|
+
| `totalPages` | `total-pages` | `number` | `1` |
|
|
26
|
+
| `label` | `label` | `string` | `'Pagination'` |
|
|
27
|
+
|
|
28
|
+
| Event | Detail |
|
|
29
|
+
| ---------------- | ------------------ |
|
|
30
|
+
| `kt-page-change` | `{ page: number }` |
|
|
31
|
+
|
|
32
|
+
| Part | Description |
|
|
33
|
+
| ---------- | --------------------- |
|
|
34
|
+
| `previous` | The previous button |
|
|
35
|
+
| `next` | The next button |
|
|
36
|
+
| `info` | The "Page 2 / 7" text |
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# `<kt-progress-bar>`
|
|
2
|
+
|
|
3
|
+
A determinate progress bar.
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<kt-progress-bar value="64" show-value show-label label="Importing entities"></kt-progress-bar>
|
|
7
|
+
<kt-progress-bar value="90" variant="warning" striped animated></kt-progress-bar>
|
|
8
|
+
<kt-progress-bar value="4" max="7" size="small"></kt-progress-bar>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## The caption
|
|
12
|
+
|
|
13
|
+
`show-value` puts the percentage in a caption **above** the track, not inside
|
|
14
|
+
it. A label centred over an 8px bar is half on the fill and half off it, so it
|
|
15
|
+
is unreadable at one end of the range whatever colour it is given — and at
|
|
16
|
+
`size="small"` the 4px track clips it outright. Above the bar it reads in every
|
|
17
|
+
theme, at every size, at every value.
|
|
18
|
+
|
|
19
|
+
`show-label` puts `label` in the same row, on the left. Without it `label` stays
|
|
20
|
+
the accessible name and nothing visible changes, which is right when the copy
|
|
21
|
+
around the bar already says what is progressing.
|
|
22
|
+
|
|
23
|
+
Reaching `max` switches the fill to the success colour whatever the variant, so
|
|
24
|
+
"done" reads at a glance without the caller swapping anything.
|
|
25
|
+
|
|
26
|
+
Out-of-range values are clamped and a `max` of zero is treated as 100 — a
|
|
27
|
+
progress bar should never be the thing that puts `NaN%` on screen.
|
|
28
|
+
|
|
29
|
+
## Stripes
|
|
30
|
+
|
|
31
|
+
The animated stripe is the one decorative animation in Kanto, and it earns its
|
|
32
|
+
place: it is how an operation says it is still working when the number is not
|
|
33
|
+
moving. It needs both `striped` and `animated`, and it stops under
|
|
34
|
+
`prefers-reduced-motion`.
|
|
35
|
+
|
|
36
|
+
## Accessibility
|
|
37
|
+
|
|
38
|
+
`role="progressbar"` with `aria-valuenow`/`aria-valuemax`, plus an
|
|
39
|
+
`aria-valuetext` of `"64 %"` so it is read as a percentage rather than a bare
|
|
40
|
+
number. Give it a `label` saying _what_ is progressing.
|
|
41
|
+
|
|
42
|
+
## API
|
|
43
|
+
|
|
44
|
+
| Property | Attribute | Type | Default |
|
|
45
|
+
| ----------- | ------------ | ------------------------------------------------------------------------ | ----------- |
|
|
46
|
+
| `value` | `value` | `number` | `0` |
|
|
47
|
+
| `max` | `max` | `number` | `100` |
|
|
48
|
+
| `size` | `size` | `'small' \| 'medium' \| 'large'` | `'medium'` |
|
|
49
|
+
| `showLabel` | `show-label` | `boolean` | `false` |
|
|
50
|
+
| `variant` | `variant` | `'primary' \| 'info' \| 'success' \| 'warning' \| 'danger' \| 'neutral'` | `'primary'` |
|
|
51
|
+
| `showValue` | `show-value` | `boolean` | `false` |
|
|
52
|
+
| `striped` | `striped` | `boolean` | `false` |
|
|
53
|
+
| `animated` | `animated` | `boolean` | `false` |
|
|
54
|
+
| `label` | `label` | `string` | `''` |
|
|
55
|
+
|
|
56
|
+
| Getter | Returns |
|
|
57
|
+
| --------- | ----------------------- |
|
|
58
|
+
| `percent` | Whole percentage, 0–100 |
|
|
59
|
+
|
|
60
|
+
| Part | Description |
|
|
61
|
+
| --------- | ----------------------- |
|
|
62
|
+
| `base` | The container |
|
|
63
|
+
| `caption` | The row above the track |
|
|
64
|
+
| `value` | The percentage |
|
|
65
|
+
| `track` | The groove |
|
|
66
|
+
| `fill` | The filled portion |
|