@xmesh/system-design 0.0.1

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 (175) hide show
  1. package/README.md +472 -0
  2. package/assets/brand-lockup-dark.svg +9 -0
  3. package/assets/brand-lockup-light.svg +9 -0
  4. package/assets/brand-mark.svg +9 -0
  5. package/colors_and_type.css +11 -0
  6. package/dist/lit/components/alert/index.css +201 -0
  7. package/dist/lit/components/alert/index.d.ts +25 -0
  8. package/dist/lit/components/alert/index.js +191 -0
  9. package/dist/lit/components/app-bar/index.css +80 -0
  10. package/dist/lit/components/app-bar/index.d.ts +19 -0
  11. package/dist/lit/components/app-bar/index.js +120 -0
  12. package/dist/lit/components/artifact/index.css +166 -0
  13. package/dist/lit/components/artifact/index.d.ts +37 -0
  14. package/dist/lit/components/artifact/index.js +294 -0
  15. package/dist/lit/components/autocomplete/index.css +171 -0
  16. package/dist/lit/components/autocomplete/index.d.ts +47 -0
  17. package/dist/lit/components/autocomplete/index.js +404 -0
  18. package/dist/lit/components/avatar/index.css +62 -0
  19. package/dist/lit/components/avatar/index.d.ts +19 -0
  20. package/dist/lit/components/avatar/index.js +112 -0
  21. package/dist/lit/components/avatar-group/index.css +60 -0
  22. package/dist/lit/components/avatar-group/index.d.ts +19 -0
  23. package/dist/lit/components/avatar-group/index.js +97 -0
  24. package/dist/lit/components/badge/index.css +72 -0
  25. package/dist/lit/components/badge/index.d.ts +18 -0
  26. package/dist/lit/components/badge/index.js +115 -0
  27. package/dist/lit/components/brand-mark/index.css +109 -0
  28. package/dist/lit/components/brand-mark/index.d.ts +24 -0
  29. package/dist/lit/components/brand-mark/index.js +116 -0
  30. package/dist/lit/components/breadcrumbs/index.css +91 -0
  31. package/dist/lit/components/breadcrumbs/index.d.ts +19 -0
  32. package/dist/lit/components/breadcrumbs/index.js +104 -0
  33. package/dist/lit/components/bubble/index.css +182 -0
  34. package/dist/lit/components/bubble/index.d.ts +72 -0
  35. package/dist/lit/components/bubble/index.js +617 -0
  36. package/dist/lit/components/button/index.css +342 -0
  37. package/dist/lit/components/button/index.d.ts +32 -0
  38. package/dist/lit/components/button/index.js +202 -0
  39. package/dist/lit/components/card/index.css +99 -0
  40. package/dist/lit/components/card/index.d.ts +20 -0
  41. package/dist/lit/components/card/index.js +133 -0
  42. package/dist/lit/components/chat/index.css +292 -0
  43. package/dist/lit/components/chat/index.d.ts +74 -0
  44. package/dist/lit/components/chat/index.js +589 -0
  45. package/dist/lit/components/checkbox/index.css +126 -0
  46. package/dist/lit/components/checkbox/index.d.ts +21 -0
  47. package/dist/lit/components/checkbox/index.js +138 -0
  48. package/dist/lit/components/chip/index.css +145 -0
  49. package/dist/lit/components/chip/index.d.ts +30 -0
  50. package/dist/lit/components/chip/index.js +230 -0
  51. package/dist/lit/components/chip-group/index.css +19 -0
  52. package/dist/lit/components/chip-group/index.d.ts +24 -0
  53. package/dist/lit/components/chip-group/index.js +171 -0
  54. package/dist/lit/components/code/index.css +42 -0
  55. package/dist/lit/components/code/index.d.ts +12 -0
  56. package/dist/lit/components/code/index.js +68 -0
  57. package/dist/lit/components/composer/index.css +548 -0
  58. package/dist/lit/components/composer/index.d.ts +67 -0
  59. package/dist/lit/components/composer/index.js +713 -0
  60. package/dist/lit/components/data-table/index.css +166 -0
  61. package/dist/lit/components/data-table/index.d.ts +55 -0
  62. package/dist/lit/components/data-table/index.js +390 -0
  63. package/dist/lit/components/dialog/index.css +124 -0
  64. package/dist/lit/components/dialog/index.d.ts +24 -0
  65. package/dist/lit/components/dialog/index.js +199 -0
  66. package/dist/lit/components/divider/index.css +27 -0
  67. package/dist/lit/components/divider/index.d.ts +13 -0
  68. package/dist/lit/components/divider/index.js +67 -0
  69. package/dist/lit/components/empty-state/index.css +69 -0
  70. package/dist/lit/components/empty-state/index.d.ts +21 -0
  71. package/dist/lit/components/empty-state/index.js +123 -0
  72. package/dist/lit/components/expansion-panel/index.css +120 -0
  73. package/dist/lit/components/expansion-panel/index.d.ts +22 -0
  74. package/dist/lit/components/expansion-panel/index.js +174 -0
  75. package/dist/lit/components/field/index.css +223 -0
  76. package/dist/lit/components/field/index.d.ts +106 -0
  77. package/dist/lit/components/field/index.js +388 -0
  78. package/dist/lit/components/file-input/index.css +257 -0
  79. package/dist/lit/components/file-input/index.d.ts +30 -0
  80. package/dist/lit/components/file-input/index.js +298 -0
  81. package/dist/lit/components/form/index.css +29 -0
  82. package/dist/lit/components/form/index.d.ts +38 -0
  83. package/dist/lit/components/form/index.js +192 -0
  84. package/dist/lit/components/grid/index.css +53 -0
  85. package/dist/lit/components/grid/index.d.ts +14 -0
  86. package/dist/lit/components/grid/index.js +82 -0
  87. package/dist/lit/components/kbd/index.css +35 -0
  88. package/dist/lit/components/kbd/index.d.ts +11 -0
  89. package/dist/lit/components/kbd/index.js +43 -0
  90. package/dist/lit/components/list/index.css +15 -0
  91. package/dist/lit/components/list/index.d.ts +28 -0
  92. package/dist/lit/components/list/index.js +188 -0
  93. package/dist/lit/components/list-item/index.css +119 -0
  94. package/dist/lit/components/list-item/index.d.ts +20 -0
  95. package/dist/lit/components/list-item/index.js +127 -0
  96. package/dist/lit/components/menu/index.css +94 -0
  97. package/dist/lit/components/menu/index.d.ts +47 -0
  98. package/dist/lit/components/menu/index.js +386 -0
  99. package/dist/lit/components/navigation-drawer/index.css +114 -0
  100. package/dist/lit/components/navigation-drawer/index.d.ts +29 -0
  101. package/dist/lit/components/navigation-drawer/index.js +218 -0
  102. package/dist/lit/components/overlay/index.css +171 -0
  103. package/dist/lit/components/overlay/index.d.ts +65 -0
  104. package/dist/lit/components/overlay/index.js +566 -0
  105. package/dist/lit/components/pagination/index.css +102 -0
  106. package/dist/lit/components/pagination/index.d.ts +22 -0
  107. package/dist/lit/components/pagination/index.js +184 -0
  108. package/dist/lit/components/primitives/index.css +504 -0
  109. package/dist/lit/components/primitives/index.d.ts +25 -0
  110. package/dist/lit/components/primitives/index.js +283 -0
  111. package/dist/lit/components/progress/index.css +143 -0
  112. package/dist/lit/components/progress/index.d.ts +23 -0
  113. package/dist/lit/components/progress/index.js +180 -0
  114. package/dist/lit/components/radio-group/index.css +178 -0
  115. package/dist/lit/components/radio-group/index.d.ts +35 -0
  116. package/dist/lit/components/radio-group/index.js +292 -0
  117. package/dist/lit/components/select/index.css +151 -0
  118. package/dist/lit/components/select/index.d.ts +50 -0
  119. package/dist/lit/components/select/index.js +390 -0
  120. package/dist/lit/components/sidebar-item/index.css +133 -0
  121. package/dist/lit/components/sidebar-item/index.d.ts +20 -0
  122. package/dist/lit/components/sidebar-item/index.js +105 -0
  123. package/dist/lit/components/skeleton/index.css +81 -0
  124. package/dist/lit/components/skeleton/index.d.ts +19 -0
  125. package/dist/lit/components/skeleton/index.js +119 -0
  126. package/dist/lit/components/slider/index.css +171 -0
  127. package/dist/lit/components/slider/index.d.ts +36 -0
  128. package/dist/lit/components/slider/index.js +302 -0
  129. package/dist/lit/components/snackbar/index.css +279 -0
  130. package/dist/lit/components/snackbar/index.d.ts +33 -0
  131. package/dist/lit/components/snackbar/index.js +195 -0
  132. package/dist/lit/components/stack/index.css +41 -0
  133. package/dist/lit/components/stack/index.d.ts +20 -0
  134. package/dist/lit/components/stack/index.js +103 -0
  135. package/dist/lit/components/switch/index.css +126 -0
  136. package/dist/lit/components/switch/index.d.ts +17 -0
  137. package/dist/lit/components/switch/index.js +116 -0
  138. package/dist/lit/components/table/index.css +85 -0
  139. package/dist/lit/components/table/index.d.ts +25 -0
  140. package/dist/lit/components/table/index.js +139 -0
  141. package/dist/lit/components/tabs/index.css +116 -0
  142. package/dist/lit/components/tabs/index.d.ts +49 -0
  143. package/dist/lit/components/tabs/index.js +320 -0
  144. package/dist/lit/components/text-field/index.css +90 -0
  145. package/dist/lit/components/text-field/index.d.ts +17 -0
  146. package/dist/lit/components/text-field/index.js +101 -0
  147. package/dist/lit/components/textarea/index.css +55 -0
  148. package/dist/lit/components/textarea/index.d.ts +26 -0
  149. package/dist/lit/components/textarea/index.js +124 -0
  150. package/dist/lit/components/tooltip/index.css +37 -0
  151. package/dist/lit/components/tooltip/index.d.ts +31 -0
  152. package/dist/lit/components/tooltip/index.js +196 -0
  153. package/dist/lit/components/validation/index.css +386 -0
  154. package/dist/lit/components/validation/index.d.ts +45 -0
  155. package/dist/lit/components/validation/index.js +318 -0
  156. package/dist/lit/index.d.ts +50 -0
  157. package/dist/lit/index.js +59 -0
  158. package/package.json +81 -0
  159. package/styles/README.md +346 -0
  160. package/styles/_elevation.css +24 -0
  161. package/styles/_fonts.css +6 -0
  162. package/styles/_layout.css +37 -0
  163. package/styles/_primitives.css +154 -0
  164. package/styles/_scroll.css +75 -0
  165. package/styles/_semantic.css +146 -0
  166. package/styles/_space.css +61 -0
  167. package/styles/_type.css +139 -0
  168. package/styles/_xmesh-extensions.css +232 -0
  169. package/styles/index.css +44 -0
  170. package/styles/md3/_color.css +102 -0
  171. package/styles/md3/_elevation.css +26 -0
  172. package/styles/md3/_motion.css +35 -0
  173. package/styles/md3/_shape.css +22 -0
  174. package/styles/md3/_state.css +22 -0
  175. package/styles/md3/_type.css +111 -0
