@opengeni/react 3.8.0-canary.0 → 3.8.0-canary.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +6 -0
  2. package/dist/chat.js +1 -1
  3. package/dist/chunk-5M6VTFJ5.js +171 -0
  4. package/dist/chunk-5M6VTFJ5.js.map +1 -0
  5. package/dist/{chunk-IOLVN74D.js → chunk-6J56T3MG.js} +15 -1
  6. package/dist/chunk-6J56T3MG.js.map +1 -0
  7. package/dist/{chunk-BQGIXRKV.js → chunk-7BWFU6H4.js} +22 -4
  8. package/dist/chunk-7BWFU6H4.js.map +1 -0
  9. package/dist/{chunk-3HIF5IFC.js → chunk-7W6PVVTK.js} +63 -18
  10. package/dist/chunk-7W6PVVTK.js.map +1 -0
  11. package/dist/{chunk-ZFOFY5ST.js → chunk-NLTS7JHI.js} +16 -31
  12. package/dist/chunk-NLTS7JHI.js.map +1 -0
  13. package/dist/chunk-NOSYBS2D.js +208 -0
  14. package/dist/chunk-NOSYBS2D.js.map +1 -0
  15. package/dist/{chunk-F2CFHN3Y.js → chunk-YAIPFO5D.js} +2 -1
  16. package/dist/chunk-YAIPFO5D.js.map +1 -0
  17. package/dist/chunk-YBM6CQRU.js +292 -0
  18. package/dist/chunk-YBM6CQRU.js.map +1 -0
  19. package/dist/chunk-ZYRGEKWS.js +216 -0
  20. package/dist/chunk-ZYRGEKWS.js.map +1 -0
  21. package/dist/components/composer.d.ts +4 -2
  22. package/dist/components/message-timeline.d.ts +9 -2
  23. package/dist/components/timeline-annotation-chrome.d.ts +25 -0
  24. package/dist/components/timeline-annotation-layout.d.ts +42 -0
  25. package/dist/components/timeline-annotation-markers.d.ts +8 -0
  26. package/dist/components/timeline-annotation-reveal-context.d.ts +4 -0
  27. package/dist/components/timeline-annotation-shared.d.ts +31 -0
  28. package/dist/components/timeline-annotations-dialog.d.ts +1 -1
  29. package/dist/components/timeline-annotations.d.ts +8 -2
  30. package/dist/composer.js +2 -2
  31. package/dist/hooks/use-composer.d.ts +2 -0
  32. package/dist/index.js +9 -6
  33. package/dist/index.js.map +1 -1
  34. package/dist/interaction.js +6 -6
  35. package/dist/machines.js +1 -1
  36. package/dist/{queue-surface-implementation-XL2A6PBM.js → queue-surface-implementation-LK3S4BIW.js} +5 -2
  37. package/dist/{queue-surface-implementation-XL2A6PBM.js.map → queue-surface-implementation-LK3S4BIW.js.map} +1 -1
  38. package/dist/session-ui.js +8 -5
  39. package/dist/session.js +1 -1
  40. package/dist/timeline-annotation-markers-DRSTLEM6.js +165 -0
  41. package/dist/timeline-annotation-markers-DRSTLEM6.js.map +1 -0
  42. package/dist/timeline-annotation-selection-IHLUGVND.js +236 -0
  43. package/dist/timeline-annotation-selection-IHLUGVND.js.map +1 -0
  44. package/dist/timeline-annotations-dialog-6Q53N5FG.js +262 -0
  45. package/dist/timeline-annotations-dialog-6Q53N5FG.js.map +1 -0
  46. package/package.json +2 -2
  47. package/src/components/chat-composer.tsx +5 -2
  48. package/src/components/composer.tsx +40 -5
  49. package/src/components/copy-button.tsx +1 -0
  50. package/src/components/machines-dashboard.tsx +1 -16
  51. package/src/components/message-timeline.tsx +357 -297
  52. package/src/components/timeline-annotation-chrome.tsx +183 -0
  53. package/src/components/timeline-annotation-layout.ts +268 -0
  54. package/src/components/timeline-annotation-markers.tsx +185 -0
  55. package/src/components/timeline-annotation-reveal-context.ts +9 -0
  56. package/src/components/timeline-annotation-selection.tsx +99 -54
  57. package/src/components/timeline-annotation-shared.ts +245 -0
  58. package/src/components/timeline-annotations-dialog.tsx +172 -128
  59. package/src/components/timeline-annotations.tsx +178 -45
  60. package/src/hooks/use-composer.ts +17 -0
  61. package/styles/compiled.css +86 -22
  62. package/dist/chunk-3HIF5IFC.js.map +0 -1
  63. package/dist/chunk-BQGIXRKV.js.map +0 -1
  64. package/dist/chunk-F2CFHN3Y.js.map +0 -1
  65. package/dist/chunk-IOLVN74D.js.map +0 -1
  66. package/dist/chunk-W3OUAH6M.js +0 -170
  67. package/dist/chunk-W3OUAH6M.js.map +0 -1
  68. package/dist/chunk-ZFOFY5ST.js.map +0 -1
  69. package/dist/timeline-annotation-selection-3L7LHGG2.js +0 -187
  70. package/dist/timeline-annotation-selection-3L7LHGG2.js.map +0 -1
  71. package/dist/timeline-annotations-dialog-U7EVLR75.js +0 -196
  72. package/dist/timeline-annotations-dialog-U7EVLR75.js.map +0 -1
