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.
Files changed (113) hide show
  1. package/README.md +26 -1
  2. package/dist/chunks/defaults-DKzFsNbv.js +57 -0
  3. package/dist/chunks/defaults-DKzFsNbv.js.map +1 -0
  4. package/dist/chunks/form-control-CxjBTt1c.js.map +1 -1
  5. package/dist/chunks/kt-element-B_jjQDhg.js +38 -0
  6. package/dist/chunks/kt-element-B_jjQDhg.js.map +1 -0
  7. package/dist/chunks/{listbox-CUXYn_3S.js → listbox-Sm3nvsC6.js} +5 -5
  8. package/dist/chunks/{listbox-CUXYn_3S.js.map → listbox-Sm3nvsC6.js.map} +1 -1
  9. package/dist/components/core/kt-avatar/kt-avatar.js +9 -6
  10. package/dist/components/core/kt-avatar/kt-avatar.js.map +1 -1
  11. package/dist/components/core/kt-badge/kt-badge.js +17 -17
  12. package/dist/components/core/kt-badge/kt-badge.js.map +1 -1
  13. package/dist/components/core/kt-button/kt-button.d.ts +7 -0
  14. package/dist/components/core/kt-button/kt-button.js +68 -60
  15. package/dist/components/core/kt-button/kt-button.js.map +1 -1
  16. package/dist/components/core/kt-card/kt-card.js +1 -1
  17. package/dist/components/core/kt-code/kt-code.js +12 -12
  18. package/dist/components/core/kt-code/kt-code.js.map +1 -1
  19. package/dist/components/core/kt-icon/kt-icon.js +2 -2
  20. package/dist/components/core/kt-kbd/kt-kbd.js +14 -14
  21. package/dist/components/core/kt-kbd/kt-kbd.js.map +1 -1
  22. package/dist/components/core/kt-split-button/kt-split-button.d.ts +112 -0
  23. package/dist/components/core/kt-split-button/kt-split-button.js +262 -0
  24. package/dist/components/core/kt-split-button/kt-split-button.js.map +1 -0
  25. package/dist/components/data/kt-chart/cartesian.d.ts +62 -0
  26. package/dist/components/data/kt-chart/geometry.d.ts +41 -0
  27. package/dist/components/data/kt-chart/kt-chart.d.ts +79 -35
  28. package/dist/components/data/kt-chart/kt-chart.js +1200 -213
  29. package/dist/components/data/kt-chart/kt-chart.js.map +1 -1
  30. package/dist/components/data/kt-chart/model.d.ts +38 -0
  31. package/dist/components/data/kt-chart/point.d.ts +56 -0
  32. package/dist/components/data/kt-chart/radial.d.ts +60 -0
  33. package/dist/components/data/kt-chart/scale.d.ts +37 -0
  34. package/dist/components/data/kt-meter/kt-meter.js +1 -1
  35. package/dist/components/data/kt-pagination/kt-pagination.js +1 -1
  36. package/dist/components/data/kt-stat/kt-stat.js +5 -5
  37. package/dist/components/data/kt-stat/kt-stat.js.map +1 -1
  38. package/dist/components/data/kt-table/kt-table.js +2 -2
  39. package/dist/components/data/kt-table/kt-table.js.map +1 -1
  40. package/dist/components/data/kt-timeline/kt-timeline.js +1 -1
  41. package/dist/components/feedback/kt-alert/kt-alert.js +26 -26
  42. package/dist/components/feedback/kt-alert/kt-alert.js.map +1 -1
  43. package/dist/components/feedback/kt-empty-state/kt-empty-state.js +1 -1
  44. package/dist/components/feedback/kt-progress-bar/kt-progress-bar.js +2 -2
  45. package/dist/components/feedback/kt-progress-bar/kt-progress-bar.js.map +1 -1
  46. package/dist/components/feedback/kt-skeleton/kt-skeleton.js +1 -1
  47. package/dist/components/feedback/kt-toast/kt-toast.js +22 -22
  48. package/dist/components/feedback/kt-toast/kt-toast.js.map +1 -1
  49. package/dist/components/feedback/kt-toast-container/kt-toast-container.js +1 -1
  50. package/dist/components/feedback/kt-tooltip/kt-tooltip.js +1 -1
  51. package/dist/components/forms/kt-drag-drop/kt-drag-drop.d.ts +11 -1
  52. package/dist/components/forms/kt-drag-drop/kt-drag-drop.js +69 -36
  53. package/dist/components/forms/kt-drag-drop/kt-drag-drop.js.map +1 -1
  54. package/dist/components/forms/kt-form/kt-form.js +1 -1
  55. package/dist/components/forms/kt-input/kt-input.js +95 -91
  56. package/dist/components/forms/kt-input/kt-input.js.map +1 -1
  57. package/dist/components/forms/kt-input-menu/kt-input-menu.d.ts +10 -1
  58. package/dist/components/forms/kt-input-menu/kt-input-menu.js +83 -53
  59. package/dist/components/forms/kt-input-menu/kt-input-menu.js.map +1 -1
  60. package/dist/components/forms/kt-label-input/kt-label-input.js +2 -2
  61. package/dist/components/forms/kt-label-input/kt-label-input.js.map +1 -1
  62. package/dist/components/forms/kt-select/kt-select.js +3 -3
  63. package/dist/components/forms/kt-select/kt-select.js.map +1 -1
  64. package/dist/components/forms/kt-textarea/kt-textarea.js +15 -13
  65. package/dist/components/forms/kt-textarea/kt-textarea.js.map +1 -1
  66. package/dist/components/forms/kt-toggle/kt-toggle.js +8 -7
  67. package/dist/components/forms/kt-toggle/kt-toggle.js.map +1 -1
  68. package/dist/components/navigation/kt-breadcrumb/kt-breadcrumb.js +1 -1
  69. package/dist/components/navigation/kt-header/kt-header.js +1 -1
  70. package/dist/components/navigation/kt-page-header/kt-page-header.js +18 -18
  71. package/dist/components/navigation/kt-page-header/kt-page-header.js.map +1 -1
  72. package/dist/components/navigation/kt-segmented-control/kt-segmented-control.d.ts +10 -1
  73. package/dist/components/navigation/kt-segmented-control/kt-segmented-control.js +88 -62
  74. package/dist/components/navigation/kt-segmented-control/kt-segmented-control.js.map +1 -1
  75. package/dist/components/navigation/kt-sub-menu-navigation/kt-sub-menu-navigation.js +5 -5
  76. package/dist/components/navigation/kt-sub-menu-navigation/kt-sub-menu-navigation.js.map +1 -1
  77. package/dist/components/navigation/kt-tabs/kt-tabs.js +1 -1
  78. package/dist/components/navigation/kt-toggle-button/kt-toggle-button.js +3 -3
  79. package/dist/components/navigation/kt-toggle-button/kt-toggle-button.js.map +1 -1
  80. package/dist/components/navigation/kt-toggle-button-group/kt-toggle-button-group.js +1 -1
  81. package/dist/components/overlays/kt-collapsible/kt-collapsible.js +1 -1
  82. package/dist/components/overlays/kt-confirm-dialog/kt-confirm-dialog.js +41 -25
  83. package/dist/components/overlays/kt-confirm-dialog/kt-confirm-dialog.js.map +1 -1
  84. package/dist/components/overlays/kt-dropdown/kt-dropdown.d.ts +16 -0
  85. package/dist/components/overlays/kt-dropdown/kt-dropdown.js +95 -60
  86. package/dist/components/overlays/kt-dropdown/kt-dropdown.js.map +1 -1
  87. package/dist/components/overlays/kt-modal/kt-modal.js +12 -10
  88. package/dist/components/overlays/kt-modal/kt-modal.js.map +1 -1
  89. package/dist/components/overlays/kt-side-panel/kt-side-panel.js +1 -1
  90. package/dist/custom-elements.json +11791 -0
  91. package/dist/icons/index.js +7 -34
  92. package/dist/icons/index.js.map +1 -1
  93. package/dist/index.d.ts +4 -2
  94. package/dist/index.js +89 -87
  95. package/dist/index.js.map +1 -1
  96. package/dist/internal/form-control.d.ts +7 -2
  97. package/dist/react/index.d.ts +13 -0
  98. package/dist/react/index.js +176 -162
  99. package/dist/react/index.js.map +1 -1
  100. package/dist/tokens/README.md +7 -3
  101. package/dist/tokens/colors.css +24 -5
  102. package/dist/tokens/theme-light.css +18 -0
  103. package/dist/vscode.css-custom-data.json +154 -0
  104. package/dist/vscode.html-custom-data.json +1136 -0
  105. package/dist/vue/index.d.ts +2 -0
  106. package/dist/vue/index.js +8 -7
  107. package/dist/vue/index.js.map +1 -1
  108. package/dist/web-types.json +3186 -0
  109. package/package.json +25 -6
  110. package/dist/chunks/kt-element-CcMLO5e8.js +0 -28
  111. package/dist/chunks/kt-element-CcMLO5e8.js.map +0 -1
  112. package/dist/chunks/registry-X4LS9J5K.js +0 -30
  113. package/dist/chunks/registry-X4LS9J5K.js.map +0 -1
package/README.md CHANGED
@@ -25,6 +25,13 @@ import 'kanto-ds/styles.css';
25
25
 
26
26
  ---
27
27
 
28
+ ## Showcase
29
+
30
+ ![dashboard.png](demo/public/dashboard.png)
31
+
32
+ | ![guide.png](demo/public/guide.png) | ![component.png](demo/public/component.png) |
33
+ | ----------------------------------- | ------------------------------------------- |
34
+
28
35
  ## Why custom elements
29
36
 
30
37
  One implementation, every framework. The alternative — a React port, a Vue
@@ -79,7 +86,7 @@ Forty-two elements. Each has a page beside its source.
79
86
 
80
87
  | Group | Elements |
81
88
  | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
