kanto-ds 1.10.0 → 1.11.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 (45) hide show
  1. package/dist/cdn/kanto.min.js +289 -187
  2. package/dist/chunks/defaults-DaB3TcsM.js +72 -0
  3. package/dist/chunks/{defaults-BnB3ir8l.js.map → defaults-DaB3TcsM.js.map} +1 -1
  4. package/dist/chunks/{floating-C9RLa6cZ.js → floating-DxiFx4AK.js} +11 -10
  5. package/dist/chunks/floating-DxiFx4AK.js.map +1 -0
  6. package/dist/components/core/kt-icon/kt-icon.js +1 -1
  7. package/dist/components/data/kt-chat-message/kt-chat-message.d.ts +6 -0
  8. package/dist/components/data/kt-chat-message/kt-chat-message.js +49 -13
  9. package/dist/components/data/kt-chat-message/kt-chat-message.js.map +1 -1
  10. package/dist/components/forms/kt-date-input/kt-date-input.js +1 -1
  11. package/dist/components/forms/kt-date-picker/kt-date-picker.js +1 -1
  12. package/dist/components/forms/kt-input/kt-input.js +1 -1
  13. package/dist/components/forms/kt-input-menu/kt-input-menu.js +1 -1
  14. package/dist/components/forms/kt-multi-select/kt-multi-select.js +1 -1
  15. package/dist/components/forms/kt-select/kt-select.js +1 -1
  16. package/dist/components/navigation/kt-app-shell/kt-app-shell.d.ts +2 -2
  17. package/dist/components/navigation/kt-app-shell/kt-app-shell.js +15 -10
  18. package/dist/components/navigation/kt-app-shell/kt-app-shell.js.map +1 -1
  19. package/dist/components/navigation/kt-header/kt-header.js +8 -0
  20. package/dist/components/navigation/kt-header/kt-header.js.map +1 -1
  21. package/dist/components/navigation/kt-user-menu/kt-user-menu.d.ts +6 -0
  22. package/dist/components/navigation/kt-user-menu/kt-user-menu.js +92 -40
  23. package/dist/components/navigation/kt-user-menu/kt-user-menu.js.map +1 -1
  24. package/dist/components/overlays/kt-dropdown/kt-dropdown.js +1 -1
  25. package/dist/components/overlays/kt-side-panel/kt-side-panel.d.ts +2 -0
  26. package/dist/components/overlays/kt-side-panel/kt-side-panel.js +30 -19
  27. package/dist/components/overlays/kt-side-panel/kt-side-panel.js.map +1 -1
  28. package/dist/components/overlays/kt-tour/kt-tour.d.ts +6 -0
  29. package/dist/components/overlays/kt-tour/kt-tour.js +23 -13
  30. package/dist/components/overlays/kt-tour/kt-tour.js.map +1 -1
  31. package/dist/custom-elements.json +4223 -4152
  32. package/dist/docs/kt-app-shell.md +2 -2
  33. package/dist/docs/kt-chat-message.md +13 -0
  34. package/dist/docs/kt-side-panel.md +13 -6
  35. package/dist/docs/kt-user-menu.md +15 -0
  36. package/dist/icons/defaults.d.ts +1 -0
  37. package/dist/icons/index.js +1 -1
  38. package/dist/index.js +1 -1
  39. package/dist/internal/floating.d.ts +1 -1
  40. package/dist/vscode.css-custom-data.json +32 -32
  41. package/dist/vscode.html-custom-data.json +356 -337
  42. package/dist/web-types.json +1063 -1030
  43. package/package.json +1 -1
  44. package/dist/chunks/defaults-BnB3ir8l.js +0 -71
  45. package/dist/chunks/floating-C9RLa6cZ.js.map +0 -1
