@timbal-ai/timbal-react 0.8.1 → 1.0.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.
@@ -16,6 +16,179 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
16
16
  */
17
17
  declare const APP_KIT_AGENT_INSTRUCTIONS: string;
18
18
 
19
+ /**
20
+ * The single source of truth for what generated Timbal UIs are *allowed* to
21
+ * look like — the anti-slop constraint, encoded as data.
22
+ *
23
+ * Both the deterministic linter (`ui-lint.ts`) and the agent prompt
24
+ * (`APP_KIT_AGENT_INSTRUCTIONS`) read from this module, so the rules a model is
25
+ * told and the rules it is checked against can never drift apart.
26
+ *
27
+ * "Slop" = the generic AI-dashboard look: a decorative icon on every tile,
28
+ * loud green/red trend pills, arbitrary palette colors, gratuitous dividers,
29
+ * card-in-card nesting, bold giant numbers. Taste lives here, not in prose.
30
+ *
31
+ * This is a **public, documented** API (exported from the package root and
32
+ * `/app`), in the same tier as the theme generator — not an internal class
33
+ * composite.
34
+ */
35
+ /**
36
+ * Semantic color token roots the design system defines (see `styles.css`).
37
+ * Generated code may only reach for colors through these — `bg-background`,
38
+ * `text-muted-foreground`, `border-border`, `text-primary`, `bg-destructive`,
39
+ * the timbal chrome extensions, etc. Anything else is slop.
40
+ */
41
+ declare const SEMANTIC_COLOR_TOKENS: readonly ["background", "foreground", "card", "card-foreground", "popover", "popover-foreground", "primary", "primary-foreground", "secondary", "secondary-foreground", "muted", "muted-foreground", "accent", "accent-foreground", "destructive", "destructive-foreground", "border", "input", "ring", "sidebar", "sidebar-foreground", "sidebar-primary", "sidebar-primary-foreground", "sidebar-accent", "sidebar-accent-foreground", "sidebar-border", "sidebar-ring", "elevated-from", "elevated-to", "modal-from", "modal-to", "playground-from", "playground-via", "playground-to", "composer-bg", "composer-border", "composer-border-focus", "bubble-user", "bubble-user-foreground", "code-block-bg", "code-header-bg"];
42
+ type SemanticColorToken = (typeof SEMANTIC_COLOR_TOKENS)[number];
43
+ /**
44
+ * Gradient / fill tokens reserved for **chrome only** (buttons, the elevated
45
+ * surface, the modal shell, the playground backdrop). They must never decorate
46
+ * a data card, a stat tile, or a list — that is the canonical "slop gradient".
47
+ */
48
+ declare const RESERVED_GRADIENT_TOKENS: readonly ["primary-fill-from", "primary-fill-to", "primary-fill-hover-from", "primary-fill-hover-to", "primary-fill-active-from", "primary-fill-active-to", "secondary-fill-hover-from", "secondary-fill-hover-to", "secondary-fill-active-from", "secondary-fill-active-to", "destructive-fill-hover-from", "destructive-fill-hover-to", "destructive-fill-active-from", "destructive-fill-active-to", "ghost-fill-hover", "ghost-fill-active", "elevated-from", "elevated-to", "modal-from", "modal-to", "playground-from", "playground-via", "playground-to"];
49
+ /**
50
+ * The Tailwind named palette. Any of these followed by a numeric shade
51
+ * (`-50`..`-950`) in a color utility is a hardcoded color — not a token —
52
+ * and is rejected by the linter.
53
+ */
54
+ declare const TAILWIND_PALETTE_COLORS: readonly ["slate", "gray", "zinc", "neutral", "stone", "red", "orange", "amber", "yellow", "lime", "green", "emerald", "teal", "cyan", "sky", "blue", "indigo", "violet", "purple", "fuchsia", "pink", "rose"];
55
+ /** Tailwind color-bearing utility prefixes the linter inspects. */
56
+ declare const COLOR_UTILITY_PREFIXES: readonly ["bg", "text", "border", "ring", "from", "via", "to", "fill", "stroke", "decoration", "outline", "shadow", "divide", "accent", "caret"];
57
+ /**
58
+ * Numeric budgets the linter enforces. Tuned for "tasteful dashboard", not
59
+ * "icon confetti". A view that needs more icons than this is almost always
60
+ * decorating instead of communicating.
61
+ */
62
+ declare const SLOP_BUDGETS: {
63
+ /** Max decorative/standalone icons rendered in a single generated file. */
64
+ readonly maxIconsPerView: 6;
65
+ /** Max consecutive list rows separated by an explicit border/divider before
66
+ * it reads as a "ruled table" — prefer spacing or zebra instead. */
67
+ readonly maxRowDividers: 2;
68
+ };
69
+ /**
70
+ * House-style rules in plain language. The prompt renders these verbatim and
71
+ * the linter maps each `id` to a check, so the model is told and tested on the
72
+ * exact same list.
73
+ */
74
+ interface HouseRule {
75
+ id: string;
76
+ /** One-line imperative the agent reads. */
77
+ rule: string;
78
+ /** Why it matters (kept short — models follow rules with rationale better). */
79
+ why: string;
80
+ /** A wrong example (kept to a fragment). */
81
+ slop?: string;
82
+ /** The tasteful equivalent. */
83
+ good?: string;
84
+ }
85
+ declare const HOUSE_RULES: readonly HouseRule[];
86
+
87
+ /**
88
+ * Deterministic anti-slop linter for generated Timbal UI code.
89
+ *
90
+ * Runs a dependency-free line scan over a `.tsx` string and flags the patterns
91
+ * that turn a clean dashboard into generic AI slop: hardcoded colors, icon
92
+ * spam, bold giant numbers, divider-per-row lists, gradients on data cards.
93
+ *
94
+ * It intentionally avoids a full AST/parser dependency — the checks are
95
+ * line/regex heuristics tuned for high precision on the patterns that actually
96
+ * recur in generated output. Feed `formatLintReport(findings)` back to the
97
+ * generating agent (see `reviewGeneratedUi`) so it can self-correct.
98
+ *
99
+ * Public, documented API — exported from the package root and `/app`.
100
+ */
101
+ type LintSeverity = "error" | "warn";
102
+ interface LintFinding {
103
+ /** Stable rule id (maps to a HouseRule where applicable). */
104
+ rule: string;
105
+ severity: LintSeverity;
106
+ /** 1-based line number in the supplied source. */
107
+ line: number;
108
+ /** Human-readable explanation + fix. */
109
+ message: string;
110
+ /** The offending source fragment (trimmed). */
111
+ snippet: string;
112
+ }
113
+ interface LintResult {
114
+ findings: LintFinding[];
115
+ errorCount: number;
116
+ warnCount: number;
117
+ /** True when there are no `error`-severity findings. */
118
+ ok: boolean;
119
+ }
120
+ interface LintOptions {
121
+ /** Max standalone icons before `icon-spam` fires. Defaults to the budget. */
122
+ maxIconsPerView?: number;
123
+ /** Max bordered list rows before `row-divider` fires. Defaults to the budget. */
124
+ maxRowDividers?: number;
125
+ /** Treat warnings as errors (so `ok` reflects them too). */
126
+ strict?: boolean;
127
+ }
128
+ /**
129
+ * Lint a single generated `.tsx` (or fragment) string for slop.
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * const { ok, findings } = lintGeneratedUi(generatedTsx);
134
+ * if (!ok) sendBackToAgent(formatLintReport(findings));
135
+ * ```
136
+ */
137
+ declare function lintGeneratedUi(source: string, options?: LintOptions): LintResult;
138
+ /**
139
+ * Render lint findings as a compact, agent- and human-readable report.
140
+ * Empty string when there are no findings.
141
+ */
142
+ declare function formatLintReport(findings: LintFinding[]): string;
143
+
144
+ /**
145
+ * Layer 4 of the anti-slop system: the critique loop.
146
+ *
147
+ * `reviewGeneratedUi` runs the deterministic linter (Layer 2) and packages the
148
+ * result into something a generating agent can act on in one round-trip — a
149
+ * pass/fail verdict plus a ready-to-send revision prompt that names the exact
150
+ * lines and fixes. The system prompt string (`UI_REVIEW_AGENT_INSTRUCTIONS`)
151
+ * teaches the model to self-review *before* it returns code, so the loop is
152
+ * usually closed without a second model call.
153
+ *
154
+ * Public, documented API — exported from the package root and `/app`.
155
+ */
156
+
157
+ interface ReviewResult {
158
+ /** Raw linter output. */
159
+ lint: LintResult;
160
+ /** True when no blocking (error-severity, or any warning in strict mode) findings remain. */
161
+ passed: boolean;
162
+ /** Compact human/agent-readable report ("" when clean). */
163
+ report: string;
164
+ /**
165
+ * A ready-to-send follow-up prompt instructing the agent to fix the findings,
166
+ * or `null` when the UI passed. Send this back to the model and re-run
167
+ * `reviewGeneratedUi` on its next output until `passed` is true.
168
+ */
169
+ revisionPrompt: string | null;
170
+ }
171
+ /**
172
+ * Review a generated `.tsx` string for slop and produce an actionable verdict.
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * let code = await generate(userPrompt);
177
+ * for (let i = 0; i < 2; i++) {
178
+ * const review = reviewGeneratedUi(code, { strict: true });
179
+ * if (review.passed) break;
180
+ * code = await generate(review.revisionPrompt!); // agent fixes named issues
181
+ * }
182
+ * ```
183
+ */
184
+ declare function reviewGeneratedUi(source: string, options?: LintOptions): ReviewResult;
185
+ /**
186
+ * Append to a UI-generation agent's system prompt so it self-reviews before
187
+ * returning code. Pairs with `APP_KIT_AGENT_INSTRUCTIONS` and
188
+ * `THEME_AGENT_INSTRUCTIONS`.
189
+ */
190
+ declare const UI_REVIEW_AGENT_INSTRUCTIONS: string;
191
+
19
192
  /**
20
193
  * Theme generator — turn brand *intent* into a complete, paired light + dark
21
194
  * token set, so agents and apps never hand-author `oklch(...)` or risk a
@@ -41,15 +214,39 @@ interface TimbalThemeTokens {
41
214
  light: ThemeTokenMap;
42
215
  /** Variables applied in `.dark`. */