82
- | **Core** | [button](src/components/core/kt-button/kt-button.md) · [card](src/components/core/kt-card/kt-card.md) · [code](src/components/core/kt-code/kt-code.md) · [icon](src/components/core/kt-icon/kt-icon.md) · [avatar](src/components/core/kt-avatar/kt-avatar.md) · [badge](src/components/core/kt-badge/kt-badge.md) · [kbd](src/components/core/kt-kbd/kt-kbd.md) |
89
+ | **Core** | [button](src/components/core/kt-button/kt-button.md) · [split-button](src/components/core/kt-split-button/kt-split-button.md) · [card](src/components/core/kt-card/kt-card.md) · [code](src/components/core/kt-code/kt-code.md) · [icon](src/components/core/kt-icon/kt-icon.md) · [avatar](src/components/core/kt-avatar/kt-avatar.md) · [badge](src/components/core/kt-badge/kt-badge.md) · [kbd](src/components/core/kt-kbd/kt-kbd.md) |
83
90
  | **Forms** | [input](src/components/forms/kt-input/kt-input.md) · [textarea](src/components/forms/kt-textarea/kt-textarea.md) · [label-input](src/components/forms/kt-label-input/kt-label-input.md) · [form](src/components/forms/kt-form/kt-form.md) · [select](src/components/forms/kt-select/kt-select.md) · [input-menu](src/components/forms/kt-input-menu/kt-input-menu.md) · [toggle](src/components/forms/kt-toggle/kt-toggle.md) · [drag-drop](src/components/forms/kt-drag-drop/kt-drag-drop.md) |
84
91
  | **Navigation** | [header](src/components/navigation/kt-header/kt-header.md) · [breadcrumb](src/components/navigation/kt-breadcrumb/kt-breadcrumb.md) · [sub-menu-navigation](src/components/navigation/kt-sub-menu-navigation/kt-sub-menu-navigation.md) · [page-header](src/components/navigation/kt-page-header/kt-page-header.md) · [tabs](src/components/navigation/kt-tabs/kt-tabs.md) · [segmented-control](src/components/navigation/kt-segmented-control/kt-segmented-control.md) · [toggle-button](src/components/navigation/kt-toggle-button/kt-toggle-button.md) · [toggle-button-group](src/components/navigation/kt-toggle-button-group/kt-toggle-button-group.md) |
85
92
  | **Feedback** | [progress-bar](src/components/feedback/kt-progress-bar/kt-progress-bar.md) · [skeleton](src/components/feedback/kt-skeleton/kt-skeleton.md) · [tooltip](src/components/feedback/kt-tooltip/kt-tooltip.md) · [toast](src/components/feedback/kt-toast/kt-toast.md) · [toast-container + toaster](src/components/feedback/kt-toast-container/kt-toast-container.md) · [alert](src/components/feedback/kt-alert/kt-alert.md) · [empty-state](src/components/feedback/kt-empty-state/kt-empty-state.md) |
@@ -121,6 +128,24 @@ input — no hidden mirror inputs, no manual wiring.
121
128
  </form>
