@lovett/ui 0.0.3 → 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.
- package/dist/index.d.ts +2495 -0
- package/dist/index.js +14038 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +562 -0
- package/dist/tokens.css +579 -0
- package/package.json +26 -16
- package/src/allocation-sparkbar.tsx +90 -0
- package/src/data-grid/index.ts +1 -0
- package/src/data-grid/table-elements.tsx +6 -7
- package/src/data-grid/toolbar.tsx +44 -0
- package/src/floating-status-bar.tsx +112 -0
- package/src/index.ts +13 -0
- package/src/microsoft-logo.tsx +33 -0
- package/src/token-badge.tsx +92 -0
package/dist/index.d.ts
ADDED
|
@@ -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 };
|