@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,548 @@
1
+ /* ============================================
2
+ Composer — canonical chat composer
3
+ Visual + behavior matches preview/composer.html
4
+ Pairs with components/composer/index.jsx.
5
+ References --md-sys-* / --xm-* tokens only.
6
+
7
+ Two BEM blocks live here:
8
+ .composer — the input card (toolbar, field, send/stop)
9
+ .att — attachment system (chips, cards, tray, bundle)
10
+ kept as a separate block because the artifact
11
+ chip in <Bubble> reuses .att-card without the
12
+ composer chrome.
13
+ ============================================ */
14
+
15
+ /* Outer wrap — stacks the composer card and the transparent
16
+ `.composer-shell__bottom` hint strip beneath it. */
17
+ .composer-shell {
18
+ display: flex;
19
+ flex-direction: column;
20
+ background: var(--md-sys-color-surface);
21
+ }
22
+
23
+ .composer {
24
+ background: var(--md-sys-color-surface-container-high);
25
+ border: 1px solid var(--md-sys-color-outline);
26
+ border-radius: var(--md-sys-shape-corner-extra-large);
27
+ padding: var(--s-5);
28
+ display: flex;
29
+ flex-direction: column;
30
+ gap: var(--s-3);
31
+ min-height: 88px;
32
+ transition:
33
+ border-color var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard),
34
+ box-shadow var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard);
35
+ box-shadow: var(--md-sys-elevation-level0);
36
+ cursor: text;
37
+ }
38
+ .composer button,
39
+ .composer xm-button,
40
+ .composer a {
41
+ cursor: pointer;
42
+ }
43
+ .composer button[disabled],
44
+ .composer xm-button[disabled] {
45
+ cursor: not-allowed;
46
+ }
47
+ .composer:hover {
48
+ border-color: var(--md-sys-color-outline);
49
+ }
50
+ .composer:focus-within {
51
+ border-color: var(--md-sys-color-outline);
52
+ box-shadow: var(--xm-state-focus-ring), var(--md-sys-elevation-level0);
53
+ }
54
+ .composer--dragging {
55
+ border-color: var(--md-sys-color-primary);
56
+ box-shadow:
57
+ 0 0 0 3px color-mix(in oklab, var(--md-sys-color-primary) 22%, transparent),
58
+ var(--md-sys-elevation-level0);
59
+ }
60
+
61
+ .composer__field {
62
+ border: 0;
63
+ background: transparent;
64
+ color: var(--md-sys-color-on-surface);
65
+ font:
66
+ var(--md-sys-typescale-body-large-weight)
67
+ var(--md-sys-typescale-body-large-size) /
68
+ var(--md-sys-typescale-body-large-line-height)
69
+ var(--md-sys-typescale-body-large-font);
70
+ padding: var(--s-0-5) var(--s-0-5) 0;
71
+ min-height: 22px;
72
+ max-height: 240px;
73
+ outline: none;
74
+ resize: none;
75
+ width: 100%;
76
+ overflow-y: auto;
77
+ }
78
+ .composer__field::placeholder { color: var(--xm-color-on-surface-soft); }
79
+
80
+ .composer__toolbar { display: flex; align-items: center; justify-content: space-between; gap: var(--s-1-5); }
81
+ .composer__toolbar-left,
82
+ .composer__toolbar-right { display: flex; align-items: center; gap: var(--s-1-5); }
83
+
84
+ /* Inner shape used by the Stop xm-button — a 9px filled square that
85
+ reads as the universal "stop" affordance inside the button chip. */
86
+ .composer__stop-icon { display: inline-block; width: 9px; height: 9px; background: currentColor; border-radius: 1px; }
87
+
88
+ .composer__hint {
89
+ font: 500 10px/1 var(--xm-typescale-mono-font);
90
+ color: var(--md-sys-color-on-surface);
91
+ text-transform: uppercase;
92
+ letter-spacing: 0.06em;
93
+ display: inline-flex;
94
+ align-items: center;
95
+ gap: var(--s-1-5);
96
+ }
97
+ .composer__hint kbd {
98
+ display: inline-block;
99
+ padding: 1px var(--s-1);
100
+ font: 600 9px/1 var(--xm-typescale-mono-font);
101
+ color: var(--md-sys-color-on-surface);
102
+ background: var(--md-sys-color-surface-container);
103
+ border: 1px solid var(--md-sys-color-outline);
104
+ border-bottom-width: 2px;
105
+ border-radius: 4px;
106
+ margin: 0 1px;
107
+ }
108
+
109
+ /* Transparent strip that hosts the keyboard-shortcut hint below the
110
+ composer card. Sits inside the chat shell's `.chat-shell__composer`, but is
111
+ rendered by <Composer> so standalone previews get it too. */
112
+ .composer-shell__bottom {
113
+ background: transparent;
114
+ display: flex;
115
+ justify-content: center;
116
+ padding: var(--s-2) var(--s-1) 0;
117
+ }
118
+
119
+ .composer__counter {
120
+ font: 500 11px/1 var(--xm-typescale-mono-font);
121
+ color: var(--xm-color-on-surface-soft);
122
+ font-feature-settings: "tnum";
123
+ }
124
+ .composer__counter--warn { color: var(--md-sys-color-on-surface); }
125
+ .composer__counter--over { color: var(--md-sys-color-on-surface); font-weight: 700; }
126
+
127
+ /* Thinking pill */
128
+ .composer__thinking {
129
+ display: flex;
130
+ align-items: center;
131
+ gap: var(--s-3);
132
+ padding: var(--s-2-5) var(--s-3-5);
133
+ border-radius: 10px;
134
+ background: color-mix(in oklab, var(--md-sys-color-primary-container) 70%, var(--md-sys-color-surface-container-low) 30%);
135
+ color: var(--md-sys-color-on-primary-container);
136
+ font: 500 13px/1 var(--md-sys-typescale-body-large-font);
137
+ }
138
+ .composer__thinking-dots { display: inline-flex; gap: var(--s-1); flex-shrink: 0; }
139
+ .composer__thinking-dot {
140
+ width: 6px; height: 6px;
141
+ border-radius: 50%;
142
+ background: color-mix(in oklab, var(--md-sys-color-primary) 65%, var(--md-sys-color-surface-container-low) 35%);
143
+ animation: thinkingPulse 1.2s ease-in-out infinite;
144
+ }
145
+ .composer__thinking-dot:nth-child(2) { animation-delay: 0.18s; }
146
+ .composer__thinking-dot:nth-child(3) { animation-delay: 0.36s; }
147
+ @keyframes thinkingPulse {
148
+ 0%, 80%, 100% { opacity: 0.35; transform: scale(0.85); }
149
+ 40% { opacity: 1; transform: scale(1.1); }
150
+ }
151
+
152
+ /* ============================================
153
+ Attachments — block: .att
154
+ ============================================ */
155
+ .att {
156
+ display: flex;
157
+ flex-direction: column;
158
+ gap: var(--s-2);
159
+ padding: 0 var(--s-0-5) var(--s-0-5);
160
+ }
161
+
162
+ .att__header {
163
+ display: flex;
164
+ align-items: center;
165
+ justify-content: space-between;
166
+ gap: var(--s-3);
167
+ font: 500 11px/1 var(--xm-typescale-mono-font);
168
+ color: var(--xm-color-on-surface-soft);
169
+ text-transform: uppercase;
170
+ letter-spacing: 0.06em;
171
+ padding: 0 var(--s-0-5);
172
+ }
173
+ .att__header-left { display: inline-flex; align-items: center; gap: var(--s-2); font-feature-settings: "tnum"; }
174
+ .att__pip {
175
+ display: inline-flex; align-items: center; justify-content: center;
176
+ height: 18px; min-width: 18px; padding: 0 5px;
177
+ border-radius: 999px;
178
+ background: var(--md-sys-color-outline);
179
+ color: var(--md-sys-color-on-surface);
180
+ font: 600 10px/1 var(--xm-typescale-mono-font);
181
+ letter-spacing: 0.04em;
182
+ }
183
+ .att__header-right { display: inline-flex; align-items: center; gap: var(--s-3); }
184
+
185
+ .att__link {
186
+ background: none; border: 0; padding: 0;
187
+ font: 500 11px/1 var(--xm-typescale-mono-font);
188
+ color: var(--xm-color-on-surface-soft);
189
+ text-transform: uppercase;
190
+ letter-spacing: 0.06em;
191
+ cursor: pointer;
192
+ }
193
+ .att__link:hover { color: var(--md-sys-color-on-surface); }
194
+
195
+ /* Card grid */
196
+ .att__grid {
197
+ display: flex;
198
+ flex-direction: row;
199
+ gap: var(--s-2-5);
200
+ overflow-x: auto;
201
+ overflow-y: hidden;
202
+ padding: var(--s-0-5) var(--s-0-5) var(--s-2);
203
+ scrollbar-width: thin;
204
+ scroll-snap-type: x proximity;
205
+ }
206
+
207
+ .att-card {
208
+ position: relative;
209
+ flex-shrink: 0;
210
+ width: 150px;
211
+ height: 150px;
212
+ border: 1px solid var(--md-sys-color-outline-variant);
213
+ background: var(--md-sys-color-inverse-surface);
214
+ border-radius: 10px;
215
+ overflow: hidden;
216
+ display: flex;
217
+ flex-direction: column;
218
+ transition:
219
+ border-color var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard),
220
+ box-shadow var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard);
221
+ scroll-snap-align: start;
222
+ }
223
+ .att-card:hover { border-color: var(--md-sys-color-outline); }
224
+
225
+ .att-card--media .att-card__media {
226
+ position: absolute; inset: 0;
227
+ background-size: cover;
228
+ background-position: top center;
229
+ background-color: var(--md-sys-color-surface-container-high);
230
+ }
231
+ .att-card--media .att-card__ext {
232
+ position: absolute;
233
+ left: var(--s-2); bottom: var(--s-2);
234
+ padding: 3px 7px;
235
+ border-radius: 4px;
236
+ background: var(--xm-photo-overlay);
237
+ color: var(--xm-photo-overlay-ink);
238
+ font: 600 10px/1 var(--xm-typescale-mono-font);
239
+ letter-spacing: 0.08em;
240
+ text-transform: uppercase;
241
+ backdrop-filter: blur(4px);
242
+ }
243
+ .att-card--media .att-card__meta {
244
+ position: absolute;
245
+ right: var(--s-2); bottom: var(--s-2);
246
+ padding: 3px 7px;
247
+ border-radius: 4px;
248
+ background: var(--xm-photo-overlay);
249
+ color: var(--xm-photo-overlay-ink);
250
+ font: 500 10px/1 var(--xm-typescale-mono-font);
251
+ letter-spacing: 0.04em;
252
+ backdrop-filter: blur(4px);
253
+ font-feature-settings: "tnum";
254
+ }
255
+
256
+ .att-card--text {
257
+ background: var(--md-sys-color-surface-container-high);
258
+ padding: var(--s-3-5) var(--s-3) var(--s-3);
259
+ justify-content: flex-start;
260
+ }
261
+ .att-card--text .att-card__name {
262
+ font: 500 13px/1.3 var(--md-sys-typescale-body-large-font);
263
+ color: var(--md-sys-color-inverse-on-surface);
264
+ word-break: break-word;
265
+ display: -webkit-box;
266
+ -webkit-line-clamp: 3;
267
+ -webkit-box-orient: vertical;
268
+ overflow: hidden;
269
+ margin-right: var(--s-5-5);
270
+ }
271
+ .att-card--text .att-card__sub {
272
+ margin-top: var(--s-2);
273
+ display: flex;
274
+ flex-direction: column;
275
+ gap: var(--s-1-5);
276
+ font: 400 11px/1.2 var(--xm-typescale-mono-font);
277
+ color: var(--xm-color-inverse-on-surface-muted);
278
+ font-feature-settings: "tnum";
279
+ }
280
+ .att-card--text .att-card__sub-primary { color: var(--md-sys-color-inverse-on-surface); font-weight: 500; }
281
+ .att-card--text .att-card__sub-secondary { color: var(--xm-color-inverse-on-surface-muted); font-size: 10.5px; }
282
+ .att-card--text .att-card__ext {
283
+ position: absolute;
284
+ left: var(--s-2-5); bottom: var(--s-2-5);
285
+ padding: 3px 7px;
286
+ border-radius: 4px;
287
+ background: color-mix(in oklab, var(--md-sys-color-inverse-on-surface) 8%, transparent);
288
+ color: var(--md-sys-color-inverse-on-surface);
289
+ font: 600 10px/1 var(--xm-typescale-mono-font);
290
+ letter-spacing: 0.08em;
291
+ text-transform: uppercase;
292
+ }
293
+
294
+ /* ----- Row variant (used in bubbles to reference an artifact) -----
295
+ Lives inside a bot bubble that rides `surface`, so this variant
296
+ uses the on-surface family (POLICIES rule 7a) — not the inverse-on-
297
+ surface ink that .att-card--text uses inside the composer (which
298
+ sits on inverse-surface). The primitives flip in light theme via
299
+ _primitives.css, so a single rule covers both modes. */
300
+ .att-card--text-row {
301
+ width: 100%;
302
+ height: auto;
303
+ margin-top: var(--s-2-5);
304
+ flex-direction: row;
305
+ align-items: center;
306
+ gap: var(--s-3);
307
+ padding: var(--s-2-5) var(--s-3);
308
+ background: var(--md-sys-color-surface-container-low);
309
+ border: 1px solid var(--md-sys-color-outline);
310
+ color: var(--md-sys-color-on-surface);
311
+ /* Reset native <button> chrome — the chip is rendered as a button
312
+ so it can be activated by keyboard, but it must not paint a UA
313
+ focus ring that fights the design system. */
314
+ appearance: none;
315
+ font: inherit;
316
+ text-align: left;
317
+ cursor: pointer;
318
+ outline: none;
319
+ transition:
320
+ background var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard),
321
+ border-color var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard);
322
+ }
323
+ .att-card--text-row:hover {
324
+ background: var(--md-sys-color-surface-container);
325
+ border-color: var(--xm-color-on-surface-soft);
326
+ }
327
+ .att-card--text-row:focus-visible {
328
+ border-color: var(--xm-color-on-surface-soft);
329
+ box-shadow: var(--xm-state-focus-ring);
330
+ }
331
+ .att-card--text-row .att-card__name {
332
+ margin: 0;
333
+ -webkit-line-clamp: 1;
334
+ white-space: nowrap;
335
+ overflow: hidden;
336
+ text-overflow: ellipsis;
337
+ color: var(--md-sys-color-on-surface);
338
+ }
339
+ /* Folded-corner document tile — a tilted card with a clipped
340
+ top-right corner so the chip's leading slot reads as a doc icon
341
+ rather than a generic square. Uses tokens only; the corner is
342
+ carved with clip-path on the tile and a tiny pseudo-element fold.
343
+ The translucent on-surface wash auto-flips per theme: lighter than
344
+ the chip surface in dark, darker than it in light. */
345
+ .att-card--text-row .att-card__icon {
346
+ position: relative;
347
+ width: 40px; height: 44px;
348
+ flex-shrink: 0;
349
+ display: inline-flex; align-items: center; justify-content: center;
350
+ background: color-mix(in oklab, var(--md-sys-color-on-surface) 18%, transparent);
351
+ border: 1px solid color-mix(in oklab, var(--md-sys-color-on-surface) 26%, transparent);
352
+ border-radius: 4px;
353
+ color: var(--md-sys-color-on-surface);
354
+ transform: rotate(-4deg);
355
+ box-shadow: var(--md-sys-elevation-level0);
356
+ --fold: 10px;
357
+ clip-path: polygon(
358
+ 0 0,
359
+ calc(100% - var(--fold)) 0,
360
+ 100% var(--fold),
361
+ 100% 100%,
362
+ 0 100%
363
+ );
364
+ }
365
+ .att-card--text-row .att-card__icon::after {
366
+ content: "";
367
+ position: absolute;
368
+ top: 0; right: 0;
369
+ width: var(--fold);
370
+ height: var(--fold);
371
+ background: color-mix(in oklab, var(--md-sys-color-on-surface) 32%, transparent);
372
+ clip-path: polygon(0 0, 100% 100%, 0 100%);
373
+ }
374
+ .att-card--text-row .att-card__icon svg {
375
+ position: relative;
376
+ z-index: 1;
377
+ }
378
+ .att-card--text-row .att-card__body {
379
+ flex: 1;
380
+ min-width: 0;
381
+ display: flex;
382
+ flex-direction: column;
383
+ gap: var(--s-0-5);
384
+ }
385
+ .att-card--text-row .att-card__sub {
386
+ margin-top: 0;
387
+ flex-direction: row;
388
+ gap: var(--s-1-5);
389
+ align-items: center;
390
+ flex-wrap: nowrap;
391
+ white-space: nowrap;
392
+ color: var(--xm-color-on-surface-soft);
393
+ }
394
+ .att-card--text-row .att-card__sub .ds-sep { opacity: 0.5; }
395
+ .att-card--text-row .att-card__action {
396
+ flex-shrink: 0;
397
+ display: inline-flex;
398
+ align-items: center;
399
+ gap: var(--s-2);
400
+ }
401
+ .att-card__x {
402
+ position: absolute;
403
+ top: var(--s-1-5); right: var(--s-1-5);
404
+ width: 22px; height: 22px;
405
+ border-radius: 999px;
406
+ border: none;
407
+ background: color-mix(in oklab, var(--md-sys-color-inverse-surface) 88%, transparent);
408
+ color: var(--md-sys-color-inverse-on-surface);
409
+ cursor: pointer;
410
+ display: inline-flex; align-items: center; justify-content: center;
411
+ box-shadow: 0 0 0 1px var(--md-sys-color-outline-variant);
412
+ backdrop-filter: blur(4px);
413
+ transition:
414
+ background var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard),
415
+ color var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard);
416
+ }
417
+ .att-card__x:hover { background: var(--md-sys-color-inverse-on-surface); color: var(--md-sys-color-inverse-surface); box-shadow: 0 0 0 1px var(--md-sys-color-inverse-on-surface); }
418
+
419
+ /* Bundle chip + tray */
420
+ .att__bundle {
421
+ display: inline-flex;
422
+ align-items: center;
423
+ gap: var(--s-2-5);
424
+ height: 44px;
425
+ padding: 0 var(--s-3);
426
+ border: 1px solid var(--md-sys-color-outline-variant);
427
+ background: var(--md-sys-color-surface-container-high);
428
+ border-radius: 8px;
429
+ color: var(--md-sys-color-inverse-on-surface);
430
+ font: 500 12px/1 var(--md-sys-typescale-body-large-font);
431
+ cursor: pointer;
432
+ transition: border-color var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard);
433
+ align-self: flex-start;
434
+ }
435
+ .att__bundle:hover { border-color: var(--md-sys-color-outline); }
436
+ .att__bundle-stack { position: relative; width: 28px; height: 28px; flex-shrink: 0; }
437
+ .att__bundle-stack span {
438
+ position: absolute; inset: 0;
439
+ border-radius: 5px;
440
+ background: var(--md-sys-color-surface-container-high);
441
+ border: 1px solid var(--md-sys-color-outline-variant);
442
+ }
443
+ .att__bundle-stack span:nth-child(1) { transform: translate(4px, -3px) rotate(6deg); opacity: 0.5; }
444
+ .att__bundle-stack span:nth-child(2) { transform: translate(2px, -1px) rotate(3deg); opacity: 0.75; }
445
+ .att__bundle-stack span:nth-child(3) {
446
+ background: var(--md-sys-color-surface-container-high);
447
+ display: inline-flex; align-items: center; justify-content: center;
448
+ color: var(--md-sys-color-inverse-on-surface);
449
+ }
450
+ [data-theme="dark"] .att__bundle-stack span:nth-child(3) {
451
+ background: var(--md-sys-color-surface-container-low);
452
+ color: var(--md-sys-color-on-surface);
453
+ }
454
+ .att__bundle-meta { display: flex; flex-direction: column; gap: 3px; }
455
+ .att__bundle-name { font: 500 12px/1 var(--md-sys-typescale-body-large-font); color: var(--md-sys-color-inverse-on-surface); }
456
+ .att__bundle-sub { font: 400 10.5px/1 var(--xm-typescale-mono-font); color: var(--xm-color-inverse-on-surface-muted); font-feature-settings: "tnum"; }
457
+ .att__bundle-caret { color: var(--xm-color-inverse-on-surface-muted); margin-left: var(--s-1); display: inline-flex; }
458
+ .att__bundle[aria-expanded="true"] .att__bundle-caret { transform: rotate(180deg); }
459
+
460
+ .att__tray {
461
+ border: 1px solid var(--md-sys-color-outline-variant);
462
+ border-radius: 10px;
463
+ background: var(--md-sys-color-surface-container-high);
464
+ max-height: 260px;
465
+ overflow-y: auto;
466
+ scrollbar-width: thin;
467
+ animation: trayIn 180ms ease;
468
+ }
469
+ @keyframes trayIn {
470
+ from { opacity: 0; transform: translateY(-4px); }
471
+ to { opacity: 1; transform: translateY(0); }
472
+ }
473
+
474
+ .att__row {
475
+ display: grid;
476
+ grid-template-columns: 28px 1fr auto auto;
477
+ align-items: center;
478
+ gap: var(--s-2-5);
479
+ padding: var(--s-2) var(--s-2-5);
480
+ border-bottom: 1px solid var(--md-sys-color-outline-variant);
481
+ font: 500 12px/1 var(--md-sys-typescale-body-large-font);
482
+ }
483
+ .att__row:last-child { border-bottom: 0; }
484
+ .att__row:hover { background: color-mix(in oklab, var(--md-sys-color-inverse-on-surface) 4%, transparent); }
485
+ .att__row-thumb {
486
+ width: 28px; height: 28px; border-radius: 5px;
487
+ background-size: cover; background-position: center;
488
+ background-color: var(--md-sys-color-primary-container);
489
+ }
490
+ .att__row-icon {
491
+ width: 28px; height: 28px; border-radius: 5px;
492
+ display: inline-flex; align-items: center; justify-content: center;
493
+ background: var(--md-sys-color-surface-container-high);
494
+ color: var(--md-sys-color-inverse-on-surface);
495
+ }
496
+ [data-theme="dark"] .att__row-icon {
497
+ background: var(--md-sys-color-surface-container-low);
498
+ color: var(--md-sys-color-on-surface);
499
+ }
500
+ .att__row-name {
501
+ min-width: 0;
502
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
503
+ color: var(--md-sys-color-inverse-on-surface);
504
+ }
505
+ .att__row-size {
506
+ font: 400 10.5px/1 var(--xm-typescale-mono-font);
507
+ color: var(--xm-color-inverse-on-surface-muted);
508
+ font-feature-settings: "tnum";
509
+ }
510
+ .att__row-meta {
511
+ display: flex; flex-direction: column; align-items: flex-end; gap: 3px;
512
+ font-feature-settings: "tnum"; text-align: right;
513
+ }
514
+ .att__row-meta-primary { font: 400 10.5px/1 var(--xm-typescale-mono-font); color: var(--md-sys-color-inverse-on-surface); }
515
+ .att__row-meta-secondary { font: 400 10.5px/1 var(--xm-typescale-mono-font); color: var(--xm-color-inverse-on-surface-muted); }
516
+ .att__row-x {
517
+ width: 22px; height: 22px;
518
+ border-radius: 999px;
519
+ border: 1px solid var(--md-sys-color-outline-variant);
520
+ background: var(--md-sys-color-inverse-surface);
521
+ color: var(--xm-color-inverse-on-surface-muted);
522
+ cursor: pointer;
523
+ display: inline-flex; align-items: center; justify-content: center;
524
+ transition:
525
+ background var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard),
526
+ color var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard);
527
+ }
528
+ .att__row-x:hover { background: var(--md-sys-color-inverse-on-surface); color: var(--md-sys-color-inverse-surface); border-color: var(--md-sys-color-inverse-on-surface); }
529
+
530
+ /* Inline warning — neutral surface, severity carried by <WarnIcon /> + bold label */
531
+ .att__warn {
532
+ display: flex;
533
+ align-items: center;
534
+ gap: var(--s-2);
535
+ padding: var(--s-1-5) var(--s-2-5);
536
+ border-radius: 8px;
537
+ background: var(--md-sys-color-surface-container-high);
538
+ border: 1px solid var(--md-sys-color-outline-variant);
539
+ color: var(--md-sys-color-inverse-on-surface);
540
+ font: 600 11px/1.3 var(--xm-typescale-mono-font);
541
+ letter-spacing: 0.02em;
542
+ }
543
+ [data-theme="dark"] .att__warn {
544
+ background: var(--md-sys-color-surface-container-low);
545
+ border-color: var(--md-sys-color-outline);
546
+ color: var(--md-sys-color-on-surface);
547
+ }
548
+ .att__warn svg { flex-shrink: 0; }
@@ -0,0 +1,67 @@
1
+ import { LitElement } from "lit";
2
+ import type { PropertyValues, TemplateResult } from "lit";
3
+ import "../button/index.js";
4
+ export interface ComposerAttachment {
5
+ id: number;
6
+ name: string;
7
+ kind: "image" | "file";
8
+ size: number;
9
+ ext: string;
10
+ dataUrl?: string;
11
+ lines?: number;
12
+ pages?: number;
13
+ dims?: string;
14
+ }
15
+ declare class XmComposer extends LitElement {
16
+ initialValue: string;
17
+ initialFocus: boolean;
18
+ processing: boolean;
19
+ thinkingLabel: string;
20
+ maxChars: number;
21
+ counterAt: number;
22
+ placeholder: string;
23
+ showAttachments: boolean;
24
+ value: string | null;
25
+ attachments: ComposerAttachment[] | null;
26
+ private _value;
27
+ private _atts;
28
+ private _warning;
29
+ private _trayOpen;
30
+ private _dragging;
31
+ private _dragDepth;
32
+ private _warnTimer;
33
+ private _didInitialFocus;
34
+ private _lastValueProp;
35
+ private _lastAttsProp;
36
+ createRenderRoot(): HTMLElement | DocumentFragment;
37
+ connectedCallback(): void;
38
+ willUpdate(changed: PropertyValues): void;
39
+ updated(changed: PropertyValues): void;
40
+ private _flashWarning;
41
+ private _addFiles;
42
+ private _removeAtt;
43
+ private _clearAtts;
44
+ private _send;
45
+ private _cancel;
46
+ private _onInput;
47
+ private _onKeyDown;
48
+ private _onPaste;
49
+ private _onDragEnter;
50
+ private _onDragOver;
51
+ private _onDragLeave;
52
+ private _onDrop;
53
+ private _onBoxClick;
54
+ private _onPickFile;
55
+ private _onFileInput;
56
+ private _renderAttCard;
57
+ private _renderAttRow;
58
+ private _renderAttachments;
59
+ private _renderHint;
60
+ render(): TemplateResult;
61
+ }
62
+ declare global {
63
+ interface HTMLElementTagNameMap {
64
+ "xm-composer": XmComposer;
65
+ }
66
+ }
67
+ export {};