43
216
  dark: ThemeTokenMap;
44
- /** Mode-independent variables (e.g. `--radius`) applied once in `:root`. */
217
+ /** Mode-independent variables (e.g. `--radius`, `--font-sans`) applied once in `:root`. */
45
218
  root?: ThemeTokenMap;
219
+ /**
220
+ * Font stack applied as `font-family` on the theme scope (and `body`), so
221
+ * every component re-skins. Set independently of the `--font-*` vars so the
222
+ * serializer can emit the actual `font-family` declaration.
223
+ */
224
+ fontFamily?: string;
225
+ /**
226
+ * Optional stylesheet URL (e.g. a Google Fonts link) that loads the font in
227
+ * `fontFamily`. Injected as a `<link>` by `applyTimbalTheme` / `TimbalThemeStyle`;
228
+ * for build-time `themeToCss` the host should add the link itself.
229
+ */
230
+ fontImportUrl?: string;
231
+ }
232
+ /** Drop-shadow weight for cards / elevated surfaces. */
233
+ type ThemeShadow = "none" | "hairline" | "soft" | "medium" | "strong";
234
+ interface TimbalThemeTypography {
235
+ /** Body / UI font stack. Applied as `font-family` and `--font-sans`. */
236
+ sans: string;
237
+ /** Optional heading/display stack (`--font-display`; falls back to sans). */
238
+ display?: string;
239
+ /** Optional monospace stack (`--font-mono`). */
240
+ mono?: string;
241
+ /** Optional stylesheet URL that loads the fonts (Google Fonts CSS, etc.). */
242
+ importUrl?: string;
46
243
  }