@@ -0,0 +1,20 @@
1
+ import { LitElement } from "lit";
2
+ import type { TemplateResult } from "lit";
3
+ type CardSize = "xs" | "sm" | "md" | "lg";
4
+ type CardElevation = 0 | 1 | 2 | 3 | 4 | 5;
5
+ declare class XmCard extends LitElement {
6
+ elevation: CardElevation;
7
+ size: CardSize;
8
+ private _mo;
9
+ render(): TemplateResult;
10
+ private _slotEmpty;
11
+ private _onSlot;
12
+ connectedCallback(): void;
13
+ disconnectedCallback(): void;
14
+ }
15
+ declare global {
16
+ interface HTMLElementTagNameMap {
17
+ "xm-card": XmCard;
18
+ }
19
+ }
20
+ export {};
@@ -0,0 +1,133 @@
1
+ /*
2
+ card/index.ts — <xm-card>, the general-purpose containment surface.
3
+
4
+ <xm-card> — a card-stack container for non-chat screens. Belongs to the
5
+ INVERSE-SURFACE family (like the drawer), the opposite of the app bar:
6
+ background var(--md-sys-color-inverse-surface), ink
7
+ var(--md-sys-color-inverse-on-surface). The card tier is theme-following
8
+ (ADR 0006): a lifted dark surface in dark theme, white in light — ink follows.
9
+
10
+ Authoring:
11
+ <xm-card elevation="2">
12
+ <span slot="header">Routing pipeline</span>
13
+ Body content goes in the default slot.
14
+ <span slot="footer">3 agents · updated 2 minutes ago</span>
15
+ <xm-button slot="action" variant="ghost" size="sm">Edit</xm-button>
16
+ <xm-button slot="action" variant="primary" size="sm">Run</xm-button>
17
+ </xm-card>
18
+
19
+ Properties:
20
+ elevation 0–5 — selects --md-sys-elevation-level* (default 2)
21
+ size "xs" | "sm" | "md" | "lg" (default "md")
22
+
23
+ Slots:
24
+ header leading region (split from body by a 1px rule)
25
+ default body content
26
+ footer trailing region (split from body by a 1px rule)
27
+ action SINGULAR trailing-action region in the footer row
28
+
29
+ Shadow DOM; Lit from lit; sibling CSS via the
30
+ built-file-relative new URL(...). BEM block `card`.
31
+ */
32
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
33
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
34
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
35
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
36
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
37
+ };
38
+ import { LitElement, html } from "lit";
39
+ import { customElement, property } from "lit/decorators.js";
40
+ // Resolve CSS relative to the *built* file:
41
+ // lit/build/components/card/index.js → ../card/index.css.
42
+ const CARD_CSS = new URL("../card/index.css", import.meta.url).href;
43
+ let XmCard = class XmCard extends LitElement {
44
+ constructor() {
45
+ super(...arguments);
46
+ this.elevation = 2;
47
+ this.size = "md";
48
+ this._mo = null;
49
+ this._onSlot = () => {
50
+ this.requestUpdate();
51
+ };
52
+ }
53
+ render() {
54
+ const elevation = [0, 1, 2, 3, 4, 5].includes(this.elevation)
55
+ ? this.elevation
56
+ : 2;
57
+ const size = ["xs", "sm", "md", "lg"].includes(this.size)
58
+ ? this.size
59
+ : "md";
60
+ const headerEmpty = this._slotEmpty("header");
61
+ const footerEmpty = this._slotEmpty("footer");
62
+ const actionEmpty = this._slotEmpty("action");
63
+ const footerHidden = footerEmpty && actionEmpty;
64
+ return html `
65
+ <link rel="stylesheet" href="${CARD_CSS}" />
66
+ <style>
67
+ :host {
68
+ display: block;
69
+ }
70
+ :host([hidden]) {
71
+ display: none;
72
+ }
73
+ </style>
74
+ <article class="card card--elevation-${elevation} card--${size}">
75
+ <div class="card__header ${headerEmpty ? "is-empty" : ""}">
76
+ <slot name="header" @slotchange=${this._onSlot}></slot>
77
+ </div>
78
+ <div class="card__body">
79
+ <slot @slotchange=${this._onSlot}></slot>
80
+ </div>
81
+ <div class="card__footer ${footerHidden ? "is-empty" : ""}">
82
+ <div class="card__footer-content ${footerEmpty ? "is-empty" : ""}">
83
+ <slot name="footer" @slotchange=${this._onSlot}></slot>
84
+ </div>
85
+ <div class="card__action ${actionEmpty ? "is-empty" : ""}">
86
+ <slot name="action" @slotchange=${this._onSlot}></slot>
87
+ </div>
88
+ </div>
89
+ </article>
90
+ `;
91
+ }
92
+ _slotEmpty(name) {
93
+ for (const node of this.childNodes) {
94
+ if (node.nodeType === Node.ELEMENT_NODE) {
95
+ const slotName = node.getAttribute("slot");
96
+ const target = name || null;
97
+ const matches = (target === null && !slotName) || slotName === target;
98
+ if (matches)
99
+ return false;
100
+ }
101
+ else if (node.nodeType === Node.TEXT_NODE && !name) {
102
+ if (node.textContent?.trim())
103
+ return false;
104
+ }
105
+ }
106
+ return true;
107
+ }
108
+ connectedCallback() {
109
+ super.connectedCallback();
110
+ if (!this._mo) {
111
+ this._mo = new MutationObserver(() => this.requestUpdate());
112
+ this._mo.observe(this, {
113
+ childList: true,
114
+ characterData: true,
115
+ subtree: true,
116
+ });
117
+ }
118
+ }
119
+ disconnectedCallback() {
120
+ super.disconnectedCallback();
121
+ this._mo?.disconnect();
122
+ this._mo = null;
123
+ }
124
+ };
125
+ __decorate([
126
+ property({ type: Number })
127
+ ], XmCard.prototype, "elevation", void 0);
128
+ __decorate([
129
+ property({ type: String })
130
+ ], XmCard.prototype, "size", void 0);
131
+ XmCard = __decorate([
132
+ customElement("xm-card")
133
+ ], XmCard);
@@ -0,0 +1,292 @@
1
+ /* ============================================================
2
+ <ChatShell /> — full-viewport interactive chat layout.
3
+
4
+ Three-region grid (sidebar | top / center) that grows a fourth
5
+ region (artifact) when the artifact viewer opens. Owns the
6
+ layout, scroll regions, and composer overlay only — every
7
+ visual element (Bubble, Composer, BrandMark, SidebarItem,
8
+ Artifact) lives in its own components/<name>/index.css.
9
+
10
+ Two BEM blocks live here:
11
+ .chat-shell — the grid + top-bar + thread + composer overlay
12
+ .chat-sidebar — the left column (conversations list, search)
13
+ promoted to its own block so descendant names
14
+ stay readable.
15
+ .chat-empty — alternate empty-state body used in place of
16
+ .chat-shell__thread + chat-shell__composer.
17
+
18
+ Pairs with components/chat/index.jsx.
19
+ ============================================================ */
20
+
21
+ /* ============================================================
22
+ Chat shell — three-region grid (sidebar | top / center).
23
+ Full-viewport: fills the window edge-to-edge.
24
+ ============================================================ */
25
+ .chat-shell {
26
+ position: relative;
27
+ display: grid;
28
+ grid-template-columns: var(--sidebar-w, 272px) 1fr;
29
+ grid-template-rows: auto 1fr;
30
+ grid-template-areas:
31
+ "sidebar top"
32
+ "sidebar center";
33
+ height: 100%;
34
+ width: 100%;
35
+ background: var(--md-sys-color-surface);
36
+ color: var(--md-sys-color-on-surface);
37
+ overflow: hidden;
38
+ transition: grid-template-columns var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-emphasized-decelerate);
39
+ }
40
+ /* Opt-in: pin the shell to the viewport. Used by full-bleed previews
41
+ (chat.html, chat-empty.html). Embedded hosts omit this and size the
42
+ shell via their own container. */
43
+ .chat-shell--full-viewport { height: 100vh; }
44
+ .chat-shell--collapsed { --sidebar-w: 56px; }
45
+
46
+ /* ---------- Lit shadow-boundary fixes ----------
47
+ In the React port these selectors had a single direct-child selector
48
+ in the parent's CSS (`.chat-shell__composer > .composer-shell`). In
49
+ the Lit port, <xm-composer> wraps .composer-shell with display:contents,
50
+ so the selector still walks the real DOM and .composer-shell is now a
51
+ *grand*child. The descendant variants below restore the intended sizing
52
+ and re-enable pointer-events on the composer (the overlay sets
53
+ pointer-events:none so it doesn't swallow clicks above the composer —
54
+ without re-enabling on .composer-shell, the textarea is unclickable).
55
+ Same shape for the artifact slot. */
56
+ .chat-shell__composer .composer-shell {
57
+ width: 100%;
58
+ max-width: 720px;
59
+ pointer-events: auto;
60
+ }
61
+ .chat-shell__artifact-slot .artifact { flex: 1; min-height: 0; }
62
+
63
+ /* When the artifact viewer is open, a third column appears on the
64
+ right and spans both rows — pushing top + center to the left.
65
+ Sidebar stays put. */
66
+ .chat-shell--has-artifact {
67
+ grid-template-columns: var(--sidebar-w, 272px) 3fr 2fr;
68
+ grid-template-areas:
69
+ "sidebar top artifact"
70
+ "sidebar center artifact";
71
+ }
72
+
73
+ .chat-shell__top { grid-area: top; }
74
+
75
+ .chat-shell__center {
76
+ grid-area: center;
77
+ position: relative;
78
+ min-height: 0;
79
+ overflow: hidden;
80
+ }
81
+
82
+ .chat-shell__artifact-slot {
83
+ grid-area: artifact;
84
+ min-height: 0;
85
+ display: flex;
86
+ }
87
+ .chat-shell__artifact-slot > .artifact { flex: 1; min-height: 0; }
88
+
89
+ /* ---------- Sidebar block ----------
90
+ Transparent — inherits the chat-shell surface. Only the
91
+ right-edge hairline marks the seam to the thread. */
92
+ .chat-sidebar {
93
+ grid-area: sidebar;
94
+ background: transparent;
95
+ border-right: 1px solid var(--md-sys-color-outline);
96
+ display: flex;
97
+ flex-direction: column;
98
+ min-height: 0;
99
+ overflow: hidden;
100
+ }
101
+
102
+ .chat-sidebar__top {
103
+ margin: var(--s-3) var(--s-3) var(--s-2);
104
+ }
105
+ /* Pin the right-slot icon to the brand-mark chip's 24px height so both
106
+ children present the same box for the button's `align-items: center`,
107
+ keeping the X chip and panel-toggle icon on a single centerline. */
108
+ .chat-sidebar__top [slot="icon-right"] {
109
+ display: inline-flex;
110
+ align-items: center;
111
+ justify-content: center;
112
+ height: 24px;
113
+ }
114
+ .chat-shell--collapsed .chat-sidebar__top {
115
+ margin: var(--s-3) auto var(--s-2);
116
+ }
117
+
118
+ /* New chat — xm-button host. Margin matches the sidebar column gutter. */
119
+ .chat-sidebar__new {
120
+ margin: var(--s-1) var(--s-3) var(--s-2);
121
+ }
122
+ .chat-shell--collapsed .chat-sidebar__new {
123
+ align-self: center;
124
+ }
125
+
126
+ /* Search */
127
+ .chat-sidebar__search { padding: 0 var(--s-3) var(--s-2); }
128
+ .chat-shell--collapsed .chat-sidebar__search--full { display: none; }
129
+ .chat-sidebar__search--icon-only {
130
+ display: none;
131
+ margin: 0 auto var(--s-2);
132
+ }
133
+ .chat-shell--collapsed .chat-sidebar__search--icon-only { display: inline-flex; }
134
+
135
+ /* Section labels + chat list */
136
+ .chat-sidebar__list {
137
+ flex: 1;
138
+ min-height: 0;
139
+ overflow-y: auto;
140
+ padding: var(--s-1) var(--s-2) var(--s-3-5);
141
+ display: flex;
142
+ flex-direction: column;
143
+ gap: var(--s-0-5);
144
+ }
145
+ .chat-shell--collapsed .chat-sidebar__list { padding: var(--s-2) 0 var(--s-3-5); align-items: center; gap: var(--s-4); }
146
+ .chat-shell--collapsed .sidebar-item--eyebrow { display: none; }
147
+
148
+ .chat-sidebar__divider {
149
+ width: 28px;
150
+ height: 1px;
151
+ background: var(--md-sys-color-outline);
152
+ margin: var(--s-2) auto;
153
+ display: none;
154
+ }
155
+ .chat-shell--collapsed .chat-sidebar__divider { display: block; }
156
+
157
+ /* ---------- Top panel ---------- */
158
+ .chat-shell__top {
159
+ display: flex;
160
+ align-items: center;
161
+ justify-content: space-between;
162
+ gap: var(--s-4);
163
+ padding: var(--s-3) var(--s-5);
164
+ min-height: 56px;
165
+ box-sizing: border-box;
166
+ background: var(--md-sys-color-surface);
167
+ z-index: 2;
168
+ }
169
+ .chat-shell__top-left { display: flex; flex-direction: column; gap: var(--s-0-5); min-width: 0; }
170
+ .chat-shell__top-title {
171
+ font: 600 14.5px/1.2 var(--md-sys-typescale-body-large-font);
172
+ color: var(--md-sys-color-on-surface);
173
+ letter-spacing: -0.005em;
174
+ white-space: nowrap;
175
+ overflow: hidden;
176
+ text-overflow: ellipsis;
177
+ }
178
+ .chat-shell__top-sub {
179
+ font: 400 11px/1 var(--xm-typescale-mono-font);
180
+ color: var(--xm-color-on-surface-soft);
181
+ font-feature-settings: "tnum";
182
+ display: inline-flex;
183
+ align-items: center;
184
+ gap: var(--s-1-5);
185
+ flex-wrap: nowrap;
186
+ white-space: nowrap;
187
+ }
188
+ .chat-shell__top-sub > span { white-space: nowrap; }
189
+ .chat-shell__top-right { display: inline-flex; align-items: center; gap: var(--s-1-5); }
190
+
191
+ /* ---------- Center panel — scrollable thread ---------- */
192
+ .chat-shell__thread {
193
+ position: absolute;
194
+ inset: 0;
195
+ overflow-y: auto;
196
+ scrollbar-gutter: stable both-edges;
197
+ padding: var(--s-6) var(--s-5) 132px; /* bottom padding clears the composer */
198
+ display: flex;
199
+ flex-direction: column;
200
+ align-items: center;
201
+ }
202
+ .chat-shell__thread-inner {
203
+ width: 100%;
204
+ max-width: 720px;
205
+ display: flex;
206
+ flex-direction: column;
207
+ /* Base gap is the tight, same-speaker rhythm; a speaker change adds
208
+ extra margin below so turns read as grouped utterances, not a flat
209
+ evenly-spaced list. */
210
+ gap: var(--s-2-5);
211
+ }
212
+
213
+ /* Bubble row alignment is page layout — the Bubble component owns
214
+ the visuals of each turn. */
215
+ .chat-shell__row { display: flex; }
216
+ .chat-shell__row--user { justify-content: flex-end; }
217
+ .chat-shell__row--bot { justify-content: flex-start; }
218
+
219
+ /* Speaker-change rhythm: when the author flips, open up the gap. */
220
+ .chat-shell__row--user + .chat-shell__row--bot,
221
+ .chat-shell__row--bot + .chat-shell__row--user {
222
+ margin-top: var(--s-3);
223
+ }
224
+
225
+ /* ---------- Empty state — centered serif greeting + composer ----------
226
+ Used by the chat-empty variant (passed in via the `empty` prop).
227
+ The shell renders a .chat-empty block in place of .chat-shell__thread +
228
+ .chat-shell__composer; the caller owns its own composer and any
229
+ suggestion chips. */
230
+ .chat-empty {
231
+ position: absolute;
232
+ inset: 0;
233
+ display: flex;
234
+ flex-direction: column;
235
+ align-items: center;
236
+ justify-content: center;
237
+ gap: var(--s-6);
238
+ padding: var(--s-6) var(--s-5) var(--s-10);
239
+ }
240
+ .chat-empty__hero {
241
+ width: 100%;
242
+ max-width: 720px;
243
+ display: flex;
244
+ flex-direction: column;
245
+ align-items: center;
246
+ gap: var(--s-1-5);
247
+ text-align: center;
248
+ }
249
+ .chat-empty__title {
250
+ font:
251
+ var(--md-sys-typescale-headline-medium-weight)
252
+ var(--md-sys-typescale-headline-medium-size) /
253
+ var(--md-sys-typescale-headline-medium-line-height)
254
+ var(--md-sys-typescale-headline-medium-font);
255
+ color: var(--md-sys-color-on-surface);
256
+ letter-spacing: -0.01em;
257
+ margin: 0;
258
+ }
259
+ .chat-empty__sub {
260
+ font:
261
+ var(--md-sys-typescale-body-large-weight)
262
+ var(--md-sys-typescale-body-large-size) /
263
+ var(--md-sys-typescale-body-large-line-height)
264
+ var(--md-sys-typescale-body-large-font);
265
+ color: var(--xm-color-on-surface-soft);
266
+ margin: 0;
267
+ }
268
+ .chat-empty__composer {
269
+ width: 100%;
270
+ max-width: 720px;
271
+ }
272
+
273
+ /* ---------- Bottom panel — composer overlay ----------
274
+ Transparent — the thread already pads its bottom by 132px so
275
+ bubbles never sit underneath the composer card. */
276
+ .chat-shell__composer {
277
+ position: absolute;
278
+ left: 0;
279
+ right: 0;
280
+ bottom: 0;
281
+ display: flex;
282
+ justify-content: center;
283
+ padding: var(--s-2) var(--s-5) 0;
284
+ pointer-events: none;
285
+ z-index: 2;
286
+ }
287
+ .chat-shell__composer > .composer-shell {
288
+ pointer-events: auto;
289
+ width: 100%;
290
+ max-width: 720px;
291
+ padding-bottom: var(--s-5);
292
+ }
@@ -0,0 +1,74 @@
1
+ import { LitElement } from "lit";
2
+ import type { PropertyValues, TemplateResult } from "lit";
3
+ import "../primitives/index.js";
4
+ import "../brand-mark/index.js";
5
+ import "../button/index.js";
6
+ import "../sidebar-item/index.js";
7
+ import "../bubble/index.js";
8
+ import "../composer/index.js";
9
+ import "../artifact/index.js";
10
+ import type { BubbleArtifact, BubbleAttachment } from "../bubble/index.js";
11
+ export interface ConversationItem {
12
+ id: string;
13
+ title: string;
14
+ active?: boolean;
15
+ }
16
+ export interface ConversationGroup {
17
+ group: string;
18
+ items: ConversationItem[];
19
+ }
20
+ export interface ThreadMessage {
21
+ from: "user" | "bot";
22
+ text?: string;
23
+ html?: string;
24
+ ts?: string;
25
+ atts?: BubbleAttachment[];
26
+ artifact?: BubbleArtifact | null;
27
+ }
28
+ declare class XmChatShell extends LitElement {
29
+ conversations: ConversationGroup[];
30
+ thread: ThreadMessage[];
31
+ processing: boolean;
32
+ thinkingLabel: string;
33
+ topTitle: string;
34
+ /** Pin the shell to the viewport (height: 100vh). Default is height: 100%
35
+ so the shell sizes to its container — embedded hosts get correct
36
+ sizing for free. Full-bleed previews opt in via the `full-viewport`
37
+ attribute. */
38
+ fullViewport: boolean;
39
+ private _collapsed;
40
+ private _activeId;
41
+ private _openArtifact;
42
+ private _hasEmpty;
43
+ private _searchValue;
44
+ private _copiedIdx;
45
+ private _copiedTimer;
46
+ private _artifactBodyNodes;
47
+ private _artifactCodeNodes;
48
+ private _emptyNodes;
49
+ createRenderRoot(): HTMLElement | DocumentFragment;
50
+ connectedCallback(): void;
51
+ willUpdate(changed: PropertyValues): void;
52
+ updated(): void;
53
+ private _toggleCollapsed;
54
+ private _selectConv;
55
+ private _onSearchInput;
56
+ private _onSearchClear;
57
+ private _onArtifactOpen;
58
+ private _onArtifactClose;
59
+ private _onComposerSend;
60
+ private _onComposerCancel;
61
+ private _onCopyMessage;
62
+ private _renderSidebar;
63
+ private _renderCollapsedList;
64
+ private _renderExpandedList;
65
+ private _renderTopBar;
66
+ private _renderBubbleRow;
67
+ render(): TemplateResult;
68
+ }
69
+ declare global {
70
+ interface HTMLElementTagNameMap {
71
+ "xm-chat-shell": XmChatShell;
72
+ }
73
+ }
74
+ export {};