@opengeni/react 0.44.3 → 0.44.5
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 +42 -0
- package/dist/chunk-22KP6LR5.js +31 -0
- package/dist/{chunk-TK7G6XLT.js.map → chunk-22KP6LR5.js.map} +1 -1
- package/dist/{chunk-SXIQK54Z.js → chunk-6EDV6YFE.js} +8 -8
- package/dist/{chunk-SXIQK54Z.js.map → chunk-6EDV6YFE.js.map} +1 -1
- package/dist/{chunk-U6K24XQD.js → chunk-EHSYZ4KP.js} +37 -16
- package/dist/chunk-EHSYZ4KP.js.map +1 -0
- package/dist/chunk-JB5725BI.js +48 -0
- package/dist/chunk-JB5725BI.js.map +1 -0
- package/dist/{chunk-QQRM3DO3.js → chunk-L3EWO3UK.js} +6 -6
- package/dist/{chunk-QQRM3DO3.js.map → chunk-L3EWO3UK.js.map} +1 -1
- package/dist/{chunk-YNYIAYXQ.js → chunk-LYRJUU5V.js} +23 -23
- package/dist/chunk-LYRJUU5V.js.map +1 -0
- package/dist/{chunk-ATSTR5P3.js → chunk-U3CSCMWA.js} +5 -49
- package/dist/chunk-U3CSCMWA.js.map +1 -0
- package/dist/{chunk-YDNWMKXO.js → chunk-VCBFUSUZ.js} +4 -4
- package/dist/chunk-VCBFUSUZ.js.map +1 -0
- package/dist/components/model-policy-picker.d.ts +10 -1
- package/dist/composer.js +5 -4
- package/dist/index.js +11 -9
- package/dist/index.js.map +1 -1
- package/dist/machines.js +2 -2
- package/dist/{queue-surface-implementation-THPAKGMD.js → queue-surface-implementation-J4XJFKRW.js} +41 -26
- package/dist/queue-surface-implementation-J4XJFKRW.js.map +1 -0
- package/dist/realtime/dropdown-menu.d.ts +4 -4
- package/dist/realtime.js +58 -20
- package/dist/realtime.js.map +1 -1
- package/dist/session-ui.js +5 -4
- package/package.json +1 -1
- package/src/components/composer.tsx +3 -3
- package/src/components/enrollment-device-flow.tsx +2 -2
- package/src/components/message-timeline.tsx +15 -15
- package/src/components/model-policy-picker.tsx +47 -14
- package/src/components/queue-surface-implementation.tsx +28 -18
- package/src/components/queue-surface-state.tsx +3 -3
- package/src/components/queue-surface.tsx +2 -2
- package/src/components/session-status.tsx +1 -1
- package/src/lib/cn.ts +14 -1
- package/src/lib/use-portal-token-style.ts +1 -1
- package/src/provider.tsx +4 -4
- package/src/realtime/dropdown-menu.tsx +51 -8
- package/src/realtime/realtime-control.tsx +2 -2
- package/styles/index.css +91 -11
- package/styles/tokens.css +61 -0
- package/dist/chunk-ATSTR5P3.js.map +0 -1
- package/dist/chunk-TK7G6XLT.js +0 -18
- package/dist/chunk-U6K24XQD.js.map +0 -1
- package/dist/chunk-YDNWMKXO.js.map +0 -1
- package/dist/chunk-YNYIAYXQ.js.map +0 -1
- package/dist/queue-surface-implementation-THPAKGMD.js.map +0 -1
|
@@ -9,8 +9,17 @@ import {
|
|
|
9
9
|
} from "lucide-react";
|
|
10
10
|
import { motion, useReducedMotion } from "motion/react";
|
|
11
11
|
import { DropdownMenu } from "radix-ui";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
useEffect,
|
|
14
|
+
useMemo,
|
|
15
|
+
useRef,
|
|
16
|
+
useState,
|
|
17
|
+
type CSSProperties,
|
|
18
|
+
type ReactNode,
|
|
19
|
+
type SVGProps,
|
|
20
|
+
} from "react";
|
|
13
21
|
import { cn } from "../lib/cn";
|
|
22
|
+
import { usePortalTokenStyle } from "../lib/use-portal-token-style";
|
|
14
23
|
import {
|
|
15
24
|
coerceReasoningEffortForModel,
|
|
16
25
|
effortOptionsForModel,
|
|
@@ -72,12 +81,21 @@ export type ModelPolicyPickerProps = {
|
|
|
72
81
|
disabled?: boolean | undefined;
|
|
73
82
|
loading?: boolean | undefined;
|
|
74
83
|
error?: string | null | undefined;
|
|
84
|
+
/** Controlled menu state. Omit for the built-in uncontrolled behavior. */
|
|
85
|
+
open?: boolean | undefined;
|
|
86
|
+
/** Initial menu state when `open` is uncontrolled. */
|
|
87
|
+
defaultOpen?: boolean | undefined;
|
|
88
|
+
onOpenChange?: ((open: boolean) => void) | undefined;
|
|
75
89
|
/** Non-Codex models stay visible but cannot be selected. */
|
|
76
90
|
codexOnly?: boolean | undefined;
|
|
77
91
|
/** Resets drill-down navigation when the session scope changes. */
|
|
78
92
|
sessionKey?: string | undefined;
|
|
79
93
|
/** Prefer bottom on new-chat surfaces and top for bottom-docked composers. */
|
|
80
94
|
menuSide?: "top" | "bottom" | undefined;
|
|
95
|
+
/** Classes for the portalled menu surface. Prefer --og-* tokens for theming. */
|
|
96
|
+
contentClassName?: string | undefined;
|
|
97
|
+
/** Inline styles for the portalled menu, applied after inherited --og-* tokens. */
|
|
98
|
+
contentStyle?: CSSProperties | undefined;
|
|
81
99
|
className?: string | undefined;
|
|
82
100
|
messages?: Partial<ModelPolicyPickerMessages> | undefined;
|
|
83
101
|
onModelChange: (modelId: string) => void;
|
|
@@ -225,17 +243,19 @@ export function PickerNavRow(props: {
|
|
|
225
243
|
onClick={props.onClick}
|
|
226
244
|
data-testid={props.testId}
|
|
227
245
|
className={cn(
|
|
228
|
-
"flex w-full cursor-pointer items-center gap-2 rounded-og-sm px-
|
|
246
|
+
"flex w-full cursor-pointer items-center gap-2 rounded-og-sm px-[var(--og-model-picker-row-padding-x)] py-[var(--og-model-picker-row-padding-y)] text-left text-og-fg outline-none transition-colors hover:bg-og-surface-2 focus-visible:ring-2 focus-visible:ring-og-accent/40",
|
|
229
247
|
props.disabled && "cursor-not-allowed opacity-50",
|
|
230
248
|
)}
|
|
231
249
|
>
|
|
232
250
|
{props.icon}
|
|
233
251
|
<span className="min-w-0 flex-1">
|
|
234
|
-
<span className={cn("block truncate text-
|
|
252
|
+
<span className={cn("block truncate text-og-menu", props.active && "font-medium")}>
|
|
235
253
|
{props.label}
|
|
236
254
|
</span>
|
|
237
255
|
{props.hint ? (
|
|
238
|
-
<span className="mt-0.5 block truncate text-
|
|
256
|
+
<span className="mt-0.5 block truncate text-og-control text-og-fg-subtle">
|
|
257
|
+
{props.hint}
|
|
258
|
+
</span>
|
|
239
259
|
) : null}
|
|
240
260
|
</span>
|
|
241
261
|
{props.trailing ? <span className="ml-auto shrink-0">{props.trailing}</span> : null}
|
|
@@ -262,7 +282,7 @@ export function PickerBackHeader(props: {
|
|
|
262
282
|
>
|
|
263
283
|
<ChevronLeftIcon className="size-3.5 shrink-0 text-og-fg-subtle" />
|
|
264
284
|
{props.icon}
|
|
265
|
-
<span className="min-w-0 flex-1 truncate text-
|
|
285
|
+
<span className="min-w-0 flex-1 truncate text-og-menu font-medium">{props.label}</span>
|
|
266
286
|
</button>
|
|
267
287
|
{props.trailing ? <div className="relative z-10 shrink-0">{props.trailing}</div> : null}
|
|
268
288
|
</div>
|
|
@@ -352,9 +372,9 @@ export function ModelPolicyPickerMenu(
|
|
|
352
372
|
|
|
353
373
|
let body: ReactNode;
|
|
354
374
|
if (props.loading) {
|
|
355
|
-
body = <p className="px-2 py-3 text-
|
|
375
|
+
body = <p className="px-2 py-3 text-og-control text-og-fg-subtle">{messages.loading}</p>;
|
|
356
376
|
} else if (groups.length === 0) {
|
|
357
|
-
body = <p className="px-2 py-3 text-
|
|
377
|
+
body = <p className="px-2 py-3 text-og-control text-og-fg-subtle">{messages.noModels}</p>;
|
|
358
378
|
} else if (effectiveNav.level === "providers") {
|
|
359
379
|
body = (
|
|
360
380
|
<div className="flex flex-col gap-0.5" data-testid="model-picker-providers">
|
|
@@ -449,11 +469,11 @@ export function ModelPolicyPickerMenu(
|
|
|
449
469
|
) : null
|
|
450
470
|
}
|
|
451
471
|
/>
|
|
452
|
-
<p className="px-2.5 pt-1 pb-1 text-
|
|
472
|
+
<p className="px-2.5 pt-1 pb-1 text-og-control font-medium tracking-wide text-og-fg-subtle uppercase">
|
|
453
473
|
{messages.thinking}
|
|
454
474
|
</p>
|
|
455
475
|
{focusModel.catalog.capabilities?.inputModalities.includes("image") === false ? (
|
|
456
|
-
<p className="px-2.5 pb-1.5 text-
|
|
476
|
+
<p className="px-2.5 pb-1.5 text-og-control leading-relaxed text-og-fg-subtle">
|
|
457
477
|
Unsupported attachments stay in the session but are hidden from this model.
|
|
458
478
|
</p>
|
|
459
479
|
) : null}
|
|
@@ -467,7 +487,7 @@ export function ModelPolicyPickerMenu(
|
|
|
467
487
|
disabled={!focusModel.selectable}
|
|
468
488
|
onClick={() => selectEffort(focusModel, effort)}
|
|
469
489
|
className={cn(
|
|
470
|
-
"flex h-
|
|
490
|
+
"flex h-[var(--og-model-picker-effort-height)] w-full cursor-pointer items-center rounded-og-sm px-[var(--og-model-picker-row-padding-x)] text-left text-og-menu text-og-fg outline-none transition-colors hover:bg-og-surface-2 focus-visible:ring-2 focus-visible:ring-og-accent/40 disabled:cursor-not-allowed disabled:opacity-50",
|
|
471
491
|
selected && "bg-og-surface-2",
|
|
472
492
|
)}
|
|
473
493
|
>
|
|
@@ -504,7 +524,7 @@ export function ModelPolicyPickerMenu(
|
|
|
504
524
|
return (
|
|
505
525
|
<div data-testid="model-picker-menu" className="relative overflow-hidden">
|
|
506
526
|
{props.error ? (
|
|
507
|
-
<p className="px-2 py-1 text-
|
|
527
|
+
<p className="px-2 py-1 text-og-control text-og-status-failed" role="alert">
|
|
508
528
|
{props.error}
|
|
509
529
|
</p>
|
|
510
530
|
) : null}
|
|
@@ -516,7 +536,14 @@ export function ModelPolicyPickerMenu(
|
|
|
516
536
|
}
|
|
517
537
|
|
|
518
538
|
export function ModelPolicyPicker(props: ModelPolicyPickerProps) {
|
|
519
|
-
const [
|
|
539
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(props.defaultOpen ?? false);
|
|
540
|
+
const open = props.open ?? uncontrolledOpen;
|
|
541
|
+
const setOpen = (next: boolean) => {
|
|
542
|
+
if (props.open === undefined) setUncontrolledOpen(next);
|
|
543
|
+
props.onOpenChange?.(next);
|
|
544
|
+
};
|
|
545
|
+
const triggerRef = useRef<HTMLButtonElement | null>(null);
|
|
546
|
+
const portalStyle = usePortalTokenStyle(triggerRef);
|
|
520
547
|
const messages = useMemo(
|
|
521
548
|
() => ({ ...defaultModelPolicyPickerMessages, ...props.messages }),
|
|
522
549
|
[props.messages],
|
|
@@ -541,11 +568,12 @@ export function ModelPolicyPicker(props: ModelPolicyPickerProps) {
|
|
|
541
568
|
<DropdownMenu.Root open={open} onOpenChange={setOpen}>
|
|
542
569
|
<DropdownMenu.Trigger asChild>
|
|
543
570
|
<button
|
|
571
|
+
ref={triggerRef}
|
|
544
572
|
type="button"
|
|
545
573
|
disabled={props.disabled}
|
|
546
574
|
aria-label={messages.label}
|
|
547
575
|
className={cn(
|
|
548
|
-
"inline-flex h-
|
|
576
|
+
"og-root inline-flex h-[var(--og-model-picker-trigger-height)] min-w-0 max-w-64 items-center gap-1 rounded-full border border-transparent px-2.5 text-og-control text-og-fg-muted outline-none transition-colors hover:border-og-border hover:bg-og-surface-2 hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent/40 disabled:cursor-not-allowed disabled:opacity-50 max-sm:h-[var(--og-model-picker-trigger-height-mobile)] max-sm:max-w-[7.5rem] max-sm:px-2",
|
|
549
577
|
props.className,
|
|
550
578
|
)}
|
|
551
579
|
>
|
|
@@ -580,7 +608,12 @@ export function ModelPolicyPicker(props: ModelPolicyPickerProps) {
|
|
|
580
608
|
sideOffset={8}
|
|
581
609
|
collisionPadding={12}
|
|
582
610
|
onCloseAutoFocus={(event) => event.preventDefault()}
|
|
583
|
-
className=
|
|
611
|
+
className={cn(
|
|
612
|
+
"og-root z-50 flex max-h-[min(20rem,var(--radix-dropdown-menu-content-available-height))] w-[var(--og-model-picker-menu-width)] max-w-[calc(100vw-16px)] flex-col overflow-hidden rounded-og-lg border border-og-border bg-og-surface-1 p-[var(--og-model-picker-menu-padding)] text-og-fg shadow-og-lg",
|
|
613
|
+
props.contentClassName,
|
|
614
|
+
)}
|
|
615
|
+
style={{ ...portalStyle, ...props.contentStyle }}
|
|
616
|
+
data-testid="model-picker-content"
|
|
584
617
|
>
|
|
585
618
|
<div className="min-h-0 flex-1 overflow-y-auto overscroll-contain">
|
|
586
619
|
<ModelPolicyPickerMenu {...props} nav={nav} onNavChange={setNav} />
|
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
import { DropdownMenu } from "radix-ui";
|
|
41
41
|
import type { ComposerState } from "../hooks/use-composer";
|
|
42
42
|
import type { QueueMutationKind, UseTurnQueueResult } from "../hooks/use-turn-queue";
|
|
43
|
+
import { type PortalTokenStyle, usePortalTokenStyle } from "../lib/use-portal-token-style";
|
|
43
44
|
import { requestQueueDraftEdit } from "./queue-draft-policy";
|
|
44
45
|
import { QueueErrorAlert, QueueStoppingStatus } from "./queue-surface-state";
|
|
45
46
|
|
|
@@ -80,6 +81,7 @@ export function QueueSurface({
|
|
|
80
81
|
const [announcement, setAnnouncement] = useState("");
|
|
81
82
|
const [draggedTurnId, setDraggedTurnId] = useState<string | null>(null);
|
|
82
83
|
const surfaceRef = useRef<HTMLDivElement | null>(null);
|
|
84
|
+
const portalTokenStyle = usePortalTokenStyle(surfaceRef);
|
|
83
85
|
const [keyboardDrag, setKeyboardDrag] = useState<{
|
|
84
86
|
turnId: string;
|
|
85
87
|
projectedIndex: number;
|
|
@@ -244,7 +246,7 @@ export function QueueSurface({
|
|
|
244
246
|
return (
|
|
245
247
|
<div
|
|
246
248
|
ref={surfaceRef}
|
|
247
|
-
className="mx-auto mb-2 w-full max-w-3xl shrink-0 px-4 sm:px-6"
|
|
249
|
+
className="og-root mx-auto mb-2 w-full max-w-3xl shrink-0 px-4 sm:px-6"
|
|
248
250
|
data-testid="queue-surface"
|
|
249
251
|
>
|
|
250
252
|
<div className="overflow-hidden rounded-lg border border-border bg-surface/80 shadow-sm">
|
|
@@ -265,7 +267,7 @@ export function QueueSurface({
|
|
|
265
267
|
aria-hidden="true"
|
|
266
268
|
className={`size-3.5 shrink-0 text-fg-subtle transition-transform ${open ? "rotate-180" : ""}`}
|
|
267
269
|
/>
|
|
268
|
-
<span className="text-
|
|
270
|
+
<span className="text-og-control font-medium text-fg">
|
|
269
271
|
{count > 0 ? `${count} queued prompt${count === 1 ? "" : "s"}` : null}
|
|
270
272
|
{count > 0 && pendingInputCount > 0 ? " · " : null}
|
|
271
273
|
{pendingInputCount > 0
|
|
@@ -273,7 +275,7 @@ export function QueueSurface({
|
|
|
273
275
|
: null}
|
|
274
276
|
</span>
|
|
275
277
|
{readOnly ? (
|
|
276
|
-
<span className="shrink-0 rounded border border-border px-1.5 py-0.5 text-
|
|
278
|
+
<span className="shrink-0 rounded border border-border px-1.5 py-0.5 text-og-xs text-fg-subtle">
|
|
277
279
|
Read-only
|
|
278
280
|
</span>
|
|
279
281
|
) : null}
|
|
@@ -282,7 +284,7 @@ export function QueueSurface({
|
|
|
282
284
|
aria-hidden="true"
|
|
283
285
|
className={`max-w-full truncate text-fg-muted ${
|
|
284
286
|
collapsedPreview.collapsedVisual === collapsedPreview.summary
|
|
285
|
-
? "min-w-0 flex-1 text-
|
|
287
|
+
? "min-w-0 flex-1 text-og-control"
|
|
286
288
|
: "shrink-0 text-[10px]"
|
|
287
289
|
}`}
|
|
288
290
|
data-testid="queue-collapsed-preview"
|
|
@@ -352,6 +354,7 @@ export function QueueSurface({
|
|
|
352
354
|
pending={queue.mutationFor(turn.id)}
|
|
353
355
|
confirmingReplace={replaceDraftFor === turn.id}
|
|
354
356
|
keyboardDragging={keyboardDrag?.turnId === turn.id}
|
|
357
|
+
portalTokenStyle={portalTokenStyle}
|
|
355
358
|
onHandleKeyDown={(event) => onHandleKeyDown(event, turn.id)}
|
|
356
359
|
onMove={(nextIndex) => void moveToIndex(turn.id, nextIndex)}
|
|
357
360
|
onEdit={canEditInComposer ? () => requestEdit(turn) : undefined}
|
|
@@ -393,7 +396,7 @@ export function QueueSurface({
|
|
|
393
396
|
<DragOverlay modifiers={[verticalOnly]}>
|
|
394
397
|
{draggedTurnId ? (
|
|
395
398
|
<div
|
|
396
|
-
className="max-h-20 w-[min(36rem,calc(100vw-2rem))] max-w-[calc(100vw-2rem)] overflow-hidden rounded-md border border-brand/40 bg-surface px-3 py-2 text-
|
|
399
|
+
className="max-h-20 w-[min(36rem,calc(100vw-2rem))] max-w-[calc(100vw-2rem)] overflow-hidden rounded-md border border-brand/40 bg-surface px-3 py-2 text-og-control text-fg shadow-lg"
|
|
397
400
|
data-testid="queue-drag-overlay"
|
|
398
401
|
>
|
|
399
402
|
<p
|
|
@@ -434,14 +437,18 @@ function PendingMachineInputs({
|
|
|
434
437
|
}) {
|
|
435
438
|
return (
|
|
436
439
|
<section className="border-t border-border px-3 py-2">
|
|
437
|
-
<p className="text-
|
|
440
|
+
<p className="text-og-xs font-medium text-fg-subtle">
|
|
438
441
|
{attached
|
|
439
442
|
? `${inputs.length} update${inputs.length === 1 ? "" : "s"} will join this prompt`
|
|
440
443
|
: "Incoming updates waiting to run"}
|
|
441
444
|
</p>
|
|
442
445
|
<ol className="mt-1 space-y-1">
|
|
443
446
|
{inputs.map((input) => (
|
|
444
|
-
<li
|
|
447
|
+
<li
|
|
448
|
+
key={input.id}
|
|
449
|
+
className="line-clamp-3 break-words text-og-control text-fg"
|
|
450
|
+
dir="auto"
|
|
451
|
+
>
|
|
445
452
|
<strong className="capitalize text-fg-muted">
|
|
446
453
|
{input.kind.replace("_terminal", "").replaceAll("_", " ")}
|
|
447
454
|
</strong>{" "}
|
|
@@ -756,7 +763,7 @@ function QueuePrompt({
|
|
|
756
763
|
<div className="w-full min-w-0 max-w-full">
|
|
757
764
|
<div
|
|
758
765
|
aria-label={`Queued prompt ${index + 1} summary: ${preview.summary}`}
|
|
759
|
-
className="max-w-full overflow-hidden text-
|
|
766
|
+
className="max-w-full overflow-hidden text-og-control leading-5 text-fg"
|
|
760
767
|
data-testid={`queue-prompt-preview-${index + 1}`}
|
|
761
768
|
dir="auto"
|
|
762
769
|
role="note"
|
|
@@ -771,7 +778,7 @@ function QueuePrompt({
|
|
|
771
778
|
</span>
|
|
772
779
|
{preview.visibleIdentity && preview.visibleIdentityLabel ? (
|
|
773
780
|
<span
|
|
774
|
-
className="flex min-w-0 max-w-[70%] shrink-0 items-center gap-1 text-
|
|
781
|
+
className="flex min-w-0 max-w-[70%] shrink-0 items-center gap-1 text-og-xs leading-4 text-fg-muted sm:mt-0.5 sm:max-w-full"
|
|
775
782
|
data-testid={`queue-prompt-identity-row-${index + 1}`}
|
|
776
783
|
>
|
|
777
784
|
<span className="shrink-0 font-medium text-fg-subtle">
|
|
@@ -793,7 +800,7 @@ function QueuePrompt({
|
|
|
793
800
|
aria-controls={fullContentId}
|
|
794
801
|
aria-expanded={expanded}
|
|
795
802
|
aria-label={`${expanded ? "Hide" : "Show"} full content for queued prompt ${index + 1}`}
|
|
796
|
-
className="mt-1 inline-flex min-h-7 min-w-0 max-w-full items-center gap-1 whitespace-normal rounded-md text-left text-
|
|
803
|
+
className="mt-1 inline-flex min-h-7 min-w-0 max-w-full items-center gap-1 whitespace-normal rounded-md text-left text-og-xs font-medium text-fg outline-none focus-visible:ring-2 focus-visible:ring-ring/40 pointer-coarse:min-h-[44px]"
|
|
797
804
|
data-testid={`queue-prompt-disclosure-${index + 1}`}
|
|
798
805
|
onClick={() => {
|
|
799
806
|
const next = !expanded;
|
|
@@ -812,7 +819,7 @@ function QueuePrompt({
|
|
|
812
819
|
id={fullContentId}
|
|
813
820
|
role="region"
|
|
814
821
|
aria-label={`Full content for queued prompt ${index + 1}`}
|
|
815
|
-
className="mt-1.5 max-h-64 w-full min-w-0 max-w-full overflow-auto overscroll-contain rounded-md border border-border bg-surface-2/60 p-2 whitespace-pre-wrap break-all font-mono text-
|
|
822
|
+
className="mt-1.5 max-h-64 w-full min-w-0 max-w-full overflow-auto overscroll-contain rounded-md border border-border bg-surface-2/60 p-2 whitespace-pre-wrap break-all font-mono text-og-control leading-5 text-fg [unicode-bidi:plaintext]"
|
|
816
823
|
data-testid={`queue-prompt-full-${index + 1}`}
|
|
817
824
|
dir="auto"
|
|
818
825
|
tabIndex={0}
|
|
@@ -837,13 +844,13 @@ function ReadOnlyQueueRow({
|
|
|
837
844
|
}) {
|
|
838
845
|
return (
|
|
839
846
|
<li className="flex min-w-0 items-start gap-2 bg-surface px-3 py-2">
|
|
840
|
-
<span className="mt-1 shrink-0 font-mono text-
|
|
847
|
+
<span className="mt-1 shrink-0 font-mono text-og-xs text-fg-subtle">{index + 1}</span>
|
|
841
848
|
<div className="min-w-0 flex-1">
|
|
842
849
|
<QueuePrompt prompt={turn.prompt} index={index} onDisclosureChange={onDisclosureChange} />
|
|
843
850
|
{attachedInputs.length > 0 ? (
|
|
844
851
|
<PendingMachineInputs inputs={attachedInputs} attached />
|
|
845
852
|
) : null}
|
|
846
|
-
<div className="mt-1 flex min-w-0 items-center gap-2 overflow-hidden whitespace-nowrap text-
|
|
853
|
+
<div className="mt-1 flex min-w-0 items-center gap-2 overflow-hidden whitespace-nowrap text-og-xs text-fg-subtle">
|
|
847
854
|
{turn.resources.length > 0 ? (
|
|
848
855
|
<span className="shrink-0">
|
|
849
856
|
{turn.resources.length} resource{turn.resources.length === 1 ? "" : "s"}
|
|
@@ -870,6 +877,7 @@ function SortableQueueRow({
|
|
|
870
877
|
pending,
|
|
871
878
|
confirmingReplace,
|
|
872
879
|
keyboardDragging,
|
|
880
|
+
portalTokenStyle,
|
|
873
881
|
onHandleKeyDown,
|
|
874
882
|
onMove,
|
|
875
883
|
onEdit,
|
|
@@ -886,6 +894,7 @@ function SortableQueueRow({
|
|
|
886
894
|
pending: QueueMutationKind | null;
|
|
887
895
|
confirmingReplace: boolean;
|
|
888
896
|
keyboardDragging: boolean;
|
|
897
|
+
portalTokenStyle: PortalTokenStyle;
|
|
889
898
|
onHandleKeyDown: (event: ReactKeyboardEvent<HTMLButtonElement>) => void;
|
|
890
899
|
onMove: (index: number) => void;
|
|
891
900
|
onEdit?: (() => void) | undefined;
|
|
@@ -924,7 +933,7 @@ function SortableQueueRow({
|
|
|
924
933
|
>
|
|
925
934
|
<GripVerticalIcon className="size-3.5" />
|
|
926
935
|
</button>
|
|
927
|
-
<span className="col-start-2 row-start-1 mt-1 shrink-0 font-mono text-
|
|
936
|
+
<span className="col-start-2 row-start-1 mt-1 shrink-0 font-mono text-og-xs text-fg-subtle">
|
|
928
937
|
{index + 1}
|
|
929
938
|
</span>
|
|
930
939
|
<div className="col-span-full row-start-2 min-w-0 sm:col-span-1 sm:col-start-3 sm:row-start-1">
|
|
@@ -932,7 +941,7 @@ function SortableQueueRow({
|
|
|
932
941
|
{attachedInputs.length > 0 ? (
|
|
933
942
|
<PendingMachineInputs inputs={attachedInputs} attached />
|
|
934
943
|
) : null}
|
|
935
|
-
<div className="mt-1 flex min-w-0 items-center gap-2 overflow-hidden whitespace-nowrap text-
|
|
944
|
+
<div className="mt-1 flex min-w-0 items-center gap-2 overflow-hidden whitespace-nowrap text-og-xs text-fg-subtle">
|
|
936
945
|
{turn.resources.length > 0 ? (
|
|
937
946
|
<span className="shrink-0">
|
|
938
947
|
{turn.resources.length} resource{turn.resources.length === 1 ? "" : "s"}
|
|
@@ -954,7 +963,7 @@ function SortableQueueRow({
|
|
|
954
963
|
onClick={onSteer}
|
|
955
964
|
aria-label={`Steer queued prompt ${index + 1}`}
|
|
956
965
|
title="Steer — interrupt the current turn and send this message now"
|
|
957
|
-
className="inline-flex h-7 shrink-0 items-center justify-center gap-1 rounded-md px-2 text-
|
|
966
|
+
className="inline-flex h-7 shrink-0 items-center justify-center gap-1 rounded-md px-2 text-og-control font-medium text-fg outline-none transition-[background-color] hover:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-50 pointer-coarse:min-h-[44px] pointer-coarse:min-w-[44px]"
|
|
958
967
|
>
|
|
959
968
|
{pending === "steer" ? (
|
|
960
969
|
<Loader2Icon className="size-3.5 animate-spin" />
|
|
@@ -996,7 +1005,8 @@ function SortableQueueRow({
|
|
|
996
1005
|
<DropdownMenu.Content
|
|
997
1006
|
align="end"
|
|
998
1007
|
sideOffset={4}
|
|
999
|
-
className="z-50 w-48 max-w-[calc(100vw-16px)] rounded-md border border-border bg-surface p-1 text-
|
|
1008
|
+
className="og-root z-50 w-48 max-w-[calc(100vw-16px)] rounded-md border border-border bg-surface p-1 text-og-control text-fg shadow-lg"
|
|
1009
|
+
style={portalTokenStyle}
|
|
1000
1010
|
data-testid={`queue-actions-menu-${index + 1}`}
|
|
1001
1011
|
>
|
|
1002
1012
|
{onEdit ? (
|
|
@@ -1044,7 +1054,7 @@ function SortableQueueRow({
|
|
|
1044
1054
|
</div>
|
|
1045
1055
|
</div>
|
|
1046
1056
|
{confirmingReplace ? (
|
|
1047
|
-
<div className="mx-3 mb-2 rounded-md border border-status-waiting/30 bg-status-waiting/10 p-2 text-
|
|
1057
|
+
<div className="mx-3 mb-2 rounded-md border border-status-waiting/30 bg-status-waiting/10 p-2 text-og-control text-fg">
|
|
1048
1058
|
<p>Your composer already has a draft. Replace it with this queued prompt?</p>
|
|
1049
1059
|
<p className="mt-0.5 text-fg-muted">
|
|
1050
1060
|
The current draft will be permanently discarded; this queued prompt is preserved until
|
|
@@ -10,7 +10,7 @@ export function EmptyQueueStateSurface({ queue }: QueueStateProps) {
|
|
|
10
10
|
const hasError = Boolean(queue.error || queue.mutationError);
|
|
11
11
|
return (
|
|
12
12
|
<div
|
|
13
|
-
className="mx-auto mb-2 w-full max-w-3xl shrink-0 px-4 sm:px-6"
|
|
13
|
+
className="og-root mx-auto mb-2 w-full max-w-3xl shrink-0 px-4 sm:px-6"
|
|
14
14
|
data-testid="queue-surface"
|
|
15
15
|
>
|
|
16
16
|
<div className="overflow-hidden rounded-lg border border-border bg-surface/80 shadow-sm">
|
|
@@ -31,7 +31,7 @@ export function QueueStoppingStatus({
|
|
|
31
31
|
<div
|
|
32
32
|
role="status"
|
|
33
33
|
aria-live="polite"
|
|
34
|
-
className={`flex min-h-11 items-center gap-2.5 bg-status-waiting/[0.07] px-3 py-2 text-
|
|
34
|
+
className={`flex min-h-11 items-center gap-2.5 bg-status-waiting/[0.07] px-3 py-2 text-og-control text-fg ${
|
|
35
35
|
dividerAfter ? "border-b border-status-waiting/20" : ""
|
|
36
36
|
}`}
|
|
37
37
|
data-testid="stopping-previous-attempt"
|
|
@@ -64,7 +64,7 @@ export function QueueErrorAlert({
|
|
|
64
64
|
<div className={`${dividerBefore ? "border-t border-border" : ""} p-2`}>
|
|
65
65
|
<div
|
|
66
66
|
role="alert"
|
|
67
|
-
className="flex min-w-0 max-w-full flex-wrap items-start gap-2 rounded-md bg-status-failed/10 px-2 py-1.5 text-
|
|
67
|
+
className="flex min-w-0 max-w-full flex-wrap items-start gap-2 rounded-md bg-status-failed/10 px-2 py-1.5 text-og-control text-status-failed"
|
|
68
68
|
>
|
|
69
69
|
<span
|
|
70
70
|
role="region"
|
|
@@ -43,12 +43,12 @@ function QueueSurfaceFallback() {
|
|
|
43
43
|
return (
|
|
44
44
|
<div
|
|
45
45
|
aria-live="polite"
|
|
46
|
-
className="mx-auto mb-2 w-full max-w-3xl shrink-0 px-4 sm:px-6"
|
|
46
|
+
className="og-root mx-auto mb-2 w-full max-w-3xl shrink-0 px-4 sm:px-6"
|
|
47
47
|
data-testid="queue-surface-loading"
|
|
48
48
|
role="status"
|
|
49
49
|
>
|
|
50
50
|
<div className="overflow-hidden rounded-lg border border-border bg-surface/80 shadow-sm">
|
|
51
|
-
<div className="flex items-center gap-2 px-3 py-2 text-
|
|
51
|
+
<div className="flex items-center gap-2 px-3 py-2 text-og-control text-fg-muted pointer-coarse:min-h-[44px]">
|
|
52
52
|
<Loader2Icon
|
|
53
53
|
aria-hidden="true"
|
|
54
54
|
className="size-3.5 shrink-0 animate-spin motion-reduce:animate-none"
|
|
@@ -77,7 +77,7 @@ export function SessionStatus({ status, label, size = "md", className }: Session
|
|
|
77
77
|
data-status={status}
|
|
78
78
|
className={cn(
|
|
79
79
|
"og-root inline-flex shrink-0 items-center rounded-full border font-medium",
|
|
80
|
-
size === "sm" ? "gap-1 px-1.5 py-px text-og-xs" : "gap-1.5 px-2 py-0.5 text-
|
|
80
|
+
size === "sm" ? "gap-1 px-1.5 py-px text-og-xs" : "gap-1.5 px-2 py-0.5 text-og-control",
|
|
81
81
|
meta.badgeClassName,
|
|
82
82
|
className,
|
|
83
83
|
)}
|
package/src/lib/cn.ts
CHANGED
|
@@ -15,7 +15,20 @@ import { extendTailwindMerge } from "tailwind-merge";
|
|
|
15
15
|
const twMerge = extendTailwindMerge({
|
|
16
16
|
extend: {
|
|
17
17
|
classGroups: {
|
|
18
|
-
"font-size": [
|
|
18
|
+
"font-size": [
|
|
19
|
+
{
|
|
20
|
+
text: [
|
|
21
|
+
"og-xs",
|
|
22
|
+
"og-sm",
|
|
23
|
+
"og-base",
|
|
24
|
+
"og-md",
|
|
25
|
+
"og-control",
|
|
26
|
+
"og-menu",
|
|
27
|
+
"og-composer",
|
|
28
|
+
"og-composer-wide",
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
],
|
|
19
32
|
},
|
|
20
33
|
},
|
|
21
34
|
});
|
|
@@ -34,7 +34,7 @@ export function usePortalTokenStyle(sourceRef: RefObject<HTMLElement | null>): P
|
|
|
34
34
|
const observer = new MutationObserver(sync);
|
|
35
35
|
observer.observe(ancestor, {
|
|
36
36
|
attributes: true,
|
|
37
|
-
attributeFilter: ["class", "data-og-theme", "style"],
|
|
37
|
+
attributeFilter: ["class", "data-og-density", "data-og-theme", "style"],
|
|
38
38
|
});
|
|
39
39
|
observers.push(observer);
|
|
40
40
|
ancestor = ancestor.parentElement;
|
package/src/provider.tsx
CHANGED
|
@@ -152,17 +152,17 @@ function ApiContractMismatchScreen({ mismatch }: { mismatch: OpenGeniApiContract
|
|
|
152
152
|
data-opengeni-api-contract-mismatch
|
|
153
153
|
>
|
|
154
154
|
<div className="w-full max-w-md rounded-xl border border-og-border bg-og-surface p-6 shadow-2xl">
|
|
155
|
-
<p className="text-
|
|
156
|
-
<p className="mt-2 text-
|
|
155
|
+
<p className="text-og-menu font-semibold text-og-fg">OpenGeni updated</p>
|
|
156
|
+
<p className="mt-2 text-og-menu leading-6 text-og-muted">
|
|
157
157
|
This tab cannot safely continue with the new server version. Reload it before sending or
|
|
158
158
|
controlling work.
|
|
159
159
|
</p>
|
|
160
|
-
<p className="mt-3 font-mono text-
|
|
160
|
+
<p className="mt-3 font-mono text-og-control text-og-subtle">
|
|
161
161
|
Client {mismatch.expected} · API {mismatch.actual}
|
|
162
162
|
</p>
|
|
163
163
|
<button
|
|
164
164
|
type="button"
|
|
165
|
-
className="mt-5 inline-flex h-9 items-center rounded-md bg-og-fg px-3 text-
|
|
165
|
+
className="mt-5 inline-flex h-9 items-center rounded-md bg-og-fg px-3 text-og-menu font-medium text-og-bg"
|
|
166
166
|
onClick={() => window.location.reload()}
|
|
167
167
|
>
|
|
168
168
|
Reload now
|
|
@@ -2,31 +2,69 @@
|
|
|
2
2
|
|
|
3
3
|
import { ChevronRightIcon } from "lucide-react";
|
|
4
4
|
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
|
|
5
|
-
import
|
|
5
|
+
import {
|
|
6
|
+
createContext,
|
|
7
|
+
useContext,
|
|
8
|
+
useRef,
|
|
9
|
+
type ComponentProps,
|
|
10
|
+
type Ref,
|
|
11
|
+
type RefObject,
|
|
12
|
+
} from "react";
|
|
6
13
|
import { cn } from "../lib/cn";
|
|
14
|
+
import { usePortalTokenStyle } from "../lib/use-portal-token-style";
|
|
15
|
+
|
|
16
|
+
const DropdownMenuSourceContext = createContext<RefObject<HTMLElement | null> | null>(null);
|
|
17
|
+
|
|
18
|
+
function assignRef<T>(ref: Ref<T> | undefined, value: T | null) {
|
|
19
|
+
if (typeof ref === "function") ref(value);
|
|
20
|
+
else if (ref) ref.current = value;
|
|
21
|
+
}
|
|
7
22
|
|
|
8
23
|
function DropdownMenu(props: ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
9
|
-
|
|
24
|
+
const sourceRef = useRef<HTMLElement | null>(null);
|
|
25
|
+
return (
|
|
26
|
+
<DropdownMenuSourceContext.Provider value={sourceRef}>
|
|
27
|
+
<DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
|
|
28
|
+
</DropdownMenuSourceContext.Provider>
|
|
29
|
+
);
|
|
10
30
|
}
|
|
11
31
|
|
|
12
|
-
function DropdownMenuTrigger(
|
|
13
|
-
|
|
32
|
+
function DropdownMenuTrigger({
|
|
33
|
+
ref,
|
|
34
|
+
...props
|
|
35
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
|
36
|
+
const sourceRef = useContext(DropdownMenuSourceContext);
|
|
37
|
+
return (
|
|
38
|
+
<DropdownMenuPrimitive.Trigger
|
|
39
|
+
data-slot="dropdown-menu-trigger"
|
|
40
|
+
ref={(node) => {
|
|
41
|
+
if (sourceRef) sourceRef.current = node;
|
|
42
|
+
assignRef(ref, node);
|
|
43
|
+
}}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
14
47
|
}
|
|
15
48
|
|
|
16
49
|
function DropdownMenuContent({
|
|
17
50
|
className,
|
|
18
51
|
sideOffset = 4,
|
|
52
|
+
style,
|
|
19
53
|
...props
|
|
20
54
|
}: ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
55
|
+
const sourceRef = useContext(DropdownMenuSourceContext);
|
|
56
|
+
const fallbackRef = useRef<HTMLElement | null>(null);
|
|
57
|
+
const portalStyle = usePortalTokenStyle(sourceRef ?? fallbackRef);
|
|
21
58
|
return (
|
|
22
59
|
<DropdownMenuPrimitive.Portal>
|
|
23
60
|
<DropdownMenuPrimitive.Content
|
|
24
61
|
data-slot="dropdown-menu-content"
|
|
25
62
|
sideOffset={sideOffset}
|
|
26
63
|
className={cn(
|
|
27
|
-
"z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
64
|
+
"og-root z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
28
65
|
className,
|
|
29
66
|
)}
|
|
67
|
+
style={{ ...portalStyle, ...style }}
|
|
30
68
|
{...props}
|
|
31
69
|
/>
|
|
32
70
|
</DropdownMenuPrimitive.Portal>
|
|
@@ -48,7 +86,7 @@ function DropdownMenuItem({
|
|
|
48
86
|
data-inset={inset}
|
|
49
87
|
data-variant={variant}
|
|
50
88
|
className={cn(
|
|
51
|
-
"relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-
|
|
89
|
+
"relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-og-menu outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!",
|
|
52
90
|
className,
|
|
53
91
|
)}
|
|
54
92
|
{...props}
|
|
@@ -84,7 +122,7 @@ function DropdownMenuSubTrigger({
|
|
|
84
122
|
data-slot="dropdown-menu-sub-trigger"
|
|
85
123
|
data-inset={inset}
|
|
86
124
|
className={cn(
|
|
87
|
-
"flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-
|
|
125
|
+
"flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-og-menu outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
88
126
|
className,
|
|
89
127
|
)}
|
|
90
128
|
{...props}
|
|
@@ -97,15 +135,20 @@ function DropdownMenuSubTrigger({
|
|
|
97
135
|
|
|
98
136
|
function DropdownMenuSubContent({
|
|
99
137
|
className,
|
|
138
|
+
style,
|
|
100
139
|
...props
|
|
101
140
|
}: ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
|
141
|
+
const sourceRef = useContext(DropdownMenuSourceContext);
|
|
142
|
+
const fallbackRef = useRef<HTMLElement | null>(null);
|
|
143
|
+
const portalStyle = usePortalTokenStyle(sourceRef ?? fallbackRef);
|
|
102
144
|
return (
|
|
103
145
|
<DropdownMenuPrimitive.SubContent
|
|
104
146
|
data-slot="dropdown-menu-sub-content"
|
|
105
147
|
className={cn(
|
|
106
|
-
"z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
148
|
+
"og-root z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
107
149
|
className,
|
|
108
150
|
)}
|
|
151
|
+
style={{ ...portalStyle, ...style }}
|
|
109
152
|
{...props}
|
|
110
153
|
/>
|
|
111
154
|
);
|
|
@@ -866,8 +866,8 @@ export function RealtimeVoiceModelPanel(props: {
|
|
|
866
866
|
<div className="flex shrink-0 items-start gap-1 px-2 pt-1 pb-1.5">
|
|
867
867
|
{props.leading}
|
|
868
868
|
<div className="min-w-0">
|
|
869
|
-
<div className="text-
|
|
870
|
-
<p className="mt-0.5 text-
|
|
869
|
+
<div className="text-og-menu font-medium text-og-fg">Voice model</div>
|
|
870
|
+
<p className="mt-0.5 text-og-control text-og-fg-subtle">
|
|
871
871
|
Used when you start a voice conversation.
|
|
872
872
|
</p>
|
|
873
873
|
</div>
|