47
244
  interface TimbalThemeIntent {
48
245
  /** Primary brand color — any CSS color: `#4f46e5`, `rgb(...)`, `oklch(...)`. */
49
246
  brand: string;
50
247
  /** Optional secondary accent. Defaults to a desaturated brand. */
51
248
  accent?: string;
52
- /** Corner radius in rem (maps to `--radius`). Default keeps the shipped 0.75. */
249
+ /** Corner radius in rem (maps to `--radius` + `--radius-2xl`). Default 0.75. */
53
250
  radius?: number;
54
251
  /**
55
252
  * Tint neutral surfaces (background / muted / border) toward the brand hue
@@ -57,6 +254,13 @@ interface TimbalThemeIntent {
57
254
  * keeps the shipped neutral grays.
58
255
  */
59
256
  tintNeutrals?: boolean;
257
+ /**
258
+ * Full typography personality (font stacks + optional web-font URL). When
259
+ * set, the generated theme re-skins every component's font.
260
+ */
261
+ typography?: TimbalThemeTypography;
262
+ /** Shadow weight for cards / elevated surfaces. Default keeps the shipped `medium`. */
263
+ shadow?: ThemeShadow;
60
264
  }
61
265
  /**
62
266
  * Derive a complete paired token set from brand intent. Pure — safe in SSR,
@@ -72,20 +276,35 @@ interface ThemeToCssOptions {
72
276
  scope?: string;
73
277
  /** Indentation for emitted declarations. Default two spaces. */
