@simmalugnt-se/payload-editor-assistant 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +29 -3
  3. package/dist/collections/approvals.js +3 -2
  4. package/dist/collections/audit.js +1 -1
  5. package/dist/components/ChangedFieldsHighlight.d.ts +8 -0
  6. package/dist/components/ChangedFieldsHighlight.js +50 -0
  7. package/dist/components/EditorAssistantAside.js +169 -63
  8. package/dist/components/EditorAssistantDocumentBridge.js +52 -1
  9. package/dist/components/EditorAssistantProvider.js +2 -1
  10. package/dist/components/assistant-context.d.ts +14 -0
  11. package/dist/components/assistant-context.js +4 -0
  12. package/dist/components/copy.d.ts +109 -0
  13. package/dist/components/copy.js +109 -0
  14. package/dist/components/selection-dom.d.ts +16 -0
  15. package/dist/components/selection-dom.js +104 -0
  16. package/dist/domain/propose.d.ts +7 -1
  17. package/dist/domain/propose.js +8 -3
  18. package/dist/endpoints/chat.js +2 -0
  19. package/dist/form/changed-paths.d.ts +6 -0
  20. package/dist/form/changed-paths.js +26 -0
  21. package/dist/form/diff.js +1 -22
  22. package/dist/form/empty.js +1 -19
  23. package/dist/form/lexical.d.ts +8 -0
  24. package/dist/form/lexical.js +24 -0
  25. package/dist/runtime/agent.d.ts +4 -1
  26. package/dist/runtime/agent.js +21 -8
  27. package/dist/runtime/context.d.ts +3 -0
  28. package/dist/runtime/context.js +10 -3
  29. package/dist/runtime/propose-loop.d.ts +9 -0
  30. package/dist/runtime/propose-loop.js +13 -1
  31. package/dist/runtime/selection.d.ts +28 -0
  32. package/dist/runtime/selection.js +87 -0
  33. package/dist/runtime/system-prompt.js +17 -1
  34. package/dist/runtime/tools.d.ts +7 -0
  35. package/dist/runtime/tools.js +2 -1
  36. package/dist/runtime/voice.js +2 -2
  37. package/dist/schema/fields.d.ts +1 -0
  38. package/dist/schema/fields.js +1 -0
  39. package/dist/styles/assistant.css +210 -181
  40. package/package.json +1 -1
@@ -31,7 +31,11 @@ html:has(.ea-root) body {
31
31
  min-height: 100%;
32
32
  }
33
33
 