122
129
  ```
123
130
 
131
+ ## Editor support
132
+
133
+ The package ships a [Custom Elements Manifest](https://custom-elements-manifest.open-wc.org/)
134
+ — every element's attributes, properties, events, slots and CSS parts — and
135
+ editor data generated from it, so plain HTML gets completion and hover docs:
136
+
137
+ - **WebStorm / JetBrains** read `web-types.json` from the package on their own.
138
+ - **VS Code** needs pointing at it once, in `.vscode/settings.json`:
139
+
140
+ ```json
141
+ {
142
+ "html.customData": ["./node_modules/kanto-ds/dist/vscode.html-custom-data.json"],
143
+ "css.customData": ["./node_modules/kanto-ds/dist/vscode.css-custom-data.json"]
144
+ }
145
+ ```
146
+
147
+ - **Storybook** and API-docs generators take `kanto-ds/custom-elements.json`.
148
+
124
149
  ## Accessibility
125
150
 
126
151
  Not a phase at the end; it is why several of these components exist in this
@@ -0,0 +1,57 @@
1
+ import { X as s, User as a, TriangleAlert as c, Trash2 as i, Search as f, Menu as g, LoaderCircle as p, Info as u, FileUp as y, File as A, EyeOff as C, Eye as l, Copy as I, CircleCheck as h, CircleAlert as w, ChevronUp as $, ChevronRight as b, ChevronLeft as d, ChevronDown as v, Check as U, ArrowUp as Z, ArrowDown as k } from "lucide";
2
+ const n = /* @__PURE__ */ new Map();
3
+ function t(e) {
4
+ return e.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-zA-Z])(\d)/g, "$1-$2").replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
5
+ }
6
+ function m(e, r) {
7
+ n.set(t(e), r);
8
+ }
9
+ function z(e) {
10
+ for (const [r, o] of Object.entries(e))
11
+ L(o) && m(r, o);
12
+ }
13
+ function E(e) {
14
+ return n.get(t(e));
15
+ }
16
+ function F() {
17
+ return [...n.keys()].sort();
18
+ }
19
+ function L(e) {
20
+ return Array.isArray(e) && e.every(
21
+ (r) => Array.isArray(r) && typeof r[0] == "string" && typeof r[1] == "object" && r[1] !== null
22
+ );
23
+ }
24
+ const j = {
25
+ ArrowDown: k,
26
+ ArrowUp: Z,
27
+ Check: U,
28
+ ChevronDown: v,
29
+ ChevronLeft: d,
30
+ ChevronRight: b,
31
+ ChevronUp: $,
32
+ CircleAlert: w,
33
+ CircleCheck: h,
34
+ Copy: I,
35
+ Eye: l,
36
+ EyeOff: C,
37
+ File: A,
38
+ FileUp: y,
39
+ Info: u,
40
+ LoaderCircle: p,
41
+ Menu: g,
42
+ Search: f,
43
+ Trash2: i,
44
+ TriangleAlert: c,
45
+ User: a,
46
+ X: s
47
+ };
48
+ z(j);
49
+ export {
50
+ z as a,
51
+ F as b,
52
+ j as d,
53
+ E as g,
54
+ m as r,
55
+ t
56
+ };
57
+ //# sourceMappingURL=defaults-DKzFsNbv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults-DKzFsNbv.js","sources":["../../src/icons/registry.ts","../../src/icons/defaults.ts"],"sourcesContent":["/**\n * The icon registry.\n *\n * `<kt-icon>` looks icons up by name at render time, which means the set of\n * icons cannot be statically analysed and a bundler cannot tree-shake it. So\n * Kanto does not bundle all two thousand Lucide icons: the elements register\n * the handful they need themselves, and an application registers whatever else\n * it uses.\n *\n * import { Rocket, Wallet } from 'lucide';\n * import { registerIcons } from 'kanto-ds/icons';\n *\n * registerIcons({ Rocket, Wallet });\n *\n * Names are normalised to kebab-case, so `Rocket`, `rocket` and\n * `ChevronDown` / `chevron-down` all resolve.\n */\n\n/** A Lucide icon: a flat list of SVG children, each `[tag, attributes]`. */\nexport type IconNode = [tag: string, attrs: Record<string, string | number | undefined>][];\n\nconst registry = new Map<string, IconNode>();\n\n/**\n * `ChevronDown` → `chevron-down`, `Trash2` → `trash-2`, `AArrowDown` →\n * `a-arrow-down`.\n *\n * The digit boundary matters: Lucide names that icon `trash-2`, so a rule that\n * only splits on case produces `trash2` and the lookup quietly misses.\n */\nexport function toKebabCase(name: string): string {\n return name\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2') // acronym run before a word\n .replace(/([a-zA-Z])(\\d)/g, '$1-$2') // letter before a digit\n .replace(/([a-z])([A-Z])/g, '$1-$2') // ordinary camel boundary\n .replace(/[\\s_]+/g, '-')\n .toLowerCase();\n}\n\n/** Registers a single icon under `name`. */\nexport function registerIcon(name: string, node: IconNode): void {\n registry.set(toKebabCase(name), node);\n}\n\n/**\n * Registers a map of icons. Accepts a Lucide namespace import directly:\n * every non-icon export (`createElement`, `createIcons`, …) is skipped.\n */\nexport function registerIcons(icons: Record<string, unknown>): void {\n for (const [name, node] of Object.entries(icons)) {\n if (isIconNode(node)) registerIcon(name, node);\n }\n}\n\n/** Returns the icon registered under `name`, or `undefined`. */\nexport function getIcon(name: string): IconNode | undefined {\n return registry.get(toKebabCase(name));\n}\n\n/** Every registered name, kebab-cased and sorted. Useful for docs and tests. */\nexport function registeredIcons(): string[] {\n return [...registry.keys()].sort();\n}\n\nfunction isIconNode(value: unknown): value is IconNode {\n return (\n Array.isArray(value) &&\n value.every(\n (child) =>\n Array.isArray(child) &&\n typeof child[0] === 'string' &&\n typeof child[1] === 'object' &&\n child[1] !== null,\n )\n );\n}\n","/**\n * The icons the design system uses in its own elements.\n *\n * Importing any Kanto element pulls this set in — roughly 2 kB of path data,\n * the price of `<kt-select>` being able to draw its own chevron. Application\n * icons are registered separately through `registerIcons`.\n */\nimport {\n ArrowDown,\n ArrowUp,\n Check,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n ChevronUp,\n CircleAlert,\n CircleCheck,\n Copy,\n Eye,\n EyeOff,\n File,\n FileUp,\n Info,\n LoaderCircle,\n Menu,\n Search,\n Trash2,\n TriangleAlert,\n User,\n X,\n} from 'lucide';\n// The sibling registry, not the `kanto-ds` barrel: the barrel pulls in every\n// element, and one of them pulls in this file — a cycle that leaves\n// `registerIcons` undefined by the time the call below runs.\nimport { registerIcons } from './registry.js';\n\n/** Icons referenced by Kanto elements, keyed by their Lucide name. */\nexport const defaultIcons = {\n ArrowDown,\n ArrowUp,\n Check,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n ChevronUp,\n CircleAlert,\n CircleCheck,\n Copy,\n Eye,\n EyeOff,\n File,\n FileUp,\n Info,\n LoaderCircle,\n Menu,\n Search,\n Trash2,\n TriangleAlert,\n User,\n X,\n};\n\nregisterIcons(defaultIcons);\n"],"names":["registry","toKebabCase","name","registerIcon","node","registerIcons","icons","isIconNode","getIcon","registeredIcons","value","child","defaultIcons","ArrowDown","ArrowUp","Check","ChevronDown","ChevronLeft","ChevronRight","ChevronUp","CircleAlert","CircleCheck","Copy","Eye","EyeOff","File","FileUp","Info","LoaderCircle","Menu","Search","Trash2","TriangleAlert","User","X"],"mappings":";AAqBA,MAAMA,wBAAe,IAAA;AASd,SAASC,EAAYC,GAAsB;AAChD,SAAOA,EACJ,QAAQ,yBAAyB,OAAO,EACxC,QAAQ,mBAAmB,OAAO,EAClC,QAAQ,mBAAmB,OAAO,EAClC,QAAQ,WAAW,GAAG,EACtB,YAAA;AACL;AAGO,SAASC,EAAaD,GAAcE,GAAsB;AAC/D,EAAAJ,EAAS,IAAIC,EAAYC,CAAI,GAAGE,CAAI;AACtC;AAMO,SAASC,EAAcC,GAAsC;AAClE,aAAW,CAACJ,GAAME,CAAI,KAAK,OAAO,QAAQE,CAAK;AAC7C,IAAIC,EAAWH,CAAI,KAAGD,EAAaD,GAAME,CAAI;AAEjD;AAGO,SAASI,EAAQN,GAAoC;AAC1D,SAAOF,EAAS,IAAIC,EAAYC,CAAI,CAAC;AACvC;AAGO,SAASO,IAA4B;AAC1C,SAAO,CAAC,GAAGT,EAAS,KAAA,CAAM,EAAE,KAAA;AAC9B;AAEA,SAASO,EAAWG,GAAmC;AACrD,SACE,MAAM,QAAQA,CAAK,KACnBA,EAAM;AAAA,IACJ,CAACC,MACC,MAAM,QAAQA,CAAK,KACnB,OAAOA,EAAM,CAAC,KAAM,YACpB,OAAOA,EAAM,CAAC,KAAM,YACpBA,EAAM,CAAC,MAAM;AAAA,EAAA;AAGrB;ACtCO,MAAMC,IAAe;AAAA,EAC1B,WAAAC;AAAA,EACA,SAAAC;AAAA,EACA,OAAAC;AAAA,EACA,aAAAC;AAAA,EACA,aAAAC;AAAA,EACA,cAAAC;AAAA,EACA,WAAAC;AAAA,EACA,aAAAC;AAAA,EACA,aAAAC;AAAA,EACA,MAAAC;AAAA,EACA,KAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAC;AAAA,EACA,cAAAC;AAAA,EACA,MAAAC;AAAA,EACA,QAAAC;AAAA,EACA,QAAAC;AAAA,EACA,eAAAC;AAAA,EACA,MAAAC;AAAA,EACA,GAAAC;AACF;AAEA7B,EAAcO,CAAY;"}
@@ -1 +1 @@
1
- {"version":3,"file":"form-control-CxjBTt1c.js","sources":["../../src/internal/form-control.ts"],"sourcesContent":["/**\n * Form participation for Kanto's input elements.\n *\n * A control inside a shadow root is invisible to the form around it. The\n * platform's answer is `ElementInternals`: the element declares\n * `static formAssociated = true`, calls `attachInternals()` and pushes its\n * value in with `setFormValue`, which makes it a first-class form control —\n * serialised into `FormData`, reset by `form.reset()`, validated by\n * `form.checkValidity()`.\n *\n * Every browser Kanto targets supports this. Test environments do not: neither\n * happy-dom nor jsdom implements it, and jsdom stubs `attachInternals` with an\n * object that has no `setFormValue`. So each call is guarded, and an element\n * still works — minus form serialisation — where the API is missing.\n */\n\n/** An `ElementInternals` implementation complete enough to be worth calling. */\nexport type UsableInternals = ElementInternals;\n\nexport function attachFormInternals(host: HTMLElement): UsableInternals | null {\n if (typeof host.attachInternals !== 'function') return null;\n\n const internals = host.attachInternals();\n if (typeof internals.setFormValue !== 'function') return null;\n\n return internals;\n}\n\n/** Pushes the control's current value into the enclosing form, if there is one. */\nexport function setFormValue(internals: UsableInternals | null, value: string | null): void {\n internals?.setFormValue(value);\n}\n\n/**\n * Mirrors a control's validity onto the host element.\n *\n * `anchor` is the element a browser scrolls to and anchors the native bubble\n * against when the form is submitted invalid.\n */\nexport function setValidity(\n internals: UsableInternals | null,\n flags: ValidityStateFlags,\n message: string,\n anchor?: HTMLElement,\n): void {\n if (!internals || typeof internals.setValidity !== 'function') return;\n if (Object.values(flags).some(Boolean)) internals.setValidity(flags, message, anchor);\n else internals.setValidity({});\n}\n"],"names":["attachFormInternals","host","internals","setFormValue","value","setValidity","flags","message","anchor"],"mappings":"AAmBO,SAASA,EAAoBC,GAA2C;AAC7E,MAAI,OAAOA,EAAK,mBAAoB,WAAY,QAAO;AAEvD,QAAMC,IAAYD,EAAK,gBAAA;AACvB,SAAI,OAAOC,EAAU,gBAAiB,aAAmB,OAElDA;AACT;AAGO,SAASC,EAAaD,GAAmCE,GAA4B;AAC1F,EAAAF,GAAW,aAAaE,CAAK;AAC/B;AAQO,SAASC,EACdH,GACAI,GACAC,GACAC,GACM;AACN,EAAI,CAACN,KAAa,OAAOA,EAAU,eAAgB,eAC/C,OAAO,OAAOI,CAAK,EAAE,KAAK,OAAO,IAAGJ,EAAU,YAAYI,GAAOC,GAASC,CAAM,IAC/EN,EAAU,YAAY,EAAE;AAC/B;"}
1
+ {"version":3,"file":"form-control-CxjBTt1c.js","sources":["../../src/internal/form-control.ts"],"sourcesContent":["/**\n * Form participation for Kanto's input elements.\n *\n * A control inside a shadow root is invisible to the form around it. The\n * platform's answer is `ElementInternals`: the element declares\n * `static formAssociated = true`, calls `attachInternals()` and pushes its\n * value in with `setFormValue`, which makes it a first-class form control —\n * serialised into `FormData`, reset by `form.reset()`, validated by\n * `form.checkValidity()`.\n *\n * Every browser Kanto targets supports this. Test environments do not: neither\n * happy-dom nor jsdom implements it, and jsdom stubs `attachInternals` with an\n * object that has no `setFormValue`. So each call is guarded, and an element\n * still works — minus form serialisation — where the API is missing.\n */\n\n/** An `ElementInternals` implementation complete enough to be worth calling. */\nexport type UsableInternals = ElementInternals;\n\nexport function attachFormInternals(host: HTMLElement): UsableInternals | null {\n if (typeof host.attachInternals !== 'function') return null;\n\n const internals = host.attachInternals();\n if (typeof internals.setFormValue !== 'function') return null;\n\n return internals;\n}\n\n/**\n * Pushes the control's current value into the enclosing form, if there is one.\n *\n * A `FormData` submits each of its entries as they are named in it — which is\n * how one control contributes several files under one name.\n */\nexport function setFormValue(\n internals: UsableInternals | null,\n value: string | FormData | null,\n): void {\n internals?.setFormValue(value);\n}\n\n/**\n * Mirrors a control's validity onto the host element.\n *\n * `anchor` is the element a browser scrolls to and anchors the native bubble\n * against when the form is submitted invalid.\n */\nexport function setValidity(\n internals: UsableInternals | null,\n flags: ValidityStateFlags,\n message: string,\n anchor?: HTMLElement,\n): void {\n if (!internals || typeof internals.setValidity !== 'function') return;\n if (Object.values(flags).some(Boolean)) internals.setValidity(flags, message, anchor);\n else internals.setValidity({});\n}\n"],"names":["attachFormInternals","host","internals","setFormValue","value","setValidity","flags","message","anchor"],"mappings":"AAmBO,SAASA,EAAoBC,GAA2C;AAC7E,MAAI,OAAOA,EAAK,mBAAoB,WAAY,QAAO;AAEvD,QAAMC,IAAYD,EAAK,gBAAA;AACvB,SAAI,OAAOC,EAAU,gBAAiB,aAAmB,OAElDA;AACT;AAQO,SAASC,EACdD,GACAE,GACM;AACN,EAAAF,GAAW,aAAaE,CAAK;AAC/B;AAQO,SAASC,EACdH,GACAI,GACAC,GACAC,GACM;AACN,EAAI,CAACN,KAAa,OAAOA,EAAU,eAAgB,eAC/C,OAAO,OAAOI,CAAK,EAAE,KAAK,OAAO,IAAGJ,EAAU,YAAYI,GAAOC,GAASC,CAAM,IAC/EN,EAAU,YAAY,EAAE;AAC/B;"}
@@ -0,0 +1,38 @@
1
+ import { LitElement as i, css as s } from "lit";
2
+ class o extends i {
3
+ static {
4
+ this.styles = s`
5
+ :host {
6
+ box-sizing: border-box;
7
+ }
8
+
9
+ :host([hidden]) {
10
+ display: none !important;
11
+ }
12
+
13
+ *,
14
+ *::before,
15
+ *::after {
16
+ box-sizing: inherit;
17
+ }
18
+
19
+ /* Read by assistive technology, never drawn. */
20
+ .visually-hidden {
21
+ position: absolute;
22
+ width: 1px;
23
+ height: 1px;
24
+ overflow: hidden;
25
+ clip-path: inset(50%);
26
+ white-space: nowrap;
27
+ }
28
+ `;
29
+ }
30
+ }
31
+ function d(e, t) {
32
+ customElements.get(e) || customElements.define(e, t);
33
+ }
34
+ export {
35
+ o as K,
36
+ d
37
+ };
38
+ //# sourceMappingURL=kt-element-B_jjQDhg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kt-element-B_jjQDhg.js","sources":["../../src/internal/kt-element.ts"],"sourcesContent":["import { LitElement, css, type CSSResultGroup } from 'lit';\n\n/**\n * Base class for every Kanto element.\n *\n * It exists for two reasons. First, `box-sizing: border-box` does not cross a\n * shadow boundary, so each root has to re-establish it. Second, `[hidden]`\n * loses to a `:host { display: flex }` rule inside the shadow root, and every\n * element in this system sets its own display — without the override here,\n * hiding a Kanto element from the outside silently does nothing.\n */\nexport class KtElement extends LitElement {\n static override styles: CSSResultGroup = css`\n :host {\n box-sizing: border-box;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n *,\n *::before,\n *::after {\n box-sizing: inherit;\n }\n\n /* Read by assistive technology, never drawn. */\n .visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n }\n `;\n}\n\n/**\n * Registers a custom element, tolerating a repeat call.\n *\n * A design system gets loaded twice more often than you would like — two\n * versions in one dependency tree, a dev-server hot reload, a micro-frontend\n * mounting a second copy. `customElements.define` throws on a duplicate tag\n * and would take the whole page down with it.\n */\nexport function defineElement(tag: string, ctor: CustomElementConstructor): void {\n if (customElements.get(tag)) return;\n customElements.define(tag, ctor);\n}\n"],"names":["KtElement","LitElement","css","defineElement","tag","ctor"],"mappings":";AAWO,MAAMA,UAAkBC,EAAW;AAAA,EACxC,OAAA;AAAA,SAAgB,SAAyBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAyB3C;AAUO,SAASC,EAAcC,GAAaC,GAAsC;AAC/E,EAAI,eAAe,IAAID,CAAG,KAC1B,eAAe,OAAOA,GAAKC,CAAI;AACjC;"}
@@ -91,11 +91,11 @@ const f = i`
91
91
  }