74
278
  indent?: string;
279
+ /**
280
+ * Prepend an `@import url("…")` for the theme's `fontImportUrl`. Off by
281
+ * default — `@import` must precede all other rules, so this is only safe when
282
+ * the returned CSS is the entire stylesheet. Prefer loading the font with a
283
+ * `<link>` (which `applyTimbalTheme` / `TimbalThemeStyle` do automatically).
284
+ */
285
+ includeFontImport?: boolean;
75
286
  }
76
287
  /**
77
288
  * Serialize a theme to a CSS string with paired `:root` (light) and `.dark`
78
289
  * blocks — the exact shape apps would otherwise hand-author. Writing this in a
79
- * single block guarantees light + dark stay in sync.
290
+ * single block guarantees light + dark stay in sync. When the theme carries a
291
+ * `fontFamily`, a matching `font-family` rule is emitted so every component
292
+ * re-skins (scoped to the subtree for previews, or `:root` + `body` globally).
80
293
  */
81
294
  declare function themeToCss(theme: TimbalThemeTokens, options?: ThemeToCssOptions): string;
295
+ /**
296
+ * Ensure a stylesheet `<link>` for a web-font URL exists in `<head>`. Idempotent
297
+ * per URL; replaces any previously injected theme font link. No-op in SSR.
298
+ */
299
+ declare function ensureThemeFontLink(url: string | undefined): void;
82
300
  /**
83
301
  * Apply a theme at runtime by injecting (or replacing) a single managed
84
- * `<style>` element in `<head>`. Works with the `.dark` class toggle used by
85
- * `next-themes` / `ModeToggle` — both light and dark blocks are written, so
86
- * switching mode never desyncs. No-op in SSR / non-DOM contexts.
302
+ * `<style>` element in `<head>` (and a font `<link>` when the theme carries
303
+ * one). Works with the `.dark` class toggle used by `next-themes` / `ModeToggle`
304
+ * both light and dark blocks are written, so switching mode never desyncs.
305
+ * No-op in SSR / non-DOM contexts.
87
306
  *
88
- * Returns a disposer that removes the injected style.
307
+ * Returns a disposer that removes the injected style + font link.
89
308
  */
90
309
  declare function applyTimbalTheme(theme: TimbalThemeTokens): () => void;
91
310
  /** Remove a runtime theme injected by {@link applyTimbalTheme}. */
@@ -101,7 +320,7 @@ declare function clearTimbalTheme(): void;
101
320
  * infinite palette for both humans and models.
102
321
  */
103
322
 
