camox 0.65.1 → 0.67.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 (42) hide show
  1. package/dist/features/canvas/CamoxCanvas.js +195 -173
  2. package/dist/features/canvas/canvasFrameCapture.js +5 -12
  3. package/dist/features/canvas/canvasFrameDocument.js +90 -29
  4. package/dist/features/canvas/canvasItems.js +22 -6
  5. package/dist/features/canvas/sidebar/ContentSidebar.js +19 -21
  6. package/dist/features/canvas/sidebar/LayoutPageOverview.js +22 -49
  7. package/dist/features/canvas/sidebar/LayoutPageSeo.js +73 -76
  8. package/dist/features/canvas/sidebar/PageInspector.js +61 -50
  9. package/dist/features/canvas/sidebar/PageInspectorSkeleton.js +4 -4
  10. package/dist/features/canvas/useCanvasCamera.js +22 -5
  11. package/dist/features/content/components/MissingFromLocale.js +1 -1
  12. package/dist/features/page/UnplacedLayoutContent.js +141 -0
  13. package/dist/features/preview/components/ItemFieldsEditor.js +50 -44
  14. package/dist/features/preview/components/PageInfo.js +103 -100
  15. package/dist/features/preview/components/SelectionEditor.js +284 -231
  16. package/dist/features/preview/components/contentFieldSchema.js +5 -1
  17. package/dist/features/runtime/RuntimeChrome.js +66 -40
  18. package/dist/features/runtime/pageApp.js +24 -10
  19. package/dist/features/runtime/runtime.d.ts +13 -0
  20. package/dist/features/runtime/runtime.js +58 -2
  21. package/dist/features/studio/components/AgentSidebar.js +3 -3
  22. package/dist/features/studio/components/ChatWidget.js +34 -29
  23. package/dist/features/studio/components/ContentFindings.js +397 -0
  24. package/dist/features/studio/components/DraftsControl.js +172 -159
  25. package/dist/features/studio/components/Patrol.js +449 -426
  26. package/dist/features/studio/components/ReviewDraftSheet.js +231 -192
  27. package/dist/features/studio/components/Squareling.js +0 -9
  28. package/dist/features/studio/components/ThreadComposer.js +183 -121
  29. package/dist/features/studio/components/ThreadMessages.js +19 -11
  30. package/dist/features/studio/components/UnnamedDraftBar.js +349 -0
  31. package/dist/features/studio/findingSentence.js +3 -5
  32. package/dist/features/studio/patrollerBio.js +39 -0
  33. package/dist/features/studio/reportSentence.js +0 -5
  34. package/dist/features/studio/studioStore.js +13 -0
  35. package/dist/features/studio/workingSentence.js +2 -11
  36. package/dist/lib/revisions.js +25 -3
  37. package/dist/lib/use-thread.js +1 -1
  38. package/dist/package.js +1 -1
  39. package/dist/studio.css +1 -1
  40. package/package.json +4 -4
  41. package/dist/features/canvas/sidebar/DerivedPageInspector.js +0 -49
  42. package/dist/features/canvas/sidebar/SingletonPageInspector.js +0 -39
@@ -1,5 +1,5 @@
1
1
  import { c } from "react/compiler-runtime";
2
- import { useEffect, useRef, useState } from "react";
2
+ import { useEffect, useLayoutEffect, useRef, useState } from "react";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { ArrowUp, Square, SquareDashedMousePointer, X } from "lucide-react";
5
5
  import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupTextarea } from "@camox/ui/input-group";
@@ -9,68 +9,116 @@ import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupTextarea } fro
9
9
  * Where an editor writes to the agent: Enter sends, Shift+Enter adds a line. While a run is
10
10
  * going, sending steers it, and a Stop button sits beside Send. Over the message, what the
11
11
  * editor has selected, which their messages carry to the agent until they clear it. A message
12
- * filled in from elsewhere in the studio replaces what the editor wrote, for them to send.
12
+ * filled in from elsewhere in the studio replaces what the editor wrote, for them to send. Given a
13
+ * `carry`, the composer of the next thread goes on from this one, as when the studio enters the
14
+ * draft the editor's request was handed off to: with what they were writing, focused if it was.
13
15
  */