@@ -0,0 +1,72 @@
1
+ import { X as s, User as a, Upload as i, TriangleAlert as c, Trash2 as l, Settings as f, Send as p, Search as g, RefreshCw as C, Plus as u, Pencil as y, PanelLeft as A, Minus as w, Menu as d, LoaderCircle as h, Info as I, Inbox as b, Filter as U, FileUp as $, File as v, EyeOff as L, Eye as k, ExternalLink as D, Ellipsis as E, Download as Z, Copy as m, CircleCheck as x, CircleAlert as z, ChevronsUpDown as F, ChevronUp as M, ChevronRight as P, ChevronLeft as S, ChevronDown as j, Check as O, Calendar as R, ArrowUp as T, 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 N(e, r) {
7
+ n.set(t(e), r);
8
+ }
9
+ function X(e) {
10
+ for (const [r, o] of Object.entries(e))
11
+ _(o) && N(r, o);
12
+ }
13
+ function G(e) {
14
+ return n.get(t(e));
15
+ }
16
+ function H() {
17
+ return [...n.keys()].sort();
18
+ }
19
+ function _(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 q = {
25
+ ArrowDown: K,
26
+ ArrowUp: T,
27
+ Calendar: R,
28
+ Check: O,
29
+ ChevronDown: j,
30
+ ChevronLeft: S,
31
+ ChevronRight: P,
32
+ ChevronUp: M,
33
+ ChevronsUpDown: F,
34
+ CircleAlert: z,
35
+ CircleCheck: x,
36
+ Copy: m,
37
+ Download: Z,
38
+ Ellipsis: E,
39
+ ExternalLink: D,
40
+ Eye: k,
41
+ EyeOff: L,
42
+ File: v,
43
+ FileUp: $,
44
+ Filter: U,
45
+ Inbox: b,
46
+ Info: I,
47
+ LoaderCircle: h,
48
+ Menu: d,
49
+ Minus: w,
50
+ PanelLeft: A,
51
+ Pencil: y,
52
+ Plus: u,
53
+ RefreshCw: C,
54
+ Search: g,
55
+ Send: p,
56
+ Settings: f,
57
+ Trash2: l,
58
+ TriangleAlert: c,
59
+ Upload: i,
60
+ User: a,
61
+ X: s
62
+ };
63
+ X(q);
64
+ export {
65
+ X as a,
66
+ H as b,
67
+ q as d,
68
+ G as g,
69
+ N as r,
70
+ t
71
+ };
72
+ //# sourceMappingURL=defaults-DaB3TcsM.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"defaults-BnB3ir8l.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, and the few a first\n * screen reaches for — plus, pencil, settings, download, upload, an external\n * link, a filter, an ellipsis, a refresh — so a button copied from the docs\n * draws its icon without a registration step.\n *\n * Importing any Kanto element pulls this set in — roughly 3 kB of path data,\n * the price of `<kt-select>` drawing its own chevron and a first `icon=\"plus\"`\n * working. Other application icons are registered through `registerIcons`.\n */\nimport {\n ArrowDown,\n ArrowUp,\n Calendar,\n Check,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n ChevronUp,\n CircleAlert,\n CircleCheck,\n Copy,\n Download,\n Ellipsis,\n ExternalLink,\n Eye,\n EyeOff,\n File,\n FileUp,\n Filter,\n Inbox,\n Info,\n LoaderCircle,\n Menu,\n Minus,\n PanelLeft,\n Pencil,\n Plus,\n RefreshCw,\n Search,\n Send,\n Settings,\n Trash2,\n TriangleAlert,\n Upload,\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 Calendar,\n Check,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n ChevronUp,\n CircleAlert,\n CircleCheck,\n Copy,\n Download,\n Ellipsis,\n ExternalLink,\n Eye,\n EyeOff,\n File,\n FileUp,\n Filter,\n Inbox,\n Info,\n LoaderCircle,\n Menu,\n Minus,\n PanelLeft,\n Pencil,\n Plus,\n RefreshCw,\n Search,\n Send,\n Settings,\n Trash2,\n TriangleAlert,\n Upload,\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","Calendar","Check","ChevronDown","ChevronLeft","ChevronRight","ChevronUp","CircleAlert","CircleCheck","Copy","Download","Ellipsis","ExternalLink","Eye","EyeOff","File","FileUp","Filter","Inbox","Info","LoaderCircle","Menu","Minus","PanelLeft","Pencil","Plus","RefreshCw","Search","Send","Settings","Trash2","TriangleAlert","Upload","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;ACrBO,MAAMC,IAAe;AAAA,EAC1B,WAAAC;AAAA,EACA,SAAAC;AAAA,EACA,UAAAC;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,UAAAC;AAAA,EACA,UAAAC;AAAA,EACA,cAAAC;AAAA,EACA,KAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAC;AAAA,EACA,QAAAC;AAAA,EACA,QAAAC;AAAA,EACA,OAAAC;AAAA,EACA,MAAAC;AAAA,EACA,cAAAC;AAAA,EACA,MAAAC;AAAA,EACA,OAAAC;AAAA,EACA,WAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAC;AAAA,EACA,WAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAC;AAAA,EACA,UAAAC;AAAA,EACA,QAAAC;AAAA,EACA,eAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAC;AAAA,EACA,GAAAC;AACF;AAEA3C,EAAcO,CAAY;"}
1
+ {"version":3,"file":"defaults-DaB3TcsM.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, and the few a first\n * screen reaches for — plus, pencil, settings, download, upload, an external\n * link, a filter, an ellipsis, a refresh — so a button copied from the docs\n * draws its icon without a registration step.\n *\n * Importing any Kanto element pulls this set in — roughly 3 kB of path data,\n * the price of `<kt-select>` drawing its own chevron and a first `icon=\"plus\"`\n * working. Other application icons are registered through `registerIcons`.\n */\nimport {\n ArrowDown,\n ArrowUp,\n Calendar,\n Check,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n ChevronUp,\n ChevronsUpDown,\n CircleAlert,\n CircleCheck,\n Copy,\n Download,\n Ellipsis,\n ExternalLink,\n Eye,\n EyeOff,\n File,\n FileUp,\n Filter,\n Inbox,\n Info,\n LoaderCircle,\n Menu,\n Minus,\n PanelLeft,\n Pencil,\n Plus,\n RefreshCw,\n Search,\n Send,\n Settings,\n Trash2,\n TriangleAlert,\n Upload,\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 Calendar,\n Check,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n ChevronUp,\n ChevronsUpDown,\n CircleAlert,\n CircleCheck,\n Copy,\n Download,\n Ellipsis,\n ExternalLink,\n Eye,\n EyeOff,\n File,\n FileUp,\n Filter,\n Inbox,\n Info,\n LoaderCircle,\n Menu,\n Minus,\n PanelLeft,\n Pencil,\n Plus,\n RefreshCw,\n Search,\n Send,\n Settings,\n Trash2,\n TriangleAlert,\n Upload,\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","Calendar","Check","ChevronDown","ChevronLeft","ChevronRight","ChevronUp","ChevronsUpDown","CircleAlert","CircleCheck","Copy","Download","Ellipsis","ExternalLink","Eye","EyeOff","File","FileUp","Filter","Inbox","Info","LoaderCircle","Menu","Minus","PanelLeft","Pencil","Plus","RefreshCw","Search","Send","Settings","Trash2","TriangleAlert","Upload","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;ACpBO,MAAMC,IAAe;AAAA,EAC1B,WAAAC;AAAA,EACA,SAAAC;AAAA,EACA,UAAAC;AAAA,EACA,OAAAC;AAAA,EACA,aAAAC;AAAA,EACA,aAAAC;AAAA,EACA,cAAAC;AAAA,EACA,WAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,aAAAC;AAAA,EACA,aAAAC;AAAA,EACA,MAAAC;AAAA,EACA,UAAAC;AAAA,EACA,UAAAC;AAAA,EACA,cAAAC;AAAA,EACA,KAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAC;AAAA,EACA,QAAAC;AAAA,EACA,QAAAC;AAAA,EACA,OAAAC;AAAA,EACA,MAAAC;AAAA,EACA,cAAAC;AAAA,EACA,MAAAC;AAAA,EACA,OAAAC;AAAA,EACA,WAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAC;AAAA,EACA,WAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAC;AAAA,EACA,UAAAC;AAAA,EACA,QAAAC;AAAA,EACA,eAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAC;AAAA,EACA,GAAAC;AACF;AAEA5C,EAAcO,CAAY;"}
@@ -1,6 +1,6 @@
1
- import { css as n } from "lit";
2
- import { p as r } from "./position-Cx_ZH5zh.js";
3
- const p = n`
1
+ import { css as r } from "lit";
2
+ import { p as a } from "./position-Cx_ZH5zh.js";
3
+ const d = r`
4
4
  .floating {
5
5
  position: fixed;
6
6
  inset: 0 auto auto 0;
@@ -16,7 +16,7 @@ const p = n`
16
16
  box-shadow: var(--shadow-popover);
17
17
  }
18
18
  `;
19
- class d {
19
+ class c {
20
20
  constructor(e, t) {
21
21
  this.options = t, this.open = !1, this.frame = 0, this.follow = () => {
22
22
  cancelAnimationFrame(this.frame), this.frame = requestAnimationFrame(() => this.place());
@@ -45,19 +45,20 @@ class d {
45
45
  place() {
46
46
  const e = this.options.panel(), t = this.options.anchor()?.getBoundingClientRect();
47
47
  if (!e || !t) return;
48
- this.options.matchWidth && (e.style.width = `${t.width}px`);
49
- const { x: i, y: o, placement: s } = r(
48
+ const i = this.options.matchWidth;
49
+ (typeof i == "function" ? i() : i) && (e.style.width = `${t.width}px`);
50
+ const { x: o, y: s, placement: n } = a(
50
51
  t,
51
52
  { width: e.offsetWidth, height: e.offsetHeight },
52
53
  { width: window.innerWidth, height: window.innerHeight },
53
54
  this.options.side?.() ?? "bottom",
54
55
  this.options.align?.() ?? "start"
55
56
  );
56
- e.style.left = `${i}px`, e.style.top = `${o}px`, this.options.onPlace?.(s);
57
+ e.style.left = `${o}px`, e.style.top = `${s}px`, this.options.onPlace?.(n);
57
58
  }
58
59
  }
59
60
  export {
60
- d as F,
61
- p as f
61
+ c as F,
62
+ d as f
62
63
  };
63
- //# sourceMappingURL=floating-C9RLa6cZ.js.map
64
+ //# sourceMappingURL=floating-DxiFx4AK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floating-DxiFx4AK.js","sources":["../../src/internal/floating.ts"],"sourcesContent":["import { css, type ReactiveController, type ReactiveControllerHost } from 'lit';\nimport { placeFloating, type Align, type Side } from './position.js';\n\n/**\n * A panel that opens from a trigger — a select's list, a date picker's\n * calendar, a menu — drawn in the top layer and placed from the trigger.\n *\n * A panel positioned inside its element was cut off by any ancestor with\n * `overflow: hidden`: a table cell, a side panel, an app's scrolling main\n * area. In the top layer, nothing clips it. It opens on the side asked for, or\n * the other one when that has no room, and follows the trigger as the page\n * scrolls.\n */\n\nexport interface FloatingOptions {\n /** The panel, which carries `popover=\"manual\"` and the `floating` class. */\n readonly panel: () => HTMLElement | null | undefined;\n /** What the panel opens from. */\n readonly anchor: () => Element | null | undefined;\n /** The side it prefers. */\n readonly side?: () => Side;\n /** Which edge of the anchor it lines up with; its start by default. */\n readonly align?: () => Align;\n /** Sizes the panel to the anchor's width — a list under its field. */\n readonly matchWidth?: boolean | (() => boolean);\n /** Told the side it opened on, for the direction of its entrance. */\n readonly onPlace?: (side: Side) => void;\n}\n\n/**\n * The panel's own styles. Closed, it keeps the display and the hidden,\n * animatable state its element gives it, so it can fade out after it leaves\n * the top layer: `display` here only undoes the popover's `display: none`, and\n * a panel's own `display` still wins.\n *\n * Until it is first placed it sits top left. With auto insets a closed panel\n * sat where the flow put it — beside a right-hand trigger, past the edge of\n * the page, which then scrolled sideways.\n */\nexport const floatingStyles = css`\n .floating {\n position: fixed;\n inset: 0 auto auto 0;\n display: block;\n /* As wide as what it holds, wherever it is placed: a box sized from its\n position would change size when moved, and be moved again. */\n width: max-content;\n margin: 0;\n color: inherit;\n /* Set apart from the page by the theme: a lighter surface in the dark,\n an edge and a soft shadow in the light. */\n border: var(--border-width) solid var(--border-popover);\n box-shadow: var(--shadow-popover);\n }\n`;\n\nexport class FloatingController implements ReactiveController {\n private open = false;\n private frame = 0;\n /** Places the panel again when its size changes — content drawn after it opened. */\n private resizeObserver: ResizeObserver | undefined;\n\n constructor(\n host: ReactiveControllerHost,\n private readonly options: FloatingOptions,\n ) {\n host.addController(this);\n }\n\n /**\n * Call from the host's `updated()` with whether the panel is open. While it\n * is, every update re-places it: its content — a filtered list — can change\n * its size.\n */\n sync(open: boolean): void {\n // First, and whatever the panel: one rendered only while open is already\n // gone when it closes, and its listeners must go with it.\n if (open !== this.open) {\n this.open = open;\n const method = open ? 'addEventListener' : 'removeEventListener';\n window[method]('scroll', this.follow, { capture: true, passive: true });\n window[method]('resize', this.follow);\n }\n\n const panel = this.options.panel();\n // Where popovers are missing — a test DOM — the panel stays where it is.\n if (!panel || typeof panel.showPopover !== 'function') return;\n\n if (open) {\n if (!panel.matches(':popover-open')) panel.showPopover();\n this.place();\n // A panel measured at opening may grow once what it holds has drawn —\n // a calendar is an element of its own — and must be placed again.\n if (!this.resizeObserver && typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver(this.follow);\n this.resizeObserver.observe(panel);\n }\n } else {\n this.unobserve();\n if (panel.matches(':popover-open')) panel.hidePopover();\n }\n }\n\n private unobserve(): void {\n this.resizeObserver?.disconnect();\n this.resizeObserver = undefined;\n }\n\n hostDisconnected(): void {\n this.sync(false);\n this.unobserve();\n cancelAnimationFrame(this.frame);\n }\n\n private follow = (): void => {\n cancelAnimationFrame(this.frame);\n this.frame = requestAnimationFrame(() => this.place());\n };\n\n private place(): void {\n const panel = this.options.panel();\n const anchor = this.options.anchor()?.getBoundingClientRect();\n if (!panel || !anchor) return;\n\n const match = this.options.matchWidth;\n if (typeof match === 'function' ? match() : match) panel.style.width = `${anchor.width}px`;\n // Untransformed size: the entrance animation scales and slides the panel.\n const { x, y, placement } = placeFloating(\n anchor,\n { width: panel.offsetWidth, height: panel.offsetHeight },\n { width: window.innerWidth, height: window.innerHeight },\n this.options.side?.() ?? 'bottom',\n this.options.align?.() ?? 'start',\n );\n panel.style.left = `${x}px`;\n panel.style.top = `${y}px`;\n this.options.onPlace?.(placement);\n }\n}\n"],"names":["floatingStyles","css","FloatingController","host","options","open","method","panel","anchor","match","x","y","placement","placeFloating"],"mappings":";;AAuCO,MAAMA,IAAiBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBvB,MAAMC,EAAiD;AAAA,EAM5D,YACEC,GACiBC,GACjB;AADiB,SAAA,UAAAA,GAPnB,KAAQ,OAAO,IACf,KAAQ,QAAQ,GAwDhB,KAAQ,SAAS,MAAY;AAC3B,2BAAqB,KAAK,KAAK,GAC/B,KAAK,QAAQ,sBAAsB,MAAM,KAAK,OAAO;AAAA,IACvD,GAnDED,EAAK,cAAc,IAAI;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,KAAKE,GAAqB;AAGxB,QAAIA,MAAS,KAAK,MAAM;AACtB,WAAK,OAAOA;AACZ,YAAMC,IAASD,IAAO,qBAAqB;AAC3C,aAAOC,CAAM,EAAE,UAAU,KAAK,QAAQ,EAAE,SAAS,IAAM,SAAS,IAAM,GACtE,OAAOA,CAAM,EAAE,UAAU,KAAK,MAAM;AAAA,IACtC;AAEA,UAAMC,IAAQ,KAAK,QAAQ,MAAA;AAE3B,IAAI,CAACA,KAAS,OAAOA,EAAM,eAAgB,eAEvCF,KACGE,EAAM,QAAQ,eAAe,OAAS,YAAA,GAC3C,KAAK,MAAA,GAGD,CAAC,KAAK,kBAAkB,OAAO,iBAAmB,QACpD,KAAK,iBAAiB,IAAI,eAAe,KAAK,MAAM,GACpD,KAAK,eAAe,QAAQA,CAAK,OAGnC,KAAK,UAAA,GACDA,EAAM,QAAQ,eAAe,OAAS,YAAA;AAAA,EAE9C;AAAA,EAEQ,YAAkB;AACxB,SAAK,gBAAgB,WAAA,GACrB,KAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,mBAAyB;AACvB,SAAK,KAAK,EAAK,GACf,KAAK,UAAA,GACL,qBAAqB,KAAK,KAAK;AAAA,EACjC;AAAA,EAOQ,QAAc;AACpB,UAAMA,IAAQ,KAAK,QAAQ,MAAA,GACrBC,IAAS,KAAK,QAAQ,OAAA,GAAU,sBAAA;AACtC,QAAI,CAACD,KAAS,CAACC,EAAQ;AAEvB,UAAMC,IAAQ,KAAK,QAAQ;AAC3B,KAAI,OAAOA,KAAU,aAAaA,EAAA,IAAUA,OAAOF,EAAM,MAAM,QAAQ,GAAGC,EAAO,KAAK;AAEtF,UAAM,EAAE,GAAAE,GAAG,GAAAC,GAAG,WAAAC,EAAA,IAAcC;AAAA,MAC1BL;AAAA,MACA,EAAE,OAAOD,EAAM,aAAa,QAAQA,EAAM,aAAA;AAAA,MAC1C,EAAE,OAAO,OAAO,YAAY,QAAQ,OAAO,YAAA;AAAA,MAC3C,KAAK,QAAQ,OAAA,KAAY;AAAA,MACzB,KAAK,QAAQ,aAAa;AAAA,IAAA;AAE5B,IAAAA,EAAM,MAAM,OAAO,GAAGG,CAAC,MACvBH,EAAM,MAAM,MAAM,GAAGI,CAAC,MACtB,KAAK,QAAQ,UAAUC,CAAS;AAAA,EAClC;AACF;"}
@@ -1,7 +1,7 @@
1
1
  import { css as f, html as c, nothing as l } from "lit";
2
2
  import { property as n } from "lit/decorators.js";
3
3
  import { K as m, d as u } from "../../../chunks/kt-element-DvWtPQ1Y.js";
4
- import { g as v } from "../../../chunks/defaults-BnB3ir8l.js";
4
+ import { g as v } from "../../../chunks/defaults-DaB3TcsM.js";
5
5
  var w = Object.defineProperty, o = (i, e, r, h) => {
6
6
  for (var t = void 0, a = i.length - 1, d; a >= 0; a--)
7
7
  (d = i[a]) && (t = d(e, r, t) || t);
@@ -51,6 +51,12 @@ export declare class KtChatMessage extends KtElement {
51
51
  thinking: boolean;
52
52
  /** Still arriving: a caret after the last word. */
53
53
  streaming: boolean;
54
+ /**
55
+ * The next message of a run from one person: no avatar and no name again,
56
+ * the words lined up with the first. Its time moves to the avatar's gutter,
57
+ * read by a screen reader, shown on hover or focus.
58
+ */
59
+ continued: boolean;
54
60
  render(): TemplateResult;
55
61
  }
56
62
  declare global {
@@ -1,16 +1,16 @@
1
1
  import { css as c, nothing as t, html as a } from "lit";
2
2
  import { property as i } from "lit/decorators.js";
3
- import { K as h, d as v } from "../../../chunks/kt-element-DvWtPQ1Y.js";
4
- import { s as g } from "../../../chunks/index-1ZFgagWW.js";
3
+ import { K as h, d as u } from "../../../chunks/kt-element-DvWtPQ1Y.js";
4
+ import { s as v } from "../../../chunks/index-1ZFgagWW.js";
5
5
  import "../../core/kt-avatar/kt-avatar.js";
6
- var f = Object.defineProperty, r = (l, s, o, d) => {
6
+ var g = Object.defineProperty, r = (l, s, o, d) => {
7
7
  for (var n = void 0, p = l.length - 1, m; p >= 0; p--)
8
8
  (m = l[p]) && (n = m(s, o, n) || n);
9
- return n && f(s, o, n), n;
9
+ return n && g(s, o, n), n;
10
10
  };
11
11
  class e extends h {
12
12
  constructor() {
13
- super(...arguments), this.from = "assistant", this.name = "", this.avatar = "", this.time = "", this.datetime = "", this.thinking = !1, this.streaming = !1;
13
+ super(...arguments), this.from = "assistant", this.name = "", this.avatar = "", this.time = "", this.datetime = "", this.thinking = !1, this.streaming = !1, this.continued = !1;
14
14
  }
15
15
  static {
16
16
  this.styles = [
@@ -33,6 +33,31 @@ class e extends h {
33
33
  flex: none;
34
34
  line-height: 0;
35
35
  }
36
+ /* A run's next message: the small avatar's room (24px) kept, so the words line up. */
37
+ .avatar.spacer {
38
+ position: relative;
39
+ width: 24px;
40
+ }
41
+ /* Its time, in the gutter: there for a screen reader, shown on hover or focus. */
42
+ .gutter-time {
43
+ position: absolute;
44
+ top: 0.35em;
45
+ right: -4px;
46
+ color: var(--text-muted);
47
+ font: var(--font-normal-small);
48
+ font-size: 10px;
49
+ line-height: 1.6;
50
+ white-space: nowrap;
51
+ opacity: 0;
52
+ transition: opacity var(--duration-fast) var(--easing-standard);
53
+ }
54
+ :host(:hover) .gutter-time,
55
+ :host(:focus-within) .gutter-time {
56
+ opacity: 1;
57
+ }
58
+ :host([continued]) .meta {
59
+ display: none;
60
+ }
36
61
 
37
62
  .body {
38
63
  display: grid;
@@ -158,18 +183,26 @@ class e extends h {
158
183
  aria-label=${this.name || t}
159
184
  aria-busy=${o ? "true" : t}
160
185
  >
161
- ${s ? t : a`<div class="avatar">
162
- <slot name="avatar"
163
- ><kt-avatar name=${this.name} src=${this.avatar || t} size="small"></kt-avatar
164
- ></slot>
165
- </div>`}
186
+ ${s ? t : this.continued ? a`<div class="avatar spacer">
187
+ ${this.time ? a`<time class="gutter-time" datetime=${this.datetime || t}
188
+ >${this.time}</time
189
+ >` : t}
190
+ </div>` : a`<div class="avatar">
191
+ <slot name="avatar"
192
+ ><kt-avatar
193
+ name=${this.name}
194
+ src=${this.avatar || t}
195
+ size="small"
196
+ ></kt-avatar
197
+ ></slot>
198
+ </div>`}
166
199
  <div class="body">
167
200
  ${this.name || this.time ? a`<div part="meta" class="meta">
168
- ${this.name && !s ? a`<span class="name">${this.name}</span>` : t}
201
+ ${this.name && !s && !this.continued ? a`<span class="name">${this.name}</span>` : t}
169
202
  ${this.time ? a`<time datetime=${this.datetime || t}>${this.time}</time>` : t}
170
203
  </div>` : t}
171
204
  ${this.thinking ? a`<span class="dots" aria-hidden="true"><i></i><i></i><i></i></span
172
- ><span class="visually-hidden">${g().thinking}</span>` : t}
205
+ ><span class="visually-hidden">${v().thinking}</span>` : t}
173
206
  ${s ? a`<div part="bubble" class="bubble">${d}</div>` : d}
174
207
  <div class="actions"><slot name="actions"></slot></div>
175
208
  </div>
@@ -197,7 +230,10 @@ r([
197
230
  r([
198
231
  i({ type: Boolean, reflect: !0 })
199
232
  ], e.prototype, "streaming");
200
- v("kt-chat-message", e);
233
+ r([
234
+ i({ type: Boolean, reflect: !0 })
235
+ ], e.prototype, "continued");
236
+ u("kt-chat-message", e);
201
237
  export {
202
238
  e as KtChatMessage
203
239
  };
@@ -1 +1 @@
1
- {"version":3,"file":"kt-chat-message.js","sources":["../../../../src/components/data/kt-chat-message/kt-chat-message.ts"],"sourcesContent":["import { css, html, nothing, type TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { strings } from '#internal/strings';\nimport '../../core/kt-avatar/kt-avatar.js';\n\nexport type KtChatMessageFrom = 'assistant' | 'user';\n\n/**\n * One message of a conversation with an assistant.\n *\n * An assistant's reply sits beside its avatar, as text on the page — a reply\n * is often long, and a bubble around paragraphs, lists and code only crowds\n * them. A person's message sits in a bubble on the other side, short and\n * clearly theirs.\n *\n * `thinking` shows three dots, and says so in words, until the reply has a\n * word of its own; `streaming` marks the end of a reply still arriving. Both\n * set `aria-busy`. The content is the default slot: render your markdown into\n * it, as you would anywhere.\n *\n * @element kt-chat-message\n *\n * @slot - The message.\n * @slot avatar - Replaces the avatar drawn from `name` and `avatar`.\n * @slot actions - Under the message: copy, retry, a rating.\n *\n * @csspart base - The `<article>`.\n * @csspart bubble - A person's bubble.\n * @csspart content - The message.\n * @csspart meta - The author and the time.\n *\n * @example\n * ```html\n * <kt-chat-message from=\"user\" name=\"Dana\">What changed this week?</kt-chat-message>\n * <kt-chat-message name=\"Northwind AI\" time=\"09:41\">\n * <p>Revenue rose 12%, led by three new Team plans.</p>\n * <kt-button slot=\"actions\" size=\"small\" variant=\"text\" icon=\"copy\">Copy</kt-button>\n * </kt-chat-message>\n * ```\n */\nexport class KtChatMessage extends KtElement {\n static override styles = [\n KtElement.styles,\n css`\n :host {\n display: block;\n }\n\n article {\n display: flex;\n gap: var(--gap-form);\n align-items: flex-start;\n }\n :host([from='user']) article {\n justify-content: flex-end;\n }\n\n .avatar {\n flex: none;\n line-height: 0;\n }\n\n .body {\n display: grid;\n gap: var(--gap-element);\n min-width: 0;\n max-width: 100%;\n }\n :host([from='user']) .body {\n justify-items: end;\n max-width: min(75%, 560px);\n }\n\n .meta {\n display: flex;\n gap: var(--gap-button);\n align-items: baseline;\n color: var(--text-muted);\n font: var(--font-normal-small);\n }\n .name {\n color: var(--text-body);\n font: var(--font-normal-medium);\n }\n\n .content {\n min-width: 0;\n color: var(--text-body);\n font: var(--font-normal-regular);\n line-height: 1.6;\n overflow-wrap: anywhere;\n }\n .content[hidden] {\n display: none;\n }\n .content ::slotted(:first-child) {\n margin-top: 0;\n }\n .content ::slotted(:last-child) {\n margin-bottom: 0;\n }\n\n .bubble {\n padding: var(--padding-expand) var(--padding-form);\n background: var(--color-primary-soft);\n border-radius: var(--border-radius-card);\n border-end-end-radius: var(--radius-sub-menu);\n }\n\n /* A reply still arriving: a caret after its last word. */\n .caret {\n display: inline-block;\n width: 0.5em;\n height: 1.1em;\n margin-inline-start: 2px;\n vertical-align: text-bottom;\n background: var(--color-primary-base);\n border-radius: 1px;\n animation: kt-chat-caret calc(var(--duration-slow) * 2.5) steps(1) infinite;\n }\n @keyframes kt-chat-caret {\n 50% {\n opacity: 0;\n }\n }\n\n /* Thinking: three dots, one after another. */\n .dots {\n display: inline-flex;\n gap: 4px;\n align-items: center;\n height: 1.6em;\n }\n .dots i {\n width: 6px;\n height: 6px;\n background: var(--text-muted);\n border-radius: var(--radius-full);\n animation: kt-chat-dot calc(var(--duration-slow) * 3) var(--easing-standard) infinite;\n }\n .dots i:nth-child(2) {\n animation-delay: calc(var(--duration-slow) * 0.5);\n }\n .dots i:nth-child(3) {\n animation-delay: var(--duration-slow);\n }\n @keyframes kt-chat-dot {\n 0%,\n 60%,\n 100% {\n opacity: 0.35;\n translate: 0 0;\n }\n 30% {\n opacity: 1;\n translate: 0 -3px;\n }\n }\n\n .actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--gap-element);\n color: var(--text-muted);\n }\n\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 /** Who wrote it: an `assistant`, beside its avatar, or the `user`, in a bubble. */\n @property({ type: String, reflect: true })\n from: KtChatMessageFrom = 'assistant';\n\n /** The author: names the message, and draws the avatar's initials. */\n @property({ type: String })\n name = '';\n\n /** A picture for the avatar. */\n @property({ type: String })\n avatar = '';\n\n /** When it was sent, as shown. */\n @property({ type: String })\n time = '';\n\n /** The same moment, machine-readable, for the `<time>`. */\n @property({ type: String })\n datetime = '';\n\n /** Thinking: dots instead of the content, until the reply has a word. */\n @property({ type: Boolean, reflect: true })\n thinking = false;\n\n /** Still arriving: a caret after the last word. */\n @property({ type: Boolean, reflect: true })\n streaming = false;\n\n override render(): TemplateResult {\n const user = this.from === 'user';\n const busy = this.thinking || this.streaming;\n const content = html`<div part=\"content\" class=\"content\" ?hidden=${this.thinking}>\n <slot></slot>${\n this.streaming && !this.thinking\n ? html`<span class=\"caret\" aria-hidden=\"true\"></span>`\n : nothing\n }\n </div>`;\n\n return html`<article\n part=\"base\"\n aria-label=${this.name || nothing}\n aria-busy=${busy ? 'true' : nothing}\n >\n ${\n user\n ? nothing\n : html`<div class=\"avatar\">\n <slot name=\"avatar\"\n ><kt-avatar name=${this.name} src=${this.avatar || nothing} size=\"small\"></kt-avatar\n ></slot>\n </div>`\n }\n <div class=\"body\">\n ${\n this.name || this.time\n ? html`<div part=\"meta\" class=\"meta\">\n ${this.name && !user ? html`<span class=\"name\">${this.name}</span>` : nothing}\n ${\n this.time\n ? html`<time datetime=${this.datetime || nothing}>${this.time}</time>`\n : nothing\n }\n </div>`\n : nothing\n }\n ${\n this.thinking\n ? html`<span class=\"dots\" aria-hidden=\"true\"><i></i><i></i><i></i></span\n ><span class=\"visually-hidden\">${strings().thinking}</span>`\n : nothing\n }\n ${user ? html`<div part=\"bubble\" class=\"bubble\">${content}</div>` : content}\n <div class=\"actions\"><slot name=\"actions\"></slot></div>\n </div>\n </article>`;\n }\n}\n\ndefineElement('kt-chat-message', KtChatMessage);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-chat-message': KtChatMessage;\n }\n}\n"],"names":["KtChatMessage","KtElement","css","user","busy","content","html","nothing","strings","__decorateClass","property","defineElement"],"mappings":"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"}
1
+ {"version":3,"file":"kt-chat-message.js","sources":["../../../../src/components/data/kt-chat-message/kt-chat-message.ts"],"sourcesContent":["import { css, html, nothing, type TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { strings } from '#internal/strings';\nimport '../../core/kt-avatar/kt-avatar.js';\n\nexport type KtChatMessageFrom = 'assistant' | 'user';\n\n/**\n * One message of a conversation with an assistant.\n *\n * An assistant's reply sits beside its avatar, as text on the page — a reply\n * is often long, and a bubble around paragraphs, lists and code only crowds\n * them. A person's message sits in a bubble on the other side, short and\n * clearly theirs.\n *\n * `thinking` shows three dots, and says so in words, until the reply has a\n * word of its own; `streaming` marks the end of a reply still arriving. Both\n * set `aria-busy`. The content is the default slot: render your markdown into\n * it, as you would anywhere.\n *\n * @element kt-chat-message\n *\n * @slot - The message.\n * @slot avatar - Replaces the avatar drawn from `name` and `avatar`.\n * @slot actions - Under the message: copy, retry, a rating.\n *\n * @csspart base - The `<article>`.\n * @csspart bubble - A person's bubble.\n * @csspart content - The message.\n * @csspart meta - The author and the time.\n *\n * @example\n * ```html\n * <kt-chat-message from=\"user\" name=\"Dana\">What changed this week?</kt-chat-message>\n * <kt-chat-message name=\"Northwind AI\" time=\"09:41\">\n * <p>Revenue rose 12%, led by three new Team plans.</p>\n * <kt-button slot=\"actions\" size=\"small\" variant=\"text\" icon=\"copy\">Copy</kt-button>\n * </kt-chat-message>\n * ```\n */\nexport class KtChatMessage extends KtElement {\n static override styles = [\n KtElement.styles,\n css`\n :host {\n display: block;\n }\n\n article {\n display: flex;\n gap: var(--gap-form);\n align-items: flex-start;\n }\n :host([from='user']) article {\n justify-content: flex-end;\n }\n\n .avatar {\n flex: none;\n line-height: 0;\n }\n /* A run's next message: the small avatar's room (24px) kept, so the words line up. */\n .avatar.spacer {\n position: relative;\n width: 24px;\n }\n /* Its time, in the gutter: there for a screen reader, shown on hover or focus. */\n .gutter-time {\n position: absolute;\n top: 0.35em;\n right: -4px;\n color: var(--text-muted);\n font: var(--font-normal-small);\n font-size: 10px;\n line-height: 1.6;\n white-space: nowrap;\n opacity: 0;\n transition: opacity var(--duration-fast) var(--easing-standard);\n }\n :host(:hover) .gutter-time,\n :host(:focus-within) .gutter-time {\n opacity: 1;\n }\n :host([continued]) .meta {\n display: none;\n }\n\n .body {\n display: grid;\n gap: var(--gap-element);\n min-width: 0;\n max-width: 100%;\n }\n :host([from='user']) .body {\n justify-items: end;\n max-width: min(75%, 560px);\n }\n\n .meta {\n display: flex;\n gap: var(--gap-button);\n align-items: baseline;\n color: var(--text-muted);\n font: var(--font-normal-small);\n }\n .name {\n color: var(--text-body);\n font: var(--font-normal-medium);\n }\n\n .content {\n min-width: 0;\n color: var(--text-body);\n font: var(--font-normal-regular);\n line-height: 1.6;\n overflow-wrap: anywhere;\n }\n .content[hidden] {\n display: none;\n }\n .content ::slotted(:first-child) {\n margin-top: 0;\n }\n .content ::slotted(:last-child) {\n margin-bottom: 0;\n }\n\n .bubble {\n padding: var(--padding-expand) var(--padding-form);\n background: var(--color-primary-soft);\n border-radius: var(--border-radius-card);\n border-end-end-radius: var(--radius-sub-menu);\n }\n\n /* A reply still arriving: a caret after its last word. */\n .caret {\n display: inline-block;\n width: 0.5em;\n height: 1.1em;\n margin-inline-start: 2px;\n vertical-align: text-bottom;\n background: var(--color-primary-base);\n border-radius: 1px;\n animation: kt-chat-caret calc(var(--duration-slow) * 2.5) steps(1) infinite;\n }\n @keyframes kt-chat-caret {\n 50% {\n opacity: 0;\n }\n }\n\n /* Thinking: three dots, one after another. */\n .dots {\n display: inline-flex;\n gap: 4px;\n align-items: center;\n height: 1.6em;\n }\n .dots i {\n width: 6px;\n height: 6px;\n background: var(--text-muted);\n border-radius: var(--radius-full);\n animation: kt-chat-dot calc(var(--duration-slow) * 3) var(--easing-standard) infinite;\n }\n .dots i:nth-child(2) {\n animation-delay: calc(var(--duration-slow) * 0.5);\n }\n .dots i:nth-child(3) {\n animation-delay: var(--duration-slow);\n }\n @keyframes kt-chat-dot {\n 0%,\n 60%,\n 100% {\n opacity: 0.35;\n translate: 0 0;\n }\n 30% {\n opacity: 1;\n translate: 0 -3px;\n }\n }\n\n .actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--gap-element);\n color: var(--text-muted);\n }\n\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 /** Who wrote it: an `assistant`, beside its avatar, or the `user`, in a bubble. */\n @property({ type: String, reflect: true })\n from: KtChatMessageFrom = 'assistant';\n\n /** The author: names the message, and draws the avatar's initials. */\n @property({ type: String })\n name = '';\n\n /** A picture for the avatar. */\n @property({ type: String })\n avatar = '';\n\n /** When it was sent, as shown. */\n @property({ type: String })\n time = '';\n\n /** The same moment, machine-readable, for the `<time>`. */\n @property({ type: String })\n datetime = '';\n\n /** Thinking: dots instead of the content, until the reply has a word. */\n @property({ type: Boolean, reflect: true })\n thinking = false;\n\n /** Still arriving: a caret after the last word. */\n @property({ type: Boolean, reflect: true })\n streaming = false;\n\n /**\n * The next message of a run from one person: no avatar and no name again,\n * the words lined up with the first. Its time moves to the avatar's gutter,\n * read by a screen reader, shown on hover or focus.\n */\n @property({ type: Boolean, reflect: true })\n continued = false;\n\n override render(): TemplateResult {\n const user = this.from === 'user';\n const busy = this.thinking || this.streaming;\n const content = html`<div part=\"content\" class=\"content\" ?hidden=${this.thinking}>\n <slot></slot>${\n this.streaming && !this.thinking\n ? html`<span class=\"caret\" aria-hidden=\"true\"></span>`\n : nothing\n }\n </div>`;\n\n return html`<article\n part=\"base\"\n aria-label=${this.name || nothing}\n aria-busy=${busy ? 'true' : nothing}\n >\n ${\n user\n ? nothing\n : this.continued\n ? html`<div class=\"avatar spacer\">\n ${\n this.time\n ? html`<time class=\"gutter-time\" datetime=${this.datetime || nothing}\n >${this.time}</time\n >`\n : nothing\n }\n </div>`\n : html`<div class=\"avatar\">\n <slot name=\"avatar\"\n ><kt-avatar\n name=${this.name}\n src=${this.avatar || nothing}\n size=\"small\"\n ></kt-avatar\n ></slot>\n </div>`\n }\n <div class=\"body\">\n ${\n this.name || this.time\n ? html`<div part=\"meta\" class=\"meta\">\n ${\n this.name && !user && !this.continued\n ? html`<span class=\"name\">${this.name}</span>`\n : nothing\n }\n ${\n this.time\n ? html`<time datetime=${this.datetime || nothing}>${this.time}</time>`\n : nothing\n }\n </div>`\n : nothing\n }\n ${\n this.thinking\n ? html`<span class=\"dots\" aria-hidden=\"true\"><i></i><i></i><i></i></span\n ><span class=\"visually-hidden\">${strings().thinking}</span>`\n : nothing\n }\n ${user ? html`<div part=\"bubble\" class=\"bubble\">${content}</div>` : content}\n <div class=\"actions\"><slot name=\"actions\"></slot></div>\n </div>\n </article>`;\n }\n}\n\ndefineElement('kt-chat-message', KtChatMessage);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-chat-message': KtChatMessage;\n }\n}\n"],"names":["KtChatMessage","KtElement","css","user","busy","content","html","nothing","strings","__decorateClass","property","defineElement"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { property as w, state as x, query as $ } from "lit/decorators.js";
3
3
  import { classMap as C } from "lit/directives/class-map.js";
4
4
  import { d as P } from "../../../chunks/kt-element-DvWtPQ1Y.js";
5
5
  import { u as S, t as I } from "../../../chunks/events-r51msXNf.js";
6
- import { F as q, f as E } from "../../../chunks/floating-C9RLa6cZ.js";
6
+ import { F as q, f as E } from "../../../chunks/floating-DxiFx4AK.js";
7
7
  import { K as f } from "../../../chunks/segmented-field-T_Zo6lc1.js";
8
8
  import { d as y, p as u, t as v, c as b, f as Y } from "../../../chunks/kt-calendar-SK8eapuy.js";
9
9
  import { d as K, e as L, t as M } from "../../../chunks/typed-date-CaU0kXoY.js";
@@ -5,7 +5,7 @@ import { live as O } from "lit/directives/live.js";
5
5
  import { K as D, d as R } from "../../../chunks/kt-element-DvWtPQ1Y.js";
6
6
  import { u as q, t as E, e as v } from "../../../chunks/events-r51msXNf.js";
7
7
  import { a as B, s as F, b as L } from "../../../chunks/form-control-B74_EHtG.js";
8
- import { F as z, f as K } from "../../../chunks/floating-C9RLa6cZ.js";
8
+ import { F as z, f as K } from "../../../chunks/floating-DxiFx4AK.js";
9
9
  import { r as M, d as _ } from "../../../chunks/locale-C5xLkGx5.js";
10
10
  import { s as f } from "../../../chunks/index-1ZFgagWW.js";
11
11
  import { a as P, p as u, c as g, b as w, t as m, e as k, f as C, g as V, h as I, d as W } from "../../../chunks/kt-calendar-SK8eapuy.js";
@@ -5,7 +5,7 @@ import { live as w } from "lit/directives/live.js";
5
5
  import { K as g, d as $ } from "../../../chunks/kt-element-DvWtPQ1Y.js";
6
6
  import { t as C, e as c } from "../../../chunks/events-r51msXNf.js";
7
7
  import { a as S, s as b, b as E } from "../../../chunks/form-control-B74_EHtG.js";
8
- import { F as O, f as z } from "../../../chunks/floating-C9RLa6cZ.js";
8
+ import { F as O, f as z } from "../../../chunks/floating-DxiFx4AK.js";
9
9
  import { s as u } from "../../../chunks/index-1ZFgagWW.js";
10
10
  import "../../core/kt-icon/kt-icon.js";
11
11
  import "../../feedback/kt-tooltip/kt-tooltip.js";
@@ -6,7 +6,7 @@ import { K as m, d as $ } from "../../../chunks/kt-element-DvWtPQ1Y.js";
6
6
  import { u as I, t as y, e as f } from "../../../chunks/events-r51msXNf.js";
7
7
  import { a as D, s as q, b as O } from "../../../chunks/form-control-B74_EHtG.js";
8
8
  import { a as S, b as C, o as g, f as v, l as P, n as E } from "../../../chunks/listbox-LsUEyGhQ.js";
9
- import { F as L, f as A } from "../../../chunks/floating-C9RLa6cZ.js";
9
+ import { F as L, f as A } from "../../../chunks/floating-DxiFx4AK.js";
10
10
  import { s as l } from "../../../chunks/index-1ZFgagWW.js";
11
11
  import "../../core/kt-icon/kt-icon.js";
12
12
  var V = Object.defineProperty, i = (u, t, o, r) => {
@@ -6,7 +6,7 @@ import { K as $, d as P } from "../../../chunks/kt-element-DvWtPQ1Y.js";
6
6
  import { u as C, t as I, e as D } from "../../../chunks/events-r51msXNf.js";
7
7
  import { a as L, s as z, b as B } from "../../../chunks/form-control-B74_EHtG.js";
8
8
  import { a as T, b as F, f as y, l as V, n as _, o as w } from "../../../chunks/listbox-LsUEyGhQ.js";
9
- import { F as A, f as W } from "../../../chunks/floating-C9RLa6cZ.js";
9
+ import { F as A, f as W } from "../../../chunks/floating-DxiFx4AK.js";
10
10
  import { s as p } from "../../../chunks/index-1ZFgagWW.js";
11
11
  import "../../core/kt-icon/kt-icon.js";
12
12
  var K = Object.defineProperty, r = (m, t, i, e) => {
@@ -5,7 +5,7 @@ import { K as v, d as w } from "../../../chunks/kt-element-DvWtPQ1Y.js";
5
5
  import { u as k, t as g, e as m } from "../../../chunks/events-r51msXNf.js";
6
6
  import { a as $, s as I, b as D } from "../../../chunks/form-control-B74_EHtG.js";
7
7
  import { a as S, f as b, l as L, n as C, o as y } from "../../../chunks/listbox-LsUEyGhQ.js";
8
- import { F as E, f as P } from "../../../chunks/floating-C9RLa6cZ.js";
8
+ import { F as E, f as P } from "../../../chunks/floating-DxiFx4AK.js";
9
9
  import { s as l } from "../../../chunks/index-1ZFgagWW.js";
10
10
  import "../../core/kt-icon/kt-icon.js";
11
11
  var q = Object.defineProperty, i = (c, e, o, a) => {
@@ -7,8 +7,8 @@ import '../../core/kt-button/kt-button.js';
7
7
  *
8
8
  * Wide, the sidebar sits beside the content, and its toggle narrows it to a
9
9
  * rail (`collapsed`). Narrower than `breakpoint` — measured on the shell
10
- * itself, not the viewport — the sidebar leaves the layout: the toggle opens
11
- * it as a drawer over the content, behind a backdrop, closed by Escape or a
10
+ * itself, not the viewport — the sidebar leaves the layout: the toggle moves
11
+ * to the end of the header and opens it as a drawer over the content, behind a backdrop, closed by Escape or a
12
12
  * click outside. A closed drawer is inert, so Tab never wanders into it.
13
13
  *
14
14
  * The shell fills its container's height; give the container one —
@@ -1,23 +1,23 @@
1
1
  import { css as c, nothing as m, html as s } from "lit";
2
2
  import { property as o, state as g, query as b } from "lit/decorators.js";
3
- import { K as p, d as v } from "../../../chunks/kt-element-DvWtPQ1Y.js";
4
- import { u, e as h } from "../../../chunks/events-r51msXNf.js";
3
+ import { K as h, d as u } from "../../../chunks/kt-element-DvWtPQ1Y.js";
4
+ import { u as v, e as p } from "../../../chunks/events-r51msXNf.js";
5
5
  import { s as f } from "../../../chunks/index-1ZFgagWW.js";
6
6
  import "../../core/kt-button/kt-button.js";
7
7
  var w = Object.defineProperty, a = (n, e, r, k) => {
8
- for (var i = void 0, l = n.length - 1, d; l >= 0; l--)
9
- (d = n[l]) && (i = d(e, r, i) || i);
8
+ for (var i = void 0, d = n.length - 1, l; d >= 0; d--)
9
+ (l = n[d]) && (i = l(e, r, i) || i);
10
10
  return i && w(e, r, i), i;
11
11
  };
12
- class t extends p {
12
+ class t extends h {
13
13
  constructor() {
14
- super(...arguments), this.collapsed = !1, this.sidebarOpen = !1, this.breakpoint = 900, this.noToggle = !1, this.noLandmarks = !1, this.label = "", this.narrow = !1, this.sidebarId = u("kt-app-shell-sidebar"), this.observer = null, this.onKeyDown = (e) => {
14
+ super(...arguments), this.collapsed = !1, this.sidebarOpen = !1, this.breakpoint = 900, this.noToggle = !1, this.noLandmarks = !1, this.label = "", this.narrow = !1, this.sidebarId = v("kt-app-shell-sidebar"), this.observer = null, this.onKeyDown = (e) => {
15
15
  e.key === "Escape" && this.narrow && this.sidebarOpen && (e.preventDefault(), this.closeDrawer());
16
16
  };
17
17
  }
18
18
  static {
19
19
  this.styles = [
20
- p.styles,
20
+ h.styles,
21
21
  c`
22
22
  :host {
23
23
  display: block;
@@ -60,6 +60,11 @@ class t extends p {
60
60
  gap: var(--gap-form);
61
61
  min-width: 0;
62
62
  }
63
+ /* Narrow, the toggle opens a drawer, not a rail beside it: it ends the
64
+ header, where a thumb reaches it, after the header's own content. */
65
+ :host([narrow]) .toggle {
66
+ order: 1;
67
+ }
63
68
 
64
69
  .sidebar {
65
70
  grid-area: sidebar;
@@ -134,10 +139,10 @@ class t extends p {
134
139
  }
135
140
  /** Opens or closes the sidebar, as its toggle does. */
136
141
  toggleSidebar() {
137
- this.narrow ? this.sidebarOpen = !this.sidebarOpen : this.collapsed = !this.collapsed, h(this, "kt-sidebar-toggle", { open: this.open });
142
+ this.narrow ? this.sidebarOpen = !this.sidebarOpen : this.collapsed = !this.collapsed, p(this, "kt-sidebar-toggle", { open: this.open });
138
143
  }
139
144
  closeDrawer() {
140
- !this.narrow || !this.sidebarOpen || (this.sidebarOpen = !1, h(this, "kt-sidebar-toggle", { open: !1 }));
145
+ !this.narrow || !this.sidebarOpen || (this.sidebarOpen = !1, p(this, "kt-sidebar-toggle", { open: !1 }));
141
146
  }
142
147
  willUpdate(e) {
143
148
  e.has("breakpoint") && this.measure(this.getBoundingClientRect().width);
@@ -213,7 +218,7 @@ a([
213
218
  a([
214
219
  b(".toggle")
215
220
  ], t.prototype, "toggle");
216
- v("kt-app-shell", t);
221
+ u("kt-app-shell", t);
217
222
  export {
218
223
  t as KtAppShell
219
224
  };
@@ -1 +1 @@
1
- {"version":3,"file":"kt-app-shell.js","sources":["../../../../src/components/navigation/kt-app-shell/kt-app-shell.ts"],"sourcesContent":["import { css, html, nothing, type PropertyValues, type TemplateResult } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { emit, uniqueId } from '#internal/events';\nimport { strings } from '#internal/strings';\nimport '../../core/kt-button/kt-button.js';\n\n/**\n * The frame of an application: a header along the top, a sidebar down the\n * side, and the content, which scrolls on its own.\n *\n * Wide, the sidebar sits beside the content, and its toggle narrows it to a\n * rail (`collapsed`). Narrower than `breakpoint` — measured on the shell\n * itself, not the viewport — the sidebar leaves the layout: the toggle opens\n * it as a drawer over the content, behind a backdrop, closed by Escape or a\n * click outside. A closed drawer is inert, so Tab never wanders into it.\n *\n * The shell fills its container's height; give the container one —\n * `height: 100dvh` on a page, a fixed height in a preview.\n *\n * @element kt-app-shell\n *\n * @slot header - The top bar: a wordmark, a search, an account menu.\n * @slot sidebar - Down the side: the application's navigation.\n * @slot - The content.\n *\n * @csspart header - The top bar.\n * @csspart sidebar - The `<aside>`.\n * @csspart main - The `<main>`.\n * @csspart toggle - The sidebar's toggle.\n *\n * @cssproperty --kt-app-shell-sidebar-width - The sidebar's width. 240px.\n * @cssproperty --kt-app-shell-rail-width - Its width when collapsed. 64px.\n * @cssproperty --kt-app-shell-header-height - The top bar's height. 56px.\n *\n * @fires kt-sidebar-toggle - The sidebar opened or closed — collapsed or\n * expanded when wide, the drawer when narrow. `detail: { open }`.\n *\n * @example\n * ```html\n * <kt-app-shell style=\"height: 100dvh\">\n * <a slot=\"header\" href=\"/\">Northwind</a>\n * <kt-sub-menu-navigation slot=\"sidebar\"></kt-sub-menu-navigation>\n * <h1>Overview</h1>\n * </kt-app-shell>\n * ```\n */\nexport class KtAppShell extends KtElement {\n static override styles = [\n KtElement.styles,\n css`\n :host {\n display: block;\n height: 100%;\n --kt-app-shell-sidebar-width: 240px;\n --kt-app-shell-rail-width: 64px;\n --kt-app-shell-header-height: 56px;\n }\n\n .shell {\n position: relative;\n display: grid;\n grid-template:\n 'header header' auto\n 'sidebar main' minmax(0, 1fr)\n / var(--kt-app-shell-sidebar-width) minmax(0, 1fr);\n height: 100%;\n overflow: hidden;\n color: var(--text-body);\n background: var(--surface-page);\n transition: grid-template-columns var(--duration-normal) var(--easing-standard);\n }\n :host([collapsed]:not([narrow])) .shell {\n grid-template-columns: var(--kt-app-shell-rail-width) minmax(0, 1fr);\n }\n\n .header {\n grid-area: header;\n display: flex;\n align-items: center;\n gap: var(--gap-form);\n min-height: var(--kt-app-shell-header-height);\n padding: 0 var(--padding-form);\n border-bottom: var(--border-width) solid var(--border-subtle);\n }\n .header-content {\n display: flex;\n flex: 1;\n align-items: center;\n gap: var(--gap-form);\n min-width: 0;\n }\n\n .sidebar {\n grid-area: sidebar;\n min-width: 0;\n overflow: hidden auto;\n background: var(--surface-page);\n border-right: var(--border-width) solid var(--border-subtle);\n outline: none;\n }\n\n .main {\n grid-area: main;\n min-width: 0;\n overflow: auto;\n }\n\n .backdrop {\n display: none;\n }\n\n /* === Narrow: the sidebar is a drawer over the content === */\n :host([narrow]) .shell {\n grid-template:\n 'header' auto\n 'main' minmax(0, 1fr)\n / minmax(0, 1fr);\n }\n :host([narrow]) .sidebar {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n z-index: 2;\n width: min(var(--kt-app-shell-sidebar-width), 85%);\n box-shadow: var(--shadow-popover);\n translate: -100% 0;\n visibility: hidden;\n transition:\n translate var(--duration-normal) var(--easing-standard),\n visibility 0s linear var(--duration-normal);\n }\n :host([narrow][sidebar-open]) .sidebar {\n translate: 0 0;\n visibility: visible;\n transition: translate var(--duration-normal) var(--easing-standard);\n }\n :host([narrow][sidebar-open]) .backdrop {\n position: absolute;\n inset: 0;\n z-index: 1;\n display: block;\n background: var(--color-backdrop);\n }\n `,\n ];\n\n /** Wide: the sidebar narrowed to a rail. */\n @property({ type: Boolean, reflect: true })\n collapsed = false;\n\n /** Narrow: the sidebar open as a drawer. */\n @property({ type: Boolean, reflect: true, attribute: 'sidebar-open' })\n sidebarOpen = false;\n\n /** Below this width, in pixels of the shell itself, the sidebar becomes a drawer. */\n @property({ type: Number })\n breakpoint = 900;\n\n /** Leaves the toggle out, for a header that brings its own. */\n @property({ type: Boolean, attribute: 'no-toggle' })\n noToggle = false;\n\n /**\n * Draws the sidebar and the content as plain boxes rather than an \\`<aside>\\`\n * and a \\`<main>\\` — for a shell shown inside a page that has its own, a\n * preview or a demo, where a second main landmark would be wrong.\n */\n @property({ type: Boolean, attribute: 'no-landmarks' })\n noLandmarks = false;\n\n /** Accessible name for the sidebar. Defaults to the translated \"Sidebar\". */\n @property({ type: String })\n label = '';\n\n /** Narrower than `breakpoint`: reflected as the `narrow` attribute, for styling. */\n @state() private narrow = false;\n\n @query('.sidebar') private aside!: HTMLElement;\n @query('.toggle') private toggle?: HTMLElement;\n\n private readonly sidebarId = uniqueId('kt-app-shell-sidebar');\n private observer: ResizeObserver | null = null;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('keydown', this.onKeyDown);\n if (typeof ResizeObserver === 'function') {\n this.observer = new ResizeObserver(([entry]) => {\n if (entry) this.measure(entry.contentRect.width);\n });\n this.observer.observe(this);\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this.onKeyDown);\n this.observer?.disconnect();\n this.observer = null;\n }\n\n private measure(width: number): void {\n const narrow = width > 0 && width < this.breakpoint;\n if (narrow === this.narrow) return;\n this.narrow = narrow;\n if (!narrow) this.sidebarOpen = false;\n }\n\n /** Whether the sidebar shows: expanded when wide, open when narrow. */\n private get open(): boolean {\n return this.narrow ? this.sidebarOpen : !this.collapsed;\n }\n\n /** Opens or closes the sidebar, as its toggle does. */\n toggleSidebar(): void {\n if (this.narrow) this.sidebarOpen = !this.sidebarOpen;\n else this.collapsed = !this.collapsed;\n emit(this, 'kt-sidebar-toggle', { open: this.open });\n }\n\n private closeDrawer(): void {\n if (!this.narrow || !this.sidebarOpen) return;\n this.sidebarOpen = false;\n emit(this, 'kt-sidebar-toggle', { open: false });\n }\n\n private onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape' && this.narrow && this.sidebarOpen) {\n event.preventDefault();\n this.closeDrawer();\n }\n };\n\n override willUpdate(changed: PropertyValues<this>): void {\n if (changed.has('breakpoint')) this.measure(this.getBoundingClientRect().width);\n }\n\n // `narrow` is private, so the map is read untyped.\n override updated(changed: PropertyValues): void {\n super.updated(changed);\n this.toggleAttribute('narrow', this.narrow);\n if (!changed.has('sidebarOpen') || !this.narrow) return;\n // The drawer takes the focus as it opens, and gives it back as it closes.\n if (this.sidebarOpen) this.aside.focus();\n else if (changed.get('sidebarOpen') === true) this.toggle?.focus();\n }\n\n override render(): TemplateResult {\n const label = this.label || strings().sidebar;\n return html`<div class=\"shell\">\n <div part=\"header\" class=\"header\">\n ${\n this.noToggle\n ? nothing\n : html`<kt-button\n part=\"toggle\"\n class=\"toggle\"\n variant=\"secondary-no-bg\"\n size=\"small\"\n icon=${this.narrow ? 'menu' : 'panel-left'}\n label=${label}\n aria-controls=${this.sidebarId}\n aria-expanded=${this.open ? 'true' : 'false'}\n @click=${() => this.toggleSidebar()}\n ></kt-button>`\n }\n <div class=\"header-content\"><slot name=\"header\"></slot></div>\n </div>\n ${\n this.noLandmarks\n ? html`<div\n part=\"sidebar\"\n class=\"sidebar\"\n id=${this.sidebarId}\n tabindex=\"-1\"\n ?inert=${this.narrow && !this.sidebarOpen}\n >\n <slot name=\"sidebar\"></slot>\n </div>`\n : html`<aside\n part=\"sidebar\"\n class=\"sidebar\"\n id=${this.sidebarId}\n aria-label=${label}\n tabindex=\"-1\"\n ?inert=${this.narrow && !this.sidebarOpen}\n >\n <slot name=\"sidebar\"></slot>\n </aside>`\n }\n <div class=\"backdrop\" @click=${() => this.closeDrawer()}></div>\n ${\n this.noLandmarks\n ? html`<div part=\"main\" class=\"main\"><slot></slot></div>`\n : html`<main part=\"main\" class=\"main\"><slot></slot></main>`\n }\n </div>`;\n }\n}\n\ndefineElement('kt-app-shell', KtAppShell);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-app-shell': KtAppShell;\n }\n}\n"],"names":["KtAppShell","KtElement","uniqueId","event","css","entry","width","narrow","emit","changed","label","strings","html","nothing","__decorateClass","property","state","query","defineElement"],"mappings":"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"}
1
+ {"version":3,"file":"kt-app-shell.js","sources":["../../../../src/components/navigation/kt-app-shell/kt-app-shell.ts"],"sourcesContent":["import { css, html, nothing, type PropertyValues, type TemplateResult } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { KtElement, defineElement } from '#internal/kt-element';\nimport { emit, uniqueId } from '#internal/events';\nimport { strings } from '#internal/strings';\nimport '../../core/kt-button/kt-button.js';\n\n/**\n * The frame of an application: a header along the top, a sidebar down the\n * side, and the content, which scrolls on its own.\n *\n * Wide, the sidebar sits beside the content, and its toggle narrows it to a\n * rail (`collapsed`). Narrower than `breakpoint` — measured on the shell\n * itself, not the viewport — the sidebar leaves the layout: the toggle moves\n * to the end of the header and opens it as a drawer over the content, behind a backdrop, closed by Escape or a\n * click outside. A closed drawer is inert, so Tab never wanders into it.\n *\n * The shell fills its container's height; give the container one —\n * `height: 100dvh` on a page, a fixed height in a preview.\n *\n * @element kt-app-shell\n *\n * @slot header - The top bar: a wordmark, a search, an account menu.\n * @slot sidebar - Down the side: the application's navigation.\n * @slot - The content.\n *\n * @csspart header - The top bar.\n * @csspart sidebar - The `<aside>`.\n * @csspart main - The `<main>`.\n * @csspart toggle - The sidebar's toggle.\n *\n * @cssproperty --kt-app-shell-sidebar-width - The sidebar's width. 240px.\n * @cssproperty --kt-app-shell-rail-width - Its width when collapsed. 64px.\n * @cssproperty --kt-app-shell-header-height - The top bar's height. 56px.\n *\n * @fires kt-sidebar-toggle - The sidebar opened or closed — collapsed or\n * expanded when wide, the drawer when narrow. `detail: { open }`.\n *\n * @example\n * ```html\n * <kt-app-shell style=\"height: 100dvh\">\n * <a slot=\"header\" href=\"/\">Northwind</a>\n * <kt-sub-menu-navigation slot=\"sidebar\"></kt-sub-menu-navigation>\n * <h1>Overview</h1>\n * </kt-app-shell>\n * ```\n */\nexport class KtAppShell extends KtElement {\n static override styles = [\n KtElement.styles,\n css`\n :host {\n display: block;\n height: 100%;\n --kt-app-shell-sidebar-width: 240px;\n --kt-app-shell-rail-width: 64px;\n --kt-app-shell-header-height: 56px;\n }\n\n .shell {\n position: relative;\n display: grid;\n grid-template:\n 'header header' auto\n 'sidebar main' minmax(0, 1fr)\n / var(--kt-app-shell-sidebar-width) minmax(0, 1fr);\n height: 100%;\n overflow: hidden;\n color: var(--text-body);\n background: var(--surface-page);\n transition: grid-template-columns var(--duration-normal) var(--easing-standard);\n }\n :host([collapsed]:not([narrow])) .shell {\n grid-template-columns: var(--kt-app-shell-rail-width) minmax(0, 1fr);\n }\n\n .header {\n grid-area: header;\n display: flex;\n align-items: center;\n gap: var(--gap-form);\n min-height: var(--kt-app-shell-header-height);\n padding: 0 var(--padding-form);\n border-bottom: var(--border-width) solid var(--border-subtle);\n }\n .header-content {\n display: flex;\n flex: 1;\n align-items: center;\n gap: var(--gap-form);\n min-width: 0;\n }\n /* Narrow, the toggle opens a drawer, not a rail beside it: it ends the\n header, where a thumb reaches it, after the header's own content. */\n :host([narrow]) .toggle {\n order: 1;\n }\n\n .sidebar {\n grid-area: sidebar;\n min-width: 0;\n overflow: hidden auto;\n background: var(--surface-page);\n border-right: var(--border-width) solid var(--border-subtle);\n outline: none;\n }\n\n .main {\n grid-area: main;\n min-width: 0;\n overflow: auto;\n }\n\n .backdrop {\n display: none;\n }\n\n /* === Narrow: the sidebar is a drawer over the content === */\n :host([narrow]) .shell {\n grid-template:\n 'header' auto\n 'main' minmax(0, 1fr)\n / minmax(0, 1fr);\n }\n :host([narrow]) .sidebar {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n z-index: 2;\n width: min(var(--kt-app-shell-sidebar-width), 85%);\n box-shadow: var(--shadow-popover);\n translate: -100% 0;\n visibility: hidden;\n transition:\n translate var(--duration-normal) var(--easing-standard),\n visibility 0s linear var(--duration-normal);\n }\n :host([narrow][sidebar-open]) .sidebar {\n translate: 0 0;\n visibility: visible;\n transition: translate var(--duration-normal) var(--easing-standard);\n }\n :host([narrow][sidebar-open]) .backdrop {\n position: absolute;\n inset: 0;\n z-index: 1;\n display: block;\n background: var(--color-backdrop);\n }\n `,\n ];\n\n /** Wide: the sidebar narrowed to a rail. */\n @property({ type: Boolean, reflect: true })\n collapsed = false;\n\n /** Narrow: the sidebar open as a drawer. */\n @property({ type: Boolean, reflect: true, attribute: 'sidebar-open' })\n sidebarOpen = false;\n\n /** Below this width, in pixels of the shell itself, the sidebar becomes a drawer. */\n @property({ type: Number })\n breakpoint = 900;\n\n /** Leaves the toggle out, for a header that brings its own. */\n @property({ type: Boolean, attribute: 'no-toggle' })\n noToggle = false;\n\n /**\n * Draws the sidebar and the content as plain boxes rather than an \\`<aside>\\`\n * and a \\`<main>\\` — for a shell shown inside a page that has its own, a\n * preview or a demo, where a second main landmark would be wrong.\n */\n @property({ type: Boolean, attribute: 'no-landmarks' })\n noLandmarks = false;\n\n /** Accessible name for the sidebar. Defaults to the translated \"Sidebar\". */\n @property({ type: String })\n label = '';\n\n /** Narrower than `breakpoint`: reflected as the `narrow` attribute, for styling. */\n @state() private narrow = false;\n\n @query('.sidebar') private aside!: HTMLElement;\n @query('.toggle') private toggle?: HTMLElement;\n\n private readonly sidebarId = uniqueId('kt-app-shell-sidebar');\n private observer: ResizeObserver | null = null;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('keydown', this.onKeyDown);\n if (typeof ResizeObserver === 'function') {\n this.observer = new ResizeObserver(([entry]) => {\n if (entry) this.measure(entry.contentRect.width);\n });\n this.observer.observe(this);\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this.onKeyDown);\n this.observer?.disconnect();\n this.observer = null;\n }\n\n private measure(width: number): void {\n const narrow = width > 0 && width < this.breakpoint;\n if (narrow === this.narrow) return;\n this.narrow = narrow;\n if (!narrow) this.sidebarOpen = false;\n }\n\n /** Whether the sidebar shows: expanded when wide, open when narrow. */\n private get open(): boolean {\n return this.narrow ? this.sidebarOpen : !this.collapsed;\n }\n\n /** Opens or closes the sidebar, as its toggle does. */\n toggleSidebar(): void {\n if (this.narrow) this.sidebarOpen = !this.sidebarOpen;\n else this.collapsed = !this.collapsed;\n emit(this, 'kt-sidebar-toggle', { open: this.open });\n }\n\n private closeDrawer(): void {\n if (!this.narrow || !this.sidebarOpen) return;\n this.sidebarOpen = false;\n emit(this, 'kt-sidebar-toggle', { open: false });\n }\n\n private onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape' && this.narrow && this.sidebarOpen) {\n event.preventDefault();\n this.closeDrawer();\n }\n };\n\n override willUpdate(changed: PropertyValues<this>): void {\n if (changed.has('breakpoint')) this.measure(this.getBoundingClientRect().width);\n }\n\n // `narrow` is private, so the map is read untyped.\n override updated(changed: PropertyValues): void {\n super.updated(changed);\n this.toggleAttribute('narrow', this.narrow);\n if (!changed.has('sidebarOpen') || !this.narrow) return;\n // The drawer takes the focus as it opens, and gives it back as it closes.\n if (this.sidebarOpen) this.aside.focus();\n else if (changed.get('sidebarOpen') === true) this.toggle?.focus();\n }\n\n override render(): TemplateResult {\n const label = this.label || strings().sidebar;\n return html`<div class=\"shell\">\n <div part=\"header\" class=\"header\">\n ${\n this.noToggle\n ? nothing\n : html`<kt-button\n part=\"toggle\"\n class=\"toggle\"\n variant=\"secondary-no-bg\"\n size=\"small\"\n icon=${this.narrow ? 'menu' : 'panel-left'}\n label=${label}\n aria-controls=${this.sidebarId}\n aria-expanded=${this.open ? 'true' : 'false'}\n @click=${() => this.toggleSidebar()}\n ></kt-button>`\n }\n <div class=\"header-content\"><slot name=\"header\"></slot></div>\n </div>\n ${\n this.noLandmarks\n ? html`<div\n part=\"sidebar\"\n class=\"sidebar\"\n id=${this.sidebarId}\n tabindex=\"-1\"\n ?inert=${this.narrow && !this.sidebarOpen}\n >\n <slot name=\"sidebar\"></slot>\n </div>`\n : html`<aside\n part=\"sidebar\"\n class=\"sidebar\"\n id=${this.sidebarId}\n aria-label=${label}\n tabindex=\"-1\"\n ?inert=${this.narrow && !this.sidebarOpen}\n >\n <slot name=\"sidebar\"></slot>\n </aside>`\n }\n <div class=\"backdrop\" @click=${() => this.closeDrawer()}></div>\n ${\n this.noLandmarks\n ? html`<div part=\"main\" class=\"main\"><slot></slot></div>`\n : html`<main part=\"main\" class=\"main\"><slot></slot></main>`\n }\n </div>`;\n }\n}\n\ndefineElement('kt-app-shell', KtAppShell);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'kt-app-shell': KtAppShell;\n }\n}\n"],"names":["KtAppShell","KtElement","uniqueId","event","css","entry","width","narrow","emit","changed","label","strings","html","nothing","__decorateClass","property","state","query","defineElement"],"mappings":";;;;;;;;;;;AA+CO,MAAMA,UAAmBC,EAAU;AAAA,EAAnC,cAAA;AAAA,UAAA,GAAA,SAAA,GA4GL,KAAA,YAAY,IAIZ,KAAA,cAAc,IAId,KAAA,aAAa,KAIb,KAAA,WAAW,IAQX,KAAA,cAAc,IAId,KAAA,QAAQ,IAGC,KAAQ,SAAS,IAK1B,KAAiB,YAAYC,EAAS,sBAAsB,GAC5D,KAAQ,WAAkC,MA6C1C,KAAQ,YAAY,CAACC,MAA+B;AAClD,MAAIA,EAAM,QAAQ,YAAY,KAAK,UAAU,KAAK,gBAChDA,EAAM,eAAA,GACN,KAAK,YAAA;AAAA,IAET;AAAA,EAAA;AAAA,EA9LA,OAAA;AAAA,SAAgB,SAAS;AAAA,MACvBF,EAAU;AAAA,MACVG;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;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,IAAA;AAAA,EAqGF;AAAA,EAuCS,oBAA0B;AACjC,UAAM,kBAAA,GACN,KAAK,iBAAiB,WAAW,KAAK,SAAS,GAC3C,OAAO,kBAAmB,eAC5B,KAAK,WAAW,IAAI,eAAe,CAAC,CAACC,CAAK,MAAM;AAC9C,MAAIA,KAAO,KAAK,QAAQA,EAAM,YAAY,KAAK;AAAA,IACjD,CAAC,GACD,KAAK,SAAS,QAAQ,IAAI;AAAA,EAE9B;AAAA,EAES,uBAA6B;AACpC,UAAM,qBAAA,GACN,KAAK,oBAAoB,WAAW,KAAK,SAAS,GAClD,KAAK,UAAU,WAAA,GACf,KAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,QAAQC,GAAqB;AACnC,UAAMC,IAASD,IAAQ,KAAKA,IAAQ,KAAK;AACzC,IAAIC,MAAW,KAAK,WACpB,KAAK,SAASA,GACTA,MAAQ,KAAK,cAAc;AAAA,EAClC;AAAA;AAAA,EAGA,IAAY,OAAgB;AAC1B,WAAO,KAAK,SAAS,KAAK,cAAc,CAAC,KAAK;AAAA,EAChD;AAAA;AAAA,EAGA,gBAAsB;AACpB,IAAI,KAAK,SAAQ,KAAK,cAAc,CAAC,KAAK,cACrC,KAAK,YAAY,CAAC,KAAK,WAC5BC,EAAK,MAAM,qBAAqB,EAAE,MAAM,KAAK,MAAM;AAAA,EACrD;AAAA,EAEQ,cAAoB;AAC1B,IAAI,CAAC,KAAK,UAAU,CAAC,KAAK,gBAC1B,KAAK,cAAc,IACnBA,EAAK,MAAM,qBAAqB,EAAE,MAAM,IAAO;AAAA,EACjD;AAAA,EASS,WAAWC,GAAqC;AACvD,IAAIA,EAAQ,IAAI,YAAY,UAAQ,QAAQ,KAAK,sBAAA,EAAwB,KAAK;AAAA,EAChF;AAAA;AAAA,EAGS,QAAQA,GAA+B;AAG9C,IAFA,MAAM,QAAQA,CAAO,GACrB,KAAK,gBAAgB,UAAU,KAAK,MAAM,GACtC,GAACA,EAAQ,IAAI,aAAa,KAAK,CAAC,KAAK,YAErC,KAAK,cAAa,KAAK,MAAM,MAAA,IACxBA,EAAQ,IAAI,aAAa,MAAM,MAAM,KAAK,QAAQ,MAAA;AAAA,EAC7D;AAAA,EAES,SAAyB;AAChC,UAAMC,IAAQ,KAAK,SAASC,EAAA,EAAU;AACtC,WAAOC;AAAA;AAAA,UAGD,KAAK,WACDC,IACAD;AAAA;AAAA;AAAA;AAAA;AAAA,uBAKS,KAAK,SAAS,SAAS,YAAY;AAAA,wBAClCF,CAAK;AAAA,gCACG,KAAK,SAAS;AAAA,gCACd,KAAK,OAAO,SAAS,OAAO;AAAA,yBACnC,MAAM,KAAK,cAAA,CAAe;AAAA,4BAE3C;AAAA;AAAA;AAAA,QAIA,KAAK,cACDE;AAAA;AAAA;AAAA,mBAGO,KAAK,SAAS;AAAA;AAAA,uBAEV,KAAK,UAAU,CAAC,KAAK,WAAW;AAAA;AAAA;AAAA,sBAI3CA;AAAA;AAAA;AAAA,mBAGO,KAAK,SAAS;AAAA,2BACNF,CAAK;AAAA;AAAA,uBAET,KAAK,UAAU,CAAC,KAAK,WAAW;AAAA;AAAA;AAAA,qBAIjD;AAAA,qCAC+B,MAAM,KAAK,aAAa;AAAA,QAErD,KAAK,cACDE,uDACAA,sDACN;AAAA;AAAA,EAEJ;AACF;AAtJEE,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GA3G/Bf,EA4GX,WAAA,WAAA;AAIAc,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM,WAAW,gBAAgB;AAAA,GA/G1Df,EAgHX,WAAA,aAAA;AAIAc,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAnHff,EAoHX,WAAA,YAAA;AAIAc,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,WAAW,aAAa;AAAA,GAvHxCf,EAwHX,WAAA,UAAA;AAQAc,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,WAAW,gBAAgB;AAAA,GA/H3Cf,EAgIX,WAAA,aAAA;AAIAc,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAnIff,EAoIX,WAAA,OAAA;AAGiBc,EAAA;AAAA,EAAhBE,EAAA;AAAM,GAvIIhB,EAuIM,WAAA,QAAA;AAEUc,EAAA;AAAA,EAA1BG,EAAM,UAAU;AAAA,GAzINjB,EAyIgB,WAAA,OAAA;AACDc,EAAA;AAAA,EAAzBG,EAAM,SAAS;AAAA,GA1ILjB,EA0Ie,WAAA,QAAA;AA0H5BkB,EAAc,gBAAgBlB,CAAU;"}
@@ -118,6 +118,14 @@ class t extends d {
118
118
  }
119
119
 
120
120
  @media (max-width: 899px) {
121
+ /* The navigation leaves the bar: the brand takes what is left, the
122
+ actions and the menu end it — not the actions in a middle column
123
+ that no longer has anything to centre. */
124
+ .bar,
125
+ :host([nav-align='start']) .bar {
126
+ grid-template-columns: minmax(0, 1fr) auto auto;
127
+ }
128
+
121
129
  .menu-button {
122
130
  display: inline-flex;
123
131
  }