104
- type TimbalThemePresetId = "platform" | "indigo" | "violet" | "forest" | "warm" | "slate";
323
+ type TimbalThemePresetId = "platform" | "indigo" | "violet" | "forest" | "warm" | "slate" | "folio" | "carbon";
105
324
  interface TimbalThemePreset {
106
325
  id: TimbalThemePresetId;
107
326
  /** Short human label for pickers. */
@@ -110,9 +329,12 @@ interface TimbalThemePreset {
110
329
  description: string;
111
330
  /** Representative swatch color (CSS) for chips / previews. */
112
331
  swatch: string;
332
+ /** Human-readable font name (for picker chips). `null` = system default. */
333
+ font: string | null;
113
334
  /**
114
- * Token overrides. `platform` is the shipped neutral palette and has empty
115
- * maps (no overrides — `styles.css` defaults apply).
335
+ * Full personality token set color + radius + shadow + typography.
336
+ * `platform` is the shipped neutral palette and has empty maps (no overrides;
337
+ * `styles.css` defaults apply).
116
338
  */
117
339
  tokens: TimbalThemeTokens;
118
340
  }
@@ -615,13 +837,15 @@ interface SubNavProps {
615
837
  */
616
838
  declare const SubNav: FC<SubNavProps>;
617
839
 
618
- interface BreadcrumbItem {
840
+ interface BreadcrumbEntry {
619
841
  label: ReactNode;
620
842
  href?: string;
621
843
  onClick?: () => void;
622
844
  }
845
+ /** @deprecated Use `BreadcrumbEntry` — avoids clashing with the UI `BreadcrumbItem` primitive. */
846
+ type BreadcrumbItem = BreadcrumbEntry;
623
847
  interface BreadcrumbsProps {
624
- items: BreadcrumbItem[];
848
+ items: BreadcrumbEntry[];
625
849
  className?: string;
626
850
  }
627
851
  declare const Breadcrumbs: FC<BreadcrumbsProps>;
@@ -917,4 +1141,4 @@ interface ChartArtifactViewProps {
917
1141
  */
918
1142
  declare const ChartArtifactView: FC<ChartArtifactViewProps>;
919
1143
 
920
- export { FieldSwitch as $, APP_KIT_AGENT_INSTRUCTIONS as A, type BreadcrumbItem as B, CHART_PALETTE as C, DangerZone as D, DangerZoneAction as E, type DangerZoneActionProps as F, type DangerZoneProps as G, DataTable as H, type DataTableColumn as I, type DataTableProps as J, type DataTableSort as K, type DataTableSortDirection as L, type DescriptionItem as M, DescriptionList as N, type DescriptionListProps as O, EmptyState as P, type EmptyStateProps as Q, ExpandableSection as R, type ExpandableSectionProps as S, Field as T, FieldInput as U, type FieldInputProps as V, type FieldProps as W, FieldRow as X, type FieldRowProps as Y, FieldSelect as Z, type FieldSelectProps as _, AppChatPanel as a, type ThemePresetGalleryProps as a$, type FieldSwitchProps as a0, FieldTextarea as a1, type FieldTextareaProps as a2, FilterBar as a3, type FilterBarProps as a4, FloatingUnsavedChangesBar as a5, type FloatingUnsavedChangesBarProps as a6, FormSection as a7, type FormSectionProps as a8, INTEGRATION_CATALOG_CARD_HEIGHT_CLASS as a9, type ResourceCardProps as aA, SearchInput as aB, type SearchInputProps as aC, Section as aD, type SectionProps as aE, SettingsSection as aF, SettingsSectionHeader as aG, type SettingsSectionHeaderProps as aH, type SettingsSectionProps as aI, Sparkline as aJ, type SparklineProps as aK, StatTile as aL, type StatTileProps as aM, StatusBadge as aN, type StatusBadgeProps as aO, type StatusBadgeTone as aP, StatusDot as aQ, type StatusDotProps as aR, type StatusDotTone as aS, SubNav as aT, type SubNavItem as aU, type SubNavProps as aV, SurfaceCard as aW, type SurfaceCardProps as aX, THEME_AGENT_INSTRUCTIONS as aY, TIMBAL_THEME_PRESETS as aZ, ThemePresetGallery as a_, InfoCard as aa, type InfoCardProps as ab, type InfoCardTone as ac, IntegrationCard as ad, type IntegrationCardProps as ae, type IntegrationCardStatus as af, IntegrationsEmptyState as ag, type IntegrationsEmptyStateProps as ah, LineAreaChart as ai, type LineAreaChartProps as aj, MetricChartCard as ak, type MetricChartCardProps as al, type MetricChartMetric as am, MetricRow as an, type MetricRowItem as ao, type MetricRowProps as ap, MetricTile as aq, type MetricTileProps as ar, Page as as, PageHeader as at, type PageHeaderProps as au, type PageProps as av, PlanBadge as aw, type PlanBadgeProps as ax, type PlanBadgeTone as ay, ResourceCard as az, type AppChatPanelProps as b, type ThemeToCssOptions as b0, type ThemeTokenMap as b1, type TimbalThemeIntent as b2, type TimbalThemePreset as b3, type TimbalThemePresetId as b4, TimbalThemeStyle as b5, type TimbalThemeStyleProps as b6, type TimbalThemeTokens as b7, applyThemePreset as b8, applyTimbalTheme as b9, clearTimbalTheme as ba, connectionRowListClass as bb, createTimbalTheme as bc, getStoredThemePreset as bd, getThemePreset as be, themeToCss as bf, useAppCopilotContext as bg, useAppShellChat as bh, AppConfirmDialog as c, type AppConfirmDialogProps as d, type AppCopilotContextValue as e, AppCopilotProvider as f, type AppCopilotProviderProps as g, AppShell as h, type AppShellChatControls as i, AppShellChatTrigger as j, type AppShellChatTriggerProps as k, type AppShellProps as l, AppShellTopbar as m, type AppShellTopbarProps as n, Breadcrumbs as o, type BreadcrumbsProps as p, ChartArtifactView as q, type ChartLayout as r, ChartPanel as s, type ChartPanelProps as t, type ChartSeries as u, type ChartVariant as v, ConnectionRow as w, ConnectionRowList as x, type ConnectionRowListProps as y, type ConnectionRowProps as z };
1144
+ export { FieldSelect as $, APP_KIT_AGENT_INSTRUCTIONS as A, type BreadcrumbEntry as B, CHART_PALETTE as C, type ConnectionRowListProps as D, type ConnectionRowProps as E, DangerZone as F, DangerZoneAction as G, type DangerZoneActionProps as H, type DangerZoneProps as I, DataTable as J, type DataTableColumn as K, type DataTableProps as L, type DataTableSort as M, type DataTableSortDirection as N, type DescriptionItem as O, DescriptionList as P, type DescriptionListProps as Q, EmptyState as R, type EmptyStateProps as S, ExpandableSection as T, type ExpandableSectionProps as U, Field as V, FieldInput as W, type FieldInputProps as X, type FieldProps as Y, FieldRow as Z, type FieldRowProps as _, AppChatPanel as a, type StatusBadgeProps as a$, type FieldSelectProps as a0, FieldSwitch as a1, type FieldSwitchProps as a2, FieldTextarea as a3, type FieldTextareaProps as a4, FilterBar as a5, type FilterBarProps as a6, FloatingUnsavedChangesBar as a7, type FloatingUnsavedChangesBarProps as a8, FormSection as a9, Page as aA, PageHeader as aB, type PageHeaderProps as aC, type PageProps as aD, PlanBadge as aE, type PlanBadgeProps as aF, type PlanBadgeTone as aG, RESERVED_GRADIENT_TOKENS as aH, ResourceCard as aI, type ResourceCardProps as aJ, type ReviewResult as aK, SEMANTIC_COLOR_TOKENS as aL, SLOP_BUDGETS as aM, SearchInput as aN, type SearchInputProps as aO, Section as aP, type SectionProps as aQ, type SemanticColorToken as aR, SettingsSection as aS, SettingsSectionHeader as aT, type SettingsSectionHeaderProps as aU, type SettingsSectionProps as aV, Sparkline as aW, type SparklineProps as aX, StatTile as aY, type StatTileProps as aZ, StatusBadge as a_, type FormSectionProps as aa, HOUSE_RULES as ab, type HouseRule as ac, INTEGRATION_CATALOG_CARD_HEIGHT_CLASS as ad, InfoCard as ae, type InfoCardProps as af, type InfoCardTone as ag, IntegrationCard as ah, type IntegrationCardProps as ai, type IntegrationCardStatus as aj, IntegrationsEmptyState as ak, type IntegrationsEmptyStateProps as al, LineAreaChart as am, type LineAreaChartProps as an, type LintFinding as ao, type LintOptions as ap, type LintResult as aq, type LintSeverity as ar, MetricChartCard as as, type MetricChartCardProps as at, type MetricChartMetric as au, MetricRow as av, type MetricRowItem as aw, type MetricRowProps as ax, MetricTile as ay, type MetricTileProps as az, type AppChatPanelProps as b, type StatusBadgeTone as b0, StatusDot as b1, type StatusDotProps as b2, type StatusDotTone as b3, SubNav as b4, type SubNavItem as b5, type SubNavProps as b6, SurfaceCard as b7, type SurfaceCardProps as b8, TAILWIND_PALETTE_COLORS as b9, themeToCss as bA, useAppCopilotContext as bB, useAppShellChat as bC, THEME_AGENT_INSTRUCTIONS as ba, TIMBAL_THEME_PRESETS as bb, ThemePresetGallery as bc, type ThemePresetGalleryProps as bd, type ThemeShadow as be, type ThemeToCssOptions as bf, type ThemeTokenMap as bg, type TimbalThemeIntent as bh, type TimbalThemePreset as bi, type TimbalThemePresetId as bj, TimbalThemeStyle as bk, type TimbalThemeStyleProps as bl, type TimbalThemeTokens as bm, type TimbalThemeTypography as bn, UI_REVIEW_AGENT_INSTRUCTIONS as bo, applyThemePreset as bp, applyTimbalTheme as bq, clearTimbalTheme as br, connectionRowListClass as bs, createTimbalTheme as bt, ensureThemeFontLink as bu, formatLintReport as bv, getStoredThemePreset as bw, getThemePreset as bx, lintGeneratedUi as by, reviewGeneratedUi as bz, AppConfirmDialog as c, type AppConfirmDialogProps as d, type AppCopilotContextValue as e, AppCopilotProvider as f, type AppCopilotProviderProps as g, AppShell as h, type AppShellChatControls as i, AppShellChatTrigger as j, type AppShellChatTriggerProps as k, type AppShellProps as l, AppShellTopbar as m, type AppShellTopbarProps as n, type BreadcrumbItem as o, Breadcrumbs as p, type BreadcrumbsProps as q, COLOR_UTILITY_PREFIXES as r, ChartArtifactView as s, type ChartLayout as t, ChartPanel as u, type ChartPanelProps as v, type ChartSeries as w, type ChartVariant as x, ConnectionRow as y, ConnectionRowList as z };
package/dist/chat.cjs CHANGED
@@ -4383,6 +4383,28 @@ function TimbalChat({
4383
4383
 
4384
4384
  // src/chat/workforce-selector.tsx
4385
4385
  var import_lucide_react9 = require("lucide-react");
4386
+
4387
+ // src/design/control-surface.ts
4388
+ var controlSurfaceClass = cn(
4389
+ TIMBAL_V2_SECONDARY_CHROME,
4390
+ "text-sm text-foreground outline-none",
4391
+ "placeholder:text-muted-foreground/70",
4392
+ "focus-visible:ring-2 focus-visible:ring-foreground/10",
4393
+ "focus-within:ring-2 focus-within:ring-foreground/10",
4394
+ "disabled:cursor-not-allowed disabled:opacity-50",
4395
+ "data-[placeholder]:text-muted-foreground"
4396
+ );
4397
+ var overlayAnimationClass = "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2";
4398
+ var overlaySurfaceClass = cn(
4399
+ "z-[80] border border-border bg-popover text-popover-foreground shadow-card",
4400
+ overlayAnimationClass
4401
+ );
4402
+ var overlayListPanelClass = cn(
4403
+ overlaySurfaceClass,
4404
+ "overflow-hidden rounded-lg p-0 outline-hidden"
4405
+ );
4406
+
4407
+ // src/chat/workforce-selector.tsx
4386
4408
  var import_jsx_runtime31 = require("react/jsx-runtime");
4387
4409
  var WorkforceSelector = ({
4388
4410
  workforces,
@@ -4399,8 +4421,8 @@ var WorkforceSelector = ({
4399
4421
  {
4400
4422
  className: cn(
4401
4423
  "aui-workforce-selector relative inline-flex items-center",
4424
+ controlSurfaceClass,
4402
4425
  studioTopbarPillHeightClass,
4403
- studioSecondaryChromeClass,
4404
4426
  "rounded-full",
4405
4427
  className
4406
4428
  ),
package/dist/chat.esm.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-KC5QLVUG.esm.js";
8
8
  import {
9
9
  WorkforceSelector
10
- } from "./chunk-CFU3YDTV.esm.js";
10
+ } from "./chunk-RZ6QC6RG.esm.js";
11
11
  import {
12
12
  Composer,
13
13
  ComposerAddAttachment,
@@ -24,8 +24,8 @@ import {
24
24
  useTimbalRuntime,
25
25
  useTimbalStream,
26
26
  useToolRunning
27
- } from "./chunk-5ZKLPWVN.esm.js";
28
- import "./chunk-QVAUCVQA.esm.js";
27
+ } from "./chunk-SNLXVG7H.esm.js";
28
+ import "./chunk-FOD67Z6G.esm.js";
29
29
  export {
30
30
  Composer,
31
31
  ComposerAddAttachment,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  cn
3
- } from "./chunk-QVAUCVQA.esm.js";
3
+ } from "./chunk-FOD67Z6G.esm.js";
4
4
 
5
5
  // src/ui/pill-segmented-tabs.tsx
6
6
  import {
@@ -20,7 +20,7 @@ import {
20
20
  } from "./chunk-QIABF4KB.esm.js";
21
21
  import {
22
22
  WorkforceSelector
23
- } from "./chunk-CFU3YDTV.esm.js";
23
+ } from "./chunk-RZ6QC6RG.esm.js";
24
24
  import {
25
25
  Composer,
26
26
  TimbalChat,
@@ -43,10 +43,10 @@ import {
43
43
  studioTopbarIconPillClass,
44
44
  studioTopbarPillHeightClass,
45
45
  useTimbalRuntime
46
- } from "./chunk-5ZKLPWVN.esm.js";
46
+ } from "./chunk-SNLXVG7H.esm.js";
47
47
  import {
48
48
  PillSegmentedTabs
49
- } from "./chunk-OISVICYF.esm.js";
49
+ } from "./chunk-AYHOVAMI.esm.js";
50
50
  import {
51
51
  Avatar,
52
52
  AvatarFallback,
@@ -56,7 +56,7 @@ import {
56
56
  TooltipContent,
57
57
  TooltipTrigger,
58
58
  cn
59
- } from "./chunk-QVAUCVQA.esm.js";
59
+ } from "./chunk-FOD67Z6G.esm.js";
60
60
 
61
61
  // src/hooks/use-workforces.ts
62
62
  import { useEffect, useMemo, useRef, useState } from "react";
@@ -311,6 +311,39 @@ function Button({
311
311
  );
312
312
  }
313
313
 
314
+ // src/design/control-surface.ts
315
+ var CONTROL_SIZE = {
316
+ sm: "h-9 px-3",
317
+ default: "h-10 px-3"
318
+ };
319
+ var CONTROL_SHAPE = {
320
+ field: "rounded-lg",
321
+ pill: "rounded-full"
322
+ };
323
+ var controlSurfaceClass = cn(
324
+ TIMBAL_V2_SECONDARY_CHROME,
325
+ "text-sm text-foreground outline-none",
326
+ "placeholder:text-muted-foreground/70",
327
+ "focus-visible:ring-2 focus-visible:ring-foreground/10",
328
+ "focus-within:ring-2 focus-within:ring-foreground/10",
329
+ "disabled:cursor-not-allowed disabled:opacity-50",
330
+ "data-[placeholder]:text-muted-foreground"
331
+ );
332
+ function controlClass(options = {}, className) {
333
+ const { size = "default", shape = "field" } = options;
334
+ return cn(controlSurfaceClass, CONTROL_SIZE[size], CONTROL_SHAPE[shape], className);
335
+ }
336
+ var overlayAnimationClass = "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2";
337
+ var overlaySurfaceClass = cn(
338
+ "z-[80] border border-border bg-popover text-popover-foreground shadow-card",
339
+ overlayAnimationClass
340
+ );
341
+ var overlayListPanelClass = cn(
342
+ overlaySurfaceClass,
343
+ "overflow-hidden rounded-lg p-0 outline-hidden"
344
+ );
345
+ var overlayItemClass = "relative flex cursor-default items-center gap-2 rounded-md px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground";
346
+
314
347
  // src/ui/tooltip.tsx
315
348
  import { Tooltip as TooltipPrimitive } from "radix-ui";
316
349
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -587,13 +620,22 @@ var Shimmer = memo(ShimmerComponent);
587
620
  export {
588
621
  cn,
589
622
  TIMBAL_V2_ELEVATED_GRADIENT,
623
+ TIMBAL_V2_MODAL_SURFACE,
590
624
  TIMBAL_V2_SWITCH_TRACK_OFF,
591
625
  TIMBAL_V2_SWITCH_THUMB,
592
626
  TIMBAL_V2_ELEVATED_SURFACE,
593
627
  TIMBAL_V2_SECONDARY_CHROME,
594
628
  TIMBAL_V2_LOGO_TILE,
595
629
  TimbalV2Button,
630
+ buttonVariants,
596
631
  Button,
632
+ CONTROL_SIZE,
633
+ controlSurfaceClass,
634
+ controlClass,
635
+ overlayAnimationClass,
636
+ overlaySurfaceClass,
637
+ overlayListPanelClass,
638
+ overlayItemClass,
597
639
  TooltipProvider,
598
640
  Tooltip,
599
641
  TooltipTrigger,