92
92
  `;
93
93
  export {
94
- p as a,
95
- u as b,
96
- l as f,
97
- f as l,
94
+ f as a,
95
+ l as b,
96
+ p as f,
97
+ u as l,
98
98
  s as n,
99
99
  o
100
100
  };
101
- //# sourceMappingURL=listbox-CUXYn_3S.js.map
101
+ //# sourceMappingURL=listbox-Sm3nvsC6.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"listbox-CUXYn_3S.js","sources":["../../src/internal/listbox.ts"],"sourcesContent":["import { css } from 'lit';\n\n/**\n * Shared pieces of the two option-list controls, `<kt-select>` and\n * `<kt-input-menu>`.\n *\n * They differ in how an option is chosen — pick from a list, or filter by\n * typing — but the popup, the option rows and the keyboard model are the same,\n * and having them drift apart is how a design system stops looking like one.\n */\n\nexport interface KtOption {\n readonly id: string | number;\n readonly label?: string;\n readonly disabled?: boolean;\n}\n\n/** The text to display for an option: its label, or its id as a fallback. */\nexport function optionLabel(option: KtOption): string {\n return option.label ?? String(option.id);\n}\n\n/** Case-insensitive substring match on the visible label. */\nexport function filterOptions(options: readonly KtOption[], query: string): readonly KtOption[] {\n const needle = query.trim().toLowerCase();\n if (!needle) return options;\n return options.filter((option) => optionLabel(option).toLowerCase().includes(needle));\n}\n\n/**\n * The next selectable index in `direction`, skipping disabled options and\n * wrapping at both ends. Returns -1 when every option is disabled, so a caller\n * never lands the active descendant on something that cannot be chosen.\n */\nexport function nextEnabledIndex(\n options: readonly KtOption[],\n from: number,\n direction: 1 | -1,\n): number {\n if (options.length === 0) return -1;\n\n for (let step = 1; step <= options.length; step += 1) {\n const index = (from + direction * step + options.length * step) % options.length;\n if (!options[index]?.disabled) return index;\n }\n return -1;\n}\n\n/** The first selectable index, for opening a list with nothing selected. */\nexport function firstEnabledIndex(options: readonly KtOption[]): number {\n return options.findIndex((option) => !option.disabled);\n}\n\n/** The last selectable index, for End. */\nexport function lastEnabledIndex(options: readonly KtOption[]): number {\n for (let index = options.length - 1; index >= 0; index -= 1) {\n if (!options[index]?.disabled) return index;\n }\n return -1;\n}\n\n/**\n * The popup and option-row styles.\n *\n * The panel animates through opacity and transform while staying in the layout\n * as `visibility: hidden`, rather than being added and removed: a popup that\n * unmounts cannot animate out, and one that only sets `display: none` cannot\n * animate at all.\n */\nexport const listboxStyles = css`\n .popup {\n position: absolute;\n top: calc(var(--field-height, var(--button-height)) + 6px);\n left: 0;\n z-index: var(--z-dropdown);\n display: flex;\n flex-direction: column;\n gap: var(--gap-element);\n box-sizing: border-box;\n width: 100%;\n max-height: 300px;\n margin: 0;\n padding: var(--padding-expand);\n overflow: auto;\n list-style: none;\n background: var(--color-dark-20);\n border-radius: var(--radius-input);\n scrollbar-width: thin;\n\n visibility: hidden;\n opacity: 0;\n transform: translateY(-6px) scaleY(0.98);\n transform-origin: top left;\n pointer-events: none;\n transition:\n opacity var(--duration-fast) var(--easing-standard),\n transform var(--duration-fast) var(--easing-standard);\n }\n\n .popup.open {\n visibility: visible;\n opacity: 1;\n transform: translateY(0) scaleY(1);\n pointer-events: auto;\n }\n\n .option {\n padding: var(--padding-expand-item);\n color: var(--text-muted);\n font: var(--font-input);\n border-radius: var(--radius-input);\n cursor: pointer;\n }\n\n .option:hover,\n .option.active {\n background: var(--color-dark-22);\n }\n\n .option.selected {\n color: var(--text-body);\n font-weight: 600;\n background: var(--color-dark-23);\n }\n\n .option.disabled {\n opacity: 0.5;\n pointer-events: none;\n }\n\n .empty {\n padding: var(--padding-expand-item);\n color: var(--text-muted);\n font: var(--font-normal-small);\n pointer-events: none;\n }\n`;\n"],"names":["optionLabel","option","filterOptions","options","query","needle","nextEnabledIndex","from","direction","step","index","firstEnabledIndex","lastEnabledIndex","listboxStyles","css"],"mappings":";AAkBO,SAASA,EAAYC,GAA0B;AACpD,SAAOA,EAAO,SAAS,OAAOA,EAAO,EAAE;AACzC;AAGO,SAASC,EAAcC,GAA8BC,GAAoC;AAC9F,QAAMC,IAASD,EAAM,KAAA,EAAO,YAAA;AAC5B,SAAKC,IACEF,EAAQ,OAAO,CAACF,MAAWD,EAAYC,CAAM,EAAE,YAAA,EAAc,SAASI,CAAM,CAAC,IADhEF;AAEtB;AAOO,SAASG,EACdH,GACAI,GACAC,GACQ;AACR,MAAIL,EAAQ,WAAW,EAAG,QAAO;AAEjC,WAASM,IAAO,GAAGA,KAAQN,EAAQ,QAAQM,KAAQ,GAAG;AACpD,UAAMC,KAASH,IAAOC,IAAYC,IAAON,EAAQ,SAASM,KAAQN,EAAQ;AAC1E,QAAI,CAACA,EAAQO,CAAK,GAAG,SAAU,QAAOA;AAAA,EACxC;AACA,SAAO;AACT;AAGO,SAASC,EAAkBR,GAAsC;AACtE,SAAOA,EAAQ,UAAU,CAACF,MAAW,CAACA,EAAO,QAAQ;AACvD;AAGO,SAASW,EAAiBT,GAAsC;AACrE,WAASO,IAAQP,EAAQ,SAAS,GAAGO,KAAS,GAAGA,KAAS;AACxD,QAAI,CAACP,EAAQO,CAAK,GAAG,SAAU,QAAOA;AAExC,SAAO;AACT;AAUO,MAAMG,IAAgBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;"}
1
+ {"version":3,"file":"listbox-Sm3nvsC6.js","sources":["../../src/internal/listbox.ts"],"sourcesContent":["import { css } from 'lit';\n\n/**\n * Shared pieces of the two option-list controls, `<kt-select>` and\n * `<kt-input-menu>`.\n *\n * They differ in how an option is chosen — pick from a list, or filter by\n * typing — but the popup, the option rows and the keyboard model are the same,\n * and having them drift apart is how a design system stops looking like one.\n */\n\nexport interface KtOption {\n readonly id: string | number;\n readonly label?: string;\n readonly disabled?: boolean;\n}\n\n/** The text to display for an option: its label, or its id as a fallback. */\nexport function optionLabel(option: KtOption): string {\n return option.label ?? String(option.id);\n}\n\n/** Case-insensitive substring match on the visible label. */\nexport function filterOptions(options: readonly KtOption[], query: string): readonly KtOption[] {\n const needle = query.trim().toLowerCase();\n if (!needle) return options;\n return options.filter((option) => optionLabel(option).toLowerCase().includes(needle));\n}\n\n/**\n * The next selectable index in `direction`, skipping disabled options and\n * wrapping at both ends. Returns -1 when every option is disabled, so a caller\n * never lands the active descendant on something that cannot be chosen.\n */\nexport function nextEnabledIndex(\n options: readonly KtOption[],\n from: number,\n direction: 1 | -1,\n): number {\n if (options.length === 0) return -1;\n\n for (let step = 1; step <= options.length; step += 1) {\n const index = (from + direction * step + options.length * step) % options.length;\n if (!options[index]?.disabled) return index;\n }\n return -1;\n}\n\n/** The first selectable index, for opening a list with nothing selected. */\nexport function firstEnabledIndex(options: readonly KtOption[]): number {\n return options.findIndex((option) => !option.disabled);\n}\n\n/** The last selectable index, for End. */\nexport function lastEnabledIndex(options: readonly KtOption[]): number {\n for (let index = options.length - 1; index >= 0; index -= 1) {\n if (!options[index]?.disabled) return index;\n }\n return -1;\n}\n\n/**\n * The popup and option-row styles.\n *\n * The panel animates through opacity and transform while staying in the layout\n * as `visibility: hidden`, rather than being added and removed: a popup that\n * unmounts cannot animate out, and one that only sets `display: none` cannot\n * animate at all.\n */\nexport const listboxStyles = css`\n .popup {\n position: absolute;\n top: calc(var(--field-height, var(--button-height)) + 6px);\n left: 0;\n z-index: var(--z-dropdown);\n display: flex;\n flex-direction: column;\n gap: var(--gap-element);\n box-sizing: border-box;\n width: 100%;\n max-height: 300px;\n margin: 0;\n padding: var(--padding-expand);\n overflow: auto;\n list-style: none;\n background: var(--color-dark-20);\n border-radius: var(--radius-input);\n scrollbar-width: thin;\n\n visibility: hidden;\n opacity: 0;\n transform: translateY(-6px) scaleY(0.98);\n transform-origin: top left;\n pointer-events: none;\n transition:\n opacity var(--duration-fast) var(--easing-standard),\n transform var(--duration-fast) var(--easing-standard);\n }\n\n .popup.open {\n visibility: visible;\n opacity: 1;\n transform: translateY(0) scaleY(1);\n pointer-events: auto;\n }\n\n .option {\n padding: var(--padding-expand-item);\n color: var(--text-muted);\n font: var(--font-input);\n border-radius: var(--radius-input);\n cursor: pointer;\n }\n\n .option:hover,\n .option.active {\n background: var(--color-dark-22);\n }\n\n .option.selected {\n color: var(--text-body);\n font-weight: 600;\n background: var(--color-dark-23);\n }\n\n .option.disabled {\n opacity: 0.5;\n pointer-events: none;\n }\n\n .empty {\n padding: var(--padding-expand-item);\n color: var(--text-muted);\n font: var(--font-normal-small);\n pointer-events: none;\n }\n`;\n"],"names":["optionLabel","option","filterOptions","options","query","needle","nextEnabledIndex","from","direction","step","index","firstEnabledIndex","lastEnabledIndex","listboxStyles","css"],"mappings":";AAkBO,SAASA,EAAYC,GAA0B;AACpD,SAAOA,EAAO,SAAS,OAAOA,EAAO,EAAE;AACzC;AAGO,SAASC,EAAcC,GAA8BC,GAAoC;AAC9F,QAAMC,IAASD,EAAM,KAAA,EAAO,YAAA;AAC5B,SAAKC,IACEF,EAAQ,OAAO,CAACF,MAAWD,EAAYC,CAAM,EAAE,YAAA,EAAc,SAASI,CAAM,CAAC,IADhEF;AAEtB;AAOO,SAASG,EACdH,GACAI,GACAC,GACQ;AACR,MAAIL,EAAQ,WAAW,EAAG,QAAO;AAEjC,WAASM,IAAO,GAAGA,KAAQN,EAAQ,QAAQM,KAAQ,GAAG;AACpD,UAAMC,KAASH,IAAOC,IAAYC,IAAON,EAAQ,SAASM,KAAQN,EAAQ;AAC1E,QAAI,CAACA,EAAQO,CAAK,GAAG,SAAU,QAAOA;AAAA,EACxC;AACA,SAAO;AACT;AAGO,SAASC,EAAkBR,GAAsC;AACtE,SAAOA,EAAQ,UAAU,CAACF,MAAW,CAACA,EAAO,QAAQ;AACvD;AAGO,SAASW,EAAiBT,GAAsC;AACrE,WAASO,IAAQP,EAAQ,SAAS,GAAGO,KAAS,GAAGA,KAAS;AACxD,QAAI,CAACP,EAAQO,CAAK,GAAG,SAAU,QAAOA;AAExC,SAAO;AACT;AAUO,MAAMG,IAAgBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;"}
@@ -1,25 +1,25 @@
1
1
  import { css as p, nothing as f, html as n } from "lit";
2
2
  import { state as v, property as o } from "lit/decorators.js";
3
3
  import { classMap as c } from "lit/directives/class-map.js";
4
- import { K as u, d as g } from "../../../chunks/kt-element-CcMLO5e8.js";
4
+ import { K as d, d as g } from "../../../chunks/kt-element-B_jjQDhg.js";
5
5
  import "../kt-icon/kt-icon.js";
6
6
  var m = Object.defineProperty, s = (a, e, t, b) => {
7
7
  for (var i = void 0, l = a.length - 1, h; l >= 0; l--)
8
8
  (h = a[l]) && (i = h(e, t, i) || i);
9
9
  return i && m(e, t, i), i;
10
10
  };
11
- const d = Array.from({ length: 8 }, (a, e) => `var(--chart-series-${e + 1})`);
11
+ const u = Array.from({ length: 8 }, (a, e) => `var(--chart-series-${e + 1})`);
12
12
  function y(a) {
13
13
  const t = (a.includes("@") ? a.split("@")[0] ?? "" : a).split(/[\s._-]+/).filter(Boolean);
14
14
  return t.length === 0 ? "" : t.length === 1 ? (t[0] ?? "").slice(0, 2).toUpperCase() : `${t[0][0]}${t[t.length - 1][0]}`.toUpperCase();
15
15
  }
16
- class r extends u {
16
+ class r extends d {
17
17
  constructor() {
18
18
  super(...arguments), this.failed = !1, this.name = "", this.src = "", this.size = "medium", this.square = !1, this.color = "";
19
19
  }
20
20
  static {
21
21
  this.styles = [
22
- u.styles,
22
+ d.styles,
23
23
  p`