14
16
  function ThreadComposer(t0) {
15
- const $ = c(39);
16
- const { onSend, onStop, selection, onClearSelection, running: t1, disabled: t2, filled } = t0;
17
+ const $ = c(48);
18
+ const { onSend, onStop, selection, onClearSelection, running: t1, disabled: t2, filled, carry } = t0;
17
19
  const running = t1 === void 0 ? false : t1;
18
20
  const disabled = t2 === void 0 ? false : t2;
19
- const [text, setText] = useState("");
21
+ let t3;
22
+ if ($[0] !== carry) {
23
+ t3 = () => carry?.held()?.text ?? "";
24
+ $[0] = carry;
25
+ $[1] = t3;
26
+ } else t3 = $[1];
27
+ const [text, setText] = useState(t3);
20
28
  const [filledId, setFilledId] = useState();
21
29
  if (filled && filled.id !== filledId) {
22
30
  setFilledId(filled.id);
23
31
  setText(filled.text);
24
32
  }
25
33
  const box = useRef(null);
26
- let t3;
27
34
  let t4;
28
- if ($[0] !== filledId) {
29
- t3 = () => {
30
- if (filledId !== void 0) box.current?.focus();
35
+ let t5;
36
+ if ($[2] !== carry || $[3] !== text) {
37
+ t4 = () => {
38
+ carry?.hold({
39
+ text,
40
+ focused: carry.held()?.focused ?? false
41
+ });
31
42
  };
32
- t4 = [filledId];
33
- $[0] = filledId;
34
- $[1] = t3;
35
- $[2] = t4;
43
+ t5 = [carry, text];
44
+ $[2] = carry;
45
+ $[3] = text;
46
+ $[4] = t4;
47
+ $[5] = t5;
36
48
  } else {
37
- t3 = $[1];
38
- t4 = $[2];
49
+ t4 = $[4];
50
+ t5 = $[5];
39
51
  }
40
- useEffect(t3, t4);
41
- let t5;
42
- if ($[3] !== text) {
43
- t5 = text.trim();
44
- $[3] = text;
45
- $[4] = t5;
46
- } else t5 = $[4];
47
- const message = t5;
48
- const canSend = !disabled && message !== "" && onSend !== void 0;
52
+ useEffect(t4, t5);
49
53
  let t6;
50
- if ($[5] !== canSend || $[6] !== message || $[7] !== onSend) {
54
+ let t7;
55
+ if ($[6] !== carry) {
51
56
  t6 = () => {
57
+ const element = box.current;
58
+ if (!carry || !element) return;
59
+ if (carry.held()?.focused) element.focus();
60
+ return () => carry.hold({
61
+ text: element.value,
62
+ focused: element.ownerDocument.activeElement === element
63
+ });
64
+ };
65
+ t7 = [carry];
66
+ $[6] = carry;
67
+ $[7] = t6;
68
+ $[8] = t7;
69
+ } else {
70
+ t6 = $[7];
71
+ t7 = $[8];
72
+ }
73
+ useLayoutEffect(t6, t7);
74
+ let t8;
75
+ let t9;
76
+ if ($[9] !== filledId) {
77
+ t8 = () => {
78
+ if (filledId !== void 0) box.current?.focus();
79
+ };
80
+ t9 = [filledId];
81
+ $[9] = filledId;
82
+ $[10] = t8;
83
+ $[11] = t9;
84
+ } else {
85
+ t8 = $[10];
86
+ t9 = $[11];
87
+ }
88
+ useEffect(t8, t9);
89
+ let t10;
90
+ if ($[12] !== text) {
91
+ t10 = text.trim();
92
+ $[12] = text;
93
+ $[13] = t10;
94
+ } else t10 = $[13];
95
+ const message = t10;
96
+ const canSend = !disabled && message !== "" && onSend !== void 0;
97
+ let t11;
98
+ if ($[14] !== canSend || $[15] !== message || $[16] !== onSend) {
99
+ t11 = () => {
52
100
  if (!canSend) return;
53
101
  onSend(message);
54
102
  setText("");
55
103
  };
56
- $[5] = canSend;
57
- $[6] = message;
58
- $[7] = onSend;
59
- $[8] = t6;
60
- } else t6 = $[8];
61
- const submit = t6;
62
- let t7;
63
- if ($[9] !== submit) {
64
- t7 = (event) => {
104
+ $[14] = canSend;
105
+ $[15] = message;
106
+ $[16] = onSend;
107
+ $[17] = t11;
108
+ } else t11 = $[17];
109
+ const submit = t11;
110
+ let t12;
111
+ if ($[18] !== submit) {
112
+ t12 = (event) => {
65
113
  event.preventDefault();
66
114
  submit();
67
115
  };
68
- $[9] = submit;
69
- $[10] = t7;
70
- } else t7 = $[10];
71
- let t8;
72
- if ($[11] !== onClearSelection || $[12] !== selection) {
73
- t8 = selection && /* @__PURE__ */ jsx(InputGroupAddon, {
116
+ $[18] = submit;
117
+ $[19] = t12;
118
+ } else t12 = $[19];
119
+ let t13;
120
+ if ($[20] !== onClearSelection || $[21] !== selection) {
121
+ t13 = selection && /* @__PURE__ */ jsx(InputGroupAddon, {
74
122
  align: "block-start",
75
123
  className: "border-input border-b",
76
124
  children: /* @__PURE__ */ jsx(SelectionChip, {
@@ -78,45 +126,45 @@ function ThreadComposer(t0) {
78
126
  onClear: onClearSelection
79
127
  })
80
128
  });
81
- $[11] = onClearSelection;
82
- $[12] = selection;
83
- $[13] = t8;
84
- } else t8 = $[13];
85
- let t9;
86
- if ($[14] === Symbol.for("react.memo_cache_sentinel")) {
87
- t9 = (event_0) => setText(event_0.target.value);
88
- $[14] = t9;
89
- } else t9 = $[14];
90
- let t10;
91
- if ($[15] !== submit) {
92
- t10 = (event_1) => {
129
+ $[20] = onClearSelection;
130
+ $[21] = selection;
131
+ $[22] = t13;
132
+ } else t13 = $[22];
133
+ let t14;
134
+ if ($[23] === Symbol.for("react.memo_cache_sentinel")) {
135
+ t14 = (event_0) => setText(event_0.target.value);
136
+ $[23] = t14;
137
+ } else t14 = $[23];
138
+ let t15;
139
+ if ($[24] !== submit) {
140
+ t15 = (event_1) => {
93
141
  if (event_1.key !== "Enter" || event_1.shiftKey || event_1.nativeEvent.isComposing) return;
94
142
  event_1.preventDefault();
95
143
  submit();
96
144
  };
97
- $[15] = submit;
98
- $[16] = t10;
99
- } else t10 = $[16];
100
- let t11;
101
- if ($[17] !== disabled || $[18] !== t10 || $[19] !== text) {
102
- t11 = /* @__PURE__ */ jsx(InputGroupTextarea, {
145
+ $[24] = submit;
146
+ $[25] = t15;
147
+ } else t15 = $[25];
148
+ let t16;
149
+ if ($[26] !== disabled || $[27] !== t15 || $[28] !== text) {
150
+ t16 = /* @__PURE__ */ jsx(InputGroupTextarea, {
103
151
  ref: box,
104
152
  "aria-label": "Message",
105
153
  placeholder: "Message Camox…",
106
154
  value: text,
107
155
  disabled,
108
- onChange: t9,
109
- onKeyDown: t10,
156
+ onChange: t14,
157
+ onKeyDown: t15,
110
158
  className: "max-h-48 min-h-14"
111
159
  });
112
- $[17] = disabled;
113
- $[18] = t10;
114
- $[19] = text;
115
- $[20] = t11;
116
- } else t11 = $[20];
117
- let t12;
118
- if ($[21] !== disabled || $[22] !== onStop || $[23] !== running) {
119
- t12 = running && onStop && /* @__PURE__ */ jsxs(InputGroupButton, {
160
+ $[26] = disabled;
161
+ $[27] = t15;
162
+ $[28] = text;
163
+ $[29] = t16;
164
+ } else t16 = $[29];
165
+ let t17;
166
+ if ($[30] !== disabled || $[31] !== onStop || $[32] !== running) {
167
+ t17 = running && onStop && /* @__PURE__ */ jsxs(InputGroupButton, {
120
168
  type: "button",
121
169
  variant: "outline",
122
170
  size: "icon-sm",
@@ -127,73 +175,87 @@ function ThreadComposer(t0) {
127
175
  children: "Stop"
128
176
  })]
129
177
  });
130
- $[21] = disabled;
131
- $[22] = onStop;
132
- $[23] = running;
133
- $[24] = t12;
134
- } else t12 = $[24];
135
- const t13 = !canSend;
136
- let t14;
137
- let t15;
138
- if ($[25] === Symbol.for("react.memo_cache_sentinel")) {
139
- t14 = /* @__PURE__ */ jsx(ArrowUp, {});
140
- t15 = /* @__PURE__ */ jsx("span", {
178
+ $[30] = disabled;
179
+ $[31] = onStop;
180
+ $[32] = running;
181
+ $[33] = t17;
182
+ } else t17 = $[33];
183
+ const t18 = !canSend;
184
+ let t19;
185
+ let t20;
186
+ if ($[34] === Symbol.for("react.memo_cache_sentinel")) {
187
+ t19 = /* @__PURE__ */ jsx(ArrowUp, {});
188
+ t20 = /* @__PURE__ */ jsx("span", {
141
189
  className: "sr-only",
142
190
  children: "Send"
143
191
  });
144
- $[25] = t14;
145
- $[26] = t15;
192
+ $[34] = t19;
193
+ $[35] = t20;
146
194
  } else {
147
- t14 = $[25];
148
- t15 = $[26];
195
+ t19 = $[34];
196
+ t20 = $[35];
149
197
  }
150
- let t16;
151
- if ($[27] !== t13) {
152
- t16 = /* @__PURE__ */ jsxs(InputGroupButton, {
198
+ let t21;
199
+ if ($[36] !== t18) {
200
+ t21 = /* @__PURE__ */ jsxs(InputGroupButton, {
153
201
  type: "submit",
154
202
  variant: "default",
155
203
  size: "icon-sm",
156
- disabled: t13,
157
- children: [t14, t15]
204
+ disabled: t18,
205
+ children: [t19, t20]
158
206
  });
159
- $[27] = t13;
160
- $[28] = t16;
161
- } else t16 = $[28];
162
- let t17;
163
- if ($[29] !== t12 || $[30] !== t16) {
164
- t17 = /* @__PURE__ */ jsxs(InputGroupAddon, {
207
+ $[36] = t18;
208
+ $[37] = t21;
209
+ } else t21 = $[37];
210
+ let t22;
211
+ if ($[38] !== t17 || $[39] !== t21) {
212
+ t22 = /* @__PURE__ */ jsxs(InputGroupAddon, {
165
213
  align: "block-end",
166
214
  className: "justify-end",
167
- children: [t12, t16]
215
+ children: [t17, t21]
168
216
  });
169
- $[29] = t12;
170
- $[30] = t16;
171
- $[31] = t17;
172
- } else t17 = $[31];
173
- let t18;
174
- if ($[32] !== t11 || $[33] !== t17 || $[34] !== t8) {
175
- t18 = /* @__PURE__ */ jsxs(InputGroup, { children: [
176
- t8,
177
- t11,
178
- t17
217
+ $[38] = t17;
218
+ $[39] = t21;
219
+ $[40] = t22;
220
+ } else t22 = $[40];
221
+ let t23;
222
+ if ($[41] !== t13 || $[42] !== t16 || $[43] !== t22) {
223
+ t23 = /* @__PURE__ */ jsxs(InputGroup, { children: [
224
+ t13,
225
+ t16,
226
+ t22
179
227
  ] });
180
- $[32] = t11;
181
- $[33] = t17;
182
- $[34] = t8;
183
- $[35] = t18;
184
- } else t18 = $[35];
185
- let t19;
186
- if ($[36] !== t18 || $[37] !== t7) {
187
- t19 = /* @__PURE__ */ jsx("form", {
228
+ $[41] = t13;
229
+ $[42] = t16;
230
+ $[43] = t22;
231
+ $[44] = t23;
232
+ } else t23 = $[44];
233
+ let t24;
234
+ if ($[45] !== t12 || $[46] !== t23) {
235
+ t24 = /* @__PURE__ */ jsx("form", {
188
236
  className: "p-2",
189
- onSubmit: t7,
190
- children: t18
237
+ onSubmit: t12,
238
+ children: t23
191
239
  });
192
- $[36] = t18;
193
- $[37] = t7;
194
- $[38] = t19;
195
- } else t19 = $[38];
196
- return t19;
240
+ $[45] = t12;
241
+ $[46] = t23;
242
+ $[47] = t24;
243
+ } else t24 = $[47];
244
+ return t24;
245
+ }
246
+ /** A carrier that lasts as long as the component that keeps it. */
247
+ function useComposerCarrier() {
248
+ const [carrier] = useState(_temp);
249
+ return carrier;
250
+ }
251
+ function _temp() {
252
+ let held = null;
253
+ return {
254
+ held: () => held,
255
+ hold: (carry) => {
256
+ held = carry;
257
+ }
258
+ };
197
259
  }
198
260
  /** The selection the editor's messages carry, by its name. */
199
261
  function SelectionChip(t0) {
@@ -247,4 +309,4 @@ function SelectionChip(t0) {
247
309
  }
248
310
 
249
311
  //#endregion
250
- export { ThreadComposer };
312
+ export { ThreadComposer, useComposerCarrier };
@@ -18,7 +18,7 @@ import { MessageScroller, MessageScrollerButton, MessageScrollerContent, Message
18
18
  * agent does, never how: thinking, looking around, making changes, building, fixing the build,
19
19
  * or starting a draft. Each editor's message shows its
20
20
  * sender's avatar, without their name. A Live turn handed off to a draft ends on the draft's
21
- * card, which `onOpenDraft` opens.
21
+ * card, which `onOpenDraft` opens. The thread keeps its end in view, unless the editor scrolls up.
22
22
  */
23
23
  function ThreadMessages(t0) {
24
24
  const $ = c(20);
@@ -105,10 +105,13 @@ function ThreadMessages(t0) {
105
105
  } else t5 = $[17];
106
106
  let t6;
107
107
  if ($[18] !== t4) {
108
- t6 = /* @__PURE__ */ jsx(MessageScrollerProvider, { children: /* @__PURE__ */ jsxs(MessageScroller, {
109
- className: "min-h-0 flex-1",
110
- children: [t4, t5]
111
- }) });
108
+ t6 = /* @__PURE__ */ jsx(MessageScrollerProvider, {
109
+ autoScroll: true,
110
+ children: /* @__PURE__ */ jsxs(MessageScroller, {
111
+ className: "min-h-0 flex-1",
112
+ children: [t4, t5]
113
+ })
114
+ });
112
115
  $[18] = t4;
113
116
  $[19] = t6;
114
117
  } else t6 = $[19];
@@ -492,8 +495,8 @@ function _temp(subject, index) {
492
495
  }, index);
493
496
  }
494
497
  /**
495
- * A message's text, cropped past its fourth line: the next ones fade out, above a button that
496
- * shows it all. A message that fits shows as is.
498
+ * A message's text, cropped past five lines and a half, fading out gently from its second line,
499
+ * above a button that shows it all. A message that fits shows as is.
497
500
  */
498
501
  function CroppedText(t0) {
499
502
  const $ = c(17);
@@ -508,9 +511,14 @@ function CroppedText(t0) {
508
511
  if (!element || expanded) return;
509
512
  const measure = () => setOverflows(element.scrollHeight > element.clientHeight + 1);
510
513
  measure();
511
- const observer = new ResizeObserver(measure);
512
- observer.observe(element);
513
- return () => observer.disconnect();
514
+ const resizes = new ResizeObserver(measure);
515
+ resizes.observe(element);
516
+ const views = new IntersectionObserver(measure);
517
+ views.observe(element);
518
+ return () => {
519
+ resizes.disconnect();
520
+ views.disconnect();
521
+ };
514
522
  };
515
523
  $[0] = expanded;
516
524
  $[1] = t1;
@@ -526,7 +534,7 @@ function CroppedText(t0) {
526
534
  const cropped = !expanded && overflows;
527
535
  const t3 = cropped || void 0;
528
536
  const t4 = !expanded && "max-h-[5.5lh] overflow-hidden";
529
- const t5 = cropped && "mask-[linear-gradient(to_bottom,black_4lh,transparent)]";
537
+ const t5 = cropped && "mask-[linear-gradient(to_bottom,black_1.5lh,transparent)]";
530
538
  let t6;
531
539
  if ($[5] !== t4 || $[6] !== t5) {
532
540
  t6 = cn("whitespace-pre-wrap", t4, t5);