@ai-composer/dom 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +5 -2
- package/dist/icons.d.ts +11 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +46 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/mount.d.ts +41 -0
- package/dist/mount.d.ts.map +1 -0
- package/dist/mount.js +168 -0
- package/dist/mount.js.map +1 -0
- package/dist/package.json +25 -0
- package/dist/parse.d.ts +13 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +133 -0
- package/dist/parse.js.map +1 -0
- package/dist/popup.d.ts +34 -0
- package/dist/popup.d.ts.map +1 -0
- package/dist/popup.js +121 -0
- package/dist/popup.js.map +1 -0
- package/dist/render.d.ts +17 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +84 -0
- package/dist/render.js.map +1 -0
- package/dist/selection.d.ts +13 -0
- package/dist/selection.d.ts.map +1 -0
- package/dist/selection.js +110 -0
- package/dist/selection.js.map +1 -0
- package/dist/suggestions.d.ts +23 -0
- package/dist/suggestions.d.ts.map +1 -0
- package/dist/suggestions.js +113 -0
- package/dist/suggestions.js.map +1 -0
- package/dist/surface.d.ts +40 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +372 -0
- package/dist/surface.js.map +1 -0
- package/dist/template.d.ts +26 -0
- package/dist/template.d.ts.map +1 -0
- package/dist/template.js +47 -0
- package/dist/template.js.map +1 -0
- package/package.json +21 -3
- package/project.json +56 -0
- package/src/icons.ts +51 -0
- package/src/index.ts +50 -0
- package/src/mount.ts +218 -0
- package/src/parse.ts +135 -0
- package/src/popup.ts +153 -0
- package/src/render.ts +88 -0
- package/src/selection.ts +141 -0
- package/src/suggestions.ts +146 -0
- package/src/surface.test.ts +266 -0
- package/src/surface.ts +433 -0
- package/src/template.ts +80 -0
- package/tsconfig.json +15 -0
- package/tsconfig.lib.json +15 -0
- package/tsconfig.spec.json +16 -0
- package/vitest.config.ts +16 -0
package/dist/surface.js
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editable surface: binds a contentEditable host to an editor using the
|
|
3
|
+
* model-first pipeline:
|
|
4
|
+
*
|
|
5
|
+
* user input → parse DOM → editor.applyViewUpdate() (model is authoritative)
|
|
6
|
+
* model change → render → restore caret from model selection
|
|
7
|
+
*
|
|
8
|
+
* All programmatic APIs (setValue/insertNode/undo…) write the model; the
|
|
9
|
+
* surface re-projects it. See ADR-0001.
|
|
10
|
+
*/
|
|
11
|
+
import { createSelection, documentToText, ensureNodeKey, fromGlobalOffset, getRange, sanitizeDocument, toGlobalOffset, } from '@ai-composer/core';
|
|
12
|
+
import { parseEditableHost, htmlToPlainText, CLIPBOARD_MIME } from './parse';
|
|
13
|
+
import { renderDocument } from './render';
|
|
14
|
+
import { applyModelSelection, domSelectionToModel } from './selection';
|
|
15
|
+
export const EDITABLE_SURFACE_CLASS = 'aic-input';
|
|
16
|
+
let surfaceCounter = 0;
|
|
17
|
+
export function createEditableSurface(editor, host, options = {}) {
|
|
18
|
+
const surfaceId = options.id ?? `aic-input-${(surfaceCounter += 1)}`;
|
|
19
|
+
let submitKeyOverride = options.submitKey;
|
|
20
|
+
const submitKey = () => submitKeyOverride ?? editor.getConfig().submitKey ?? 'enter';
|
|
21
|
+
const ariaLabel = () => options.ariaLabel ?? editor.getConfig().placeholder ?? 'AI Composer';
|
|
22
|
+
let composing = false;
|
|
23
|
+
let rendering = false;
|
|
24
|
+
let fromDom = false;
|
|
25
|
+
let destroyed = false;
|
|
26
|
+
let multiline = options.multiline ?? true;
|
|
27
|
+
let lastRendered = null;
|
|
28
|
+
const disposables = [];
|
|
29
|
+
host.id = surfaceId;
|
|
30
|
+
host.classList.add(EDITABLE_SURFACE_CLASS);
|
|
31
|
+
host.setAttribute('data-aic-input', '');
|
|
32
|
+
host.setAttribute('role', 'textbox');
|
|
33
|
+
host.setAttribute('aria-label', ariaLabel());
|
|
34
|
+
host.setAttribute('aria-multiline', String(multiline));
|
|
35
|
+
host.spellcheck = false;
|
|
36
|
+
// -- rendering -----------------------------------------------------------
|
|
37
|
+
function render() {
|
|
38
|
+
if (destroyed)
|
|
39
|
+
return;
|
|
40
|
+
rendering = true;
|
|
41
|
+
try {
|
|
42
|
+
renderDocument(host, editor.getValue(), editor.nodes);
|
|
43
|
+
lastRendered = editor.getValue();
|
|
44
|
+
applyModelSelection(host, editor.getValue(), editor.getSelection());
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
rendering = false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function syncFromState() {
|
|
51
|
+
if (destroyed)
|
|
52
|
+
return;
|
|
53
|
+
const state = editor.getState();
|
|
54
|
+
const editable = !state.disabled && !state.readonly;
|
|
55
|
+
if (host.getAttribute('contenteditable') !== (editable ? 'true' : 'false')) {
|
|
56
|
+
host.setAttribute('contenteditable', editable ? 'true' : 'false');
|
|
57
|
+
}
|
|
58
|
+
host.toggleAttribute('data-aic-readonly', state.readonly);
|
|
59
|
+
host.toggleAttribute('data-aic-disabled', state.disabled);
|
|
60
|
+
host.setAttribute('aria-label', ariaLabel());
|
|
61
|
+
if (state.placeholder) {
|
|
62
|
+
host.setAttribute('data-placeholder', state.placeholder);
|
|
63
|
+
}
|
|
64
|
+
host.toggleAttribute('data-aic-empty', state.empty);
|
|
65
|
+
if (state.value !== lastRendered) {
|
|
66
|
+
if (fromDom) {
|
|
67
|
+
// The change originated from this host's own input event — the DOM
|
|
68
|
+
// already reflects it. Re-rendering under the browser's active input
|
|
69
|
+
// processing corrupts caret/insert state (duplicated keystrokes).
|
|
70
|
+
lastRendered = state.value;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
render();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
syncMultilineHint(state.empty);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Multiline detection for styling (compact pill → rounded box) and a11y:
|
|
80
|
+
* true when the model contains a newline OR the content spans more than one
|
|
81
|
+
* line box (soft wrap). Growth then comes from `height: auto`; the cap is
|
|
82
|
+
* `--aic-input-max-height` with an internal scrollbar. Never true for an
|
|
83
|
+
* empty host — the browser's trailing `<br>` artifact would flag it.
|
|
84
|
+
*/
|
|
85
|
+
function syncMultilineHint(empty) {
|
|
86
|
+
// Only real text newlines count — serialized chips may render as '\n'.
|
|
87
|
+
const hasNewline = editor
|
|
88
|
+
.getValue()
|
|
89
|
+
.nodes.some((node) => node.type === 'text' && node.text.includes('\n'));
|
|
90
|
+
const multiline = !empty && (hasNewline || spansMultipleLines(host));
|
|
91
|
+
// Mirrored onto the root so theme CSS uses plain attribute selectors —
|
|
92
|
+
// `:has()`-based rules are still dropped by some engine versions.
|
|
93
|
+
host.toggleAttribute('data-aic-multiline', multiline);
|
|
94
|
+
host.closest('.aic-root')?.toggleAttribute('data-aic-multiline', multiline);
|
|
95
|
+
}
|
|
96
|
+
// -- input pipeline --------------------------------------------------------
|
|
97
|
+
function syncFromDom() {
|
|
98
|
+
if (destroyed || rendering || composing)
|
|
99
|
+
return;
|
|
100
|
+
const parsed = parseEditableHost(host, editor.nodes);
|
|
101
|
+
const selection = domSelectionToModel(host, parsed);
|
|
102
|
+
fromDom = true;
|
|
103
|
+
try {
|
|
104
|
+
editor.applyViewUpdate(parsed, selection ?? undefined);
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
fromDom = false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function handleEnter(shiftKey) {
|
|
111
|
+
const state = editor.getState();
|
|
112
|
+
const key = submitKey();
|
|
113
|
+
if (key === 'none' || (key === 'enter' && shiftKey) || (key === 'shift-enter' && !shiftKey)) {
|
|
114
|
+
editor.insertText('\n');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (state.suggestions.length > 0) {
|
|
118
|
+
void editor.acceptSuggestion();
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
void editor.submit();
|
|
122
|
+
}
|
|
123
|
+
function onBeforeInput(event) {
|
|
124
|
+
if (destroyed)
|
|
125
|
+
return;
|
|
126
|
+
const inputType = event.inputType;
|
|
127
|
+
// Enter is fully handled at keydown; beforeinput is a safety net against
|
|
128
|
+
// native paragraph markup from edge paths (e.g. IME confirm).
|
|
129
|
+
if (inputType === 'insertParagraph') {
|
|
130
|
+
event.preventDefault();
|
|
131
|
+
}
|
|
132
|
+
if (inputType === 'historyUndo') {
|
|
133
|
+
event.preventDefault();
|
|
134
|
+
editor.undo();
|
|
135
|
+
}
|
|
136
|
+
if (inputType === 'historyRedo') {
|
|
137
|
+
event.preventDefault();
|
|
138
|
+
editor.redo();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function onInput() {
|
|
142
|
+
if (composing)
|
|
143
|
+
return;
|
|
144
|
+
syncFromDom();
|
|
145
|
+
}
|
|
146
|
+
function onKeyDown(event) {
|
|
147
|
+
if (destroyed)
|
|
148
|
+
return;
|
|
149
|
+
const state = editor.getState();
|
|
150
|
+
const key = event.key;
|
|
151
|
+
// Suggestion menu navigation
|
|
152
|
+
if (state.suggestions.length > 0) {
|
|
153
|
+
if (key === 'ArrowDown') {
|
|
154
|
+
event.preventDefault();
|
|
155
|
+
editor.moveSuggestionSelection(1);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (key === 'ArrowUp') {
|
|
159
|
+
event.preventDefault();
|
|
160
|
+
editor.moveSuggestionSelection(-1);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (key === 'Enter' || key === 'Tab') {
|
|
164
|
+
event.preventDefault();
|
|
165
|
+
void editor.acceptSuggestion();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (key === 'Escape') {
|
|
169
|
+
event.preventDefault();
|
|
170
|
+
editor.closeTrigger('escape');
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else if (key === 'Enter') {
|
|
175
|
+
// Enter semantics live here — keydown carries reliable modifier state.
|
|
176
|
+
event.preventDefault();
|
|
177
|
+
handleEnter(event.shiftKey);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// History shortcuts (native contentEditable undo is disabled)
|
|
181
|
+
const meta = event.metaKey || event.ctrlKey;
|
|
182
|
+
if (meta && key.toLowerCase() === 'z') {
|
|
183
|
+
event.preventDefault();
|
|
184
|
+
if (event.shiftKey)
|
|
185
|
+
editor.redo();
|
|
186
|
+
else
|
|
187
|
+
editor.undo();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (meta && key.toLowerCase() === 'y') {
|
|
191
|
+
event.preventDefault();
|
|
192
|
+
editor.redo();
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function onPaste(event) {
|
|
197
|
+
if (destroyed)
|
|
198
|
+
return;
|
|
199
|
+
event.preventDefault();
|
|
200
|
+
const transfer = event.clipboardData;
|
|
201
|
+
if (!transfer)
|
|
202
|
+
return;
|
|
203
|
+
const internal = transfer.getData(CLIPBOARD_MIME);
|
|
204
|
+
if (internal) {
|
|
205
|
+
try {
|
|
206
|
+
const parsed = JSON.parse(internal);
|
|
207
|
+
if (Array.isArray(parsed?.nodes)) {
|
|
208
|
+
const sanitized = sanitizeDocument({ nodes: parsed.nodes.map(ensureNodeKey) }, (type) => editor.nodes.has(type));
|
|
209
|
+
if (sanitized.nodes.length > 0) {
|
|
210
|
+
editor.replaceRange(getRange(editor.getSelection()), sanitized.nodes);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// malformed internal payload — fall through to plain text
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
const html = transfer.getData('text/html');
|
|
220
|
+
const text = transfer.getData('text/plain') || (html ? htmlToPlainText(html) : '');
|
|
221
|
+
if (text)
|
|
222
|
+
editor.insertText(text);
|
|
223
|
+
}
|
|
224
|
+
function onCopy(event) {
|
|
225
|
+
const payload = sliceSelection(editor.getValue(), editor.getSelection());
|
|
226
|
+
if (payload.nodes.length === 0)
|
|
227
|
+
return;
|
|
228
|
+
event.preventDefault();
|
|
229
|
+
const selectedDoc = { nodes: payload.nodes };
|
|
230
|
+
event.clipboardData?.setData('text/plain', documentText(editor, selectedDoc));
|
|
231
|
+
event.clipboardData?.setData(CLIPBOARD_MIME, JSON.stringify({ nodes: payload.nodes }));
|
|
232
|
+
}
|
|
233
|
+
function onFocus() {
|
|
234
|
+
editor.setFocused(true);
|
|
235
|
+
}
|
|
236
|
+
function onBlur() {
|
|
237
|
+
editor.setFocused(false);
|
|
238
|
+
}
|
|
239
|
+
function onSelectionChange() {
|
|
240
|
+
if (destroyed || rendering)
|
|
241
|
+
return;
|
|
242
|
+
const ownerDocument = host.ownerDocument;
|
|
243
|
+
const domSelection = ownerDocument.getSelection();
|
|
244
|
+
if (!domSelection || !host.contains(domSelection.anchorNode))
|
|
245
|
+
return;
|
|
246
|
+
const selection = domSelectionToModel(host, editor.getValue());
|
|
247
|
+
if (selection) {
|
|
248
|
+
try {
|
|
249
|
+
editor.setSelection(selection);
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
// Editor may have been destroyed between the timer scheduling and now.
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// -- wiring ---------------------------------------------------------------
|
|
257
|
+
host.addEventListener('beforeinput', onBeforeInput);
|
|
258
|
+
host.addEventListener('input', onInput);
|
|
259
|
+
host.addEventListener('keydown', onKeyDown);
|
|
260
|
+
host.addEventListener('paste', onPaste);
|
|
261
|
+
host.addEventListener('copy', onCopy);
|
|
262
|
+
host.addEventListener('focus', onFocus);
|
|
263
|
+
host.addEventListener('blur', onBlur);
|
|
264
|
+
host.addEventListener('compositionstart', () => {
|
|
265
|
+
composing = true;
|
|
266
|
+
});
|
|
267
|
+
host.addEventListener('compositionend', () => {
|
|
268
|
+
composing = false;
|
|
269
|
+
syncFromDom();
|
|
270
|
+
});
|
|
271
|
+
host.ownerDocument.addEventListener('selectionchange', onSelectionChange);
|
|
272
|
+
disposables.push(editor.attachView({
|
|
273
|
+
focus: () => surface.focus(),
|
|
274
|
+
blur: () => surface.blur(),
|
|
275
|
+
render: () => render(),
|
|
276
|
+
}));
|
|
277
|
+
disposables.push(editor.subscribe(syncFromState));
|
|
278
|
+
editor.on('destroy', () => surface.destroy());
|
|
279
|
+
syncFromState();
|
|
280
|
+
const surface = {
|
|
281
|
+
host,
|
|
282
|
+
render,
|
|
283
|
+
focus(options2) {
|
|
284
|
+
host.focus({ preventScroll: true });
|
|
285
|
+
const ownerDocument = host.ownerDocument;
|
|
286
|
+
const domSelection = ownerDocument.getSelection();
|
|
287
|
+
if (!domSelection || !host.contains(domSelection.focusNode)) {
|
|
288
|
+
const position = options2?.at ?? 'end';
|
|
289
|
+
const doc = editor.getValue();
|
|
290
|
+
const total = doc.nodes.reduce((sum, n) => sum + (n.type === 'text' ? n.text.length : 1), 0);
|
|
291
|
+
const offset = position === 'start' ? 0 : total;
|
|
292
|
+
editor.setSelection(createSelection(fromGlobalOffset(doc, offset)));
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
blur() {
|
|
296
|
+
host.blur();
|
|
297
|
+
},
|
|
298
|
+
setMultiline(next) {
|
|
299
|
+
multiline = next;
|
|
300
|
+
host.setAttribute('aria-multiline', String(next));
|
|
301
|
+
},
|
|
302
|
+
setSubmitKey(key) {
|
|
303
|
+
submitKeyOverride = key;
|
|
304
|
+
},
|
|
305
|
+
destroy() {
|
|
306
|
+
if (destroyed)
|
|
307
|
+
return;
|
|
308
|
+
destroyed = true;
|
|
309
|
+
host.removeEventListener('beforeinput', onBeforeInput);
|
|
310
|
+
host.removeEventListener('input', onInput);
|
|
311
|
+
host.removeEventListener('keydown', onKeyDown);
|
|
312
|
+
host.removeEventListener('paste', onPaste);
|
|
313
|
+
host.removeEventListener('copy', onCopy);
|
|
314
|
+
host.removeEventListener('focus', onFocus);
|
|
315
|
+
host.removeEventListener('blur', onBlur);
|
|
316
|
+
host.ownerDocument.removeEventListener('selectionchange', onSelectionChange);
|
|
317
|
+
for (const dispose of disposables.splice(0))
|
|
318
|
+
dispose();
|
|
319
|
+
host.setAttribute('contenteditable', 'false');
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
return surface;
|
|
323
|
+
}
|
|
324
|
+
function documentText(editor, doc) {
|
|
325
|
+
return documentToText(doc, { nodes: editor.nodes });
|
|
326
|
+
}
|
|
327
|
+
/** True when the host's content occupies more than one visual line. */
|
|
328
|
+
function spansMultipleLines(host) {
|
|
329
|
+
const doc = host.ownerDocument;
|
|
330
|
+
const range = doc.createRange();
|
|
331
|
+
range.selectNodeContents(host);
|
|
332
|
+
if (typeof range.getClientRects !== 'function')
|
|
333
|
+
return false; // jsdom
|
|
334
|
+
const rects = Array.from(range.getClientRects());
|
|
335
|
+
if (rects.length < 2)
|
|
336
|
+
return false;
|
|
337
|
+
// Same-line items (inline chips + text runs) overlap vertically, so their
|
|
338
|
+
// combined span stays close to the tallest single rect; wrapped/newline
|
|
339
|
+
// content stacks and roughly doubles it.
|
|
340
|
+
const span = Math.max(...rects.map((rect) => rect.bottom)) - Math.min(...rects.map((rect) => rect.top));
|
|
341
|
+
const tallest = Math.max(...rects.map((rect) => rect.height));
|
|
342
|
+
return tallest > 0 && span > tallest * 1.5;
|
|
343
|
+
}
|
|
344
|
+
/** Clone the nodes intersecting the current selection (used for copy). */
|
|
345
|
+
function sliceSelection(doc, selection) {
|
|
346
|
+
const { start, end } = getRange(selection);
|
|
347
|
+
const toOffset = (position) => toGlobalOffset(doc, position);
|
|
348
|
+
const low = Math.min(toOffset(start), toOffset(end));
|
|
349
|
+
const high = Math.max(toOffset(start), toOffset(end));
|
|
350
|
+
const nodes = [];
|
|
351
|
+
let cursor = 0;
|
|
352
|
+
for (const node of doc.nodes) {
|
|
353
|
+
const length = node.type === 'text' ? node.text.length : 1;
|
|
354
|
+
const nodeStart = cursor;
|
|
355
|
+
const nodeEnd = cursor + length;
|
|
356
|
+
cursor = nodeEnd;
|
|
357
|
+
if (nodeEnd <= low || nodeStart >= high)
|
|
358
|
+
continue;
|
|
359
|
+
if (node.type !== 'text') {
|
|
360
|
+
nodes.push(node);
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
const from = Math.max(0, low - nodeStart);
|
|
364
|
+
const to = Math.min(length, high - nodeStart);
|
|
365
|
+
const text = node.text.slice(from, to);
|
|
366
|
+
if (text)
|
|
367
|
+
nodes.push({ ...node, text });
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return { nodes };
|
|
371
|
+
}
|
|
372
|
+
//# sourceMappingURL=surface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface.js","sourceRoot":"","sources":["../src/surface.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural templates. Modes are presets, not separate implementations:
|
|
3
|
+
* a template describes which slots exist and how the surface behaves.
|
|
4
|
+
*/
|
|
5
|
+
import type { SubmitKey } from '@ai-composer/core';
|
|
6
|
+
export type TemplateSlotName = 'root' | 'header' | 'body' | 'attachments' | 'input' | 'suggestions' | 'toolbar' | 'actions' | 'footer' | 'status';
|
|
7
|
+
export interface AIComposerDomTemplate {
|
|
8
|
+
name: string;
|
|
9
|
+
/** Slots rendered by the default mount, in order. */
|
|
10
|
+
slots: TemplateSlotName[];
|
|
11
|
+
/** Multiline editing surface. */
|
|
12
|
+
multiline: boolean;
|
|
13
|
+
/** Default submit key behavior for the mode. */
|
|
14
|
+
submitKey?: SubmitKey;
|
|
15
|
+
/** Toolbar buttons included by the default mount. */
|
|
16
|
+
toolbarButtons?: Array<'undo' | 'redo' | 'submit'>;
|
|
17
|
+
}
|
|
18
|
+
export declare const COMPACT_TEMPLATE: AIComposerDomTemplate;
|
|
19
|
+
export declare const DEFAULT_TEMPLATE: AIComposerDomTemplate;
|
|
20
|
+
export declare const CHAT_TEMPLATE: AIComposerDomTemplate;
|
|
21
|
+
export declare const EXPANDED_TEMPLATE: AIComposerDomTemplate;
|
|
22
|
+
export declare function templateForMode(mode: string): AIComposerDomTemplate;
|
|
23
|
+
/** Register a custom mode preset (used by applications/other packages). */
|
|
24
|
+
export declare function registerTemplate(template: AIComposerDomTemplate): void;
|
|
25
|
+
export declare const SLOT_ATTRIBUTE = "data-aic-slot";
|
|
26
|
+
//# sourceMappingURL=template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,QAAQ,GACR,MAAM,GACN,aAAa,GACb,OAAO,GACP,aAAa,GACb,SAAS,GACT,SAAS,GACT,QAAQ,GACR,QAAQ,CAAC;AAEb,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,iCAAiC;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,qDAAqD;IACrD,cAAc,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC,CAAC;CACpD;AAED,eAAO,MAAM,gBAAgB,EAAE,qBAO9B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,qBAK9B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,qBAM3B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,qBAM/B,CAAC;AASF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,CAEnE;AAED,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAEtE;AAED,eAAO,MAAM,cAAc,kBAAkB,CAAC"}
|
package/dist/template.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural templates. Modes are presets, not separate implementations:
|
|
3
|
+
* a template describes which slots exist and how the surface behaves.
|
|
4
|
+
*/
|
|
5
|
+
export const COMPACT_TEMPLATE = {
|
|
6
|
+
name: 'compact',
|
|
7
|
+
slots: ['body', 'attachments', 'input', 'suggestions', 'toolbar'],
|
|
8
|
+
multiline: true,
|
|
9
|
+
submitKey: 'enter',
|
|
10
|
+
// One line: chips + input + send inside the pill (CSS lays them in a row).
|
|
11
|
+
toolbarButtons: ['submit'],
|
|
12
|
+
};
|
|
13
|
+
export const DEFAULT_TEMPLATE = {
|
|
14
|
+
name: 'default',
|
|
15
|
+
slots: ['body', 'attachments', 'input', 'suggestions'],
|
|
16
|
+
multiline: true,
|
|
17
|
+
submitKey: 'enter',
|
|
18
|
+
};
|
|
19
|
+
export const CHAT_TEMPLATE = {
|
|
20
|
+
name: 'chat',
|
|
21
|
+
slots: ['header', 'body', 'attachments', 'input', 'suggestions', 'toolbar', 'actions'],
|
|
22
|
+
multiline: true,
|
|
23
|
+
submitKey: 'enter',
|
|
24
|
+
toolbarButtons: ['submit'],
|
|
25
|
+
};
|
|
26
|
+
export const EXPANDED_TEMPLATE = {
|
|
27
|
+
name: 'expanded',
|
|
28
|
+
slots: ['header', 'body', 'attachments', 'input', 'suggestions', 'toolbar', 'footer'],
|
|
29
|
+
multiline: true,
|
|
30
|
+
submitKey: 'shift-enter',
|
|
31
|
+
toolbarButtons: ['undo', 'redo', 'submit'],
|
|
32
|
+
};
|
|
33
|
+
const TEMPLATES = {
|
|
34
|
+
compact: COMPACT_TEMPLATE,
|
|
35
|
+
default: DEFAULT_TEMPLATE,
|
|
36
|
+
chat: CHAT_TEMPLATE,
|
|
37
|
+
expanded: EXPANDED_TEMPLATE,
|
|
38
|
+
};
|
|
39
|
+
export function templateForMode(mode) {
|
|
40
|
+
return TEMPLATES[mode] ?? DEFAULT_TEMPLATE;
|
|
41
|
+
}
|
|
42
|
+
/** Register a custom mode preset (used by applications/other packages). */
|
|
43
|
+
export function registerTemplate(template) {
|
|
44
|
+
TEMPLATES[template.name] = template;
|
|
45
|
+
}
|
|
46
|
+
export const SLOT_ATTRIBUTE = 'data-aic-slot';
|
|
47
|
+
//# sourceMappingURL=template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.js","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA4BH,MAAM,CAAC,MAAM,gBAAgB,GAA0B;IACrD,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,CAAC;IACjE,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,OAAO;IAClB,2EAA2E;IAC3E,cAAc,EAAE,CAAC,QAAQ,CAAC;CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAA0B;IACrD,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,CAAC;IACtD,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,OAAO;CACnB,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAA0B;IAClD,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,CAAC;IACtF,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,OAAO;IAClB,cAAc,EAAE,CAAC,QAAQ,CAAC;CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAA0B;IACtD,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,CAAC;IACrF,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,aAAa;IACxB,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;CAC3C,CAAC;AAEF,MAAM,SAAS,GAA0C;IACvD,OAAO,EAAE,gBAAgB;IACzB,OAAO,EAAE,gBAAgB;IACzB,IAAI,EAAE,aAAa;IACnB,QAAQ,EAAE,iBAAiB;CAC5B,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,gBAAgB,CAAC;AAC7C,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,gBAAgB,CAAC,QAA+B;IAC9D,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,eAAe,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-composer/dom",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"@ai-composer/core": "^0.1.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"vitest": "^2.1.8",
|
|
21
|
+
"jsdom": "^25.0.1",
|
|
22
|
+
"@ai-composer/core": "0.1.0"
|
|
23
|
+
}
|
|
6
24
|
}
|
package/project.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dom",
|
|
3
|
+
"$schema": "../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "packages/dom/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"tags": [
|
|
7
|
+
"scope:dom",
|
|
8
|
+
"type:lib"
|
|
9
|
+
],
|
|
10
|
+
"targets": {
|
|
11
|
+
"build": {
|
|
12
|
+
"executor": "@nx/js:tsc",
|
|
13
|
+
"outputs": [
|
|
14
|
+
"{options.outputPath}"
|
|
15
|
+
],
|
|
16
|
+
"options": {
|
|
17
|
+
"outputPath": "packages/dom/dist",
|
|
18
|
+
"main": "packages/dom/src/index.ts",
|
|
19
|
+
"tsConfig": "packages/dom/tsconfig.lib.json",
|
|
20
|
+
"rootDir": "packages/dom/src",
|
|
21
|
+
"assets": [
|
|
22
|
+
{
|
|
23
|
+
"input": "../packages/dom",
|
|
24
|
+
"glob": "*.md",
|
|
25
|
+
"output": "."
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"generateExportsIfAbsent": false
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"test": {
|
|
32
|
+
"executor": "nx:run-commands",
|
|
33
|
+
"options": {
|
|
34
|
+
"command": "vitest run --project dom"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"lint": {
|
|
38
|
+
"executor": "@nx/eslint:lint",
|
|
39
|
+
"outputs": [
|
|
40
|
+
"{options.outputFile}"
|
|
41
|
+
],
|
|
42
|
+
"options": {
|
|
43
|
+
"lintFilePatterns": [
|
|
44
|
+
"packages/dom/**/*.ts",
|
|
45
|
+
"packages/dom/**/*.tsx"
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"typecheck": {
|
|
50
|
+
"executor": "nx:run-commands",
|
|
51
|
+
"options": {
|
|
52
|
+
"command": "tsc -p packages/dom/tsconfig.spec.json --noEmit"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/icons.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline SVG icons for the default mount UI (lucide-derived geometry).
|
|
3
|
+
* Built with createElementNS so no innerHTML parsing is involved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
type IconPaths = Array<Array<[string, Record<string, string | number>]>>;
|
|
7
|
+
|
|
8
|
+
const ICON_PATHS: Record<'send' | 'undo' | 'redo' | 'close', IconPaths> = {
|
|
9
|
+
send: [
|
|
10
|
+
[['M12 19V5', { 'stroke-width': 2.4 }], ['m5 12 7-7 7 7', { 'stroke-width': 2.4 }]],
|
|
11
|
+
],
|
|
12
|
+
undo: [
|
|
13
|
+
[['M3 7v6h6', {}], ['M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13', {}]],
|
|
14
|
+
],
|
|
15
|
+
redo: [
|
|
16
|
+
[['M21 7v6h-6', {}], ['M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3L21 13', {}]],
|
|
17
|
+
],
|
|
18
|
+
close: [[['M18 6 6 18', {}], ['m6 6 12 12', {}]]],
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
22
|
+
|
|
23
|
+
export function createIcon(name: keyof typeof ICON_PATHS, size = 16): SVGSVGElement {
|
|
24
|
+
const svg = document.createElementNS(SVG_NS, 'svg');
|
|
25
|
+
svg.setAttribute('width', String(size));
|
|
26
|
+
svg.setAttribute('height', String(size));
|
|
27
|
+
svg.setAttribute('viewBox', '0 0 24 24');
|
|
28
|
+
svg.setAttribute('fill', 'none');
|
|
29
|
+
svg.setAttribute('stroke', 'currentColor');
|
|
30
|
+
svg.setAttribute('stroke-width', '2');
|
|
31
|
+
svg.setAttribute('stroke-linecap', 'round');
|
|
32
|
+
svg.setAttribute('stroke-linejoin', 'round');
|
|
33
|
+
svg.setAttribute('aria-hidden', 'true');
|
|
34
|
+
for (const [d, attributes] of ICON_PATHS[name].flat()) {
|
|
35
|
+
const path = document.createElementNS(SVG_NS, 'path');
|
|
36
|
+
path.setAttribute('d', d);
|
|
37
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
38
|
+
path.setAttribute(key, String(value));
|
|
39
|
+
}
|
|
40
|
+
svg.appendChild(path);
|
|
41
|
+
}
|
|
42
|
+
return svg;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Loading state for the send button (animated in themes css). */
|
|
46
|
+
export function createSpinner(): HTMLSpanElement {
|
|
47
|
+
const spinner = document.createElement('span');
|
|
48
|
+
spinner.className = 'aic-spinner';
|
|
49
|
+
spinner.setAttribute('aria-hidden', 'true');
|
|
50
|
+
return spinner;
|
|
51
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ai-composer/dom — browser layer over @ai-composer/core.
|
|
3
|
+
*
|
|
4
|
+
* surface contentEditable binding (input pipeline, keyboard, clipboard, IME)
|
|
5
|
+
* render model → DOM projection (chips carry data-aic-* attributes)
|
|
6
|
+
* parse DOM → model with strict sanitization
|
|
7
|
+
* selection DOM selection ↔ model selection mapping
|
|
8
|
+
* suggestions accessible suggestion listbox driven by state
|
|
9
|
+
* template structural mode presets (compact/default/chat/expanded)
|
|
10
|
+
* mount vanilla JS mountAIComposer()
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
createEditableSurface,
|
|
15
|
+
EDITABLE_SURFACE_CLASS,
|
|
16
|
+
type EditableSurface,
|
|
17
|
+
type EditableSurfaceOptions,
|
|
18
|
+
} from './surface';
|
|
19
|
+
|
|
20
|
+
export { renderChip, renderDocument, renderTextRun } from './render';
|
|
21
|
+
export { htmlToPlainText, parseEditableHost, CLIPBOARD_MIME } from './parse';
|
|
22
|
+
export { applyModelSelection, caretToEnd, domSelectionToModel } from './selection';
|
|
23
|
+
export {
|
|
24
|
+
createSuggestionList,
|
|
25
|
+
type SuggestionList,
|
|
26
|
+
type SuggestionListOptions,
|
|
27
|
+
} from './suggestions';
|
|
28
|
+
export {
|
|
29
|
+
attachCaretAnchoredPopup,
|
|
30
|
+
measureCaret,
|
|
31
|
+
type CaretAnchor,
|
|
32
|
+
type CaretAnchorOptions,
|
|
33
|
+
type CaretPoint,
|
|
34
|
+
} from './popup';
|
|
35
|
+
export {
|
|
36
|
+
CHAT_TEMPLATE,
|
|
37
|
+
COMPACT_TEMPLATE,
|
|
38
|
+
DEFAULT_TEMPLATE,
|
|
39
|
+
EXPANDED_TEMPLATE,
|
|
40
|
+
registerTemplate,
|
|
41
|
+
SLOT_ATTRIBUTE,
|
|
42
|
+
templateForMode,
|
|
43
|
+
type AIComposerDomTemplate,
|
|
44
|
+
type TemplateSlotName,
|
|
45
|
+
} from './template';
|
|
46
|
+
export {
|
|
47
|
+
mountAIComposer,
|
|
48
|
+
type MountedEditor,
|
|
49
|
+
type MountOptions,
|
|
50
|
+
} from './mount';
|