@nadicodeai/ui 10.0.2 → 12.1.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/AGENTS.md +39 -24
- package/README.md +58 -124
- package/dist/agent-orb.d.ts +1 -1
- package/dist/agent-orb.d.ts.map +1 -1
- package/dist/assets/brand/index.json +1 -1
- package/dist/components/action-menu.js +1 -1
- package/dist/components/agent-card.d.ts.map +1 -1
- package/dist/components/agent-card.js +2 -4
- package/dist/components/agent-orb.d.ts +11 -5
- package/dist/components/agent-orb.d.ts.map +1 -1
- package/dist/components/agent-orb.js +8 -6
- package/dist/components/alert.js +3 -3
- package/dist/components/badge.js +6 -6
- package/dist/components/brand-field.d.ts +2 -0
- package/dist/components/brand-field.d.ts.map +1 -1
- package/dist/components/brand-field.js +3 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/button.d.ts.map +1 -1
- package/dist/components/button.js +4 -5
- package/dist/components/carousel.js +2 -2
- package/dist/components/chart-bar-horizontal.js +1 -1
- package/dist/components/chart.js +1 -1
- package/dist/components/command.js +1 -1
- package/dist/components/context-menu.js +1 -1
- package/dist/components/diff-count.js +1 -1
- package/dist/components/dropdown-menu.js +3 -3
- package/dist/components/footer.d.ts +15 -9
- package/dist/components/footer.d.ts.map +1 -1
- package/dist/components/footer.js +6 -27
- package/dist/components/item.js +1 -1
- package/dist/components/kpi-card.js +2 -2
- package/dist/components/label-system.d.ts +1 -5
- package/dist/components/label-system.d.ts.map +1 -1
- package/dist/components/label-system.js +2 -6
- package/dist/components/menu-choice-row.js +1 -1
- package/dist/components/menubar.js +1 -1
- package/dist/components/object-workspace.js +1 -1
- package/dist/components/progress.js +1 -1
- package/dist/components/scope-switcher.d.ts +24 -0
- package/dist/components/scope-switcher.d.ts.map +1 -0
- package/dist/components/scope-switcher.js +34 -0
- package/dist/components/settings-section.d.ts +2 -1
- package/dist/components/settings-section.d.ts.map +1 -1
- package/dist/components/settings-section.js +2 -2
- package/dist/components/status-dot.js +1 -1
- package/dist/components/status-row.js +1 -1
- package/dist/components/table.d.ts.map +1 -1
- package/dist/components/table.js +1 -1
- package/dist/components/tabs.d.ts +11 -5
- package/dist/components/tabs.d.ts.map +1 -1
- package/dist/components/tabs.js +37 -5
- package/dist/components/tooltip.js +1 -1
- package/dist/components/trend-badge.d.ts.map +1 -1
- package/dist/components/trend-badge.js +1 -2
- package/dist/eslint/index.js +4 -0
- package/dist/eslint/rules/jsx-class-utility.js +1 -1
- package/dist/eslint/rules/no-shadcn-appearance-override.js +3 -3
- package/dist/eslint/rules/one-control-height.js +94 -0
- package/dist/eslint/rules/settings-section-description.js +45 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/agent-orb-motion.d.ts +1 -0
- package/dist/internal/agent-orb-motion.d.ts.map +1 -1
- package/dist/internal/agent-orb-motion.js +6 -3
- package/dist/internal/agent-orb.d.ts +10 -2
- package/dist/internal/agent-orb.d.ts.map +1 -1
- package/dist/internal/agent-orb.js +19 -9
- package/dist/internal/assistant-ui/attachment.js +4 -4
- package/dist/internal/assistant-ui/follow-up-suggestions.js +1 -1
- package/dist/internal/assistant-ui/markdown-text.js +4 -4
- package/dist/internal/assistant-ui/reasoning.js +2 -2
- package/dist/internal/assistant-ui/thread.d.ts.map +1 -1
- package/dist/internal/assistant-ui/thread.js +11 -9
- package/dist/internal/assistant-ui/tool-group.js +2 -2
- package/dist/styles/components.css +9 -5
- package/dist/styles/globals.css +43 -0
- package/package.json +3 -4
- package/dist/components/handoff-banner.d.ts +0 -9
- package/dist/components/handoff-banner.d.ts.map +0 -1
- package/dist/components/handoff-banner.js +0 -6
- package/docs/activity.md +0 -113
- package/docs/agent-orb.md +0 -168
- package/docs/component-classification.md +0 -45
- package/docs/consuming-cross-repo.md +0 -116
- package/docs/contract.md +0 -388
- package/docs/icon-assets.md +0 -106
- package/docs/migration/1.0.0.md +0 -75
- package/docs/migration/10.0.0.md +0 -144
- package/docs/migration/2.0.0.md +0 -69
- package/docs/migration/6.0.0.md +0 -30
- package/docs/migration/9.0.0.md +0 -35
- package/docs/migration/base-ui-migration.md +0 -62
- package/docs/model-identity.md +0 -18
- package/docs/product-compositions.md +0 -96
- package/docs/product-sections.md +0 -200
|
@@ -7,7 +7,9 @@ import { Reasoning, ReasoningContent, ReasoningRoot, ReasoningText, ReasoningTri
|
|
|
7
7
|
import { ToolFallback } from "./tool-fallback.js";
|
|
8
8
|
import { ToolGroupContent, ToolGroupRoot, ToolGroupTrigger, } from "./tool-group.js";
|
|
9
9
|
import { TooltipIconButton } from "./tooltip-icon-button.js";
|
|
10
|
+
import { AgentOrb } from "../../components/agent-orb.js";
|
|
10
11
|
import { Button } from "../../components/button.js";
|
|
12
|
+
import { Alert } from "../../components/alert.js";
|
|
11
13
|
import { cn } from "../../lib/utils.js";
|
|
12
14
|
import { ActionBarMorePrimitive, ActionBarPrimitive, AuiIf, BranchPickerPrimitive, ComposerPrimitive, ErrorPrimitive, groupPartByType, MessagePrimitive, SuggestionPrimitive, ThreadPrimitive, useAuiState, } from "@assistant-ui/react";
|
|
13
15
|
import { ArrowDownIcon, ArrowUpIcon, CheckIcon, ChevronLeftIcon, ChevronRightIcon, CopyIcon, DownloadIcon, MicIcon, MoreHorizontalIcon, PencilIcon, RefreshCwIcon, SquareIcon, } from "lucide-react";
|
|
@@ -26,7 +28,7 @@ const ThreadRoot = ({ isEmpty }) => {
|
|
|
26
28
|
return (_jsx(ThreadPrimitive.Root, { className: "aui-root aui-thread-root bg-background @container flex h-full flex-col", style: {
|
|
27
29
|
["--thread-max-width"]: "44rem",
|
|
28
30
|
["--composer-bg"]: "var(--color-muted)",
|
|
29
|
-
["--composer-radius"]: "
|
|
31
|
+
["--composer-radius"]: "var(--radius-md)",
|
|
30
32
|
["--composer-padding"]: "8px",
|
|
31
33
|
}, children: _jsx(ThreadPrimitive.Viewport, { turnAnchor: "top", "data-slot": "aui_thread-viewport", className: "relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth", children: _jsxs("div", { className: cn("mx-auto flex w-full max-w-(--thread-max-width) flex-1 flex-col px-4 pt-4", isEmpty && "justify-center"), children: [_jsx(AuiIf, { condition: isNewChatView, children: _jsx(Welcome, {}) }), _jsx("div", { "data-slot": "aui_message-group", className: "mb-14 flex flex-col gap-y-6 empty:hidden", children: _jsx(ThreadPrimitive.Messages, { children: () => _jsx(ThreadMessage, {}) }) }), _jsxs(ThreadPrimitive.ViewportFooter, { className: cn("aui-thread-viewport-footer bg-background flex flex-col gap-4 overflow-visible pb-4 md:pb-6", !isEmpty && "sticky bottom-0 mt-auto rounded-t-(--composer-radius)"), children: [_jsx(ThreadScrollToBottom, {}), _jsx(ThreadFollowupSuggestions, {}), _jsx(Composer, {}), _jsx(AuiIf, { condition: (s) => isNewChatView(s) && s.composer.isEmpty, children: _jsx(ThreadSuggestions, {}) })] })] }) }) }));
|
|
32
34
|
};
|
|
@@ -41,7 +43,7 @@ const ThreadMessage = () => {
|
|
|
41
43
|
return _jsx(AssistantMessageComponent, {});
|
|
42
44
|
};
|
|
43
45
|
const ThreadScrollToBottom = () => {
|
|
44
|
-
return (_jsx(ThreadPrimitive.ScrollToBottom, { render: _jsx(TooltipIconButton, { tooltip: "Scroll to bottom", variant: "outline", className: "aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center rounded-
|
|
46
|
+
return (_jsx(ThreadPrimitive.ScrollToBottom, { render: _jsx(TooltipIconButton, { tooltip: "Scroll to bottom", variant: "outline", className: "aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center rounded-md p-4 disabled:invisible" }), children: _jsx(ArrowDownIcon, {}) }));
|
|
45
47
|
};
|
|
46
48
|
const ThreadWelcome = () => {
|
|
47
49
|
return (_jsx("div", { className: "aui-thread-welcome-root mb-6 flex flex-col items-center px-4 text-center", children: _jsx("h1", { className: "aui-thread-welcome-message-inner text-2xl font-semibold", children: "How can I help you today?" }) }));
|
|
@@ -50,16 +52,16 @@ const ThreadSuggestions = () => {
|
|
|
50
52
|
return (_jsx("div", { className: "aui-thread-welcome-suggestions flex w-full flex-wrap items-center justify-center gap-2 px-4", children: _jsx(ThreadPrimitive.Suggestions, { children: () => _jsx(ThreadSuggestionItem, {}) }) }));
|
|
51
53
|
};
|
|
52
54
|
const ThreadSuggestionItem = () => {
|
|
53
|
-
return (_jsx("div", { className: "aui-thread-welcome-suggestion-display", children: _jsxs(SuggestionPrimitive.Trigger, { send: true, render: _jsx(Button, { variant: "ghost", className: "aui-thread-welcome-suggestion text-foreground hover:bg-muted border-border
|
|
55
|
+
return (_jsx("div", { className: "aui-thread-welcome-suggestion-display", children: _jsxs(SuggestionPrimitive.Trigger, { send: true, render: _jsx(Button, { variant: "ghost", className: "aui-thread-welcome-suggestion text-foreground hover:bg-muted border-border h-auto gap-1.5 rounded-md border px-3.5 py-1.5 text-sm font-normal whitespace-nowrap transition-colors" }), children: [_jsx(SuggestionPrimitive.Title, { className: "aui-thread-welcome-suggestion-text-1" }), _jsx(SuggestionPrimitive.Description, { className: "aui-thread-welcome-suggestion-text-2 empty:hidden" })] }) }));
|
|
54
56
|
};
|
|
55
57
|
const Composer = () => {
|
|
56
58
|
return (_jsx(ComposerPrimitive.Root, { className: "aui-composer-root relative flex w-full flex-col", children: _jsxs(ComposerPrimitive.AttachmentDropzone, { render: _jsx("div", { "data-slot": "aui_composer-shell", className: "nc-transition-paint flex w-full flex-col gap-2 rounded-(--composer-radius) border border-border bg-(--composer-bg) p-(--composer-padding) focus-within:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:border-ring data-[dragging=true]:bg-accent" }), children: [_jsx(ComposerAttachments, {}), _jsx(ComposerPrimitive.Input, { placeholder: "Send a message...", className: "aui-composer-input caret-primary placeholder:text-muted-foreground/80 max-h-32 min-h-10 w-full resize-none bg-transparent px-2.5 py-1 text-base outline-none", rows: 1, autoFocus: true, enterKeyHint: "send", "aria-label": "Message input" }), _jsx(ComposerAction, {})] }) }));
|
|
57
59
|
};
|
|
58
60
|
const ComposerAction = () => {
|
|
59
|
-
return (_jsxs("div", { className: "aui-composer-action-wrapper relative flex items-center justify-between", children: [_jsx(ComposerAddAttachment, {}), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs(AuiIf, { condition: (s) => s.thread.capabilities.dictation, children: [_jsx(AuiIf, { condition: (s) => s.composer.dictation == null, children: _jsx(ComposerPrimitive.Dictate, { render: _jsx(TooltipIconButton, { tooltip: "Voice input", side: "bottom", type: "button", variant: "ghost", size: "icon", className: "aui-composer-dictate size-7 rounded-
|
|
61
|
+
return (_jsxs("div", { className: "aui-composer-action-wrapper relative flex items-center justify-between", children: [_jsx(ComposerAddAttachment, {}), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs(AuiIf, { condition: (s) => s.thread.capabilities.dictation, children: [_jsx(AuiIf, { condition: (s) => s.composer.dictation == null, children: _jsx(ComposerPrimitive.Dictate, { render: _jsx(TooltipIconButton, { tooltip: "Voice input", side: "bottom", type: "button", variant: "ghost", size: "icon", className: "aui-composer-dictate size-7 rounded-md", "aria-label": "Start voice input" }), children: _jsx(MicIcon, { className: "aui-composer-dictate-icon size-4" }) }) }), _jsx(AuiIf, { condition: (s) => s.composer.dictation != null, children: _jsx(ComposerPrimitive.StopDictation, { render: _jsx(TooltipIconButton, { tooltip: "Stop dictation", side: "bottom", type: "button", variant: "ghost", size: "icon", className: "aui-composer-stop-dictation text-destructive size-7 rounded-md", "aria-label": "Stop voice input" }), children: _jsx(SquareIcon, { className: "aui-composer-stop-dictation-icon size-3.5 fill-current" }) }) })] }), _jsx(AuiIf, { condition: (s) => !s.thread.isRunning, children: _jsx(ComposerPrimitive.Send, { render: _jsx(TooltipIconButton, { tooltip: "Send message", side: "bottom", type: "button", variant: "default", size: "icon", className: "aui-composer-send size-7 rounded-md", "aria-label": "Send message" }), children: _jsx(ArrowUpIcon, { className: "aui-composer-send-icon size-4.5" }) }) }), _jsx(AuiIf, { condition: (s) => s.thread.isRunning, children: _jsx(ComposerPrimitive.Cancel, { render: _jsx(Button, { type: "button", variant: "default", size: "icon", className: "aui-composer-cancel size-7 rounded-md", "aria-label": "Stop generating" }), children: _jsx(SquareIcon, { className: "aui-composer-cancel-icon size-3.5 fill-current" }) }) })] })] }));
|
|
60
62
|
};
|
|
61
63
|
const MessageError = () => {
|
|
62
|
-
return (_jsx(MessagePrimitive.Error, { children: _jsx(ErrorPrimitive.Root, { className: "aui-message-error-root mt-2
|
|
64
|
+
return (_jsx(MessagePrimitive.Error, { children: _jsx(ErrorPrimitive.Root, { render: _jsx(Alert, { className: "aui-message-error-root mt-2", variant: "destructive" }), children: _jsx(ErrorPrimitive.Message, { className: "aui-message-error-message line-clamp-2" }) }) }));
|
|
63
65
|
};
|
|
64
66
|
const AssistantMessage = () => {
|
|
65
67
|
const { ToolFallback: ToolFallbackComponent = ToolFallback, ToolGroup, ReasoningGroup, } = useContext(ThreadComponentsContext);
|
|
@@ -95,23 +97,23 @@ const AssistantMessage = () => {
|
|
|
95
97
|
case "data":
|
|
96
98
|
return part.dataRendererUI;
|
|
97
99
|
case "indicator":
|
|
98
|
-
return (_jsx("span", { "data-slot": "aui_assistant-message-indicator", className: "
|
|
100
|
+
return (_jsx("span", { "data-slot": "aui_assistant-message-indicator", className: "inline-flex", children: _jsx(AgentOrb, { form: "orbit", size: 20, state: "working", label: "Assistant is working" }) }));
|
|
99
101
|
default:
|
|
100
102
|
return null;
|
|
101
103
|
}
|
|
102
104
|
} }), _jsx(MessageError, {})] }), _jsxs("div", { "data-slot": "aui_assistant-message-footer", className: cn("ms-2 flex items-center", ACTION_BAR_HEIGHT), children: [_jsx(BranchPicker, {}), _jsx(AssistantActionBar, {})] })] }));
|
|
103
105
|
};
|
|
104
106
|
const AssistantActionBar = () => {
|
|
105
|
-
return (_jsxs(ActionBarPrimitive.Root, { hideWhenRunning: true, autohide: "not-last", className: "aui-assistant-action-bar-root nc-transition-opacity col-start-3 row-start-2 -ms-1 flex gap-1 text-muted-foreground", children: [_jsxs(ActionBarPrimitive.Copy, { render: _jsx(TooltipIconButton, { tooltip: "Copy" }), children: [_jsx(AuiIf, { condition: (s) => s.message.isCopied, children: _jsx(CheckIcon, {}) }), _jsx(AuiIf, { condition: (s) => !s.message.isCopied, children: _jsx(CopyIcon, {}) })] }), _jsx(ActionBarPrimitive.Reload, { render: _jsx(TooltipIconButton, { tooltip: "Refresh" }), children: _jsx(RefreshCwIcon, {}) }), _jsxs(ActionBarMorePrimitive.Root, { children: [_jsx(ActionBarMorePrimitive.Trigger, { render: _jsx(TooltipIconButton, { tooltip: "More", className: "data-[state=open]:bg-accent" }), children: _jsx(MoreHorizontalIcon, {}) }), _jsx(ActionBarMorePrimitive.Content, { side: "bottom", align: "start", sideOffset: 6, className: "aui-action-bar-more-content nc-transition-opacity z-50 min-w-[8rem] overflow-hidden rounded-
|
|
107
|
+
return (_jsxs(ActionBarPrimitive.Root, { hideWhenRunning: true, autohide: "not-last", className: "aui-assistant-action-bar-root nc-transition-opacity col-start-3 row-start-2 -ms-1 flex gap-1 text-muted-foreground", children: [_jsxs(ActionBarPrimitive.Copy, { render: _jsx(TooltipIconButton, { tooltip: "Copy" }), children: [_jsx(AuiIf, { condition: (s) => s.message.isCopied, children: _jsx(CheckIcon, {}) }), _jsx(AuiIf, { condition: (s) => !s.message.isCopied, children: _jsx(CopyIcon, {}) })] }), _jsx(ActionBarPrimitive.Reload, { render: _jsx(TooltipIconButton, { tooltip: "Refresh" }), children: _jsx(RefreshCwIcon, {}) }), _jsxs(ActionBarMorePrimitive.Root, { children: [_jsx(ActionBarMorePrimitive.Trigger, { render: _jsx(TooltipIconButton, { tooltip: "More", className: "data-[state=open]:bg-accent" }), children: _jsx(MoreHorizontalIcon, {}) }), _jsx(ActionBarMorePrimitive.Content, { side: "bottom", align: "start", sideOffset: 6, className: "aui-action-bar-more-content nc-transition-opacity z-50 min-w-[8rem] overflow-hidden rounded-md border-0 bg-popover p-1.5 text-popover-foreground nc-elevation-floating data-[state=closed]:opacity-0 data-[state=open]:opacity-100", children: _jsxs(ActionBarPrimitive.ExportMarkdown, { render: _jsx(ActionBarMorePrimitive.Item, { className: "aui-action-bar-more-item hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground flex cursor-pointer items-center gap-2 rounded-md px-2.5 py-1.5 text-sm outline-none select-none" }), children: [_jsx(DownloadIcon, { className: "size-4" }), "Export as Markdown"] }) })] })] }));
|
|
106
108
|
};
|
|
107
109
|
const UserMessage = () => {
|
|
108
|
-
return (_jsxs(MessagePrimitive.Root, { "data-slot": "aui_user-message-root", className: "grid auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 [contain-intrinsic-size:auto_200px] [content-visibility:auto] [&:where(>*)]:col-start-2", "data-role": "user", children: [_jsx(UserMessageAttachments, {}), _jsxs("div", { className: "aui-user-message-content-wrapper relative col-start-2 min-w-0", children: [_jsx("div", { className: "aui-user-message-content peer bg-muted text-foreground rounded-
|
|
110
|
+
return (_jsxs(MessagePrimitive.Root, { "data-slot": "aui_user-message-root", className: "grid auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 [contain-intrinsic-size:auto_200px] [content-visibility:auto] [&:where(>*)]:col-start-2", "data-role": "user", children: [_jsx(UserMessageAttachments, {}), _jsxs("div", { className: "aui-user-message-content-wrapper relative col-start-2 min-w-0", children: [_jsx("div", { className: "aui-user-message-content peer bg-muted text-foreground rounded-md px-4 py-2 wrap-break-word empty:hidden", children: _jsx(MessagePrimitive.Parts, {}) }), _jsx("div", { className: "aui-user-action-bar-wrapper absolute start-0 top-1/2 -translate-x-full -translate-y-1/2 pe-2 peer-empty:hidden rtl:translate-x-full", children: _jsx(UserActionBar, {}) })] }), _jsx(BranchPicker, { "data-slot": "aui_user-branch-picker", className: "col-span-full col-start-1 row-start-3 -me-1 justify-end" })] }));
|
|
109
111
|
};
|
|
110
112
|
const UserActionBar = () => {
|
|
111
113
|
return (_jsx(ActionBarPrimitive.Root, { hideWhenRunning: true, autohide: "not-last", className: "aui-user-action-bar-root flex flex-col items-end", children: _jsx(ActionBarPrimitive.Edit, { render: _jsx(TooltipIconButton, { tooltip: "Edit", className: "aui-user-action-edit" }), children: _jsx(PencilIcon, {}) }) }));
|
|
112
114
|
};
|
|
113
115
|
const EditComposer = () => {
|
|
114
|
-
return (_jsx(MessagePrimitive.Root, { "data-slot": "aui_edit-composer-wrapper", className: "flex flex-col px-2 [contain-intrinsic-size:auto_200px] [content-visibility:auto]", children: _jsxs(ComposerPrimitive.Root, { className: "aui-edit-composer-root ms-auto flex w-full max-w-[85%] flex-col rounded-(--composer-radius) border border-border bg-(--composer-bg)", children: [_jsx(ComposerPrimitive.Input, { className: "aui-edit-composer-input text-foreground min-h-14 w-full resize-none bg-transparent px-4 pt-3 pb-1 text-base outline-none", autoFocus: true }), _jsxs("div", { className: "aui-edit-composer-footer mx-2.5 mb-2.5 flex items-center gap-1.5 self-end", children: [_jsx(ComposerPrimitive.Cancel, { render: _jsx(Button, { variant: "ghost", size: "sm", className: "h-8
|
|
116
|
+
return (_jsx(MessagePrimitive.Root, { "data-slot": "aui_edit-composer-wrapper", className: "flex flex-col px-2 [contain-intrinsic-size:auto_200px] [content-visibility:auto]", children: _jsxs(ComposerPrimitive.Root, { className: "aui-edit-composer-root ms-auto flex w-full max-w-[85%] flex-col rounded-(--composer-radius) border border-border bg-(--composer-bg)", children: [_jsx(ComposerPrimitive.Input, { className: "aui-edit-composer-input text-foreground min-h-14 w-full resize-none bg-transparent px-4 pt-3 pb-1 text-base outline-none", autoFocus: true }), _jsxs("div", { className: "aui-edit-composer-footer mx-2.5 mb-2.5 flex items-center gap-1.5 self-end", children: [_jsx(ComposerPrimitive.Cancel, { render: _jsx(Button, { variant: "ghost", size: "sm", className: "h-8 px-3.5" }), children: "Cancel" }), _jsx(ComposerPrimitive.Send, { render: _jsx(Button, { size: "sm", className: "h-8 px-3.5" }), children: "Update" })] })] }) }));
|
|
115
117
|
};
|
|
116
118
|
const BranchPicker = ({ className, ...rest }) => {
|
|
117
119
|
return (_jsxs(BranchPickerPrimitive.Root, { hideWhenSingleBranch: true, className: cn("aui-branch-picker-root text-muted-foreground -ms-2 me-2 inline-flex items-center text-xs", className), ...rest, children: [_jsx(BranchPickerPrimitive.Previous, { render: _jsx(TooltipIconButton, { tooltip: "Previous" }), children: _jsx(ChevronLeftIcon, {}) }), _jsxs("span", { className: "aui-branch-picker-state font-medium", children: [_jsx(BranchPickerPrimitive.Number, {}), " / ", _jsx(BranchPickerPrimitive.Count, {})] }), _jsx(BranchPickerPrimitive.Next, { render: _jsx(TooltipIconButton, { tooltip: "Next" }), children: _jsx(ChevronRightIcon, {}) })] }));
|
|
@@ -10,9 +10,9 @@ const ANIMATION_DURATION = 200;
|
|
|
10
10
|
const toolGroupVariants = cva("aui-tool-group-root group/tool-group w-full", {
|
|
11
11
|
variants: {
|
|
12
12
|
variant: {
|
|
13
|
-
outline: "rounded-
|
|
13
|
+
outline: "rounded-md border py-3",
|
|
14
14
|
ghost: "",
|
|
15
|
-
muted: "border-
|
|
15
|
+
muted: "border-border bg-muted rounded-md border py-3",
|
|
16
16
|
},
|
|
17
17
|
},
|
|
18
18
|
defaultVariants: { variant: "outline" },
|
|
@@ -27,13 +27,17 @@
|
|
|
27
27
|
* The one glass material (DESIGN.md "Elevation & Depth"): floating chrome —
|
|
28
28
|
* menus, popovers, selects, comboboxes, the command palette, and bars — may
|
|
29
29
|
* carry it; content surfaces stay solid. Glass composites only over our own
|
|
30
|
-
* content
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
30
|
+
* content. Its edge is the floating rung's recipe, whose inset top highlight
|
|
31
|
+
* and inner hairline only show once the fill turns translucent. A fine grain
|
|
32
|
+
* over the fill keeps the blurred colour behind it from banding. Declared as a
|
|
33
|
+
* utility so variant prefixes can gate it (navigation-menu's non-viewport
|
|
34
|
+
* popup). Reduced transparency falls back to the same solid surface at the
|
|
35
|
+
* same elevation.
|
|
34
36
|
*/
|
|
35
37
|
@utility nc-glass {
|
|
36
|
-
background:
|
|
38
|
+
background:
|
|
39
|
+
url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxNDAnIGhlaWdodD0nMTQwJz48ZmlsdGVyIGlkPSdnJz48ZmVUdXJidWxlbmNlIHR5cGU9J2ZyYWN0YWxOb2lzZScgYmFzZUZyZXF1ZW5jeT0nLjg1JyBudW1PY3RhdmVzPScyJyBzdGl0Y2hUaWxlcz0nc3RpdGNoJy8+PGZlQ29sb3JNYXRyaXggdHlwZT0nc2F0dXJhdGUnIHZhbHVlcz0nMCcvPjwvZmlsdGVyPjxyZWN0IHdpZHRoPScxMDAlJyBoZWlnaHQ9JzEwMCUnIGZpbHRlcj0ndXJsKCNnKScgb3BhY2l0eT0nLjA1Jy8+PC9zdmc+"),
|
|
40
|
+
color-mix(in srgb, var(--popover) var(--nc-material-glass-opacity), transparent);
|
|
37
41
|
backdrop-filter: blur(var(--nc-material-glass-blur)) saturate(var(--nc-material-glass-saturation));
|
|
38
42
|
|
|
39
43
|
@media (prefers-reduced-transparency: reduce) {
|
package/dist/styles/globals.css
CHANGED
|
@@ -29,6 +29,49 @@
|
|
|
29
29
|
*/
|
|
30
30
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
31
31
|
|
|
32
|
+
/*
|
|
33
|
+
* Dark mode carries height in tone (DESIGN.md "Elevation & Depth"): the page
|
|
34
|
+
* stays true black and each rung's surface is one fixed step lighter. The rung
|
|
35
|
+
* sets the card and popover roles on its own element, so whichever role that
|
|
36
|
+
* surface paints with takes the rung's tone, whatever order the classes land
|
|
37
|
+
* in. A rung behind a variant prefix keeps the page's roles. In light every
|
|
38
|
+
* tone is the solid white. This belongs to the application
|
|
39
|
+
* stylesheet, not components.css, because a host keeps its own roles.
|
|
40
|
+
*/
|
|
41
|
+
@layer components {
|
|
42
|
+
.nc-elevation-resting {
|
|
43
|
+
--card: var(--nc-material-resting);
|
|
44
|
+
--popover: var(--nc-material-resting);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.nc-elevation-raised {
|
|
48
|
+
--card: var(--nc-material-raised);
|
|
49
|
+
--popover: var(--nc-material-raised);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.nc-elevation-floating {
|
|
53
|
+
--card: var(--nc-material-floating);
|
|
54
|
+
--popover: var(--nc-material-floating);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.nc-elevation-modal {
|
|
58
|
+
--card: var(--nc-material-modal);
|
|
59
|
+
--popover: var(--nc-material-modal);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/*
|
|
63
|
+
* A lifted dark surface is lighter than the soft steps the hover, selected
|
|
64
|
+
* and keycap fills take on the black page, so on it those fills step up
|
|
65
|
+
* from its own tone instead: 8% of the foreground over the surface. Light
|
|
66
|
+
* surfaces are white, where the soft steps already read.
|
|
67
|
+
*/
|
|
68
|
+
:where(.dark)
|
|
69
|
+
:is(.nc-elevation-resting, .nc-elevation-raised, .nc-elevation-floating, .nc-elevation-modal) {
|
|
70
|
+
--accent: color-mix(in oklab, var(--popover) 92%, var(--foreground));
|
|
71
|
+
--muted: color-mix(in oklab, var(--popover) 92%, var(--foreground));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
32
75
|
@layer base {
|
|
33
76
|
* {
|
|
34
77
|
@apply border-border outline-ring;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nadicodeai/ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "12.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -52,8 +52,7 @@
|
|
|
52
52
|
"LICENSES",
|
|
53
53
|
"NOTICE",
|
|
54
54
|
"README.md",
|
|
55
|
-
"AGENTS.md"
|
|
56
|
-
"docs"
|
|
55
|
+
"AGENTS.md"
|
|
57
56
|
],
|
|
58
57
|
"scripts": {
|
|
59
58
|
"dev": "node scripts/dev-build.mjs --watch",
|
|
@@ -72,7 +71,7 @@
|
|
|
72
71
|
"@assistant-ui/react": "0.15.21",
|
|
73
72
|
"@assistant-ui/react-markdown": "0.14.16",
|
|
74
73
|
"@base-ui/react": "^1.8.0",
|
|
75
|
-
"@nadicodeai/design-system": "
|
|
74
|
+
"@nadicodeai/design-system": "12.1.0",
|
|
76
75
|
"class-variance-authority": "^0.7.1",
|
|
77
76
|
"clsx": "^2.1.1",
|
|
78
77
|
"cmdk": "^1.1.1",
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
declare function HandoffBanner({ className, reason, destination, children, ...props }: Omit<React.ComponentProps<"div">, "children"> & {
|
|
3
|
-
reason?: string;
|
|
4
|
-
destination?: string;
|
|
5
|
-
/** Escape hatch: rich banner content that replaces the serializable model. */
|
|
6
|
-
children?: React.ReactNode;
|
|
7
|
-
}): React.JSX.Element;
|
|
8
|
-
export { HandoffBanner };
|
|
9
|
-
//# sourceMappingURL=handoff-banner.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handoff-banner.d.ts","sourceRoot":"","sources":["../../src/components/handoff-banner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,MAAM,EACN,WAAW,EACX,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GAAG;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,qBAWA;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { cn } from "../lib/utils.js";
|
|
3
|
-
function HandoffBanner({ className, reason, destination, children, ...props }) {
|
|
4
|
-
return (_jsx("div", { "data-slot": "handoff-banner", className: cn("nc-handoff-banner", className), ...props, children: children ?? (_jsxs(_Fragment, { children: [destination != null && _jsx("span", { "data-slot": "handoff-banner-destination", children: destination }), reason != null && _jsx("span", { "data-slot": "handoff-banner-reason", children: reason })] })) }));
|
|
5
|
-
}
|
|
6
|
-
export { HandoffBanner };
|
package/docs/activity.md
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
# System activity
|
|
2
|
-
|
|
3
|
-
Who does the work decides how it looks.
|
|
4
|
-
|
|
5
|
-
An Agent's work shows that Agent's orb in its state and a sentence saying what
|
|
6
|
-
it is doing; [AgentOrb](agent-orb.md) owns it, and Nadia connecting is her
|
|
7
|
-
ribbon, working. Everything on this page is the *system's* own work: a save, a
|
|
8
|
-
sign-in, a refresh, a page load. An orb means an Agent, so system work never
|
|
9
|
-
takes one.
|
|
10
|
-
|
|
11
|
-
| The wait | What it shows |
|
|
12
|
-
| --- | --- |
|
|
13
|
-
| Under about a second | The control's own label changes to its pending word. Nothing else. |
|
|
14
|
-
| Past a second | One `WaitingLine` beside the work, and nothing else moves. |
|
|
15
|
-
| Measurable | `Progress` with a written count ("120 di 240 fatture"). |
|
|
16
|
-
| A page load | `Skeleton` placeholders in the shape of the content, still. |
|
|
17
|
-
|
|
18
|
-
One wait gets one indicator. Separately progressing operations may each have
|
|
19
|
-
one. A request waiting for a person is not a wait: queued, paused, offline,
|
|
20
|
-
blocked, successful and failed conditions take the status or feedback
|
|
21
|
-
treatment. An account being active is not an activity.
|
|
22
|
-
|
|
23
|
-
## The pending label
|
|
24
|
-
|
|
25
|
-
The control keeps its place, its size and its icon; only its word changes, and
|
|
26
|
-
the caller marks the control `disabled` and `aria-busy` so the change is
|
|
27
|
-
announced as well as read.
|
|
28
|
-
|
|
29
|
-
```tsx
|
|
30
|
-
import { PendingLabel } from "@nadicodeai/ui/components/pending-label";
|
|
31
|
-
|
|
32
|
-
<Button aria-busy={saving || undefined} disabled={saving} type="submit">
|
|
33
|
-
<PendingLabel pending={saving} pendingLabel="Salvataggio…">
|
|
34
|
-
Salva modifiche
|
|
35
|
-
</PendingLabel>
|
|
36
|
-
</Button>;
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
`pending` and `pendingLabel` are required; the children are the idle label. It
|
|
40
|
-
renders a `span` carrying `data-slot="pending-label"` and, while pending,
|
|
41
|
-
`data-pending="true"`. It adds no mark of its own: a control that had an icon
|
|
42
|
-
keeps that icon, unchanged, throughout the wait.
|
|
43
|
-
|
|
44
|
-
## The waiting line
|
|
45
|
-
|
|
46
|
-
A 2 px track of ink with a 32% segment crossing it linearly on the `wait`
|
|
47
|
-
token, after one second of waiting. Before that second the track is there and
|
|
48
|
-
empty, unannounced, so the line arriving moves nothing around it; a wait the
|
|
49
|
-
person barely notices does not deserve movement, and a control that flashed an
|
|
50
|
-
indicator for 200 ms reads as a glitch.
|
|
51
|
-
|
|
52
|
-
```tsx
|
|
53
|
-
import { WaitingLine } from "@nadicodeai/ui/components/waiting-line";
|
|
54
|
-
|
|
55
|
-
<WaitingLine label="Caricamento delle fatture" />;
|
|
56
|
-
|
|
57
|
-
<div>
|
|
58
|
-
<p>Stiamo preparando il documento.</p>
|
|
59
|
-
<WaitingLine decorative />
|
|
60
|
-
</div>;
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
A meaningful standalone line takes `label` and announces itself as a status;
|
|
64
|
-
`decorative` removes its accessible name when the text beside it already says
|
|
65
|
-
what is happening. Width comes from the caller (`className="w-24"`, or the
|
|
66
|
-
full width of the region it belongs to); height, ink, segment and timing are
|
|
67
|
-
the component's and are not tunable. The one-second delay is
|
|
68
|
-
`WAITING_LINE_DELAY_MS`, exported so a test can name it rather than guess it.
|
|
69
|
-
|
|
70
|
-
Reduced motion drops the travel and breathes the full line in opacity, so a
|
|
71
|
-
wait still reads as a wait. The rule lives in
|
|
72
|
-
`packages/design-system/src/css/motion.css` as `.nc-anim-wait`, with the rest
|
|
73
|
-
of the motion vocabulary.
|
|
74
|
-
|
|
75
|
-
Product code unmounts the line when the operation ends or cannot proceed.
|
|
76
|
-
|
|
77
|
-
## Measurable and still
|
|
78
|
-
|
|
79
|
-
`Progress` carries work whose completed amount is known, always beside a
|
|
80
|
-
written count. When work will become measurable, reserve the progress
|
|
81
|
-
treatment from the start so the transition does not move the layout. Never
|
|
82
|
-
invent a percentage.
|
|
83
|
-
|
|
84
|
-
`Skeleton` is a still placeholder shaped like the content behind it. It does
|
|
85
|
-
not pulse. Do not show a skeleton and a waiting line for the same wait: the
|
|
86
|
-
placeholders already say the page is arriving.
|
|
87
|
-
|
|
88
|
-
## What retired
|
|
89
|
-
|
|
90
|
-
`ActivityOrb` and `mountActivityOrb`, `Spinner`, `GlyphSpinner`, Sonner's
|
|
91
|
-
spinning loading icon, the raw `LoaderCircle` spinners in `feedback-state`,
|
|
92
|
-
`installer-shell`, `automation-section` and `confirm-dialog`, the assistant-ui
|
|
93
|
-
attachment, tool-fallback and tool-group spinners, and the shimmer text on the
|
|
94
|
-
reasoning, tool-fallback and tool-group triggers. With them went the
|
|
95
|
-
`thinking-orbs` system-activity palette, the `tw-shimmer` dependency and the
|
|
96
|
-
duplicate `@utility shimmer`, and the unused `nc-anim-typing` and
|
|
97
|
-
`nc-anim-shimmer` hooks.
|
|
98
|
-
|
|
99
|
-
Where one of those marked a running state inside a component, the state is now
|
|
100
|
-
said in words and marked with a still glyph: an installer step and an
|
|
101
|
-
automation row take `CircleDotIcon`, and a running tool call says "Running
|
|
102
|
-
tool". A status badge never moves; its word and its mark carry the state.
|
|
103
|
-
|
|
104
|
-
## Ownership and source
|
|
105
|
-
|
|
106
|
-
The components own the delay, the geometry, the ink and the motion. The
|
|
107
|
-
application owns the request, the retry, the copy, the completion and the
|
|
108
|
-
recovery. The decision behind this page is
|
|
109
|
-
[the nadicode design system ADR](../../../docs/adr/2026-09-23-the-nadicode-design-system.md);
|
|
110
|
-
the design-system side of it is
|
|
111
|
-
[`DESIGN.md`, "## System activity"](../../design-system/DESIGN.md#system-activity).
|
|
112
|
-
The distinction between measured and unmeasured progress follows
|
|
113
|
-
[Apple's progress guidance](https://developer.apple.com/design/human-interface-guidelines/progress-indicators).
|
package/docs/agent-orb.md
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
# Agent orbs
|
|
2
|
-
|
|
3
|
-
`AgentOrb` is the one Agent identity in every product: seven structures from
|
|
4
|
-
`thinking-orbs` 0.3.1, each painted in one chosen colour, and Nadia's own
|
|
5
|
-
striped ribbon. These are persistent appearance choices, not activity states.
|
|
6
|
-
No other Agent form, avatar or portrait exists; a custom picture a person
|
|
7
|
-
uploads in Nadia is theirs, not an identity this package draws.
|
|
8
|
-
|
|
9
|
-
| Form | Structure | Upstream preset |
|
|
10
|
-
| --- | --- | --- |
|
|
11
|
-
| `ribbon` | Flowing dotted bands | `composing` |
|
|
12
|
-
| `lattice` | Rotating particle bands | `solving` |
|
|
13
|
-
| `orbit` | Particles on tilted orbits | `working` |
|
|
14
|
-
| `globe` | Dotted globe and scanning meridian | `searching` |
|
|
15
|
-
| `network` | Connected constellation | `connecting` |
|
|
16
|
-
| `braid` | Interwoven strands | `weaving` |
|
|
17
|
-
| `morph` | Changing geometric contour | `shaping` |
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
## Nadia
|
|
21
|
-
|
|
22
|
-
`form="nadia"` is the ribbon striped along its whole length, across its width:
|
|
23
|
-
azzurro (`--nc-identity-azzurro`), verde, the orb's own pigment, and rosso.
|
|
24
|
-
The third stripe is the white of the tricolore; it takes the inherited text
|
|
25
|
-
colour so it stays visible as ink on a white ground. The stripes are fixed:
|
|
26
|
-
the same four at every size, in both themes and in every state, and nobody
|
|
27
|
-
chooses them. Each dot keeps its lane through the engine's depth sort, so a
|
|
28
|
-
stripe never changes colour as the ribbon turns. Her motion is the ribbon's.
|
|
29
|
-
|
|
30
|
-
## Stored appearance
|
|
31
|
-
|
|
32
|
-
Nadia stores an Agent's look in its profile and reports it to the Portal on
|
|
33
|
-
every check-in; the Portal renders it and never writes it.
|
|
34
|
-
`@nadicodeai/ui/components/agent-orb-appearance` is the one reading of those
|
|
35
|
-
strings, server-safe so a server can resolve a row before it renders:
|
|
36
|
-
|
|
37
|
-
| Field | Stored as |
|
|
38
|
-
| --- | --- |
|
|
39
|
-
| `shape` | `orb:orbit`, `orb:ribbon`, `orb:lattice`, `orb:globe`, `orb:network`, `orb:braid`, `orb:morph` |
|
|
40
|
-
| `color` | The design system's identity hex of cobalto, verde or arancio, or null; or a rosso an Agent chose before rosso left the picker |
|
|
41
|
-
|
|
42
|
-
`resolveAgentOrb(stored, { root })` returns the form and colour to draw. The
|
|
43
|
-
root Agent is Nadia and draws `nadia` whatever is stored. An unknown or empty
|
|
44
|
-
shape draws `orbit`; an unknown or empty colour draws the inherited text
|
|
45
|
-
colour, which is also the default a picker's reset restores. Paint a colour
|
|
46
|
-
with `agentOrbColorTokens[color]`. Each retired `forma:` spelling resolves to
|
|
47
|
-
its own orb, so an Agent keeps a distinct look until someone changes it.
|
|
48
|
-
|
|
49
|
-
## The three colours
|
|
50
|
-
|
|
51
|
-
A person chooses cobalto, verde or arancio, or nothing, which leaves the orb
|
|
52
|
-
the inherited text colour. All three clear 3:1 against both the white and the
|
|
53
|
-
black canvas, so a chosen orb stays visible in either theme; giallo does not
|
|
54
|
-
(1.6:1 on white) and is not offered.
|
|
55
|
-
|
|
56
|
-
Rosso is not offered either. It is exactly the error red, so a red Agent beside
|
|
57
|
-
a red "Bloccato" badge read as a broken Agent rather than a chosen colour.
|
|
58
|
-
Nadia keeps rosso in her own stripes, where it is one of four and says nothing
|
|
59
|
-
on its own. An Agent that chose rosso before it left the picker keeps a colour:
|
|
60
|
-
`resolveAgentOrb` maps a stored `rosso`, by name or by the `#d3302f` hex, to
|
|
61
|
-
arancio, the nearest hue that is not a status. That is a mapping on the way in,
|
|
62
|
-
not an offer on the way out — `agentOrbColors` is what a picker shows, and it
|
|
63
|
-
has three entries.
|
|
64
|
-
|
|
65
|
-
The appearance is a person's choice, never derived: do not infer it from a name,
|
|
66
|
-
an id hash or a role. A machine check-in is not Agent activity, so a surface that
|
|
67
|
-
only knows check-ins draws the orb idle. The form does not select a job, tools or runtime status. Do not switch it when
|
|
68
|
-
an Agent starts searching or solving. Applications own the persisted form,
|
|
69
|
-
colour, name and status; names beside avatars provide exact identification.
|
|
70
|
-
|
|
71
|
-
## Component
|
|
72
|
-
|
|
73
|
-
```tsx
|
|
74
|
-
import { AgentOrb } from "@nadicodeai/ui/components/agent-orb";
|
|
75
|
-
|
|
76
|
-
<AgentOrb form="ribbon" color="var(--nc-identity-cobalto)" size={32} label="Research" />;
|
|
77
|
-
<AgentOrb form="nadia" size={32} label="Nadia" />;
|
|
78
|
-
<AgentOrb form="globe" presence="over-picture" size={96} state="working" label="Ricerca" />;
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
`form` is required. `color` accepts one CSS colour, including a customer-chosen
|
|
82
|
-
colour or a canonical token. Omit it to inherit text colour. This configurable
|
|
83
|
-
artwork is not a new palette for controls or status. Every particle and line
|
|
84
|
-
of a chosen form uses the same pigment, and on Nadia each stripe keeps its own;
|
|
85
|
-
opacity, not another colour, creates depth. Working
|
|
86
|
-
releases occasional coloured flourishes; Done repeats the same arcs,
|
|
87
|
-
arrowheads, rings and sparkles in a short celebration around
|
|
88
|
-
that single-colour identity, using the existing chart and warning tokens. Choose a
|
|
89
|
-
colour visible on the intended background. A deliberately black pigment on a
|
|
90
|
-
black surface is not automatically recoloured.
|
|
91
|
-
|
|
92
|
-
A native startup screen paints an orb before React loads through
|
|
93
|
-
`mountAgentOrb(canvas, { form, size, presence, state, paused })` from
|
|
94
|
-
`@nadicodeai/ui/agent-orb`, the React-free entry beside
|
|
95
|
-
`@nadicodeai/ui/activity`. It is the renderer `AgentOrb` itself mounts, with
|
|
96
|
-
the same motion, states and presence; the caller supplies the canvas and the
|
|
97
|
-
adjacent name, and calls `destroy()` when React replaces the startup surface.
|
|
98
|
-
Import `@nadicodeai/ui/globals.css` with it: the renderer inherits the CSS ink
|
|
99
|
-
and reads the colour tokens from the element.
|
|
100
|
-
|
|
101
|
-
Sizes are 20, 24, 32, 40, 64, 96 and 160 CSS pixels. Menu sizes through 32 use
|
|
102
|
-
the upstream compact density; larger sizes use its detailed profile. `paused`
|
|
103
|
-
holds the current frame and resumes without resetting the appearance. An
|
|
104
|
-
accessible image requires `label`; use `decorative` beside an existing name.
|
|
105
|
-
The component is Canvas 2D, not WebGL. It reuses the vendor's portable geometry
|
|
106
|
-
API because the stock React component only offers monochrome light/dark ink,
|
|
107
|
-
not a configurable pigment.
|
|
108
|
-
|
|
109
|
-
Motion is limited to 30 painted frames per second. Offscreen and hidden orbs
|
|
110
|
-
stop scheduling animation. Unmount removes the frame request and observers.
|
|
111
|
-
DPR is capped at two. Without Canvas 2D, the accessible name remains
|
|
112
|
-
available.
|
|
113
|
-
|
|
114
|
-
The engine paints the box the canvas occupies, not the `size` it was given: a
|
|
115
|
-
`ResizeObserver` follows the element, and the backing store and the geometry's
|
|
116
|
-
density profile both come from the measured CSS pixels. `size` sets that box
|
|
117
|
-
through `--nc-agent-orb-size` in a class, so a caller whose layout decides the
|
|
118
|
-
size overrides it with its own sizing class and the orb stays sharp at
|
|
119
|
-
whatever width it lands on. The declared size still stands in before layout
|
|
120
|
-
has measured anything, on a server render and in a test environment without
|
|
121
|
-
layout.
|
|
122
|
-
|
|
123
|
-
`presence` decides how loudly one orb reads on its ground, per mount, never
|
|
124
|
-
as a module setting: two orbs on one page can want different weights.
|
|
125
|
-
`plain`, the default, is the interface's own ink. `over-picture` multiplies
|
|
126
|
-
ink by 2.3 and every dot and line radius by 1.9, for an orb drawn on a
|
|
127
|
-
photograph, where the plain weights sink into the image. Nadia on open sky
|
|
128
|
-
keeps `plain`.
|
|
129
|
-
|
|
130
|
-
Reduced motion turns movement off and keeps opacity and colour. A thinking or
|
|
131
|
-
working orb breathes between full ink and 0.45 over 1.6 s, ease-in-out, so
|
|
132
|
-
busy still reads as busy; its geometry does not turn, and the state cue
|
|
133
|
-
breathes with the body. Every other state, idle, waiting, blocked and done
|
|
134
|
-
included, holds one still frame. The preference is observed live.
|
|
135
|
-
|
|
136
|
-
`state` accepts idle, working, waiting, blocked, thinking and done, and every
|
|
137
|
-
surface passes the Agent's real one: only Agents move on their own, so motion
|
|
138
|
-
on a screen means an Agent is working and a still orb means it is not. Idle
|
|
139
|
-
holds one still pose and schedules no frame after its first paint; a surface
|
|
140
|
-
that knows only check-ins draws idle, because a machine check-in is not Agent
|
|
141
|
-
activity. Geometry and state gestures have separate clocks. Each form has its
|
|
142
|
-
own geometry pace, shared across avatar sizes, which Working and Thinking
|
|
143
|
-
keep; Morph holds a contour for about 1.6 seconds and changes it over one
|
|
144
|
-
second. Waiting holds its pose; Blocked makes one gentle interrupted effort
|
|
145
|
-
and stops.
|
|
146
|
-
V7 keeps the material free-standing and intact:
|
|
147
|
-
no gear, thought bubble, pause, exclamation mark or check is cut into the form.
|
|
148
|
-
Working and Thinking preserve the native geometry: do not stretch, flatten,
|
|
149
|
-
fold or emit copies of the orb to convey either state. Working uses one open,
|
|
150
|
-
tapered multicoloured ribbon passing behind and in front of the orb on a
|
|
151
|
-
7.2-second loop. Thinking uses three persistent coloured dots above the orb,
|
|
152
|
-
with sequential opacity and slight size pulses on a 3.6-second loop.
|
|
153
|
-
The distinct symbols remain visible throughout both cycles. Done repeats
|
|
154
|
-
the ribbon in three celebratory sweeps and then rests. Changing `motionKey`
|
|
155
|
-
replays it. These exterior cues use the celebration palette; the body keeps
|
|
156
|
-
its configured pigment.
|
|
157
|
-
No state has an enclosing circle. Keep a nearby status label where exact
|
|
158
|
-
state identification matters, including reduced motion and compact sizes.
|
|
159
|
-
|
|
160
|
-
In the Portal, [`agent-identity.tsx`](../../../apps/portal/src/components/agent-identity.tsx)
|
|
161
|
-
draws every Agent, in its lists, Agent workspace and the sign-in, sign-up and
|
|
162
|
-
Get Nadia pages, and `src/lib/agent-orb.ts` maps what a machine reported to
|
|
163
|
-
the state drawn. It also gives an orb a `travelId`, which wraps it in React's
|
|
164
|
-
`<ViewTransition>` so the same orb travels from a list row into the Agent's
|
|
165
|
-
page; `apps/portal/docs/design-doctrine.md` owns that rule. Inspect them in
|
|
166
|
-
the running local Portal for compact and full-size appearances.
|
|
167
|
-
|
|
168
|
-
[Upstream library and presets](https://libraries.dev/orbs), MIT licensed.
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# Component Classification
|
|
2
|
-
|
|
3
|
-
This file records the ownership class for U4 product compositions. The package may render standard product UI, but consuming apps own app behavior, data, persistence, and product-specific promises.
|
|
4
|
-
|
|
5
|
-
If first-party shadcn or assistant-ui registry source already covers the same
|
|
6
|
-
generic product UI, do not add a parallel nadicode package API. Use the
|
|
7
|
-
registry item in the consuming app and adapt it there with app-owned data,
|
|
8
|
-
copy, and behavior.
|
|
9
|
-
|
|
10
|
-
## Removed Direct Reinventions
|
|
11
|
-
|
|
12
|
-
| Removed API | Registry source to use instead | Reason |
|
|
13
|
-
| --- | --- | --- |
|
|
14
|
-
| Package-level `DataTable`, `DataTableColumnControls`, `DataTableEmptyState`, `DataTableState` | [shadcn Data Table guide](https://ui.shadcn.com/docs/components/base/data-table), `@shadcn/table`, and the table in `@shadcn/dashboard-01` | These are first-party composition sources for sorting, visibility, filtering, and pagination. Portal retains its app-owned `DataTable` adapter for registry and URL behavior. |
|
|
15
|
-
| `CommandPalette`, `ModelPickerCommand`, `SessionPickerCommand` | `@shadcn/command` and its `CommandDialog` export ([Command guide](https://ui.shadcn.com/docs/components/base/command)) | The command primitive and dialog composition are already supplied; model/session execution is app behavior. |
|
|
16
|
-
| `ChartCard`, `MetricChart`, `semanticChartColors` | The package chart kit, owned by [`contract.md`](contract.md) | shadcn already ships the chart primitives and blocks the kit is pulled from; metric aggregation and chart choice are app behavior. |
|
|
17
|
-
|
|
18
|
-
## Retained Package Compositions
|
|
19
|
-
|
|
20
|
-
| Component | Classification | Built on | Required states | Package-owned accessibility | Fixture |
|
|
21
|
-
| --- | --- | --- | --- | --- | --- |
|
|
22
|
-
| `ActionMenu` | Canonical record-action composition. | shadcn `Button` and `DropdownMenu`. | closed, open, keyboard selection, focus return. | Required accessible trigger name; inherited menu mechanics. | `../src/components/action-menu.test.tsx` |
|
|
23
|
-
| `SettingsSection` | nadicode product composition. | shadcn Card slots, Separator, and FieldGroup. | header, field group, and divided action footer. | Section structure; consumer owns the form transaction. | `../src/components/settings-section.test.tsx` |
|
|
24
|
-
| `SettingsField` | nadicode product composition. | shadcn Field, FieldLabel, FieldDescription, and FieldError. | valid, invalid, required, and disabled field rows. | Render callback supplies the control's label and message associations in server and client components. | `../src/components/settings-section.test.tsx` |
|
|
25
|
-
| `FeedbackState` | Net-new central product state composition adapted from shadcn empty-state patterns. | shadcn `Empty` and lucide status icons. | `empty`, `loading`, `saving`, `error`, `permission`, `offline`, `no-results`, `fatal`. | `role="status"` for loading/saving; `role="alert"` for error, permission, offline, and fatal. | `../tests/guards/product-compositions.test.ts` |
|
|
26
|
-
|
|
27
|
-
## App-Owned Boundaries
|
|
28
|
-
|
|
29
|
-
Keep these out of `@nadicodeai/ui`:
|
|
30
|
-
|
|
31
|
-
- data fetching, React Query, routers, server actions, desktop IPC, terminal runtime code, and persistence;
|
|
32
|
-
- login/signup routes, OTP/two-factor flows, auth provider choices, recovery flows, session mutation, and analytics;
|
|
33
|
-
- permission decisions, tenant/customer scoping, and policy enforcement;
|
|
34
|
-
- app-specific product copy, page IA, and route-specific ordering;
|
|
35
|
-
- fake proof, invented customer names, invented metrics, or placeholder testimonials.
|
|
36
|
-
|
|
37
|
-
## Fixture Guidance
|
|
38
|
-
|
|
39
|
-
U4 fixtures should use nadicode-relevant work objects:
|
|
40
|
-
|
|
41
|
-
- briefing agents, review agents, approval queues, sessions, models, workspace defaults, files, pairing codes, and weekly approvals;
|
|
42
|
-
- controlled state examples for sorting, selection, visibility, validation, loading, saving, offline, permission, and fatal states;
|
|
43
|
-
- no external network, browser, customer PII, signed contracts, financials, or fake proof.
|
|
44
|
-
|
|
45
|
-
Browser-driven tests stay out of the default Vitest suite. U4 fixtures render through static and SSR-friendly tests only.
|