@cueplusplus/ui 0.20.1 → 0.21.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/CHANGELOG.md +115 -0
- package/dist/chat/agent-pile.js +2 -2
- package/dist/chrome/_status-bar.js +1 -1
- package/dist/chrome/app-shell.js +1 -1
- package/dist/chrome/navigation-menu.js +3 -3
- package/dist/chrome/row.js +1 -1
- package/dist/chrome/scroll-area.js +1 -1
- package/dist/chrome/section-header.js +1 -1
- package/dist/chrome/segmented-control.js +1 -1
- package/dist/chrome/tabs.js +1 -1
- package/dist/chrome/toolbar.js +1 -1
- package/dist/chrome/tree.js +3 -3
- package/dist/date/calendar.js +3 -3
- package/dist/dmx/channel-matrix.js +1 -1
- package/dist/dmx/universe-grid.js +1 -1
- package/dist/elements/agent-handoff.js +3 -3
- package/dist/elements/agent-plan.js +1 -1
- package/dist/elements/agent-status.js +1 -1
- package/dist/elements/agent-surface.d.ts +9 -6
- package/dist/elements/agent-surface.js +3 -2
- package/dist/elements/approval-card.d.ts +29 -3
- package/dist/elements/approval-card.js +18 -8
- package/dist/elements/artifact-card.js +2 -2
- package/dist/elements/canvas-split.js +3 -3
- package/dist/elements/chart.js +1 -1
- package/dist/elements/chat-panel.js +2 -2
- package/dist/elements/checkpoint-history.js +1 -1
- package/dist/elements/code-diff.js +1 -1
- package/dist/elements/code-runner.js +1 -1
- package/dist/elements/composer.d.ts +8 -2
- package/dist/elements/composer.js +20 -12
- package/dist/elements/computer-use.js +2 -2
- package/dist/elements/confidence-marker.js +1 -1
- package/dist/elements/connection-state.js +2 -2
- package/dist/elements/context-breakdown.js +1 -1
- package/dist/elements/context-usage.js +1 -1
- package/dist/elements/conversation-search.js +2 -2
- package/dist/elements/cost-meter.js +1 -1
- package/dist/elements/data-table.js +1 -1
- package/dist/elements/diagram.js +1 -1
- package/dist/elements/draft-restore.js +2 -2
- package/dist/elements/edit-message.js +1 -1
- package/dist/elements/elements.css +134 -0
- package/dist/elements/elicitation-form.d.ts +8 -1
- package/dist/elements/elicitation-form.js +24 -16
- package/dist/elements/empty-state.js +3 -3
- package/dist/elements/error-state.js +2 -2
- package/dist/elements/event-feed.d.ts +88 -0
- package/dist/elements/event-feed.js +190 -0
- package/dist/elements/feedback-dialog.js +2 -2
- package/dist/elements/file-tree.js +1 -1
- package/dist/elements/flow-graph.js +2 -2
- package/dist/elements/generative.css +13 -0
- package/dist/elements/generative.d.ts +8 -6
- package/dist/elements/generative.js +4 -3
- package/dist/elements/image-generation.js +2 -2
- package/dist/elements/index.d.ts +7 -3
- package/dist/elements/index.js +5 -2
- package/dist/elements/inline-citation.js +1 -1
- package/dist/elements/job-progress.js +1 -1
- package/dist/elements/launcher-bubble.js +3 -3
- package/dist/elements/loading-state.js +1 -1
- package/dist/elements/map-answer.js +1 -1
- package/dist/elements/math-block.js +1 -1
- package/dist/elements/mcp-server-panel.js +3 -3
- package/dist/elements/memory-chips.js +1 -1
- package/dist/elements/message-attachment.js +3 -3
- package/dist/elements/message-branches.js +1 -1
- package/dist/elements/message-pair.js +2 -2
- package/dist/elements/message-queue.js +1 -1
- package/dist/elements/message-timing.js +1 -1
- package/dist/elements/mobile-composer.js +1 -1
- package/dist/elements/model-picker.js +1 -1
- package/dist/elements/number-ticker.js +1 -1
- package/dist/elements/onboarding.js +3 -3
- package/dist/elements/permission-grant.js +3 -3
- package/dist/elements/prompt-library.js +1 -1
- package/dist/elements/question-card.d.ts +50 -0
- package/dist/elements/question-card.js +117 -0
- package/dist/elements/queue-dock.js +1 -1
- package/dist/elements/quota-banner.js +1 -1
- package/dist/elements/quote-reply.js +3 -3
- package/dist/elements/read-aloud.js +2 -2
- package/dist/elements/reasoning-effort.js +2 -2
- package/dist/elements/reasoning-panel.js +3 -3
- package/dist/elements/recommendation-card.js +2 -2
- package/dist/elements/regenerate-menu.js +1 -1
- package/dist/elements/request-delivery.js +31 -0
- package/dist/elements/research-report.js +1 -1
- package/dist/elements/retrieval-chunks.js +3 -3
- package/dist/elements/revert-dock.js +1 -1
- package/dist/elements/reviewable-diff.js +4 -4
- package/dist/elements/schedule-card.js +2 -2
- package/dist/elements/score-breakdown.js +2 -2
- package/dist/elements/scroll-anchor.js +2 -2
- package/dist/elements/settings-panel.js +3 -3
- package/dist/elements/sources.js +1 -1
- package/dist/elements/spec-sheet.js +1 -1
- package/dist/elements/stopped-run.js +2 -2
- package/dist/elements/streaming-text.js +2 -2
- package/dist/elements/subagent-list.js +4 -4
- package/dist/elements/suggestions.js +1 -1
- package/dist/elements/surfaces.d.ts +6 -6
- package/dist/elements/surfaces.js +7 -7
- package/dist/elements/tail-status.js +1 -1
- package/dist/elements/terminal-block.js +1 -1
- package/dist/elements/thinking-indicator.js +1 -1
- package/dist/elements/timeline.js +1 -1
- package/dist/elements/todo-list.js +1 -1
- package/dist/elements/tool-call.d.ts +18 -2
- package/dist/elements/tool-call.js +20 -11
- package/dist/elements/tool-error.js +2 -2
- package/dist/elements/tool-group.d.ts +11 -3
- package/dist/elements/tool-group.js +62 -38
- package/dist/elements/tool-state.d.ts +13 -0
- package/dist/elements/tool-state.js +44 -0
- package/dist/elements/tool-timeline.js +2 -2
- package/dist/elements/trace-waterfall.js +2 -2
- package/dist/elements/unsupported-request-card.d.ts +31 -0
- package/dist/elements/unsupported-request-card.js +80 -0
- package/dist/elements/vocabulary.d.ts +50 -1
- package/dist/elements/vocabulary.js +50 -1
- package/dist/elements/voice-conversation.js +5 -5
- package/dist/elements/web-preview.js +1 -1
- package/dist/elements/web-search.js +2 -2
- package/dist/elements/work-collapse.js +1 -1
- package/dist/forms/file-upload.js +1 -1
- package/dist/forms/rating.js +1 -1
- package/dist/forms/select.js +1 -1
- package/dist/forms/switch.js +2 -2
- package/dist/forms/toggle.js +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/instruments/_ledger-disclosure.js +1 -1
- package/dist/instruments/data-tree.js +1 -1
- package/dist/instruments/meter.js +1 -1
- package/dist/instruments/seam-grid.js +1 -1
- package/dist/layout/_collapse.js +3 -3
- package/dist/layout/bento.js +1 -1
- package/dist/layout/breadcrumb.js +1 -1
- package/dist/layout/carousel.js +1 -1
- package/dist/layout/collapsible.js +1 -1
- package/dist/layout/index.d.ts +3 -1
- package/dist/layout/index.js +3 -1
- package/dist/layout/item.js +1 -1
- package/dist/layout/link.js +1 -1
- package/dist/layout/pagination.js +1 -1
- package/dist/layout/pane-seam.d.ts +75 -0
- package/dist/layout/pane-seam.js +127 -0
- package/dist/layout/resizable.d.ts +2 -1
- package/dist/layout/resizable.js +3 -2
- package/dist/layout/sidebar.js +3 -3
- package/dist/layout/split-pane.d.ts +74 -0
- package/dist/layout/split-pane.js +135 -0
- package/dist/layout/stepper.js +1 -1
- package/dist/lib/auto-grow.js +42 -0
- package/dist/overlays/_surface.d.ts +4 -4
- package/dist/overlays/_surface.js +4 -4
- package/dist/overlays/drawer.js +1 -1
- package/dist/overlays/menubar.js +1 -1
- package/dist/overlays/sheet.js +1 -1
- package/dist/overlays/toast.js +1 -1
- package/dist/primitives/button.js +1 -1
- package/dist/primitives/chip.d.ts +1 -1
- package/dist/system/agent-skin.d.ts +11 -5
- package/manifest/components/agent-surface.json +5 -4
- package/manifest/components/approval-card.json +45 -7
- package/manifest/components/composer-input.json +16 -2
- package/manifest/components/elicitation-form.json +16 -1
- package/manifest/components/event-feed.json +171 -0
- package/manifest/components/event-row.json +116 -0
- package/manifest/components/generative-ui.json +4 -3
- package/manifest/components/pane-seam.json +171 -0
- package/manifest/components/question-card.json +157 -0
- package/manifest/components/resizable.json +1 -1
- package/manifest/components/split-pane.json +224 -0
- package/manifest/components/tool-call.json +46 -2
- package/manifest/components/tool-group.json +15 -3
- package/manifest/components/unsupported-request-card.json +117 -0
- package/manifest/fixtures.json +16 -0
- package/manifest/manifest.json +88 -10
- package/manifest/tokens.json +9 -2
- package/package.json +2 -2
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useIsomorphicLayoutEffect } from "../system/use-isomorphic-layout-effect.js";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
//#region src/lib/auto-grow.ts
|
|
5
|
+
/** Whether this browser sizes a textarea to its content itself (`field-sizing: content`). */
|
|
6
|
+
function sizesItself() {
|
|
7
|
+
return typeof CSS !== "undefined" && typeof CSS.supports === "function" && CSS.supports("field-sizing", "content");
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Grow a textarea with what it holds, where CSS cannot.
|
|
11
|
+
*
|
|
12
|
+
* `field-sizing: content` sizes a textarea to its text in the browsers that
|
|
13
|
+
* have it, and a `max-height` caps it, so in those this does nothing. Where the
|
|
14
|
+
* property is missing, the textarea is measured instead: its height is reset
|
|
15
|
+
* and set to its `scrollHeight` on every input, and again whenever `value`
|
|
16
|
+
* changes from outside, so a composer the parent clears after sending shrinks
|
|
17
|
+
* back to one line. The cap stays the stylesheet's.
|
|
18
|
+
*
|
|
19
|
+
* Returns a ref for the textarea. A caller that passes its own `ref` after this
|
|
20
|
+
* one replaces it, and the field then sizes with CSS alone.
|
|
21
|
+
*
|
|
22
|
+
* @param value The textarea's value, so a change made from outside re-measures it.
|
|
23
|
+
*/
|
|
24
|
+
function useAutoGrow(value) {
|
|
25
|
+
const node = React.useRef(null);
|
|
26
|
+
const fit = React.useCallback(() => {
|
|
27
|
+
const element = node.current;
|
|
28
|
+
if (element === null || sizesItself()) return;
|
|
29
|
+
element.style.height = "auto";
|
|
30
|
+
element.style.height = `${element.scrollHeight}px`;
|
|
31
|
+
}, []);
|
|
32
|
+
const ref = React.useCallback((element) => {
|
|
33
|
+
node.current?.removeEventListener("input", fit);
|
|
34
|
+
node.current = element;
|
|
35
|
+
element?.addEventListener("input", fit);
|
|
36
|
+
fit();
|
|
37
|
+
}, [fit]);
|
|
38
|
+
useIsomorphicLayoutEffect(fit, [value, fit]);
|
|
39
|
+
return { ref };
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { useAutoGrow };
|
|
@@ -73,9 +73,9 @@ declare const overlaySurfaceClasses = "rounded-overlay border-transparent border
|
|
|
73
73
|
* composed declaration without entering it; at rest the property is theirs.
|
|
74
74
|
* The pseudo's `transition` and timing are its own classes: Tailwind
|
|
75
75
|
* registers `--tw-duration` and `--tw-ease` with `inherits: false`, so the
|
|
76
|
-
* scrim's `duration-
|
|
76
|
+
* scrim's `duration-fast ease-out` never reach it.
|
|
77
77
|
*/
|
|
78
|
-
declare const scrimClasses = "fixed inset-0 z-50 bg-(--cue-scrim) before:absolute before:inset-0 before:content-[''] before:pointer-events-none before:[backdrop-filter:var(--cue-paint-scrim-filter,none)] transition-[background-color,backdrop-filter] duration-
|
|
78
|
+
declare const scrimClasses = "fixed inset-0 z-50 bg-(--cue-scrim) before:absolute before:inset-0 before:content-[''] before:pointer-events-none before:[backdrop-filter:var(--cue-paint-scrim-filter,none)] transition-[background-color,backdrop-filter] duration-fast ease-out before:transition-opacity before:duration-fast before:ease-out motion-reduce:transition-none motion-reduce:before:transition-none data-[starting-style]:bg-transparent data-[ending-style]:bg-transparent data-[starting-style]:[backdrop-filter:none] data-[ending-style]:[backdrop-filter:none] data-[starting-style]:before:opacity-0 data-[ending-style]:before:opacity-0";
|
|
79
79
|
/**
|
|
80
80
|
* What a Base UI `Positioner` needs and nothing more: it is a layout box, not a
|
|
81
81
|
* painted one. The stacking context lives here so the popup itself can stay
|
|
@@ -88,14 +88,14 @@ declare const overlayPositionerClasses = "z-50 outline-none";
|
|
|
88
88
|
* transitions — no animation library, and nothing to run on the main thread
|
|
89
89
|
* when the user has asked for reduced motion.
|
|
90
90
|
*/
|
|
91
|
-
declare const overlayPopupTransitionClasses = "origin-(--transform-origin) transition-[opacity,scale] duration-
|
|
91
|
+
declare const overlayPopupTransitionClasses = "origin-(--transform-origin) transition-[opacity,scale] duration-instant ease-out motion-reduce:transition-none data-[starting-style]:scale-[0.98] data-[starting-style]:opacity-0 data-[ending-style]:scale-[0.98] data-[ending-style]:opacity-0";
|
|
92
92
|
/**
|
|
93
93
|
* Enter/exit for a centred modal surface. Split from
|
|
94
94
|
* {@link overlayPopupTransitionClasses} because a dialog is centred with a
|
|
95
95
|
* translate, and animating `scale` alongside a static `translate` needs the
|
|
96
96
|
* transition property list to name both.
|
|
97
97
|
*/
|
|
98
|
-
declare const overlayModalTransitionClasses = "transition-[opacity,scale] duration-
|
|
98
|
+
declare const overlayModalTransitionClasses = "transition-[opacity,scale] duration-fast ease-out motion-reduce:transition-none data-[starting-style]:scale-[0.98] data-[starting-style]:opacity-0 data-[ending-style]:scale-[0.98] data-[ending-style]:opacity-0";
|
|
99
99
|
/**
|
|
100
100
|
* Body copy inside an overlay: the body voice (mono unless a style set names
|
|
101
101
|
* another face — `_style-body.ts`), one rung under the panel's own text.
|
|
@@ -88,9 +88,9 @@ const overlaySurfaceClasses = `rounded-overlay ${STROKE_SURFACE_2} ${ELEVATION_2
|
|
|
88
88
|
* composed declaration without entering it; at rest the property is theirs.
|
|
89
89
|
* The pseudo's `transition` and timing are its own classes: Tailwind
|
|
90
90
|
* registers `--tw-duration` and `--tw-ease` with `inherits: false`, so the
|
|
91
|
-
* scrim's `duration-
|
|
91
|
+
* scrim's `duration-fast ease-out` never reach it.
|
|
92
92
|
*/
|
|
93
|
-
const scrimClasses = "fixed inset-0 z-50 bg-(--cue-scrim) before:absolute before:inset-0 before:content-[''] before:pointer-events-none before:[backdrop-filter:var(--cue-paint-scrim-filter,none)] transition-[background-color,backdrop-filter] duration-
|
|
93
|
+
const scrimClasses = "fixed inset-0 z-50 bg-(--cue-scrim) before:absolute before:inset-0 before:content-[''] before:pointer-events-none before:[backdrop-filter:var(--cue-paint-scrim-filter,none)] transition-[background-color,backdrop-filter] duration-fast ease-out before:transition-opacity before:duration-fast before:ease-out motion-reduce:transition-none motion-reduce:before:transition-none data-[starting-style]:bg-transparent data-[ending-style]:bg-transparent data-[starting-style]:[backdrop-filter:none] data-[ending-style]:[backdrop-filter:none] data-[starting-style]:before:opacity-0 data-[ending-style]:before:opacity-0";
|
|
94
94
|
/**
|
|
95
95
|
* What a Base UI `Positioner` needs and nothing more: it is a layout box, not a
|
|
96
96
|
* painted one. The stacking context lives here so the popup itself can stay
|
|
@@ -103,14 +103,14 @@ const overlayPositionerClasses = "z-50 outline-none";
|
|
|
103
103
|
* transitions — no animation library, and nothing to run on the main thread
|
|
104
104
|
* when the user has asked for reduced motion.
|
|
105
105
|
*/
|
|
106
|
-
const overlayPopupTransitionClasses = "origin-(--transform-origin) transition-[opacity,scale] duration-
|
|
106
|
+
const overlayPopupTransitionClasses = "origin-(--transform-origin) transition-[opacity,scale] duration-instant ease-out motion-reduce:transition-none data-[starting-style]:scale-[0.98] data-[starting-style]:opacity-0 data-[ending-style]:scale-[0.98] data-[ending-style]:opacity-0";
|
|
107
107
|
/**
|
|
108
108
|
* Enter/exit for a centred modal surface. Split from
|
|
109
109
|
* {@link overlayPopupTransitionClasses} because a dialog is centred with a
|
|
110
110
|
* translate, and animating `scale` alongside a static `translate` needs the
|
|
111
111
|
* transition property list to name both.
|
|
112
112
|
*/
|
|
113
|
-
const overlayModalTransitionClasses = "transition-[opacity,scale] duration-
|
|
113
|
+
const overlayModalTransitionClasses = "transition-[opacity,scale] duration-fast ease-out motion-reduce:transition-none data-[starting-style]:scale-[0.98] data-[starting-style]:opacity-0 data-[ending-style]:scale-[0.98] data-[ending-style]:opacity-0";
|
|
114
114
|
/**
|
|
115
115
|
* Body copy inside an overlay: the body voice (mono unless a style set names
|
|
116
116
|
* another face — `_style-body.ts`), one rung under the panel's own text.
|
package/dist/overlays/drawer.js
CHANGED
|
@@ -106,7 +106,7 @@ const Drawer$1 = {
|
|
|
106
106
|
children: /* @__PURE__ */ jsxs(Drawer.Popup, {
|
|
107
107
|
ref,
|
|
108
108
|
"data-slot": "drawer-popup",
|
|
109
|
-
className: cn(overlaySurfaceClasses, DRAWER_RADIUS, "flex flex-col overflow-y-auto overscroll-contain outline-none transition-transform duration-
|
|
109
|
+
className: cn(overlaySurfaceClasses, DRAWER_RADIUS, "flex flex-col overflow-y-auto overscroll-contain outline-none transition-transform duration-brisk ease-out data-[swiping]:duration-0 motion-reduce:transition-none", POPUP_GEOMETRY[direction], className),
|
|
110
110
|
...popupProps,
|
|
111
111
|
children: [grabHandle ? /* @__PURE__ */ jsx("div", {
|
|
112
112
|
"data-slot": "drawer-grab-handle",
|
package/dist/overlays/menubar.js
CHANGED
|
@@ -68,7 +68,7 @@ const Menubar$1 = {
|
|
|
68
68
|
return /* @__PURE__ */ jsx(Menu.Trigger, {
|
|
69
69
|
ref,
|
|
70
70
|
"data-slot": "menubar-trigger",
|
|
71
|
-
className: cn(`inline-flex h-control-sm shrink-0 cursor-default items-center rounded-control px-(--cue-space-3) text-(length:--cue-text-ui) whitespace-nowrap text-fg-muted transition-colors duration-
|
|
71
|
+
className: cn(`inline-flex h-control-sm shrink-0 cursor-default items-center rounded-control px-(--cue-space-3) text-(length:--cue-text-ui) whitespace-nowrap text-fg-muted transition-colors duration-fast outline-none select-none hover:text-fg ${FOCUS_RING_INSET} data-[popup-open]:bg-accent-soft data-[popup-open]:text-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-40`, CONTROL_FACE, className),
|
|
72
72
|
...elementProps
|
|
73
73
|
});
|
|
74
74
|
}),
|
package/dist/overlays/sheet.js
CHANGED
|
@@ -23,7 +23,7 @@ import { Dialog } from "@base-ui/react/dialog";
|
|
|
23
23
|
* into a corner; killing the outer edge is what makes it read as part of the
|
|
24
24
|
* window.
|
|
25
25
|
*/
|
|
26
|
-
const sheetPopupVariants = cva(`${overlaySurfaceClasses} fixed z-50 flex flex-col gap-(--cue-space-4) overflow-y-auto p-(--cue-space-6) outline-none transition-transform duration-
|
|
26
|
+
const sheetPopupVariants = cva(`${overlaySurfaceClasses} fixed z-50 flex flex-col gap-(--cue-space-4) overflow-y-auto p-(--cue-space-6) outline-none transition-transform duration-brisk ease-out motion-reduce:transition-none`, {
|
|
27
27
|
variants: { side: {
|
|
28
28
|
right: "inset-y-0 right-0 w-[min(28rem,calc(100vw-2rem))] rounded-r-none border-y-0 border-r-0 data-[starting-style]:translate-x-full data-[ending-style]:translate-x-full",
|
|
29
29
|
left: "inset-y-0 left-0 w-[min(28rem,calc(100vw-2rem))] rounded-l-none border-y-0 border-l-0 data-[starting-style]:-translate-x-full data-[ending-style]:-translate-x-full",
|
package/dist/overlays/toast.js
CHANGED
|
@@ -83,7 +83,7 @@ function ToastItem({ toast, className, closeLabel }) {
|
|
|
83
83
|
return /* @__PURE__ */ jsxs(Toast.Root, {
|
|
84
84
|
toast,
|
|
85
85
|
"data-slot": "toast-root",
|
|
86
|
-
className: cn(overlaySurfaceClasses, `relative flex flex-col gap-(--cue-space-1) border-l-2 ${TOAST_PAD_Y} pr-(--cue-space-6) ${TOAST_PAD_X} outline-none`, "transition-[opacity,translate] duration-
|
|
86
|
+
className: cn(overlaySurfaceClasses, `relative flex flex-col gap-(--cue-space-1) border-l-2 ${TOAST_PAD_Y} pr-(--cue-space-6) ${TOAST_PAD_X} outline-none`, "transition-[opacity,translate] duration-fast ease-out motion-reduce:transition-none", "data-[starting-style]:translate-x-2 data-[starting-style]:opacity-0", "data-[ending-style]:translate-x-2 data-[ending-style]:opacity-0", "data-[limited]:hidden", TOAST_TONE_RAIL[toToastTone(toast.type)], className),
|
|
87
87
|
children: [
|
|
88
88
|
/* @__PURE__ */ jsx(Toast.Title, {
|
|
89
89
|
"data-slot": "toast-title",
|
|
@@ -38,7 +38,7 @@ import { useRender } from "@base-ui/react/use-render";
|
|
|
38
38
|
*
|
|
39
39
|
* @internal Not part of the public API; imported by `icon-button.tsx`.
|
|
40
40
|
*/
|
|
41
|
-
const buttonChassis = `inline-flex select-none items-center justify-center ${CONTROL_GAP} whitespace-nowrap rounded-control ${CONTROL_FACE} ${CONTROL_WEIGHT} ${CONTROL_TRACKING} ${CONTROL_TRIM} ${CONTROL_CASE} transition-colors duration-
|
|
41
|
+
const buttonChassis = `inline-flex select-none items-center justify-center ${CONTROL_GAP} whitespace-nowrap rounded-control ${CONTROL_FACE} ${CONTROL_WEIGHT} ${CONTROL_TRACKING} ${CONTROL_TRIM} ${CONTROL_CASE} transition-colors duration-fast outline-none ${FOCUS_RING_PAINT} focus-visible:outline-offset-[var(--cue-style-focus-offset,1px)] disabled:pointer-events-none ${DISABLED_OPACITY}`;
|
|
42
42
|
/**
|
|
43
43
|
* A style set's chevron cut (structural Looks, spec 2026-10-02 §3.3), for the tones
|
|
44
44
|
* that are a filled shape: primary and danger always, secondary only where the set
|
|
@@ -2,7 +2,7 @@ import { ClassProp, VariantProps } from "../lib/cva.js";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
//#region src/primitives/chip.d.ts
|
|
4
4
|
declare const chipVariants: (props?: ({
|
|
5
|
-
tone?: "danger" | "info" | "warn" | "
|
|
5
|
+
tone?: "danger" | "info" | "warn" | "busy" | "accent" | "ok" | "neutral" | null | undefined;
|
|
6
6
|
variant?: "outline" | "tinted" | "tag" | null | undefined;
|
|
7
7
|
interactive?: boolean | null | undefined;
|
|
8
8
|
} & ClassProp) | undefined) => string;
|
|
@@ -9,18 +9,24 @@ import "react";
|
|
|
9
9
|
* - `aui` — supersede mode. `@cueplusplus/ui/elements.css` re-points those same
|
|
10
10
|
* tokens to assistant-ui's own values under `[data-cue-skin="aui"]`, so one
|
|
11
11
|
* DOM paints two ways with no branching in any component.
|
|
12
|
+
* - `cursor` — the same mechanism with Cursor's agent-pane values, under
|
|
13
|
+
* `[data-cue-skin="cursor"]`: the gallery study's palette, published so a
|
|
14
|
+
* consumer wears it rather than copying it. Its light and dark halves follow
|
|
15
|
+
* `data-mode`, as assistant-ui's do.
|
|
12
16
|
*/
|
|
13
|
-
type AgentSkin = "cue" | "aui";
|
|
17
|
+
type AgentSkin = "cue" | "aui" | "cursor";
|
|
14
18
|
/**
|
|
15
19
|
* How far the supersede island goes: colour only, or colour and geometry.
|
|
16
20
|
*
|
|
17
21
|
* - `cue-metrics` — the default. Colour is re-pointed; cue's type scale, radius
|
|
18
22
|
* ladder and density ladder still apply, so an island tracks the density of
|
|
19
23
|
* the console around it.
|
|
20
|
-
* - `upstream` —
|
|
21
|
-
* 12 / 11 px type
|
|
22
|
-
*
|
|
23
|
-
* element exactly as its authors
|
|
24
|
+
* - `upstream` — the skin's own geometry too. Under `aui` that is
|
|
25
|
+
* assistant-ui's radii, their literal 13.5 / 12 / 11 px type and `--spacing`
|
|
26
|
+
* pinned at Tailwind's default, so density stops at the island edge, which is
|
|
27
|
+
* the point: this is the mode for showing an element exactly as its authors
|
|
28
|
+
* drew it. Under `cursor` it is Cursor's corners and its two faces. Cursor's
|
|
29
|
+
* type sizes and spacing were never recorded, so those stay cue's.
|
|
24
30
|
*/
|
|
25
31
|
type AgentFidelity = "upstream" | "cue-metrics";
|
|
26
32
|
//#endregion
|
|
@@ -5,17 +5,18 @@
|
|
|
5
5
|
"importPath": "@cueplusplus/ui/elements",
|
|
6
6
|
"peerDependencies": [],
|
|
7
7
|
"clientOnly": true,
|
|
8
|
-
"description": "The supersede island: one subtree, painted by a different set of values.\n\nRenders a plain `<div data-slot=\"agent-surface\" data-cue-skin=\"…\"\ndata-cue-fidelity=\"…\">` and publishes the same pair on React context. The attributes do the work —\n`@cueplusplus/ui/elements.css` re-declares, under them, the `--cue-*` tokens\nthe whole elements family reads, and custom properties inherit, so every\nelement inside repaints with no prop threading and no branch in any\ncomponent. The context exists for the one place that cannot see the DOM: an\noverlay portaled to `<body>` from inside the island, which\n{@link useCuePortalProps } stamps from the same values.\n\nTwo things this is not. It is not a theme — `data-theme`, `data-mode` and\n`data-density` are untouched, and a light app keeps a light island. And it is\nnot needed for cue mode: the elements were rewritten onto cue's tokens by the\nvendoring codemod, so `skin=\"cue\"` is what they already do. Reach for this to\nshow an element the way assistant-ui drew it,
|
|
8
|
+
"description": "The supersede island: one subtree, painted by a different set of values.\n\nRenders a plain `<div data-slot=\"agent-surface\" data-cue-skin=\"…\"\ndata-cue-fidelity=\"…\">` and publishes the same pair on React context. The attributes do the work —\n`@cueplusplus/ui/elements.css` re-declares, under them, the `--cue-*` tokens\nthe whole elements family reads, and custom properties inherit, so every\nelement inside repaints with no prop threading and no branch in any\ncomponent. The context exists for the one place that cannot see the DOM: an\noverlay portaled to `<body>` from inside the island, which\n{@link useCuePortalProps } stamps from the same values.\n\nTwo things this is not. It is not a theme — `data-theme`, `data-mode` and\n`data-density` are untouched, and a light app keeps a light island. And it is\nnot needed for cue mode: the elements were rewritten onto cue's tokens by the\nvendoring codemod, so `skin=\"cue\"` is what they already do. Reach for this to\nshow an element the way assistant-ui drew it, to hand a chat panel back to\nupstream's design language inside a console that is otherwise cue's, or to\nwear Cursor's agent pane with `skin=\"cursor\"` rather than copying its palette.\n\nWhat an `aui` island re-points is this family's own vocabulary rather than the\nwhole token contract: `--cue-busy`, `--cue-info`, `--cue-selection`,\n`--cue-focus`, `--cue-scrim` and every derived `*-soft` / `*-border` stay on\nthe console's theme. Nothing in the elements group reads them, so the island\nis complete for what it is for — but a *cue* component placed inside one (a\n`Chip tone=\"busy\"`, a `Toast`) paints half in each palette, and the\nderivations cannot be made to follow at all: they are `color-mix()` values\nresolved on the theme block and inherited as answers. `elements.css` carries\nthe full accounting beside the values themselves.\n\n`elements.css` is a consumer import: `@import \"@cueplusplus/ui/elements.css\";`\nafter the main stylesheet. Without it a `skin=\"aui\"` island simply stays in\ncue's palette.",
|
|
9
9
|
"props": [
|
|
10
10
|
{
|
|
11
11
|
"name": "skin",
|
|
12
|
-
"type": "\"cue\" | \"aui\"",
|
|
12
|
+
"type": "\"cursor\" | \"cue\" | \"aui\"",
|
|
13
13
|
"required": false,
|
|
14
14
|
"defaultValue": "cue",
|
|
15
|
-
"description": "Which value-set paints the subtree: `cue` (the default)
|
|
15
|
+
"description": "Which value-set paints the subtree: `cue` (the default); `aui`, which\ninstalls assistant-ui's own inks, grounds and hues; or `cursor`, Cursor's\nagent-pane values. Both halves of each follow `data-mode`.",
|
|
16
16
|
"control": {
|
|
17
17
|
"kind": "enum",
|
|
18
18
|
"members": [
|
|
19
|
+
"cursor",
|
|
19
20
|
"cue",
|
|
20
21
|
"aui"
|
|
21
22
|
]
|
|
@@ -26,7 +27,7 @@
|
|
|
26
27
|
"type": "\"upstream\" | \"cue-metrics\"",
|
|
27
28
|
"required": false,
|
|
28
29
|
"defaultValue": "cue-metrics",
|
|
29
|
-
"description": "How much a supersede island re-points: `cue-metrics` (the default, colour\nonly) or `upstream`, which also pins
|
|
30
|
+
"description": "How much a supersede island re-points: `cue-metrics` (the default, colour\nonly) or `upstream`, which also pins the skin's own geometry. For `aui`\nthat is its radii, literal type sizes and spacing, so the density ladder\nstops at the island edge; for `cursor`, its corners and faces.",
|
|
30
31
|
"control": {
|
|
31
32
|
"kind": "enum",
|
|
32
33
|
"members": [
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"type": "(() => void)",
|
|
72
72
|
"required": false,
|
|
73
73
|
"defaultValue": null,
|
|
74
|
-
"description": "Called when the user clicks Always allow.",
|
|
74
|
+
"description": "Called when the user clicks Always allow. The button is drawn only when this is\nset, so a card never offers a standing grant nothing can honour.",
|
|
75
75
|
"control": {
|
|
76
76
|
"kind": "callback",
|
|
77
77
|
"fixture": "callback.log"
|
|
@@ -87,10 +87,46 @@
|
|
|
87
87
|
"kind": "callback",
|
|
88
88
|
"fixture": "callback.log"
|
|
89
89
|
}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"name": "options",
|
|
93
|
+
"type": "readonly ApprovalOption[]",
|
|
94
|
+
"required": false,
|
|
95
|
+
"defaultValue": null,
|
|
96
|
+
"description": "The decisions the agent offered, one button each and in this order. Replaces the\ndefault Deny, Always allow and Allow once.",
|
|
97
|
+
"control": {
|
|
98
|
+
"kind": "array"
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"name": "onDecide",
|
|
103
|
+
"type": "((id: string) => void)",
|
|
104
|
+
"required": false,
|
|
105
|
+
"defaultValue": null,
|
|
106
|
+
"description": "Called with an option's `id` when the user picks it.",
|
|
107
|
+
"control": {
|
|
108
|
+
"kind": "callback",
|
|
109
|
+
"fixture": "callback.log"
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"name": "delivery",
|
|
114
|
+
"type": "\"failed\" | \"sending\" | \"sent\"",
|
|
115
|
+
"required": false,
|
|
116
|
+
"defaultValue": null,
|
|
117
|
+
"description": "Where the answer has got to: `sending`, `sent` or `failed`. While it is on its way\nand once it has arrived, the card offers nothing to press. `failed` offers the\ndecisions again. An outcome `state` wins over it.",
|
|
118
|
+
"control": {
|
|
119
|
+
"kind": "enum",
|
|
120
|
+
"members": [
|
|
121
|
+
"failed",
|
|
122
|
+
"sending",
|
|
123
|
+
"sent"
|
|
124
|
+
]
|
|
125
|
+
}
|
|
90
126
|
}
|
|
91
127
|
],
|
|
92
128
|
"typeReferences": [
|
|
93
|
-
"Omit<\n ComponentProps<\"div\">,\n | \"children\"\n | \"state\"\n | \"command\"\n | \"title\"\n | \"subtitle\"\n | \"onAllowOnce\"\n | \"onAlwaysAllow\"\n | \"onDeny\"\n> & {\n /** Lifecycle of the card: request with actions, running spinner, done check, or denied. */\n state: ApprovalState;\n /** Command shown in the mono field the agent wants to run. */\n command: string;\n /** Headline naming the action that needs approval. */\n title: string;\n /** Supporting line under the title explaining the request. */\n subtitle: string;\n /** Called when the user clicks Allow once. */\n onAllowOnce?: () => void;\n
|
|
129
|
+
"Omit<\n ComponentProps<\"div\">,\n | \"children\"\n | \"state\"\n | \"command\"\n | \"title\"\n | \"subtitle\"\n | \"onAllowOnce\"\n | \"onAlwaysAllow\"\n | \"onDeny\"\n | \"options\"\n | \"onDecide\"\n | \"delivery\"\n> & {\n /** Lifecycle of the card: request with actions, running spinner, done check, or denied. */\n state: ApprovalState;\n /** Command shown in the mono field the agent wants to run. */\n command: string;\n /** Headline naming the action that needs approval. */\n title: string;\n /** Supporting line under the title explaining the request. */\n subtitle: string;\n /** Called when the user clicks Allow once. */\n onAllowOnce?: () => void;\n /**\n * Called when the user clicks Always allow. The button is drawn only when this is\n * set, so a card never offers a standing grant nothing can honour.\n */\n onAlwaysAllow?: () => void;\n /** Called when the user clicks Deny. */\n onDeny?: () => void;\n /**\n * The decisions the agent offered, one button each and in this order. Replaces the\n * default Deny, Always allow and Allow once.\n */\n options?: readonly ApprovalOption[];\n /** Called with an option's `id` when the user picks it. */\n onDecide?: (id: string) => void;\n /**\n * Where the answer has got to: `sending`, `sent` or `failed`. While it is on its way\n * and once it has arrived, the card offers nothing to press. `failed` offers the\n * decisions again. An outcome `state` wins over it.\n */\n delivery?: RequestDelivery;\n}"
|
|
94
130
|
],
|
|
95
131
|
"subcomponents": [],
|
|
96
132
|
"parts": [],
|
|
@@ -122,14 +158,16 @@
|
|
|
122
158
|
"jsonUrl": "/r/components/approval-card.json",
|
|
123
159
|
"whenToUse": [
|
|
124
160
|
"A command with side effects that must not run until someone says so.",
|
|
125
|
-
"Carrying that request through its whole lifecycle, since one card covers request, running, done and denied."
|
|
161
|
+
"Carrying that request through its whole lifecycle, since one card covers request, running, done and denied.",
|
|
162
|
+
"Drawing exactly the decisions the agent offered. Pass `options` with `onDecide`, and only those buttons appear."
|
|
126
163
|
],
|
|
127
164
|
"whenNotToUse": [
|
|
128
165
|
"A decision with no command behind it. `command` is required and is shown in a mono field.",
|
|
129
166
|
"Reporting a command that failed. The four states are request, running, done and denied; a failure needs somewhere else to go."
|
|
130
167
|
],
|
|
131
168
|
"commonMistakes": [
|
|
132
|
-
"Leaving `state=\"request\"` after the user has answered
|
|
169
|
+
"Leaving `state=\"request\"` after the user has answered with no `delivery`, so Allow and Deny stay pressable. Set `delivery=\"sending\"` as the answer leaves.",
|
|
170
|
+
"Passing a no-op `onAlwaysAllow`. Always allow is drawn only when the handler is set, so set it only when a standing grant can be honoured.",
|
|
133
171
|
"Folding the explanation into `title`. `title` names the action that needs approval; `subtitle` is the supporting line that explains it."
|
|
134
172
|
],
|
|
135
173
|
"specimens": [
|
|
@@ -139,9 +177,9 @@
|
|
|
139
177
|
"components": [
|
|
140
178
|
"ApprovalCard"
|
|
141
179
|
],
|
|
142
|
-
"code": "<Specimens>\n {APPROVALS.map((state) => (\n <Specimen key={state} label={state} wide>\n <ApprovalCard\n state={approvals[state] ?? state}\n command=\"cue unpatch --universe 4 --all\"\n title=\"Unpatch universe 4\"\n subtitle=\"48 channels stop responding until they are patched again.\"\n onAllowOnce={settle(state, \"running\")}\n onAlwaysAllow={settle(state, \"running\")}\n onDeny={settle(state, \"denied\")}\n />\n </Specimen>\n ))}\n</Specimens>",
|
|
143
|
-
"note": "Human in the loop for one action: the command in mono exactly as it will run, and
|
|
144
|
-
"interaction": "Allow once and Always allow are separate answers, never one control with a modifier. Denying settles the card rather than hiding it."
|
|
180
|
+
"code": "<Specimens>\n {APPROVALS.map((state) => (\n <Specimen key={state} label={state} wide>\n <ApprovalCard\n state={approvals[state] ?? state}\n command=\"cue unpatch --universe 4 --all\"\n title=\"Unpatch universe 4\"\n subtitle=\"48 channels stop responding until they are patched again.\"\n onAllowOnce={settle(state, \"running\")}\n onAlwaysAllow={settle(state, \"running\")}\n onDeny={settle(state, \"denied\")}\n />\n </Specimen>\n ))}\n <Specimen label=\"the agent's own decisions\" wide>\n <ApprovalCard\n state=\"request\"\n command=\"cue patch --universe 3 --fixtures 6\"\n title=\"Patch universe 3\"\n subtitle=\"The agent offered two answers, so the card draws two.\"\n options={[\n { id: \"reject\", label: \"Reject\" },\n { id: \"approve\", label: \"Approve\", tone: \"primary\" },\n ]}\n onDecide={() => {}}\n />\n </Specimen>\n <Specimen label=\"sending\" wide>\n <ApprovalCard\n state=\"request\"\n delivery=\"sending\"\n command=\"cue unpatch --universe 4 --all\"\n title=\"Unpatch universe 4\"\n subtitle=\"48 channels stop responding until they are patched again.\"\n />\n </Specimen>\n <Specimen label=\"not sent\" wide>\n <ApprovalCard\n state=\"request\"\n delivery=\"failed\"\n command=\"cue unpatch --universe 4 --all\"\n title=\"Unpatch universe 4\"\n subtitle=\"48 channels stop responding until they are patched again.\"\n onAllowOnce={() => {}}\n onDeny={() => {}}\n />\n </Specimen>\n</Specimens>",
|
|
181
|
+
"note": "Human in the loop for one action: the command in mono exactly as it will run, and the answers the agent offered. The first four specimens are the four states of the union, and the first one is live: answer it and it moves. Then a card drawing the agent's own two decisions rather than the default three, and two deliveries: an answer on its way, which offers nothing to press, and one that did not arrive, which offers the answers again.",
|
|
182
|
+
"interaction": "Allow once and Always allow are separate answers, never one control with a modifier, and Always allow is drawn only when something can honour it. Denying settles the card rather than hiding it."
|
|
145
183
|
}
|
|
146
184
|
]
|
|
147
185
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"lucide-react"
|
|
8
8
|
],
|
|
9
9
|
"clientOnly": true,
|
|
10
|
-
"description": "The text field. Enter
|
|
10
|
+
"description": "The text field: a textarea that grows with what it holds, to a cap. Enter sends and\nShift+Enter breaks the line, both guarded against IME composition so accepting a\ncandidate does not send the message.",
|
|
11
11
|
"props": [
|
|
12
12
|
{
|
|
13
13
|
"name": "onSubmit",
|
|
@@ -19,10 +19,24 @@
|
|
|
19
19
|
"kind": "callback",
|
|
20
20
|
"fixture": "callback.log"
|
|
21
21
|
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "size",
|
|
25
|
+
"type": "\"sm\" | \"md\"",
|
|
26
|
+
"required": false,
|
|
27
|
+
"defaultValue": "md",
|
|
28
|
+
"description": "`md` (the default) or `sm`: the smaller rung, a 36px floor with body type, for a\ncompact console.",
|
|
29
|
+
"control": {
|
|
30
|
+
"kind": "enum",
|
|
31
|
+
"members": [
|
|
32
|
+
"sm",
|
|
33
|
+
"md"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
22
36
|
}
|
|
23
37
|
],
|
|
24
38
|
"typeReferences": [
|
|
25
|
-
"Omit<ComponentProps<\"
|
|
39
|
+
"Omit<ComponentProps<\"textarea\">, \"onSubmit\"> & {\n /**\n * Called on Enter, guarded against IME composition so accepting a candidate does not\n * send.\n */\n onSubmit?: () => void;\n /**\n * `md` (the default) or `sm`: the smaller rung, a 36px floor with body type, for a\n * compact console.\n */\n size?: \"sm\" | \"md\";\n}"
|
|
26
40
|
],
|
|
27
41
|
"subcomponents": [],
|
|
28
42
|
"parts": [],
|
|
@@ -76,10 +76,25 @@
|
|
|
76
76
|
"kind": "callback",
|
|
77
77
|
"fixture": "callback.log"
|
|
78
78
|
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"name": "delivery",
|
|
82
|
+
"type": "\"failed\" | \"sending\" | \"sent\"",
|
|
83
|
+
"required": false,
|
|
84
|
+
"defaultValue": null,
|
|
85
|
+
"description": "Where the answer has got to: `sending`, `sent` or `failed`. While it is on its way\nand once it has arrived, the form offers nothing to press. `failed` offers Decline\nand Send again. An outcome `state` wins over it.",
|
|
86
|
+
"control": {
|
|
87
|
+
"kind": "enum",
|
|
88
|
+
"members": [
|
|
89
|
+
"failed",
|
|
90
|
+
"sending",
|
|
91
|
+
"sent"
|
|
92
|
+
]
|
|
93
|
+
}
|
|
79
94
|
}
|
|
80
95
|
],
|
|
81
96
|
"typeReferences": [
|
|
82
|
-
"Omit<\n ComponentProps<\"div\">,\n | \"children\"\n | \"server\"\n | \"message\"\n | \"fields\"\n | \"state\"\n | \"onAccept\"\n | \"onDecline\"\n> & {\n /** Which server paused to ask. */\n server: string;\n /** Why the input is needed, in the server's words. */\n message: string;\n /** The schema the server sent, already resolved to display values. */\n fields: readonly ElicitationField[];\n /** Swaps the action row for the outcome once the user answers. */\n state: ElicitationState;\n /** Called when the filled form is sent back. */\n onAccept?: () => void;\n /** Called when the request is refused. */\n onDecline?: () => void;\n}"
|
|
97
|
+
"Omit<\n ComponentProps<\"div\">,\n | \"children\"\n | \"server\"\n | \"message\"\n | \"fields\"\n | \"state\"\n | \"onAccept\"\n | \"onDecline\"\n | \"delivery\"\n> & {\n /** Which server paused to ask. */\n server: string;\n /** Why the input is needed, in the server's words. */\n message: string;\n /** The schema the server sent, already resolved to display values. */\n fields: readonly ElicitationField[];\n /** Swaps the action row for the outcome once the user answers. */\n state: ElicitationState;\n /** Called when the filled form is sent back. */\n onAccept?: () => void;\n /** Called when the request is refused. */\n onDecline?: () => void;\n /**\n * Where the answer has got to: `sending`, `sent` or `failed`. While it is on its way\n * and once it has arrived, the form offers nothing to press. `failed` offers Decline\n * and Send again. An outcome `state` wins over it.\n */\n delivery?: RequestDelivery;\n}"
|
|
83
98
|
],
|
|
84
99
|
"subcomponents": [],
|
|
85
100
|
"parts": [],
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "EventFeed",
|
|
3
|
+
"slug": "event-feed",
|
|
4
|
+
"group": "elements",
|
|
5
|
+
"importPath": "@cueplusplus/ui/elements",
|
|
6
|
+
"peerDependencies": [],
|
|
7
|
+
"clientOnly": true,
|
|
8
|
+
"description": "A filterable activity feed: timestamped, typed records with a one-line\npreview, and a selection the detail pane follows (#103).\n\nThe chips are built from the kinds present, in the order each first\nappears, each with its count, so a feed never offers a filter that keeps\nnothing. The rows are a listbox: j and k, or the arrows, move the selection\nthrough the rows the filter keeps, and Home and End jump to the ends. The\nselection follows the keyboard, so the detail beside it follows too.",
|
|
9
|
+
"props": [
|
|
10
|
+
{
|
|
11
|
+
"name": "label",
|
|
12
|
+
"type": "string",
|
|
13
|
+
"required": true,
|
|
14
|
+
"defaultValue": null,
|
|
15
|
+
"description": "The feed's accessible name: `Run events`.",
|
|
16
|
+
"control": {
|
|
17
|
+
"kind": "string"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "events",
|
|
22
|
+
"type": "readonly FeedEvent[]",
|
|
23
|
+
"required": true,
|
|
24
|
+
"defaultValue": null,
|
|
25
|
+
"description": "The records, oldest first or newest first: the feed keeps the order given.",
|
|
26
|
+
"control": {
|
|
27
|
+
"kind": "array",
|
|
28
|
+
"fixture": "agents.feed"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"name": "filter",
|
|
33
|
+
"type": "string",
|
|
34
|
+
"required": false,
|
|
35
|
+
"defaultValue": null,
|
|
36
|
+
"description": "The kind the feed keeps, or `all`, when the caller holds it.",
|
|
37
|
+
"control": {
|
|
38
|
+
"kind": "string"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "defaultFilter",
|
|
43
|
+
"type": "string",
|
|
44
|
+
"required": false,
|
|
45
|
+
"defaultValue": "all",
|
|
46
|
+
"description": "The kind to start on when nothing controls it. Defaults to `all`.",
|
|
47
|
+
"control": {
|
|
48
|
+
"kind": "string"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "onFilterChange",
|
|
53
|
+
"type": "((filter: string) => void)",
|
|
54
|
+
"required": false,
|
|
55
|
+
"defaultValue": null,
|
|
56
|
+
"description": "Called with the kind, or `all`, when a chip is pressed.",
|
|
57
|
+
"control": {
|
|
58
|
+
"kind": "callback",
|
|
59
|
+
"fixture": "callback.log"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "selectedId",
|
|
64
|
+
"type": "string | null",
|
|
65
|
+
"required": false,
|
|
66
|
+
"defaultValue": "null",
|
|
67
|
+
"description": "The selected event's `id`, or `null` for none.",
|
|
68
|
+
"control": {
|
|
69
|
+
"kind": "string",
|
|
70
|
+
"nullable": true
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "onSelect",
|
|
75
|
+
"type": "((id: string) => void)",
|
|
76
|
+
"required": false,
|
|
77
|
+
"defaultValue": null,
|
|
78
|
+
"description": "Called with an event's `id` when a row is clicked or the keyboard moves to it.",
|
|
79
|
+
"control": {
|
|
80
|
+
"kind": "callback",
|
|
81
|
+
"fixture": "callback.log"
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "formatTime",
|
|
86
|
+
"type": "((timestamp: string | number | Date) => string)",
|
|
87
|
+
"required": false,
|
|
88
|
+
"defaultValue": null,
|
|
89
|
+
"description": "Formats the time column. Defaults to a time of day for a `Date` or a number.",
|
|
90
|
+
"control": {
|
|
91
|
+
"kind": "callback",
|
|
92
|
+
"fixture": "callback.log"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"name": "labels",
|
|
97
|
+
"type": "Partial<EventFeedLabels>",
|
|
98
|
+
"required": false,
|
|
99
|
+
"defaultValue": null,
|
|
100
|
+
"description": "Replace any of the feed's own copy.",
|
|
101
|
+
"control": {
|
|
102
|
+
"kind": "opaque"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"typeReferences": [
|
|
107
|
+
"Omit<React.ComponentPropsWithoutRef<\"div\">, \"children\" | \"onSelect\">"
|
|
108
|
+
],
|
|
109
|
+
"subcomponents": [],
|
|
110
|
+
"parts": [],
|
|
111
|
+
"variants": {},
|
|
112
|
+
"defaultVariants": {},
|
|
113
|
+
"tokensUsed": [
|
|
114
|
+
"--cue-accent",
|
|
115
|
+
"--cue-border",
|
|
116
|
+
"--cue-danger",
|
|
117
|
+
"--cue-fg",
|
|
118
|
+
"--cue-fg-muted",
|
|
119
|
+
"--cue-fg-subtle",
|
|
120
|
+
"--cue-focus",
|
|
121
|
+
"--cue-focus-ring",
|
|
122
|
+
"--cue-ok",
|
|
123
|
+
"--cue-radius-control",
|
|
124
|
+
"--cue-space-1",
|
|
125
|
+
"--cue-space-2",
|
|
126
|
+
"--cue-space-3",
|
|
127
|
+
"--cue-stream",
|
|
128
|
+
"--cue-style-focus-width",
|
|
129
|
+
"--cue-surface-2",
|
|
130
|
+
"--cue-text-label",
|
|
131
|
+
"--cue-text-ui",
|
|
132
|
+
"--cue-warn"
|
|
133
|
+
],
|
|
134
|
+
"summary": "A filterable activity feed: typed, timestamped records with a one-line preview and a selection.",
|
|
135
|
+
"examples": [
|
|
136
|
+
{
|
|
137
|
+
"title": "Usage",
|
|
138
|
+
"code": "const [selected, setSelected] = React.useState<string | null>(null);\n\n<EventFeed\n label=\"Run events\"\n events={events}\n selectedId={selected}\n onSelect={setSelected}\n/>",
|
|
139
|
+
"language": "tsx"
|
|
140
|
+
}
|
|
141
|
+
],
|
|
142
|
+
"status": "stable",
|
|
143
|
+
"url": "/docs/components/event-feed",
|
|
144
|
+
"mdUrl": "/docs/components/event-feed.md",
|
|
145
|
+
"jsonUrl": "/r/components/event-feed.json",
|
|
146
|
+
"whenToUse": [
|
|
147
|
+
"Inspecting a run beside its transcript: tool calls, permission asks, compactions, errors.",
|
|
148
|
+
"Any stream of typed records outside agents: MCP logs, device heartbeats, billing events, CI steps."
|
|
149
|
+
],
|
|
150
|
+
"whenNotToUse": [
|
|
151
|
+
"The conversation itself. Tool calls in the transcript are `ToolGroup`'s; this is the list beside it.",
|
|
152
|
+
"Raw log lines with ANSI colour. `LogViewer`, from `@cueplusplus/ui/instruments/log-viewer`, reads those."
|
|
153
|
+
],
|
|
154
|
+
"commonMistakes": [
|
|
155
|
+
"Drawing the detail inside the feed. The feed reports a selection; put the detail in `SplitPane`'s `detail` slot.",
|
|
156
|
+
"Kinds that are sentences. Each kind becomes a chip, so keep them to a word: `tool`, `permission`, `error`.",
|
|
157
|
+
"Formatting time strings and also passing `formatTime`. A string timestamp is drawn as given; pass a `Date` or a number to have it formatted."
|
|
158
|
+
],
|
|
159
|
+
"specimens": [
|
|
160
|
+
{
|
|
161
|
+
"title": "EventFeed",
|
|
162
|
+
"group": "elements",
|
|
163
|
+
"components": [
|
|
164
|
+
"EventFeed"
|
|
165
|
+
],
|
|
166
|
+
"code": "<div className=\"w-full max-w-md\">\n <EventFeed\n label=\"Patch run events\"\n events={RUN_EVENTS}\n selectedId={runEvent}\n onSelect={setRunEvent}\n />\n</div>",
|
|
167
|
+
"note": "The inspector beside a transcript: typed records, each a time, a toned dot, a kind, a title and a one-line preview. The chips are built from the kinds present, each with its count, so no chip keeps nothing. The detail is the host's: in a console it goes in SplitPane's detail slot.",
|
|
168
|
+
"interaction": "press a chip to keep one kind. Tab into the list, then j and k, or the arrows, move the selection through the rows the filter keeps, and Home and End jump to the ends."
|
|
169
|
+
}
|
|
170
|
+
]
|
|
171
|
+
}
|