package/README.md CHANGED
@@ -844,3 +844,9 @@ thinking labels through `messages`, and override payment descriptions through
844
844
  Subscription descriptions appear once per provider group. Free models carry a
845
845
  Free badge. Pass `hasImageAttachments` for the current draft to show an image
846
846
  compatibility warning only when the selected model cannot view those images.
847
+
848
+ `MessageTimeline.renderMessageActions(item)` places host-owned controls beside
849
+ Copy and the timestamp for user messages and completed assistant messages.
850
+ The host owns feedback, fork authorization, and mutations; streaming assistant
851
+ messages omit this slot. Use the `group/copy` hover/focus state and preserve
852
+ visible touch targets when styling actions.
package/dist/chat.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  HumanInputForm,
3
3
  Markdown
4
- } from "./chunk-F2CFHN3Y.js";
4
+ } from "./chunk-YAIPFO5D.js";
5
5
  import "./chunk-JVYQRRC4.js";
6
6
  import "./chunk-HQV2I5HV.js";
7
7
  import "./chunk-VZTQ73XT.js";
@@ -0,0 +1,171 @@
1
+ import {
2
+ annotationNoteNeedsDisclosure
3
+ } from "./chunk-ZYRGEKWS.js";
4
+ import {
5
+ annotationSourceLabel,
6
+ revealLoadedAnnotationSource,
7
+ truncateAnnotationQuote
8
+ } from "./chunk-NOSYBS2D.js";
9
+ import {
10
+ cn
11
+ } from "./chunk-22KP6LR5.js";
12
+
13
+ // src/components/timeline-annotation-chrome.tsx
14
+ import { useLayoutEffect, useRef, useState } from "react";
15
+
16
+ // src/components/timeline-annotation-reveal-context.ts
17
+ import { createContext, useContext } from "react";
18
+ var TimelineAnnotationSourceRootContext = createContext(null);
19
+ function useTimelineAnnotationSourceRoot() {
20
+ return useContext(TimelineAnnotationSourceRootContext);
21
+ }
22
+
23
+ // src/components/timeline-annotation-chrome.tsx
24
+ import { jsx, jsxs } from "react/jsx-runtime";
25
+ var NOTE_MAX_HEIGHT_PX = 160;
26
+ function autosizeNote(textarea) {
27
+ if (!textarea) return;
28
+ textarea.style.height = "auto";
29
+ textarea.style.height = `${Math.min(Math.max(textarea.scrollHeight, 32), NOTE_MAX_HEIGHT_PX)}px`;
30
+ }
31
+ function quotePreview(quote) {
32
+ const trimmed = quote.trim();
33
+ const multiline = trimmed.includes("\n");
34
+ return {
35
+ text: multiline ? trimmed : trimmed.replace(/\s+/g, " "),
36
+ multiline
37
+ };
38
+ }
39
+ function AnnotationQuoteSourceButton({
40
+ annotation,
41
+ lines = 2,
42
+ onRevealSource,
43
+ onUnavailable
44
+ }) {
45
+ const preview = quotePreview(annotation.quote);
46
+ const sourceLabel = annotationSourceLabel(annotation.source);
47
+ const sourceRoot = useTimelineAnnotationSourceRoot();
48
+ return /* @__PURE__ */ jsxs(
49
+ "button",
50
+ {
51
+ type: "button",
52
+ title: annotation.quote,
53
+ "aria-label": `View ${sourceLabel} source: ${truncateAnnotationQuote(annotation.quote, 88)}`,
54
+ className: "block w-full min-w-0 rounded-sm border-0 bg-transparent text-left text-og-sm leading-5 text-og-fg-muted outline-hidden transition-colors hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:min-h-[44px]",
55
+ onClick: () => {
56
+ const revealed = onRevealSource?.(annotation.source) ?? (sourceRoot ? revealLoadedAnnotationSource(annotation.source, sourceRoot.current) : revealLoadedAnnotationSource(annotation.source));
57
+ onUnavailable(revealed ? null : annotation.id);
58
+ },
59
+ children: [
60
+ /* @__PURE__ */ jsx(
61
+ "span",
62
+ {
63
+ className: cn(
64
+ "block min-w-0 max-w-full break-words",
65
+ preview.multiline ? "whitespace-pre-wrap" : "whitespace-normal",
66
+ lines === 3 ? "line-clamp-3" : "line-clamp-2"
67
+ ),
68
+ children: preview.text
69
+ }
70
+ ),
71
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: " view source" })
72
+ ]
73
+ }
74
+ );
75
+ }
76
+ function AnnotationAccentRow({
77
+ children,
78
+ className
79
+ }) {
80
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex gap-2.5", className), children: [
81
+ /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: "w-0.5 shrink-0 rounded-full bg-og-accent/55" }),
82
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children })
83
+ ] });
84
+ }
85
+ function AnnotationNotePreview({
86
+ note,
87
+ annotationId,
88
+ ordinal,
89
+ className
90
+ }) {
91
+ const [expanded, setExpanded] = useState(false);
92
+ if (!note) return null;
93
+ const collapsible = annotationNoteNeedsDisclosure(note);
94
+ const contentId = `og-annotation-note-${annotationId}`;
95
+ return /* @__PURE__ */ jsxs("div", { className, children: [
96
+ /* @__PURE__ */ jsx(
97
+ "p",
98
+ {
99
+ id: contentId,
100
+ "data-og-annotation-note": "",
101
+ "data-og-annotation-note-expanded": expanded ? "true" : "false",
102
+ className: cn(
103
+ "mt-0.5 break-words whitespace-pre-wrap text-og-sm leading-5 text-og-fg",
104
+ !expanded && "line-clamp-4"
105
+ ),
106
+ children: note
107
+ }
108
+ ),
109
+ collapsible ? /* @__PURE__ */ jsx(
110
+ "button",
111
+ {
112
+ type: "button",
113
+ className: "mt-0.5 inline-flex min-h-7 items-center rounded-og-sm px-1 text-og-xs font-medium text-og-fg-muted outline-hidden hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:min-h-11",
114
+ "aria-expanded": expanded,
115
+ "aria-controls": contentId,
116
+ "aria-label": expanded ? `Show less annotation ${ordinal}` : `Show more annotation ${ordinal}`,
117
+ onClick: () => setExpanded((current) => !current),
118
+ children: expanded ? "Show less" : "Show more"
119
+ }
120
+ ) : null
121
+ ] });
122
+ }
123
+ function AnnotationNoteField({
124
+ annotation,
125
+ inputRef,
126
+ onUpdate,
127
+ onCommit
128
+ }) {
129
+ const localRef = useRef(null);
130
+ const setRef = (node) => {
131
+ localRef.current = node;
132
+ inputRef?.(node);
133
+ autosizeNote(node);
134
+ };
135
+ useLayoutEffect(() => {
136
+ autosizeNote(localRef.current);
137
+ }, [annotation.note]);
138
+ return /* @__PURE__ */ jsx(
139
+ "textarea",
140
+ {
141
+ ref: setRef,
142
+ value: annotation.note,
143
+ rows: 1,
144
+ maxLength: 2048,
145
+ placeholder: "Add a note\u2026",
146
+ "aria-label": "Note",
147
+ className: "mt-0.5 max-h-40 min-h-8 w-full resize-none overflow-y-auto break-words border-0 bg-transparent px-0 py-1 text-og-sm leading-5 text-og-fg outline-hidden placeholder:text-og-fg-subtle focus-visible:ring-0",
148
+ onInput: (event) => {
149
+ autosizeNote(event.currentTarget);
150
+ onUpdate(annotation.id, event.currentTarget.value);
151
+ },
152
+ onKeyDown: (event) => {
153
+ if (event.key !== "Enter" || event.shiftKey || event.nativeEvent.isComposing) return;
154
+ event.preventDefault();
155
+ event.stopPropagation();
156
+ if (event.currentTarget.value.trim().length === 0) return;
157
+ onCommit?.();
158
+ }
159
+ }
160
+ );
161
+ }
162
+
163
+ export {
164
+ TimelineAnnotationSourceRootContext,
165
+ useTimelineAnnotationSourceRoot,
166
+ AnnotationQuoteSourceButton,
167
+ AnnotationAccentRow,
168
+ AnnotationNotePreview,
169
+ AnnotationNoteField
170
+ };
171
+ //# sourceMappingURL=chunk-5M6VTFJ5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/timeline-annotation-chrome.tsx","../src/components/timeline-annotation-reveal-context.ts"],"sourcesContent":["import type {\n DraftTimelineAnnotation,\n TimelineAnnotation,\n TimelineAnnotationSource,\n} from \"@opengeni/sdk\";\nimport { useLayoutEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { annotationNoteNeedsDisclosure } from \"./timeline-annotation-layout\";\nimport { useTimelineAnnotationSourceRoot } from \"./timeline-annotation-reveal-context\";\nimport {\n annotationSourceLabel,\n revealLoadedAnnotationSource,\n truncateAnnotationQuote,\n} from \"./timeline-annotation-shared\";\n\nexport type TimelineAnnotationLike = DraftTimelineAnnotation | TimelineAnnotation;\n\nconst NOTE_MAX_HEIGHT_PX = 160;\n\nfunction autosizeNote(textarea: HTMLTextAreaElement | null): void {\n if (!textarea) return;\n textarea.style.height = \"auto\";\n textarea.style.height = `${Math.min(Math.max(textarea.scrollHeight, 32), NOTE_MAX_HEIGHT_PX)}px`;\n}\n\nfunction quotePreview(quote: string): { text: string; multiline: boolean } {\n const trimmed = quote.trim();\n const multiline = trimmed.includes(\"\\n\");\n return {\n text: multiline ? trimmed : trimmed.replace(/\\s+/g, \" \"),\n multiline,\n };\n}\n\nexport function AnnotationQuoteSourceButton({\n annotation,\n lines = 2,\n onRevealSource,\n onUnavailable,\n}: {\n annotation: TimelineAnnotationLike;\n lines?: 2 | 3;\n onRevealSource?: ((source: TimelineAnnotationSource) => boolean) | undefined;\n onUnavailable: (id: string | null) => void;\n}) {\n const preview = quotePreview(annotation.quote);\n const sourceLabel = annotationSourceLabel(annotation.source);\n const sourceRoot = useTimelineAnnotationSourceRoot();\n return (\n <button\n type=\"button\"\n title={annotation.quote}\n aria-label={`View ${sourceLabel} source: ${truncateAnnotationQuote(annotation.quote, 88)}`}\n className=\"block w-full min-w-0 rounded-sm border-0 bg-transparent text-left text-og-sm leading-5 text-og-fg-muted outline-hidden transition-colors hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:min-h-[44px]\"\n onClick={() => {\n const revealed =\n onRevealSource?.(annotation.source) ??\n (sourceRoot\n ? revealLoadedAnnotationSource(annotation.source, sourceRoot.current)\n : revealLoadedAnnotationSource(annotation.source));\n onUnavailable(revealed ? null : annotation.id);\n }}\n >\n <span\n className={cn(\n \"block min-w-0 max-w-full break-words\",\n preview.multiline ? \"whitespace-pre-wrap\" : \"whitespace-normal\",\n lines === 3 ? \"line-clamp-3\" : \"line-clamp-2\",\n )}\n >\n {preview.text}\n </span>\n <span className=\"sr-only\"> view source</span>\n </button>\n );\n}\n\nexport function AnnotationAccentRow({\n children,\n className,\n}: {\n children: ReactNode;\n className?: string | undefined;\n}) {\n return (\n <div className={cn(\"flex gap-2.5\", className)}>\n <div aria-hidden=\"true\" className=\"w-0.5 shrink-0 rounded-full bg-og-accent/55\" />\n <div className=\"min-w-0 flex-1\">{children}</div>\n </div>\n );\n}\n\nexport function AnnotationNotePreview({\n note,\n annotationId,\n ordinal,\n className,\n}: {\n note: string;\n annotationId: string;\n ordinal: number;\n className?: string | undefined;\n}) {\n const [expanded, setExpanded] = useState(false);\n if (!note) return null;\n const collapsible = annotationNoteNeedsDisclosure(note);\n const contentId = `og-annotation-note-${annotationId}`;\n return (\n <div className={className}>\n <p\n id={contentId}\n data-og-annotation-note=\"\"\n data-og-annotation-note-expanded={expanded ? \"true\" : \"false\"}\n className={cn(\n \"mt-0.5 break-words whitespace-pre-wrap text-og-sm leading-5 text-og-fg\",\n !expanded && \"line-clamp-4\",\n )}\n >\n {note}\n </p>\n {collapsible ? (\n <button\n type=\"button\"\n className=\"mt-0.5 inline-flex min-h-7 items-center rounded-og-sm px-1 text-og-xs font-medium text-og-fg-muted outline-hidden hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:min-h-11\"\n aria-expanded={expanded}\n aria-controls={contentId}\n aria-label={\n expanded ? `Show less annotation ${ordinal}` : `Show more annotation ${ordinal}`\n }\n onClick={() => setExpanded((current) => !current)}\n >\n {expanded ? \"Show less\" : \"Show more\"}\n </button>\n ) : null}\n </div>\n );\n}\n\nexport function AnnotationNoteField({\n annotation,\n inputRef,\n onUpdate,\n onCommit,\n}: {\n annotation: TimelineAnnotationLike;\n inputRef?: ((node: HTMLTextAreaElement | null) => void) | undefined;\n onUpdate: (id: string, note: string) => void;\n onCommit?: (() => void) | undefined;\n}) {\n const localRef = useRef<HTMLTextAreaElement | null>(null);\n const setRef = (node: HTMLTextAreaElement | null) => {\n localRef.current = node;\n inputRef?.(node);\n autosizeNote(node);\n };\n\n useLayoutEffect(() => {\n autosizeNote(localRef.current);\n }, [annotation.note]);\n\n return (\n <textarea\n ref={setRef}\n value={annotation.note}\n rows={1}\n maxLength={2048}\n placeholder=\"Add a note…\"\n aria-label=\"Note\"\n className=\"mt-0.5 max-h-40 min-h-8 w-full resize-none overflow-y-auto break-words border-0 bg-transparent px-0 py-1 text-og-sm leading-5 text-og-fg outline-hidden placeholder:text-og-fg-subtle focus-visible:ring-0\"\n onInput={(event) => {\n autosizeNote(event.currentTarget);\n onUpdate(annotation.id, event.currentTarget.value);\n }}\n onKeyDown={(event) => {\n if (event.key !== \"Enter\" || event.shiftKey || event.nativeEvent.isComposing) return;\n event.preventDefault();\n event.stopPropagation();\n if (event.currentTarget.value.trim().length === 0) return;\n onCommit?.();\n }}\n />\n );\n}\n","import { createContext, useContext, type RefObject } from \"react\";\n\n/** Owning timeline scroller for quote-source navigation. */\nexport const TimelineAnnotationSourceRootContext =\n createContext<RefObject<HTMLElement | null> | null>(null);\n\nexport function useTimelineAnnotationSourceRoot(): RefObject<HTMLElement | null> | null {\n return useContext(TimelineAnnotationSourceRootContext);\n}\n"],"mappings":"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","names":[]}
@@ -1794,6 +1794,19 @@ function useComposer(sessionId, options = {}) {
1794
1794
  const clearAnnotationReviewTarget = useCallback(() => {
1795
1795
  setAnnotationReviewTargetId(null);
1796
1796
  }, []);
1797
+ const requestAnnotationReview = useCallback((id) => {
1798
+ const current = annotationsRef.current;
1799
+ if (current.length === 0) {
1800
+ setAnnotationReviewTargetId(null);
1801
+ return;
1802
+ }
1803
+ if (id && current.some((annotation) => annotation.id === id)) {
1804
+ setAnnotationReviewTargetId(id);
1805
+ return;
1806
+ }
1807
+ const incomplete = current.find((annotation) => annotation.note.trim().length === 0);
1808
+ setAnnotationReviewTargetId(incomplete?.id ?? current[0].id);
1809
+ }, []);
1797
1810
  const updatePolicy = useCallback(
1798
1811
  (next) => {
1799
1812
  if (targetKeyRef.current !== targetKey) return;
@@ -1941,6 +1954,7 @@ function useComposer(sessionId, options = {}) {
1941
1954
  removeAnnotation,
1942
1955
  annotationReviewTargetId: identityMatches ? annotationReviewTargetId : null,
1943
1956
  clearAnnotationReviewTarget,
1957
+ requestAnnotationReview,
1944
1958
  hasDraftContent,
1945
1959
  send,
1946
1960
  optimisticMessages: visibleOptimisticMessages,
@@ -2073,4 +2087,4 @@ export {
2073
2087
  shouldSubmitOnKey,
2074
2088
  shouldSteerOnKey
2075
2089
  };
2076
- //# sourceMappingURL=chunk-IOLVN74D.js.map
2090
+ //# sourceMappingURL=chunk-6J56T3MG.js.map