@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.
- package/README.md +472 -0
- package/assets/brand-lockup-dark.svg +9 -0
- package/assets/brand-lockup-light.svg +9 -0
- package/assets/brand-mark.svg +9 -0
- package/colors_and_type.css +11 -0
- package/dist/lit/components/alert/index.css +201 -0
- package/dist/lit/components/alert/index.d.ts +25 -0
- package/dist/lit/components/alert/index.js +191 -0
- package/dist/lit/components/app-bar/index.css +80 -0
- package/dist/lit/components/app-bar/index.d.ts +19 -0
- package/dist/lit/components/app-bar/index.js +120 -0
- package/dist/lit/components/artifact/index.css +166 -0
- package/dist/lit/components/artifact/index.d.ts +37 -0
- package/dist/lit/components/artifact/index.js +294 -0
- package/dist/lit/components/autocomplete/index.css +171 -0
- package/dist/lit/components/autocomplete/index.d.ts +47 -0
- package/dist/lit/components/autocomplete/index.js +404 -0
- package/dist/lit/components/avatar/index.css +62 -0
- package/dist/lit/components/avatar/index.d.ts +19 -0
- package/dist/lit/components/avatar/index.js +112 -0
- package/dist/lit/components/avatar-group/index.css +60 -0
- package/dist/lit/components/avatar-group/index.d.ts +19 -0
- package/dist/lit/components/avatar-group/index.js +97 -0
- package/dist/lit/components/badge/index.css +72 -0
- package/dist/lit/components/badge/index.d.ts +18 -0
- package/dist/lit/components/badge/index.js +115 -0
- package/dist/lit/components/brand-mark/index.css +109 -0
- package/dist/lit/components/brand-mark/index.d.ts +24 -0
- package/dist/lit/components/brand-mark/index.js +116 -0
- package/dist/lit/components/breadcrumbs/index.css +91 -0
- package/dist/lit/components/breadcrumbs/index.d.ts +19 -0
- package/dist/lit/components/breadcrumbs/index.js +104 -0
- package/dist/lit/components/bubble/index.css +182 -0
- package/dist/lit/components/bubble/index.d.ts +72 -0
- package/dist/lit/components/bubble/index.js +617 -0
- package/dist/lit/components/button/index.css +342 -0
- package/dist/lit/components/button/index.d.ts +32 -0
- package/dist/lit/components/button/index.js +202 -0
- package/dist/lit/components/card/index.css +99 -0
- package/dist/lit/components/card/index.d.ts +20 -0
- package/dist/lit/components/card/index.js +133 -0
- package/dist/lit/components/chat/index.css +292 -0
- package/dist/lit/components/chat/index.d.ts +74 -0
- package/dist/lit/components/chat/index.js +589 -0
- package/dist/lit/components/checkbox/index.css +126 -0
- package/dist/lit/components/checkbox/index.d.ts +21 -0
- package/dist/lit/components/checkbox/index.js +138 -0
- package/dist/lit/components/chip/index.css +145 -0
- package/dist/lit/components/chip/index.d.ts +30 -0
- package/dist/lit/components/chip/index.js +230 -0
- package/dist/lit/components/chip-group/index.css +19 -0
- package/dist/lit/components/chip-group/index.d.ts +24 -0
- package/dist/lit/components/chip-group/index.js +171 -0
- package/dist/lit/components/code/index.css +42 -0
- package/dist/lit/components/code/index.d.ts +12 -0
- package/dist/lit/components/code/index.js +68 -0
- package/dist/lit/components/composer/index.css +548 -0
- package/dist/lit/components/composer/index.d.ts +67 -0
- package/dist/lit/components/composer/index.js +713 -0
- package/dist/lit/components/data-table/index.css +166 -0
- package/dist/lit/components/data-table/index.d.ts +55 -0
- package/dist/lit/components/data-table/index.js +390 -0
- package/dist/lit/components/dialog/index.css +124 -0
- package/dist/lit/components/dialog/index.d.ts +24 -0
- package/dist/lit/components/dialog/index.js +199 -0
- package/dist/lit/components/divider/index.css +27 -0
- package/dist/lit/components/divider/index.d.ts +13 -0
- package/dist/lit/components/divider/index.js +67 -0
- package/dist/lit/components/empty-state/index.css +69 -0
- package/dist/lit/components/empty-state/index.d.ts +21 -0
- package/dist/lit/components/empty-state/index.js +123 -0
- package/dist/lit/components/expansion-panel/index.css +120 -0
- package/dist/lit/components/expansion-panel/index.d.ts +22 -0
- package/dist/lit/components/expansion-panel/index.js +174 -0
- package/dist/lit/components/field/index.css +223 -0
- package/dist/lit/components/field/index.d.ts +106 -0
- package/dist/lit/components/field/index.js +388 -0
- package/dist/lit/components/file-input/index.css +257 -0
- package/dist/lit/components/file-input/index.d.ts +30 -0
- package/dist/lit/components/file-input/index.js +298 -0
- package/dist/lit/components/form/index.css +29 -0
- package/dist/lit/components/form/index.d.ts +38 -0
- package/dist/lit/components/form/index.js +192 -0
- package/dist/lit/components/grid/index.css +53 -0
- package/dist/lit/components/grid/index.d.ts +14 -0
- package/dist/lit/components/grid/index.js +82 -0
- package/dist/lit/components/kbd/index.css +35 -0
- package/dist/lit/components/kbd/index.d.ts +11 -0
- package/dist/lit/components/kbd/index.js +43 -0
- package/dist/lit/components/list/index.css +15 -0
- package/dist/lit/components/list/index.d.ts +28 -0
- package/dist/lit/components/list/index.js +188 -0
- package/dist/lit/components/list-item/index.css +119 -0
- package/dist/lit/components/list-item/index.d.ts +20 -0
- package/dist/lit/components/list-item/index.js +127 -0
- package/dist/lit/components/menu/index.css +94 -0
- package/dist/lit/components/menu/index.d.ts +47 -0
- package/dist/lit/components/menu/index.js +386 -0
- package/dist/lit/components/navigation-drawer/index.css +114 -0
- package/dist/lit/components/navigation-drawer/index.d.ts +29 -0
- package/dist/lit/components/navigation-drawer/index.js +218 -0
- package/dist/lit/components/overlay/index.css +171 -0
- package/dist/lit/components/overlay/index.d.ts +65 -0
- package/dist/lit/components/overlay/index.js +566 -0
- package/dist/lit/components/pagination/index.css +102 -0
- package/dist/lit/components/pagination/index.d.ts +22 -0
- package/dist/lit/components/pagination/index.js +184 -0
- package/dist/lit/components/primitives/index.css +504 -0
- package/dist/lit/components/primitives/index.d.ts +25 -0
- package/dist/lit/components/primitives/index.js +283 -0
- package/dist/lit/components/progress/index.css +143 -0
- package/dist/lit/components/progress/index.d.ts +23 -0
- package/dist/lit/components/progress/index.js +180 -0
- package/dist/lit/components/radio-group/index.css +178 -0
- package/dist/lit/components/radio-group/index.d.ts +35 -0
- package/dist/lit/components/radio-group/index.js +292 -0
- package/dist/lit/components/select/index.css +151 -0
- package/dist/lit/components/select/index.d.ts +50 -0
- package/dist/lit/components/select/index.js +390 -0
- package/dist/lit/components/sidebar-item/index.css +133 -0
- package/dist/lit/components/sidebar-item/index.d.ts +20 -0
- package/dist/lit/components/sidebar-item/index.js +105 -0
- package/dist/lit/components/skeleton/index.css +81 -0
- package/dist/lit/components/skeleton/index.d.ts +19 -0
- package/dist/lit/components/skeleton/index.js +119 -0
- package/dist/lit/components/slider/index.css +171 -0
- package/dist/lit/components/slider/index.d.ts +36 -0
- package/dist/lit/components/slider/index.js +302 -0
- package/dist/lit/components/snackbar/index.css +279 -0
- package/dist/lit/components/snackbar/index.d.ts +33 -0
- package/dist/lit/components/snackbar/index.js +195 -0
- package/dist/lit/components/stack/index.css +41 -0
- package/dist/lit/components/stack/index.d.ts +20 -0
- package/dist/lit/components/stack/index.js +103 -0
- package/dist/lit/components/switch/index.css +126 -0
- package/dist/lit/components/switch/index.d.ts +17 -0
- package/dist/lit/components/switch/index.js +116 -0
- package/dist/lit/components/table/index.css +85 -0
- package/dist/lit/components/table/index.d.ts +25 -0
- package/dist/lit/components/table/index.js +139 -0
- package/dist/lit/components/tabs/index.css +116 -0
- package/dist/lit/components/tabs/index.d.ts +49 -0
- package/dist/lit/components/tabs/index.js +320 -0
- package/dist/lit/components/text-field/index.css +90 -0
- package/dist/lit/components/text-field/index.d.ts +17 -0
- package/dist/lit/components/text-field/index.js +101 -0
- package/dist/lit/components/textarea/index.css +55 -0
- package/dist/lit/components/textarea/index.d.ts +26 -0
- package/dist/lit/components/textarea/index.js +124 -0
- package/dist/lit/components/tooltip/index.css +37 -0
- package/dist/lit/components/tooltip/index.d.ts +31 -0
- package/dist/lit/components/tooltip/index.js +196 -0
- package/dist/lit/components/validation/index.css +386 -0
- package/dist/lit/components/validation/index.d.ts +45 -0
- package/dist/lit/components/validation/index.js +318 -0
- package/dist/lit/index.d.ts +50 -0
- package/dist/lit/index.js +59 -0
- package/package.json +81 -0
- package/styles/README.md +346 -0
- package/styles/_elevation.css +24 -0
- package/styles/_fonts.css +6 -0
- package/styles/_layout.css +37 -0
- package/styles/_primitives.css +154 -0
- package/styles/_scroll.css +75 -0
- package/styles/_semantic.css +146 -0
- package/styles/_space.css +61 -0
- package/styles/_type.css +139 -0
- package/styles/_xmesh-extensions.css +232 -0
- package/styles/index.css +44 -0
- package/styles/md3/_color.css +102 -0
- package/styles/md3/_elevation.css +26 -0
- package/styles/md3/_motion.css +35 -0
- package/styles/md3/_shape.css +22 -0
- package/styles/md3/_state.css +22 -0
- package/styles/md3/_type.css +111 -0
|
@@ -0,0 +1,713 @@
|
|
|
1
|
+
/*
|
|
2
|
+
composer/index.ts — Lit port of components/composer/index.jsx.
|
|
3
|
+
|
|
4
|
+
<xm-composer> — canonical chat composer.
|
|
5
|
+
|
|
6
|
+
Public properties (mirror the React props):
|
|
7
|
+
initialValue prefill text
|
|
8
|
+
initialFocus focus textarea on first render (default true)
|
|
9
|
+
processing render thinking pill + stop button
|
|
10
|
+
thinkingLabel text for the thinking pill
|
|
11
|
+
(default "Routing query through Planning Path…")
|
|
12
|
+
maxChars char counter cap (default 5000)
|
|
13
|
+
counterAt threshold to show counter (0..1) (default 0.8)
|
|
14
|
+
placeholder textarea placeholder
|
|
15
|
+
(default "Describe what you want to create…")
|
|
16
|
+
showAttachments enable attach button + drop/paste + chips/cards/tray
|
|
17
|
+
value controlled-mode mirror property
|
|
18
|
+
(set via JS to seed text from a host)
|
|
19
|
+
attachments controlled-mode array — same idea for files
|
|
20
|
+
|
|
21
|
+
Events (all bubble, composed):
|
|
22
|
+
send detail: { text, attachments: [...] }
|
|
23
|
+
cancel
|
|
24
|
+
value-change detail: { value }
|
|
25
|
+
attachments-change detail: { attachments }
|
|
26
|
+
|
|
27
|
+
Light DOM. Uses components/composer/index.css + components/button/index.css.
|
|
28
|
+
*/
|
|
29
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
30
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
31
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
32
|
+
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;
|
|
33
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
34
|
+
};
|
|
35
|
+
import { LitElement, html, svg, nothing } from "lit";
|
|
36
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
37
|
+
// Side-effect import: registers <xm-button> for use in the toolbar.
|
|
38
|
+
import "../button/index.js";
|
|
39
|
+
/* ---------- attachment helpers (verbatim from JSX) ---------- */
|
|
40
|
+
const STRIP_LIMIT = 10;
|
|
41
|
+
const HARD_CAP = 50;
|
|
42
|
+
const PER_FILE_MAX = 25 * 1024 * 1024;
|
|
43
|
+
const TEXTY_EXTS = new Set([
|
|
44
|
+
"TXT", "MD", "JSON", "YAML", "YML", "CSV", "LOG", "XML", "HTML", "CSS", "JS",
|
|
45
|
+
"TS", "JSX", "TSX", "PY", "GO", "RS", "SH", "SQL", "TOML", "INI", "ENV"
|
|
46
|
+
]);
|
|
47
|
+
const fmtSize = (b) => {
|
|
48
|
+
if (b < 1024)
|
|
49
|
+
return b + " B";
|
|
50
|
+
if (b < 1024 * 1024)
|
|
51
|
+
return (b / 1024).toFixed(b < 10240 ? 1 : 0) + " KB";
|
|
52
|
+
return (b / (1024 * 1024)).toFixed(1) + " MB";
|
|
53
|
+
};
|
|
54
|
+
let _nextAttId = 1;
|
|
55
|
+
const nextAttId = () => _nextAttId++;
|
|
56
|
+
/* ---------- inline icon SVG fragments ---------- */
|
|
57
|
+
const I_PAPERCLIP = (size = 14) => svg `
|
|
58
|
+
<svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="none"
|
|
59
|
+
stroke="currentColor" stroke-width="1.8" stroke-linecap="round"
|
|
60
|
+
stroke-linejoin="round" class="ds-icon">
|
|
61
|
+
<path d="M21.4 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 17.93 8.83l-8.06 8.06a2 2 0 0 1-2.83-2.83l7.07-7.07" />
|
|
62
|
+
</svg>
|
|
63
|
+
`;
|
|
64
|
+
const I_SEND = (size = 14) => svg `
|
|
65
|
+
<svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="none"
|
|
66
|
+
stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
67
|
+
stroke-linejoin="round" class="ds-icon">
|
|
68
|
+
<path d="M7 17L17 7" />
|
|
69
|
+
<path d="M9 7h8v8" />
|
|
70
|
+
</svg>
|
|
71
|
+
`;
|
|
72
|
+
const I_PLAY = (size = 14) => svg `
|
|
73
|
+
<svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="none"
|
|
74
|
+
stroke="currentColor" stroke-width="1.8" stroke-linecap="round"
|
|
75
|
+
stroke-linejoin="round" class="ds-icon">
|
|
76
|
+
<path d="M5 4l14 8-14 8V4z" />
|
|
77
|
+
</svg>
|
|
78
|
+
`;
|
|
79
|
+
const I_FILE = (size = 14) => svg `
|
|
80
|
+
<svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="none"
|
|
81
|
+
stroke="currentColor" stroke-width="1.8" stroke-linecap="round"
|
|
82
|
+
stroke-linejoin="round" class="ds-icon">
|
|
83
|
+
<path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z" />
|
|
84
|
+
<path d="M14 3v5h5" />
|
|
85
|
+
</svg>
|
|
86
|
+
`;
|
|
87
|
+
const I_X = (size = 10) => svg `
|
|
88
|
+
<svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="none"
|
|
89
|
+
stroke="currentColor" stroke-width="2.6" stroke-linecap="round"
|
|
90
|
+
stroke-linejoin="round" class="ds-icon">
|
|
91
|
+
<path d="M6 6l12 12M18 6L6 18" />
|
|
92
|
+
</svg>
|
|
93
|
+
`;
|
|
94
|
+
const I_WARN = (size = 14) => svg `
|
|
95
|
+
<svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="none"
|
|
96
|
+
stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
97
|
+
stroke-linejoin="round" class="ds-icon">
|
|
98
|
+
<path d="M12 9v4" />
|
|
99
|
+
<path d="M12 17h.01" />
|
|
100
|
+
<path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
|
|
101
|
+
</svg>
|
|
102
|
+
`;
|
|
103
|
+
const I_CARET = (size = 12) => svg `
|
|
104
|
+
<svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="none"
|
|
105
|
+
stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
106
|
+
stroke-linejoin="round" class="ds-icon">
|
|
107
|
+
<polyline points="6 9 12 15 18 9" />
|
|
108
|
+
</svg>
|
|
109
|
+
`;
|
|
110
|
+
let XmComposer = class XmComposer extends LitElement {
|
|
111
|
+
constructor() {
|
|
112
|
+
super(...arguments);
|
|
113
|
+
this.initialValue = "";
|
|
114
|
+
this.initialFocus = true;
|
|
115
|
+
this.processing = false;
|
|
116
|
+
this.thinkingLabel = "";
|
|
117
|
+
this.maxChars = 5000;
|
|
118
|
+
this.counterAt = 0.8;
|
|
119
|
+
this.placeholder = "Describe what you want to create…";
|
|
120
|
+
this.showAttachments = false;
|
|
121
|
+
this.value = null;
|
|
122
|
+
this.attachments = null;
|
|
123
|
+
this._value = "";
|
|
124
|
+
this._atts = [];
|
|
125
|
+
this._warning = null;
|
|
126
|
+
this._trayOpen = false;
|
|
127
|
+
this._dragging = false;
|
|
128
|
+
this._dragDepth = 0;
|
|
129
|
+
this._warnTimer = null;
|
|
130
|
+
this._didInitialFocus = false;
|
|
131
|
+
this._lastValueProp = null;
|
|
132
|
+
this._lastAttsProp = null;
|
|
133
|
+
this._clearAtts = () => {
|
|
134
|
+
this._atts = [];
|
|
135
|
+
this._trayOpen = false;
|
|
136
|
+
this._warning = null;
|
|
137
|
+
};
|
|
138
|
+
this._send = () => {
|
|
139
|
+
const t = this._value.trim();
|
|
140
|
+
const hasAtts = this._atts.length > 0;
|
|
141
|
+
const overLimit = this._value.length > this.maxChars;
|
|
142
|
+
if (!t && !hasAtts)
|
|
143
|
+
return;
|
|
144
|
+
if (overLimit)
|
|
145
|
+
return;
|
|
146
|
+
this.dispatchEvent(new CustomEvent("send", {
|
|
147
|
+
detail: { text: t || "(attachment only)", attachments: this._atts.slice() },
|
|
148
|
+
bubbles: true, composed: true,
|
|
149
|
+
}));
|
|
150
|
+
this._value = "";
|
|
151
|
+
this._atts = [];
|
|
152
|
+
this._trayOpen = false;
|
|
153
|
+
};
|
|
154
|
+
this._cancel = () => {
|
|
155
|
+
this.dispatchEvent(new CustomEvent("cancel", { bubbles: true, composed: true }));
|
|
156
|
+
};
|
|
157
|
+
this._onInput = (e) => {
|
|
158
|
+
this._value = e.target.value;
|
|
159
|
+
};
|
|
160
|
+
this._onKeyDown = (e) => {
|
|
161
|
+
if (e.key === "Enter" && !e.shiftKey && !this.processing) {
|
|
162
|
+
e.preventDefault();
|
|
163
|
+
this._send();
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
this._onPaste = (e) => {
|
|
167
|
+
if (!this.showAttachments)
|
|
168
|
+
return;
|
|
169
|
+
const items = e.clipboardData?.items;
|
|
170
|
+
if (!items)
|
|
171
|
+
return;
|
|
172
|
+
const files = [];
|
|
173
|
+
for (const it of items) {
|
|
174
|
+
if (it.kind === "file") {
|
|
175
|
+
const f = it.getAsFile();
|
|
176
|
+
if (f)
|
|
177
|
+
files.push(f);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (files.length) {
|
|
181
|
+
e.preventDefault();
|
|
182
|
+
this._addFiles(files);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
this._onDragEnter = (e) => {
|
|
186
|
+
if (!this.showAttachments)
|
|
187
|
+
return;
|
|
188
|
+
if (!e.dataTransfer?.types?.includes("Files"))
|
|
189
|
+
return;
|
|
190
|
+
e.preventDefault();
|
|
191
|
+
this._dragDepth++;
|
|
192
|
+
this._dragging = true;
|
|
193
|
+
};
|
|
194
|
+
this._onDragOver = (e) => {
|
|
195
|
+
if (!this.showAttachments)
|
|
196
|
+
return;
|
|
197
|
+
if (e.dataTransfer?.types?.includes("Files"))
|
|
198
|
+
e.preventDefault();
|
|
199
|
+
};
|
|
200
|
+
this._onDragLeave = () => {
|
|
201
|
+
if (!this.showAttachments)
|
|
202
|
+
return;
|
|
203
|
+
this._dragDepth = Math.max(0, this._dragDepth - 1);
|
|
204
|
+
if (this._dragDepth === 0)
|
|
205
|
+
this._dragging = false;
|
|
206
|
+
};
|
|
207
|
+
this._onDrop = (e) => {
|
|
208
|
+
if (!this.showAttachments)
|
|
209
|
+
return;
|
|
210
|
+
if (!e.dataTransfer?.files?.length)
|
|
211
|
+
return;
|
|
212
|
+
e.preventDefault();
|
|
213
|
+
this._dragDepth = 0;
|
|
214
|
+
this._dragging = false;
|
|
215
|
+
this._addFiles(e.dataTransfer.files);
|
|
216
|
+
};
|
|
217
|
+
this._onBoxClick = (e) => {
|
|
218
|
+
const target = e.target;
|
|
219
|
+
if (target instanceof Element && target.closest("textarea, button, xm-button, a, input, label, [role='button']"))
|
|
220
|
+
return;
|
|
221
|
+
const ta = this.querySelector(".composer__field");
|
|
222
|
+
if (!ta)
|
|
223
|
+
return;
|
|
224
|
+
ta.focus();
|
|
225
|
+
const len = ta.value.length;
|
|
226
|
+
try {
|
|
227
|
+
ta.setSelectionRange(len, len);
|
|
228
|
+
}
|
|
229
|
+
catch (_) { }
|
|
230
|
+
};
|
|
231
|
+
this._onPickFile = () => {
|
|
232
|
+
this.querySelector(".composer__file-input")?.click();
|
|
233
|
+
};
|
|
234
|
+
this._onFileInput = (e) => {
|
|
235
|
+
const input = e.target;
|
|
236
|
+
if (input.files?.length)
|
|
237
|
+
this._addFiles(input.files);
|
|
238
|
+
input.value = "";
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
createRenderRoot() {
|
|
242
|
+
return this;
|
|
243
|
+
}
|
|
244
|
+
connectedCallback() {
|
|
245
|
+
super.connectedCallback();
|
|
246
|
+
// Make the host transparent to flex/grid layout so the inner
|
|
247
|
+
// .composer-shell behaves as the direct child of whatever container
|
|
248
|
+
// the host sits in. Matters for selectors like
|
|
249
|
+
// `.chat-shell__composer > .composer-shell` in components/chat/index.css.
|
|
250
|
+
if (!this.style.display)
|
|
251
|
+
this.style.display = "contents";
|
|
252
|
+
if (this.value != null) {
|
|
253
|
+
this._value = this.value;
|
|
254
|
+
this._lastValueProp = this.value;
|
|
255
|
+
}
|
|
256
|
+
else if (this.initialValue) {
|
|
257
|
+
this._value = this.initialValue;
|
|
258
|
+
}
|
|
259
|
+
if (Array.isArray(this.attachments)) {
|
|
260
|
+
this._atts = this.attachments.slice();
|
|
261
|
+
this._lastAttsProp = this.attachments;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
willUpdate(changed) {
|
|
265
|
+
// Sync from controlled props when they change identity (mirrors the
|
|
266
|
+
// React useEffect on controlledValue / controlledAttachments).
|
|
267
|
+
if (changed.has("value")) {
|
|
268
|
+
if (this.value != null && this.value !== this._lastValueProp) {
|
|
269
|
+
this._value = this.value;
|
|
270
|
+
this._lastValueProp = this.value;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (changed.has("attachments")) {
|
|
274
|
+
if (Array.isArray(this.attachments) && this.attachments !== this._lastAttsProp) {
|
|
275
|
+
this._atts = this.attachments.slice();
|
|
276
|
+
this._lastAttsProp = this.attachments;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
updated(changed) {
|
|
281
|
+
// Autoresize textarea — match JSX useLayoutEffect (max 240px).
|
|
282
|
+
const ta = this.querySelector(".composer__field");
|
|
283
|
+
if (ta) {
|
|
284
|
+
ta.style.height = "auto";
|
|
285
|
+
if (ta.scrollHeight > 0) {
|
|
286
|
+
ta.style.height = Math.min(ta.scrollHeight, 240) + "px";
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
ta.style.removeProperty("height");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// Initial focus once on first render.
|
|
293
|
+
if (!this._didInitialFocus && this.initialFocus && ta) {
|
|
294
|
+
ta.focus();
|
|
295
|
+
const len = ta.value.length;
|
|
296
|
+
try {
|
|
297
|
+
ta.setSelectionRange(len, len);
|
|
298
|
+
}
|
|
299
|
+
catch (_) { }
|
|
300
|
+
this._didInitialFocus = true;
|
|
301
|
+
}
|
|
302
|
+
// Notify listeners on value changes from internal updates.
|
|
303
|
+
if (changed.has("_value")) {
|
|
304
|
+
this.dispatchEvent(new CustomEvent("value-change", {
|
|
305
|
+
detail: { value: this._value },
|
|
306
|
+
bubbles: true, composed: true,
|
|
307
|
+
}));
|
|
308
|
+
}
|
|
309
|
+
if (changed.has("_atts")) {
|
|
310
|
+
this.dispatchEvent(new CustomEvent("attachments-change", {
|
|
311
|
+
detail: { attachments: this._atts },
|
|
312
|
+
bubbles: true, composed: true,
|
|
313
|
+
}));
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/* ---------- attachment handlers ---------- */
|
|
317
|
+
_flashWarning(msg) {
|
|
318
|
+
if (this._warnTimer)
|
|
319
|
+
clearTimeout(this._warnTimer);
|
|
320
|
+
if (!msg) {
|
|
321
|
+
this._warning = null;
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
this._warning = { msg };
|
|
325
|
+
this._warnTimer = setTimeout(() => { this._warning = null; }, 5000);
|
|
326
|
+
}
|
|
327
|
+
_addFiles(fileList) {
|
|
328
|
+
const incoming = Array.from(fileList);
|
|
329
|
+
const current = this._atts;
|
|
330
|
+
const slots = Math.max(0, HARD_CAP - current.length);
|
|
331
|
+
const accepted = [];
|
|
332
|
+
let dupes = 0, oversized = 0, overCap = 0;
|
|
333
|
+
for (const f of incoming) {
|
|
334
|
+
if (current.some((a) => a.name === f.name && a.size === f.size)) {
|
|
335
|
+
dupes++;
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
if (f.size > PER_FILE_MAX) {
|
|
339
|
+
oversized++;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
if (accepted.length >= slots) {
|
|
343
|
+
overCap++;
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
accepted.push(f);
|
|
347
|
+
}
|
|
348
|
+
const next = [...current];
|
|
349
|
+
const newlyAdded = [];
|
|
350
|
+
for (const f of accepted) {
|
|
351
|
+
const id = nextAttId();
|
|
352
|
+
const ext = (f.name.split(".").pop() || "").toUpperCase();
|
|
353
|
+
const isImage = f.type.startsWith("image/");
|
|
354
|
+
const att = {
|
|
355
|
+
id, name: f.name, kind: isImage ? "image" : "file",
|
|
356
|
+
size: f.size, ext,
|
|
357
|
+
};
|
|
358
|
+
next.push(att);
|
|
359
|
+
newlyAdded.push({ att, file: f, isImage, ext });
|
|
360
|
+
}
|
|
361
|
+
this._atts = next;
|
|
362
|
+
// Async readers for previews / line counts — same logic as JSX.
|
|
363
|
+
for (const { att, file, isImage, ext } of newlyAdded) {
|
|
364
|
+
if (isImage) {
|
|
365
|
+
const reader = new FileReader();
|
|
366
|
+
reader.onload = (e) => {
|
|
367
|
+
const result = e.target?.result;
|
|
368
|
+
if (typeof result !== "string")
|
|
369
|
+
return;
|
|
370
|
+
this._atts = this._atts.map((a) => a.id === att.id ? { ...a, dataUrl: result } : a);
|
|
371
|
+
};
|
|
372
|
+
reader.readAsDataURL(file);
|
|
373
|
+
}
|
|
374
|
+
else if (TEXTY_EXTS.has(ext) && file.size <= 2 * 1024 * 1024) {
|
|
375
|
+
const reader = new FileReader();
|
|
376
|
+
reader.onload = (e) => {
|
|
377
|
+
const t = (e.target?.result ?? "");
|
|
378
|
+
let count = 0;
|
|
379
|
+
for (let i = 0; i < t.length; i++)
|
|
380
|
+
if (t.charCodeAt(i) === 10)
|
|
381
|
+
count++;
|
|
382
|
+
if (t.length && t.charCodeAt(t.length - 1) !== 10)
|
|
383
|
+
count++;
|
|
384
|
+
this._atts = this._atts.map((a) => a.id === att.id ? { ...a, lines: count } : a);
|
|
385
|
+
};
|
|
386
|
+
reader.readAsText(file);
|
|
387
|
+
}
|
|
388
|
+
else if (ext === "PDF") {
|
|
389
|
+
// Synchronous estimate for the placeholder; React mutated the att
|
|
390
|
+
// object directly. We patch through a state update for parity.
|
|
391
|
+
this._atts = this._atts.map((a) => a.id === att.id
|
|
392
|
+
? { ...a, pages: Math.max(1, Math.round(file.size / (60 * 1024))) }
|
|
393
|
+
: a);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
const parts = [];
|
|
397
|
+
if (overCap)
|
|
398
|
+
parts.push(`${overCap} skipped (${HARD_CAP}-file cap reached)`);
|
|
399
|
+
if (oversized)
|
|
400
|
+
parts.push(`${oversized} too large (>${fmtSize(PER_FILE_MAX)} each)`);
|
|
401
|
+
if (dupes)
|
|
402
|
+
parts.push(`${dupes} duplicate${dupes > 1 ? "s" : ""} ignored`);
|
|
403
|
+
this._flashWarning(parts.length ? parts.join(" · ") : null);
|
|
404
|
+
}
|
|
405
|
+
_removeAtt(id) {
|
|
406
|
+
const next = this._atts.filter((a) => a.id !== id);
|
|
407
|
+
if (next.length <= STRIP_LIMIT)
|
|
408
|
+
this._trayOpen = false;
|
|
409
|
+
this._atts = next;
|
|
410
|
+
}
|
|
411
|
+
/* ---------- render fragments ---------- */
|
|
412
|
+
_renderAttCard(att) {
|
|
413
|
+
if (att.kind === "image" && att.dataUrl) {
|
|
414
|
+
const meta = att.dims ? `${att.dims} · ${fmtSize(att.size)}` : fmtSize(att.size);
|
|
415
|
+
return html `
|
|
416
|
+
<div class="att-card att-card--media" title="${att.name}">
|
|
417
|
+
<span
|
|
418
|
+
class="att-card__media"
|
|
419
|
+
style="background-image:url(${att.dataUrl})"
|
|
420
|
+
role="img"
|
|
421
|
+
aria-label="${att.name}"
|
|
422
|
+
></span>
|
|
423
|
+
<span class="att-card__ext">${att.ext || "IMG"}</span>
|
|
424
|
+
<span class="att-card__meta">${meta}</span>
|
|
425
|
+
<button class="att-card__x" aria-label="remove attachment"
|
|
426
|
+
@click=${() => this._removeAtt(att.id)}>${I_X()}</button>
|
|
427
|
+
</div>
|
|
428
|
+
`;
|
|
429
|
+
}
|
|
430
|
+
const primary = att.lines != null ? `${att.lines.toLocaleString()} lines` :
|
|
431
|
+
att.pages != null ? `${att.pages} page${att.pages === 1 ? "" : "s"}` : null;
|
|
432
|
+
const secondary = fmtSize(att.size);
|
|
433
|
+
return html `
|
|
434
|
+
<div class="att-card att-card--text" title="${att.name}">
|
|
435
|
+
<span class="att-card__name">${att.name}</span>
|
|
436
|
+
${primary
|
|
437
|
+
? html `
|
|
438
|
+
<span class="att-card__sub">
|
|
439
|
+
<span class="att-card__sub-primary">${primary}</span>
|
|
440
|
+
<span class="att-card__sub-secondary">${secondary}</span>
|
|
441
|
+
</span>
|
|
442
|
+
`
|
|
443
|
+
: html `<span class="att-card__sub">${secondary}</span>`}
|
|
444
|
+
<span class="att-card__ext">${att.ext || "FILE"}</span>
|
|
445
|
+
<button class="att-card__x" aria-label="remove attachment"
|
|
446
|
+
@click=${() => this._removeAtt(att.id)}>${I_X()}</button>
|
|
447
|
+
</div>
|
|
448
|
+
`;
|
|
449
|
+
}
|
|
450
|
+
_renderAttRow(att) {
|
|
451
|
+
const ext = att.kind === "image" ? (att.ext || "PNG") : (att.ext || "FILE");
|
|
452
|
+
const meta = att.lines != null ? `${att.lines.toLocaleString()} lines` :
|
|
453
|
+
att.pages != null ? `${att.pages} page${att.pages === 1 ? "" : "s"}` :
|
|
454
|
+
att.dims ? att.dims : null;
|
|
455
|
+
return html `
|
|
456
|
+
<div class="att__row">
|
|
457
|
+
${att.kind === "image" && att.dataUrl
|
|
458
|
+
? html `<span class="att__row-thumb"
|
|
459
|
+
style="background-image:url(${att.dataUrl})"></span>`
|
|
460
|
+
: html `<span class="att__row-icon">${I_FILE()}</span>`}
|
|
461
|
+
<span class="att__row-name" title="${att.name}">${att.name}</span>
|
|
462
|
+
${meta
|
|
463
|
+
? html `
|
|
464
|
+
<span class="att__row-meta">
|
|
465
|
+
<span class="att__row-meta-primary">${meta}</span>
|
|
466
|
+
<span class="att__row-meta-secondary">${ext} · ${fmtSize(att.size)}</span>
|
|
467
|
+
</span>
|
|
468
|
+
`
|
|
469
|
+
: html `<span class="att__row-size">${ext} · ${fmtSize(att.size)}</span>`}
|
|
470
|
+
<button class="att__row-x" aria-label="remove attachment"
|
|
471
|
+
@click=${() => this._removeAtt(att.id)}>${I_X(9)}</button>
|
|
472
|
+
</div>
|
|
473
|
+
`;
|
|
474
|
+
}
|
|
475
|
+
_renderAttachments() {
|
|
476
|
+
const atts = this._atts;
|
|
477
|
+
const warning = this._warning;
|
|
478
|
+
if (atts.length === 0 && !warning)
|
|
479
|
+
return nothing;
|
|
480
|
+
const n = atts.length;
|
|
481
|
+
const sumSize = atts.reduce((s, a) => s + (a.size || 0), 0);
|
|
482
|
+
return html `
|
|
483
|
+
<div class="att">
|
|
484
|
+
${warning
|
|
485
|
+
? html `<div class="att__warn" role="status">${I_WARN()}<span>${warning.msg}</span></div>`
|
|
486
|
+
: nothing}
|
|
487
|
+
${n > 0
|
|
488
|
+
? html `
|
|
489
|
+
<div class="att__header">
|
|
490
|
+
<span class="att__header-left">
|
|
491
|
+
<span class="att__pip">${n}</span>
|
|
492
|
+
${n === 1 ? " attachment" : " attachments"} · ${fmtSize(sumSize)}
|
|
493
|
+
</span>
|
|
494
|
+
<span class="att__header-right">
|
|
495
|
+
<button class="att__link" @click=${this._clearAtts}>Clear all</button>
|
|
496
|
+
</span>
|
|
497
|
+
</div>
|
|
498
|
+
${n <= STRIP_LIMIT
|
|
499
|
+
? html `<div class="att__grid">${atts.map((a) => this._renderAttCard(a))}</div>`
|
|
500
|
+
: html `
|
|
501
|
+
<button
|
|
502
|
+
type="button"
|
|
503
|
+
class="att__bundle"
|
|
504
|
+
aria-expanded="${this._trayOpen}"
|
|
505
|
+
@click=${() => { this._trayOpen = !this._trayOpen; }}
|
|
506
|
+
>
|
|
507
|
+
<span class="att__bundle-stack" aria-hidden="true">
|
|
508
|
+
<span></span><span></span>
|
|
509
|
+
<span>${I_FILE()}</span>
|
|
510
|
+
</span>
|
|
511
|
+
<span class="att__bundle-meta">
|
|
512
|
+
<span class="att__bundle-name">${n} files bundled</span>
|
|
513
|
+
<span class="att__bundle-sub">${fmtSize(sumSize)} · ${this._trayOpen ? "Hide list" : "View list"}</span>
|
|
514
|
+
</span>
|
|
515
|
+
<span class="att__bundle-caret">${I_CARET()}</span>
|
|
516
|
+
</button>
|
|
517
|
+
${this._trayOpen
|
|
518
|
+
? html `<div class="att__tray" role="list">
|
|
519
|
+
${atts.map((a) => this._renderAttRow(a))}
|
|
520
|
+
</div>`
|
|
521
|
+
: nothing}
|
|
522
|
+
`}
|
|
523
|
+
`
|
|
524
|
+
: nothing}
|
|
525
|
+
</div>
|
|
526
|
+
`;
|
|
527
|
+
}
|
|
528
|
+
_renderHint() {
|
|
529
|
+
if (this.processing) {
|
|
530
|
+
return html `
|
|
531
|
+
<span class="composer__hint">
|
|
532
|
+
Click <span class="composer__stop-icon"
|
|
533
|
+
style="vertical-align:-1px;margin:0 2px"
|
|
534
|
+
aria-hidden="true"></span> to cancel current request
|
|
535
|
+
</span>
|
|
536
|
+
`;
|
|
537
|
+
}
|
|
538
|
+
const n = this._atts.length;
|
|
539
|
+
if (n >= HARD_CAP) {
|
|
540
|
+
return html `<span class="composer__hint">${HARD_CAP}/${HARD_CAP} attached · cap reached</span>`;
|
|
541
|
+
}
|
|
542
|
+
if (n > STRIP_LIMIT) {
|
|
543
|
+
return html `<span class="composer__hint">${n} attached · expand list to manage</span>`;
|
|
544
|
+
}
|
|
545
|
+
if (n > 0) {
|
|
546
|
+
return html `<span class="composer__hint">${n} attached · paste with <kbd>⌘V</kbd></span>`;
|
|
547
|
+
}
|
|
548
|
+
return html `<span class="composer__hint">Enter to send · <kbd>Shift</kbd>+<kbd>Enter</kbd> for new line</span>`;
|
|
549
|
+
}
|
|
550
|
+
render() {
|
|
551
|
+
const text = this._value;
|
|
552
|
+
const hasText = text.trim().length > 0;
|
|
553
|
+
const hasAtts = this._atts.length > 0;
|
|
554
|
+
const charCount = text.length;
|
|
555
|
+
const overLimit = charCount > this.maxChars;
|
|
556
|
+
const showCounter = charCount >= this.maxChars * this.counterAt;
|
|
557
|
+
const canSend = (hasText || hasAtts) && !overLimit && !this.processing;
|
|
558
|
+
return html `
|
|
559
|
+
<div class="composer-shell">
|
|
560
|
+
<div
|
|
561
|
+
class="composer ${this._dragging ? "composer--dragging" : ""}"
|
|
562
|
+
@click=${this._onBoxClick}
|
|
563
|
+
@dragenter=${this._onDragEnter}
|
|
564
|
+
@dragover=${this._onDragOver}
|
|
565
|
+
@dragleave=${this._onDragLeave}
|
|
566
|
+
@drop=${this._onDrop}
|
|
567
|
+
>
|
|
568
|
+
${this.showAttachments ? this._renderAttachments() : nothing}
|
|
569
|
+
|
|
570
|
+
${this.processing
|
|
571
|
+
? html `
|
|
572
|
+
<div class="composer__thinking" role="status" aria-live="polite">
|
|
573
|
+
<span class="composer__thinking-dots" aria-hidden="true">
|
|
574
|
+
<span class="composer__thinking-dot"></span>
|
|
575
|
+
<span class="composer__thinking-dot"></span>
|
|
576
|
+
<span class="composer__thinking-dot"></span>
|
|
577
|
+
</span>
|
|
578
|
+
<span class="composer__thinking-label">${this.thinkingLabel || "Routing query through Planning Path…"}</span>
|
|
579
|
+
</div>
|
|
580
|
+
`
|
|
581
|
+
: nothing}
|
|
582
|
+
|
|
583
|
+
<textarea
|
|
584
|
+
class="composer__field scroll-canvas"
|
|
585
|
+
name="message"
|
|
586
|
+
rows="1"
|
|
587
|
+
.value=${text}
|
|
588
|
+
placeholder="${this.placeholder}"
|
|
589
|
+
aria-label="Message"
|
|
590
|
+
@input=${this._onInput}
|
|
591
|
+
@keydown=${this._onKeyDown}
|
|
592
|
+
@paste=${this._onPaste}
|
|
593
|
+
></textarea>
|
|
594
|
+
|
|
595
|
+
<div class="composer__toolbar">
|
|
596
|
+
<div class="composer__toolbar-left">
|
|
597
|
+
${this.showAttachments
|
|
598
|
+
? html `
|
|
599
|
+
<xm-button
|
|
600
|
+
variant="ghost"
|
|
601
|
+
size="sm"
|
|
602
|
+
icon-only
|
|
603
|
+
aria-label="attach"
|
|
604
|
+
title="Attach file"
|
|
605
|
+
@click=${this._onPickFile}
|
|
606
|
+
>${I_PAPERCLIP()}</xm-button>
|
|
607
|
+
<input
|
|
608
|
+
type="file"
|
|
609
|
+
multiple
|
|
610
|
+
hidden
|
|
611
|
+
class="composer__file-input"
|
|
612
|
+
@change=${this._onFileInput}
|
|
613
|
+
/>
|
|
614
|
+
`
|
|
615
|
+
: nothing}
|
|
616
|
+
</div>
|
|
617
|
+
<div class="composer__toolbar-right">
|
|
618
|
+
${showCounter && !this.processing
|
|
619
|
+
? html `
|
|
620
|
+
<span class="composer__counter ${overLimit ? "composer__counter--over" : "composer__counter--warn"}">
|
|
621
|
+
${charCount.toLocaleString()} / ${this.maxChars.toLocaleString()}
|
|
622
|
+
</span>
|
|
623
|
+
`
|
|
624
|
+
: nothing}
|
|
625
|
+
|
|
626
|
+
${!this.processing
|
|
627
|
+
? html `
|
|
628
|
+
<xm-button
|
|
629
|
+
variant="primary"
|
|
630
|
+
size="sm"
|
|
631
|
+
aria-label="send"
|
|
632
|
+
?disabled=${!canSend}
|
|
633
|
+
title="${overLimit ? "Message too long" : canSend ? "Send (Enter)" : "Type a message to send"}"
|
|
634
|
+
@click=${this._send}
|
|
635
|
+
>
|
|
636
|
+
<span slot="icon-left">${I_SEND()}</span>
|
|
637
|
+
Send
|
|
638
|
+
</xm-button>
|
|
639
|
+
`
|
|
640
|
+
: html `
|
|
641
|
+
<xm-button
|
|
642
|
+
variant="ghost-canvas"
|
|
643
|
+
size="sm"
|
|
644
|
+
icon-only
|
|
645
|
+
disabled
|
|
646
|
+
aria-label="sending"
|
|
647
|
+
title="Generating response…"
|
|
648
|
+
>${I_PLAY()}</xm-button>
|
|
649
|
+
<xm-button
|
|
650
|
+
variant="ghost-canvas"
|
|
651
|
+
size="sm"
|
|
652
|
+
icon-only
|
|
653
|
+
aria-label="stop"
|
|
654
|
+
title="Cancel current request"
|
|
655
|
+
@click=${this._cancel}
|
|
656
|
+
><span class="composer__stop-icon"></span></xm-button>
|
|
657
|
+
`}
|
|
658
|
+
</div>
|
|
659
|
+
</div>
|
|
660
|
+
</div>
|
|
661
|
+
<div class="composer-shell__bottom">${this._renderHint()}</div>
|
|
662
|
+
</div>
|
|
663
|
+
`;
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
__decorate([
|
|
667
|
+
property({ type: String, attribute: "initial-value" })
|
|
668
|
+
], XmComposer.prototype, "initialValue", void 0);
|
|
669
|
+
__decorate([
|
|
670
|
+
property({ type: Boolean, attribute: "initial-focus" })
|
|
671
|
+
], XmComposer.prototype, "initialFocus", void 0);
|
|
672
|
+
__decorate([
|
|
673
|
+
property({ type: Boolean })
|
|
674
|
+
], XmComposer.prototype, "processing", void 0);
|
|
675
|
+
__decorate([
|
|
676
|
+
property({ type: String, attribute: "thinking-label" })
|
|
677
|
+
], XmComposer.prototype, "thinkingLabel", void 0);
|
|
678
|
+
__decorate([
|
|
679
|
+
property({ type: Number, attribute: "max-chars" })
|
|
680
|
+
], XmComposer.prototype, "maxChars", void 0);
|
|
681
|
+
__decorate([
|
|
682
|
+
property({ type: Number, attribute: "counter-at" })
|
|
683
|
+
], XmComposer.prototype, "counterAt", void 0);
|
|
684
|
+
__decorate([
|
|
685
|
+
property({ type: String })
|
|
686
|
+
], XmComposer.prototype, "placeholder", void 0);
|
|
687
|
+
__decorate([
|
|
688
|
+
property({ type: Boolean, attribute: "show-attachments" })
|
|
689
|
+
], XmComposer.prototype, "showAttachments", void 0);
|
|
690
|
+
__decorate([
|
|
691
|
+
property({ attribute: false })
|
|
692
|
+
], XmComposer.prototype, "value", void 0);
|
|
693
|
+
__decorate([
|
|
694
|
+
property({ attribute: false })
|
|
695
|
+
], XmComposer.prototype, "attachments", void 0);
|
|
696
|
+
__decorate([
|
|
697
|
+
state()
|
|
698
|
+
], XmComposer.prototype, "_value", void 0);
|
|
699
|
+
__decorate([
|
|
700
|
+
state()
|
|
701
|
+
], XmComposer.prototype, "_atts", void 0);
|
|
702
|
+
__decorate([
|
|
703
|
+
state()
|
|
704
|
+
], XmComposer.prototype, "_warning", void 0);
|
|
705
|
+
__decorate([
|
|
706
|
+
state()
|
|
707
|
+
], XmComposer.prototype, "_trayOpen", void 0);
|
|
708
|
+
__decorate([
|
|
709
|
+
state()
|
|
710
|
+
], XmComposer.prototype, "_dragging", void 0);
|
|
711
|
+
XmComposer = __decorate([
|
|
712
|
+
customElement("xm-composer")
|
|
713
|
+
], XmComposer);
|