34
+ /* Payload's own tokens for greys, spacing, radii and type. The accent is visual editing's
35
+ highlight blue, so the selection here and the outline in the preview read as the same thing. */
34
36
  .ea-aside {
37
+ --ea-accent: #2563eb;
38
+ --ea-accent-tint: rgba(37, 99, 235, 0.1);
35
39
  box-sizing: border-box;
36
40
  display: flex;
37
41
  flex-direction: column;
@@ -40,163 +44,88 @@ html:has(.ea-root) body {
40
44
  height: 100%;
41
45
  max-height: 100%;
42
46
  overflow: hidden;
43
- border-inline-start: 1px solid var(--theme-elevation-150);
47
+ border-inline-start: 1px solid var(--theme-elevation-100);
44
48
  background: var(--theme-bg, var(--theme-elevation-0));
45
49
  color: var(--theme-text);
46
- font-size: 13px;
47
- line-height: 1.45;
48
50
  }
49
51
 
50
- .ea-aside__rail {
51
- writing-mode: vertical-rl;
52
- transform: rotate(180deg);
53
- width: 100%;
54
- height: 100%;
55
- border: 0;
56
- background: var(--theme-elevation-50);
57
- color: var(--theme-elevation-800);
58
- cursor: pointer;
59
- letter-spacing: 0.14em;
60
- text-transform: uppercase;
61
- font: inherit;
62
- font-size: 12px;
52
+ html[data-theme="dark"] .ea-aside {
53
+ --ea-accent: #60a5fa;
54
+ --ea-accent-tint: rgba(96, 165, 250, 0.14);
63
55
  }
64
56
 
65
- .ea-aside__rail:hover {
66
- color: var(--theme-text);
67
- background: var(--theme-elevation-100);
57
+ .ea-aside--collapsed {
58
+ border-inline-start-color: var(--theme-elevation-100);
68
59
  }
69
60
 
70
- .ea-btn {
71
- appearance: none;
72
- display: inline-flex;
61
+ .ea-aside__rail {
62
+ display: flex;
63
+ flex-direction: column;
73
64
  align-items: center;
74
- justify-content: center;
75
- margin: 0;
76
- border: 1px solid var(--theme-elevation-150);
77
- background: var(--theme-elevation-50);
78
- color: var(--theme-text);
79
- border-radius: var(--style-radius-s, 3px);
80
- padding: 5px 10px;
65
+ gap: calc(var(--base) * 0.5);
66
+ width: 100%;
67
+ height: 100%;
68
+ padding: calc(var(--base) * 0.8) 0;
69
+ border: 0;
70
+ background: transparent;
71
+ color: var(--theme-elevation-500);
81
72
  font: inherit;
82
- font-size: 12px;
83
- font-weight: 500;
84
- line-height: 1.2;
85
73
  cursor: pointer;
86
74
  }
87
75
 
88
- .ea-btn:hover {
89
- background: var(--theme-elevation-100);
90
- }
91
-
92
- .ea-btn:disabled {
93
- opacity: 0.45;
94
- cursor: not-allowed;
95
- }
96
-
97
- .ea-btn--ghost {
98
- border-color: transparent;
99
- background: transparent;
100
- color: var(--theme-elevation-800);
101
- }
102
-
103
- .ea-btn--ghost:hover {
104
- background: var(--theme-elevation-100);
105
- color: var(--theme-text);
106
- }
107
-
108
- .ea-btn--primary {
109
- border-color: var(--theme-success-500);
110
- background: var(--theme-success-500);
111
- color: var(--theme-success-50, #fff);
112
- }
113
-
114
- .ea-btn--primary:hover {
115
- background: var(--theme-success-600, var(--theme-success-500));
116
- }
117
-
118
- .ea-btn--danger {
119
- border-color: var(--theme-error-500);
120
- background: var(--theme-error-500);
121
- color: #fff;
122
- }
123
-
124
- .ea-btn--danger:hover {
125
- background: var(--theme-error-600, var(--theme-error-500));
126
- }
127
-
128
- .ea-btn--stop {
129
- border-color: var(--theme-elevation-150);
130
- background: transparent;
131
- color: var(--theme-error-500);
132
- }
133
-
134
- .ea-btn--stop:hover {
135
- background: var(--theme-error-50, var(--theme-elevation-100));
136
- }
137
-
138
- .ea-btn--chip {
139
- border-radius: 999px;
140
- background: transparent;
141
- color: var(--theme-elevation-800);
142
- padding: 3px 9px;
76
+ .ea-aside__rail span {
77
+ writing-mode: vertical-rl;
143
78
  }
144
79
 
145
- .ea-btn--chip:hover {
80
+ .ea-aside__rail:hover {
146
81
  color: var(--theme-text);
147
- border-color: var(--theme-elevation-400, var(--theme-elevation-150));
82
+ background: var(--theme-elevation-50);
148
83
  }
149
84
 
150
85
  .ea-aside__head {
151
86
  display: flex;
152
87
  align-items: center;
153
- gap: 4px;
88
+ gap: calc(var(--base) * 0.4);
154
89
  flex-shrink: 0;
155
- padding: 8px 10px 8px 14px;
90
+ min-height: var(--app-header-height, calc(var(--base) * 2.8));
91
+ padding: calc(var(--base) * 0.5) calc(var(--base) * 0.6) calc(var(--base) * 0.5) var(--base);
156
92
  border-bottom: 1px solid var(--theme-elevation-150);
157
93
  }
158
94
 
159
- .ea-aside__head h2 {
95
+ .ea-aside__title {
160
96
  flex: 1;
97
+ min-width: 0;
98
+ }
99
+
100
+ /* Sized like Payload's own small headings on this row (breadcrumbs, field labels), not an h4. */
101
+ .ea-aside__title h2 {
161
102
  margin: 0;
162
- font-size: 11px;
103
+ font-size: 13px;
163
104
  font-weight: 600;
164
- letter-spacing: 0.08em;
165
- text-transform: uppercase;
166
- color: var(--theme-elevation-800);
105
+ letter-spacing: normal;
106
+ line-height: 20px;
167
107
  }
168
108
 
169
- .ea-aside__body {
170
- display: flex;
171
- flex-direction: column;
172
- flex: 1;
173
- min-height: 0;
109
+ .ea-aside__context {
110
+ margin: 0;
174
111
  overflow: hidden;
112
+ color: var(--theme-elevation-500);
113
+ font-size: 12px;
114
+ line-height: 18px;
115
+ text-overflow: ellipsis;
116
+ white-space: nowrap;
175
117
  }
176
118
 
177
- .ea-context {
178
- display: flex;
179
- flex-wrap: wrap;
180
- align-items: center;
119
+ .ea-aside__collapse {
181
120
  flex-shrink: 0;
182
- padding: 8px 14px;
183
- border-bottom: 1px solid var(--theme-elevation-150);
184
- color: var(--theme-elevation-800);
185
- font-size: 11px;
186
121
  }
187
122
 
188
- .ea-context span + span::before {
189
- content: "·";
190
- margin: 0 6px;
191
- color: var(--theme-elevation-400, var(--theme-elevation-150));
192
- }
193
-
194
- .ea-context__warn {
195
- color: var(--theme-warning-600, var(--theme-warning-500));
196
- }
197
-
198
- .ea-context__ok {
199
- color: var(--theme-success-600, var(--theme-success-500));
123
+ .ea-aside__body {
124
+ display: flex;
125
+ flex-direction: column;
126
+ flex: 1;
127
+ min-height: 0;
128
+ overflow: hidden;
200
129
  }
201
130
 
202
131
  .ea-messages {
@@ -204,22 +133,25 @@ html:has(.ea-root) body {
204
133
  min-height: 0;
205
134
  overflow: auto;
206
135
  overscroll-behavior: contain;
207
- padding: 14px;
136
+ padding: var(--base);
208
137
  display: flex;
209
138
  flex-direction: column;
210
- gap: 10px;
139
+ gap: calc(var(--base) * 0.8);
211
140
  }
212
141
 
142
+ /* The assistant writes plain text, the editor's messages sit in a quiet bubble. */
213
143
  .ea-msg {
214
- max-width: 92%;
215
- padding: 9px 11px;
216
- border-radius: 8px;
217
- border: 1px solid var(--theme-elevation-150);
218
- background: var(--theme-elevation-50);
144
+ max-width: 100%;
145
+ line-height: 1.5;
146
+ white-space: pre-wrap;
147
+ overflow-wrap: anywhere;
219
148
  }
220
149
 
221
150
  .ea-msg--user {
222
151
  align-self: flex-end;
152
+ max-width: 85%;
153
+ padding: calc(var(--base) * 0.4) calc(var(--base) * 0.6);
154
+ border-radius: var(--style-radius-m);
223
155
  background: var(--theme-elevation-100);
224
156
  }
225
157
 
@@ -228,40 +160,97 @@ html:has(.ea-root) body {
228
160
  }
229
161
 
230
162
  .ea-msg--system {
231
- align-self: stretch;
232
- max-width: none;
233
- background: transparent;
234
- border: 0;
235
- color: var(--theme-elevation-800);
163
+ color: var(--theme-elevation-500);
236
164
  font-size: 12px;
237
- padding: 2px 0;
165
+ }
166
+
167
+ .ea-msg--working {
168
+ display: flex;
169
+ align-items: center;
170
+ gap: calc(var(--base) * 0.4);
171
+ color: var(--theme-elevation-500);
172
+ }
173
+
174
+ .ea-dots {
175
+ display: inline-flex;
176
+ gap: 3px;
177
+ }
178
+
179
+ .ea-dots span {
180
+ width: 5px;
181
+ height: 5px;
182
+ border-radius: 50%;
183
+ background: var(--ea-accent);
184
+ animation: ea-dot 1.2s infinite ease-in-out;
185
+ }
186
+
187
+ .ea-dots span:nth-child(2) {
188
+ animation-delay: 0.15s;
189
+ }
190
+
191
+ .ea-dots span:nth-child(3) {
192
+ animation-delay: 0.3s;
193
+ }
194
+
195
+ @keyframes ea-dot {
196
+ 0%,
197
+ 80%,
198
+ 100% {
199
+ opacity: 0.25;
200
+ }
201
+ 40% {
202
+ opacity: 1;
203
+ }
204
+ }
205
+
206
+ @media (prefers-reduced-motion: reduce) {
207
+ .ea-dots span {
208
+ animation: none;
209
+ opacity: 0.6;
210
+ }
211
+ }
212
+
213
+ .ea-actions {
214
+ display: flex;
215
+ gap: calc(var(--base) * 0.4);
216
+ flex-wrap: wrap;
217
+ margin-top: calc(var(--base) * 0.4);
238
218
  }
239
219
 
240
220
  .ea-approval {
241
221
  flex-shrink: 0;
242
- padding: 12px 14px;
243
- border-top: 1px solid var(--theme-warning-300, var(--theme-elevation-150));
244
- background: var(--theme-warning-50, var(--theme-elevation-50));
222
+ margin: 0 var(--base) calc(var(--base) * 0.6);
223
+ padding: calc(var(--base) * 0.6) calc(var(--base) * 0.8);
224
+ border: 1px solid var(--theme-elevation-150);
225
+ border-inline-start: 3px solid var(--ea-accent);
226
+ border-radius: var(--style-radius-m);
227
+ background: var(--theme-elevation-50);
245
228
  }
246
229
 
247
230
  .ea-approval h3 {
248
- margin: 0 0 8px;
231
+ margin: 0 0 calc(var(--base) * 0.4);
249
232
  font-size: 13px;
250
- }
251
-
252
- .ea-msg--working {
253
- display: flex;
254
- align-items: center;
255
- gap: 8px;
256
- color: var(--theme-elevation-800);
233
+ font-weight: 600;
234
+ line-height: 1.4;
257
235
  }
258
236
 
259
237
  .ea-approval__diff {
260
238
  max-height: 40vh;
261
239
  overflow-y: auto;
262
- margin: 0 0 10px;
240
+ margin: 0 0 calc(var(--base) * 0.2);
263
241
  padding-left: 1.1em;
264
- font-size: 13px;
242
+ line-height: 1.5;
243
+ }
244
+
245
+ .ea-approval__hint {
246
+ margin: 0 0 calc(var(--base) * 0.4);
247
+ color: var(--theme-elevation-500);
248
+ font-size: 12px;
249
+ }
250
+
251
+ .ea-approval__warn {
252
+ margin: calc(var(--base) * 0.4) 0 0;
253
+ color: var(--theme-warning-700, var(--theme-text));
265
254
  }
266
255
 
267
256
  .ea-approval__sub {
@@ -269,71 +258,117 @@ html:has(.ea-root) body {
269
258
  margin-left: 0.4em;
270
259
  padding-left: 0.6em;
271
260
  border-left: 2px solid var(--theme-elevation-150);
272
- color: var(--theme-elevation-800);
273
- }
274
-
275
- .ea-approval pre {
276
- margin: 0 0 10px;
277
- white-space: pre-wrap;
278
- font-size: 12px;
279
- font-family: var(--font-mono, ui-monospace, monospace);
280
- }
281
-
282
- .ea-actions {
283
- display: flex;
284
- gap: 8px;
285
- flex-wrap: wrap;
286
- margin-top: 8px;
261
+ color: var(--theme-elevation-600);
287
262
  }
288
263
 
289
264
  .ea-status {
290
265
  flex-shrink: 0;
291
- padding: 8px 14px;
266
+ padding: 0 var(--base) calc(var(--base) * 0.4);
292
267
  color: var(--theme-error-500);
293
268
  font-size: 12px;
294
269
  }
295
270
 
296
271
  .ea-composer {
297
272
  flex-shrink: 0;
298
- padding: 10px 14px 12px;
273
+ padding: calc(var(--base) * 0.6) var(--base) var(--base);
299
274
  border-top: 1px solid var(--theme-elevation-150);
300
- background: var(--theme-elevation-50);
301
275
  }
302
276
 
303
277
  .ea-shortcuts {
304
278
  display: flex;
305
279
  flex-wrap: wrap;
306
- gap: 6px;
307
- margin-bottom: 8px;
280
+ gap: calc(var(--base) * 0.3);
281
+ margin-bottom: calc(var(--base) * 0.4);
282
+ }
283
+
284
+ .ea-selection {
285
+ display: flex;
286
+ align-items: center;
287
+ gap: calc(var(--base) * 0.2);
288
+ margin-bottom: calc(var(--base) * 0.4);
289
+ padding: 3px 3px 3px calc(var(--base) * 0.5);
290
+ border-inline-start: 3px solid var(--ea-accent);
291
+ border-radius: var(--style-radius-s);
292
+ background: var(--ea-accent-tint);
293
+ color: var(--theme-elevation-600);
294
+ font-size: 12px;
295
+ }
296
+
297
+ .ea-selection__label {
298
+ flex: 1;
299
+ min-width: 0;
300
+ overflow: hidden;
301
+ text-overflow: ellipsis;
302
+ white-space: nowrap;
303
+ }
304
+
305
+ .ea-selection__label strong {
306
+ color: var(--ea-accent);
307
+ font-weight: 600;
308
+ }
309
+
310
+ .ea-selection__clear {
311
+ display: flex;
312
+ flex-shrink: 0;
313
+ padding: 0;
314
+ border: 0;
315
+ border-radius: var(--style-radius-s);
316
+ background: transparent;
317
+ color: var(--theme-elevation-500);
318
+ cursor: pointer;
319
+ }
320
+
321
+ .ea-selection__clear:hover {
322
+ background: var(--ea-accent-tint);
323
+ color: var(--ea-accent);
308
324
  }
309
325
 
326
+ .ea-selection__clear svg {
327
+ width: 20px;
328
+ height: 20px;
329
+ }
330
+
331
+ /* Payload's text input: same border, radius, background and focus as fields in the form. */
310
332
  .ea-composer__box {
311
333
  display: flex;
312
334
  flex-direction: column;
313
- gap: 6px;
335
+ gap: calc(var(--base) * 0.3);
336
+ padding: calc(var(--base) * 0.4) calc(var(--base) * 0.5) calc(var(--base) * 0.4)
337
+ calc(var(--base) * 0.75);
314
338
  border: 1px solid var(--theme-elevation-150);
315
- border-radius: var(--style-radius-m, 4px);
339
+ border-radius: var(--style-radius-s);
316
340
  background: var(--theme-input-bg, var(--theme-elevation-0));
317
- padding: 8px 10px;
341
+ box-shadow: 0 2px 2px -1px #0000001a;
342
+ transition: border 100ms cubic-bezier(0, 0.2, 0.2, 1);
343
+ }
344
+
345
+ .ea-composer__box:hover {
346
+ border-color: var(--theme-elevation-250);
318
347
  }
319
348
 
320
349
  .ea-composer__box:focus-within {
321
- border-color: var(--theme-elevation-400, var(--theme-elevation-150));
350
+ border-color: var(--ea-accent);
351
+ box-shadow: 0 0 0 3px var(--ea-accent-tint);
322
352
  }
323
353
 
324
354
  .ea-composer textarea {
325
355
  width: 100%;
326
356
  box-sizing: border-box;
327
- resize: none;
357
+ min-height: 40px;
358
+ padding: 0;
328
359
  border: 0;
329
360
  background: transparent;
330
361
  color: var(--theme-text);
331
- padding: 0;
332
362
  font: inherit;
333
- min-height: 40px;
363
+ line-height: 1.5;
364
+ resize: none;
334
365
  outline: none;
335
366
  }
336
367
 
368
+ .ea-composer textarea::placeholder {
369
+ color: var(--theme-elevation-400);
370
+ }
371
+
337
372
  .ea-composer textarea:focus,
338
373
  .ea-composer textarea:focus-visible {
339
374
  outline: none;
@@ -348,13 +383,7 @@ html:has(.ea-root) body {
348
383
  display: flex;
349
384
  align-items: center;
350
385
  justify-content: flex-end;
351
- gap: 8px;
352
- }
353
-
354
- .ea-composer__status {
355
- margin-right: auto;
356
- color: var(--theme-elevation-800);
357
- font-size: 12px;
386
+ gap: calc(var(--base) * 0.4);
358
387
  }
359
388
 
360
389
  .ea-trigger {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simmalugnt-se/payload-editor-assistant",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Context-aware editor assistant plugin for Payload Admin",
5
5
  "keywords": [
6
6
  "payload",