kanto-ds 1.0.0 → 1.1.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 +26 -1
- package/dist/chunks/defaults-DKzFsNbv.js +57 -0
- package/dist/chunks/defaults-DKzFsNbv.js.map +1 -0
- package/dist/chunks/form-control-CxjBTt1c.js.map +1 -1
- package/dist/chunks/kt-element-B_jjQDhg.js +38 -0
- package/dist/chunks/kt-element-B_jjQDhg.js.map +1 -0
- package/dist/chunks/{listbox-CUXYn_3S.js → listbox-Sm3nvsC6.js} +5 -5
- package/dist/chunks/{listbox-CUXYn_3S.js.map → listbox-Sm3nvsC6.js.map} +1 -1
- package/dist/components/core/kt-avatar/kt-avatar.js +9 -6
- package/dist/components/core/kt-avatar/kt-avatar.js.map +1 -1
- package/dist/components/core/kt-badge/kt-badge.js +17 -17
- package/dist/components/core/kt-badge/kt-badge.js.map +1 -1
- package/dist/components/core/kt-button/kt-button.d.ts +7 -0
- package/dist/components/core/kt-button/kt-button.js +68 -60
- package/dist/components/core/kt-button/kt-button.js.map +1 -1
- package/dist/components/core/kt-card/kt-card.js +1 -1
- package/dist/components/core/kt-code/kt-code.js +12 -12
- package/dist/components/core/kt-code/kt-code.js.map +1 -1
- package/dist/components/core/kt-icon/kt-icon.js +2 -2
- package/dist/components/core/kt-kbd/kt-kbd.js +14 -14
- package/dist/components/core/kt-kbd/kt-kbd.js.map +1 -1
- package/dist/components/core/kt-split-button/kt-split-button.d.ts +112 -0
- package/dist/components/core/kt-split-button/kt-split-button.js +262 -0
- package/dist/components/core/kt-split-button/kt-split-button.js.map +1 -0
- package/dist/components/data/kt-chart/cartesian.d.ts +62 -0
- package/dist/components/data/kt-chart/geometry.d.ts +41 -0
- package/dist/components/data/kt-chart/kt-chart.d.ts +79 -35
- package/dist/components/data/kt-chart/kt-chart.js +1200 -213
- package/dist/components/data/kt-chart/kt-chart.js.map +1 -1
- package/dist/components/data/kt-chart/model.d.ts +38 -0
- package/dist/components/data/kt-chart/point.d.ts +56 -0
- package/dist/components/data/kt-chart/radial.d.ts +60 -0
- package/dist/components/data/kt-chart/scale.d.ts +37 -0
- package/dist/components/data/kt-meter/kt-meter.js +1 -1
- package/dist/components/data/kt-pagination/kt-pagination.js +1 -1
- package/dist/components/data/kt-stat/kt-stat.js +5 -5
- package/dist/components/data/kt-stat/kt-stat.js.map +1 -1
- package/dist/components/data/kt-table/kt-table.js +2 -2
- package/dist/components/data/kt-table/kt-table.js.map +1 -1
- package/dist/components/data/kt-timeline/kt-timeline.js +1 -1
- package/dist/components/feedback/kt-alert/kt-alert.js +26 -26
- package/dist/components/feedback/kt-alert/kt-alert.js.map +1 -1
- package/dist/components/feedback/kt-empty-state/kt-empty-state.js +1 -1
- package/dist/components/feedback/kt-progress-bar/kt-progress-bar.js +2 -2
- package/dist/components/feedback/kt-progress-bar/kt-progress-bar.js.map +1 -1
- package/dist/components/feedback/kt-skeleton/kt-skeleton.js +1 -1
- package/dist/components/feedback/kt-toast/kt-toast.js +22 -22
- package/dist/components/feedback/kt-toast/kt-toast.js.map +1 -1
- package/dist/components/feedback/kt-toast-container/kt-toast-container.js +1 -1
- package/dist/components/feedback/kt-tooltip/kt-tooltip.js +1 -1
- package/dist/components/forms/kt-drag-drop/kt-drag-drop.d.ts +11 -1
- package/dist/components/forms/kt-drag-drop/kt-drag-drop.js +69 -36
- package/dist/components/forms/kt-drag-drop/kt-drag-drop.js.map +1 -1
- package/dist/components/forms/kt-form/kt-form.js +1 -1
- package/dist/components/forms/kt-input/kt-input.js +95 -91
- package/dist/components/forms/kt-input/kt-input.js.map +1 -1
- package/dist/components/forms/kt-input-menu/kt-input-menu.d.ts +10 -1
- package/dist/components/forms/kt-input-menu/kt-input-menu.js +83 -53
- package/dist/components/forms/kt-input-menu/kt-input-menu.js.map +1 -1
- package/dist/components/forms/kt-label-input/kt-label-input.js +2 -2
- package/dist/components/forms/kt-label-input/kt-label-input.js.map +1 -1
- package/dist/components/forms/kt-select/kt-select.js +3 -3
- package/dist/components/forms/kt-select/kt-select.js.map +1 -1
- package/dist/components/forms/kt-textarea/kt-textarea.js +15 -13
- package/dist/components/forms/kt-textarea/kt-textarea.js.map +1 -1
- package/dist/components/forms/kt-toggle/kt-toggle.js +8 -7
- package/dist/components/forms/kt-toggle/kt-toggle.js.map +1 -1
- package/dist/components/navigation/kt-breadcrumb/kt-breadcrumb.js +1 -1
- package/dist/components/navigation/kt-header/kt-header.js +1 -1
- package/dist/components/navigation/kt-page-header/kt-page-header.js +18 -18
- package/dist/components/navigation/kt-page-header/kt-page-header.js.map +1 -1
- package/dist/components/navigation/kt-segmented-control/kt-segmented-control.d.ts +10 -1
- package/dist/components/navigation/kt-segmented-control/kt-segmented-control.js +88 -62
- package/dist/components/navigation/kt-segmented-control/kt-segmented-control.js.map +1 -1
- package/dist/components/navigation/kt-sub-menu-navigation/kt-sub-menu-navigation.js +5 -5
- package/dist/components/navigation/kt-sub-menu-navigation/kt-sub-menu-navigation.js.map +1 -1
- package/dist/components/navigation/kt-tabs/kt-tabs.js +1 -1
- package/dist/components/navigation/kt-toggle-button/kt-toggle-button.js +3 -3
- package/dist/components/navigation/kt-toggle-button/kt-toggle-button.js.map +1 -1
- package/dist/components/navigation/kt-toggle-button-group/kt-toggle-button-group.js +1 -1
- package/dist/components/overlays/kt-collapsible/kt-collapsible.js +1 -1
- package/dist/components/overlays/kt-confirm-dialog/kt-confirm-dialog.js +41 -25
- package/dist/components/overlays/kt-confirm-dialog/kt-confirm-dialog.js.map +1 -1
- package/dist/components/overlays/kt-dropdown/kt-dropdown.d.ts +16 -0
- package/dist/components/overlays/kt-dropdown/kt-dropdown.js +95 -60
- package/dist/components/overlays/kt-dropdown/kt-dropdown.js.map +1 -1
- package/dist/components/overlays/kt-modal/kt-modal.js +12 -10
- package/dist/components/overlays/kt-modal/kt-modal.js.map +1 -1
- package/dist/components/overlays/kt-side-panel/kt-side-panel.js +1 -1
- package/dist/custom-elements.json +11791 -0
- package/dist/icons/index.js +7 -34
- package/dist/icons/index.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +89 -87
- package/dist/index.js.map +1 -1
- package/dist/internal/form-control.d.ts +7 -2
- package/dist/react/index.d.ts +13 -0
- package/dist/react/index.js +176 -162
- package/dist/react/index.js.map +1 -1
- package/dist/tokens/README.md +7 -3
- package/dist/tokens/colors.css +24 -5
- package/dist/tokens/theme-light.css +18 -0
- package/dist/vscode.css-custom-data.json +154 -0
- package/dist/vscode.html-custom-data.json +1136 -0
- package/dist/vue/index.d.ts +2 -0
- package/dist/vue/index.js +8 -7
- package/dist/vue/index.js.map +1 -1
- package/dist/web-types.json +3186 -0
- package/package.json +25 -6
- package/dist/chunks/kt-element-CcMLO5e8.js +0 -28
- package/dist/chunks/kt-element-CcMLO5e8.js.map +0 -1
- package/dist/chunks/registry-X4LS9J5K.js +0 -30
- package/dist/chunks/registry-X4LS9J5K.js.map +0 -1
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { css as f, nothing as c, html as a } from "lit";
|
|
2
|
+
import { query as b, state as g, property as o } from "lit/decorators.js";
|
|
3
|
+
import { classMap as y } from "lit/directives/class-map.js";
|
|
4
|
+
import { K as h, d as w } from "../../../chunks/kt-element-B_jjQDhg.js";
|
|
5
|
+
import { e as x } from "../../../chunks/events-Bjl5Zmmq.js";
|
|
6
|
+
import { f as m, o as k, l as $, n as u } from "../../../chunks/listbox-Sm3nvsC6.js";
|
|
7
|
+
import "../kt-button/kt-button.js";
|
|
8
|
+
import "../kt-icon/kt-icon.js";
|
|
9
|
+
import "../../overlays/kt-dropdown/kt-dropdown.js";
|
|
10
|
+
var I = Object.defineProperty, i = (n, t, r, l) => {
|
|
11
|
+
for (var s = void 0, d = n.length - 1, p; d >= 0; d--)
|
|
12
|
+
(p = n[d]) && (s = p(t, r, s) || s);
|
|
13
|
+
return s && I(t, r, s), s;
|
|
14
|
+
};
|
|
15
|
+
const v = { small: 16, medium: 20, large: 24 };
|
|
16
|
+
class e extends h {
|
|
17
|
+
constructor() {
|
|
18
|
+
super(...arguments), this.activeIndex = -1, this.items = [], this.variant = "primary", this.size = "medium", this.disabled = !1, this.icon = "", this.menuLabel = "More actions", this.preferredPlacement = "bottom", this.emptyText = "No actions", this.onOpen = () => {
|
|
19
|
+
this.moveTo(m(this.items));
|
|
20
|
+
}, this.onClose = () => {
|
|
21
|
+
const t = this.shadowRoot?.activeElement;
|
|
22
|
+
this.activeIndex = -1, t instanceof HTMLElement && t.classList.contains("item") && this.caret?.focus();
|
|
23
|
+
}, this.onMenuKeyDown = (t) => {
|
|
24
|
+
const l = {
|
|
25
|
+
ArrowDown: () => u(this.items, this.activeIndex, 1),
|
|
26
|
+
ArrowUp: () => u(this.items, this.activeIndex, -1),
|
|
27
|
+
Home: () => m(this.items),
|
|
28
|
+
End: () => $(this.items)
|
|
29
|
+
}[t.key];
|
|
30
|
+
l && (t.preventDefault(), this.moveTo(l()));
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
static {
|
|
34
|
+
this.styles = [
|
|
35
|
+
h.styles,
|
|
36
|
+
f`
|
|
37
|
+
:host {
|
|
38
|
+
display: inline-flex;
|
|
39
|
+
vertical-align: middle;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* A hairline of the page showing through is the seam between the two
|
|
43
|
+
segments — the same trick the rest of the system uses for elevation,
|
|
44
|
+
where a border would have been. */
|
|
45
|
+
.split {
|
|
46
|
+
display: inline-flex;
|
|
47
|
+
align-items: stretch;
|
|
48
|
+
gap: var(--border-width);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.action::part(button) {
|
|
52
|
+
border-top-right-radius: 0;
|
|
53
|
+
border-bottom-right-radius: 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.caret::part(button) {
|
|
57
|
+
border-top-left-radius: 0;
|
|
58
|
+
border-bottom-left-radius: 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.menu {
|
|
62
|
+
display: flex;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
gap: var(--gap-element);
|
|
65
|
+
max-height: 208px;
|
|
66
|
+
overflow: auto;
|
|
67
|
+
scrollbar-width: thin;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.item {
|
|
71
|
+
display: flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
gap: var(--gap-button);
|
|
74
|
+
width: 100%;
|
|
75
|
+
padding: var(--padding-expand-item);
|
|
76
|
+
color: var(--text-muted);
|
|
77
|
+
font: var(--font-normal-regular);
|
|
78
|
+
text-align: left;
|
|
79
|
+
background: none;
|
|
80
|
+
border: none;
|
|
81
|
+
border-radius: var(--radius-input);
|
|
82
|
+
cursor: pointer;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.item:hover {
|
|
86
|
+
color: var(--text-body);
|
|
87
|
+
background: var(--surface-hover);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Inset, so the ring is never clipped by the panel it scrolls inside. */
|
|
91
|
+
.item:focus-visible {
|
|
92
|
+
outline: var(--outline-width) solid var(--color-primary-base);
|
|
93
|
+
outline-offset: calc(-1 * var(--outline-width));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.item.danger {
|
|
97
|
+
color: var(--color-danger-text);
|
|
98
|
+
}
|
|
99
|
+
.item.danger:hover {
|
|
100
|
+
color: var(--color-danger-text);
|
|
101
|
+
background: var(--color-danger-soft);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.item[aria-disabled='true'] {
|
|
105
|
+
color: var(--text-disabled);
|
|
106
|
+
cursor: not-allowed;
|
|
107
|
+
}
|
|
108
|
+
.item[aria-disabled='true']:hover {
|
|
109
|
+
color: var(--text-disabled);
|
|
110
|
+
background: none;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.empty {
|
|
114
|
+
padding: var(--padding-expand-item);
|
|
115
|
+
color: var(--text-muted);
|
|
116
|
+
font: var(--font-normal-small);
|
|
117
|
+
cursor: default;
|
|
118
|
+
}
|
|
119
|
+
`
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
/** Whether the menu is showing. */
|
|
123
|
+
get isOpen() {
|
|
124
|
+
return this.dropdown?.isOpen ?? !1;
|
|
125
|
+
}
|
|
126
|
+
/** Opens the menu. */
|
|
127
|
+
show() {
|
|
128
|
+
this.dropdown?.show();
|
|
129
|
+
}
|
|
130
|
+
/** Closes it. */
|
|
131
|
+
hide() {
|
|
132
|
+
this.dropdown?.hide();
|
|
133
|
+
}
|
|
134
|
+
/** Either. */
|
|
135
|
+
toggle() {
|
|
136
|
+
this.dropdown?.toggle();
|
|
137
|
+
}
|
|
138
|
+
/** Moves focus to the primary segment. */
|
|
139
|
+
focus(t) {
|
|
140
|
+
this.shadowRoot?.querySelector(".action")?.focus(t);
|
|
141
|
+
}
|
|
142
|
+
row(t) {
|
|
143
|
+
return this.shadowRoot?.querySelectorAll(".item")[t] ?? null;
|
|
144
|
+
}
|
|
145
|
+
/** Lands the roving tabindex on `index` and takes focus there. */
|
|
146
|
+
async moveTo(t) {
|
|
147
|
+
t < 0 || (this.activeIndex = t, await this.updateComplete, this.row(t)?.focus());
|
|
148
|
+
}
|
|
149
|
+
choose(t) {
|
|
150
|
+
t.disabled || (this.hide(), x(this, "kt-select", { value: t.id, item: t }));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* A click anywhere in the menu stops here. It originates inside this
|
|
154
|
+
* element's shadow root, so without this it would surface on the host as a
|
|
155
|
+
* `click` and be mistaken for the primary action.
|
|
156
|
+
*/
|
|
157
|
+
containClick(t) {
|
|
158
|
+
t.stopPropagation();
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* The caret drives the panel itself rather than leaning on the click
|
|
162
|
+
* reaching `<kt-dropdown>`'s own trigger through the slot: stopping here
|
|
163
|
+
* keeps the press off the host, and leaving it to bubble would toggle twice.
|
|
164
|
+
*/
|
|
165
|
+
onCaretClick(t) {
|
|
166
|
+
t.stopPropagation(), this.toggle();
|
|
167
|
+
}
|
|
168
|
+
renderItem(t, r) {
|
|
169
|
+
return a`<button
|
|
170
|
+
part="item"
|
|
171
|
+
class=${y({ item: !0, danger: t.variant === "danger" })}
|
|
172
|
+
type="button"
|
|
173
|
+
role="menuitem"
|
|
174
|
+
tabindex=${r === this.activeIndex ? 0 : -1}
|
|
175
|
+
aria-disabled=${t.disabled ? "true" : c}
|
|
176
|
+
@click=${() => this.choose(t)}
|
|
177
|
+
>
|
|
178
|
+
${t.icon ? a`<kt-icon name=${t.icon} size=${v[this.size]}></kt-icon>` : c}
|
|
179
|
+
${k(t)}
|
|
180
|
+
</button>`;
|
|
181
|
+
}
|
|
182
|
+
render() {
|
|
183
|
+
return a`<div class="split">
|
|
184
|
+
<!-- The icon is slotted rather than passed as \`icon\`: <kt-button> reads
|
|
185
|
+
its own text content to decide whether it is icon-only, and a <slot>
|
|
186
|
+
has none, so setting \`icon\` here would collapse it to a square. -->
|
|
187
|
+
<kt-button
|
|
188
|
+
part="action"
|
|
189
|
+
class="action"
|
|
190
|
+
variant=${this.variant}
|
|
191
|
+
size=${this.size}
|
|
192
|
+
?disabled=${this.disabled}
|
|
193
|
+
>
|
|
194
|
+
${this.icon ? a`<kt-icon name=${this.icon} size=${v[this.size]}></kt-icon>` : c}
|
|
195
|
+
<slot></slot>
|
|
196
|
+
</kt-button>
|
|
197
|
+
|
|
198
|
+
<kt-dropdown
|
|
199
|
+
align="end"
|
|
200
|
+
preferred-placement=${this.preferredPlacement}
|
|
201
|
+
?disabled=${this.disabled}
|
|
202
|
+
@click=${this.containClick}
|
|
203
|
+
@kt-open=${this.onOpen}
|
|
204
|
+
@kt-close=${this.onClose}
|
|
205
|
+
>
|
|
206
|
+
<kt-button
|
|
207
|
+
slot="trigger"
|
|
208
|
+
part="caret"
|
|
209
|
+
class="caret"
|
|
210
|
+
variant=${this.variant}
|
|
211
|
+
size=${this.size}
|
|
212
|
+
icon="chevron-down"
|
|
213
|
+
label=${this.menuLabel}
|
|
214
|
+
?disabled=${this.disabled}
|
|
215
|
+
@click=${this.onCaretClick}
|
|
216
|
+
></kt-button>
|
|
217
|
+
|
|
218
|
+
<div slot="panel" part="menu" class="menu" role="menu" @keydown=${this.onMenuKeyDown}>
|
|
219
|
+
${this.items.length > 0 ? this.items.map((t, r) => this.renderItem(t, r)) : a`<div class="empty">${this.emptyText}</div>`}
|
|
220
|
+
</div>
|
|
221
|
+
</kt-dropdown>
|
|
222
|
+
</div>`;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
i([
|
|
226
|
+
b("kt-dropdown")
|
|
227
|
+
], e.prototype, "dropdown");
|
|
228
|
+
i([
|
|
229
|
+
b(".caret")
|
|
230
|
+
], e.prototype, "caret");
|
|
231
|
+
i([
|
|
232
|
+
g()
|
|
233
|
+
], e.prototype, "activeIndex");
|
|
234
|
+
i([
|
|
235
|
+
o({ attribute: !1 })
|
|
236
|
+
], e.prototype, "items");
|
|
237
|
+
i([
|
|
238
|
+
o({ type: String, reflect: !0 })
|
|
239
|
+
], e.prototype, "variant");
|
|
240
|
+
i([
|
|
241
|
+
o({ type: String, reflect: !0 })
|
|
242
|
+
], e.prototype, "size");
|
|
243
|
+
i([
|
|
244
|
+
o({ type: Boolean, reflect: !0 })
|
|
245
|
+
], e.prototype, "disabled");
|
|
246
|
+
i([
|
|
247
|
+
o({ type: String })
|
|
248
|
+
], e.prototype, "icon");
|
|
249
|
+
i([
|
|
250
|
+
o({ type: String, attribute: "menu-label" })
|
|
251
|
+
], e.prototype, "menuLabel");
|
|
252
|
+
i([
|
|
253
|
+
o({ type: String, attribute: "preferred-placement" })
|
|
254
|
+
], e.prototype, "preferredPlacement");
|
|
255
|
+
i([
|
|
256
|
+
o({ type: String, attribute: "empty-text" })
|
|
257
|
+
], e.prototype, "emptyText");
|
|
258
|
+
w("kt-split-button", e);
|
|
259
|
+
export {
|
|
260
|
+
e as KtSplitButton
|
|
261
|
+
};
|
|
262
|
+
//# sourceMappingURL=kt-split-button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kt-split-button.js","sources":["../../../../src/components/core/kt-split-button/kt-split-button.ts"],"sourcesContent":["import { css, html, nothing, type TemplateResult } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { emit } from '#internal/events';\nimport {\n firstEnabledIndex,\n lastEnabledIndex,\n nextEnabledIndex,\n optionLabel,\n type KtOption,\n} from '#internal/listbox';\nimport type { KtButtonSize, KtButtonVariant } from '../kt-button/kt-button.js';\nimport type { KtDropdown, KtDropdownPlacement } from '../../overlays/kt-dropdown/kt-dropdown.js';\nimport '../kt-button/kt-button.js';\nimport '../kt-icon/kt-icon.js';\nimport '../../overlays/kt-dropdown/kt-dropdown.js';\n\n/** A row of the menu. `danger` tints it, for the one action to think twice about. */\nexport interface KtSplitButtonItem extends KtOption {\n readonly icon?: string;\n readonly variant?: 'default' | 'danger';\n}\n\n/** Icon size per button size, matching `<kt-button>`. */\nconst ICON_SIZE: Record<KtButtonSize, number> = { small: 16, medium: 20, large: 24 };\n\n/**\n * One button carrying a menu of related actions.\n *\n * The body runs the action a user wants nine times out of ten and emits a\n * plain `click`; the caret opens the rest. Reach for it when the alternatives\n * are variations on the same action — \"Save and close\", \"Save a copy\" — and\n * for an unrelated set of actions use `<kt-dropdown>` instead, which has no\n * default action to promote.\n *\n * A caret press never reads as a `click` on the host, so a single `click`\n * listener means the primary action and nothing else.\n *\n * @element kt-split-button\n *\n * @slot - The primary action's label.\n *\n * @csspart action - The primary `<kt-button>`.\n * @csspart caret - The `<kt-button>` that opens the menu.\n * @csspart menu - The list of rows.\n * @csspart item - A menu row.\n *\n * @fires kt-select - A menu row was chosen. `detail: { value, item }`.\n * @fires kt-open - The menu opened.\n * @fires kt-close - The menu closed.\n *\n * @example\n * ```html\n * <kt-split-button>Save</kt-split-button>\n * ```\n * ```js\n * el.items = [\n * { id: 'close', label: 'Save and close' },\n * { id: 'discard', label: 'Discard', variant: 'danger' },\n * ];\n * el.addEventListener('kt-select', (e) => run(e.detail.value));\n * ```\n */\nexport class KtSplitButton extends KtElement {\n static override styles = [\n KtElement.styles,\n css`\n :host {\n display: inline-flex;\n vertical-align: middle;\n }\n\n /* A hairline of the page showing through is the seam between the two\n segments — the same trick the rest of the system uses for elevation,\n where a border would have been. */\n .split {\n display: inline-flex;\n align-items: stretch;\n gap: var(--border-width);\n }\n\n .action::part(button) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n\n .caret::part(button) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n\n .menu {\n display: flex;\n flex-direction: column;\n gap: var(--gap-element);\n max-height: 208px;\n overflow: auto;\n scrollbar-width: thin;\n }\n\n .item {\n display: flex;\n align-items: center;\n gap: var(--gap-button);\n width: 100%;\n padding: var(--padding-expand-item);\n color: var(--text-muted);\n font: var(--font-normal-regular);\n text-align: left;\n background: none;\n border: none;\n border-radius: var(--radius-input);\n cursor: pointer;\n }\n\n .item:hover {\n color: var(--text-body);\n background: var(--surface-hover);\n }\n\n /* Inset, so the ring is never clipped by the panel it scrolls inside. */\n .item:focus-visible {\n outline: var(--outline-width) solid var(--color-primary-base);\n outline-offset: calc(-1 * var(--outline-width));\n }\n\n .item.danger {\n color: var(--color-danger-text);\n }\n .item.danger:hover {\n color: var(--color-danger-text);\n background: var(--color-danger-soft);\n }\n\n .item[aria-disabled='true'] {\n color: var(--text-disabled);\n cursor: not-allowed;\n }\n .item[aria-disabled='true']:hover {\n color: var(--text-disabled);\n background: none;\n }\n\n .empty {\n padding: var(--padding-expand-item);\n color: var(--text-muted);\n font: var(--font-normal-small);\n cursor: default;\n }\n `,\n ];\n\n @query('kt-dropdown')\n private dropdown?: KtDropdown;\n\n @query('.caret')\n private caret?: HTMLElement & { focus(): void };\n\n /** The row the roving tabindex currently sits on. */\n @state()\n private activeIndex = -1;\n\n /** The menu rows. */\n @property({ attribute: false })\n items: readonly KtSplitButtonItem[] = [];\n\n /** Visual variant, forwarded to both segments. */\n @property({ type: String, reflect: true })\n variant: KtButtonVariant = 'primary';\n\n /** Height, forwarded to both segments. */\n @property({ type: String, reflect: true })\n size: KtButtonSize = 'medium';\n\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /** Lucide icon name for the primary segment. */\n @property({ type: String })\n icon = '';\n\n /** Accessible name of the caret, which has no text of its own. */\n @property({ type: String, attribute: 'menu-label' })\n menuLabel = 'More actions';\n\n /** Where to put the menu when there is room on both sides. */\n @property({ type: String, attribute: 'preferred-placement' })\n preferredPlacement: KtDropdownPlacement = 'bottom';\n\n @property({ type: String, attribute: 'empty-text' })\n emptyText = 'No actions';\n\n /** Whether the menu is showing. */\n get isOpen(): boolean {\n return this.dropdown?.isOpen ?? false;\n }\n\n /** Opens the menu. */\n show(): void {\n this.dropdown?.show();\n }\n\n /** Closes it. */\n hide(): void {\n this.dropdown?.hide();\n }\n\n /** Either. */\n toggle(): void {\n this.dropdown?.toggle();\n }\n\n /** Moves focus to the primary segment. */\n override focus(options?: FocusOptions): void {\n this.shadowRoot?.querySelector<HTMLElement>('.action')?.focus(options);\n }\n\n private row(index: number): HTMLElement | null {\n return this.shadowRoot?.querySelectorAll<HTMLElement>('.item')[index] ?? null;\n }\n\n /** Lands the roving tabindex on `index` and takes focus there. */\n private async moveTo(index: number): Promise<void> {\n if (index < 0) return;\n this.activeIndex = index;\n await this.updateComplete;\n this.row(index)?.focus();\n }\n\n private onOpen = (): void => {\n void this.moveTo(firstEnabledIndex(this.items));\n };\n\n /**\n * Returns focus to the caret, but only when it was inside the menu — an\n * outside click already moved it somewhere the user chose, and pulling it\n * back here would undo that.\n */\n private onClose = (): void => {\n const active = this.shadowRoot?.activeElement;\n this.activeIndex = -1;\n if (active instanceof HTMLElement && active.classList.contains('item')) this.caret?.focus();\n };\n\n private onMenuKeyDown = (event: KeyboardEvent): void => {\n const moves: Record<string, () => number> = {\n ArrowDown: () => nextEnabledIndex(this.items, this.activeIndex, 1),\n ArrowUp: () => nextEnabledIndex(this.items, this.activeIndex, -1),\n Home: () => firstEnabledIndex(this.items),\n End: () => lastEnabledIndex(this.items),\n };\n\n const move = moves[event.key];\n if (!move) return;\n\n event.preventDefault();\n void this.moveTo(move());\n };\n\n private choose(item: KtSplitButtonItem): void {\n if (item.disabled) return;\n this.hide();\n emit(this, 'kt-select', { value: item.id, item });\n }\n\n /**\n * A click anywhere in the menu stops here. It originates inside this\n * element's shadow root, so without this it would surface on the host as a\n * `click` and be mistaken for the primary action.\n */\n private containClick(event: Event): void {\n event.stopPropagation();\n }\n\n /**\n * The caret drives the panel itself rather than leaning on the click\n * reaching `<kt-dropdown>`'s own trigger through the slot: stopping here\n * keeps the press off the host, and leaving it to bubble would toggle twice.\n */\n private onCaretClick(event: Event): void {\n event.stopPropagation();\n this.toggle();\n }\n\n private renderItem(item: KtSplitButtonItem, index: number): TemplateResult {\n return html`<button\n part=\"item\"\n class=${classMap({ item: true, danger: item.variant === 'danger' })}\n type=\"button\"\n role=\"menuitem\"\n tabindex=${index === this.activeIndex ? 0 : -1}\n aria-disabled=${item.disabled ? 'true' : nothing}\n @click=${() => this.choose(item)}\n >\n ${\n item.icon\n ? html`<kt-icon name=${item.icon} size=${ICON_SIZE[this.size]}></kt-icon>`\n : nothing\n }\n ${optionLabel(item)}\n </button>`;\n }\n\n override render(): TemplateResult {\n return html`<div class=\"split\">\n <!-- The icon is slotted rather than passed as \\`icon\\`: <kt-button> reads\n its own text content to decide whether it is icon-only, and a <slot>\n has none, so setting \\`icon\\` here would collapse it to a square. -->\n <kt-button\n part=\"action\"\n class=\"action\"\n variant=${this.variant}\n size=${this.size}\n ?disabled=${this.disabled}\n >\n ${\n this.icon\n ? html`<kt-icon name=${this.icon} size=${ICON_SIZE[this.size]}></kt-icon>`\n : nothing\n }\n <slot></slot>\n </kt-button>\n\n <kt-dropdown\n align=\"end\"\n preferred-placement=${this.preferredPlacement}\n ?disabled=${this.disabled}\n @click=${this.containClick}\n @kt-open=${this.onOpen}\n @kt-close=${this.onClose}\n >\n <kt-button\n slot=\"trigger\"\n part=\"caret\"\n class=\"caret\"\n variant=${this.variant}\n size=${this.size}\n icon=\"chevron-down\"\n label=${this.menuLabel}\n ?disabled=${this.disabled}\n @click=${this.onCaretClick}\n ></kt-button>\n\n <div slot=\"panel\" part=\"menu\" class=\"menu\" role=\"menu\" @keydown=${this.onMenuKeyDown}>\n ${\n this.items.length > 0\n ? this.items.map((item, index) => this.renderItem(item, index))\n : html`<div class=\"empty\">${this.emptyText}</div>`\n }\n </div>\n </kt-dropdown>\n </div>`;\n }\n}\n\ndefineElement('kt-split-button', KtSplitButton);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-split-button': KtSplitButton;\n }\n}\n"],"names":["ICON_SIZE","KtSplitButton","KtElement","firstEnabledIndex","active","event","move","nextEnabledIndex","lastEnabledIndex","css","options","index","item","emit","html","classMap","nothing","optionLabel","__decorateClass","query","state","property","defineElement"],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type SVGTemplateResult } from 'lit';
|
|
2
|
+
import type { Format, KtMark, KtSeries, Measure, PlotBox } from './model.js';
|
|
3
|
+
import { type Ticks } from './scale.js';
|
|
4
|
+
/**
|
|
5
|
+
* Line, area and bar charts: one category axis, one value axis.
|
|
6
|
+
*
|
|
7
|
+
* The layout is computed once per render and every position is read from it,
|
|
8
|
+
* so the marks, the labels, the tooltip and the hit test cannot disagree about
|
|
9
|
+
* where a category is.
|
|
10
|
+
*/
|
|
11
|
+
export interface CartesianInput {
|
|
12
|
+
readonly width: number;
|
|
13
|
+
readonly height: number;
|
|
14
|
+
readonly series: readonly KtSeries[];
|
|
15
|
+
readonly hidden: ReadonlySet<number>;
|
|
16
|
+
readonly labels: readonly string[];
|
|
17
|
+
/** The chart's mark; a series can override it with its own `type`. */
|
|
18
|
+
readonly type: KtMark;
|
|
19
|
+
readonly stacked: boolean;
|
|
20
|
+
readonly horizontal: boolean;
|
|
21
|
+
readonly min: number | null;
|
|
22
|
+
readonly max: number | null;
|
|
23
|
+
readonly noAxis: boolean;
|
|
24
|
+
readonly measure: Measure;
|
|
25
|
+
readonly format: Format;
|
|
26
|
+
}
|
|
27
|
+
export interface CartesianLayout {
|
|
28
|
+
readonly box: PlotBox;
|
|
29
|
+
readonly ticks: Ticks;
|
|
30
|
+
/** How many categories there are. */
|
|
31
|
+
readonly count: number;
|
|
32
|
+
readonly horizontal: boolean;
|
|
33
|
+
/** Categories are bands rather than points — true as soon as a bar is shown. */
|
|
34
|
+
readonly banded: boolean;
|
|
35
|
+
/** The mark each series is drawn as, by series index. */
|
|
36
|
+
readonly marks: readonly KtMark[];
|
|
37
|
+
/** Indices of the series that are not hidden. */
|
|
38
|
+
readonly visible: readonly number[];
|
|
39
|
+
}
|
|
40
|
+
export declare function cartesianLayout(input: CartesianInput): CartesianLayout;
|
|
41
|
+
/** Where category `index` sits along its axis, in px. */
|
|
42
|
+
export declare function categoryCentre(layout: CartesianLayout, index: number): number;
|
|
43
|
+
/** Where `value` sits along the value axis, in px. */
|
|
44
|
+
export declare function valuePosition(layout: CartesianLayout, value: number): number;
|
|
45
|
+
/** The category under a pointer at `x`, `y`: the band it is in, or the nearest sample. */
|
|
46
|
+
export declare function categoryAt(layout: CartesianLayout, x: number, y: number): number;
|
|
47
|
+
export interface CartesianView extends CartesianInput {
|
|
48
|
+
readonly layout: CartesianLayout;
|
|
49
|
+
/** The active category, or -1. */
|
|
50
|
+
readonly active: number;
|
|
51
|
+
readonly smooth: boolean;
|
|
52
|
+
readonly noGrid: boolean;
|
|
53
|
+
readonly colorOf: (series: number) => string;
|
|
54
|
+
/** Prefix for ids inside the shadow root, so two charts never share a gradient. */
|
|
55
|
+
readonly idPrefix: string;
|
|
56
|
+
}
|
|
57
|
+
export declare function renderCartesian(view: CartesianView): SVGTemplateResult;
|
|
58
|
+
/** Where the tooltip for the active category points: at its tallest mark. */
|
|
59
|
+
export declare function tooltipAnchor(view: CartesianView): {
|
|
60
|
+
x: number;
|
|
61
|
+
y: number;
|
|
62
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SVG path geometry for the chart's marks. Every function is pure and writes
|
|
3
|
+
* coordinates rounded to two decimals, so paths stay short and comparable.
|
|
4
|
+
*/
|
|
5
|
+
export type Point = readonly [number, number];
|
|
6
|
+
/** One cubic Bézier piece of a curve. */
|
|
7
|
+
export interface Segment {
|
|
8
|
+
readonly from: Point;
|
|
9
|
+
readonly c1: Point;
|
|
10
|
+
readonly c2: Point;
|
|
11
|
+
readonly to: Point;
|
|
12
|
+
}
|
|
13
|
+
export declare const TAU: number;
|
|
14
|
+
export declare const round: (value: number) => number;
|
|
15
|
+
/** Straight segments through `points`. `move` false continues an open path. */
|
|
16
|
+
export declare function linearPath(points: readonly Point[], move?: boolean): string;
|
|
17
|
+
/**
|
|
18
|
+
* A monotone cubic through `points` (Fritsch–Carlson).
|
|
19
|
+
*
|
|
20
|
+
* Between two samples the curve stays within their range, so it never draws a
|
|
21
|
+
* peak or a dip that is not in the data — the failure of the cardinal splines
|
|
22
|
+
* most charts use. Needs at least three points; fewer have nothing to smooth.
|
|
23
|
+
*/
|
|
24
|
+
export declare function monotoneSegments(points: readonly Point[]): Segment[];
|
|
25
|
+
/** A monotone curve as a path, or straight segments when there is nothing to smooth. */
|
|
26
|
+
export declare function monotonePath(points: readonly Point[], move?: boolean): string;
|
|
27
|
+
/** The point at `radius` and `angle` from a centre; 0 is twelve o'clock, clockwise. */
|
|
28
|
+
export declare function polar(cx: number, cy: number, radius: number, angle: number): Point;
|
|
29
|
+
/**
|
|
30
|
+
* A slice from `start` to `end`: a wedge to the centre when `inner` is 0, an
|
|
31
|
+
* annular sector otherwise. A whole turn is drawn as circles (and a hole, with
|
|
32
|
+
* `fill-rule="evenodd"`) because a single SVG arc cannot close on itself.
|
|
33
|
+
*/
|
|
34
|
+
export declare function arcPath(cx: number, cy: number, inner: number, outer: number, start: number, end: number): string;
|
|
35
|
+
/** Which end of a bar is rounded. The baseline end always stays square. */
|
|
36
|
+
export type Tip = 'top' | 'bottom' | 'left' | 'right' | 'none';
|
|
37
|
+
/**
|
|
38
|
+
* A bar, rounded at its tip only. A bar rounded at the baseline too floats
|
|
39
|
+
* above the axis instead of standing on it.
|
|
40
|
+
*/
|
|
41
|
+
export declare function barPath(x: number, y: number, width: number, height: number, radius: number, tip: Tip): string;
|
|
@@ -1,25 +1,20 @@
|
|
|
1
1
|
import { type TemplateResult } from 'lit';
|
|
2
2
|
import { KtElement } from '#internal/kt-element';
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
readonly name: string;
|
|
6
|
-
readonly values: readonly number[];
|
|
7
|
-
/** Overrides the slot this series would take from the categorical order. */
|
|
8
|
-
readonly color?: string;
|
|
9
|
-
}
|
|
3
|
+
import type { Format, KtChartType, KtSeries } from './model.js';
|
|
4
|
+
export type { KtChartType, KtMark, KtPoint, KtSeries } from './model.js';
|
|
10
5
|
/**
|
|
11
|
-
* A
|
|
6
|
+
* A chart, drawn from the token layer.
|
|
12
7
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
8
|
+
* Line, area and bar — stacked, sideways or mixed — plus scatter, bubble,
|
|
9
|
+
* pie, doughnut, polar area and radar, all in Kanto's voice: the eight
|
|
10
|
+
* categorical hues in fixed order, one value axis, recessive grid, and the
|
|
11
|
+
* data always available as a table.
|
|
16
12
|
*
|
|
17
13
|
* **Colour.** One series takes the brand hue: with nothing to tell apart there
|
|
18
14
|
* is no identity to encode, and the title names it. Two or more take the fixed
|
|
19
15
|
* categorical order in `--chart-series-1…8`, assigned by position and never
|
|
20
16
|
* cycled, so a series keeps its colour when a filter removes its neighbours.
|
|
21
|
-
*
|
|
22
|
-
* mistaken for a status.
|
|
17
|
+
* Slices take the same order by slice.
|
|
23
18
|
*
|
|
24
19
|
* **The table is not optional.** Every chart also renders its data as a table,
|
|
25
20
|
* visually hidden by default. It is what a screen reader reads, and it is the
|
|
@@ -29,11 +24,14 @@ export interface KtSeries {
|
|
|
29
24
|
* @element kt-chart
|
|
30
25
|
*
|
|
31
26
|
* @csspart svg - The plot.
|
|
32
|
-
* @csspart legend - The legend
|
|
27
|
+
* @csspart legend - The legend.
|
|
33
28
|
* @csspart table - The data table.
|
|
34
29
|
*
|
|
35
|
-
* @fires kt-point-hover - The
|
|
36
|
-
*
|
|
30
|
+
* @fires kt-point-hover - The active point changed. `detail: { index, series }`;
|
|
31
|
+
* `index` is -1 when nothing is active, `series` -1 when the index spans
|
|
32
|
+
* every series.
|
|
33
|
+
* @fires kt-series-toggle - A legend item was pressed. `detail: { series, hidden }`.
|
|
34
|
+
* Cancelable.
|
|
37
35
|
*
|
|
38
36
|
* @example
|
|
39
37
|
* ```js
|
|
@@ -47,49 +45,95 @@ export declare class KtChart extends KtElement {
|
|
|
47
45
|
private observer?;
|
|
48
46
|
private readonly tableId;
|
|
49
47
|
private box;
|
|
48
|
+
/** The active category, point or slice, or -1. */
|
|
50
49
|
private active;
|
|
50
|
+
/** The series the active point belongs to, for scatter and bubble; -1 otherwise. */
|
|
51
|
+
private activeSeries;
|
|
52
|
+
/**
|
|
53
|
+
* Series hidden from the legend — or slices, for pie, doughnut and polar
|
|
54
|
+
* area. Not `hidden`: that is HTMLElement's, and shadowing it would stop
|
|
55
|
+
* `chart.hidden = true` from hiding the chart.
|
|
56
|
+
*/
|
|
57
|
+
private hiddenSeries;
|
|
51
58
|
type: KtChartType;
|
|
52
59
|
series: readonly KtSeries[];
|
|
53
|
-
/** One label per index along the
|
|
60
|
+
/** One label per index along the category axis, or per slice or spoke. */
|
|
54
61
|
labels: readonly string[];
|
|
55
62
|
height: number;
|
|
56
|
-
/** Formats a value for the tooltip and the table. */
|
|
57
|
-
format:
|
|
58
|
-
/**
|
|
63
|
+
/** Formats a value for the value axis, the tooltip and the table. */
|
|
64
|
+
format: Format;
|
|
65
|
+
/** Formats the x value of a scatter or bubble point. */
|
|
66
|
+
formatX: Format;
|
|
67
|
+
/** Grid lines. */
|
|
59
68
|
noGrid: boolean;
|
|
69
|
+
/** Hides the value axis labels, for a chart too small to carry them. */
|
|
70
|
+
noAxis: boolean;
|
|
60
71
|
/** Puts the data table on screen instead of only in the accessibility tree. */
|
|
61
72
|
showTable: boolean;
|
|
62
73
|
/**
|
|
63
|
-
* Smooths
|
|
74
|
+
* Smooths lines and areas through a monotone spline.
|
|
64
75
|
*
|
|
65
76
|
* Off by default on purpose: a curve between two samples draws values that
|
|
66
77
|
* were never measured. Turn it on when the underlying quantity really is
|
|
67
78
|
* continuous and the reader knows it.
|
|
68
79
|
*/
|
|
69
80
|
smooth: boolean;
|
|
81
|
+
/** Bars, and areas, on top of one another instead of side by side. */
|
|
82
|
+
stacked: boolean;
|
|
83
|
+
/** Bars along the horizontal axis, with the categories down the left. */
|
|
84
|
+
horizontal: boolean;
|
|
85
|
+
/** Pins the bottom of the value axis. */
|
|
86
|
+
min: number | null;
|
|
87
|
+
/** Pins the top of the value axis. */
|
|
88
|
+
max: number | null;
|
|
89
|
+
/** Names the total in the middle of a doughnut. */
|
|
90
|
+
centerLabel: string;
|
|
91
|
+
/** Names the sum in a stacked chart's tooltip and table. */
|
|
92
|
+
totalLabel: string;
|
|
70
93
|
/** Accessible name. Say what the chart shows. */
|
|
71
94
|
label: string;
|
|
72
95
|
connectedCallback(): void;
|
|
73
96
|
firstUpdated(): void;
|
|
74
97
|
disconnectedCallback(): void;
|
|
75
|
-
|
|
98
|
+
willUpdate(changed: Map<PropertyKey, unknown>): void;
|
|
99
|
+
private get family();
|
|
76
100
|
private get pointCount();
|
|
77
|
-
private
|
|
78
|
-
private
|
|
79
|
-
|
|
80
|
-
private
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
private
|
|
101
|
+
private colorOf;
|
|
102
|
+
private measureContext;
|
|
103
|
+
/** Text width in the axis font. Estimated where there is no canvas to ask. */
|
|
104
|
+
private measure;
|
|
105
|
+
private get cartesianView();
|
|
106
|
+
private get pointView();
|
|
107
|
+
/** Pie, doughnut and polar area: one series, whose slices are the labels. */
|
|
108
|
+
private get sliced();
|
|
109
|
+
private sliceColor;
|
|
110
|
+
private get radialView();
|
|
111
|
+
/** Whether there is anything to draw. */
|
|
112
|
+
private get hasData();
|
|
113
|
+
private setActive;
|
|
86
114
|
private onPointerMove;
|
|
87
115
|
private onPointerLeave;
|
|
88
|
-
|
|
89
|
-
private
|
|
90
|
-
|
|
91
|
-
|
|
116
|
+
/** How many positions the keyboard walks through, in order. */
|
|
117
|
+
private get stops();
|
|
118
|
+
/**
|
|
119
|
+
* Arrows walk the points, Home and End jump to the ends, Escape lets go.
|
|
120
|
+
* Every move emits `kt-point-hover` and opens the tooltip, which is a live
|
|
121
|
+
* region, so a keyboard user hears what a pointer user sees.
|
|
122
|
+
*/
|
|
123
|
+
private onKeyDown;
|
|
124
|
+
/**
|
|
125
|
+
* Scatter and bubble: left and right walk the current series in x order,
|
|
126
|
+
* up and down move to the neighbouring visible series.
|
|
127
|
+
*/
|
|
128
|
+
private onPointKeyDown;
|
|
129
|
+
private toggle;
|
|
130
|
+
private renderMarks;
|
|
131
|
+
private get tooltip();
|
|
92
132
|
private renderTooltip;
|
|
133
|
+
private renderLegend;
|
|
134
|
+
private renderPointTable;
|
|
135
|
+
private renderSliceTable;
|
|
136
|
+
private renderTable;
|
|
93
137
|
render(): TemplateResult;
|
|
94
138
|
}
|
|
95
139
|
declare global {
|