@lovett/ui 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2495 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as react from 'react';
3
+ import react__default, { HTMLAttributes, ReactNode, ButtonHTMLAttributes, InputHTMLAttributes, TextareaHTMLAttributes, CSSProperties, RefObject, ComponentProps, ComponentType, FormHTMLAttributes, FormEvent } from 'react';
4
+ import { Toaster as Toaster$1 } from 'sonner';
5
+ export { toast } from 'sonner';
6
+ import { DndContext, DragEndEvent } from '@dnd-kit/core';
7
+ import { ClassValue } from 'clsx';
8
+
9
+ /**
10
+ * Card — head/body/foot anatomy.
11
+ *
12
+ * Usage:
13
+ * <Card interactive onClick={...}>
14
+ * <Card.Head>
15
+ * <IconTile bg={...} fg={...}><Icon/></IconTile>
16
+ * <div className="flex-1 min-w-0">
17
+ * <Card.Title>Roof Replacement</Card.Title>
18
+ * <Card.Desc>Full tear-off and replacement...</Card.Desc>
19
+ * </div>
20
+ * </Card.Head>
21
+ * <Card.Body>
22
+ * <TagRow tags={['25-Year Warranty', 'Metal & Asphalt']}/>
23
+ * </Card.Body>
24
+ * <Card.Foot>
25
+ * <Card.Meta>...</Card.Meta>
26
+ * <Card.Actions>...</Card.Actions>
27
+ * </Card.Foot>
28
+ * </Card>
29
+ *
30
+ * `interactive` adds cursor + hover lift + reveal-on-hover for Card.Actions.
31
+ */
32
+ type DivProps = HTMLAttributes<HTMLDivElement>;
33
+ interface CardProps extends DivProps {
34
+ interactive?: boolean;
35
+ }
36
+ declare const CardRoot: react.ForwardRefExoticComponent<CardProps & react.RefAttributes<HTMLDivElement>>;
37
+ declare function Head({ className, ...rest }: DivProps): react_jsx_runtime.JSX.Element;
38
+ declare function Body({ className, ...rest }: DivProps): react_jsx_runtime.JSX.Element;
39
+ declare function Tray$1({ className, ...rest }: DivProps): react_jsx_runtime.JSX.Element;
40
+ declare function Foot({ className, ...rest }: DivProps): react_jsx_runtime.JSX.Element;
41
+ declare function Title({ children, className, ...rest }: HTMLAttributes<HTMLDivElement>): react_jsx_runtime.JSX.Element;
42
+ declare function Desc({ children, className, ...rest }: HTMLAttributes<HTMLDivElement> & {
43
+ clamp?: 2 | 3;
44
+ }): react_jsx_runtime.JSX.Element;
45
+ declare function Meta({ className, ...rest }: DivProps): react_jsx_runtime.JSX.Element;
46
+ declare function MetaItem({ icon, children, className, }: {
47
+ icon?: ReactNode;
48
+ children: ReactNode;
49
+ className?: string;
50
+ }): react_jsx_runtime.JSX.Element;
51
+ declare function Actions({ className, ...rest }: DivProps): react_jsx_runtime.JSX.Element;
52
+ interface ActionButtonProps$1 extends HTMLAttributes<HTMLButtonElement> {
53
+ danger?: boolean;
54
+ }
55
+ declare const ActionButton$1: react.ForwardRefExoticComponent<ActionButtonProps$1 & react.RefAttributes<HTMLButtonElement>>;
56
+ /**
57
+ * Icon-on-color tile used in card heads. Pass tone colors as inline rgb()
58
+ * strings so they can reference semantic tokens (info/success/etc.).
59
+ */
60
+ declare function IconTile({ bg, fg, size, className, children, }: {
61
+ bg: string;
62
+ fg: string;
63
+ size?: number;
64
+ className?: string;
65
+ children: ReactNode;
66
+ }): react_jsx_runtime.JSX.Element;
67
+ /** Tag row helper — reads `--tag-bg`/`--border` automatically. */
68
+ declare function TagRow({ tags, max, className, }: {
69
+ tags: string[];
70
+ max?: number;
71
+ className?: string;
72
+ }): react_jsx_runtime.JSX.Element;
73
+ type CardComponent = typeof CardRoot & {
74
+ Head: typeof Head;
75
+ Body: typeof Body;
76
+ Tray: typeof Tray$1;
77
+ Foot: typeof Foot;
78
+ Title: typeof Title;
79
+ Desc: typeof Desc;
80
+ Meta: typeof Meta;
81
+ MetaItem: typeof MetaItem;
82
+ Actions: typeof Actions;
83
+ ActionButton: typeof ActionButton$1;
84
+ IconTile: typeof IconTile;
85
+ TagRow: typeof TagRow;
86
+ };
87
+ declare const Card: CardComponent;
88
+
89
+ type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'destructive-soft' | 'icon' | 'toolbar';
90
+ type ButtonSize = 'sm' | 'md' | 'lg';
91
+ type ButtonShape = 'default' | 'circle';
92
+ interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
93
+ variant?: ButtonVariant;
94
+ size?: ButtonSize;
95
+ /** ADR-026 D3 — `circle` only takes effect when `variant="icon"`. */
96
+ shape?: ButtonShape;
97
+ /** Show the loading spinner overlay; auto-disables the button. */
98
+ loading?: boolean;
99
+ /** Optional left-side icon. Forces icon-text gap from .btn. */
100
+ leadingIcon?: ReactNode;
101
+ /** Optional right-side icon. */
102
+ trailingIcon?: ReactNode;
103
+ }
104
+ declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
105
+
106
+ interface ButtonGroupProps extends HTMLAttributes<HTMLDivElement> {
107
+ /** One or more `<Button>` elements. */
108
+ children: ReactNode;
109
+ }
110
+ declare function ButtonGroup({ children, className, role, ...rest }: ButtonGroupProps): react_jsx_runtime.JSX.Element;
111
+
112
+ type InputSize = 'sm' | 'md' | 'lg';
113
+ interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix'> {
114
+ inputSize?: InputSize;
115
+ error?: boolean;
116
+ /** Element rendered before the input — typically an icon. Static, no interaction. */
117
+ leadingAffix?: ReactNode;
118
+ /** Element rendered after the input. Pass an `<button class="affix action">` for clickable. */
119
+ trailingAffix?: ReactNode;
120
+ /** Override classes on the .input-shell wrapper. */
121
+ shellClassName?: string;
122
+ /**
123
+ * Show/hide affordance for `type="password"`. Manages visibility state
124
+ * internally and renders an Eye/EyeOff toggle in the trailing affix slot.
125
+ * No-op when `type !== "password"`. Caller-supplied `trailingAffix`
126
+ * wins — the toggle is only injected when the slot is otherwise empty.
127
+ */
128
+ showPasswordToggle?: boolean;
129
+ /**
130
+ * Numeric variant (ADR-076 D8) — renders the field in the monospace
131
+ * face with `tabular-nums` so digits align as the value changes.
132
+ * Pair with the existing `leadingAffix` (e.g. a `$`) / `trailingAffix`
133
+ * (e.g. a unit suffix) for calculator inputs. No new prefix/suffix
134
+ * props — affixes are the canonical adornment slots.
135
+ */
136
+ numeric?: boolean;
137
+ }
138
+ declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttributes<HTMLInputElement>>;
139
+
140
+ interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
141
+ error?: boolean;
142
+ /** Override classes on the .input-shell wrapper. */
143
+ shellClassName?: string;
144
+ }
145
+ declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
146
+
147
+ /**
148
+ * Modal — a centered floating panel on top of a backdrop. Built on
149
+ * `.ds-card-surface` so it inherits the premium card chrome (border,
150
+ * radius, multi-layer shadow with inner highlight in light mode).
151
+ *
152
+ * Two layout modes:
153
+ *
154
+ * 1. Flat children (back-compat) — pass content directly:
155
+ *
156
+ * <Modal title="..." onClose={...}>
157
+ * <p>body</p>
158
+ * <Button>action</Button>
159
+ * </Modal>
160
+ *
161
+ * 2. Shell / Tray pattern (recommended) — body in a recessed tray,
162
+ * action buttons on the outer-card bottom strip below the tray:
163
+ *
164
+ * <Modal title="..." onClose={...}>
165
+ * <Modal.Tray>
166
+ * <p>body content sits in a recessed shelf</p>
167
+ * <textarea ... />
168
+ * </Modal.Tray>
169
+ * <Modal.Footer>
170
+ * <Button variant="ghost" onClick={onClose}>Cancel</Button>
171
+ * <Button>Confirm</Button>
172
+ * </Modal.Footer>
173
+ * </Modal>
174
+ */
175
+ interface ModalProps {
176
+ isOpen: boolean;
177
+ onClose: () => void;
178
+ title: string;
179
+ children: ReactNode;
180
+ className?: string;
181
+ }
182
+ declare function Modal({ isOpen, onClose, title, children, className }: ModalProps): react_jsx_runtime.JSX.Element | null;
183
+ declare namespace Modal {
184
+ var Tray: ({ className, ...rest }: HTMLAttributes<HTMLDivElement>) => react_jsx_runtime.JSX.Element;
185
+ var Footer: ({ className, ...rest }: HTMLAttributes<HTMLDivElement>) => react_jsx_runtime.JSX.Element;
186
+ }
187
+
188
+ type Side$1 = 'right' | 'bottom';
189
+ type Anchor = 'viewport' | 'container';
190
+ interface FloatingDrawerProps {
191
+ isOpen: boolean;
192
+ onClose: () => void;
193
+ side: Side$1;
194
+ /** Width (`side="right"`) or height (`side="bottom"`) in px. Defaults: 520 / 480. */
195
+ size?: number;
196
+ /** When true, render a drag handle along the leading edge of the panel. */
197
+ resizable?: boolean;
198
+ /** Called as the user drags the resize handle. */
199
+ onResize?: (next: number) => void;
200
+ /** Header title — short, e.g. the record's name or the drawer's purpose. */
201
+ title?: ReactNode;
202
+ /** Optional element rendered to the right of the title, before close. */
203
+ titleSlot?: ReactNode;
204
+ /** Optional footer — action buttons. */
205
+ footer?: ReactNode;
206
+ children: ReactNode;
207
+ className?: string;
208
+ /** Optional className on the inner panel for fine-grained body styling. */
209
+ panelClassName?: string;
210
+ /**
211
+ * Modal mode renders a backdrop, locks body scroll, and closes on Esc
212
+ * (default — matches the card-grid drawer use case). Non-modal mode
213
+ * (used by GeoSearch's always-on results panel per Phase 7a) skips
214
+ * the backdrop + scroll lock + Esc handler so the user can interact
215
+ * with content behind the panel.
216
+ */
217
+ modal?: boolean;
218
+ /**
219
+ * Collapsed mode hides the body and footer entirely so the panel
220
+ * shrinks to just the header — no residual flex-1 body div, no
221
+ * seam between header and panel edge. Designed for non-modal,
222
+ * always-on consumers (GeoSearch) where the user toggles the panel
223
+ * between "show table" and "hide table" without dismissing it.
224
+ * The header keeps its border-bottom hidden in this state so it
225
+ * reads as a clean single-bar strip.
226
+ *
227
+ * When collapsed, callers should pass `size` matching the header's
228
+ * natural height (Phase 7a uses 44px); panel border + header chrome
229
+ * fit cleanly inside that height with `box-sizing: border-box`.
230
+ */
231
+ collapsed?: boolean;
232
+ /**
233
+ * `'viewport'` (default) anchors the drawer with `position: fixed` to
234
+ * the browser viewport — the card-grid drawer pattern. `'container'`
235
+ * anchors with `position: absolute` to the nearest positioned ancestor
236
+ * (the parent MUST establish a containing block, e.g.
237
+ * `position: relative`). Container mode scopes the drawer to a lens
238
+ * pane so it doesn't escape the surrounding chrome — used by
239
+ * GeoSearch in Phase 7a.
240
+ */
241
+ anchor?: Anchor;
242
+ /** Whether to render a default close (X) button after `titleSlot`. Default true. */
243
+ showClose?: boolean;
244
+ /** Override the header padding. Default: `px-4 py-2.5` — tighter than
245
+ * the right-drawer's body padding so the action bar feels integrated. */
246
+ headerClassName?: string;
247
+ }
248
+ declare function FloatingDrawer({ isOpen, onClose, side, size, resizable, onResize, title, titleSlot, footer, children, className, panelClassName, modal, anchor, showClose, headerClassName, collapsed, }: FloatingDrawerProps): react_jsx_runtime.JSX.Element;
249
+ /**
250
+ * DetailSection — small label/value layout for drawer body content.
251
+ * Ports verbatim from brand-ai-extension's detail-drawer.tsx.
252
+ */
253
+ declare function DetailSection({ label, children, className, }: {
254
+ label: string;
255
+ children: ReactNode;
256
+ className?: string;
257
+ }): react_jsx_runtime.JSX.Element;
258
+
259
+ type BrandLogoTileSize = 'xs' | 'sm' | 'md' | 'lg' | number;
260
+ interface BrandLogoTileProps {
261
+ /** Size token or a raw pixel number. Defaults to `md` (56px). */
262
+ size?: BrandLogoTileSize;
263
+ /** Image URL — logo, favicon, anything `<img>` can render. */
264
+ url?: string | null;
265
+ /**
266
+ * Brand name. Used as `alt` text and as the source for the
267
+ * single-character fallback when no `url` is provided (or the image
268
+ * fails to load).
269
+ */
270
+ name?: string;
271
+ /**
272
+ * Treat the image as a favicon — render it smaller, centred, without
273
+ * stretching to fill the tile. Auto-detected when the URL starts
274
+ * with the Google s2 favicon endpoint; pass `true`/`false` to override.
275
+ */
276
+ isFavicon?: boolean;
277
+ /**
278
+ * Adds a subtle accent-coloured radial glow above the tile. Used on
279
+ * the brand profile rail to give the logo a sense of presence
280
+ * against the slate frame.
281
+ */
282
+ accentGlow?: boolean;
283
+ /** Override the fallback character (defaults to `name[0]`). */
284
+ fallbackChar?: ReactNode;
285
+ /**
286
+ * Override the tile background. Use for contexts that have their own
287
+ * visual identity (e.g. the sidebar switcher's blue gradient). When
288
+ * omitted, the tile picks up the neutral card→overlay gradient that
289
+ * blends with surrounding chrome.
290
+ */
291
+ background?: string;
292
+ /**
293
+ * Override the fallback character / image-area text colour. Pair
294
+ * with `background` for branded variants (white text on coloured
295
+ * gradient). Defaults to the accent token.
296
+ */
297
+ color?: string;
298
+ /** Drop the 1px border (used when the tile sits on a strongly tinted bg). */
299
+ borderless?: boolean;
300
+ className?: string;
301
+ style?: CSSProperties;
302
+ }
303
+ declare function BrandLogoTile({ size, url, name, isFavicon, accentGlow, fallbackChar, background, color, borderless, className, style, }: BrandLogoTileProps): react_jsx_runtime.JSX.Element;
304
+
305
+ interface ActionButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
306
+ label: string;
307
+ }
308
+ declare function ActionButton({ label, className, children, ...rest }: ActionButtonProps): react_jsx_runtime.JSX.Element;
309
+ interface FootProps {
310
+ meta?: ReactNode;
311
+ link?: {
312
+ label: string;
313
+ onClick: () => void;
314
+ icon?: ReactNode;
315
+ };
316
+ }
317
+ /** FootItem — a single icon+text item inside the foot. */
318
+ declare function FootItem({ children }: {
319
+ children: ReactNode;
320
+ }): react_jsx_runtime.JSX.Element;
321
+ interface BaseProps {
322
+ /** DOM id and `data-section-id` for ChipNav scroll-spy. */
323
+ id: string;
324
+ /** Lucide icon (rendered ~17px). */
325
+ icon?: ReactNode;
326
+ /** Section title. */
327
+ title: string;
328
+ /** Section subtitle / description. */
329
+ subtitle?: string;
330
+ /** Optional foot meta + AI-action link. */
331
+ foot?: FootProps;
332
+ /** Extra padding tweak. */
333
+ className?: string;
334
+ }
335
+ interface StaticSectionProps extends BaseProps {
336
+ /** Right-side header actions (override default pencil/generate). */
337
+ actions?: ReactNode;
338
+ children: ReactNode;
339
+ editable?: undefined;
340
+ }
341
+ interface EditableSectionProps extends BaseProps {
342
+ editable: {
343
+ onSave: () => void | Promise<void>;
344
+ onCancel?: () => void;
345
+ isSaving?: boolean;
346
+ saveDisabled?: boolean;
347
+ /** Controlled editing state. If omitted, state is internal. */
348
+ isEditing?: boolean;
349
+ onEditingChange?: (editing: boolean) => void;
350
+ /** Extra actions before the pencil in view mode (e.g. Generate). */
351
+ extraViewActions?: ReactNode;
352
+ };
353
+ /** Render-prop child receives the current editing state. */
354
+ children: (isEditing: boolean) => ReactNode;
355
+ actions?: undefined;
356
+ }
357
+ type ProfileSectionProps = StaticSectionProps | EditableSectionProps;
358
+ declare function ProfileSection(props: ProfileSectionProps): react_jsx_runtime.JSX.Element;
359
+ type ProfileSectionComponent = typeof ProfileSection & {
360
+ ActionButton: typeof ActionButton;
361
+ FootItem: typeof FootItem;
362
+ };
363
+ declare const PS: ProfileSectionComponent;
364
+
365
+ interface ChipNavItem {
366
+ id: string;
367
+ label: string;
368
+ }
369
+ interface ChipNavProps {
370
+ items: ChipNavItem[];
371
+ /**
372
+ * Element (ref or CSS selector) used as the scroll container for both
373
+ * the IntersectionObserver root and the smooth-scroll target. Falls
374
+ * back to the document if omitted.
375
+ */
376
+ scrollContainer?: React.RefObject<HTMLElement | null> | string;
377
+ /** Pixel offset for sticky positioning (default: 0 — caller manages). */
378
+ stickyTop?: number;
379
+ /** Pixels above the section to offset when click-scrolling. */
380
+ scrollOffset?: number;
381
+ /**
382
+ * Optional content rendered on the right side of the bar, separated
383
+ * from the chips by a flexible spacer. Use for page-level actions
384
+ * that should stay pinned to the sticky bar (e.g. Export, Generate).
385
+ */
386
+ actions?: ReactNode;
387
+ /** Extra Tailwind classes on the outer wrapper. */
388
+ className?: string;
389
+ /** Inline style on the outer wrapper. */
390
+ style?: CSSProperties;
391
+ /**
392
+ * Background painted on the sticky wrapper so page content scrolling
393
+ * behind the chip pill gets masked cleanly.
394
+ *
395
+ * - `'none'` (default) — wrapper is transparent. Correct inside a Card,
396
+ * inside a tray, or anywhere the chip nav sits over a non-page surface.
397
+ * - `'page'` — wrapper paints `rgb(var(--main-content-bg))`. Correct
398
+ * when the chip nav is mounted directly under the AppHeader, against
399
+ * the page background, and needs to mask scrolling content beneath.
400
+ *
401
+ * Default was page-colored in the original brand-ai port; that bled
402
+ * into Card / Modal / Tray contexts as a discordant horizontal strip.
403
+ * Phase 2 callers that mount ChipNav against the page background must
404
+ * pass `surface="page"`.
405
+ */
406
+ surface?: 'none' | 'page';
407
+ /**
408
+ * Controlled mode: when provided, the parent owns the active chip.
409
+ * Scroll-spy is disabled and `onItemClick` is invoked instead of the
410
+ * default smooth-scroll behavior. Phase 7a GeoSearch uses this to
411
+ * drive mode-switch tabs (not scroll targets).
412
+ */
413
+ activeId?: string;
414
+ /**
415
+ * Optional click handler. When provided, takes precedence over the
416
+ * built-in scroll-to-section behavior. Required for controlled-mode
417
+ * (`activeId`) use.
418
+ */
419
+ onItemClick?: (id: string) => void;
420
+ /**
421
+ * `'sticky'` (default) — the wrapper is `sticky top-{stickyTop}` for
422
+ * the canonical scroll-spy use case.
423
+ * `'static'` — wrapper is `relative` with no inset; the consumer owns
424
+ * positioning. Used by GeoSearch (Phase 7a) to mount ChipNav as a
425
+ * floating island absolute-positioned above the map.
426
+ */
427
+ position?: 'sticky' | 'static';
428
+ /**
429
+ * `'comfortable'` (default, 32px chip height) — the canonical
430
+ * brand-profile lens density.
431
+ * `'compact'` (24px chip height) — slim variant for tight chrome
432
+ * like the `<PageHeaderHost />` center slot, where the surrounding
433
+ * header is only 48px tall. Reduces inner pill padding and chip
434
+ * vertical padding by 2px each.
435
+ */
436
+ density?: 'comfortable' | 'compact';
437
+ }
438
+ declare function ChipNav({ items, scrollContainer, stickyTop, scrollOffset, actions, className, style, surface, activeId: activeIdProp, onItemClick, position, density, }: ChipNavProps): react_jsx_runtime.JSX.Element;
439
+
440
+ interface CompletionRingProps {
441
+ /** 0–100. Values outside the range are clamped. */
442
+ percent: number;
443
+ /** Outer dimension in px. Default 30. */
444
+ size?: number;
445
+ /** Ring stroke width in px. Default scales with size (size / 12). */
446
+ strokeWidth?: number;
447
+ /**
448
+ * What to render in the middle. Defaults to the percent number with
449
+ * a `%` suffix. Pass `false`/`null` to hide. Pass a node (icon, text)
450
+ * to fully override.
451
+ */
452
+ label?: ReactNode | false;
453
+ /** Convenience: false hides the default label. Same as `label={false}`. */
454
+ showLabel?: boolean;
455
+ /** Track colour CSS value. Defaults to `--surface-overlay-strong`. */
456
+ trackColor?: string;
457
+ /** Fill (progress arc) colour. Defaults to `--accent`. */
458
+ fillColor?: string;
459
+ /** Extra classes / inline style on the wrapper. */
460
+ className?: string;
461
+ style?: CSSProperties;
462
+ }
463
+ declare function CompletionRing({ percent, size, strokeWidth, label, showLabel, trackColor, fillColor, className, style, }: CompletionRingProps): react_jsx_runtime.JSX.Element;
464
+
465
+ /**
466
+ * MicrosoftLogo — the Microsoft four-square brand mark, for "Sign in with
467
+ * Microsoft" SSO buttons (ADR-124 D8). Lucide has no Microsoft glyph, so this
468
+ * is a bespoke SVG primitive — which `@lovett/ui` is the one allowed home for
469
+ * (CLAUDE.md §2/§6). The four square colours are Microsoft's required brand
470
+ * colours (per their identity guidelines); they are intrinsic to the mark, not
471
+ * theme tokens, exactly like BrandLogoTile's imagery — so they live here as
472
+ * literals rather than `tokens.css` variables.
473
+ */
474
+ interface MicrosoftLogoProps {
475
+ /** Square size in px. Default 18 (matches a control-height button glyph). */
476
+ size?: number;
477
+ className?: string;
478
+ }
479
+ declare function MicrosoftLogo({ size, className }: MicrosoftLogoProps): react_jsx_runtime.JSX.Element;
480
+
481
+ interface ChoroplethProps {
482
+ /** `radius` → concentric circles; `isochrone` → concentric polygons. */
483
+ mode?: 'radius' | 'isochrone';
484
+ className?: string;
485
+ style?: CSSProperties;
486
+ }
487
+ declare function Choropleth({ mode, className, style }: ChoroplethProps): react_jsx_runtime.JSX.Element;
488
+
489
+ type Crumb = {
490
+ label: string;
491
+ to?: string;
492
+ };
493
+ interface PageShellProps {
494
+ /** Breadcrumb chain — last item renders as the bold current label.
495
+ * For back-compat, `breadcrumb` + `title` are still accepted. */
496
+ crumbs?: Crumb[];
497
+ /** Legacy convenience: single parent crumb (label only). */
498
+ breadcrumb?: string;
499
+ /** Legacy: current-page title. Used as the last crumb when `crumbs` isn't provided. */
500
+ title?: string;
501
+ /** Right-side actions in the page header. */
502
+ actions?: ReactNode;
503
+ /**
504
+ * Content for the horizontally-centered slot in `<PageHeaderHost />`
505
+ * (Phase 7a). Relayed via the slot portal alongside `crumbs` /
506
+ * `actions`. When mounted in slot-host mode, the content sits in a
507
+ * dedicated absolutely-centered slot between the breadcrumb cluster
508
+ * and the trailing chrome, so it stays centered regardless of left/
509
+ * right slot widths. Ignored when PageShell renders its own inline
510
+ * header (no `<PageHeaderHost />` mounted).
511
+ *
512
+ * Phase 7a's GeoSearch lens lifts its mode-tabs ChipNav into this
513
+ * slot so the AppHeader carries: sidebar-toggle | crumbs | tabs |
514
+ * theme-toggle. Other lenses leave it unset.
515
+ */
516
+ headerCenter?: ReactNode;
517
+ children: ReactNode;
518
+ /** Override content padding if needed. Default leaves room for the sticky-blend header. */
519
+ contentClassName?: string;
520
+ }
521
+ declare function PageHeaderSlotProvider({ children }: {
522
+ children: ReactNode;
523
+ }): react_jsx_runtime.JSX.Element;
524
+ /**
525
+ * Page shell — promoted from brand-ai-extension Phase 2a (ADR-009 Decision 7).
526
+ *
527
+ * Self-contained: provides a scrollable region whose sticky-blend header
528
+ * gains a translucent backdrop-blur background once you scroll past a few
529
+ * px. Breadcrumbs render at top-left, page actions at top-right.
530
+ *
531
+ * When mounted inside <PageHeaderSlotProvider> with a <PageHeaderHost />
532
+ * elsewhere, PageShell portals its header content into the host instead of
533
+ * rendering its own bar — the workspace uses this to merge the lens crumbs
534
+ * onto the same row as the workspace sidebar toggle.
535
+ */
536
+ declare function PageShell({ crumbs, breadcrumb, title, actions, headerCenter, children, contentClassName, }: PageShellProps): react_jsx_runtime.JSX.Element;
537
+
538
+ /**
539
+ * PageHeaderHost — single workspace-level header bar that the active
540
+ * <PageShell> portals its breadcrumbs/actions into. Renders the `leading`
541
+ * slot (typically a sidebar toggle button) on the same row, so the lens's
542
+ * chrome doesn't stack as a separate sticky band. The `trailing` slot
543
+ * sits past the portal area for persistent right-cluster chrome (e.g.
544
+ * a theme toggle) that should never collide with per-page actions.
545
+ *
546
+ * Sticky-blend: subscribes to the scroll container the active PageShell
547
+ * registered with the slot so the same scroll-past-4px fade-in still fires.
548
+ */
549
+ declare function PageHeaderHost({ leading, center, trailing, padX, }: {
550
+ leading?: ReactNode;
551
+ /**
552
+ * Horizontal padding utility for the header bar. Defaults to `px-3`
553
+ * (the toggle-anchored layout). Callers with no `leading` slot (e.g. a
554
+ * single-lens skin that hides the sidebar toggle) pass a larger inset
555
+ * like `px-7` so the breadcrumbs line up with the content column below
556
+ * instead of hugging the edge. ADR-061 D3.
557
+ */
558
+ padX?: string;
559
+ /**
560
+ * Horizontally-centered slot — Phase 7a (ADR-012 Decision 12
561
+ * deviation). Renders absolutely positioned at the geometric center
562
+ * of the header so width changes in the breadcrumb (left) and
563
+ * trailing (right) clusters never shift its position. The active
564
+ * `<PageShell>` may also portal content into this slot via its
565
+ * `headerCenter` prop; both routes target the same DOM node.
566
+ *
567
+ * Wrapped in a `max-w` so on narrow viewports the center stays
568
+ * within the breadcrumb and trailing clusters' visual lanes
569
+ * (truncates internally before overlapping).
570
+ */
571
+ center?: ReactNode;
572
+ trailing?: ReactNode;
573
+ }): react_jsx_runtime.JSX.Element;
574
+ /**
575
+ * Scrollable wrapper that exposes its scrollRef via a render prop so
576
+ * the consuming header (PageShell's internal PageHeader) can subscribe
577
+ * to scroll for the stuck-state effect.
578
+ */
579
+ declare function AppScroll({ children, className, }: {
580
+ children: (scrollRef: RefObject<HTMLDivElement | null>) => ReactNode;
581
+ className?: string;
582
+ }): react_jsx_runtime.JSX.Element;
583
+
584
+ type SonnerToasterProps = ComponentProps<typeof Toaster$1>;
585
+ /**
586
+ * Token-aware `<Toaster />` shell.
587
+ *
588
+ * Defaults: top-right, 12px gap, 5s duration. The toastOptions wire
589
+ * Sonner's internal CSS variables to our `--toast-*` tokens so toasts
590
+ * adopt the design system surface color, border, and text color.
591
+ *
592
+ * Apps can override any prop (position, duration, theme, etc.) by
593
+ * passing it through.
594
+ */
595
+ declare function Toaster(props: SonnerToasterProps): react_jsx_runtime.JSX.Element;
596
+
597
+ declare function SectionLabel({ children }: {
598
+ children: ReactNode;
599
+ }): react_jsx_runtime.JSX.Element;
600
+ declare function IdentityLabel({ children }: {
601
+ children: ReactNode;
602
+ }): react_jsx_runtime.JSX.Element;
603
+ declare function IdentityValue({ children, className, }: {
604
+ children: ReactNode;
605
+ className?: string;
606
+ }): react_jsx_runtime.JSX.Element;
607
+ declare function TextInput({ value, onChange, placeholder, autoFocus, autoComplete, name, }: {
608
+ value: string;
609
+ onChange: (v: string) => void;
610
+ placeholder?: string | undefined;
611
+ autoFocus?: boolean | undefined;
612
+ /** Forwarded so the browser's autofill / password manager can identify the field. */
613
+ autoComplete?: string | undefined;
614
+ /** Forwarded so the field participates in form submission / autofill heuristics. */
615
+ name?: string | undefined;
616
+ }): react_jsx_runtime.JSX.Element;
617
+ declare function TextareaInput({ value, onChange, placeholder, autoFocus, autoComplete, name, rows, }: {
618
+ value: string;
619
+ onChange: (v: string) => void;
620
+ placeholder?: string | undefined;
621
+ autoFocus?: boolean | undefined;
622
+ autoComplete?: string | undefined;
623
+ name?: string | undefined;
624
+ rows?: number | undefined;
625
+ }): react_jsx_runtime.JSX.Element;
626
+ declare function EmptyPlaceholder({ label, description, onAdd, }: {
627
+ label: string;
628
+ description?: string | undefined;
629
+ onAdd?: (() => void) | undefined;
630
+ }): react_jsx_runtime.JSX.Element;
631
+ declare function ListItem({ children }: {
632
+ children: ReactNode;
633
+ }): react_jsx_runtime.JSX.Element;
634
+
635
+ type Strategy = 'vertical' | 'horizontal' | 'grid';
636
+ declare function SortableList<T>({ items, getId, onReorder, strategy, children, }: {
637
+ items: T[];
638
+ getId: (item: T, index: number) => string;
639
+ onReorder: (items: T[]) => void;
640
+ strategy?: Strategy;
641
+ children: ReactNode;
642
+ }): react_jsx_runtime.JSX.Element;
643
+ declare function SortableItem({ id, children, }: {
644
+ id: string;
645
+ children: (props: {
646
+ dragHandleProps: HTMLAttributes<HTMLElement>;
647
+ setNodeRef: (node: HTMLElement | null) => void;
648
+ style: CSSProperties;
649
+ isDragging: boolean;
650
+ }) => ReactNode;
651
+ }): react_jsx_runtime.JSX.Element;
652
+ declare function DragHandle({ dragHandleProps, className, }: {
653
+ dragHandleProps: HTMLAttributes<HTMLElement>;
654
+ className?: string;
655
+ }): react_jsx_runtime.JSX.Element;
656
+
657
+ interface EmptyStateProps {
658
+ /** Lucide icon (or any ReactNode) rendered inside the 56×56 tile.
659
+ * Pass at h-7 w-7 (28px) for visual parity with the canonical sites. */
660
+ icon: ReactNode;
661
+ /** Headline text. */
662
+ title: string;
663
+ /** Optional supporting copy. Kept under max-w-md by default. */
664
+ description?: string;
665
+ /** Optional action buttons row. Wraps with gap-2. */
666
+ actions?: ReactNode;
667
+ /** Optional className override on the outer container — use sparingly
668
+ * (e.g. when the parent already provides vertical padding). */
669
+ className?: string;
670
+ }
671
+ declare function EmptyState({ icon, title, description, actions, className, }: EmptyStateProps): react_jsx_runtime.JSX.Element;
672
+
673
+ interface RadioGroupProps<T extends string = string> {
674
+ /** Form name — required for proper radio semantics + form submission. */
675
+ name: string;
676
+ /** Currently selected value. */
677
+ value: T | null;
678
+ /** Fires when the user picks a different option. */
679
+ onChange: (next: T) => void;
680
+ /** <Radio> children. */
681
+ children: ReactNode;
682
+ /** Visually-hidden label for screen readers. Renders as <legend>. */
683
+ ariaLabel?: string;
684
+ /** Layout direction. Defaults to vertical. */
685
+ orientation?: 'horizontal' | 'vertical';
686
+ /** Extra classes on the wrapping <fieldset>. */
687
+ className?: string;
688
+ /** Disable every child radio. */
689
+ disabled?: boolean;
690
+ }
691
+ declare function RadioGroup<T extends string = string>({ name, value, onChange, children, ariaLabel, orientation, className, disabled, }: RadioGroupProps<T>): react_jsx_runtime.JSX.Element;
692
+ interface RadioProps {
693
+ /** Value emitted to the group's onChange when picked. */
694
+ value: string;
695
+ /** Visible label. */
696
+ label: ReactNode;
697
+ /** Optional secondary text (smaller, --text-tertiary). */
698
+ description?: ReactNode;
699
+ /** Disable this specific radio (overrides group default). */
700
+ disabled?: boolean;
701
+ /** Extra classes on the outer <label>. */
702
+ className?: string;
703
+ }
704
+ declare const Radio: react.ForwardRefExoticComponent<RadioProps & react.RefAttributes<HTMLInputElement>>;
705
+
706
+ interface OptionTileProps {
707
+ selected: boolean;
708
+ onSelect: () => void;
709
+ inputType: 'radio' | 'checkbox';
710
+ /** Required for radio (shared name across the group). */
711
+ inputName: string | undefined;
712
+ label: ReactNode;
713
+ description: ReactNode | undefined;
714
+ disabled: boolean | undefined;
715
+ className: string | undefined;
716
+ }
717
+ declare function OptionTile({ selected, onSelect, inputType, inputName, label, description, disabled, className, }: OptionTileProps): react_jsx_runtime.JSX.Element;
718
+ interface OptionTileGroupOption<T extends string> {
719
+ value: T;
720
+ label: ReactNode;
721
+ description?: ReactNode;
722
+ disabled?: boolean;
723
+ }
724
+ type OptionTileGroupProps<T extends string = string> = {
725
+ type: 'radio';
726
+ name: string;
727
+ value: T | null;
728
+ onChange: (next: T) => void;
729
+ options: OptionTileGroupOption<T>[];
730
+ ariaLabel?: string;
731
+ columns?: number;
732
+ className?: string;
733
+ } | {
734
+ type: 'checkbox';
735
+ value: T[];
736
+ onChange: (next: T[]) => void;
737
+ options: OptionTileGroupOption<T>[];
738
+ ariaLabel?: string;
739
+ columns?: number;
740
+ className?: string;
741
+ /** Optional shared `name` attr on the underlying checkboxes (rarely needed). */
742
+ name?: string;
743
+ };
744
+ declare function OptionTileGroup<T extends string = string>(props: OptionTileGroupProps<T>): react_jsx_runtime.JSX.Element;
745
+
746
+ type MetricCardTone = 'neutral' | 'accent' | 'success' | 'warning' | 'destructive' | 'info';
747
+ interface MetricCardProps {
748
+ /** Headline value (large, semibold, tone-colored). Numbers should
749
+ * use `font-mono` for tabular alignment when relevant. */
750
+ value: ReactNode;
751
+ /** Small descriptive label below the value. */
752
+ label: string;
753
+ /** Optional tone — colors the value text. Background stays neutral. */
754
+ tone?: MetricCardTone;
755
+ /** Optional icon shown to the left of the value (h-5 w-5 expected). */
756
+ icon?: ReactNode;
757
+ /**
758
+ * Where the label sits relative to the value. Default `'bottom'`
759
+ * (value-then-label — the original shape; existing consumers are
760
+ * unchanged). `'top'` renders a small uppercase label above the
761
+ * value — the KPI-chip shape used by Calculator Shell v2 (ADR-076
762
+ * D8). The value size is unchanged in both positions.
763
+ */
764
+ labelPosition?: 'top' | 'bottom';
765
+ /** Optional className override for the outer container. */
766
+ className?: string;
767
+ }
768
+ declare function MetricCard({ value, label, tone, icon, labelPosition, className, }: MetricCardProps): react_jsx_runtime.JSX.Element;
769
+
770
+ /**
771
+ * ProgressBar — labeled fill bar.
772
+ *
773
+ * Promoted in ADR-020 (Phase 3a Discovery report generation, first
774
+ * committed consumer). Cross-batch consumers: Phase 8 (AI-suggest
775
+ * progress if surfaced), Phase 12 (generation step in wizard).
776
+ *
777
+ * Indeterminate variant for unknown-duration progress (animated
778
+ * stripe sweep); determinate variant for known-percent progress.
779
+ *
780
+ * Token discipline: all colors via public tokens.
781
+ */
782
+ interface ProgressBarProps {
783
+ /** Optional label above the bar. */
784
+ label?: string;
785
+ /** 0-100 percent (determinate). Omit for indeterminate animation. */
786
+ percent?: number;
787
+ /** Optional secondary text shown right of the label. Often "X%" or a status message. */
788
+ status?: string;
789
+ /** Track height in px (default 8). */
790
+ height?: number;
791
+ }
792
+ declare function ProgressBar({ label, percent, status, height }: ProgressBarProps): react_jsx_runtime.JSX.Element;
793
+
794
+ /**
795
+ * StepLoader — a sequential, multi-step loading indicator (3-5 steps). Each step
796
+ * dwells for a believable duration, then the next begins (completed → check, current
797
+ * → spinner, pending → dot), connected by a vertical rail.
798
+ *
799
+ * The defining behavior: the FINAL step is HELD until the real work reports `done`
800
+ * AND a minimum dwell has elapsed — so a backend that returns faster than usual still
801
+ * plays the full, believable sequence instead of snapping away. Non-final steps always
802
+ * advance on their own timers (independent of `done`).
803
+ *
804
+ * <StepLoader steps={[...]} done={isReady} onComplete={() => show()} />
805
+ */
806
+ interface StepLoaderStep {
807
+ label: string;
808
+ /** Override the default dwell for this step (ms). */
809
+ durationMs?: number;
810
+ }
811
+ interface StepLoaderProps {
812
+ /** The ordered steps (3-5). Strings use the default dwell. */
813
+ steps: ReadonlyArray<string | StepLoaderStep>;
814
+ /** The real work finished — gates completion of the FINAL step only. */
815
+ done?: boolean;
816
+ /** Fired once the sequence has played out AND `done` is true (+ `minLastStepMs`). */
817
+ onComplete?: () => void;
818
+ /** Default per-step dwell (ms) for steps without an explicit duration. */
819
+ defaultStepMs?: number;
820
+ /** Minimum time the final step stays before completing — keeps a fast result believable. */
821
+ minLastStepMs?: number;
822
+ className?: string;
823
+ }
824
+ declare function StepLoader({ steps, done, onComplete, defaultStepMs, minLastStepMs, className, }: StepLoaderProps): react_jsx_runtime.JSX.Element;
825
+
826
+ type BadgeTone = 'neutral' | 'accent' | 'success' | 'warning' | 'destructive' | 'info';
827
+ interface BadgeProps {
828
+ tone: BadgeTone;
829
+ children: ReactNode;
830
+ /** Optional leading icon — sized 12-14px expected. */
831
+ icon?: ReactNode;
832
+ /** Leading status dot in the tone color (gray-ui chip style). Ignored
833
+ * when `icon` is provided. */
834
+ dot?: boolean;
835
+ /** Size variant. `sm` = compact (10px), `md` = default (11px),
836
+ * `lg` = roomier category-chip (12px, taller). */
837
+ size?: 'sm' | 'md' | 'lg';
838
+ /** Extra classes merged onto the outer span (no longer replaces base). */
839
+ className?: string;
840
+ }
841
+ declare function Badge({ tone, children, icon, dot, size, className, }: BadgeProps): react_jsx_runtime.JSX.Element;
842
+
843
+ interface TokenBadgeProps {
844
+ /** Public token name to tint from, e.g. `--folder-teal`, `--accent`,
845
+ * `--success`. Must include the leading `--`. */
846
+ colorVar: string;
847
+ children: ReactNode;
848
+ /** `soft` = tinted fill (default). `outline` = transparent fill + tinted
849
+ * border. */
850
+ variant?: 'soft' | 'outline';
851
+ /** Optional leading status dot in the token color. Ignored when `icon` set. */
852
+ dot?: boolean;
853
+ /** Optional leading icon (12–14px expected). */
854
+ icon?: ReactNode;
855
+ /** `sm` (10px) · `md` (11px, default) · `lg` (12px, taller). */
856
+ size?: 'sm' | 'md' | 'lg';
857
+ /** Pill (`full`) vs squared category tag (`tag`, default). */
858
+ shape?: 'tag' | 'pill';
859
+ /** Uppercase + wider tracking for short category codes (PRG, YT…). */
860
+ uppercase?: boolean;
861
+ className?: string;
862
+ }
863
+ declare function TokenBadge({ colorVar, children, variant, dot, icon, size, shape, uppercase, className, }: TokenBadgeProps): react_jsx_runtime.JSX.Element;
864
+
865
+ /**
866
+ * AllocationSparkbar — a compact per-period bar strip.
867
+ *
868
+ * New in ADR-123 (Budget Flighting redesign). Renders one bar per period
869
+ * (month), height proportional to the value; a zero/paused period renders
870
+ * short + dashed in a muted tone. Each bar can tint from its own token (e.g. a
871
+ * flight-group color), falling back to `baseColorVar`. Optional single-letter
872
+ * labels sit under each bar.
873
+ *
874
+ * Token discipline: colors come only from public token *names* via
875
+ * `rgb(var(--token) / a)`. No literals. Layout sizes use the spacing scale.
876
+ */
877
+ interface AllocationSparkbarProps {
878
+ /** Per-period amounts. A value of 0 is treated as paused (short + dashed). */
879
+ values: number[];
880
+ /** Base token name for normal bars, e.g. `--folder-teal`. Includes `--`. */
881
+ baseColorVar: string;
882
+ /** Optional per-period token name (e.g. a flight-group color). `null`/
883
+ * `undefined` falls back to `baseColorVar`. Length should match `values`. */
884
+ colorVars?: (string | null | undefined)[];
885
+ /** Optional short labels under each bar (e.g. `['J','F','M']`). */
886
+ labels?: string[];
887
+ /** Optional per-bar tooltip text (native `title`). */
888
+ titles?: string[];
889
+ /** Strip height in px. Default 36. */
890
+ height?: number;
891
+ className?: string;
892
+ }
893
+ declare function AllocationSparkbar({ values, baseColorVar, colorVars, labels, titles, height, className, }: AllocationSparkbarProps): react_jsx_runtime.JSX.Element;
894
+
895
+ type FloatingStatusTone = 'neutral' | 'accent' | 'success' | 'warning' | 'destructive' | 'info';
896
+ interface FloatingStatusBarProps {
897
+ /** Tone for the status dot + label color. */
898
+ tone: FloatingStatusTone;
899
+ /** Primary status label (tone-colored, bold). */
900
+ label: ReactNode;
901
+ /** Optional muted text after the label (e.g. a percentage). */
902
+ meta?: ReactNode;
903
+ /** Optional summary node shown after a vertical divider (e.g. `$X → $Y`). */
904
+ summary?: ReactNode;
905
+ /** Optional single action element (typically a secondary Button). */
906
+ action?: ReactNode;
907
+ /** Override the fixed positioning (e.g. to embed in a story). Default fixed
908
+ * bottom-center. */
909
+ className?: string;
910
+ }
911
+ declare function FloatingStatusBar({ tone, label, meta, summary, action, className, }: FloatingStatusBarProps): react_jsx_runtime.JSX.Element;
912
+
913
+ interface StatsGridProps {
914
+ children: ReactNode;
915
+ /** Minimum column width in px (controls how many cards per row at a
916
+ * given viewport). Default 220 — comfortable for 4-up at md+. */
917
+ minColumnWidth?: number;
918
+ /** Optional className override for the outer container. */
919
+ className?: string;
920
+ }
921
+ declare function StatsGrid({ children, minColumnWidth, className, }: StatsGridProps): react_jsx_runtime.JSX.Element;
922
+
923
+ interface Column<T> {
924
+ /** Unique id; doubles as the sort key. Use a `keyof T` string or
925
+ * an arbitrary string if `sortValue` is provided. */
926
+ id: string;
927
+ label: string;
928
+ /** How to render a cell for a row. */
929
+ accessor: (row: T) => ReactNode;
930
+ /** Optional explicit value used for sorting (defaults to the
931
+ * accessor's stringified output for sort comparison). */
932
+ sortValue?: (row: T) => string | number | null | undefined;
933
+ sortable?: boolean;
934
+ /** Right-align + tabular-nums for numeric columns. Default false. */
935
+ numeric?: boolean;
936
+ /** Header tooltip text. */
937
+ tooltip?: string;
938
+ /** Width as a CSS value (e.g. `120px` or `20%`). */
939
+ width?: string;
940
+ }
941
+ interface SortableTableProps<T> {
942
+ columns: Column<T>[];
943
+ rows: T[];
944
+ /** Function returning a stable React key for each row. */
945
+ rowKey: (row: T) => string;
946
+ /** Initial sort. */
947
+ initialSort?: {
948
+ columnId: string;
949
+ dir: 'asc' | 'desc';
950
+ };
951
+ /** Row click handler. */
952
+ onRowClick?: (row: T) => void;
953
+ /** Rendered when rows.length === 0. */
954
+ emptyState?: ReactNode;
955
+ /** Zebra stripe alternating rows. Default true. */
956
+ zebra?: boolean;
957
+ /** Compact density (smaller padding). Default false. */
958
+ compact?: boolean;
959
+ }
960
+ declare function SortableTable<T>({ columns, rows, rowKey, initialSort, onRowClick, emptyState, zebra, compact, }: SortableTableProps<T>): react_jsx_runtime.JSX.Element;
961
+
962
+ /**
963
+ * Pagination — "Showing X-Y of Z" + prev/next buttons.
964
+ *
965
+ * Promoted in ADR-022 (Phase 3c Discovery reports table, first
966
+ * committed consumer). Cross-batch consumers: Phase 3b contacts
967
+ * (when >50), Phase 8 keywords table, Phase 12 SEMSpec keywords tab.
968
+ *
969
+ * Stateless — parent owns currentPage state and provides onPageChange.
970
+ *
971
+ * Token discipline: all colors via public tokens.
972
+ */
973
+ interface PaginationProps {
974
+ /** 1-indexed current page. */
975
+ currentPage: number;
976
+ /** Items per page. */
977
+ pageSize: number;
978
+ /** Total item count across all pages. */
979
+ totalItems: number;
980
+ onPageChange: (page: number) => void;
981
+ }
982
+ declare function Pagination({ currentPage, pageSize, totalItems, onPageChange, }: PaginationProps): react_jsx_runtime.JSX.Element | null;
983
+
984
+ interface Tab {
985
+ id: string;
986
+ label: string;
987
+ /** Optional Lucide icon (h-3.5 w-3.5 to h-4 w-4 expected). */
988
+ icon?: ReactNode;
989
+ /** Optional count badge rendered after the label. */
990
+ count?: number;
991
+ disabled?: boolean;
992
+ }
993
+ interface TabsProps {
994
+ tabs: Tab[];
995
+ activeTabId: string;
996
+ onTabChange: (id: string) => void;
997
+ /** Compact (12px label) or default (13px). */
998
+ size?: 'sm' | 'md';
999
+ /** Underline (default) or pill active-state. */
1000
+ variant?: 'underline' | 'pill';
1001
+ /** Stretch the tablist to full width with equal-width, centred tabs. */
1002
+ stretch?: boolean;
1003
+ className?: string;
1004
+ }
1005
+ declare function Tabs({ tabs, activeTabId, onTabChange, size, variant, stretch, className, }: TabsProps): react_jsx_runtime.JSX.Element;
1006
+
1007
+ interface PillButtonProps {
1008
+ active: boolean;
1009
+ onClick: () => void;
1010
+ children: ReactNode;
1011
+ /** Size variant. `sm` = compact (12px), `md` = default (13px). */
1012
+ size?: 'sm' | 'md';
1013
+ /** Optional active-state tone. Default = accent. */
1014
+ tone?: BadgeTone;
1015
+ /** Optional leading icon (12-14px). */
1016
+ icon?: ReactNode;
1017
+ disabled?: boolean;
1018
+ }
1019
+ declare function PillButton({ active, onClick, children, size, tone, icon, disabled, }: PillButtonProps): react_jsx_runtime.JSX.Element;
1020
+
1021
+ interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'onChange' | 'checked'> {
1022
+ checked?: boolean;
1023
+ indeterminate?: boolean;
1024
+ onCheckedChange?: (checked: boolean) => void;
1025
+ }
1026
+ declare const Checkbox: react.ForwardRefExoticComponent<CheckboxProps & react.RefAttributes<HTMLInputElement>>;
1027
+
1028
+ type Align = 'start' | 'center' | 'end';
1029
+ type Side = 'top' | 'bottom';
1030
+ interface DropdownMenuProps {
1031
+ /** Controlled open state. Omit for internal state. */
1032
+ open?: boolean;
1033
+ /** Fires whenever open transitions. */
1034
+ onOpenChange?: (open: boolean) => void;
1035
+ defaultOpen?: boolean;
1036
+ children: ReactNode;
1037
+ }
1038
+ declare function DropdownMenu({ open: controlledOpen, onOpenChange, defaultOpen, children, }: DropdownMenuProps): react_jsx_runtime.JSX.Element;
1039
+ interface DropdownMenuTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
1040
+ /** Skip the default secondary-Button styling. Useful when wrapping
1041
+ * an existing Button primitive. */
1042
+ unstyled?: boolean;
1043
+ }
1044
+ /**
1045
+ * Default trigger styled per ADR-026 D4 (DQ-4) — inherits the
1046
+ * secondary Button visual (rounded-xl + `--bg-card` fill + 1px
1047
+ * `--border`). Set `unstyled` to wrap your own button shape.
1048
+ */
1049
+ declare function DropdownMenuTrigger({ unstyled, className, onClick, children, ...rest }: DropdownMenuTriggerProps): react_jsx_runtime.JSX.Element;
1050
+ interface DropdownMenuContentProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
1051
+ children: ReactNode;
1052
+ /** Horizontal alignment relative to the trigger. Default `start`. */
1053
+ align?: Align;
1054
+ /** Pixel offset along the alignment axis. Default 0. */
1055
+ alignOffset?: number;
1056
+ /** Place above (`top`) or below (`bottom`) the trigger. Default `bottom`. */
1057
+ side?: Side;
1058
+ /** Pixel offset along the side axis. Default 6. */
1059
+ sideOffset?: number;
1060
+ }
1061
+ declare function DropdownMenuContent({ children, align, alignOffset, side, sideOffset, className, style, ...rest }: DropdownMenuContentProps): react.ReactPortal | null;
1062
+ interface DropdownMenuItemProps extends ButtonHTMLAttributes<HTMLButtonElement> {
1063
+ variant?: 'default' | 'destructive';
1064
+ /** Pad-left compensation so items with no leading icon align with
1065
+ * items that have one. */
1066
+ inset?: boolean;
1067
+ }
1068
+ declare function DropdownMenuItem({ variant, inset, className, onClick, children, ...rest }: DropdownMenuItemProps): react_jsx_runtime.JSX.Element;
1069
+ interface DropdownMenuCheckboxItemProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onChange'> {
1070
+ checked?: boolean;
1071
+ onCheckedChange?: (checked: boolean) => void;
1072
+ }
1073
+ declare function DropdownMenuCheckboxItem({ checked, onCheckedChange, className, children, onClick, disabled, ...rest }: DropdownMenuCheckboxItemProps): react_jsx_runtime.JSX.Element;
1074
+ declare function DropdownMenuSeparator({ className, ...rest }: HTMLAttributes<HTMLDivElement>): react_jsx_runtime.JSX.Element;
1075
+ interface DropdownMenuLabelProps extends HTMLAttributes<HTMLDivElement> {
1076
+ inset?: boolean;
1077
+ }
1078
+ declare function DropdownMenuLabel({ inset, className, ...rest }: DropdownMenuLabelProps): react_jsx_runtime.JSX.Element;
1079
+ declare function DropdownMenuGroup({ className, ...rest }: HTMLAttributes<HTMLDivElement>): react_jsx_runtime.JSX.Element;
1080
+
1081
+ /**
1082
+ * DataGrid public types.
1083
+ *
1084
+ * Ported 2026-05-18 from gray-ui-csm
1085
+ * https://github.com/Jason-uxui/gray-ui-csm/blob/baf8346ac0c1160282e0b173de1bffc594d9c9c3/components/data-grid/types.ts
1086
+ * License: MIT (see packages/ui/licenses/gray-ui-csm-LICENSE.txt)
1087
+ * Workspace ADR: ADR-025
1088
+ *
1089
+ * BRING_AS_IS per ADR-025 bucket table — surface API unchanged from
1090
+ * source so the source repo's docs still apply.
1091
+ */
1092
+
1093
+ type DataGridIcon = ComponentType<{
1094
+ className?: string;
1095
+ }>;
1096
+ type DataGridRowBase = {
1097
+ id: string;
1098
+ };
1099
+ type DataGridColumn<ColumnId extends string> = {
1100
+ id: ColumnId;
1101
+ label: string;
1102
+ icon: DataGridIcon;
1103
+ defaultWidth: number;
1104
+ minWidth?: number;
1105
+ /** Per-column sort opt-out (ADR-027). Defaults to true when DataGrid's
1106
+ * `onSortChange` is provided; false when not. Set explicitly to disable
1107
+ * sorting for columns that don't have a meaningful comparator. */
1108
+ sortable?: boolean;
1109
+ /** Pin this column to the left or right edge so it stays visible while
1110
+ * the grid scrolls horizontally. Pinned columns render opaque with a
1111
+ * soft scroll-shadow on their inner edge. Place left-pinned columns
1112
+ * first and right-pinned columns last. The built-in select column is
1113
+ * always pinned left. */
1114
+ pin?: 'left' | 'right';
1115
+ };
1116
+ /** Row-sort state (ADR-027). DataGrid renders the chevron + ARIA per
1117
+ * this state but does NOT sort rows itself — parent passes pre-sorted
1118
+ * `rows`. */
1119
+ type DataGridSortState<ColumnId extends string> = {
1120
+ columnId: ColumnId;
1121
+ dir: 'asc' | 'desc';
1122
+ };
1123
+ type DataGridDrawerPanelProps<Row, ColumnId extends string> = {
1124
+ drawerRow: Row | null;
1125
+ drawerRowIndex: number;
1126
+ drawerRowCount: number;
1127
+ drawerColumn: DataGridColumn<ColumnId> | null;
1128
+ drawerCellValue: ReactNode;
1129
+ getRowLabel: (row: Row) => string;
1130
+ isEditableColumn: (columnId: ColumnId) => boolean;
1131
+ isEmptyValue: (value: ReactNode) => boolean;
1132
+ updateRow: (rowId: string, updater: (row: Row) => Row) => void;
1133
+ openPreviousRow: () => void;
1134
+ openNextRow: () => void;
1135
+ closeDrawer: () => void;
1136
+ /** Whether the drawer should be visible. The default <DrawerPanel>
1137
+ * reads this to drive its <FloatingDrawer isOpen> binding; consumer
1138
+ * render-overrides may use it the same way. Added in the workspace
1139
+ * port (DEVIATION-5) to remove the `@base-ui/react` context coupling
1140
+ * the source relied on. */
1141
+ isOpen: boolean;
1142
+ };
1143
+ type DataGridToolbarRenderProps<ColumnId extends string> = {
1144
+ visibleRowCount: number;
1145
+ selectedRowIds: string[];
1146
+ selectedRowCount: number;
1147
+ allVisibleRowsSelected: boolean;
1148
+ someVisibleRowsSelected: boolean;
1149
+ onToggleAllRows: (checked: boolean) => void;
1150
+ clearSelection: () => void;
1151
+ showSummaries: boolean;
1152
+ onShowSummariesChange: (next: boolean) => void;
1153
+ visibleColumns: DataGridColumn<ColumnId>[];
1154
+ visibleColumnIds: ColumnId[];
1155
+ hiddenColumns: DataGridColumn<ColumnId>[];
1156
+ toggleColumnVisibility: (columnId: ColumnId, visible: boolean) => void;
1157
+ optionsSensors: NonNullable<ComponentProps<typeof DndContext>['sensors']>;
1158
+ onOptionColumnDragEnd: (event: DragEndEvent) => void;
1159
+ optionsDndContextId: string;
1160
+ };
1161
+ type DataGridProps<Row extends DataGridRowBase, ColumnId extends string> = {
1162
+ rows: Row[];
1163
+ columns: DataGridColumn<ColumnId>[];
1164
+ getRowLabel: (row: Row) => string;
1165
+ renderCell: (row: Row, column: DataGridColumn<ColumnId>) => ReactNode;
1166
+ isEditableColumn: (columnId: ColumnId) => boolean;
1167
+ getCellEditValue: (row: Row, columnId: ColumnId) => string;
1168
+ applyCellEdit: (row: Row, columnId: ColumnId, nextValue: string) => Row;
1169
+ getDrawerCellValue: (row: Row, columnId: ColumnId) => ReactNode;
1170
+ canOpenDrawer?: (columnId: ColumnId) => boolean;
1171
+ renderSummary?: (column: DataGridColumn<ColumnId>, visibleRows: Row[]) => ReactNode;
1172
+ renderDrawerPanel?: (props: DataGridDrawerPanelProps<Row, ColumnId>) => ReactNode;
1173
+ renderToolbar?: (props: DataGridToolbarRenderProps<ColumnId>) => ReactNode;
1174
+ onToolbarPropsChange?: (props: DataGridToolbarRenderProps<ColumnId>) => void;
1175
+ onOpenDrawerCell?: (cell: EditingCell<ColumnId>) => void;
1176
+ /** Drawer renders in modal mode (backdrop + Esc + scroll lock).
1177
+ * Defaults to `false` per the source's contextless API. */
1178
+ drawerModal?: boolean;
1179
+ /** Pixel width of the drawer panel; passed through to FloatingDrawer.
1180
+ * Defaults to 520 (the FloatingDrawer side="right" default). */
1181
+ drawerSize?: number;
1182
+ stickySummaryFooter?: boolean;
1183
+ /** Keep the header row pinned to the top while the body scrolls. Renders
1184
+ * opaque with a scroll-shadow once scrolled. Default false. */
1185
+ stickyHeader?: boolean;
1186
+ /** Stretch the table to fill its container width via a trailing flex
1187
+ * "spacer" column that absorbs leftover space — real columns keep their
1188
+ * exact widths, so column resize stays independent. When the columns
1189
+ * outgrow the viewport the spacer collapses to 0 and the grid scrolls.
1190
+ * Default false. */
1191
+ fillWidth?: boolean;
1192
+ fillAvailableHeight?: boolean;
1193
+ tableContainerClassName?: string;
1194
+ onRowsChange?: (rows: Row[]) => void;
1195
+ /** Currently-sorted column + direction (ADR-027). Parent owns the
1196
+ * state and passes pre-sorted `rows`. When `null` or omitted, no
1197
+ * chevron renders (all columns show the unsorted indicator). */
1198
+ sort?: DataGridSortState<ColumnId> | null;
1199
+ /** Header click handler (ADR-027). Receives the clicked column id;
1200
+ * parent decides next direction (typical: toggle if same column,
1201
+ * else default to 'asc'). When omitted, headers are non-interactive
1202
+ * for sort purposes. Drag-to-reorder still works. */
1203
+ onSortChange?: (columnId: ColumnId) => void;
1204
+ };
1205
+ type EditingCell<ColumnId extends string> = {
1206
+ rowId: string;
1207
+ columnId: ColumnId;
1208
+ originRect?: {
1209
+ x: number;
1210
+ y: number;
1211
+ width: number;
1212
+ height: number;
1213
+ };
1214
+ };
1215
+
1216
+ declare function DataGrid<Row extends DataGridRowBase, ColumnId extends string>({ rows, columns, getRowLabel, renderCell, isEditableColumn, getCellEditValue, applyCellEdit, getDrawerCellValue, canOpenDrawer, renderSummary, renderDrawerPanel, renderToolbar, onToolbarPropsChange, onOpenDrawerCell, drawerModal, drawerSize, stickySummaryFooter, stickyHeader, fillWidth, fillAvailableHeight, tableContainerClassName, onRowsChange, sort, onSortChange, }: DataGridProps<Row, ColumnId>): react_jsx_runtime.JSX.Element;
1217
+
1218
+ interface DataGridToolbarProps {
1219
+ /** Left slot — typically a <SearchBar>. Stretches up to a comfortable
1220
+ * reading width, full-width when stacked. */
1221
+ search?: ReactNode;
1222
+ /** Right slot — filter / columns / view-toggle controls. */
1223
+ children?: ReactNode;
1224
+ className?: string;
1225
+ }
1226
+ declare function DataGridToolbar({ search, children, className, }: DataGridToolbarProps): react_jsx_runtime.JSX.Element;
1227
+
1228
+ type DataGridColumnOptionsMenuProps<ColumnId extends string> = Pick<DataGridToolbarRenderProps<ColumnId>, 'showSummaries' | 'onShowSummariesChange' | 'visibleColumns' | 'visibleColumnIds' | 'hiddenColumns' | 'toggleColumnVisibility' | 'optionsSensors' | 'onOptionColumnDragEnd' | 'optionsDndContextId'> & {
1229
+ triggerLabel?: string;
1230
+ };
1231
+ declare function DataGridColumnOptionsMenu<ColumnId extends string>({ showSummaries, onShowSummariesChange, visibleColumns, visibleColumnIds, hiddenColumns, toggleColumnVisibility, optionsSensors, onOptionColumnDragEnd, optionsDndContextId, triggerLabel, }: DataGridColumnOptionsMenuProps<ColumnId>): react_jsx_runtime.JSX.Element;
1232
+
1233
+ type DataGridDragOverlayProps<ColumnId extends string> = {
1234
+ dragOverlayColumn: DataGridColumn<ColumnId> | null;
1235
+ columnWidths: Record<ColumnId, number>;
1236
+ dragOverlayHeight: number;
1237
+ };
1238
+ declare function DataGridDragOverlay<ColumnId extends string>({ dragOverlayColumn, columnWidths, dragOverlayHeight, }: DataGridDragOverlayProps<ColumnId>): react_jsx_runtime.JSX.Element | null;
1239
+ type DataGridDropIndicatorProps = {
1240
+ dropIndicatorLeft: number | null;
1241
+ dragTableRect: {
1242
+ top: number;
1243
+ height: number;
1244
+ } | null;
1245
+ };
1246
+ declare function DataGridDropIndicator({ dropIndicatorLeft, dragTableRect, }: DataGridDropIndicatorProps): react_jsx_runtime.JSX.Element | null;
1247
+
1248
+ interface DropdownButtonItem {
1249
+ /** Stable id for keying. If omitted, the index is used (avoid for
1250
+ * long lists where order can change). */
1251
+ id?: string;
1252
+ /** Icon shown in the leading tile (Lucide or any ReactNode). */
1253
+ icon?: ReactNode;
1254
+ /** Primary label of the item. */
1255
+ label: string;
1256
+ /** Optional helper text rendered below the label. */
1257
+ description?: string;
1258
+ /** Visual variant — `default` or `destructive`. */
1259
+ variant?: 'default' | 'destructive';
1260
+ disabled?: boolean;
1261
+ onSelect: () => void;
1262
+ }
1263
+ interface DropdownButtonProps {
1264
+ /** Trigger label (e.g., "New Keyword Plan"). */
1265
+ label: string;
1266
+ /** Trigger variant — defaults to primary to match the screenshot. */
1267
+ variant?: ButtonVariant;
1268
+ /** Trigger size — passes through to the .btn size class. */
1269
+ size?: ButtonSize;
1270
+ /** Optional leading icon on the trigger (e.g., a `+`). */
1271
+ leadingIcon?: ReactNode;
1272
+ /** Override the default chevron-down trailing icon if needed. */
1273
+ trailingIcon?: ReactNode;
1274
+ /** Menu items rendered in order. */
1275
+ items: DropdownButtonItem[];
1276
+ /** Disable the trigger entirely. */
1277
+ disabled?: boolean;
1278
+ /** Show the .is-loading state on the trigger. */
1279
+ loading?: boolean;
1280
+ /** Forwarded to the trigger's className for layout overrides. */
1281
+ className?: string;
1282
+ /** Popover alignment relative to the trigger. Default `end`
1283
+ * (right-aligned) to match the reference screenshot. */
1284
+ align?: DropdownMenuContentProps['align'];
1285
+ /** Popover side — `top` or `bottom`. Default `bottom`. */
1286
+ side?: DropdownMenuContentProps['side'];
1287
+ /** Popover gap from the trigger. Default 6. */
1288
+ sideOffset?: DropdownMenuContentProps['sideOffset'];
1289
+ /** Constrain the popover width. Default `min(20rem, calc(100vw-16px))`. */
1290
+ menuWidth?: string;
1291
+ /** Optional aria-label for the trigger if the visible label is
1292
+ * ambiguous (e.g., icon-only triggers). */
1293
+ triggerAriaLabel?: string;
1294
+ /** Optional id of the currently-active item. When set, that item
1295
+ * renders a trailing check mark — turns the DropdownButton into a
1296
+ * single-select filter/picker. */
1297
+ activeId?: string;
1298
+ /** When true, the trigger gets an accent-tinted treatment — signals
1299
+ * an engaged filter. Pair with `activeId` for filter-chip use. */
1300
+ active?: boolean;
1301
+ }
1302
+ declare function DropdownButton({ label, variant, size, leadingIcon, trailingIcon, items, disabled, loading, className, align, side, sideOffset, menuWidth, triggerAriaLabel, activeId, active, }: DropdownButtonProps): react_jsx_runtime.JSX.Element;
1303
+
1304
+ interface AccordionProps {
1305
+ /** Ids of the currently-open sections. */
1306
+ openIds: string[];
1307
+ /** Fired with a section id when its header is clicked. */
1308
+ onToggle: (id: string) => void;
1309
+ children: ReactNode;
1310
+ className?: string;
1311
+ }
1312
+ declare function Accordion({ openIds, onToggle, children, className }: AccordionProps): react_jsx_runtime.JSX.Element;
1313
+ interface AccordionSectionProps {
1314
+ /** Stable id — matched against the Accordion's `openIds`. */
1315
+ id: string;
1316
+ title: string;
1317
+ /** Muted one-line summary under the title. */
1318
+ summary?: ReactNode;
1319
+ /** Optional node right of the title — e.g. a "New" <Badge>. */
1320
+ badge?: ReactNode;
1321
+ /** When true the leading indicator is an accent filled check;
1322
+ * otherwise an empty ring. */
1323
+ complete?: boolean;
1324
+ children: ReactNode;
1325
+ }
1326
+ declare function AccordionSection({ id, title, summary, badge, complete, children, }: AccordionSectionProps): react_jsx_runtime.JSX.Element;
1327
+ declare const AccordionCompound: typeof Accordion & {
1328
+ Section: typeof AccordionSection;
1329
+ };
1330
+
1331
+ interface MenuButtonItem {
1332
+ /** Stable id for keying. Falls back to the index. */
1333
+ id?: string;
1334
+ /** Optional leading icon (Lucide or any ReactNode), sized ~14px. */
1335
+ icon?: ReactNode;
1336
+ /** Primary label. */
1337
+ label: string;
1338
+ /** Optional right-aligned shortcut hint, e.g. "⌘C". */
1339
+ shortcut?: string;
1340
+ /** Visual variant. `destructive` tints the row red. */
1341
+ variant?: 'default' | 'destructive';
1342
+ disabled?: boolean;
1343
+ onSelect: () => void;
1344
+ }
1345
+ /** A divider between menu items. */
1346
+ interface MenuButtonSeparator {
1347
+ type: 'separator';
1348
+ }
1349
+ type MenuButtonEntry = MenuButtonItem | MenuButtonSeparator;
1350
+ interface MenuButtonProps {
1351
+ /** Trigger label — e.g. "File", "Edit". */
1352
+ label: string;
1353
+ /** Menu entries, in order. */
1354
+ items: MenuButtonEntry[];
1355
+ /** Optional leading icon on the trigger. */
1356
+ leadingIcon?: ReactNode;
1357
+ /** Disable the trigger entirely. */
1358
+ disabled?: boolean;
1359
+ /** Popover alignment relative to the trigger. Default `start`. */
1360
+ align?: DropdownMenuContentProps['align'];
1361
+ /** Popover width. Default `14rem`. */
1362
+ menuWidth?: string;
1363
+ /** Forwarded to the trigger className for layout overrides. */
1364
+ className?: string;
1365
+ /** aria-label for the trigger when the visible label is ambiguous. */
1366
+ triggerAriaLabel?: string;
1367
+ }
1368
+ declare function MenuButton({ label, items, leadingIcon, disabled, align, menuWidth, className, triggerAriaLabel, }: MenuButtonProps): react_jsx_runtime.JSX.Element;
1369
+
1370
+ /**
1371
+ * CopyField — an input/output field with a copy button pinned to the
1372
+ * top-right corner.
1373
+ *
1374
+ * The workbench input/output pattern from the tool prototypes: a single
1375
+ * field a user types into and that a transform writes its result back
1376
+ * into ("output replaces input"), with a one-click copy affordance
1377
+ * always in reach.
1378
+ *
1379
+ * Wraps <Textarea> (`multiline`, the default) or <Input>. Owns the copy
1380
+ * interaction end-to-end — clipboard write, a transient ✓ confirmation,
1381
+ * and a success/error toast. The field content is right-padded so text
1382
+ * never slides under the button.
1383
+ *
1384
+ * CopyField does NOT render a char/line count — that is caller state;
1385
+ * render it in the surrounding footer.
1386
+ *
1387
+ * Workspace ADR: ADR-031 Decision 2.
1388
+ */
1389
+ interface CopyFieldProps {
1390
+ /** Field value (controlled). */
1391
+ value: string;
1392
+ /** Change handler. Omit for a read-only output field. */
1393
+ onChange?: (value: string) => void;
1394
+ /** Multi-line textarea (default) or single-line input. */
1395
+ multiline?: boolean;
1396
+ /** Textarea row count. Ignored when `multiline` is false. */
1397
+ rows?: number;
1398
+ placeholder?: string;
1399
+ readOnly?: boolean;
1400
+ /** Visible field label — wires `<label htmlFor>`. */
1401
+ label?: string;
1402
+ /** Keep the label for assistive tech but hide it visually. */
1403
+ hideLabel?: boolean;
1404
+ /** Field id. Auto-generated when omitted. */
1405
+ id?: string;
1406
+ /** Toast message on a successful copy. */
1407
+ copyToastMessage?: string;
1408
+ className?: string;
1409
+ }
1410
+ declare function CopyField({ value, onChange, multiline, rows, placeholder, readOnly, label, hideLabel, id, copyToastMessage, className, }: CopyFieldProps): react_jsx_runtime.JSX.Element;
1411
+
1412
+ /**
1413
+ * TagChipInput — type-to-create chips with autocomplete.
1414
+ *
1415
+ * Behavior:
1416
+ * • Comma or Enter commits the current draft into a chip.
1417
+ * • Backspace on an empty input removes the last chip.
1418
+ * • Autocomplete suggestions surface as a popover; filtered by the
1419
+ * current draft (case-insensitive). Click or arrow-keys + Enter to
1420
+ * pick a suggestion.
1421
+ * • Tags are case-insensitively deduped; the displayed label preserves
1422
+ * the user's first casing per session.
1423
+ * • Submitting a new label (not in suggestions) creates it inline.
1424
+ *
1425
+ * Token discipline:
1426
+ * • Chips inherit Badge tones via tokens.
1427
+ * • Popover uses --popover / --popover-foreground / --shadow-lg.
1428
+ * • No hex, no inline SVG outside Lucide.
1429
+ *
1430
+ * First consumer: Keywords lens (NewSetPage, NewGroupPage). Generic —
1431
+ * promote anywhere a multi-tag input is needed.
1432
+ */
1433
+ interface TagChipInputProps {
1434
+ /** Current list of tag labels. */
1435
+ value: string[];
1436
+ onChange: (next: string[]) => void;
1437
+ /** Existing labels (across all items in scope) used for autocomplete. */
1438
+ suggestions?: string[];
1439
+ placeholder?: string;
1440
+ /** Hard cap on the number of chips. When reached, the input becomes
1441
+ * disabled with a "max reached" hint. */
1442
+ max?: number;
1443
+ /** Maximum length of any single tag. Defaults to 60. */
1444
+ maxLength?: number;
1445
+ /** Disable input + interactions. */
1446
+ disabled?: boolean;
1447
+ /** id attached to the text input — for label-for binding. */
1448
+ id?: string;
1449
+ /** Apply error styling. */
1450
+ error?: boolean;
1451
+ className?: string;
1452
+ }
1453
+ declare function TagChipInput({ value, onChange, suggestions, placeholder, max, maxLength, disabled, id, error, className, }: TagChipInputProps): react_jsx_runtime.JSX.Element;
1454
+
1455
+ /**
1456
+ * FolderTreePicker — dropdown picker for a nestable folder tree.
1457
+ *
1458
+ * Behavior:
1459
+ * • Trigger renders the selected folder's name (with parent breadcrumb
1460
+ * when nested) or a placeholder when none.
1461
+ * • Popover shows a "(No folder)" option + DFS-ordered tree with
1462
+ * indent by depth.
1463
+ * • Optional inline "+ New folder" path — when the consumer passes
1464
+ * `onCreateFolder`, the popover footer exposes a create form whose
1465
+ * parent defaults to the currently selected folder (or root).
1466
+ *
1467
+ * Generic — accepts a `folders: Array<{ id, name, parentId }>` shape so
1468
+ * any folder-like data structure can use it. First consumer: Keywords
1469
+ * lens NewSetPage / NewGroupPage.
1470
+ *
1471
+ * Token discipline: tokens only (no hex). Trigger inherits the same
1472
+ * `.btn .btn-secondary` chrome as our other dropdown triggers for
1473
+ * visual consistency.
1474
+ */
1475
+ interface FolderTreeNode {
1476
+ id: string;
1477
+ name: string;
1478
+ parentId: string | null;
1479
+ }
1480
+ interface FolderTreePickerProps {
1481
+ /** Flat list of folder nodes (parentId references id). */
1482
+ folders: FolderTreeNode[];
1483
+ /** Currently selected folder id, or null for "no folder" / root. */
1484
+ value: string | null;
1485
+ onChange: (next: string | null) => void;
1486
+ /** Optional inline-create handler. When omitted, the create UI is
1487
+ * hidden — the picker is read-only over the given folders. The
1488
+ * returned id is selected on success. */
1489
+ onCreateFolder?: (input: {
1490
+ name: string;
1491
+ parentId: string | null;
1492
+ }) => Promise<{
1493
+ id: string;
1494
+ }>;
1495
+ /** Placeholder when no folder is selected. */
1496
+ placeholder?: string;
1497
+ /** Disable everything. */
1498
+ disabled?: boolean;
1499
+ /** id for the trigger — supports label-for binding. */
1500
+ id?: string;
1501
+ /** Optional className for the trigger button. */
1502
+ className?: string;
1503
+ /** Apply error styling to the trigger. */
1504
+ error?: boolean;
1505
+ }
1506
+ declare function FolderTreePicker({ folders, value, onChange, onCreateFolder, placeholder, disabled, id, className, error, }: FolderTreePickerProps): react_jsx_runtime.JSX.Element;
1507
+
1508
+ interface HeroFormCardProps extends Omit<FormHTMLAttributes<HTMLFormElement>, 'title' | 'onSubmit'> {
1509
+ /** Small accent text above the title, e.g. "Brand · Research". */
1510
+ eyebrow?: ReactNode;
1511
+ /** The page-level title. Required. */
1512
+ title: ReactNode;
1513
+ /** Supporting copy under the title. */
1514
+ subtitle?: ReactNode;
1515
+ /** Optional helper text rendered between the body and the footer
1516
+ * (centered, muted). Good for "Name is required · everything else
1517
+ * is optional" affordances. */
1518
+ helperText?: ReactNode;
1519
+ /** Body — typically composed of Section + Field. */
1520
+ children: ReactNode;
1521
+ /** Footer action cluster (right-aligned). */
1522
+ footer?: ReactNode;
1523
+ /** Container max-width in px (default 720). */
1524
+ maxWidth?: number;
1525
+ /** When true the wrapping element is a <form> with onSubmit attached
1526
+ * (default). When false, renders a <div> — useful when an outer form
1527
+ * owns submission. */
1528
+ asForm?: boolean;
1529
+ /** Form submit handler. Ignored when `asForm` is false. */
1530
+ onSubmit?: (event: FormEvent<HTMLFormElement>) => void;
1531
+ className?: string;
1532
+ }
1533
+ interface HeroFormCardSectionProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
1534
+ /** Section heading. Optional — omit for an untitled body. */
1535
+ title?: ReactNode;
1536
+ /** Optional icon node (Lucide or custom). Sized by the consumer. */
1537
+ icon?: ReactNode;
1538
+ /** Optional supporting copy under the section title. */
1539
+ description?: ReactNode;
1540
+ /** Optional content rendered to the RIGHT of the section title row.
1541
+ * Good for inline helper text ("Name is required · everything else
1542
+ * is optional") or action chips. */
1543
+ trailing?: ReactNode;
1544
+ children: ReactNode;
1545
+ }
1546
+ declare function Section({ title, icon, description, trailing, children, className, ...rest }: HeroFormCardSectionProps): react_jsx_runtime.JSX.Element;
1547
+ interface HeroFormCardFieldProps {
1548
+ /** Visible field label. */
1549
+ label: ReactNode;
1550
+ /** HTML id of the underlying control — wires <label htmlFor>. */
1551
+ htmlFor?: string;
1552
+ required?: boolean;
1553
+ optional?: boolean;
1554
+ /** Inline error string. Renders below the field. */
1555
+ error?: string | null;
1556
+ /** Optional helper hint below the field (when no error). */
1557
+ hint?: ReactNode;
1558
+ children: ReactNode;
1559
+ className?: string;
1560
+ }
1561
+ declare function Field({ label, htmlFor, required, optional, error, hint, children, className, }: HeroFormCardFieldProps): react_jsx_runtime.JSX.Element;
1562
+ declare function FieldRow({ children, className, ...rest }: HTMLAttributes<HTMLDivElement>): react_jsx_runtime.JSX.Element;
1563
+ interface HeroFormCardBannerProps {
1564
+ /** Optional leading icon. */
1565
+ icon?: ReactNode;
1566
+ /** Body content — text + optional inline marks. */
1567
+ children: ReactNode;
1568
+ /** Visual tone. Default `info`. */
1569
+ tone?: 'info' | 'accent' | 'success' | 'warning' | 'destructive';
1570
+ className?: string;
1571
+ }
1572
+ declare function Banner({ icon, children, tone, className, }: HeroFormCardBannerProps): react_jsx_runtime.JSX.Element;
1573
+ interface HeroFormCardAdvancedProps {
1574
+ summary?: ReactNode;
1575
+ /** Optional icon node next to the summary. */
1576
+ icon?: ReactNode;
1577
+ defaultOpen?: boolean;
1578
+ children: ReactNode;
1579
+ className?: string;
1580
+ }
1581
+ declare function Advanced({ summary, icon, defaultOpen, children, className, }: HeroFormCardAdvancedProps): react_jsx_runtime.JSX.Element;
1582
+ declare function Footer({ children, className, ...rest }: HTMLAttributes<HTMLDivElement>): react_jsx_runtime.JSX.Element;
1583
+ declare const HeroFormCardCompound: react.ForwardRefExoticComponent<HeroFormCardProps & react.RefAttributes<HTMLFormElement>> & {
1584
+ Section: typeof Section;
1585
+ Field: typeof Field;
1586
+ FieldRow: typeof FieldRow;
1587
+ Banner: typeof Banner;
1588
+ Advanced: typeof Advanced;
1589
+ Footer: typeof Footer;
1590
+ };
1591
+
1592
+ interface RangeSliderProps {
1593
+ /** Lower bound of the track. */
1594
+ min: number;
1595
+ /** Upper bound of the track. */
1596
+ max: number;
1597
+ /** Current selection — `[low, high]`. Clamped within `[min, max]`. */
1598
+ value: [number, number];
1599
+ onChange: (next: [number, number]) => void;
1600
+ /** Step granularity. Default 1. */
1601
+ step?: number;
1602
+ /** Optional label rendered above the track. */
1603
+ label?: ReactNode;
1604
+ /** Formats the two end values shown beside the label. Default
1605
+ * `toLocaleString`. */
1606
+ formatValue?: (value: number) => string;
1607
+ /** id base — the two range inputs get `${id}-min` / `${id}-max`. */
1608
+ id?: string;
1609
+ disabled?: boolean;
1610
+ className?: string;
1611
+ }
1612
+ declare function RangeSlider({ min, max, value, onChange, step, label, formatValue, id, disabled, className, }: RangeSliderProps): react_jsx_runtime.JSX.Element;
1613
+
1614
+ interface SegmentedPillItem<Id extends string = string> {
1615
+ id: Id;
1616
+ label: ReactNode;
1617
+ icon?: ReactNode;
1618
+ disabled?: boolean;
1619
+ /** Optional accessible label override for icon-heavy segments. */
1620
+ ariaLabel?: string;
1621
+ }
1622
+ interface SegmentedPillProps<Id extends string = string> {
1623
+ items: SegmentedPillItem<Id>[];
1624
+ value: Id;
1625
+ onChange: (next: Id) => void;
1626
+ /** Accessible label for the whole group (rendered as aria-label on
1627
+ * the `role="tablist"` container). */
1628
+ ariaLabel?: string;
1629
+ /** Size variant — controls vertical padding + font. Default `md`.
1630
+ * `xs` is for dense inline contexts (e.g. a sort toggle inside a tab bar). */
1631
+ size?: 'xs' | 'sm' | 'md';
1632
+ /** Fill the available width and stretch segments. Default `true`. */
1633
+ stretch?: boolean;
1634
+ className?: string;
1635
+ }
1636
+ declare function SegmentedPill<Id extends string = string>({ items, value, onChange, ariaLabel, size, stretch, className, }: SegmentedPillProps<Id>): react_jsx_runtime.JSX.Element;
1637
+
1638
+ interface ShellProps extends HTMLAttributes<HTMLDivElement> {
1639
+ /** Max-width for the auto-centered page-level wrapper, in pixels.
1640
+ * Default 760 (tool-page width). New Set / similar form pages use
1641
+ * 880. When `centered` is false, the value is ignored. */
1642
+ maxWidth?: number;
1643
+ /** When true (default), the frame is centered horizontally inside
1644
+ * its parent via `mx-auto` + `max-width`. Pass `false` if you need
1645
+ * the frame to fill its parent (e.g. inside a tight grid cell). */
1646
+ centered?: boolean;
1647
+ }
1648
+ declare const ShellRoot: react.ForwardRefExoticComponent<ShellProps & react.RefAttributes<HTMLDivElement>>;
1649
+ interface ShellTrayProps extends HTMLAttributes<HTMLElement> {
1650
+ /** Visual variant. `default` (white inner pane, used for primary
1651
+ * content) or `compact` (tighter padding for dense rows). */
1652
+ variant?: 'default' | 'compact';
1653
+ }
1654
+ declare const Tray: react.ForwardRefExoticComponent<ShellTrayProps & react.RefAttributes<HTMLElement>>;
1655
+ interface ShellTrayHeaderProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
1656
+ title: ReactNode;
1657
+ /** Right-aligned meta — e.g. "12 lines · 3 dupes" or
1658
+ * "Name is required · everything else is optional". */
1659
+ meta?: ReactNode;
1660
+ /** Optional left-side numeral chip ("01", "02") in accent color.
1661
+ * Skip for tools that don't need step indication. */
1662
+ index?: ReactNode;
1663
+ /** Optional supporting copy beneath the title row. */
1664
+ description?: ReactNode;
1665
+ /** Tighter padding for dense layouts. */
1666
+ compact?: boolean;
1667
+ }
1668
+ declare function TrayHeader({ title, meta, index, description, compact, className, style, ...rest }: ShellTrayHeaderProps): react_jsx_runtime.JSX.Element;
1669
+ interface ShellTrayBodyProps extends HTMLAttributes<HTMLDivElement> {
1670
+ /** Vertical gap between children. Default `form` (16px). `grid`
1671
+ * (14px) is for tighter sub-card grids. `flush` (0) lets the
1672
+ * consumer manage spacing entirely. */
1673
+ spacing?: 'form' | 'grid' | 'flush';
1674
+ /** Tighter padding for dense layouts. */
1675
+ compact?: boolean;
1676
+ }
1677
+ declare function TrayBody({ spacing, compact, className, style, children, ...rest }: ShellTrayBodyProps): react_jsx_runtime.JSX.Element;
1678
+ interface ShellTrayFooterProps extends HTMLAttributes<HTMLDivElement> {
1679
+ /** Tighter padding for dense layouts. */
1680
+ compact?: boolean;
1681
+ /** Left-aligned secondary controls (toggles, disclosure, etc.).
1682
+ * Renders inline before any extra children. */
1683
+ left?: ReactNode;
1684
+ /** Right-aligned primary action (button, link, etc.). Pushed to
1685
+ * the right edge via `margin-left: auto`. */
1686
+ right?: ReactNode;
1687
+ }
1688
+ declare function TrayFooter({ compact, left, right, className, style, children, ...rest }: ShellTrayFooterProps): react_jsx_runtime.JSX.Element;
1689
+ interface ShellSubCardProps extends HTMLAttributes<HTMLDivElement> {
1690
+ /** Optional header content rendered above the body. */
1691
+ header?: ReactNode;
1692
+ }
1693
+ declare function SubCard({ header, className, style, children, ...rest }: ShellSubCardProps): react_jsx_runtime.JSX.Element;
1694
+ /** Value-text tone for <ShellStat>. Semantic tones map to the public
1695
+ * status tokens — handy for traffic-light KPIs (e.g. competition). */
1696
+ type ShellStatTone = 'default' | 'accent' | 'success' | 'warning' | 'destructive';
1697
+ interface ShellStatProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
1698
+ /** KPI name — rendered in the outer frame, above the tray. */
1699
+ label: ReactNode;
1700
+ /** The metric value — rendered large inside the inner white tray. */
1701
+ value: ReactNode;
1702
+ /** Optional icon shown beside the label in the frame. */
1703
+ icon?: ReactNode;
1704
+ /** Optional supporting text under the value (e.g. "+3 this week"). */
1705
+ hint?: ReactNode;
1706
+ /** Value text tone — `default`, `accent`, or a semantic status
1707
+ * color (`success` / `warning` / `destructive`). */
1708
+ valueTone?: ShellStatTone;
1709
+ }
1710
+ declare function ShellStat({ label, value, icon, hint, valueTone, className, ...rest }: ShellStatProps): react_jsx_runtime.JSX.Element;
1711
+ type ShellComponent = typeof ShellRoot & {
1712
+ Tray: typeof Tray;
1713
+ TrayHeader: typeof TrayHeader;
1714
+ TrayBody: typeof TrayBody;
1715
+ TrayFooter: typeof TrayFooter;
1716
+ SubCard: typeof SubCard;
1717
+ Stat: typeof ShellStat;
1718
+ };
1719
+ declare const Shell: ShellComponent;
1720
+
1721
+ type FolderColorKey = 'red' | 'amber' | 'emerald' | 'teal' | 'blue' | 'violet' | 'pink' | 'slate' | 'ink';
1722
+ /** All folder colour keys, in palette order — for swatch pickers. */
1723
+ declare const FOLDER_COLOR_KEYS: FolderColorKey[];
1724
+ /** Resolve a colour key to its `rgb(var(--folder-*))` CSS value. */
1725
+ declare function folderColorVar(key: FolderColorKey): string;
1726
+ interface FolderCardProps {
1727
+ name: string;
1728
+ colorKey: FolderColorKey;
1729
+ assetCount: number;
1730
+ /** Subfolder count — omitted or 0 → not shown. */
1731
+ folderCount?: number;
1732
+ selected?: boolean;
1733
+ /** When true, a selection checkbox reveals on hover and stays
1734
+ * visible while selected. */
1735
+ selectable?: boolean;
1736
+ onOpen: () => void;
1737
+ onSelect?: () => void;
1738
+ /** Optional menu affordance (e.g. a kebab trigger), revealed on
1739
+ * hover at the row end. */
1740
+ menuSlot?: ReactNode;
1741
+ className?: string;
1742
+ }
1743
+ declare function FolderCard({ name, colorKey, assetCount, folderCount, selected, selectable, onOpen, onSelect, menuSlot, className, }: FolderCardProps): react_jsx_runtime.JSX.Element;
1744
+
1745
+ interface BulkActionBarProps {
1746
+ /** Selection count shown in the accent badge. */
1747
+ count: number;
1748
+ /** Optional summary string, e.g. "2 folders · 3 assets". When
1749
+ * omitted, a plain "<count> selected" label is shown. */
1750
+ summary?: string;
1751
+ /** Caller-owned action buttons (icon buttons or labelled Buttons). */
1752
+ children: ReactNode;
1753
+ onClear: () => void;
1754
+ }
1755
+ declare function BulkActionBar({ count, summary, children, onClear, }: BulkActionBarProps): react_jsx_runtime.JSX.Element;
1756
+
1757
+ /**
1758
+ * FileUploadButton — paperclip trigger that opens a native file picker.
1759
+ * Disables itself when the file limit is reached.
1760
+ *
1761
+ * Promoted from brand-ai-extension (ADR-036 D20).
1762
+ */
1763
+ interface FileUploadButtonProps {
1764
+ onFilesSelected: (files: File[]) => void;
1765
+ disabled?: boolean;
1766
+ fileCount?: number;
1767
+ maxFiles?: number;
1768
+ }
1769
+ declare function FileUploadButton({ onFilesSelected, disabled, fileCount, maxFiles, }: FileUploadButtonProps): react_jsx_runtime.JSX.Element;
1770
+
1771
+ interface FileDropZoneProps {
1772
+ children: ReactNode;
1773
+ onFilesDropped: (files: File[]) => void;
1774
+ disabled?: boolean;
1775
+ className?: string;
1776
+ }
1777
+ declare function FileDropZone({ children, onFilesDropped, disabled, className, }: FileDropZoneProps): react_jsx_runtime.JSX.Element;
1778
+
1779
+ /**
1780
+ * useFileUpload — stateful file-selection, validation, text-extraction, and
1781
+ * XHR upload hook with per-file progress tracking.
1782
+ *
1783
+ * Promoted from brand-ai-extension (ADR-036 D20).
1784
+ *
1785
+ * D14 fix: the original hook read `import.meta.env.VITE_API_URL` and
1786
+ * hardcoded a fallback URL. A @lovett/ui primitive must not read env vars or
1787
+ * embed URLs. Consumers pass `uploadUrl` (required) and optional `authHeaders`
1788
+ * so the workspace `lib/api.ts` config can supply both without the primitive
1789
+ * knowing anything about the deployment environment.
1790
+ */
1791
+ interface UploadResult {
1792
+ id: string;
1793
+ filename: string;
1794
+ fileType: string;
1795
+ fileSize: number;
1796
+ fileCategory: string;
1797
+ publicUrl?: string;
1798
+ status: string;
1799
+ }
1800
+ interface PendingFile {
1801
+ id: string;
1802
+ file: File;
1803
+ progress: number;
1804
+ status: 'pending' | 'uploading' | 'uploaded' | 'error';
1805
+ error?: string;
1806
+ previewUrl?: string;
1807
+ extractedText?: string;
1808
+ uploadResult?: UploadResult;
1809
+ }
1810
+ interface UseFileUploadOptions {
1811
+ /**
1812
+ * Absolute URL that accepts POST multipart/form-data uploads.
1813
+ * Supplied by the consuming lens via `lib/api.ts` — never hardcoded here.
1814
+ */
1815
+ uploadUrl: string;
1816
+ /**
1817
+ * Optional HTTP headers forwarded with every XHR upload request
1818
+ * (e.g. `{ Authorization: 'Bearer <token>' }`). Supplied by the
1819
+ * consuming lens; the primitive never reads env vars or auth stores.
1820
+ */
1821
+ authHeaders?: Record<string, string>;
1822
+ /** Conversation ID to associate uploads with an existing conversation. */
1823
+ conversationId?: string | null | undefined;
1824
+ /** Maximum number of files (default: 10). */
1825
+ maxFiles?: number;
1826
+ /** Maximum bytes per file (default: 20 MB). */
1827
+ maxFileSize?: number;
1828
+ /** Called when a file fails to upload. */
1829
+ onError?: (error: Error) => void;
1830
+ }
1831
+ declare function useFileUpload({ uploadUrl, authHeaders, conversationId, maxFiles, maxFileSize, onError, }: UseFileUploadOptions): {
1832
+ pendingFiles: PendingFile[];
1833
+ addFiles: (files: File[]) => Promise<void>;
1834
+ removeFile: (fileId: string) => void;
1835
+ clearFiles: () => void;
1836
+ getUploadedResults: () => UploadResult[];
1837
+ isUploading: boolean;
1838
+ hasFilesUploading: boolean;
1839
+ hasUploadErrors: boolean;
1840
+ allFilesUploaded: boolean;
1841
+ totalProgress: number;
1842
+ sessionId: string;
1843
+ };
1844
+
1845
+ interface FilePreviewGridProps {
1846
+ files: PendingFile[];
1847
+ onRemove: (id: string) => void;
1848
+ className?: string;
1849
+ }
1850
+ declare function FilePreviewGrid({ files, onRemove, className }: FilePreviewGridProps): react_jsx_runtime.JSX.Element | null;
1851
+
1852
+ interface FilePreviewItemProps {
1853
+ pendingFile: PendingFile;
1854
+ onRemove: (id: string) => void;
1855
+ }
1856
+ declare function FilePreviewItem({ pendingFile, onRemove }: FilePreviewItemProps): react_jsx_runtime.JSX.Element;
1857
+
1858
+ /**
1859
+ * FileThumbnail — icon-based preview tile for non-image files; renders the
1860
+ * actual image for image files when a preview URL is available.
1861
+ *
1862
+ * Promoted from brand-ai-extension (ADR-036 D20).
1863
+ *
1864
+ * Token-boundary note: the source used Tailwind color utilities (text-red-600,
1865
+ * bg-blue-100, etc.) which are raw color literals. Rewritten to use inline
1866
+ * style with CSS variables from the public token set where possible, and
1867
+ * for the categorical file-type tints we use the --folder-* palette tokens
1868
+ * (ADR-035) which are the closest semantic color set in the design system
1869
+ * for categorical accent use.
1870
+ */
1871
+ interface FileThumbnailProps {
1872
+ file: File;
1873
+ previewUrl?: string;
1874
+ className?: string;
1875
+ }
1876
+ declare function FileThumbnail({ file, previewUrl, className }: FileThumbnailProps): react_jsx_runtime.JSX.Element;
1877
+
1878
+ interface CodeBlockProps {
1879
+ /** Lowercased language identifier, e.g. "typescript" or "json". */
1880
+ language?: string;
1881
+ /** Raw source text. */
1882
+ children: string;
1883
+ }
1884
+ declare function CodeBlock({ language, children }: CodeBlockProps): react_jsx_runtime.JSX.Element;
1885
+ /**
1886
+ * MarkdownCode — react-markdown code element adapter.
1887
+ *
1888
+ * Inline code (single backtick, no className) renders as a small chip.
1889
+ * Fenced code (triple backtick, className="language-xxx") delegates to
1890
+ * CodeBlock for syntax highlighting + copy button.
1891
+ */
1892
+ declare function MarkdownCode({ className, children }: HTMLAttributes<HTMLElement>): react_jsx_runtime.JSX.Element;
1893
+
1894
+ interface MarkdownRendererProps {
1895
+ /** Raw markdown string to render. */
1896
+ children: string;
1897
+ /** Optional className applied to the wrapping div. */
1898
+ className?: string;
1899
+ }
1900
+ /**
1901
+ * MarkdownRenderer — drop-in markdown surface with GFM support.
1902
+ * Renders headings, lists, code (via CodeBlock), tables, task lists,
1903
+ * strikethrough, blockquotes, and links with workspace token styling.
1904
+ */
1905
+ declare function MarkdownRenderer({ children, className }: MarkdownRendererProps): react_jsx_runtime.JSX.Element;
1906
+
1907
+ interface ResizableHandleProps {
1908
+ /** Which edge of the parent the handle decorates. */
1909
+ side: 'left' | 'right' | 'top' | 'bottom';
1910
+ /** Controlled width/height (px). */
1911
+ value: number;
1912
+ /** Called on every animation-frame-throttled pointermove during drag. */
1913
+ onChange: (next: number) => void;
1914
+ /** Called once on pointerup with the final value. Use for persistence. */
1915
+ onCommit?: (final: number) => void;
1916
+ /** Lower bound (px). */
1917
+ min: number;
1918
+ /** Upper bound (px). */
1919
+ max: number;
1920
+ /** Double-click / Home target. Defaults to `(min + max) / 2`. */
1921
+ defaultValue?: number;
1922
+ /** Keyboard nudge step (px). Default 16. */
1923
+ step?: number;
1924
+ /** ARIA label for the splitter. Required. */
1925
+ 'aria-label': string;
1926
+ /** Disable all interaction. Used by the sidebar's hover-out mode. */
1927
+ disabled?: boolean;
1928
+ className?: string;
1929
+ }
1930
+ declare function ResizableHandle({ side, value, onChange, onCommit, min, max, defaultValue, step, 'aria-label': ariaLabel, disabled, className, }: ResizableHandleProps): react_jsx_runtime.JSX.Element;
1931
+ interface ResizablePaneProps extends ResizableHandleProps {
1932
+ children: ReactNode;
1933
+ paneClassName?: string;
1934
+ }
1935
+ declare function ResizablePane({ children, paneClassName, ...handleProps }: ResizablePaneProps): react_jsx_runtime.JSX.Element;
1936
+
1937
+ interface KbdProps {
1938
+ /** Child text — typically a single key glyph or short string. */
1939
+ children: ReactNode;
1940
+ /** Optional size — defaults to 'md'. */
1941
+ size?: 'sm' | 'md';
1942
+ }
1943
+ declare function Kbd({ children, size }: KbdProps): react_jsx_runtime.JSX.Element;
1944
+
1945
+ interface FrameStackProps extends HTMLAttributes<HTMLDivElement> {
1946
+ /** Visual gap between child cards. Defaults to 10 px to match the
1947
+ * prototype's spec. Override only with a token value
1948
+ * (e.g. `'var(--space-3)'` for 12 px) — never a literal. */
1949
+ gap?: string;
1950
+ }
1951
+ declare const FrameStack: react.ForwardRefExoticComponent<FrameStackProps & react.RefAttributes<HTMLDivElement>>;
1952
+
1953
+ interface CalculatorShellProps {
1954
+ /** Display title (e.g. "ROAS Calculator"). Rendered as H1 + last
1955
+ * crumb in <PageShell>. */
1956
+ title: string;
1957
+ /** One-line subtitle below the title. Optional — describes what the
1958
+ * calculator computes. */
1959
+ subtitle?: string;
1960
+ /** Form inputs slot. Typically a vertical stack of @lovett/ui
1961
+ * <Input> primitives wrapped in <label>s with `type="number"`. */
1962
+ inputs: ReactNode;
1963
+ /** Headline result value — large, accent-tinted, tabular-nums. Pass
1964
+ * the FORMATTED string (use `formatCurrency` / `formatPercent` /
1965
+ * `formatRatio` / `formatNumber`). NaN inputs surface as `'—'`. */
1966
+ result: ReactNode;
1967
+ /** Optional formula label (e.g. "ROAS = Revenue ÷ Ad Spend"). Small,
1968
+ * dim, monospace-feel. Render as a <code> node so monospace +
1969
+ * semantics carry. */
1970
+ formula?: ReactNode;
1971
+ /** Optional row of secondary derived stats (smaller, dim). Pass a
1972
+ * node containing 1-3 stat tiles or a single inline span. */
1973
+ secondaryStats?: ReactNode;
1974
+ /** Optional reset to defaults. Renders a secondary "Reset" button
1975
+ * when provided. */
1976
+ onReset?: () => void;
1977
+ /** Optional copy-result value (the formatted result string). Renders
1978
+ * a "Copy result" secondary button when provided. The value is
1979
+ * written to the clipboard on click; the button flashes a checkmark
1980
+ * + emits a success toast on success. Pass `undefined` to omit the
1981
+ * button — typically when the underlying number is NaN. */
1982
+ copyValue?: string | undefined;
1983
+ /** Optional share-link URL — full or path. When provided, renders a
1984
+ * "Copy link" secondary button; click writes the URL to the
1985
+ * clipboard. (No tinyURL-style encoding here — the consumer
1986
+ * pre-builds the URL with encoded inputs.) */
1987
+ shareUrl?: string | undefined;
1988
+ }
1989
+ /**
1990
+ * CalculatorShell — the layout primitive. See file-level JSDoc for the
1991
+ * locked layout / interaction / token rules.
1992
+ */
1993
+ declare function CalculatorShell({ title, subtitle, inputs, result, formula, secondaryStats, onReset, copyValue, shareUrl, }: CalculatorShellProps): react_jsx_runtime.JSX.Element;
1994
+
1995
+ type CalcLayout = 'shell' | 'open';
1996
+ /**
1997
+ * Brand-profile prefill source (ADR-076 D9). Typed now so the data
1998
+ * connection is a later drop-in, not a refactor.
1999
+ *
2000
+ * TODO(data-layer): source = useActiveBrandProfile().brand — prefill
2001
+ * audience / CPM / etc. from the active brand (canonical brn_ id).
2002
+ */
2003
+ interface CalcPrefill {
2004
+ source: 'none' | 'brand';
2005
+ values?: Record<string, number>;
2006
+ }
2007
+ interface CalculatorShellV2Props {
2008
+ /** Mono uppercase eyebrow (e.g. "Streaming TV · Reality Check"). */
2009
+ eyebrow: string;
2010
+ /** Uppercase title. The last whitespace-delimited word renders in
2011
+ * `--accent`; a single word renders entirely in accent. Pass a
2012
+ * `[lead, accentWord]` tuple for explicit control (D4). */
2013
+ title: string | [string, string];
2014
+ /** Lucide glyph rendered red inside the header tile. */
2015
+ icon: ReactNode;
2016
+ /** Layout — `'shell'` (compact card) or `'open'` (long-form). */
2017
+ layout?: CalcLayout;
2018
+ /** One or more `<ProfileSection>` Frames composing the inputs. */
2019
+ inputs: ReactNode;
2020
+ /** A `<ProfileSection>` Frame wrapping the result block + StatRow. */
2021
+ result: ReactNode;
2022
+ /** Left-aligned muted footer note (also the data-mode signal, D9). */
2023
+ footerNote: ReactNode;
2024
+ /** Right-aligned footer actions (Reset / Save). The Copy action is
2025
+ * shell-owned via `copyReport` (Amendment 1 F) — do not pass a Copy
2026
+ * button here. */
2027
+ actions?: ReactNode;
2028
+ /** Assumptions content (Amendment 1 B): manual-vs-connected inputs, the
2029
+ * "directional planning math" disclaimer, and the config/formula version.
2030
+ * Rendered as a footer hover popover (not a body strip) so it never adds
2031
+ * shell height. Omitted when absent. */
2032
+ assumptions?: ReactNode;
2033
+ /** Structured mini-report for the shell-owned Copy action (Amendment 1
2034
+ * F). A string, or a function returning one (so it captures live state
2035
+ * at click time). When set, the shell renders a Copy button that writes
2036
+ * this to the clipboard. */
2037
+ copyReport?: string | (() => string);
2038
+ /** STUBBED (D9) — typed, not read this ADR. */
2039
+ prefill?: CalcPrefill;
2040
+ /** "vs. benchmark" rail. When absent, the shell renders a muted
2041
+ * "Benchmark unavailable in manual mode" placeholder (Amendment 1 E). */
2042
+ benchmarkSlot?: ReactNode;
2043
+ }
2044
+ declare function CalculatorShellV2({ eyebrow, title, icon, layout, inputs, result, footerNote, actions, assumptions, copyReport, benchmarkSlot, }: CalculatorShellV2Props): react_jsx_runtime.JSX.Element;
2045
+
2046
+ interface StatRowStep {
2047
+ /** Lucide glyph (~16px). Inherits the dark-frame label colour. */
2048
+ icon: ReactNode;
2049
+ /** Uppercase metric label (rendered ~9.5px). */
2050
+ label: string;
2051
+ /** Pre-formatted figure. Rendered tabular-nums. */
2052
+ value: string;
2053
+ /** The single pivotal tile — rendered in `--accent` instead of
2054
+ * `--brand-ink`. At most one step should set this. */
2055
+ pivotal?: boolean;
2056
+ }
2057
+ interface StatRowProps {
2058
+ steps: StatRowStep[];
2059
+ className?: string;
2060
+ }
2061
+ declare function StatRow({ steps, className }: StatRowProps): react_jsx_runtime.JSX.Element;
2062
+
2063
+ /**
2064
+ * Slider — single-value numeric slider (ADR-076 D8).
2065
+ *
2066
+ * Distinct from <RangeSlider>, which is dual-thumb (`value: [number,
2067
+ * number]`) and cannot represent a single value. This is the control
2068
+ * the Calculator Shell v2 frequency input uses: an accent fill from the
2069
+ * track start to the current value, a `--bg-card` thumb with a 2px
2070
+ * accent ring, and a transparent native `<input type="range">` overlaid
2071
+ * for keyboard + accessibility (arrows / Home / End come free).
2072
+ *
2073
+ * <Slider value={freq} min={1} max={10} step={0.5}
2074
+ * onChange={setFreq} aria-label="Target frequency" />
2075
+ *
2076
+ * Controlled — the parent owns `value`. Presentational otherwise.
2077
+ */
2078
+ interface SliderProps {
2079
+ value: number;
2080
+ min: number;
2081
+ max: number;
2082
+ /** Step granularity. Default 1. */
2083
+ step?: number;
2084
+ onChange: (value: number) => void;
2085
+ /** Accessible name for the native range input. */
2086
+ 'aria-label'?: string;
2087
+ disabled?: boolean;
2088
+ className?: string;
2089
+ }
2090
+ declare function Slider({ value, min, max, step, onChange, 'aria-label': ariaLabel, disabled, className, }: SliderProps): react_jsx_runtime.JSX.Element;
2091
+
2092
+ /**
2093
+ * Number-formatting helpers — small set of pure, zero-dep utilities
2094
+ * shared by the `<CalculatorShell>` consumers (ROAS / ROI / CTR / CPC
2095
+ * / CPM / Conversion Rate and the future ad-performance + customer/
2096
+ * business calculators).
2097
+ *
2098
+ * Locked by ADR-030 D6 (the helpers' existence + signatures) and
2099
+ * sharpened by ADR-058 D8 (re-exported from `@lovett/ui` alongside the
2100
+ * promoted `<CalculatorShell>`). Implementation rules:
2101
+ *
2102
+ * • Garbage in → `'—'` out. NaN, ±Infinity, null, undefined all
2103
+ * produce the em-dash string. Calculator UI should never crash on
2104
+ * partial input (empty inputs, zero divisors).
2105
+ * • Uses `Intl.NumberFormat('en-US', ...)` under the hood — proper
2106
+ * locale-aware separators, no manual `toFixed` rounding.
2107
+ * • `formatPercent` expects PERCENT UNITS, not a 0–1 fraction. Pass
2108
+ * `2.45` to get `"2.45%"`. Passing `0.0245` would yield `"0.02%"`.
2109
+ *
2110
+ * Zero runtime deps — `Intl.NumberFormat` is a built-in.
2111
+ */
2112
+ interface FormatOptions {
2113
+ /** Decimal places. Defaults vary per helper (see each helper's JSDoc). */
2114
+ decimals?: number;
2115
+ }
2116
+ /**
2117
+ * Format a number as USD currency.
2118
+ *
2119
+ * formatCurrency(42.5) → "$42.50"
2120
+ * formatCurrency(1234567.89) → "$1,234,567.89"
2121
+ * formatCurrency(NaN) → "—"
2122
+ *
2123
+ * Default decimals: 2.
2124
+ */
2125
+ declare function formatCurrency(n: number, opts?: FormatOptions): string;
2126
+ /**
2127
+ * Format a number as a percent. Input is in PERCENT UNITS (i.e. pass
2128
+ * `2.45` to get `"2.45%"`, NOT `0.0245`). This matches the way the
2129
+ * calculator routes compute their results (e.g. CTR = clicks ÷
2130
+ * impressions × 100 — the × 100 already happened upstream).
2131
+ *
2132
+ * formatPercent(2.45) → "2.45%"
2133
+ * formatPercent(3.2, { decimals: 1 }) → "3.2%"
2134
+ * formatPercent(NaN) → "—"
2135
+ *
2136
+ * Default decimals: 2.
2137
+ */
2138
+ declare function formatPercent(n: number, opts?: FormatOptions): string;
2139
+ /**
2140
+ * Format a number as a ratio with the `x` suffix. Used by ROAS.
2141
+ *
2142
+ * formatRatio(4.25) → "4.25x"
2143
+ * formatRatio(10, { decimals: 0 }) → "10x"
2144
+ * formatRatio(Infinity) → "—"
2145
+ *
2146
+ * Default decimals: 2.
2147
+ */
2148
+ declare function formatRatio(n: number, opts?: FormatOptions): string;
2149
+ /**
2150
+ * Format a number with thousand-separators and configurable decimals.
2151
+ *
2152
+ * formatNumber(1234567) → "1,234,567"
2153
+ * formatNumber(1234.567, { decimals: 2 }) → "1,234.57"
2154
+ * formatNumber(NaN) → "—"
2155
+ *
2156
+ * Default decimals: 0.
2157
+ */
2158
+ declare function formatNumber(n: number, opts?: FormatOptions): string;
2159
+
2160
+ declare function cn(...inputs: ClassValue[]): string;
2161
+
2162
+ /**
2163
+ * Layout constants shared between CSS and JS.
2164
+ *
2165
+ * Some primitives (e.g. ChipNav) need numeric pixel values for
2166
+ * `IntersectionObserver` rootMargin or `position: sticky` `top` style
2167
+ * — those can't read from CSS custom properties. To keep the layout
2168
+ * coherent, this module mirrors the canonical values from `tokens.css`.
2169
+ * If you change one, change the other.
2170
+ *
2171
+ * The corresponding CSS tokens are:
2172
+ * --header-height → HEADER_HEIGHT
2173
+ * --section-scroll-offset → SECTION_SCROLL_OFFSET
2174
+ */
2175
+ /** Height of the sticky AppHeader, in px. Mirrors `--header-height`. */
2176
+ declare const HEADER_HEIGHT = 56;
2177
+ /**
2178
+ * Vertical offset for in-page section anchors (header + chip nav +
2179
+ * breathing room). Mirrors `--section-scroll-offset`.
2180
+ */
2181
+ declare const SECTION_SCROLL_OFFSET = 120;
2182
+
2183
+ interface PageHeroProps {
2184
+ /** Small uppercase label above the title, usually colored with --accent. */
2185
+ eyebrow?: string;
2186
+ title: string;
2187
+ subtitle?: string;
2188
+ /** Right-aligned trailing content — typically a row of action buttons. */
2189
+ actions?: ReactNode;
2190
+ /**
2191
+ * Optional left-side adornment rendered alongside the title — e.g. the
2192
+ * brand profile's logo block. Sits in the title row (not next to the
2193
+ * eyebrow), vertically aligned with the title text. The hero gracefully
2194
+ * collapses if this is `undefined` so pages without an adornment look
2195
+ * unchanged.
2196
+ */
2197
+ leading?: ReactNode;
2198
+ className?: string;
2199
+ }
2200
+ declare function PageHero({ eyebrow, title, subtitle, actions, leading, className, }: PageHeroProps): react_jsx_runtime.JSX.Element;
2201
+
2202
+ interface SearchBarProps {
2203
+ value: string;
2204
+ onChange: (v: string) => void;
2205
+ placeholder?: string;
2206
+ width?: number | string;
2207
+ className?: string;
2208
+ }
2209
+ declare function SearchBar({ value, onChange, placeholder, width, className, }: SearchBarProps): react_jsx_runtime.JSX.Element;
2210
+
2211
+ interface FilterBarProps {
2212
+ /**
2213
+ * `framed` (default) = bordered `.ds-card-surface` card, matching the
2214
+ * Assets bar. `bare` = no frame, just the flex row (for bars that sit
2215
+ * inside an already-framed container).
2216
+ */
2217
+ variant?: 'framed' | 'bare';
2218
+ /** Accessible label for the toolbar group (e.g. "Asset filters"). */
2219
+ 'aria-label'?: string;
2220
+ className?: string;
2221
+ children: ReactNode;
2222
+ }
2223
+ declare function FilterBarRoot({ variant, 'aria-label': ariaLabel, className, children, }: FilterBarProps): react_jsx_runtime.JSX.Element;
2224
+ interface FilterBarSearchProps {
2225
+ value: string;
2226
+ onChange: (next: string) => void;
2227
+ placeholder?: string;
2228
+ /** Required — icon-only field needs an accessible name. */
2229
+ 'aria-label': string;
2230
+ /** Override the default width sizing if a bar needs it. */
2231
+ className?: string;
2232
+ }
2233
+ /** Standardized search field: small `Input` with a leading magnifier. */
2234
+ declare function FilterBarSearch({ value, onChange, placeholder, 'aria-label': ariaLabel, className, }: FilterBarSearchProps): react_jsx_runtime.JSX.Element;
2235
+ /** Flexible spacer — everything after it is pushed to the right edge. */
2236
+ declare function FilterBarSpacer(): react_jsx_runtime.JSX.Element;
2237
+ interface FilterBarCountProps {
2238
+ shown: number;
2239
+ total: number;
2240
+ }
2241
+ /** Right-aligned "{shown} of {total}" result count, tabular-nums. */
2242
+ declare function FilterBarCount({ shown, total }: FilterBarCountProps): react_jsx_runtime.JSX.Element;
2243
+ declare const FilterBar: typeof FilterBarRoot & {
2244
+ Search: typeof FilterBarSearch;
2245
+ Spacer: typeof FilterBarSpacer;
2246
+ Count: typeof FilterBarCount;
2247
+ };
2248
+
2249
+ interface FilterOption<T extends string = string> {
2250
+ value: T;
2251
+ label: string;
2252
+ /** Right-aligned count chip in the menu. */
2253
+ count?: number;
2254
+ /** Optional left-side adornment (icon, color dot). */
2255
+ leading?: ReactNode;
2256
+ }
2257
+ interface FilterDropdownProps<T extends string = string> {
2258
+ label: string;
2259
+ value: T;
2260
+ onChange: (value: T) => void;
2261
+ options: FilterOption<T>[];
2262
+ /** The value treated as "no filter applied" — defaults to "all". When
2263
+ * `value` differs from this, the trigger flips to its active style. */
2264
+ neutralValue?: T;
2265
+ /** Defaults to the option label. */
2266
+ triggerValueLabel?: string;
2267
+ className?: string;
2268
+ align?: 'left' | 'right';
2269
+ }
2270
+ declare function FilterDropdown<T extends string = string>({ label, value, onChange, options, neutralValue, triggerValueLabel, className, align, }: FilterDropdownProps<T>): react_jsx_runtime.JSX.Element;
2271
+
2272
+ interface DeviceFrameProps {
2273
+ /** Which device bezel to render. */
2274
+ device: 'desktop' | 'mobile';
2275
+ /**
2276
+ * URL shown in the address bar / pill. On desktop, the address bar is
2277
+ * hidden when omitted; on mobile the pill falls back to a neutral
2278
+ * placeholder.
2279
+ */
2280
+ url?: string;
2281
+ /** The page being previewed, rendered inside the (scrollable) screen area. */
2282
+ children: ReactNode;
2283
+ /** Optional className on the outer frame element. */
2284
+ className?: string;
2285
+ }
2286
+ declare function DeviceFrame({ device, url, children, className }: DeviceFrameProps): react_jsx_runtime.JSX.Element;
2287
+
2288
+ interface CreativeMediaProps {
2289
+ src: string;
2290
+ alt?: string | undefined;
2291
+ mediaType?: 'image' | 'video' | undefined;
2292
+ className?: string | undefined;
2293
+ style?: react__default.CSSProperties | undefined;
2294
+ autoPlay?: boolean | undefined;
2295
+ loop?: boolean | undefined;
2296
+ showPlayOverlay?: boolean | undefined;
2297
+ thumbnailSrc?: string | undefined;
2298
+ onError?: ((e: react__default.SyntheticEvent) => void) | undefined;
2299
+ }
2300
+ declare const CreativeMedia: react__default.FC<CreativeMediaProps>;
2301
+
2302
+ type PreviewPlatform = 'facebook' | 'instagram' | 'messenger';
2303
+ type PreviewPlacement = 'feed' | 'story' | 'reel' | 'inbox' | 'instream' | 'search' | 'rightcolumn' | 'explore';
2304
+ type PreviewDevice = 'mobile' | 'desktop';
2305
+ interface PreviewConfiguration {
2306
+ platform: PreviewPlatform;
2307
+ placement: PreviewPlacement;
2308
+ device: PreviewDevice;
2309
+ format: '1:1' | '4:5' | '9:16';
2310
+ }
2311
+ interface PreviewAdData {
2312
+ adName: string;
2313
+ primaryText: string;
2314
+ headline: string;
2315
+ description: string;
2316
+ callToAction: string;
2317
+ websiteUrl: string;
2318
+ displayLink: string;
2319
+ brandName: string;
2320
+ profileImage: string;
2321
+ creativeImage: string;
2322
+ creativeMediaType?: 'image' | 'video' | undefined;
2323
+ }
2324
+ /**
2325
+ * A single carousel card for the presentational carousel views (ADR-119 D1).
2326
+ * Per-card copy/destination only — the CTA is ad-level/shared (ADR-119 D3).
2327
+ */
2328
+ interface CarouselCardView {
2329
+ key: string;
2330
+ headline?: string | undefined;
2331
+ description?: string | undefined;
2332
+ url?: string | undefined;
2333
+ }
2334
+ /**
2335
+ * Props for the pure presentational carousels (`MetaFeedCarousel`,
2336
+ * `InstagramFeedCarousel`). They own NO data or crop logic: the caller supplies
2337
+ * the card list, the active index + setter, and an image-render slot
2338
+ * (`CropFrame` on the controller-driven form side; a plain <img> on static
2339
+ * surfaces). Because the view imports neither the controller nor the crop
2340
+ * system, it lives in `packages/ui` and earns Meta-exact hex (ADR-119 D1/D5).
2341
+ */
2342
+ interface CarouselViewProps {
2343
+ cards: CarouselCardView[];
2344
+ active: number;
2345
+ onActive: (index: number) => void;
2346
+ renderImage: (index: number) => ReactNode;
2347
+ brandName: string;
2348
+ profileImage?: string | undefined;
2349
+ primaryText?: string | undefined;
2350
+ /** Ad-level CTA, shared across cards (ADR-119 D3). */
2351
+ callToAction: string;
2352
+ }
2353
+ interface PlacementPreview {
2354
+ id: string;
2355
+ platform: PreviewPlatform;
2356
+ placement: PreviewPlacement;
2357
+ label: string;
2358
+ description: string;
2359
+ aspectRatio: '1:1' | '4:5' | '9:16';
2360
+ device: PreviewDevice;
2361
+ enabled: boolean;
2362
+ }
2363
+ declare const PLACEMENT_CONFIGS: PlacementPreview[];
2364
+
2365
+ /**
2366
+ * Facebook Feed — single image (sponsored). GREENFIELD rebuild.
2367
+ *
2368
+ * Not the Creative-Hub export extraction. Faithful to the real FB feed ad chrome
2369
+ * but built cleanly: a 320px card with natural full-width flow (no fixed
2370
+ * 300px / containerWidth-24 inner rows, no divider margins), Meta-exact hex
2371
+ * (self-contained — no design tokens), a system font stack. Layout, top → bottom:
2372
+ * header · primary text · creative · link card · divider · action bar
2373
+ */
2374
+ interface MetaFeedPreviewProps {
2375
+ adData: PreviewAdData;
2376
+ format: '1:1' | '4:5' | '9:16';
2377
+ }
2378
+ declare const MetaFeedPreview: react.NamedExoticComponent<MetaFeedPreviewProps>;
2379
+
2380
+ interface MetaStoryPreviewProps {
2381
+ platform: PreviewPlatform;
2382
+ adData: PreviewAdData;
2383
+ dominantColor?: string | undefined;
2384
+ accentColor?: string | undefined;
2385
+ isLight?: boolean | undefined;
2386
+ }
2387
+ /**
2388
+ * Meta Stories Preview (Facebook/Instagram/Messenger)
2389
+ * Exact styling extracted from Facebook Creative Hub
2390
+ * Reference: creative-spec/references/META_DESIGN_TOKENS.md
2391
+ * Sources: facebook-stories-singleimage-1080x1080.html, instagram-mobile-stories-singleimage-1080x1080.html
2392
+ * Facebook Stories Container: 318x566px
2393
+ * Instagram Stories Container: 320x567px (inner: 318x565px)
2394
+ */
2395
+ declare const MetaStoryPreview: react__default.FC<MetaStoryPreviewProps>;
2396
+
2397
+ interface MetaReelPreviewProps {
2398
+ platform: PreviewPlatform;
2399
+ adData: PreviewAdData;
2400
+ dominantColor?: string | undefined;
2401
+ accentColor?: string | undefined;
2402
+ }
2403
+ /**
2404
+ * Facebook/Instagram Reels Preview
2405
+ * Exact styling extracted from Facebook Creative Hub
2406
+ * Reference: creative-spec/references/META_DESIGN_TOKENS.md
2407
+ * Source: Facebook-Reels-singleimage-1080x1080.html extraction
2408
+ * Container: 320x567px (9:16 ratio)
2409
+ */
2410
+ declare const MetaReelPreview: react__default.FC<MetaReelPreviewProps>;
2411
+
2412
+ interface MetaMessengerPreviewProps {
2413
+ adData: PreviewAdData;
2414
+ }
2415
+ /**
2416
+ * Facebook Messenger Inbox Preview
2417
+ * Exact styling extracted from Facebook Creative Hub
2418
+ * Reference: creative-spec/references/META_DESIGN_TOKENS.md
2419
+ * Source: singleimage-facebook-messenger-inbox.html
2420
+ * Container: 250x444px (outer), 375x142px (inner - Ad view)
2421
+ */
2422
+ declare const MetaMessengerPreview: react__default.FC<MetaMessengerPreviewProps>;
2423
+
2424
+ interface MetaRightColumnPreviewProps {
2425
+ adData: PreviewAdData;
2426
+ }
2427
+ /**
2428
+ * Facebook Desktop Right Column Preview
2429
+ * Exact styling extracted from Facebook Creative Hub
2430
+ * Reference: creative-spec/references/META_DESIGN_TOKENS.md
2431
+ * Source: desktop-right-column.html extraction
2432
+ * Container: 375x206px
2433
+ */
2434
+ declare const MetaRightColumnPreview: react__default.FC<MetaRightColumnPreviewProps>;
2435
+
2436
+ interface MetaSearchPreviewProps {
2437
+ adData: PreviewAdData;
2438
+ }
2439
+ declare const MetaSearchPreview: react__default.FC<MetaSearchPreviewProps>;
2440
+
2441
+ interface MetaInstreamPreviewProps {
2442
+ adData: PreviewAdData;
2443
+ }
2444
+ declare const MetaInstreamPreview: react__default.FC<MetaInstreamPreviewProps>;
2445
+
2446
+ /**
2447
+ * Instagram Feed — single image (sponsored). GREENFIELD rebuild.
2448
+ *
2449
+ * Not the Creative-Hub export extraction. Faithful to the real IG sponsored-post
2450
+ * chrome but built cleanly: a 320px card with natural full-width flow (no fixed
2451
+ * 300px inner rows, no empty placeholder divs), Meta-exact hex (self-contained —
2452
+ * no design tokens), and a system font stack. Layout, top → bottom:
2453
+ * header · creative · CTA bar · action row · caption
2454
+ */
2455
+ interface InstagramFeedPreviewProps {
2456
+ adData: PreviewAdData;
2457
+ format: '1:1' | '4:5' | '9:16';
2458
+ }
2459
+ declare const InstagramFeedPreview: react.NamedExoticComponent<InstagramFeedPreviewProps>;
2460
+
2461
+ interface InstagramExplorePreviewProps {
2462
+ adData: PreviewAdData;
2463
+ }
2464
+ declare const InstagramExplorePreview: react__default.FC<InstagramExplorePreviewProps>;
2465
+
2466
+ declare const MetaFeedCarousel: react.NamedExoticComponent<CarouselViewProps>;
2467
+
2468
+ declare const InstagramFeedCarousel: react.NamedExoticComponent<CarouselViewProps>;
2469
+
2470
+ type index_CarouselCardView = CarouselCardView;
2471
+ type index_CarouselViewProps = CarouselViewProps;
2472
+ declare const index_CreativeMedia: typeof CreativeMedia;
2473
+ declare const index_InstagramExplorePreview: typeof InstagramExplorePreview;
2474
+ declare const index_InstagramFeedCarousel: typeof InstagramFeedCarousel;
2475
+ declare const index_InstagramFeedPreview: typeof InstagramFeedPreview;
2476
+ declare const index_MetaFeedCarousel: typeof MetaFeedCarousel;
2477
+ declare const index_MetaFeedPreview: typeof MetaFeedPreview;
2478
+ declare const index_MetaInstreamPreview: typeof MetaInstreamPreview;
2479
+ declare const index_MetaMessengerPreview: typeof MetaMessengerPreview;
2480
+ declare const index_MetaReelPreview: typeof MetaReelPreview;
2481
+ declare const index_MetaRightColumnPreview: typeof MetaRightColumnPreview;
2482
+ declare const index_MetaSearchPreview: typeof MetaSearchPreview;
2483
+ declare const index_MetaStoryPreview: typeof MetaStoryPreview;
2484
+ declare const index_PLACEMENT_CONFIGS: typeof PLACEMENT_CONFIGS;
2485
+ type index_PlacementPreview = PlacementPreview;
2486
+ type index_PreviewAdData = PreviewAdData;
2487
+ type index_PreviewConfiguration = PreviewConfiguration;
2488
+ type index_PreviewDevice = PreviewDevice;
2489
+ type index_PreviewPlacement = PreviewPlacement;
2490
+ type index_PreviewPlatform = PreviewPlatform;
2491
+ declare namespace index {
2492
+ export { type index_CarouselCardView as CarouselCardView, type index_CarouselViewProps as CarouselViewProps, index_CreativeMedia as CreativeMedia, index_InstagramExplorePreview as InstagramExplorePreview, index_InstagramFeedCarousel as InstagramFeedCarousel, index_InstagramFeedPreview as InstagramFeedPreview, index_MetaFeedCarousel as MetaFeedCarousel, index_MetaFeedPreview as MetaFeedPreview, index_MetaInstreamPreview as MetaInstreamPreview, index_MetaMessengerPreview as MetaMessengerPreview, index_MetaReelPreview as MetaReelPreview, index_MetaRightColumnPreview as MetaRightColumnPreview, index_MetaSearchPreview as MetaSearchPreview, index_MetaStoryPreview as MetaStoryPreview, index_PLACEMENT_CONFIGS as PLACEMENT_CONFIGS, type index_PlacementPreview as PlacementPreview, type index_PreviewAdData as PreviewAdData, type index_PreviewConfiguration as PreviewConfiguration, type index_PreviewDevice as PreviewDevice, type index_PreviewPlacement as PreviewPlacement, type index_PreviewPlatform as PreviewPlatform };
2493
+ }
2494
+
2495
+ export { AccordionCompound as Accordion, type AccordionProps, type AccordionSectionProps, AllocationSparkbar, type AllocationSparkbarProps, AppScroll, Badge, type BadgeProps, type BadgeTone, BrandLogoTile, type BrandLogoTileProps, type BrandLogoTileSize, BulkActionBar, type BulkActionBarProps, Button, ButtonGroup, type ButtonGroupProps, type ButtonProps, type ButtonShape, type ButtonSize, type ButtonVariant, type CalcLayout, type CalcPrefill, CalculatorShell, type CalculatorShellProps, CalculatorShellV2, type CalculatorShellV2Props, Card, Checkbox, type CheckboxProps, ChipNav, type ChipNavItem, Choropleth, type ChoroplethProps, CodeBlock, type CodeBlockProps, CompletionRing, type CompletionRingProps, CopyField, type CopyFieldProps, type Crumb, DataGrid, type DataGridColumn, DataGridColumnOptionsMenu, DataGridDragOverlay, type DataGridDrawerPanelProps, DataGridDropIndicator, type DataGridIcon, type DataGridProps, type DataGridRowBase, type DataGridSortState, DataGridToolbar, type DataGridToolbarProps, type DataGridToolbarRenderProps, DetailSection, DeviceFrame, type DeviceFrameProps, DragHandle, DropdownButton, type DropdownButtonItem, type DropdownButtonProps, DropdownMenu, DropdownMenuCheckboxItem, type DropdownMenuCheckboxItemProps, DropdownMenuContent, type DropdownMenuContentProps, DropdownMenuGroup, DropdownMenuItem, type DropdownMenuItemProps, DropdownMenuLabel, type DropdownMenuLabelProps, type DropdownMenuProps, DropdownMenuSeparator, DropdownMenuTrigger, type DropdownMenuTriggerProps, type EditingCell, EmptyPlaceholder, EmptyState, type EmptyStateProps, FOLDER_COLOR_KEYS, FileDropZone, FilePreviewGrid, FilePreviewItem, FileThumbnail, FileUploadButton, FilterBar, type FilterBarCountProps, type FilterBarProps, type FilterBarSearchProps, FilterDropdown, type FilterDropdownProps, type FilterOption, FloatingDrawer, type FloatingDrawerProps, FloatingStatusBar, type FloatingStatusBarProps, type FloatingStatusTone, FolderCard, type FolderCardProps, type FolderColorKey, type FolderTreeNode, FolderTreePicker, type FolderTreePickerProps, FrameStack, type FrameStackProps, HEADER_HEIGHT, HeroFormCardCompound as HeroFormCard, type HeroFormCardAdvancedProps, type HeroFormCardBannerProps, type HeroFormCardFieldProps, type HeroFormCardProps, type HeroFormCardSectionProps, IconTile, IdentityLabel, IdentityValue, Input, type InputProps, type InputSize, Kbd, type KbdProps, ListItem, MarkdownCode, MarkdownRenderer, type MarkdownRendererProps, MenuButton, type MenuButtonEntry, type MenuButtonItem, type MenuButtonProps, type MenuButtonSeparator, index as MetaPreviews, MetricCard, type MetricCardProps, type MetricCardTone, MicrosoftLogo, type MicrosoftLogoProps, Modal, OptionTile, OptionTileGroup, type OptionTileGroupProps, type OptionTileProps, PLACEMENT_CONFIGS, PageHeaderHost, PageHeaderSlotProvider, PageHero, type PageHeroProps, PageShell, Pagination, type PaginationProps, type PendingFile, PillButton, type PillButtonProps, type PlacementPreview, type PreviewAdData, type PreviewConfiguration, type PreviewDevice, type PreviewPlacement, type PreviewPlatform, PS as ProfileSection, type ProfileSectionProps, ProgressBar, type ProgressBarProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, RangeSlider, type RangeSliderProps, ResizableHandle, type ResizableHandleProps, ResizablePane, type ResizablePaneProps, SECTION_SCROLL_OFFSET, SearchBar, type SearchBarProps, SectionLabel, SegmentedPill, type SegmentedPillItem, type SegmentedPillProps, Shell, type ShellProps, ShellStat, type ShellStatProps, type ShellStatTone, type ShellSubCardProps, type ShellTrayBodyProps, type ShellTrayFooterProps, type ShellTrayHeaderProps, type ShellTrayProps, Slider, type SliderProps, SortableItem, SortableList, SortableTable, type Column as SortableTableColumn, type SortableTableProps, StatRow, type StatRowProps, type StatRowStep, StatsGrid, type StatsGridProps, StepLoader, type StepLoaderProps, type StepLoaderStep, type Tab, Tabs, type TabsProps, TagChipInput, type TagChipInputProps, TagRow, TextInput, Textarea, TextareaInput, type TextareaProps, Toaster, TokenBadge, type TokenBadgeProps, type UploadResult, type UseFileUploadOptions, cn, folderColorVar, formatCurrency, formatNumber, formatPercent, formatRatio, useFileUpload };