@vibeflow-tools/prototyping 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # @vibeflow-tools/prototyping
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add `@vibeflow-tools/prototyping` React package for in-app variant switching. Provides `useVariant`, `useActiveVariant`, `VariantProvider`, `PageVariantSwitcher`, `VariantSwitcher`, and `VariantDevToolbar` components with URL param and localStorage persistence, keyboard shortcuts (Alt+H / Ctrl+Shift+V, configurable), overlay integration (MutationObserver + polling for bookmarklet injection), and zero runtime dependencies.
8
+
9
+ ### Patch Changes
10
+
11
+ - c525ae7: Make `VariantSwitcher` draggable — same hold-to-drag behaviour as the vibeflow corner trigger. Hold the indicator dot for 300ms, then drag to reposition anywhere on the viewport. Position is persisted to `localStorage` per scope name (`vf-variant-pos-<name>`), so it survives page reloads. Cursor changes to `grab` on hold and `grabbing` during drag for clear affordance.
12
+ - Add production-ready README with full API reference, quick start, persistence docs, keyboard shortcuts, and Vibeflow overlay integration guide.
package/README.md ADDED
@@ -0,0 +1,341 @@
1
+ # @vibeflow-tools/prototyping
2
+
3
+ > **In-app variant switching for React** — page-level and component-level prototyping with URL persistence and zero runtime dependencies.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@vibeflow-tools/prototyping)](https://www.npmjs.com/package/@vibeflow-tools/prototyping)
6
+ [![website](https://img.shields.io/badge/website-vibeflow.tools-2563eb)](https://www.vibeflow.tools/ui-prototyping.html)
7
+
8
+ ```bash
9
+ npm install @vibeflow-tools/prototyping
10
+ ```
11
+
12
+ ---
13
+
14
+ ## Built for Coding Agents
15
+
16
+ `ui-prototyping` was built to enable coding agents to propose UI variants directly in your running app — without screenshots, back-and-forth prompts, or external design tools.
17
+
18
+ An agent can define multiple named variants (layouts, colour schemes, component densities) and register them with a few lines of code. You switch between them with a click, see the result immediately in your real app, and tell the agent which one to keep. **No Figma. No mockups. No rebuild cycle.**
19
+
20
+ This makes `ui-prototyping` one of the most efficient ways for developers to give and receive UI feedback when working with AI coding assistants.
21
+
22
+ ---
23
+
24
+ ## Why It Matters
25
+
26
+ Designing and reviewing UI variations is slow when you have to change code, rebuild, and refresh every time you want to see a different state. `ui-prototyping` brings the switch directly into your running app:
27
+
28
+ - **Click to switch** — numbered dot on each component, floating toolbar for all scopes at once
29
+ - **URL-persisted** — share a URL and your reviewer sees the exact variant you're showing them
30
+ - **TypeScript-first** — variant keys are narrowed to their literal types, config objects are fully typed
31
+ - **Zero runtime deps** — peer-deps only (`react`, `react-dom`); nothing extra in your bundle
32
+ - **Vibeflow overlay integration** — when the Vibeflow overlay is detected, the toolbar is accessible via the right-click context menu ("Prototyping" option)
33
+
34
+ ---
35
+
36
+ ## Quick Start
37
+
38
+ ```tsx
39
+ import { VariantProvider, useVariant, PageVariantSwitcher } from '@vibeflow-tools/prototyping'
40
+
41
+ // 1. Define your variants
42
+ const heroVariants = {
43
+ default: {},
44
+ compact: { spacing: 'tight', titleSize: 'md' },
45
+ expanded: { spacing: 'loose', titleSize: 'xl' },
46
+ }
47
+
48
+ // 2. Read the active variant
49
+ function HeroSection() {
50
+ const v = useVariant('Hero', heroVariants)
51
+ return (
52
+ <section className={v.spacing === 'tight' ? 'py-4' : 'py-12'}>
53
+ <PageVariantSwitcher name="Hero" variants={heroVariants} />
54
+ <h1 className={v.titleSize === 'xl' ? 'text-4xl' : 'text-2xl'}>Welcome</h1>
55
+ </section>
56
+ )
57
+ }
58
+
59
+ // 3. Wrap your app
60
+ function App() {
61
+ return (
62
+ <VariantProvider>
63
+ <HeroSection />
64
+ </VariantProvider>
65
+ )
66
+ }
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Installation
72
+
73
+ ```bash
74
+ npm install @vibeflow-tools/prototyping
75
+ # or
76
+ pnpm add @vibeflow-tools/prototyping
77
+ # or
78
+ yarn add @vibeflow-tools/prototyping
79
+ ```
80
+
81
+ **Requirements:** React 18+, Node.js 18+.
82
+
83
+ ---
84
+
85
+ ## Core API
86
+
87
+ ### `<VariantProvider>`
88
+
89
+ Wrap your app (or a subtree) with `VariantProvider` to enable the variant switching system. All hooks and switcher components below it share state via this provider.
90
+
91
+ ```tsx
92
+ <VariantProvider>
93
+ <App />
94
+ </VariantProvider>
95
+ ```
96
+
97
+ #### Props
98
+
99
+ | Prop | Type | Default | Description |
100
+ |------|------|---------|-------------|
101
+ | `mode` | `"dev" \| "always"` | `"dev"` | `"dev"` hides switcher UI in production (`NODE_ENV === "production"`). `"always"` always shows it — useful for A/B testing demos. |
102
+ | `defaultVisible` | `boolean` | `true` | Initial UI visibility. Persisted in `localStorage` so users can hide/show across sessions. |
103
+ | `shortcuts` | `KeyboardShortcut[] \| false` | default shortcuts | Custom keyboard shortcuts for toggling the variant UI. Pass `false` to disable. |
104
+
105
+ ---
106
+
107
+ ### `useVariant(name, variants)`
108
+
109
+ Core hook. Registers the scope, resolves the active variant from URL → localStorage → default, and returns the matching config object.
110
+
111
+ ```tsx
112
+ const variants = {
113
+ default: {},
114
+ compact: { compact: true, density: 'low' },
115
+ detailed: { showMeta: true, showComments: true },
116
+ }
117
+
118
+ function TaskCard() {
119
+ const v = useVariant('TaskCard', variants)
120
+ // v is typed as typeof variants[keyof typeof variants]
121
+ return <div className={v.compact ? 'p-2' : 'p-4'}>…</div>
122
+ }
123
+ ```
124
+
125
+ The first key is always the default variant (applied when no URL param or storage entry is present).
126
+
127
+ ---
128
+
129
+ ### `<VariantSwitcher>`
130
+
131
+ A subtle indicator dot positioned on the edge of the parent element. Clicking it expands a numbered-dots picker.
132
+
133
+ ```tsx
134
+ function TaskCard() {
135
+ const v = useVariant('TaskCard', variants)
136
+ return (
137
+ <div style={{ position: 'relative' }}>
138
+ <VariantSwitcher name="TaskCard" variants={variants} />
139
+ {v.compact ? <CompactView /> : <FullView />}
140
+ </div>
141
+ )
142
+ }
143
+ ```
144
+
145
+ **The parent must have `position: relative` for correct placement.**
146
+
147
+ Deduplicates per scope — only the first `VariantSwitcher` for a given scope renders, even if the component is used multiple times on the page.
148
+
149
+ #### Props
150
+
151
+ | Prop | Type | Default | Description |
152
+ |------|------|---------|-------------|
153
+ | `name` | `string` | required | Scope name — must match the `useVariant` call |
154
+ | `variants` | `Record<string, object>` | required | Same variant definitions passed to `useVariant` |
155
+ | `position` | `"right" \| "left"` | `"right"` | Which side the dot appears on |
156
+
157
+ ---
158
+
159
+ ### `<PageVariantSwitcher>`
160
+
161
+ A dark segmented control fixed to the top-left of the viewport — ideal for page-level layout or theme switching.
162
+
163
+ ```tsx
164
+ function DashboardPage() {
165
+ const layout = useVariant('DashboardLayout', layoutVariants)
166
+ return (
167
+ <>
168
+ <PageVariantSwitcher name="DashboardLayout" variants={layoutVariants} />
169
+ <main className={layout.sidebar ? 'with-sidebar' : ''}>…</main>
170
+ </>
171
+ )
172
+ }
173
+ ```
174
+
175
+ #### Props
176
+
177
+ | Prop | Type | Default | Description |
178
+ |------|------|---------|-------------|
179
+ | `name` | `string` | required | Scope name — must match the `useVariant` call |
180
+ | `variants` | `Record<string, object>` | required | Same variant definitions passed to `useVariant` |
181
+
182
+ ---
183
+
184
+ ### `<VariantDevToolbar>`
185
+
186
+ An optional floating toolbar that shows **all registered variant scopes** at once in a single panel. Use this when you have many scopes and want a central control panel.
187
+
188
+ ```tsx
189
+ function App() {
190
+ return (
191
+ <VariantProvider>
192
+ <VariantDevToolbar /> {/* ← add once near the root */}
193
+ <MainContent />
194
+ </VariantProvider>
195
+ )
196
+ }
197
+ ```
198
+
199
+ The toolbar button (vibeflow icon) appears bottom-right of the page. When the Vibeflow overlay is detected, the button is hidden — access the toolbar instead via the overlay's right-click context menu.
200
+
201
+ **Keyboard shortcuts:**
202
+ - `Alt+H` — toggle all switchers on/off
203
+ - `Ctrl+Shift+V` — toggle all switchers on/off
204
+ - `Escape` — close the toolbar panel
205
+
206
+ ---
207
+
208
+ ### `registerVariant(name, variants)`
209
+
210
+ Module-level registration. Use this to centralise all variant definitions in one file instead of re-passing them to every component.
211
+
212
+ ```ts
213
+ // variants.ts
214
+ import { registerVariant } from '@vibeflow-tools/prototyping'
215
+
216
+ registerVariant('TaskCard', {
217
+ default: {},
218
+ minimal: { compact: true },
219
+ detailed: { showMeta: true, showComments: true },
220
+ })
221
+
222
+ registerVariant('KanbanBoard', {
223
+ default: {},
224
+ dense: { rowHeight: 'sm' },
225
+ })
226
+ ```
227
+
228
+ ```tsx
229
+ // TaskCard.tsx
230
+ function TaskCard() {
231
+ // Pass an empty object — registered variants are merged automatically
232
+ const v = useVariant('TaskCard', {})
233
+ return <div className={v.compact ? 'p-2' : 'p-4'}>…</div>
234
+ }
235
+ ```
236
+
237
+ Inline variants always win over registered ones when both are provided.
238
+
239
+ ---
240
+
241
+ ## Persistence
242
+
243
+ Active variants are persisted in two places:
244
+
245
+ | Layer | Storage | Scope |
246
+ |-------|---------|-------|
247
+ | URL param | `?vf-<name>=<variant>` | Shareable — copy the URL to share a specific variant |
248
+ | localStorage | `vf-<name>` | Session — survives page reloads in the same browser |
249
+
250
+ URL takes precedence over localStorage.
251
+
252
+ ---
253
+
254
+ ## Keyboard Shortcuts
255
+
256
+ | Shortcut | Action |
257
+ |----------|--------|
258
+ | `Alt+H` | Toggle all variant switchers on/off |
259
+ | `Ctrl+Shift+V` | Toggle all variant switchers on/off |
260
+
261
+ Both shortcuts call `toggleUiVisible()` on the `VariantProvider`. To open the `VariantDevToolbar` panel, click the vibeflow icon button in the bottom-right corner.
262
+
263
+ Customise or disable shortcuts via the `shortcuts` prop on `VariantProvider`:
264
+
265
+ ```tsx
266
+ // Custom shortcuts
267
+ <VariantProvider shortcuts={[{ key: 'v', alt: true }]}>
268
+ <App />
269
+ </VariantProvider>
270
+
271
+ // Disable all shortcuts
272
+ <VariantProvider shortcuts={false}>
273
+ <App />
274
+ </VariantProvider>
275
+ ```
276
+
277
+ ---
278
+
279
+ ## Vibeflow Overlay Integration
280
+
281
+ When the [Vibeflow](https://vibeflow.tools) overlay is injected into the page, `VariantDevToolbar` automatically hides its standalone vibeflow icon button and registers itself with the overlay. The toolbar is then accessible via the overlay's right-click context menu under **"Prototyping"** — both on the bottom-right trigger and when right-clicking any element on the page.
282
+
283
+ No configuration needed — detection is automatic.
284
+
285
+ > **Tip for AI coding agents:** Combine `ui-prototyping` with the [Vibeflow overlay](https://vibeflow.tools) so variants are instantly accessible via right-click anywhere on the page. The agent defines the variants; you switch and approve. See the [ui-prototyping webpage](https://www.vibeflow.tools/ui-prototyping.html) for a live demo.
286
+
287
+ ---
288
+
289
+ ## Advanced: Power User Utilities
290
+
291
+ The following URL/localStorage utilities are exported for cases where you need manual control:
292
+
293
+ ```ts
294
+ import {
295
+ readVariantFromUrl,
296
+ writeVariantToUrl,
297
+ removeVariantFromUrl,
298
+ readVariantFromStorage,
299
+ writeVariantToStorage,
300
+ removeVariantFromStorage,
301
+ resolveActiveVariant,
302
+ readUiVisibleFromStorage,
303
+ writeUiVisibleToStorage,
304
+ } from '@vibeflow-tools/prototyping'
305
+ ```
306
+
307
+ ---
308
+
309
+ ## TypeScript
310
+
311
+ All exports are fully typed. The `useVariant` hook preserves key-literal types so your IDE autocompletes variant config properties:
312
+
313
+ ```tsx
314
+ const variants = {
315
+ default: {},
316
+ compact: { compact: true as const, rows: 3 as const },
317
+ }
318
+
319
+ function MyComponent() {
320
+ const v = useVariant('MyComponent', variants)
321
+ // v.compact is typed as `true | undefined`
322
+ // v.rows is typed as `3 | undefined`
323
+ }
324
+ ```
325
+
326
+ ---
327
+
328
+ ## Contributing
329
+
330
+ ```bash
331
+ pnpm install
332
+ pnpm --filter @vibeflow-tools/prototyping run build
333
+ pnpm --filter @vibeflow-tools/prototyping run test
334
+ pnpm --filter @vibeflow-tools/prototyping run test:coverage
335
+ ```
336
+
337
+ ---
338
+
339
+ ## License
340
+
341
+ [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) — see [NOTICE](https://github.com/zorcec/vibeflow/blob/main/NOTICE) for third-party attributions.
@@ -0,0 +1,292 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+
5
+ /** Default keyboard shortcuts for toggling the variant UI. */
6
+ interface KeyboardShortcut {
7
+ /** The key value (e.g. "h", "V"). Case-sensitive for Ctrl+Shift combos. */
8
+ key: string;
9
+ /** Whether Alt must be held. */
10
+ alt?: boolean;
11
+ /** Whether Ctrl must be held. */
12
+ ctrl?: boolean;
13
+ /** Whether Shift must be held. */
14
+ shift?: boolean;
15
+ /** Whether Meta (Cmd/Win) must be held. */
16
+ meta?: boolean;
17
+ }
18
+ interface KeyboardShortcutsOptions {
19
+ /** Called when a toggle shortcut is pressed. */
20
+ onToggleUi: () => void;
21
+ /**
22
+ * Custom shortcut definitions. Defaults to [Alt+H, Ctrl+Shift+V].
23
+ * Set to `false` to disable all keyboard shortcuts.
24
+ */
25
+ shortcuts?: KeyboardShortcut[] | false;
26
+ }
27
+ /**
28
+ * Registers global keyboard shortcuts for the prototyping system.
29
+ *
30
+ * | Default Shortcut | Action |
31
+ * |------------------|----------------------|
32
+ * | Alt + H | Toggle all switchers |
33
+ * | Ctrl+Shift+V | Toggle all switchers |
34
+ *
35
+ * Shortcuts can be customized via the `shortcuts` option, or disabled
36
+ * entirely by passing `false`.
37
+ */
38
+ declare function useKeyboardShortcuts({ onToggleUi, shortcuts, }: KeyboardShortcutsOptions): void;
39
+
40
+ /**
41
+ * Core TypeScript types for @vibeflow-tools/prototyping.
42
+ *
43
+ * VariantDefinitions maps variant names to arbitrary config objects.
44
+ * The generic V type preserves key-literal types for TypeScript consumers.
45
+ */
46
+
47
+ /** A map of variant name → arbitrary config object. */
48
+ type VariantDefinitions<V extends Record<string, Record<string, unknown>>> = V;
49
+ /** The mode controls when variant switcher UI is visible. */
50
+ type VariantMode = "dev" | "always";
51
+ /** Internal state stored per named scope. */
52
+ interface VariantState {
53
+ /** Currently active variant name. */
54
+ activeVariant: string;
55
+ /** All registered variant names for this scope. */
56
+ variantNames: string[];
57
+ }
58
+ /** The shape of the context value exposed by VariantProvider. */
59
+ interface VariantContextValue {
60
+ /** Get the active variant name for a given scope. */
61
+ getActiveVariant: (name: string) => string;
62
+ /** Set the active variant for a scope. */
63
+ setActiveVariant: (name: string, variant: string) => void;
64
+ /** Register a scope with its variant names (called by useVariant / VariantSwitcher). */
65
+ registerScope: (name: string, variantNames: string[]) => void;
66
+ /**
67
+ * Register a VariantSwitcher instance for a scope.
68
+ * Returns true if this is the first instance (should render), false if duplicate (should skip).
69
+ */
70
+ registerSwitcher: (name: string) => boolean;
71
+ /** Unregister a VariantSwitcher instance (called on unmount). */
72
+ unregisterSwitcher: (name: string) => void;
73
+ /** All registered scopes and their states. */
74
+ scopes: Record<string, VariantState>;
75
+ /** Whether switcher UI should be visible. */
76
+ uiVisible: boolean;
77
+ /** Toggle switcher UI visibility. */
78
+ toggleUiVisible: () => void;
79
+ /** The current mode ("dev" | "always"). */
80
+ mode: VariantMode;
81
+ }
82
+ /** Props for VariantProvider. */
83
+ interface VariantProviderProps {
84
+ children: React.ReactNode;
85
+ /**
86
+ * "dev" (default) — switcher UI is hidden unless NODE_ENV !== "production".
87
+ * "always" — switcher UI is always visible (useful for A/B testing / user-facing demos).
88
+ */
89
+ mode?: VariantMode;
90
+ /**
91
+ * Initial UI visibility state.
92
+ * Defaults to true when mode allows it.
93
+ */
94
+ defaultVisible?: boolean;
95
+ /**
96
+ * Custom keyboard shortcuts for toggling the variant UI.
97
+ * Defaults to [Alt+H, Ctrl+Shift+V]. Pass `false` to disable shortcuts.
98
+ */
99
+ shortcuts?: KeyboardShortcut[] | false;
100
+ }
101
+ /** Props shared by switcher components. */
102
+ interface SwitcherProps {
103
+ /** Scope name — must match the first argument of useVariant. */
104
+ name: string;
105
+ /** Variant definitions object — same as passed to useVariant. */
106
+ variants: Record<string, Record<string, unknown>>;
107
+ /** Preferred side for floating placement. Default: "right". */
108
+ position?: "right" | "left";
109
+ }
110
+
111
+ declare const VariantContext: react.Context<VariantContextValue | null>;
112
+ /** Access the variant context. Throws if used outside VariantProvider. */
113
+ declare function useVariantContext(): VariantContextValue;
114
+ /**
115
+ * VariantProvider wraps your app (or a subtree) and provides the variant
116
+ * switching system. All useVariant hooks and switcher components below it
117
+ * share state via this provider.
118
+ *
119
+ * @example
120
+ * <VariantProvider>
121
+ * <App />
122
+ * </VariantProvider>
123
+ *
124
+ * @example
125
+ * // Always visible — for A/B testing or user-facing demos
126
+ * <VariantProvider mode="always">
127
+ * <App />
128
+ * </VariantProvider>
129
+ */
130
+ declare function VariantProvider({ children, mode, defaultVisible, shortcuts, }: VariantProviderProps): ReactNode;
131
+
132
+ /**
133
+ * Core hook for reading the active variant config.
134
+ *
135
+ * Registers the scope with the VariantProvider, resolves the active variant
136
+ * from URL → localStorage → default, and returns the corresponding config.
137
+ *
138
+ * @param name - Unique scope name (e.g. "TaskCard", "KanbanBoard")
139
+ * @param variants - Variant definitions object; first key is the default
140
+ * @returns The config object for the active variant
141
+ *
142
+ * @example
143
+ * const variants = {
144
+ * default: {},
145
+ * minimal: { compact: true },
146
+ * detailed: { showMeta: true, showComments: true },
147
+ * }
148
+ *
149
+ * function TaskCard() {
150
+ * const variant = useVariant('TaskCard', variants)
151
+ * return <div className={variant.compact ? 'compact' : ''}>…</div>
152
+ * }
153
+ */
154
+ declare function useVariant<V extends Record<string, Record<string, unknown>>>(name: string, variants: V): V[keyof V];
155
+
156
+ /**
157
+ * Resolves the active variant key for a scope.
158
+ *
159
+ * Checks context first, then falls back to URL → localStorage → default.
160
+ * Used by useVariant, VariantSwitcher, and PageVariantSwitcher to avoid
161
+ * duplicating the same resolution logic.
162
+ */
163
+ declare function useActiveVariant(name: string, variantKeys: string[]): string;
164
+
165
+ interface PageVariantSwitcherProps {
166
+ /** Scope name — must match the first argument of useVariant. */
167
+ name: string;
168
+ /** Variant definitions — same as passed to useVariant. */
169
+ variants: Record<string, Record<string, unknown>>;
170
+ }
171
+ /**
172
+ * Dark segmented bar floating top-left of the page.
173
+ * Renders automatically via VariantProvider for page-level variant switching.
174
+ *
175
+ * Place this component anywhere inside VariantProvider — typically at the
176
+ * top of the page component alongside useVariant.
177
+ *
178
+ * @example
179
+ * function App() {
180
+ * const layout = useVariant('Layout', layoutVariants)
181
+ * return (
182
+ * <>
183
+ * <PageVariantSwitcher name="Layout" variants={layoutVariants} />
184
+ * <main>…</main>
185
+ * </>
186
+ * )
187
+ * }
188
+ */
189
+ declare function PageVariantSwitcher({ name, variants, }: PageVariantSwitcherProps): react_jsx_runtime.JSX.Element | null;
190
+
191
+ /**
192
+ * Component variant switcher with a subtle indicator dot.
193
+ *
194
+ * Shows a small, non-intrusive dot on the right (or left) side of the parent.
195
+ * Clicking the dot expands the full numbered-dots picker.
196
+ * Clicking outside or pressing Escape collapses it back.
197
+ *
198
+ * The dot is draggable — hold for 300ms, then drag to reposition anywhere on
199
+ * the viewport. The new position is persisted to localStorage per scope name.
200
+ *
201
+ * Deduplicates per scope — only the first VariantSwitcher for a given
202
+ * scope renders. Multiple components using the same scope share one switcher.
203
+ *
204
+ * The parent element must have `position: relative` for correct placement.
205
+ *
206
+ * @example
207
+ * function TaskCard({ task }) {
208
+ * const variant = useVariant('TaskCard', taskCardVariants)
209
+ * return (
210
+ * <div style={{ position: 'relative' }}>
211
+ * <VariantSwitcher name="TaskCard" variants={taskCardVariants} />
212
+ * {variant.compact ? <CompactView /> : <FullView />}
213
+ * </div>
214
+ * )
215
+ * }
216
+ */
217
+ declare function VariantSwitcher({ name, variants, position, }: SwitcherProps): react_jsx_runtime.JSX.Element | null;
218
+
219
+ /**
220
+ * Optional floating toolbar that shows all registered variant scopes.
221
+ * Toggled via Ctrl+Shift+V keyboard shortcut or programmatically.
222
+ *
223
+ * **Vibeflow overlay integration:** When the Vibeflow overlay is detected,
224
+ * the standalone vibeflow icon button is hidden. Instead, the toolbar is accessible
225
+ * via the overlay's right-click context menu ("Prototyping" option).
226
+ *
227
+ * Place this once near the root of your app inside VariantProvider.
228
+ *
229
+ * @example
230
+ * function App() {
231
+ * return (
232
+ * <VariantProvider>
233
+ * <VariantDevToolbar />
234
+ * <MainContent />
235
+ * </VariantProvider>
236
+ * )
237
+ * }
238
+ */
239
+ declare function VariantDevToolbar(): react_jsx_runtime.JSX.Element | null;
240
+
241
+ /**
242
+ * Global variant registry.
243
+ *
244
+ * Optional module-level registration of variant definitions so they don't
245
+ * have to be re-passed to every useVariant call in deeply nested trees.
246
+ * Registered variants are merged with inline variant definitions — inline
247
+ * always wins.
248
+ */
249
+ type VariantDefs = Record<string, Record<string, unknown>>;
250
+ /**
251
+ * Register a variant definition at module level.
252
+ * Useful when you want to centralise all variant registrations in one file.
253
+ *
254
+ * @example
255
+ * registerVariant('TaskCard', {
256
+ * default: {},
257
+ * minimal: { compact: true },
258
+ * detailed: { showMeta: true },
259
+ * })
260
+ */
261
+ declare function registerVariant(name: string, variants: VariantDefs): void;
262
+ /**
263
+ * Retrieve previously registered variant definitions for a scope.
264
+ * Returns undefined if the scope was never registered.
265
+ */
266
+ declare function getRegisteredVariant(name: string): VariantDefs | undefined;
267
+ /** Clear all registrations. Primarily used in tests. */
268
+ declare function clearVariantRegistry(): void;
269
+
270
+ /** Read the active variant for a scope from the current URL search params. */
271
+ declare function readVariantFromUrl(name: string): string | null;
272
+ /** Write the active variant for a scope into the URL (pushState — no reload). */
273
+ declare function writeVariantToUrl(name: string, variant: string): void;
274
+ /** Remove a scope's variant from the URL. */
275
+ declare function removeVariantFromUrl(name: string): void;
276
+ /** Read the active variant for a scope from localStorage. */
277
+ declare function readVariantFromStorage(name: string): string | null;
278
+ /** Write the active variant for a scope to localStorage. */
279
+ declare function writeVariantToStorage(name: string, variant: string): void;
280
+ /** Remove a scope's variant from localStorage. */
281
+ declare function removeVariantFromStorage(name: string): void;
282
+ /** Persist the UI visibility flag. */
283
+ declare function writeUiVisibleToStorage(visible: boolean): void;
284
+ /** Read the persisted UI visibility flag. Returns null when not set. */
285
+ declare function readUiVisibleFromStorage(): boolean | null;
286
+ /**
287
+ * Resolve the active variant for a scope.
288
+ * Priority: URL param → localStorage → provided default key.
289
+ */
290
+ declare function resolveActiveVariant(name: string, variantKeys: string[], defaultKey: string): string;
291
+
292
+ export { type KeyboardShortcut, PageVariantSwitcher, type SwitcherProps, VariantContext, type VariantContextValue, type VariantDefinitions, VariantDevToolbar, type VariantMode, VariantProvider, type VariantProviderProps, type VariantState, VariantSwitcher, clearVariantRegistry, getRegisteredVariant, readUiVisibleFromStorage, readVariantFromStorage, readVariantFromUrl, registerVariant, removeVariantFromStorage, removeVariantFromUrl, resolveActiveVariant, useActiveVariant, useKeyboardShortcuts, useVariant, useVariantContext, writeUiVisibleToStorage, writeVariantToStorage, writeVariantToUrl };