24
24
  :host {
25
25
  display: inline-flex;
@@ -48,7 +48,10 @@ class r extends u {
48
48
  width: var(--kt-avatar-size);
49
49
  height: var(--kt-avatar-size);
50
50
  overflow: hidden;
51
- color: var(--kt-avatar-hue, var(--text-muted));
51
+ /* The hue alone is too faint on its own 12% tint. Pulled towards the
52
+ body text — lighter in dark, darker in light — it keeps its identity
53
+ and clears 4.5:1 for all eight hues in both themes. */
54
+ color: color-mix(in srgb, var(--kt-avatar-hue, var(--text-muted)) 45%, var(--text-body));
52
55
  font: 600 calc(var(--kt-avatar-size) * 0.36) / 1 var(--font-family-body);
53
56
  background: color-mix(in srgb, var(--kt-avatar-hue, transparent) 12%, transparent);
54
57
  border-radius: var(--radius-full);
@@ -104,7 +107,7 @@ class r extends u {
104
107
  if (this.color) return this.color;
105
108
  let e = 0;
106
109
  for (const t of this.name) e += t.charCodeAt(0);
107
- return d[e % d.length];
110
+ return u[e % u.length];
108
111
  }
109
112
  render() {
110
113
  const e = y(this.name), t = !!this.src && !this.failed;
@@ -1 +1 @@
1
- {"version":3,"file":"kt-avatar.js","sources":["../../../../src/components/core/kt-avatar/kt-avatar.ts"],"sourcesContent":["import { css, html, nothing, type TemplateResult } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport '../kt-icon/kt-icon.js';\n\nexport type KtAvatarSize = 'small' | 'medium' | 'large';\nexport type KtAvatarStatus = 'online' | 'away' | 'busy' | 'offline';\n\n/**\n * Deterministic hue per name, so a person keeps their colour everywhere.\n *\n * From the chart palette, not the semantic one: status colours are reserved,\n * and a person filled with `--color-danger-base` reads as an error rather than\n * as a person. These eight are the same slots a chart uses, in the same fixed\n * order, so an avatar never impersonates a state.\n */\nconst HUES = Array.from({ length: 8 }, (_, i) => `var(--chart-series-${i + 1})`);\n\n/** \"Benjamin Canac\" → \"BC\", \"emma.davis@example.com\" → \"ED\". */\nexport function initialsOf(name: string): string {\n const cleaned = name.includes('@') ? (name.split('@')[0] ?? '') : name;\n const parts = cleaned.split(/[\\s._-]+/).filter(Boolean);\n\n if (parts.length === 0) return '';\n if (parts.length === 1) return (parts[0] ?? '').slice(0, 2).toUpperCase();\n return `${parts[0]![0]}${parts[parts.length - 1]![0]}`.toUpperCase();\n}\n\n/**\n * A person or an organisation, as a picture or as their initials.\n *\n * The fallback is not decoration: most rows in most products have no photo, so\n * the initials path is the one that renders. It picks a colour from the name,\n * which means the same person is the same colour on every screen and the eye\n * can use it.\n *\n * @element kt-avatar\n *\n * @csspart base - The avatar circle.\n * @csspart image - The `<img>`, when `src` is set and loads.\n *\n * @example\n * ```html\n * <kt-avatar name=\"Benjamin Canac\"></kt-avatar>\n * <kt-avatar name=\"Emma Davis\" src=\"/emma.jpg\" status=\"online\"></kt-avatar>\n * ```\n */\nexport class KtAvatar extends KtElement {\n static override styles = [\n KtElement.styles,\n css`\n :host {\n display: inline-flex;\n --kt-avatar-size: 32px;\n }\n\n :host([size='small']) {\n --kt-avatar-size: 24px;\n }\n :host([size='large']) {\n --kt-avatar-size: 48px;\n }\n\n /* The identity hue is worn exactly the way every other tinted thing in\n Kanto wears one: the colour at 12% behind, the colour itself as the\n ink, and no border — the same pair as a secondary button, a danger\n button or a badge tone. A saturated fill with white initials is a\n different system's idea, and beside those it looks like one. */\n .avatar {\n position: relative;\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n width: var(--kt-avatar-size);\n height: var(--kt-avatar-size);\n overflow: hidden;\n color: var(--kt-avatar-hue, var(--text-muted));\n font: 600 calc(var(--kt-avatar-size) * 0.36) / 1 var(--font-family-body);\n background: color-mix(in srgb, var(--kt-avatar-hue, transparent) 12%, transparent);\n border-radius: var(--radius-full);\n user-select: none;\n }\n\n /* No hue to tint with, and a photograph that fills the circle anyway. */\n .avatar.has-image,\n .avatar.anonymous {\n background: var(--surface-raised);\n }\n\n :host([square]) .avatar {\n border-radius: var(--border-radius);\n }\n\n img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n /* The dot sits outside the clipped circle, so it needs its own box. */\n .status {\n position: absolute;\n right: 0;\n bottom: 0;\n width: calc(var(--kt-avatar-size) * 0.28);\n height: calc(var(--kt-avatar-size) * 0.28);\n border: 2px solid var(--surface-page);\n border-radius: var(--radius-full);\n }\n\n .online {\n background: var(--color-success-base);\n }\n .away {\n background: var(--color-warning-base);\n }\n .busy {\n background: var(--color-danger-base);\n }\n .offline {\n background: var(--color-text-500);\n }\n `,\n ];\n\n @state()\n private failed = false;\n\n /** The person's name. Drives the initials, the colour and the label. */\n @property({ type: String })\n name = '';\n\n /** Photo. Falls back to initials if it is missing or fails to load. */\n @property({ type: String })\n src = '';\n\n @property({ type: String, reflect: true })\n size: KtAvatarSize = 'medium';\n\n /** Rounds to the card radius instead of a circle — for organisations. */\n @property({ type: Boolean, reflect: true })\n square = false;\n\n /** Presence dot. Omit for none. */\n @property({ type: String, reflect: true })\n status?: KtAvatarStatus;\n\n /** Overrides the colour picked from the name. */\n @property({ type: String })\n color = '';\n\n override willUpdate(changed: Map<string, unknown>): void {\n // A new source deserves a fresh attempt; without this a single failure\n // would stick for the element's lifetime.\n if (changed.has('src')) this.failed = false;\n }\n\n private get hue(): string {\n if (this.color) return this.color;\n\n let sum = 0;\n for (const char of this.name) sum += char.charCodeAt(0);\n return HUES[sum % HUES.length]!;\n }\n\n override render(): TemplateResult {\n const initials = initialsOf(this.name);\n const showImage = Boolean(this.src) && !this.failed;\n\n return html`<span\n part=\"base\"\n class=${classMap({ avatar: true, 'has-image': showImage, anonymous: !this.name })}\n style=${showImage ? '' : `--kt-avatar-hue:${this.hue}`}\n role=\"img\"\n aria-label=${this.name || 'Avatar'}\n >\n ${\n showImage\n ? html`<img\n part=\"image\"\n src=${this.src}\n alt=\"\"\n @error=${() => {\n this.failed = true;\n }}\n />`\n : initials || html`<kt-icon name=\"user\" size=\"16\"></kt-icon>`\n }\n ${\n this.status\n ? html`<span class=${classMap({ status: true, [this.status]: true })}></span>`\n : nothing\n }\n </span>`;\n }\n}\n\ndefineElement('kt-avatar', KtAvatar);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-avatar': KtAvatar;\n }\n}\n"],"names":["HUES","_","i","initialsOf","name","parts","KtAvatar","KtElement","css","changed","sum","char","initials","showImage","html","classMap","nothing","__decorateClass","state","property","defineElement"],"mappings":"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"}
1
+ {"version":3,"file":"kt-avatar.js","sources":["../../../../src/components/core/kt-avatar/kt-avatar.ts"],"sourcesContent":["import { css, html, nothing, type TemplateResult } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport '../kt-icon/kt-icon.js';\n\nexport type KtAvatarSize = 'small' | 'medium' | 'large';\nexport type KtAvatarStatus = 'online' | 'away' | 'busy' | 'offline';\n\n/**\n * Deterministic hue per name, so a person keeps their colour everywhere.\n *\n * From the chart palette, not the semantic one: status colours are reserved,\n * and a person filled with `--color-danger-base` reads as an error rather than\n * as a person. These eight are the same slots a chart uses, in the same fixed\n * order, so an avatar never impersonates a state.\n */\nconst HUES = Array.from({ length: 8 }, (_, i) => `var(--chart-series-${i + 1})`);\n\n/** \"Benjamin Canac\" → \"BC\", \"emma.davis@example.com\" → \"ED\". */\nexport function initialsOf(name: string): string {\n const cleaned = name.includes('@') ? (name.split('@')[0] ?? '') : name;\n const parts = cleaned.split(/[\\s._-]+/).filter(Boolean);\n\n if (parts.length === 0) return '';\n if (parts.length === 1) return (parts[0] ?? '').slice(0, 2).toUpperCase();\n return `${parts[0]![0]}${parts[parts.length - 1]![0]}`.toUpperCase();\n}\n\n/**\n * A person or an organisation, as a picture or as their initials.\n *\n * The fallback is not decoration: most rows in most products have no photo, so\n * the initials path is the one that renders. It picks a colour from the name,\n * which means the same person is the same colour on every screen and the eye\n * can use it.\n *\n * @element kt-avatar\n *\n * @csspart base - The avatar circle.\n * @csspart image - The `<img>`, when `src` is set and loads.\n *\n * @example\n * ```html\n * <kt-avatar name=\"Benjamin Canac\"></kt-avatar>\n * <kt-avatar name=\"Emma Davis\" src=\"/emma.jpg\" status=\"online\"></kt-avatar>\n * ```\n */\nexport class KtAvatar extends KtElement {\n static override styles = [\n KtElement.styles,\n css`\n :host {\n display: inline-flex;\n --kt-avatar-size: 32px;\n }\n\n :host([size='small']) {\n --kt-avatar-size: 24px;\n }\n :host([size='large']) {\n --kt-avatar-size: 48px;\n }\n\n /* The identity hue is worn exactly the way every other tinted thing in\n Kanto wears one: the colour at 12% behind, the colour itself as the\n ink, and no border — the same pair as a secondary button, a danger\n button or a badge tone. A saturated fill with white initials is a\n different system's idea, and beside those it looks like one. */\n .avatar {\n position: relative;\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n width: var(--kt-avatar-size);\n height: var(--kt-avatar-size);\n overflow: hidden;\n /* The hue alone is too faint on its own 12% tint. Pulled towards the\n body text — lighter in dark, darker in light — it keeps its identity\n and clears 4.5:1 for all eight hues in both themes. */\n color: color-mix(in srgb, var(--kt-avatar-hue, var(--text-muted)) 45%, var(--text-body));\n font: 600 calc(var(--kt-avatar-size) * 0.36) / 1 var(--font-family-body);\n background: color-mix(in srgb, var(--kt-avatar-hue, transparent) 12%, transparent);\n border-radius: var(--radius-full);\n user-select: none;\n }\n\n /* No hue to tint with, and a photograph that fills the circle anyway. */\n .avatar.has-image,\n .avatar.anonymous {\n background: var(--surface-raised);\n }\n\n :host([square]) .avatar {\n border-radius: var(--border-radius);\n }\n\n img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n /* The dot sits outside the clipped circle, so it needs its own box. */\n .status {\n position: absolute;\n right: 0;\n bottom: 0;\n width: calc(var(--kt-avatar-size) * 0.28);\n height: calc(var(--kt-avatar-size) * 0.28);\n border: 2px solid var(--surface-page);\n border-radius: var(--radius-full);\n }\n\n .online {\n background: var(--color-success-base);\n }\n .away {\n background: var(--color-warning-base);\n }\n .busy {\n background: var(--color-danger-base);\n }\n .offline {\n background: var(--color-text-500);\n }\n `,\n ];\n\n @state()\n private failed = false;\n\n /** The person's name. Drives the initials, the colour and the label. */\n @property({ type: String })\n name = '';\n\n /** Photo. Falls back to initials if it is missing or fails to load. */\n @property({ type: String })\n src = '';\n\n @property({ type: String, reflect: true })\n size: KtAvatarSize = 'medium';\n\n /** Rounds to the card radius instead of a circle — for organisations. */\n @property({ type: Boolean, reflect: true })\n square = false;\n\n /** Presence dot. Omit for none. */\n @property({ type: String, reflect: true })\n status?: KtAvatarStatus;\n\n /** Overrides the colour picked from the name. */\n @property({ type: String })\n color = '';\n\n override willUpdate(changed: Map<string, unknown>): void {\n // A new source deserves a fresh attempt; without this a single failure\n // would stick for the element's lifetime.\n if (changed.has('src')) this.failed = false;\n }\n\n private get hue(): string {\n if (this.color) return this.color;\n\n let sum = 0;\n for (const char of this.name) sum += char.charCodeAt(0);\n return HUES[sum % HUES.length]!;\n }\n\n override render(): TemplateResult {\n const initials = initialsOf(this.name);\n const showImage = Boolean(this.src) && !this.failed;\n\n return html`<span\n part=\"base\"\n class=${classMap({ avatar: true, 'has-image': showImage, anonymous: !this.name })}\n style=${showImage ? '' : `--kt-avatar-hue:${this.hue}`}\n role=\"img\"\n aria-label=${this.name || 'Avatar'}\n >\n ${\n showImage\n ? html`<img\n part=\"image\"\n src=${this.src}\n alt=\"\"\n @error=${() => {\n this.failed = true;\n }}\n />`\n : initials || html`<kt-icon name=\"user\" size=\"16\"></kt-icon>`\n }\n ${\n this.status\n ? html`<span class=${classMap({ status: true, [this.status]: true })}></span>`\n : nothing\n }\n </span>`;\n }\n}\n\ndefineElement('kt-avatar', KtAvatar);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-avatar': KtAvatar;\n }\n}\n"],"names":["HUES","_","i","initialsOf","name","parts","KtAvatar","KtElement","css","changed","sum","char","initials","showImage","html","classMap","nothing","__decorateClass","state","property","defineElement"],"mappings":"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"}
@@ -1,13 +1,13 @@
1
- import { css as u, nothing as n, html as l } from "lit";
1
+ import { css as h, nothing as n, html as l } from "lit";
2
2
  import { property as e } from "lit/decorators.js";
3
- import { classMap as h } from "lit/directives/class-map.js";
3
+ import { classMap as b } from "lit/directives/class-map.js";
4
4
  import { styleMap as m } from "lit/directives/style-map.js";
5
- import { K as p, d as v } from "../../../chunks/kt-element-CcMLO5e8.js";
6
- import { e as b } from "../../../chunks/events-Bjl5Zmmq.js";
5
+ import { K as p, d as v } from "../../../chunks/kt-element-B_jjQDhg.js";
6
+ import { e as u } from "../../../chunks/events-Bjl5Zmmq.js";
7
7
  import "../kt-icon/kt-icon.js";
8
- var g = Object.defineProperty, t = (s, r, i, f) => {
9
- for (var a = void 0, c = s.length - 1, d; c >= 0; c--)
10
- (d = s[c]) && (a = d(r, i, a) || a);
8
+ var g = Object.defineProperty, t = (c, r, i, f) => {
9
+ for (var a = void 0, s = c.length - 1, d; s >= 0; s--)
10
+ (d = c[s]) && (a = d(r, i, a) || a);
11
11
  return a && g(r, i, a), a;
12
12
  };
13
13
  class o extends p {
@@ -17,11 +17,11 @@ class o extends p {
17
17
  static {
18
18
  this.styles = [
19
19
  p.styles,
20
- u`
20
+ h`
21
21
  :host {
22
22
  display: inline-flex;
23
23
  vertical-align: middle;
24
- --kt-badge-color: var(--color-primary-hover);
24
+ --kt-badge-color: var(--color-primary-text);
25
25
  }
26
26
 
27
27
  .badge {
@@ -92,27 +92,27 @@ class o extends p {
92
92
  colour itself as the ink. The border follows on the bordered shapes
93
93
  and is simply absent on the count shape. */
94
94
  .primary {
95
- color: var(--color-primary-base);
95
+ color: var(--color-primary-text);
96
96
  background-color: var(--color-primary-soft);
97
97
  border-color: var(--color-primary-base);
98
98
  }
99
99
  .success {
100
- color: var(--color-success-base);
100
+ color: var(--color-success-text);
101
101
  background-color: var(--color-success-soft);
102
102
  border-color: var(--color-success-base);
103
103
  }
104
104
  .warning {
105
- color: var(--color-warning-base);
105
+ color: var(--color-warning-text);
106
106
  background-color: var(--color-warning-soft);
107
107
  border-color: var(--color-warning-base);
108
108
  }
109
109
  .danger {
110
- color: var(--color-danger-base);
110
+ color: var(--color-danger-text);
111
111
  background-color: var(--color-danger-soft);
112
112
  border-color: var(--color-danger-base);
113
113
  }
114
114
  .info {
115
- color: var(--color-info-base);
115
+ color: var(--color-info-text);
116
116
  background-color: var(--color-info-soft);
117
117
  border-color: var(--color-info-base);
118
118
  }
@@ -178,19 +178,19 @@ class o extends p {
178
178
  return Number.isFinite(i) && i > this.max ? `${this.max}+` : r;
179
179
  }
180
180
  activate() {
181
- this.clickable && b(this, "kt-badge-click");
181
+ this.clickable && u(this, "kt-badge-click");
182
182
  }
183
183
  onKeyDown(r) {
184
184
  this.clickable && (r.key !== "Enter" && r.key !== " " || (r.preventDefault(), this.activate()));
185
185
  }
186
186
  onRemove(r) {
187
- r.stopPropagation(), b(this, "kt-remove");
187
+ r.stopPropagation(), u(this, "kt-remove");
188
188
  }
189
189
  render() {
190
190
  const r = this.error ? "danger" : this.tone;
191
191
  return l`<span
192
192
  part="base"
193
- class=${h({
193
+ class=${b({
194
194
  badge: !0,
195
195
  [this.variant]: !0,
196
196
  [r]: r !== "neutral",
@@ -1 +1 @@
1
- {"version":3,"file":"kt-badge.js","sources":["../../../../src/components/core/kt-badge/kt-badge.ts"],"sourcesContent":["import { css, html, nothing, type TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { emit } from '#internal/events';\nimport '../kt-icon/kt-icon.js';\n\nexport type KtBadgeVariant = 'tag' | 'code' | 'category' | 'count';\nexport type KtBadgeTone = 'neutral' | 'primary' | 'success' | 'warning' | 'danger' | 'info';\nexport type KtBadgeSize = 'small' | 'medium';\n\n/**\n * A compact label: a pill `tag`, a monospaced `code` token, a `category`\n * tinted with a colour of your choosing, or a `count`.\n *\n * Two independent axes, because they answer different questions. `variant` is\n * the **shape** — what kind of thing this is. `tone` is the **colour** — what\n * it means. A tag can be neutral or dangerous; so can a count. Folding them\n * into one list would give you nine variants and no way to say \"a tag, but\n * this one is a warning\".\n *\n * `count` is the exception that carries no border, because a number pinned to\n * a nav item is not a label with an outline — it is a mark on the thing it\n * counts.\n *\n * @element kt-badge\n *\n * @slot - The text. Falls back to the `label` attribute.\n *\n * @csspart base - The container.\n * @csspart remove - The remove button, when `removable`.\n *\n * @cssproperty --kt-badge-color - Category hue. The fill is this colour at 20%.\n *\n * @fires kt-badge-click - A `clickable` badge was activated. Cancelable.\n * @fires kt-remove - The remove button was pressed. Cancelable: cancel it and\n * remove the badge yourself once the server agrees.\n *\n * @example\n * ```html\n * <kt-badge>Design systems</kt-badge>\n * <kt-badge tone=\"success\">Active</kt-badge>\n * <kt-badge variant=\"code\">--surface-card</kt-badge>\n * <kt-badge variant=\"category\" color=\"#3987e5\">Infrastructure</kt-badge>\n * <kt-badge variant=\"count\" tone=\"danger\" max=\"99\">128</kt-badge>\n * <kt-badge icon=\"user\" removable>Assigned to me</kt-badge>\n * ```\n */\nexport class KtBadge extends KtElement {\n static override styles = [\n KtElement.styles,\n css`\n :host {\n display: inline-flex;\n vertical-align: middle;\n --kt-badge-color: var(--color-primary-hover);\n }\n\n .badge {\n display: inline-flex;\n align-items: center;\n gap: var(--gap-element);\n width: fit-content;\n margin: 0;\n padding: var(--padding-chip);\n color: var(--text-body);\n font: var(--font-normal-regular);\n background-color: var(--color-dark-20);\n border: var(--border-width) solid var(--color-text-600);\n border-radius: var(--radius-input);\n white-space: normal;\n }\n\n .small {\n padding: 2px 8px;\n font: var(--font-normal-small);\n }\n\n /* === TAG === */\n .tag {\n border-radius: var(--radius-pill);\n }\n\n /* === CODE ===\n Uses the semantic code surface rather than a ramp step: --color-dark-8\n is the darkest surface in the dark theme and pure white in the light\n one, which made this badge white-on-white. */\n .code {\n color: var(--text-code);\n font: var(--font-code-regular);\n background-color: var(--surface-code);\n border-color: var(--border-code);\n }\n\n /* === CATEGORY ===\n color-mix keeps the 20% fill honest for any colour notation the host\n hands us; concatenating a \"33\" onto a hex string produces garbage\n for rgb() and named colours. */\n .category {\n color: var(--kt-badge-color);\n background-color: color-mix(in srgb, var(--kt-badge-color) 20%, transparent);\n border-color: var(--kt-badge-color);\n }\n\n /* === COUNT ===\n No border: a number pinned to a nav item is a mark on the thing it\n counts, not a label with an outline of its own. */\n .count {\n min-width: 20px;\n padding: 2px 6px;\n justify-content: center;\n color: var(--text-muted);\n font: var(--font-normal-small);\n font-variant-numeric: tabular-nums;\n line-height: 1.4;\n white-space: nowrap;\n background: var(--surface-raised);\n border: none;\n border-radius: var(--radius-pill);\n }\n\n /* === TONES ===\n The system's tinted pair everywhere: the colour at 12% behind, the\n colour itself as the ink. The border follows on the bordered shapes\n and is simply absent on the count shape. */\n .primary {\n color: var(--color-primary-base);\n background-color: var(--color-primary-soft);\n border-color: var(--color-primary-base);\n }\n .success {\n color: var(--color-success-base);\n background-color: var(--color-success-soft);\n border-color: var(--color-success-base);\n }\n .warning {\n color: var(--color-warning-base);\n background-color: var(--color-warning-soft);\n border-color: var(--color-warning-base);\n }\n .danger {\n color: var(--color-danger-base);\n background-color: var(--color-danger-soft);\n border-color: var(--color-danger-base);\n }\n .info {\n color: var(--color-info-base);\n background-color: var(--color-info-soft);\n border-color: var(--color-info-base);\n }\n\n .count.primary,\n .count.success,\n .count.warning,\n .count.danger,\n .count.info {\n border: none;\n }\n\n /* === CLICKABLE === */\n .clickable {\n cursor: pointer;\n }\n .clickable:hover {\n outline: var(--outline-width) solid var(--text-muted);\n }\n .clickable:active {\n color: var(--color-white);\n background-color: var(--color-primary-base);\n border-color: transparent;\n }\n .clickable:focus-visible {\n outline: var(--outline-width) solid var(--color-primary-base);\n outline-offset: 2px;\n }\n\n .remove {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin-right: -4px;\n padding: 0;\n color: inherit;\n background: none;\n border: none;\n border-radius: var(--radius-pill);\n cursor: pointer;\n opacity: 0.65;\n }\n\n .remove:hover {\n opacity: 1;\n }\n\n .remove:focus-visible {\n outline: var(--outline-width) solid var(--color-primary-base);\n outline-offset: 1px;\n }\n\n kt-icon {\n flex: none;\n }\n `,\n ];\n\n /** The shape: what kind of thing this is. */\n @property({ type: String, reflect: true })\n variant: KtBadgeVariant = 'tag';\n\n /** The colour: what it means. Independent of `variant`. */\n @property({ type: String, reflect: true })\n tone: KtBadgeTone = 'neutral';\n\n @property({ type: String, reflect: true })\n size: KtBadgeSize = 'medium';\n\n /** Badge text. The default slot wins when both are present. */\n @property({ type: String })\n label = '';\n\n /** Category hue: any CSS colour. The fill is this colour at 20%. */\n @property({ type: String })\n color = '';\n\n /** Lucide icon name, before the text. */\n @property({ type: String })\n icon = '';\n\n @property({ type: Boolean, reflect: true })\n clickable = false;\n\n /** Adds a remove button. Fires a cancelable `kt-remove`. */\n @property({ type: Boolean, reflect: true })\n removable = false;\n\n /**\n * Caps a numeric label: `max=\"99\"` shows `99+`.\n * Ignored when the content is not a number.\n */\n @property({ type: Number })\n max?: number;\n\n /** Shorthand for `tone=\"danger\"`, kept from the field components. */\n @property({ type: Boolean, reflect: true })\n error = false;\n\n private get display(): string {\n const raw = this.label || (this.textContent ?? '').trim();\n if (this.max === undefined) return raw;\n\n const n = Number(raw);\n return Number.isFinite(n) && n > this.max ? `${this.max}+` : raw;\n }\n\n private activate(): void {\n if (this.clickable) emit(this, 'kt-badge-click');\n }\n\n private onKeyDown(event: KeyboardEvent): void {\n if (!this.clickable) return;\n if (event.key !== 'Enter' && event.key !== ' ') return;\n event.preventDefault();\n this.activate();\n }\n\n private onRemove(event: Event): void {\n // Otherwise a removable clickable badge reports both at once.\n event.stopPropagation();\n emit(this, 'kt-remove');\n }\n\n override render(): TemplateResult {\n const tone = this.error ? 'danger' : this.tone;\n\n return html`<span\n part=\"base\"\n class=${classMap({\n badge: true,\n [this.variant]: true,\n [tone]: tone !== 'neutral',\n small: this.size === 'small',\n clickable: this.clickable,\n })}\n style=${styleMap(this.color ? { '--kt-badge-color': this.color } : {})}\n role=${this.clickable ? 'button' : nothing}\n tabindex=${this.clickable ? 0 : nothing}\n @click=${this.activate}\n @keydown=${this.onKeyDown}\n >\n ${this.icon ? html`<kt-icon name=${this.icon} size=\"14\"></kt-icon>` : nothing}\n ${this.max === undefined ? html`<slot>${this.label}</slot>` : this.display}\n ${\n this.removable\n ? html`<button\n part=\"remove\"\n type=\"button\"\n class=\"remove\"\n aria-label=${`Remove ${this.display || 'this'}`}\n @click=${this.onRemove}\n >\n <kt-icon name=\"x\" size=\"12\"></kt-icon>\n </button>`\n : nothing\n }\n </span>`;\n }\n}\n\ndefineElement('kt-badge', KtBadge);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-badge': KtBadge;\n }\n}\n"],"names":["KtBadge","KtElement","css","raw","n","emit","event","tone","html","classMap","styleMap","nothing","__decorateClass","property","defineElement"],"mappings":"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"}
1
+ {"version":3,"file":"kt-badge.js","sources":["../../../../src/components/core/kt-badge/kt-badge.ts"],"sourcesContent":["import { css, html, nothing, type TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { emit } from '#internal/events';\nimport '../kt-icon/kt-icon.js';\n\nexport type KtBadgeVariant = 'tag' | 'code' | 'category' | 'count';\nexport type KtBadgeTone = 'neutral' | 'primary' | 'success' | 'warning' | 'danger' | 'info';\nexport type KtBadgeSize = 'small' | 'medium';\n\n/**\n * A compact label: a pill `tag`, a monospaced `code` token, a `category`\n * tinted with a colour of your choosing, or a `count`.\n *\n * Two independent axes, because they answer different questions. `variant` is\n * the **shape** — what kind of thing this is. `tone` is the **colour** — what\n * it means. A tag can be neutral or dangerous; so can a count. Folding them\n * into one list would give you nine variants and no way to say \"a tag, but\n * this one is a warning\".\n *\n * `count` is the exception that carries no border, because a number pinned to\n * a nav item is not a label with an outline — it is a mark on the thing it\n * counts.\n *\n * @element kt-badge\n *\n * @slot - The text. Falls back to the `label` attribute.\n *\n * @csspart base - The container.\n * @csspart remove - The remove button, when `removable`.\n *\n * @cssproperty --kt-badge-color - Category hue. The fill is this colour at 20%.\n *\n * @fires kt-badge-click - A `clickable` badge was activated. Cancelable.\n * @fires kt-remove - The remove button was pressed. Cancelable: cancel it and\n * remove the badge yourself once the server agrees.\n *\n * @example\n * ```html\n * <kt-badge>Design systems</kt-badge>\n * <kt-badge tone=\"success\">Active</kt-badge>\n * <kt-badge variant=\"code\">--surface-card</kt-badge>\n * <kt-badge variant=\"category\" color=\"#3987e5\">Infrastructure</kt-badge>\n * <kt-badge variant=\"count\" tone=\"danger\" max=\"99\">128</kt-badge>\n * <kt-badge icon=\"user\" removable>Assigned to me</kt-badge>\n * ```\n */\nexport class KtBadge extends KtElement {\n static override styles = [\n KtElement.styles,\n css`\n :host {\n display: inline-flex;\n vertical-align: middle;\n --kt-badge-color: var(--color-primary-text);\n }\n\n .badge {\n display: inline-flex;\n align-items: center;\n gap: var(--gap-element);\n width: fit-content;\n margin: 0;\n padding: var(--padding-chip);\n color: var(--text-body);\n font: var(--font-normal-regular);\n background-color: var(--color-dark-20);\n border: var(--border-width) solid var(--color-text-600);\n border-radius: var(--radius-input);\n white-space: normal;\n }\n\n .small {\n padding: 2px 8px;\n font: var(--font-normal-small);\n }\n\n /* === TAG === */\n .tag {\n border-radius: var(--radius-pill);\n }\n\n /* === CODE ===\n Uses the semantic code surface rather than a ramp step: --color-dark-8\n is the darkest surface in the dark theme and pure white in the light\n one, which made this badge white-on-white. */\n .code {\n color: var(--text-code);\n font: var(--font-code-regular);\n background-color: var(--surface-code);\n border-color: var(--border-code);\n }\n\n /* === CATEGORY ===\n color-mix keeps the 20% fill honest for any colour notation the host\n hands us; concatenating a \"33\" onto a hex string produces garbage\n for rgb() and named colours. */\n .category {\n color: var(--kt-badge-color);\n background-color: color-mix(in srgb, var(--kt-badge-color) 20%, transparent);\n border-color: var(--kt-badge-color);\n }\n\n /* === COUNT ===\n No border: a number pinned to a nav item is a mark on the thing it\n counts, not a label with an outline of its own. */\n .count {\n min-width: 20px;\n padding: 2px 6px;\n justify-content: center;\n color: var(--text-muted);\n font: var(--font-normal-small);\n font-variant-numeric: tabular-nums;\n line-height: 1.4;\n white-space: nowrap;\n background: var(--surface-raised);\n border: none;\n border-radius: var(--radius-pill);\n }\n\n /* === TONES ===\n The system's tinted pair everywhere: the colour at 12% behind, the\n colour itself as the ink. The border follows on the bordered shapes\n and is simply absent on the count shape. */\n .primary {\n color: var(--color-primary-text);\n background-color: var(--color-primary-soft);\n border-color: var(--color-primary-base);\n }\n .success {\n color: var(--color-success-text);\n background-color: var(--color-success-soft);\n border-color: var(--color-success-base);\n }\n .warning {\n color: var(--color-warning-text);\n background-color: var(--color-warning-soft);\n border-color: var(--color-warning-base);\n }\n .danger {\n color: var(--color-danger-text);\n background-color: var(--color-danger-soft);\n border-color: var(--color-danger-base);\n }\n .info {\n color: var(--color-info-text);\n background-color: var(--color-info-soft);\n border-color: var(--color-info-base);\n }\n\n .count.primary,\n .count.success,\n .count.warning,\n .count.danger,\n .count.info {\n border: none;\n }\n\n /* === CLICKABLE === */\n .clickable {\n cursor: pointer;\n }\n .clickable:hover {\n outline: var(--outline-width) solid var(--text-muted);\n }\n .clickable:active {\n color: var(--color-white);\n background-color: var(--color-primary-base);\n border-color: transparent;\n }\n .clickable:focus-visible {\n outline: var(--outline-width) solid var(--color-primary-base);\n outline-offset: 2px;\n }\n\n .remove {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin-right: -4px;\n padding: 0;\n color: inherit;\n background: none;\n border: none;\n border-radius: var(--radius-pill);\n cursor: pointer;\n opacity: 0.65;\n }\n\n .remove:hover {\n opacity: 1;\n }\n\n .remove:focus-visible {\n outline: var(--outline-width) solid var(--color-primary-base);\n outline-offset: 1px;\n }\n\n kt-icon {\n flex: none;\n }\n `,\n ];\n\n /** The shape: what kind of thing this is. */\n @property({ type: String, reflect: true })\n variant: KtBadgeVariant = 'tag';\n\n /** The colour: what it means. Independent of `variant`. */\n @property({ type: String, reflect: true })\n tone: KtBadgeTone = 'neutral';\n\n @property({ type: String, reflect: true })\n size: KtBadgeSize = 'medium';\n\n /** Badge text. The default slot wins when both are present. */\n @property({ type: String })\n label = '';\n\n /** Category hue: any CSS colour. The fill is this colour at 20%. */\n @property({ type: String })\n color = '';\n\n /** Lucide icon name, before the text. */\n @property({ type: String })\n icon = '';\n\n @property({ type: Boolean, reflect: true })\n clickable = false;\n\n /** Adds a remove button. Fires a cancelable `kt-remove`. */\n @property({ type: Boolean, reflect: true })\n removable = false;\n\n /**\n * Caps a numeric label: `max=\"99\"` shows `99+`.\n * Ignored when the content is not a number.\n */\n @property({ type: Number })\n max?: number;\n\n /** Shorthand for `tone=\"danger\"`, kept from the field components. */\n @property({ type: Boolean, reflect: true })\n error = false;\n\n private get display(): string {\n const raw = this.label || (this.textContent ?? '').trim();\n if (this.max === undefined) return raw;\n\n const n = Number(raw);\n return Number.isFinite(n) && n > this.max ? `${this.max}+` : raw;\n }\n\n private activate(): void {\n if (this.clickable) emit(this, 'kt-badge-click');\n }\n\n private onKeyDown(event: KeyboardEvent): void {\n if (!this.clickable) return;\n if (event.key !== 'Enter' && event.key !== ' ') return;\n event.preventDefault();\n this.activate();\n }\n\n private onRemove(event: Event): void {\n // Otherwise a removable clickable badge reports both at once.\n event.stopPropagation();\n emit(this, 'kt-remove');\n }\n\n override render(): TemplateResult {\n const tone = this.error ? 'danger' : this.tone;\n\n return html`<span\n part=\"base\"\n class=${classMap({\n badge: true,\n [this.variant]: true,\n [tone]: tone !== 'neutral',\n small: this.size === 'small',\n clickable: this.clickable,\n })}\n style=${styleMap(this.color ? { '--kt-badge-color': this.color } : {})}\n role=${this.clickable ? 'button' : nothing}\n tabindex=${this.clickable ? 0 : nothing}\n @click=${this.activate}\n @keydown=${this.onKeyDown}\n >\n ${this.icon ? html`<kt-icon name=${this.icon} size=\"14\"></kt-icon>` : nothing}\n ${this.max === undefined ? html`<slot>${this.label}</slot>` : this.display}\n ${\n this.removable\n ? html`<button\n part=\"remove\"\n type=\"button\"\n class=\"remove\"\n aria-label=${`Remove ${this.display || 'this'}`}\n @click=${this.onRemove}\n >\n <kt-icon name=\"x\" size=\"12\"></kt-icon>\n </button>`\n : nothing\n }\n </span>`;\n }\n}\n\ndefineElement('kt-badge', KtBadge);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-badge': KtBadge;\n }\n}\n"],"names":["KtBadge","KtElement","css","raw","n","emit","event","tone","html","classMap","styleMap","nothing","__decorateClass","property","defineElement"],"mappings":"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"}
@@ -44,6 +44,13 @@ export declare class KtButton extends KtElement {
44
44
  iconPosition: 'left' | 'right';
45
45
  /** Accessible name. Required for an icon-only button. */
46
46
  label: string;
47
+ /**
48
+ * The kind of popup this button opens, as `aria-haspopup` on the inner
49
+ * button. Set by `<kt-dropdown>` on its trigger; rarely by hand.
50
+ */
51
+ popup: 'menu' | 'listbox' | 'dialog' | undefined;
52
+ /** Whether the popup or region this button controls is open, as `aria-expanded`. */
53
+ expanded: boolean | undefined;
47
54
  /** Stretches the button to the width of its container. */
48
55
  fullWidth: boolean;
49
56
  /** Submitted with the form, as on a native button. */