@neuronection/assistant-ui 0.53.0 → 0.54.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 +25 -0
- package/README.md +1 -0
- package/dist/chat-markdown.js +1 -1
- package/dist/chat-message.js +1 -1
- package/dist/chat-transcript.js +1 -1
- package/dist/{chunk-NOAKHVBJ.js → chunk-56QSIK4Y.js} +3 -3
- package/dist/{chunk-NOAKHVBJ.js.map → chunk-56QSIK4Y.js.map} +1 -1
- package/dist/chunk-65JY3ATO.js +94 -0
- package/dist/chunk-65JY3ATO.js.map +1 -0
- package/dist/chunk-6G7H6YP6.js +180 -0
- package/dist/chunk-6G7H6YP6.js.map +1 -0
- package/dist/chunk-7IP3JP3Z.js +54 -0
- package/dist/chunk-7IP3JP3Z.js.map +1 -0
- package/dist/{chunk-HXU6P5FD.js → chunk-E2NNTHFB.js} +4 -4
- package/dist/{chunk-HXU6P5FD.js.map → chunk-E2NNTHFB.js.map} +1 -1
- package/dist/chunk-FQXVZVA5.js +68 -0
- package/dist/chunk-FQXVZVA5.js.map +1 -0
- package/dist/chunk-FY3NCPFO.js +112 -0
- package/dist/chunk-FY3NCPFO.js.map +1 -0
- package/dist/chunk-KKZLR3YD.js +3 -0
- package/dist/chunk-KKZLR3YD.js.map +1 -0
- package/dist/{chunk-KQLKITZL.js → chunk-KLCULTOQ.js} +3 -3
- package/dist/chunk-KLCULTOQ.js.map +1 -0
- package/dist/chunk-RRT3DOPJ.js +3 -0
- package/dist/chunk-RRT3DOPJ.js.map +1 -0
- package/dist/{chunk-I4R5BRC7.js → chunk-TLFEVL42.js} +3 -3
- package/dist/{chunk-I4R5BRC7.js.map → chunk-TLFEVL42.js.map} +1 -1
- package/dist/chunk-YDQW2WJH.js +70 -0
- package/dist/chunk-YDQW2WJH.js.map +1 -0
- package/dist/index.d.ts +206 -1
- package/dist/index.js +18 -12
- package/dist/markdown-diff-view.js +1 -1
- package/dist/provider-logo.d.ts +16 -0
- package/dist/provider-logo.js +3 -0
- package/dist/provider-logo.js.map +1 -0
- package/dist/provider-setup-form.d.ts +74 -0
- package/dist/provider-setup-form.js +3 -0
- package/dist/provider-setup-form.js.map +1 -0
- package/dist/provider-setup-tiles.d.ts +41 -0
- package/dist/provider-setup-tiles.js +3 -0
- package/dist/provider-setup-tiles.js.map +1 -0
- package/dist/setup-first-run-card.d.ts +23 -0
- package/dist/setup-first-run-card.js +3 -0
- package/dist/setup-first-run-card.js.map +1 -0
- package/dist/setup-review.d.ts +51 -0
- package/dist/setup-review.js +3 -0
- package/dist/setup-review.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/switch-row.d.ts +19 -0
- package/dist/switch-row.js +3 -0
- package/dist/switch-row.js.map +1 -0
- package/package.json +25 -1
- package/dist/chunk-KQLKITZL.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @neuronection/assistant-ui
|
|
2
2
|
|
|
3
|
+
## 0.54.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`93991a7`](https://github.com/neuronection/assistant-ui/commit/93991a73ce3dc376060a9575c30c0c7e503840fb) Thanks [@constLiakos](https://github.com/constLiakos)! - **AI settings: the plan-26 one-click setup kit (Phase 2 promotion)** — the six BYOK/decision setup primitives the family's three hand-built references (desktop `SetupWizard`, study `ProviderSetupModal`, health `byok/` port) converge on. All presentational + controlled (ADR-006): preset data, validation calls, secrets and i18n stay app-side.
|
|
8
|
+
|
|
9
|
+
- **`ProviderSetupTiles`** (`provider-setup-tiles`) — neutral equal-weight preset grid in the app's family order; no "recommended" ever; `local` captions, `disabled` tiles with reasons (health overlay), `configured` badges, `suggestedKey` paste-prefix highlight (sr-only note, never color alone); `ProviderSetupManualTile` companion for the manual/custom entry.
|
|
10
|
+
- **`ProviderSetupForm`** (`provider-setup-form`) — guided setup form: vendor checklist with `{url}` interpolation + copy buttons, get-a-key link (or button via `onOpenKeyUrl` for Electron `openExternal`), free-tier note, connection name, write-only API key (`type="password"` + `autoComplete="new-password"`), Advanced `<details>` disclosure with read-only base URL for `fixedBase` presets, `advancedExtra` slot (hosting/country — study/health), and classified error copy keyed off the shared §15 enum (`SETUP_ERROR_CODES` / `SetupErrorCode`) with **labels prop-injected** (`errorLabels`, `suspectedVendorHint` `{vendor}`).
|
|
11
|
+
- **`SetupReview`** (`setup-review`) — editable pre-flight review: model-select cards with capability icons (incl. `decision`) + gap-fill switch rows with `now:` sub-lines and the never-removes footnote. Every edit emits the full five-bind options body `{curatedIds, bindChat, bindVision, bindStt, bindDecision}` (plan 26 D14); decision-only presets show the decision slot only.
|
|
12
|
+
- **`SwitchRow`** (`switch-row`) — labeled `role="switch"` row with animated knob and `currentValue` sub-line; the standalone settings toggle desktop/study/health all hand-rolled.
|
|
13
|
+
- **`ProviderLogo`** (`provider-logo`) — simple-icons path data keyed by preset key, inline (no dependency), `currentColor`, monogram fallback; openai/groq marks are gone upstream so those keys intentionally fall back to the monogram.
|
|
14
|
+
- **`SetupFirstRunCard`** (`setup-first-run-card`) — empty-state CTA when no provider is configured: title/body, `localProbing` status, Set up / optional Dismiss, `children` slot for the app's detected-local banner; chat empty states deep-link to it.
|
|
15
|
+
|
|
16
|
+
Companions: `docs/guides/ai-settings.md` rewritten to the full family assembly (first-run card → wizard → defaults-first list → re-configure), per-component docs pages + accessibility rows + Ladle stories (`ai-settings-assembly`), and a composition test proving the five-bind body end-to-end next to the TaskAssignmentPicker Decision group. This release also carries the Phase 0 decision-descriptor verification work (`decision` descriptor + `decision:<cap>` slot coverage in stories/tests, landed unreleased on 4128640) — one release for the whole promotion set, per plan 26.
|
|
17
|
+
|
|
18
|
+
## 0.53.1
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- [`a37510a`](https://github.com/neuronection/assistant-ui/commit/a37510a192ab38f2086787bd0ae79088500d2bd8) Thanks [@constLiakos](https://github.com/constLiakos)! - **Default accent contrast (a11y):** the family blue `--as-accent` deepens from `oklch(0.55 0.16 258)` (#2d6fcd) to `oklch(0.52 0.17 258)` (#1c65c8), lifting white/tone-50 text on primary surfaces (user chat bubbles, primary buttons, links, focus rings) from 4.72:1 to **5.39:1** — WCAG AA for normal-size text with headroom. `--as-accent-strong` is unchanged and stays the darker hover tier.
|
|
23
|
+
|
|
24
|
+
**User bubble legibility:** two fixes for text inside primary user bubbles. `MarkdownSurface` no longer hard-codes `text-[var(--as-fg)]` on its root — it inherits color from its context, so user messages render in `--as-primary-fg` (white) instead of near-black text on the blue bubble; and user bubbles render `font-medium`, since 14px regular strokes read washed-out on saturated backgrounds even when the ratio passes.
|
|
25
|
+
|
|
26
|
+
Apps that brand their own accent (health-assistant overrides `--as-accent`) are unaffected by the token change. Apps consuming the default — or duplicating it, as study-assistant's palette currently does — should bump their `--primary` to `oklch(0.52 0.17 258)` to match.
|
|
27
|
+
|
|
3
28
|
## 0.53.0
|
|
4
29
|
|
|
5
30
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -112,6 +112,7 @@ Visual reference: [gallery](https://neuronection.github.io/assistant-ui/).
|
|
|
112
112
|
| [`flow-status`](./docs/components/flow-status.md) | `FlowStatusCard` (multi-step AI-flow progress from the family event vocabulary: per-node status, current-step emphasis, progress summary, error + retryable, controlled retry/cancel/resume, `detail` slot for HITL cards) | [stories](https://neuronection.github.io/assistant-ui/?story=flow-status--running) |
|
|
113
113
|
| [`flow-trace`](./docs/components/flow-trace.md) | `FlowTraceCard` (run ledger over the library-owned `FlowTrace` schema: outcome badge, stage timeline, per-call LLM table with tokens/latency/prompt version, ops ✓/✗ list, simulated badge for mock rows) + `FlowTelemetryStrip` (compact `calls · tokens in/out · edits` live counters) | [stories](https://neuronection.github.io/assistant-ui/?story=flow-trace--completed-run) |
|
|
114
114
|
| [`settings-shell`](./docs/components/settings-shell.md) / [`provider-form`](./docs/components/provider-form.md) / [`connection-test-row`](./docs/components/connection-test-row.md) | `SettingsShell` (controlled two-pane nav) · `ProviderForm` (write-only API-key field) · `ConnectionTestRow` (idle/testing/ok/fail + latency, `inline` variant + meta slot) | [stories](https://neuronection.github.io/assistant-ui/?story=settings-trio--provider-form-story) |
|
|
115
|
+
| [`provider-setup-tiles`](./docs/components/provider-setup-tiles.md) / [`provider-setup-form`](./docs/components/provider-setup-form.md) / [`setup-review`](./docs/components/setup-review.md) / [`switch-row`](./docs/components/switch-row.md) / [`provider-logo`](./docs/components/provider-logo.md) / [`setup-first-run-card`](./docs/components/setup-first-run-card.md) | The plan-26 one-click setup kit (BYOK + decision models): neutral equal-weight preset tiles (family order, no "recommended") · guided setup form (checklist + copy buttons, write-only `new-password` key, Advanced disclosure with fixed-base read-only, §15 error enum copy prop-injected) · editable pre-flight review emitting the five-bind options body `{curatedIds, bindChat, bindVision, bindStt, bindDecision}` (decision-only presets show the decision slot only) · labeled `role="switch"` row with `now:` sub-line · simple-icons provider mark with monogram fallback (openai/groq gone upstream), `currentColor` · first-run CTA card with local-probe status | [stories](https://neuronection.github.io/assistant-ui/?story=ai-settings-assembly--ai-settings-setup-tiles-story) |
|
|
115
116
|
| [`admin-user-table`](./docs/components/admin-user-table.md) | `AdminUserTable` — controlled admin user management table (email + "(you)" marker, activity count, role/status, promote/demote, activate/deactivate, inline password reset with min-length gate, force logout; guard-rail 403s as friendly messages) | [stories](https://neuronection.github.io/assistant-ui/?story=admin-user-table--default) |
|
|
116
117
|
| [`instance-mode-control`](./docs/components/instance-mode-control.md) | `InstanceModeControl` — controlled §4.5 instance access-mode panel (current mode, open→authenticated with owner credential set, authenticated→open with password + explicit ack, blocked states, audit note) | [stories](https://neuronection.github.io/assistant-ui/?story=instance-mode-control--open) |
|
|
117
118
|
| [`login-form`](./docs/components/login-form.md) / [`register-form`](./docs/components/register-form.md) | `LoginForm` — controlled sign-in form (labelled email + password with visibility toggle, loading/error props, register/forgot link slots; no remember-me — HttpOnly sessions are server-owned) · `RegisterForm` — controlled registration form (confirm-password mismatch gate, optional full-name field, min-length hint, login link slot) | [stories](https://neuronection.github.io/assistant-ui/?story=login-form--default) |
|
package/dist/chat-markdown.js
CHANGED
package/dist/chat-message.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { ChatMessage, ChatMessageEditor, MessageVariantSwitcher } from './chunk-
|
|
1
|
+
export { ChatMessage, ChatMessageEditor, MessageVariantSwitcher } from './chunk-56QSIK4Y.js';
|
|
2
2
|
//# sourceMappingURL=chat-message.js.map
|
|
3
3
|
//# sourceMappingURL=chat-message.js.map
|
package/dist/chat-transcript.js
CHANGED
|
@@ -166,7 +166,7 @@ var ChatMessage = React3.forwardRef(
|
|
|
166
166
|
className: cn(
|
|
167
167
|
"relative flex max-w-[92%] flex-col gap-1.5 rounded-[var(--as-radius)] px-3 py-2 text-sm",
|
|
168
168
|
compact && "px-2.5 py-1.5",
|
|
169
|
-
isUser ? "rounded-br-[var(--as-radius-sm)] bg-[var(--as-primary)] text-[var(--as-primary-fg)]" : design === "flat" ? "max-w-full rounded-bl-[var(--as-radius-sm)] bg-transparent px-0 py-0" : "rounded-bl-[var(--as-radius-sm)] bg-[var(--as-muted)] text-[var(--as-fg)]"
|
|
169
|
+
isUser ? "rounded-br-[var(--as-radius-sm)] bg-[var(--as-primary)] font-medium text-[var(--as-primary-fg)]" : design === "flat" ? "max-w-full rounded-bl-[var(--as-radius-sm)] bg-transparent px-0 py-0" : "rounded-bl-[var(--as-radius-sm)] bg-[var(--as-muted)] text-[var(--as-fg)]"
|
|
170
170
|
),
|
|
171
171
|
children: [
|
|
172
172
|
reasoning ? /* @__PURE__ */ jsx("div", { className: "not-prose", children: reasoning }) : null,
|
|
@@ -260,5 +260,5 @@ var ChatMessage = React3.forwardRef(
|
|
|
260
260
|
);
|
|
261
261
|
|
|
262
262
|
export { ChatMessage, ChatMessageEditor, MessageVariantSwitcher };
|
|
263
|
-
//# sourceMappingURL=chunk-
|
|
264
|
-
//# sourceMappingURL=chunk-
|
|
263
|
+
//# sourceMappingURL=chunk-56QSIK4Y.js.map
|
|
264
|
+
//# sourceMappingURL=chunk-56QSIK4Y.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/chat-message/ChatMessageEditor.tsx","../src/components/chat-message/MessageVariantSwitcher.tsx","../src/components/chat-message/ChatMessage.tsx"],"names":["React","ChatMessageEditor","React2","MessageVariantSwitcher","jsxs","jsx","ChatMessage"],"mappings":"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","file":"chunk-NOAKHVBJ.js","sourcesContent":["import * as React from 'react'\n\nimport { cn } from '../../lib/utils'\nimport { Button } from '../button/Button'\n\nexport interface ChatMessageEditorLabels {\n save: string\n cancel: string\n ariaLabel: string\n}\n\nexport interface ChatMessageEditorProps {\n value: string\n onValueChange: (value: string) => void\n /** Save & resend — branches the tree (family `edit` endpoint) and reruns the turn. */\n onSubmit: () => void\n onCancel: () => void\n submitDisabled?: boolean\n rows?: number\n labels?: Partial<ChatMessageEditorLabels>\n className?: string\n}\n\n/**\n * Inline user-prompt editor for the edit-and-resend flow (study pattern):\n * controlled textarea, Cmd/Ctrl+Enter saves, Escape cancels.\n */\nexport const ChatMessageEditor = React.forwardRef<HTMLDivElement, ChatMessageEditorProps>(\n function ChatMessageEditor(\n { value, onValueChange, onSubmit, onCancel, submitDisabled = false, rows = 3, labels, className },\n ref,\n ) {\n const onKeyDown: React.KeyboardEventHandler<HTMLTextAreaElement> = (event) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n onCancel()\n return\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n if (!submitDisabled) {\n onSubmit()\n }\n }\n }\n\n return (\n <div ref={ref} data-as=\"chat-message-editor\" className={cn('as-anim-slide-up flex w-full flex-col gap-2', className)}>\n <textarea\n autoFocus\n value={value}\n rows={rows}\n aria-label={labels?.ariaLabel ?? 'Edit message'}\n onChange={(event) => onValueChange(event.target.value)}\n onKeyDown={onKeyDown}\n className=\"w-full resize-y rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] px-3 py-2 text-sm text-[var(--as-fg)] placeholder:text-[var(--as-muted-fg)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]\"\n />\n <div className=\"flex items-center justify-end gap-2\">\n <Button variant=\"ghost\" size=\"sm\" onClick={onCancel}>\n {labels?.cancel ?? 'Cancel'}\n </Button>\n <Button size=\"sm\" disabled={submitDisabled} onClick={onSubmit}>\n {labels?.save ?? 'Save & resend'}\n </Button>\n </div>\n </div>\n )\n },\n)\n","import * as React from 'react'\nimport { ChevronLeft, ChevronRight } from 'lucide-react'\n\nimport type { ChatMessageVariants } from '../chat-core/types'\nimport { cn } from '../../lib/utils'\n\nexport interface MessageVariantSwitcherLabels {\n group: string\n variantOf: (index: number, count: number) => string\n previous: string\n next: string\n}\n\nexport interface MessageVariantSwitcherProps {\n variants: ChatMessageVariants\n /** Flip the parent's active-child pointer to the sibling id (family `select` endpoint). */\n onSelect: (messageId: string) => void\n labels?: Partial<MessageVariantSwitcherLabels>\n className?: string\n}\n\n/**\n * The `‹ n/N ›` sibling-variant switcher under a branched message\n * (study's inline switcher, family branching contract).\n */\nexport const MessageVariantSwitcher = React.forwardRef<HTMLDivElement, MessageVariantSwitcherProps>(\n function MessageVariantSwitcher({ variants, onSelect, labels, className }, ref) {\n const { index, count, siblingIds } = variants\n const previousId = index > 1 ? siblingIds[index - 2] : undefined\n const nextId = index < count ? siblingIds[index] : undefined\n\n const select = (event: React.MouseEvent<HTMLButtonElement>, messageId: string | undefined) => {\n event.stopPropagation()\n if (messageId !== undefined) {\n onSelect(messageId)\n }\n }\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={labels?.group ?? 'Message variants'}\n data-as=\"message-variant-switcher\"\n className={cn('flex items-center gap-0.5 text-xs text-[var(--as-muted-fg)]', className)}\n >\n <button\n type=\"button\"\n disabled={previousId === undefined}\n aria-label={labels?.previous ?? 'Previous variant'}\n title={labels?.previous ?? 'Previous variant'}\n onClick={(event) => select(event, previousId)}\n className=\"rounded-[var(--as-radius-sm)] p-0.5 transition-colors hover:bg-[var(--as-surface-raised)] hover:text-[var(--as-fg)] disabled:pointer-events-none disabled:opacity-30 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <ChevronLeft className=\"size-3.5\" aria-hidden />\n </button>\n <span className=\"tabular-nums\" title={labels?.variantOf?.(index, count) ?? `Variant ${index} of ${count}`}>\n {index}/{count}\n </span>\n <button\n type=\"button\"\n disabled={nextId === undefined}\n aria-label={labels?.next ?? 'Next variant'}\n title={labels?.next ?? 'Next variant'}\n onClick={(event) => select(event, nextId)}\n className=\"rounded-[var(--as-radius-sm)] p-0.5 transition-colors hover:bg-[var(--as-surface-raised)] hover:text-[var(--as-fg)] disabled:pointer-events-none disabled:opacity-30 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <ChevronRight className=\"size-3.5\" aria-hidden />\n </button>\n </div>\n )\n },\n)\n","import * as React from 'react'\nimport { Check, Copy, Pencil, RotateCcw, TriangleAlert } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\nimport { Button } from '../button/Button'\nimport type { ChatError, ChatMessageVariants, ChatRole } from '../chat-core/types'\nimport { ChatMessageEditor, type ChatMessageEditorLabels } from './ChatMessageEditor'\nimport { MessageVariantSwitcher, type MessageVariantSwitcherLabels } from './MessageVariantSwitcher'\n\nexport interface ChatMessageAction {\n key: string\n label: string\n icon?: LucideIcon\n onClick: () => void\n danger?: boolean\n}\n\nexport interface ChatMessageActions {\n onCopy?: () => void\n /**\n * Controlled copied feedback for the copy action (check morph).\n * Uncontrolled by default: the library shows the check for 1.5 s\n * after each copy click.\n */\n copied?: boolean\n onEdit?: () => void\n onRegenerate?: () => void\n onRetry?: () => void\n /** Extra icon actions (app-specific). */\n extras?: ChatMessageAction[]\n /**\n * Extra node rendered inside the error card next to the Retry button —\n * e.g. an \"Open AI settings\" link when the error is a not-configured\n * failure. Rendered only while the error card is visible.\n */\n errorExtra?: React.ReactNode\n}\n\nexport interface ChatMessageLabels {\n copy: string\n copied: string\n edit: string\n regenerate: string\n retry: string\n interrupted: string\n error: string\n}\n\nexport interface ChatMessageProps {\n role: ChatRole\n /** Usually a `MarkdownSurface`; any node graph renders here. */\n content: React.ReactNode\n /** Thinking block slot (usually `ChatReasoning`). */\n reasoning?: React.ReactNode\n /** Tool cards / HITL cards below the content. */\n children?: React.ReactNode\n status?: 'streaming' | 'done' | 'error' | 'interrupted'\n error?: ChatError\n actions?: ChatMessageActions\n /** Edit-and-resend mode for user messages (renders `ChatMessageEditor`). */\n editing?: false | { value: string; onValueChange: (value: string) => void; onSubmit: () => void; onCancel: () => void; submitDisabled?: boolean }\n variants?: ChatMessageVariants\n onSelectVariant?: (messageId: string) => void\n /** Badge row (model, latency, tokens — app-defined). */\n meta?: React.ReactNode\n /** Deep-link chip row (career references, health citations). */\n chips?: React.ReactNode\n /** Attachment rail above the content. */\n attachments?: React.ReactNode\n /** Leading identity node beside the bubble (user: trailing). Render group-start avatars only when grouping transcripts. */\n avatar?: React.ReactNode\n /**\n * Visual design: `bubbles` (default) — paired role bubbles; `flat` —\n * assistant content renders as prose on the panel surface (user keeps\n * its bubble). Reasoning/tool cards are unaffected.\n */\n design?: 'bubbles' | 'flat'\n labels?: Partial<ChatMessageLabels & ChatMessageEditorLabels & MessageVariantSwitcherLabels>\n compact?: boolean\n className?: string\n}\n\nconst actionButtonClass =\n 'rounded-[var(--as-radius-sm)] p-1 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-surface-raised)] hover:text-[var(--as-fg)] focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]'\n\nconst COPIED_FEEDBACK_MS = 1500\n\n/**\n * The family chat bubble: role-aligned, hover action row (copy / edit /\n * regenerate + app extras), variant switcher under branched messages,\n * reasoning and below-content slots, inline edit-and-resend, error +\n * interrupted states. Presentational — state lives app-side.\n */\nexport const ChatMessage = React.forwardRef<HTMLDivElement, ChatMessageProps>(\n function ChatMessage(\n {\n role,\n content,\n reasoning,\n children,\n status = 'done',\n error,\n actions,\n editing = false,\n variants,\n onSelectVariant,\n meta,\n chips,\n attachments,\n avatar,\n design = 'bubbles',\n labels,\n compact = false,\n className,\n },\n ref,\n ) {\n const isUser = role === 'user'\n const isSystem = role === 'system'\n const showActions =\n actions !== undefined && (actions.onCopy !== undefined || actions.onEdit !== undefined || actions.onRegenerate !== undefined || (actions.extras?.length ?? 0) > 0)\n const editorLabels = { save: labels?.save, cancel: labels?.cancel, ariaLabel: labels?.ariaLabel }\n const switcherLabels = { group: labels?.group, variantOf: labels?.variantOf, previous: labels?.previous, next: labels?.next }\n const [copiedAt, setCopiedAt] = React.useState<number | null>(null)\n const copied = actions?.copied ?? copiedAt !== null\n\n React.useEffect(() => {\n if (copiedAt === null) {\n return\n }\n const id = window.setTimeout(() => setCopiedAt(null), COPIED_FEEDBACK_MS)\n return () => window.clearTimeout(id)\n }, [copiedAt])\n\n const onCopyClick = () => {\n actions?.onCopy?.()\n if (actions?.copied === undefined) {\n setCopiedAt(Date.now())\n }\n }\n\n if (isSystem) {\n return (\n <div\n ref={ref}\n data-as=\"chat-message\"\n data-role={role}\n className={cn('flex justify-center', className)}\n >\n <div className=\"rounded-full border border-[var(--as-border)] bg-[var(--as-surface)] px-3 py-1 text-xs text-[var(--as-muted-fg)]\">\n {content}\n </div>\n </div>\n )\n }\n\n return (\n <div\n ref={ref}\n data-as=\"chat-message\"\n data-role={role}\n data-status={status}\n data-design={design}\n className={cn('as-anim-message-in group/message flex w-full flex-col', isUser ? 'items-end' : 'items-start', className)}\n >\n {attachments ? <div className=\"mb-1.5 flex w-full flex-wrap justify-end gap-1.5\">{attachments}</div> : null}\n {(() => {\n const bubble = (\n <div\n className={cn(\n 'relative flex max-w-[92%] flex-col gap-1.5 rounded-[var(--as-radius)] px-3 py-2 text-sm',\n compact && 'px-2.5 py-1.5',\n isUser\n ? 'rounded-br-[var(--as-radius-sm)] bg-[var(--as-primary)] text-[var(--as-primary-fg)]'\n : design === 'flat'\n ? 'max-w-full rounded-bl-[var(--as-radius-sm)] bg-transparent px-0 py-0'\n : 'rounded-bl-[var(--as-radius-sm)] bg-[var(--as-muted)] text-[var(--as-fg)]',\n )}\n >\n {reasoning ? <div className=\"not-prose\">{reasoning}</div> : null}\n {editing ? (\n <ChatMessageEditor\n value={editing.value}\n onValueChange={editing.onValueChange}\n onSubmit={editing.onSubmit}\n onCancel={editing.onCancel}\n submitDisabled={editing.submitDisabled}\n labels={editorLabels}\n />\n ) : (\n <div\n key={variants && variants.count > 1 ? `variant-${variants.index}` : undefined}\n className={cn('min-w-0', variants && variants.count > 1 && 'as-anim-fade-swap')}\n >\n {content}\n </div>\n )}\n {status === 'interrupted' ? (\n <span className=\"as-anim-slide-up as-anim-pulse-once [--as-pulse-color:var(--as-warning)] self-start rounded-full bg-[var(--as-warning)]/15 px-2 py-0.5 text-[10px] font-medium uppercase tracking-wide text-[var(--as-warning)]\">\n {labels?.interrupted ?? 'Stopped'}\n </span>\n ) : null}\n {status === 'error' && error ? (\n <div\n role=\"alert\"\n className=\"as-anim-slide-up flex flex-col gap-1 rounded-[var(--as-radius)] border border-[var(--as-danger)]/40 bg-[var(--as-danger)]/10 px-2.5 py-1.5 text-xs text-[var(--as-danger)]\"\n >\n <span className=\"font-mono font-semibold uppercase tracking-wide\">{error.code}</span>\n <span className=\"whitespace-pre-wrap break-words\">{error.message}</span>\n {error.retryable && actions?.onRetry ? (\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <Button variant=\"outline\" size=\"sm\" className=\"self-start\" onClick={actions.onRetry}>\n {labels?.retry ?? 'Retry'}\n </Button>\n {actions?.errorExtra}\n </div>\n ) : actions?.errorExtra ? (\n <div className=\"self-start\">{actions.errorExtra}</div>\n ) : null}\n </div>\n ) : null}\n {chips ? <div className=\"flex flex-wrap gap-1.5\">{chips}</div> : null}\n {children ? <div className=\"flex flex-col gap-1.5\">{children}</div> : null}\n {showActions && !editing ? (\n <div\n data-as=\"chat-message-actions\"\n className={cn(\n 'absolute top-1 flex items-center gap-0.5 rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] p-0.5 shadow-[var(--as-shadow-1)]',\n isUser ? '-left-9' : '-right-9',\n )}\n >\n {actions?.onCopy ? (\n <button\n type=\"button\"\n className={actionButtonClass}\n aria-label={copied ? (labels?.copied ?? 'Copied') : (labels?.copy ?? 'Copy')}\n title={copied ? (labels?.copied ?? 'Copied') : (labels?.copy ?? 'Copy')}\n onClick={onCopyClick}\n >\n {copied ? (\n <Check className=\"as-anim-fade-swap size-3.5 text-[var(--as-success)]\" aria-hidden />\n ) : (\n <Copy className=\"size-3.5\" aria-hidden />\n )}\n </button>\n ) : null}\n {actions?.onEdit ? (\n <button type=\"button\" className={actionButtonClass} aria-label={labels?.edit ?? 'Edit'} title={labels?.edit ?? 'Edit'} onClick={actions.onEdit}>\n <Pencil className=\"size-3.5\" aria-hidden />\n </button>\n ) : null}\n {actions?.onRegenerate ? (\n <button type=\"button\" className={actionButtonClass} aria-label={labels?.regenerate ?? 'Regenerate'} title={labels?.regenerate ?? 'Regenerate'} onClick={actions.onRegenerate}>\n <RotateCcw className=\"size-3.5\" aria-hidden />\n </button>\n ) : null}\n {actions?.extras?.map((extra) => (\n <button\n key={extra.key}\n type=\"button\"\n className={cn(actionButtonClass, extra.danger && 'hover:text-[var(--as-danger)]')}\n aria-label={extra.label}\n title={extra.label}\n onClick={extra.onClick}\n >\n {extra.icon ? <extra.icon className=\"size-3.5\" aria-hidden /> : <TriangleAlert className=\"size-3.5\" aria-hidden />}\n </button>\n ))}\n </div>\n ) : null}\n </div>\n )\n return avatar !== undefined ? (\n <div className={cn('flex w-full items-end gap-2', isUser ? 'flex-row-reverse' : 'flex-row')}>\n <div data-as=\"chat-message-avatar\" className=\"shrink-0 pb-1\">\n {avatar}\n </div>\n {bubble}\n </div>\n ) : (\n bubble\n )\n })()}\n {meta ? <div className=\"mt-0.5 flex flex-wrap items-center gap-1.5 px-1 text-[10px] text-[var(--as-muted-fg)]\">{meta}</div> : null}\n {variants && variants.count > 1 && onSelectVariant ? (\n <MessageVariantSwitcher variants={variants} onSelect={onSelectVariant} labels={switcherLabels} className=\"mt-0.5 px-1\" />\n ) : null}\n </div>\n )\n },\n)\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-message/ChatMessageEditor.tsx","../src/components/chat-message/MessageVariantSwitcher.tsx","../src/components/chat-message/ChatMessage.tsx"],"names":["React","ChatMessageEditor","React2","MessageVariantSwitcher","jsxs","jsx","ChatMessage"],"mappings":"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","file":"chunk-56QSIK4Y.js","sourcesContent":["import * as React from 'react'\n\nimport { cn } from '../../lib/utils'\nimport { Button } from '../button/Button'\n\nexport interface ChatMessageEditorLabels {\n save: string\n cancel: string\n ariaLabel: string\n}\n\nexport interface ChatMessageEditorProps {\n value: string\n onValueChange: (value: string) => void\n /** Save & resend — branches the tree (family `edit` endpoint) and reruns the turn. */\n onSubmit: () => void\n onCancel: () => void\n submitDisabled?: boolean\n rows?: number\n labels?: Partial<ChatMessageEditorLabels>\n className?: string\n}\n\n/**\n * Inline user-prompt editor for the edit-and-resend flow (study pattern):\n * controlled textarea, Cmd/Ctrl+Enter saves, Escape cancels.\n */\nexport const ChatMessageEditor = React.forwardRef<HTMLDivElement, ChatMessageEditorProps>(\n function ChatMessageEditor(\n { value, onValueChange, onSubmit, onCancel, submitDisabled = false, rows = 3, labels, className },\n ref,\n ) {\n const onKeyDown: React.KeyboardEventHandler<HTMLTextAreaElement> = (event) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n onCancel()\n return\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n if (!submitDisabled) {\n onSubmit()\n }\n }\n }\n\n return (\n <div ref={ref} data-as=\"chat-message-editor\" className={cn('as-anim-slide-up flex w-full flex-col gap-2', className)}>\n <textarea\n autoFocus\n value={value}\n rows={rows}\n aria-label={labels?.ariaLabel ?? 'Edit message'}\n onChange={(event) => onValueChange(event.target.value)}\n onKeyDown={onKeyDown}\n className=\"w-full resize-y rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] px-3 py-2 text-sm text-[var(--as-fg)] placeholder:text-[var(--as-muted-fg)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]\"\n />\n <div className=\"flex items-center justify-end gap-2\">\n <Button variant=\"ghost\" size=\"sm\" onClick={onCancel}>\n {labels?.cancel ?? 'Cancel'}\n </Button>\n <Button size=\"sm\" disabled={submitDisabled} onClick={onSubmit}>\n {labels?.save ?? 'Save & resend'}\n </Button>\n </div>\n </div>\n )\n },\n)\n","import * as React from 'react'\nimport { ChevronLeft, ChevronRight } from 'lucide-react'\n\nimport type { ChatMessageVariants } from '../chat-core/types'\nimport { cn } from '../../lib/utils'\n\nexport interface MessageVariantSwitcherLabels {\n group: string\n variantOf: (index: number, count: number) => string\n previous: string\n next: string\n}\n\nexport interface MessageVariantSwitcherProps {\n variants: ChatMessageVariants\n /** Flip the parent's active-child pointer to the sibling id (family `select` endpoint). */\n onSelect: (messageId: string) => void\n labels?: Partial<MessageVariantSwitcherLabels>\n className?: string\n}\n\n/**\n * The `‹ n/N ›` sibling-variant switcher under a branched message\n * (study's inline switcher, family branching contract).\n */\nexport const MessageVariantSwitcher = React.forwardRef<HTMLDivElement, MessageVariantSwitcherProps>(\n function MessageVariantSwitcher({ variants, onSelect, labels, className }, ref) {\n const { index, count, siblingIds } = variants\n const previousId = index > 1 ? siblingIds[index - 2] : undefined\n const nextId = index < count ? siblingIds[index] : undefined\n\n const select = (event: React.MouseEvent<HTMLButtonElement>, messageId: string | undefined) => {\n event.stopPropagation()\n if (messageId !== undefined) {\n onSelect(messageId)\n }\n }\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={labels?.group ?? 'Message variants'}\n data-as=\"message-variant-switcher\"\n className={cn('flex items-center gap-0.5 text-xs text-[var(--as-muted-fg)]', className)}\n >\n <button\n type=\"button\"\n disabled={previousId === undefined}\n aria-label={labels?.previous ?? 'Previous variant'}\n title={labels?.previous ?? 'Previous variant'}\n onClick={(event) => select(event, previousId)}\n className=\"rounded-[var(--as-radius-sm)] p-0.5 transition-colors hover:bg-[var(--as-surface-raised)] hover:text-[var(--as-fg)] disabled:pointer-events-none disabled:opacity-30 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <ChevronLeft className=\"size-3.5\" aria-hidden />\n </button>\n <span className=\"tabular-nums\" title={labels?.variantOf?.(index, count) ?? `Variant ${index} of ${count}`}>\n {index}/{count}\n </span>\n <button\n type=\"button\"\n disabled={nextId === undefined}\n aria-label={labels?.next ?? 'Next variant'}\n title={labels?.next ?? 'Next variant'}\n onClick={(event) => select(event, nextId)}\n className=\"rounded-[var(--as-radius-sm)] p-0.5 transition-colors hover:bg-[var(--as-surface-raised)] hover:text-[var(--as-fg)] disabled:pointer-events-none disabled:opacity-30 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <ChevronRight className=\"size-3.5\" aria-hidden />\n </button>\n </div>\n )\n },\n)\n","import * as React from 'react'\nimport { Check, Copy, Pencil, RotateCcw, TriangleAlert } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\nimport { Button } from '../button/Button'\nimport type { ChatError, ChatMessageVariants, ChatRole } from '../chat-core/types'\nimport { ChatMessageEditor, type ChatMessageEditorLabels } from './ChatMessageEditor'\nimport { MessageVariantSwitcher, type MessageVariantSwitcherLabels } from './MessageVariantSwitcher'\n\nexport interface ChatMessageAction {\n key: string\n label: string\n icon?: LucideIcon\n onClick: () => void\n danger?: boolean\n}\n\nexport interface ChatMessageActions {\n onCopy?: () => void\n /**\n * Controlled copied feedback for the copy action (check morph).\n * Uncontrolled by default: the library shows the check for 1.5 s\n * after each copy click.\n */\n copied?: boolean\n onEdit?: () => void\n onRegenerate?: () => void\n onRetry?: () => void\n /** Extra icon actions (app-specific). */\n extras?: ChatMessageAction[]\n /**\n * Extra node rendered inside the error card next to the Retry button —\n * e.g. an \"Open AI settings\" link when the error is a not-configured\n * failure. Rendered only while the error card is visible.\n */\n errorExtra?: React.ReactNode\n}\n\nexport interface ChatMessageLabels {\n copy: string\n copied: string\n edit: string\n regenerate: string\n retry: string\n interrupted: string\n error: string\n}\n\nexport interface ChatMessageProps {\n role: ChatRole\n /** Usually a `MarkdownSurface`; any node graph renders here. */\n content: React.ReactNode\n /** Thinking block slot (usually `ChatReasoning`). */\n reasoning?: React.ReactNode\n /** Tool cards / HITL cards below the content. */\n children?: React.ReactNode\n status?: 'streaming' | 'done' | 'error' | 'interrupted'\n error?: ChatError\n actions?: ChatMessageActions\n /** Edit-and-resend mode for user messages (renders `ChatMessageEditor`). */\n editing?: false | { value: string; onValueChange: (value: string) => void; onSubmit: () => void; onCancel: () => void; submitDisabled?: boolean }\n variants?: ChatMessageVariants\n onSelectVariant?: (messageId: string) => void\n /** Badge row (model, latency, tokens — app-defined). */\n meta?: React.ReactNode\n /** Deep-link chip row (career references, health citations). */\n chips?: React.ReactNode\n /** Attachment rail above the content. */\n attachments?: React.ReactNode\n /** Leading identity node beside the bubble (user: trailing). Render group-start avatars only when grouping transcripts. */\n avatar?: React.ReactNode\n /**\n * Visual design: `bubbles` (default) — paired role bubbles; `flat` —\n * assistant content renders as prose on the panel surface (user keeps\n * its bubble). Reasoning/tool cards are unaffected.\n */\n design?: 'bubbles' | 'flat'\n labels?: Partial<ChatMessageLabels & ChatMessageEditorLabels & MessageVariantSwitcherLabels>\n compact?: boolean\n className?: string\n}\n\nconst actionButtonClass =\n 'rounded-[var(--as-radius-sm)] p-1 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-surface-raised)] hover:text-[var(--as-fg)] focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]'\n\nconst COPIED_FEEDBACK_MS = 1500\n\n/**\n * The family chat bubble: role-aligned, hover action row (copy / edit /\n * regenerate + app extras), variant switcher under branched messages,\n * reasoning and below-content slots, inline edit-and-resend, error +\n * interrupted states. Presentational — state lives app-side.\n */\nexport const ChatMessage = React.forwardRef<HTMLDivElement, ChatMessageProps>(\n function ChatMessage(\n {\n role,\n content,\n reasoning,\n children,\n status = 'done',\n error,\n actions,\n editing = false,\n variants,\n onSelectVariant,\n meta,\n chips,\n attachments,\n avatar,\n design = 'bubbles',\n labels,\n compact = false,\n className,\n },\n ref,\n ) {\n const isUser = role === 'user'\n const isSystem = role === 'system'\n const showActions =\n actions !== undefined && (actions.onCopy !== undefined || actions.onEdit !== undefined || actions.onRegenerate !== undefined || (actions.extras?.length ?? 0) > 0)\n const editorLabels = { save: labels?.save, cancel: labels?.cancel, ariaLabel: labels?.ariaLabel }\n const switcherLabels = { group: labels?.group, variantOf: labels?.variantOf, previous: labels?.previous, next: labels?.next }\n const [copiedAt, setCopiedAt] = React.useState<number | null>(null)\n const copied = actions?.copied ?? copiedAt !== null\n\n React.useEffect(() => {\n if (copiedAt === null) {\n return\n }\n const id = window.setTimeout(() => setCopiedAt(null), COPIED_FEEDBACK_MS)\n return () => window.clearTimeout(id)\n }, [copiedAt])\n\n const onCopyClick = () => {\n actions?.onCopy?.()\n if (actions?.copied === undefined) {\n setCopiedAt(Date.now())\n }\n }\n\n if (isSystem) {\n return (\n <div\n ref={ref}\n data-as=\"chat-message\"\n data-role={role}\n className={cn('flex justify-center', className)}\n >\n <div className=\"rounded-full border border-[var(--as-border)] bg-[var(--as-surface)] px-3 py-1 text-xs text-[var(--as-muted-fg)]\">\n {content}\n </div>\n </div>\n )\n }\n\n return (\n <div\n ref={ref}\n data-as=\"chat-message\"\n data-role={role}\n data-status={status}\n data-design={design}\n className={cn('as-anim-message-in group/message flex w-full flex-col', isUser ? 'items-end' : 'items-start', className)}\n >\n {attachments ? <div className=\"mb-1.5 flex w-full flex-wrap justify-end gap-1.5\">{attachments}</div> : null}\n {(() => {\n const bubble = (\n <div\n className={cn(\n 'relative flex max-w-[92%] flex-col gap-1.5 rounded-[var(--as-radius)] px-3 py-2 text-sm',\n compact && 'px-2.5 py-1.5',\n isUser\n ? 'rounded-br-[var(--as-radius-sm)] bg-[var(--as-primary)] font-medium text-[var(--as-primary-fg)]'\n : design === 'flat'\n ? 'max-w-full rounded-bl-[var(--as-radius-sm)] bg-transparent px-0 py-0'\n : 'rounded-bl-[var(--as-radius-sm)] bg-[var(--as-muted)] text-[var(--as-fg)]',\n )}\n >\n {reasoning ? <div className=\"not-prose\">{reasoning}</div> : null}\n {editing ? (\n <ChatMessageEditor\n value={editing.value}\n onValueChange={editing.onValueChange}\n onSubmit={editing.onSubmit}\n onCancel={editing.onCancel}\n submitDisabled={editing.submitDisabled}\n labels={editorLabels}\n />\n ) : (\n <div\n key={variants && variants.count > 1 ? `variant-${variants.index}` : undefined}\n className={cn('min-w-0', variants && variants.count > 1 && 'as-anim-fade-swap')}\n >\n {content}\n </div>\n )}\n {status === 'interrupted' ? (\n <span className=\"as-anim-slide-up as-anim-pulse-once [--as-pulse-color:var(--as-warning)] self-start rounded-full bg-[var(--as-warning)]/15 px-2 py-0.5 text-[10px] font-medium uppercase tracking-wide text-[var(--as-warning)]\">\n {labels?.interrupted ?? 'Stopped'}\n </span>\n ) : null}\n {status === 'error' && error ? (\n <div\n role=\"alert\"\n className=\"as-anim-slide-up flex flex-col gap-1 rounded-[var(--as-radius)] border border-[var(--as-danger)]/40 bg-[var(--as-danger)]/10 px-2.5 py-1.5 text-xs text-[var(--as-danger)]\"\n >\n <span className=\"font-mono font-semibold uppercase tracking-wide\">{error.code}</span>\n <span className=\"whitespace-pre-wrap break-words\">{error.message}</span>\n {error.retryable && actions?.onRetry ? (\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <Button variant=\"outline\" size=\"sm\" className=\"self-start\" onClick={actions.onRetry}>\n {labels?.retry ?? 'Retry'}\n </Button>\n {actions?.errorExtra}\n </div>\n ) : actions?.errorExtra ? (\n <div className=\"self-start\">{actions.errorExtra}</div>\n ) : null}\n </div>\n ) : null}\n {chips ? <div className=\"flex flex-wrap gap-1.5\">{chips}</div> : null}\n {children ? <div className=\"flex flex-col gap-1.5\">{children}</div> : null}\n {showActions && !editing ? (\n <div\n data-as=\"chat-message-actions\"\n className={cn(\n 'absolute top-1 flex items-center gap-0.5 rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] p-0.5 shadow-[var(--as-shadow-1)]',\n isUser ? '-left-9' : '-right-9',\n )}\n >\n {actions?.onCopy ? (\n <button\n type=\"button\"\n className={actionButtonClass}\n aria-label={copied ? (labels?.copied ?? 'Copied') : (labels?.copy ?? 'Copy')}\n title={copied ? (labels?.copied ?? 'Copied') : (labels?.copy ?? 'Copy')}\n onClick={onCopyClick}\n >\n {copied ? (\n <Check className=\"as-anim-fade-swap size-3.5 text-[var(--as-success)]\" aria-hidden />\n ) : (\n <Copy className=\"size-3.5\" aria-hidden />\n )}\n </button>\n ) : null}\n {actions?.onEdit ? (\n <button type=\"button\" className={actionButtonClass} aria-label={labels?.edit ?? 'Edit'} title={labels?.edit ?? 'Edit'} onClick={actions.onEdit}>\n <Pencil className=\"size-3.5\" aria-hidden />\n </button>\n ) : null}\n {actions?.onRegenerate ? (\n <button type=\"button\" className={actionButtonClass} aria-label={labels?.regenerate ?? 'Regenerate'} title={labels?.regenerate ?? 'Regenerate'} onClick={actions.onRegenerate}>\n <RotateCcw className=\"size-3.5\" aria-hidden />\n </button>\n ) : null}\n {actions?.extras?.map((extra) => (\n <button\n key={extra.key}\n type=\"button\"\n className={cn(actionButtonClass, extra.danger && 'hover:text-[var(--as-danger)]')}\n aria-label={extra.label}\n title={extra.label}\n onClick={extra.onClick}\n >\n {extra.icon ? <extra.icon className=\"size-3.5\" aria-hidden /> : <TriangleAlert className=\"size-3.5\" aria-hidden />}\n </button>\n ))}\n </div>\n ) : null}\n </div>\n )\n return avatar !== undefined ? (\n <div className={cn('flex w-full items-end gap-2', isUser ? 'flex-row-reverse' : 'flex-row')}>\n <div data-as=\"chat-message-avatar\" className=\"shrink-0 pb-1\">\n {avatar}\n </div>\n {bubble}\n </div>\n ) : (\n bubble\n )\n })()}\n {meta ? <div className=\"mt-0.5 flex flex-wrap items-center gap-1.5 px-1 text-[10px] text-[var(--as-muted-fg)]\">{meta}</div> : null}\n {variants && variants.count > 1 && onSelectVariant ? (\n <MessageVariantSwitcher variants={variants} onSelect={onSelectVariant} labels={switcherLabels} className=\"mt-0.5 px-1\" />\n ) : null}\n </div>\n )\n },\n)\n"]}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { ProviderLogo } from './chunk-7IP3JP3Z.js';
|
|
2
|
+
import { cn } from './chunk-RVVXVTH3.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Check, Settings2 } from 'lucide-react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var ProviderSetupTiles = React.forwardRef(function ProviderSetupTiles2({
|
|
8
|
+
presets,
|
|
9
|
+
configured,
|
|
10
|
+
suggestedKey,
|
|
11
|
+
onSelect,
|
|
12
|
+
children,
|
|
13
|
+
label = "Choose a provider",
|
|
14
|
+
localLabel = "Local",
|
|
15
|
+
configuredLabel = "Set up",
|
|
16
|
+
suggestedLabel = "Suggested for your pasted key",
|
|
17
|
+
className,
|
|
18
|
+
...props
|
|
19
|
+
}, ref) {
|
|
20
|
+
const configuredSet = new Set(configured);
|
|
21
|
+
return /* @__PURE__ */ jsxs(
|
|
22
|
+
"div",
|
|
23
|
+
{
|
|
24
|
+
ref,
|
|
25
|
+
role: "group",
|
|
26
|
+
"aria-label": label,
|
|
27
|
+
"data-as": "provider-setup-tiles",
|
|
28
|
+
className: cn(
|
|
29
|
+
"grid grid-cols-2 gap-2 sm:grid-cols-3",
|
|
30
|
+
className
|
|
31
|
+
),
|
|
32
|
+
...props,
|
|
33
|
+
children: [
|
|
34
|
+
presets.map((preset) => {
|
|
35
|
+
const isConfigured = configuredSet.has(preset.key);
|
|
36
|
+
const isSuggested = suggestedKey === preset.key;
|
|
37
|
+
return /* @__PURE__ */ jsxs(
|
|
38
|
+
"button",
|
|
39
|
+
{
|
|
40
|
+
type: "button",
|
|
41
|
+
"data-preset": preset.key,
|
|
42
|
+
"data-suggested": isSuggested || void 0,
|
|
43
|
+
"aria-disabled": preset.disabled || void 0,
|
|
44
|
+
disabled: preset.disabled,
|
|
45
|
+
onClick: () => {
|
|
46
|
+
if (!preset.disabled) onSelect(preset.key);
|
|
47
|
+
},
|
|
48
|
+
className: cn(
|
|
49
|
+
"flex h-auto cursor-pointer flex-col items-center gap-2 rounded-[var(--as-radius)] border px-3 py-4 text-sm font-medium text-[var(--as-fg)] transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)] disabled:cursor-not-allowed disabled:opacity-50",
|
|
50
|
+
isSuggested ? "border-[var(--as-focus-ring)] bg-[var(--as-muted)]" : "border-[var(--as-border)] bg-[var(--as-surface)] hover:bg-[var(--as-muted)]"
|
|
51
|
+
),
|
|
52
|
+
children: [
|
|
53
|
+
/* @__PURE__ */ jsx(ProviderLogo, { preset: preset.key }),
|
|
54
|
+
/* @__PURE__ */ jsx("span", { className: "w-full truncate text-center", children: preset.name }),
|
|
55
|
+
preset.local ? /* @__PURE__ */ jsx("span", { className: "text-xs font-normal text-[var(--as-muted-fg)]", children: localLabel }) : null,
|
|
56
|
+
preset.disabled && preset.disabledReason ? /* @__PURE__ */ jsx("span", { className: "text-xs font-normal text-[var(--as-muted-fg)]", children: preset.disabledReason }) : null,
|
|
57
|
+
isConfigured ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-xs font-normal text-[var(--as-success)]", children: [
|
|
58
|
+
/* @__PURE__ */ jsx(Check, { className: "size-3", "aria-hidden": true }),
|
|
59
|
+
configuredLabel
|
|
60
|
+
] }) : null,
|
|
61
|
+
isSuggested ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: suggestedLabel }) : null
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
preset.key
|
|
65
|
+
);
|
|
66
|
+
}),
|
|
67
|
+
children ? /* @__PURE__ */ jsx("div", { className: "contents", children }) : null
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
var ProviderSetupManualTile = React.forwardRef(function ProviderSetupManualTile2({ children, className, ...props }, ref) {
|
|
73
|
+
return /* @__PURE__ */ jsxs(
|
|
74
|
+
"button",
|
|
75
|
+
{
|
|
76
|
+
ref,
|
|
77
|
+
type: "button",
|
|
78
|
+
"data-as": "provider-setup-manual-tile",
|
|
79
|
+
className: cn(
|
|
80
|
+
"flex h-auto cursor-pointer flex-col items-center gap-2 rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] px-3 py-4 text-sm font-medium text-[var(--as-fg)] transition-colors hover:bg-[var(--as-muted)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]",
|
|
81
|
+
className
|
|
82
|
+
),
|
|
83
|
+
...props,
|
|
84
|
+
children: [
|
|
85
|
+
/* @__PURE__ */ jsx("span", { className: "inline-flex size-5 shrink-0 items-center justify-center text-[var(--as-muted-fg)]", children: /* @__PURE__ */ jsx(Settings2, { className: "size-5", "aria-hidden": true }) }),
|
|
86
|
+
children
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export { ProviderSetupManualTile, ProviderSetupTiles };
|
|
93
|
+
//# sourceMappingURL=chunk-65JY3ATO.js.map
|
|
94
|
+
//# sourceMappingURL=chunk-65JY3ATO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/provider-setup-tiles/ProviderSetupTiles.tsx"],"names":["ProviderSetupTiles","ProviderSetupManualTile"],"mappings":"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","file":"chunk-65JY3ATO.js","sourcesContent":["import * as React from 'react'\nimport { Check, Settings2 } from 'lucide-react'\nimport { cn } from '../../lib/utils'\nimport { ProviderLogo } from '../provider-logo/ProviderLogo'\n\n/** One preset entry (ADR-006: the catalog is app data — the tiles only\n * render it, in the order given, with equal weight). */\nexport interface ProviderSetupTileData {\n key: string\n name: string\n /** Keyless local preset (e.g. Ollama) — renders the `localLabel` caption. */\n local?: boolean\n /** Disabled tiles render inert with their reason (health's overlay). */\n disabled?: boolean\n disabledReason?: string\n /** The preset ships a key-prefix hint (informational for the app). */\n hasKeyPrefixHint?: boolean\n}\n\nexport interface ProviderSetupTilesProps\n extends Omit<React.ComponentProps<'div'>, 'onSelect' | 'children'> {\n /** Presets in the app's family order — the grid keeps it verbatim. */\n presets: ProviderSetupTileData[]\n /** Preset keys already configured (renders the `configuredLabel` badge). */\n configured?: string[]\n /** Key of a tile the app's paste-prefix match suggests (highlight only —\n * never a \"recommended\" ranking; all tiles stay equal weight). */\n suggestedKey?: string\n /** Fires with the preset key of the activated tile. */\n onSelect: (key: string) => void\n /** Extra grid cell (e.g. the \"Manual / custom\" tile) — app-composed. */\n children?: React.ReactNode\n label?: string\n localLabel?: string\n configuredLabel?: string\n /** Visually-hidden text marking the suggested tile. */\n suggestedLabel?: string\n}\n\n/** Neutral, equal-weight provider picker grid — step one of the family's\n * one-click setup (plan 26 §6): tiles in family order, no \"recommended\"\n * anywhere, local presets visible, disabled presets explain themselves. */\nexport const ProviderSetupTiles = React.forwardRef<\n HTMLDivElement,\n ProviderSetupTilesProps\n>(function ProviderSetupTiles(\n {\n presets,\n configured,\n suggestedKey,\n onSelect,\n children,\n label = 'Choose a provider',\n localLabel = 'Local',\n configuredLabel = 'Set up',\n suggestedLabel = 'Suggested for your pasted key',\n className,\n ...props\n },\n ref,\n) {\n const configuredSet = new Set(configured)\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={label}\n data-as=\"provider-setup-tiles\"\n className={cn(\n 'grid grid-cols-2 gap-2 sm:grid-cols-3',\n className,\n )}\n {...props}\n >\n {presets.map((preset) => {\n const isConfigured = configuredSet.has(preset.key)\n const isSuggested = suggestedKey === preset.key\n return (\n <button\n key={preset.key}\n type=\"button\"\n data-preset={preset.key}\n data-suggested={isSuggested || undefined}\n aria-disabled={preset.disabled || undefined}\n disabled={preset.disabled}\n onClick={() => {\n if (!preset.disabled) onSelect(preset.key)\n }}\n className={cn(\n 'flex h-auto cursor-pointer flex-col items-center gap-2 rounded-[var(--as-radius)] border px-3 py-4 text-sm font-medium text-[var(--as-fg)] transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)] disabled:cursor-not-allowed disabled:opacity-50',\n isSuggested\n ? 'border-[var(--as-focus-ring)] bg-[var(--as-muted)]'\n : 'border-[var(--as-border)] bg-[var(--as-surface)] hover:bg-[var(--as-muted)]',\n )}\n >\n <ProviderLogo preset={preset.key} />\n <span className=\"w-full truncate text-center\">{preset.name}</span>\n {preset.local ? (\n <span className=\"text-xs font-normal text-[var(--as-muted-fg)]\">\n {localLabel}\n </span>\n ) : null}\n {preset.disabled && preset.disabledReason ? (\n <span className=\"text-xs font-normal text-[var(--as-muted-fg)]\">\n {preset.disabledReason}\n </span>\n ) : null}\n {isConfigured ? (\n <span className=\"inline-flex items-center gap-1 text-xs font-normal text-[var(--as-success)]\">\n <Check className=\"size-3\" aria-hidden />\n {configuredLabel}\n </span>\n ) : null}\n {isSuggested ? (\n <span className=\"sr-only\">{suggestedLabel}</span>\n ) : null}\n </button>\n )\n })}\n {children ? <div className=\"contents\">{children}</div> : null}\n </div>\n )\n})\n\n/** The \"manual / custom\" tile apps append as `children` of the grid. */\nexport const ProviderSetupManualTile = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<'button'>\n>(function ProviderSetupManualTile(\n { children, className, ...props },\n ref,\n) {\n return (\n <button\n ref={ref}\n type=\"button\"\n data-as=\"provider-setup-manual-tile\"\n className={cn(\n 'flex h-auto cursor-pointer flex-col items-center gap-2 rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] px-3 py-4 text-sm font-medium text-[var(--as-fg)] transition-colors hover:bg-[var(--as-muted)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]',\n className,\n )}\n {...props}\n >\n <span className=\"inline-flex size-5 shrink-0 items-center justify-center text-[var(--as-muted-fg)]\">\n <Settings2 className=\"size-5\" aria-hidden />\n </span>\n {children}\n </button>\n )\n})\n"]}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { CopyButton } from './chunk-XFYCNCPS.js';
|
|
2
|
+
import { Input } from './chunk-GQDW6BBO.js';
|
|
3
|
+
import { Button } from './chunk-4WBBF5LH.js';
|
|
4
|
+
import { cn } from './chunk-RVVXVTH3.js';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { ExternalLink } from 'lucide-react';
|
|
7
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
var SETUP_ERROR_CODES = [
|
|
10
|
+
"invalid_key",
|
|
11
|
+
"insufficient_credit",
|
|
12
|
+
"new_user_quota",
|
|
13
|
+
"region_unavailable",
|
|
14
|
+
"timeout",
|
|
15
|
+
"local_not_running",
|
|
16
|
+
"unknown"
|
|
17
|
+
];
|
|
18
|
+
var DEFAULT_SETUP_ERROR_COPY = {
|
|
19
|
+
invalid_key: "The API key was rejected \u2014 check it and try again.",
|
|
20
|
+
insufficient_credit: "The account has no credit or quota left for this key.",
|
|
21
|
+
new_user_quota: "The provider hit a rate or quota limit \u2014 try again later.",
|
|
22
|
+
region_unavailable: "This provider or model is not available in your region.",
|
|
23
|
+
timeout: "The provider took too long to answer \u2014 try again.",
|
|
24
|
+
local_not_running: "Could not reach the local engine \u2014 make sure it is running.",
|
|
25
|
+
unknown: "The provider reported an unknown error."
|
|
26
|
+
};
|
|
27
|
+
var ProviderSetupForm = React.forwardRef(function ProviderSetupForm2({
|
|
28
|
+
preset,
|
|
29
|
+
value,
|
|
30
|
+
error,
|
|
31
|
+
testing = false,
|
|
32
|
+
onSubmit,
|
|
33
|
+
onCancel,
|
|
34
|
+
onChange,
|
|
35
|
+
errorLabels,
|
|
36
|
+
suspectedVendorHint = "This looks like a {vendor} API key.",
|
|
37
|
+
onCopyStep,
|
|
38
|
+
onOpenKeyUrl,
|
|
39
|
+
advancedExtra,
|
|
40
|
+
checklistLabel = "Setup steps",
|
|
41
|
+
copyLabel = "Copy",
|
|
42
|
+
getKeyLabel = "Get an API key",
|
|
43
|
+
nameLabel = "Connection name",
|
|
44
|
+
apiKeyLabel = "API key",
|
|
45
|
+
keyPlaceholder = "sk-\u2026",
|
|
46
|
+
noKeyLabel = "Runs on your machine \u2014 no API key needed.",
|
|
47
|
+
advancedLabel = "Advanced",
|
|
48
|
+
baseUrlLabel = "API base URL",
|
|
49
|
+
baseUrlHint,
|
|
50
|
+
submitLabel = "Connect",
|
|
51
|
+
cancelLabel = "Back",
|
|
52
|
+
className,
|
|
53
|
+
...props
|
|
54
|
+
}, ref) {
|
|
55
|
+
const stepText = (step) => step.replaceAll("{url}", preset.keyUrl ?? "");
|
|
56
|
+
const errorCopy = error ? errorLabels?.[error.code] ?? DEFAULT_SETUP_ERROR_COPY[error.code] ?? errorLabels?.unknown ?? DEFAULT_SETUP_ERROR_COPY.unknown : null;
|
|
57
|
+
return /* @__PURE__ */ jsxs(
|
|
58
|
+
"form",
|
|
59
|
+
{
|
|
60
|
+
ref,
|
|
61
|
+
"data-as": "provider-setup-form",
|
|
62
|
+
className: cn("flex w-full flex-col gap-3", className),
|
|
63
|
+
onSubmit: (event) => {
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
if (!testing) onSubmit(value);
|
|
66
|
+
},
|
|
67
|
+
...props,
|
|
68
|
+
children: [
|
|
69
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-[var(--as-fg)]", children: preset.name }),
|
|
70
|
+
preset.steps && preset.steps.length > 0 ? /* @__PURE__ */ jsx(
|
|
71
|
+
"ol",
|
|
72
|
+
{
|
|
73
|
+
"aria-label": checklistLabel,
|
|
74
|
+
className: "list-inside list-decimal space-y-1 text-sm text-[var(--as-muted-fg)]",
|
|
75
|
+
children: preset.steps.map((step, index) => /* @__PURE__ */ jsxs("li", { className: "flex items-start justify-between gap-2", children: [
|
|
76
|
+
/* @__PURE__ */ jsx("span", { children: stepText(step) }),
|
|
77
|
+
/* @__PURE__ */ jsx(
|
|
78
|
+
CopyButton,
|
|
79
|
+
{
|
|
80
|
+
value: step,
|
|
81
|
+
label: copyLabel,
|
|
82
|
+
size: 14,
|
|
83
|
+
className: "mt-0.5 size-6 shrink-0",
|
|
84
|
+
onClick: () => onCopyStep?.(step)
|
|
85
|
+
}
|
|
86
|
+
)
|
|
87
|
+
] }, index))
|
|
88
|
+
}
|
|
89
|
+
) : null,
|
|
90
|
+
preset.keyUrl ? onOpenKeyUrl ? /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
|
|
91
|
+
Button,
|
|
92
|
+
{
|
|
93
|
+
type: "button",
|
|
94
|
+
variant: "outline",
|
|
95
|
+
size: "sm",
|
|
96
|
+
onClick: () => onOpenKeyUrl(preset.keyUrl),
|
|
97
|
+
children: [
|
|
98
|
+
/* @__PURE__ */ jsx(ExternalLink, { "aria-hidden": true }),
|
|
99
|
+
getKeyLabel
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
) }) : /* @__PURE__ */ jsxs(
|
|
103
|
+
"a",
|
|
104
|
+
{
|
|
105
|
+
href: preset.keyUrl,
|
|
106
|
+
target: "_blank",
|
|
107
|
+
rel: "noreferrer",
|
|
108
|
+
className: "inline-flex w-fit items-center gap-1 text-sm font-medium text-[var(--as-primary)] underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]",
|
|
109
|
+
children: [
|
|
110
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "size-3.5", "aria-hidden": true }),
|
|
111
|
+
getKeyLabel
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
) : null,
|
|
115
|
+
preset.freeTierNote ? /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--as-muted-fg)]", children: preset.freeTierNote }) : null,
|
|
116
|
+
/* @__PURE__ */ jsx(
|
|
117
|
+
Input,
|
|
118
|
+
{
|
|
119
|
+
label: nameLabel,
|
|
120
|
+
value: value.name,
|
|
121
|
+
placeholder: preset.name,
|
|
122
|
+
onChange: (event) => onChange({ ...value, name: event.target.value })
|
|
123
|
+
}
|
|
124
|
+
),
|
|
125
|
+
preset.local ? /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--as-muted-fg)]", children: noKeyLabel }) : /* @__PURE__ */ jsx(
|
|
126
|
+
Input,
|
|
127
|
+
{
|
|
128
|
+
label: apiKeyLabel,
|
|
129
|
+
type: "password",
|
|
130
|
+
autoComplete: "new-password",
|
|
131
|
+
placeholder: keyPlaceholder,
|
|
132
|
+
value: value.apiKey,
|
|
133
|
+
onChange: (event) => onChange({ ...value, apiKey: event.target.value })
|
|
134
|
+
}
|
|
135
|
+
),
|
|
136
|
+
/* @__PURE__ */ jsxs("details", { className: "rounded-[var(--as-radius)] border border-[var(--as-border)] px-3 py-2", children: [
|
|
137
|
+
/* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-sm font-medium text-[var(--as-fg)]", children: advancedLabel }),
|
|
138
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 pt-2", children: [
|
|
139
|
+
/* @__PURE__ */ jsx(
|
|
140
|
+
Input,
|
|
141
|
+
{
|
|
142
|
+
label: baseUrlLabel,
|
|
143
|
+
value: value.baseUrl ?? "",
|
|
144
|
+
readOnly: preset.fixedBase,
|
|
145
|
+
className: "font-mono data-[readonly]:cursor-default data-[readonly]:opacity-80",
|
|
146
|
+
onChange: (event) => onChange({ ...value, baseUrl: event.target.value })
|
|
147
|
+
}
|
|
148
|
+
),
|
|
149
|
+
!preset.fixedBase && baseUrlHint ? /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--as-muted-fg)]", children: baseUrlHint }) : null,
|
|
150
|
+
advancedExtra
|
|
151
|
+
] })
|
|
152
|
+
] }),
|
|
153
|
+
error && errorCopy ? /* @__PURE__ */ jsxs("div", { role: "alert", className: "space-y-1", children: [
|
|
154
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-[var(--as-danger)]", children: errorCopy }),
|
|
155
|
+
error.suspectedVendor ? /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--as-muted-fg)]", children: suspectedVendorHint.replaceAll(
|
|
156
|
+
"{vendor}",
|
|
157
|
+
error.suspectedVendor
|
|
158
|
+
) }) : null
|
|
159
|
+
] }) : null,
|
|
160
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
|
|
161
|
+
onCancel ? /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: onCancel, children: cancelLabel }) : null,
|
|
162
|
+
/* @__PURE__ */ jsx(
|
|
163
|
+
Button,
|
|
164
|
+
{
|
|
165
|
+
type: "submit",
|
|
166
|
+
size: "sm",
|
|
167
|
+
loading: testing,
|
|
168
|
+
disabled: testing || !preset.local && value.apiKey.trim() === "",
|
|
169
|
+
children: submitLabel
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
] })
|
|
173
|
+
]
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
export { DEFAULT_SETUP_ERROR_COPY, ProviderSetupForm, SETUP_ERROR_CODES };
|
|
179
|
+
//# sourceMappingURL=chunk-6G7H6YP6.js.map
|
|
180
|
+
//# sourceMappingURL=chunk-6G7H6YP6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/provider-setup-form/ProviderSetupForm.tsx"],"names":["ProviderSetupForm"],"mappings":"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","file":"chunk-6G7H6YP6.js","sourcesContent":["import * as React from 'react'\nimport { ExternalLink } from 'lucide-react'\nimport { cn } from '../../lib/utils'\nimport { Button } from '../button/Button'\nimport { CopyButton } from '../copy-button/CopyButton'\nimport { Input } from '../input/Input'\n\n/** The shared §15 error-routing enum (family contract — apps key their i18n\n * off exactly these codes). */\nexport const SETUP_ERROR_CODES = [\n 'invalid_key',\n 'insufficient_credit',\n 'new_user_quota',\n 'region_unavailable',\n 'timeout',\n 'local_not_running',\n 'unknown',\n] as const\n\nexport type SetupErrorCode = (typeof SETUP_ERROR_CODES)[number]\n\n/** English fallback copy per code — apps inject translated labels via\n * `errorLabels` (the library ships no i18n engine, ADR-006). */\nexport const DEFAULT_SETUP_ERROR_COPY: Record<SetupErrorCode, string> = {\n invalid_key: 'The API key was rejected — check it and try again.',\n insufficient_credit: 'The account has no credit or quota left for this key.',\n new_user_quota: 'The provider hit a rate or quota limit — try again later.',\n region_unavailable: 'This provider or model is not available in your region.',\n timeout: 'The provider took too long to answer — try again.',\n local_not_running: 'Could not reach the local engine — make sure it is running.',\n unknown: 'The provider reported an unknown error.',\n}\n\n/** Guided-setup preset slice (app data; snake_case API fields map app-side). */\nexport interface ProviderSetupFormPreset {\n name: string\n keyUrl?: string\n steps?: string[]\n freeTierNote?: string\n fixedBase?: boolean\n baseUrl: string\n /** Keyless local preset — renders `noKeyLabel` instead of the key field. */\n local?: boolean\n}\n\nexport interface ProviderSetupFormValue {\n name: string\n apiKey: string\n baseUrl?: string\n}\n\n/** Classified setup failure (§15 error routing) — copy comes from\n * `errorLabels`, keyed off the code. */\nexport interface ProviderSetupFormError {\n code: SetupErrorCode | string\n suspectedVendor?: string | null\n}\n\nexport interface ProviderSetupFormProps\n extends Omit<React.ComponentProps<'form'>, 'onChange' | 'onSubmit'> {\n preset: ProviderSetupFormPreset\n /** Controlled field values. */\n value: ProviderSetupFormValue\n error?: ProviderSetupFormError | null\n /** Validation/connection test in flight — disables + marks the submit. */\n testing?: boolean\n onSubmit: (value: ProviderSetupFormValue) => void\n onCancel?: () => void\n onChange: (value: ProviderSetupFormValue) => void\n /** Translated error copy per §15 code (`{vendor}` interpolates in the hint). */\n errorLabels?: Partial<Record<string, string>>\n suspectedVendorHint?: string\n /** Notified when a checklist step is copied (Electron apps mirror the copy\n * through their IPC clipboard; the browser write always happens). */\n onCopyStep?: (step: string) => void\n /** Opens the key page — render an anchor by default; Electron apps pass\n * their `openExternal` bridge to get a button instead. */\n onOpenKeyUrl?: (url: string) => void\n /** Extra app content inside the Advanced disclosure (hosting toggle,\n * country select — study/health pattern). */\n advancedExtra?: React.ReactNode\n checklistLabel?: string\n copyLabel?: string\n getKeyLabel?: string\n nameLabel?: string\n apiKeyLabel?: string\n keyPlaceholder?: string\n noKeyLabel?: string\n advancedLabel?: string\n baseUrlLabel?: string\n baseUrlHint?: string\n submitLabel?: string\n cancelLabel?: string\n}\n\n/** Guided one-click setup form (plan 26 §6): vendor checklist with copy\n * buttons and key link, connection name, write-only API key\n * (`autoComplete=\"new-password\"`), and an Advanced disclosure whose base URL\n * is read-only for fixed-endpoint presets. Validation, secrets and IPC are\n * the app's business (ADR-006) — the form reports `onSubmit`. */\nexport const ProviderSetupForm = React.forwardRef<\n HTMLFormElement,\n ProviderSetupFormProps\n>(function ProviderSetupForm(\n {\n preset,\n value,\n error,\n testing = false,\n onSubmit,\n onCancel,\n onChange,\n errorLabels,\n suspectedVendorHint = 'This looks like a {vendor} API key.',\n onCopyStep,\n onOpenKeyUrl,\n advancedExtra,\n checklistLabel = 'Setup steps',\n copyLabel = 'Copy',\n getKeyLabel = 'Get an API key',\n nameLabel = 'Connection name',\n apiKeyLabel = 'API key',\n keyPlaceholder = 'sk-…',\n noKeyLabel = 'Runs on your machine — no API key needed.',\n advancedLabel = 'Advanced',\n baseUrlLabel = 'API base URL',\n baseUrlHint,\n submitLabel = 'Connect',\n cancelLabel = 'Back',\n className,\n ...props\n },\n ref,\n) {\n const stepText = (step: string): string =>\n step.replaceAll('{url}', preset.keyUrl ?? '')\n\n const errorCopy = error\n ? (errorLabels?.[error.code] ??\n DEFAULT_SETUP_ERROR_COPY[error.code as SetupErrorCode] ??\n errorLabels?.unknown ??\n DEFAULT_SETUP_ERROR_COPY.unknown)\n : null\n\n return (\n <form\n ref={ref}\n data-as=\"provider-setup-form\"\n className={cn('flex w-full flex-col gap-3', className)}\n onSubmit={(event) => {\n event.preventDefault()\n if (!testing) onSubmit(value)\n }}\n {...props}\n >\n <h3 className=\"text-sm font-semibold text-[var(--as-fg)]\">{preset.name}</h3>\n\n {preset.steps && preset.steps.length > 0 ? (\n <ol\n aria-label={checklistLabel}\n className=\"list-inside list-decimal space-y-1 text-sm text-[var(--as-muted-fg)]\"\n >\n {preset.steps.map((step, index) => (\n <li key={index} className=\"flex items-start justify-between gap-2\">\n <span>{stepText(step)}</span>\n <CopyButton\n value={step}\n label={copyLabel}\n size={14}\n className=\"mt-0.5 size-6 shrink-0\"\n onClick={() => onCopyStep?.(step)}\n />\n </li>\n ))}\n </ol>\n ) : null}\n\n {preset.keyUrl ? onOpenKeyUrl ? (\n <div>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => onOpenKeyUrl(preset.keyUrl!)}\n >\n <ExternalLink aria-hidden />\n {getKeyLabel}\n </Button>\n </div>\n ) : (\n <a\n href={preset.keyUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex w-fit items-center gap-1 text-sm font-medium text-[var(--as-primary)] underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <ExternalLink className=\"size-3.5\" aria-hidden />\n {getKeyLabel}\n </a>\n ) : null}\n\n {preset.freeTierNote ? (\n <p className=\"text-xs text-[var(--as-muted-fg)]\">{preset.freeTierNote}</p>\n ) : null}\n\n <Input\n label={nameLabel}\n value={value.name}\n placeholder={preset.name}\n onChange={(event) => onChange({ ...value, name: event.target.value })}\n />\n\n {preset.local ? (\n <p className=\"text-sm text-[var(--as-muted-fg)]\">{noKeyLabel}</p>\n ) : (\n <Input\n label={apiKeyLabel}\n type=\"password\"\n autoComplete=\"new-password\"\n placeholder={keyPlaceholder}\n value={value.apiKey}\n onChange={(event) => onChange({ ...value, apiKey: event.target.value })}\n />\n )}\n\n <details className=\"rounded-[var(--as-radius)] border border-[var(--as-border)] px-3 py-2\">\n <summary className=\"cursor-pointer text-sm font-medium text-[var(--as-fg)]\">\n {advancedLabel}\n </summary>\n <div className=\"flex flex-col gap-1 pt-2\">\n <Input\n label={baseUrlLabel}\n value={value.baseUrl ?? ''}\n readOnly={preset.fixedBase}\n className=\"font-mono data-[readonly]:cursor-default data-[readonly]:opacity-80\"\n onChange={(event) =>\n onChange({ ...value, baseUrl: event.target.value })\n }\n />\n {!preset.fixedBase && baseUrlHint ? (\n <p className=\"text-xs text-[var(--as-muted-fg)]\">{baseUrlHint}</p>\n ) : null}\n {advancedExtra}\n </div>\n </details>\n\n {error && errorCopy ? (\n <div role=\"alert\" className=\"space-y-1\">\n <p className=\"text-sm font-medium text-[var(--as-danger)]\">\n {errorCopy}\n </p>\n {error.suspectedVendor ? (\n <p className=\"text-sm text-[var(--as-muted-fg)]\">\n {suspectedVendorHint.replaceAll(\n '{vendor}',\n error.suspectedVendor,\n )}\n </p>\n ) : null}\n </div>\n ) : null}\n\n <div className=\"flex items-center justify-end gap-2\">\n {onCancel ? (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onCancel}>\n {cancelLabel}\n </Button>\n ) : null}\n <Button\n type=\"submit\"\n size=\"sm\"\n loading={testing}\n disabled={testing || (!preset.local && value.apiKey.trim() === '')}\n >\n {submitLabel}\n </Button>\n </div>\n </form>\n )\n})\n"]}
|