uidex 0.2.4 → 0.4.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.
Files changed (65) hide show
  1. package/README.md +253 -353
  2. package/dist/cli/cli.cjs +3324 -0
  3. package/dist/cli/cli.cjs.map +1 -0
  4. package/dist/cloud/index.cjs +169 -0
  5. package/dist/cloud/index.cjs.map +1 -0
  6. package/dist/cloud/index.js +140 -0
  7. package/dist/cloud/index.js.map +1 -0
  8. package/dist/headless/index.cjs +4143 -0
  9. package/dist/headless/index.cjs.map +1 -0
  10. package/dist/headless/index.d.cts +220 -0
  11. package/dist/headless/index.d.ts +220 -0
  12. package/dist/headless/index.js +4130 -0
  13. package/dist/headless/index.js.map +1 -0
  14. package/dist/index.cjs +8704 -9883
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +968 -146
  17. package/dist/index.d.ts +968 -146
  18. package/dist/index.js +8327 -9492
  19. package/dist/index.js.map +1 -1
  20. package/dist/playwright/index.cjs +164 -24
  21. package/dist/playwright/index.cjs.map +1 -1
  22. package/dist/playwright/index.d.cts +30 -53
  23. package/dist/playwright/index.d.ts +30 -53
  24. package/dist/playwright/index.js +148 -21
  25. package/dist/playwright/index.js.map +1 -1
  26. package/dist/playwright/reporter.cjs +62 -28
  27. package/dist/playwright/reporter.cjs.map +1 -1
  28. package/dist/playwright/reporter.d.cts +24 -12
  29. package/dist/playwright/reporter.d.ts +24 -12
  30. package/dist/playwright/reporter.js +62 -28
  31. package/dist/playwright/reporter.js.map +1 -1
  32. package/dist/react/index.cjs +8706 -9883
  33. package/dist/react/index.cjs.map +1 -1
  34. package/dist/react/index.d.cts +720 -146
  35. package/dist/react/index.d.ts +720 -146
  36. package/dist/react/index.js +8518 -9629
  37. package/dist/react/index.js.map +1 -1
  38. package/dist/scan/index.cjs +3360 -0
  39. package/dist/scan/index.cjs.map +1 -0
  40. package/dist/scan/index.d.cts +378 -0
  41. package/dist/scan/index.d.ts +378 -0
  42. package/dist/scan/index.js +3303 -0
  43. package/dist/scan/index.js.map +1 -0
  44. package/package.json +67 -60
  45. package/templates/claude/audit.md +43 -0
  46. package/templates/claude/rules.md +227 -0
  47. package/claude/audit-command.md +0 -46
  48. package/claude/rules.md +0 -167
  49. package/dist/api/index.cjs +0 -254
  50. package/dist/api/index.cjs.map +0 -1
  51. package/dist/api/index.d.cts +0 -236
  52. package/dist/api/index.d.ts +0 -236
  53. package/dist/api/index.js +0 -226
  54. package/dist/api/index.js.map +0 -1
  55. package/dist/core/index.cjs +0 -11045
  56. package/dist/core/index.cjs.map +0 -1
  57. package/dist/core/index.d.cts +0 -424
  58. package/dist/core/index.d.ts +0 -424
  59. package/dist/core/index.global.js +0 -66516
  60. package/dist/core/index.global.js.map +0 -1
  61. package/dist/core/index.js +0 -10995
  62. package/dist/core/index.js.map +0 -1
  63. package/dist/core/style.css +0 -1529
  64. package/dist/scripts/cli.cjs +0 -3904
  65. package/uidex.schema.json +0 -93
@@ -1,78 +1,227 @@
1
- type BorderStyle = 'solid' | 'dashed' | 'dotted';
2
- type LabelPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
3
- type ButtonPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
4
- interface UidexDefaults {
5
- color?: string;
6
- borderStyle?: BorderStyle;
7
- borderWidth?: number;
8
- }
9
- interface UidexConfig {
10
- defaults?: UidexDefaults;
11
- colors?: Record<string, string>;
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode, ComponentType, ReactElement } from 'react';
3
+ import { StoreApi } from 'zustand/vanilla';
4
+
5
+ declare const ENTITY_KINDS: readonly ["route", "page", "feature", "widget", "region", "element", "primitive", "flow"];
6
+ type EntityKind = (typeof ENTITY_KINDS)[number];
7
+ type Scope = string;
8
+ interface Location {
9
+ file: string;
10
+ line?: number;
11
+ column?: number;
12
12
  }
13
- type UidexKind = 'block' | 'component' | 'primitive';
14
- interface UidexLocation {
15
- filePath: string;
16
- line: number;
17
- kind: UidexKind;
18
- doc?: string;
19
- scopes?: string[];
13
+ interface EntityRef {
14
+ kind: EntityKind;
15
+ id: string;
20
16
  }
21
- type UidexMap = Record<string, UidexLocation[]>;
22
- interface PrimitiveEntry {
23
- name: string;
24
- filePath: string;
25
- scope: string;
26
- composes: string[];
27
- usedBy: string[];
28
- kind: 'primitive';
29
- }
30
- interface UidexPage {
31
- dir: string;
32
- content: string;
17
+ interface Metadata {
18
+ name?: string;
33
19
  description?: string;
34
- componentIds: string[];
35
- rootId?: string;
20
+ acceptance?: string[];
21
+ notes?: string;
22
+ composes?: EntityRef[];
23
+ flows?: readonly string[];
24
+ features?: string[];
25
+ widgets?: string[];
36
26
  }
37
- interface UidexFeature {
38
- dir: string;
39
- content: string;
40
- description?: string;
41
- componentIds: string[];
27
+ interface EntityWithMetaBase {
28
+ id: string;
29
+ loc?: Location;
30
+ scopes?: Scope[];
31
+ meta?: Metadata;
42
32
  }
43
- interface KeyboardShortcut {
44
- key: string;
45
- ctrlKey?: boolean;
46
- shiftKey?: boolean;
47
- altKey?: boolean;
48
- metaKey?: boolean;
33
+ interface Route {
34
+ kind: "route";
35
+ path: string;
36
+ page: string;
49
37
  }
50
- interface IngestConfig {
51
- endpoint: string;
52
- apiKey: string;
53
- environment?: string;
54
- appVersion?: string;
55
- reporter?: {
56
- email?: string;
57
- name?: string;
58
- };
59
- metadata?: Record<string, string>;
60
- captureConsole?: boolean;
61
- captureNetwork?: boolean;
38
+ interface FlowStep {
39
+ entityId: string;
40
+ action?: string;
62
41
  }
63
- type FeedbackResult = {
64
- ok: true;
42
+ interface Flow {
43
+ kind: "flow";
65
44
  id: string;
66
- sequenceNumber: number;
45
+ loc: Location;
46
+ touches: string[];
47
+ steps: FlowStep[];
48
+ }
49
+ interface Page extends EntityWithMetaBase {
50
+ kind: "page";
51
+ }
52
+ interface Feature extends EntityWithMetaBase {
53
+ kind: "feature";
54
+ }
55
+ interface Widget extends EntityWithMetaBase {
56
+ kind: "widget";
57
+ }
58
+ interface Region extends EntityWithMetaBase {
59
+ kind: "region";
60
+ }
61
+ interface Element$1 extends EntityWithMetaBase {
62
+ kind: "element";
63
+ }
64
+ interface Primitive extends EntityWithMetaBase {
65
+ kind: "primitive";
66
+ }
67
+ type Entity = Route | Page | Feature | Widget | Region | Element$1 | Primitive | Flow;
68
+ type EntityByKind<K extends EntityKind> = Extract<Entity, {
69
+ kind: K;
70
+ }>;
71
+
72
+ interface Registry {
73
+ add(entity: Entity): void;
74
+ get<K extends EntityKind>(kind: K, id: string): EntityByKind<K> | undefined;
75
+ list<K extends EntityKind>(kind: K): ReadonlyArray<EntityByKind<K>>;
76
+ query(predicate: (entity: Entity) => boolean): Entity[];
77
+ byScope(scope: Scope): Entity[];
78
+ touchedBy(flowId: string): Entity[];
79
+ }
80
+
81
+ type ThemePreference = "light" | "dark" | "auto";
82
+ type ResolvedTheme = "light" | "dark";
83
+ interface ViewStackEntry {
84
+ id: string;
85
+ ref: EntityRef | null;
86
+ }
87
+ interface SessionSnapshot {
88
+ hover: EntityRef | null;
89
+ selection: EntityRef | null;
90
+ stack: ViewStackEntry[];
91
+ /** Sticky overlay highlight. Set by "Highlight Element" actions; cleared on Esc. */
92
+ pinnedHighlight: EntityRef | null;
93
+ inspectorActive: boolean;
94
+ theme: ThemePreference;
95
+ resolvedTheme: ResolvedTheme;
96
+ ingestActive: boolean;
97
+ }
98
+ interface SessionActions {
99
+ hover(ref: EntityRef | null): void;
100
+ select(ref: EntityRef | null): void;
101
+ /**
102
+ * Append a view onto the view stack. Pure: never resolves defaults.
103
+ */
104
+ pushStack(entry: ViewStackEntry): void;
105
+ /**
106
+ * Remove the top entry from the view stack. No-op when the stack is empty.
107
+ */
108
+ popStack(): void;
109
+ /**
110
+ * Empty the view stack.
111
+ */
112
+ clearStack(): void;
113
+ /**
114
+ * Open a view by id. If `ref` is omitted, the current `selection` is captured;
115
+ * pass `null` explicitly to open the view with no ref context. Thin wrapper
116
+ * around `pushStack`.
117
+ */
118
+ openView(id: string, ref?: EntityRef | null): void;
119
+ /**
120
+ * Clear the entire view stack. Thin wrapper around `clearStack`.
121
+ */
122
+ closeView(): void;
123
+ setInspectorActive(active: boolean): void;
124
+ toggleInspector(): void;
125
+ /** Pin the overlay to `ref` until `clearPinnedHighlight` is called. */
126
+ pinHighlight(ref: EntityRef): void;
127
+ clearPinnedHighlight(): void;
128
+ setTheme(theme: ThemePreference, resolved?: ResolvedTheme): void;
129
+ setIngest(active: boolean): void;
130
+ }
131
+ interface SessionState extends SessionSnapshot {
132
+ actions: SessionActions;
133
+ }
134
+
135
+ type SurfaceEvent = {
136
+ type: "TOGGLE_INSPECTOR";
137
+ } | {
138
+ type: "OPEN_PALETTE";
139
+ } | {
140
+ type: "PUSH_VIEW";
141
+ entry: ViewStackEntry;
142
+ } | {
143
+ type: "POP_VIEW";
144
+ } | {
145
+ type: "CLOSE";
146
+ } | {
147
+ type: "ESC";
148
+ } | {
149
+ type: "CMD_K";
150
+ } | {
151
+ type: "SELECT";
152
+ ref: EntityRef | null;
153
+ entry: ViewStackEntry;
67
154
  } | {
68
- ok: false;
69
- error: string;
155
+ type: "SET_SELECTION";
156
+ ref: EntityRef | null;
157
+ } | {
158
+ type: "HOVER";
159
+ ref: EntityRef;
160
+ element: HTMLElement | null;
161
+ color?: string | null;
162
+ } | {
163
+ type: "UNHOVER";
164
+ } | {
165
+ type: "PIN";
166
+ ref?: EntityRef;
167
+ } | {
168
+ type: "UNPIN";
169
+ } | {
170
+ type: "SET_THEME";
171
+ theme: ThemePreference;
172
+ resolvedTheme: ResolvedTheme;
173
+ } | {
174
+ type: "SET_INGEST";
175
+ active: boolean;
70
176
  };
71
- type UidexTheme = 'dark' | 'light' | 'auto';
72
- type FeedbackType = 'bug' | 'feature' | 'improvement' | 'question';
73
- type FeedbackSeverity = 'low' | 'medium' | 'high' | 'critical';
177
+
178
+ type SessionStore = StoreApi<SessionState> & {
179
+ send(event: SurfaceEvent): void;
180
+ };
181
+
182
+ type ConsoleLevel = "warn" | "error";
183
+ interface ConsoleEntry {
184
+ level: ConsoleLevel;
185
+ message: string;
186
+ timestamp: string;
187
+ }
188
+ interface ConsoleCaptureOptions {
189
+ limit?: number;
190
+ target?: Console;
191
+ now?: () => Date;
192
+ }
193
+ interface ConsoleCapture {
194
+ start(): void;
195
+ stop(): void;
196
+ readonly isActive: boolean;
197
+ entries(): readonly ConsoleEntry[];
198
+ clear(): void;
199
+ }
200
+
201
+ interface NetworkEntry {
202
+ method: string;
203
+ url: string;
204
+ status: number;
205
+ timestamp: string;
206
+ error?: string;
207
+ }
208
+ interface NetworkCaptureOptions {
209
+ limit?: number;
210
+ target?: {
211
+ fetch?: typeof fetch;
212
+ };
213
+ now?: () => Date;
214
+ }
215
+ interface NetworkCapture {
216
+ start(): void;
217
+ stop(): void;
218
+ readonly isActive: boolean;
219
+ entries(): readonly NetworkEntry[];
220
+ clear(): void;
221
+ }
222
+
74
223
  interface ConsoleLogEntry {
75
- level: 'warn' | 'error';
224
+ level: "log" | "warn" | "error" | "info";
76
225
  message: string;
77
226
  timestamp: string;
78
227
  }
@@ -80,105 +229,530 @@ interface NetworkErrorEntry {
80
229
  url: string;
81
230
  method: string;
82
231
  status: number | null;
83
- statusText: string;
232
+ statusText: string | null;
84
233
  timestamp: string;
85
234
  }
86
- interface FeedbackReport {
87
- type: FeedbackType;
88
- severity: FeedbackSeverity;
235
+ interface Viewport {
236
+ width: number;
237
+ height: number;
238
+ }
239
+ interface SourceRef {
240
+ filePath: string;
241
+ line: number;
242
+ }
243
+ interface FeedbackSuggestedTarget {
244
+ integrationId: string;
245
+ targetConfig: Record<string, unknown>;
246
+ }
247
+ interface FeedbackPayload {
248
+ type: "bug" | "feature" | "improvement" | "question";
249
+ severity: "low" | "medium" | "high" | "critical";
89
250
  title?: string;
90
251
  description: string;
91
252
  componentId: string;
92
- element: string | null;
93
- sources: {
94
- filePath: string;
95
- line: number;
96
- }[];
253
+ element?: string | null;
254
+ sources?: SourceRef[];
97
255
  url: string;
98
256
  path: string;
99
- route: string | null;
100
- timestamp: string;
101
- pageTitle: string;
102
- pageDescription?: string;
103
- locale: string;
104
- sessionId: string;
105
- viewport: {
106
- width: number;
107
- height: number;
108
- };
109
- screen: {
110
- width: number;
111
- height: number;
112
- };
113
- userAgent: string;
114
- screenshot?: string;
257
+ route?: string | null;
258
+ pageTitle?: string;
259
+ sessionId?: string;
115
260
  reporterEmail?: string;
116
261
  reporterName?: string;
262
+ timestamp: string;
263
+ viewport: Viewport;
264
+ screen: Viewport;
265
+ userAgent: string;
266
+ locale?: string;
117
267
  environment?: string;
118
268
  appVersion?: string;
119
- metadata?: Record<string, string>;
120
269
  consoleLogs?: ConsoleLogEntry[];
121
270
  networkErrors?: NetworkErrorEntry[];
122
- gitBranch?: string;
123
- gitCommit?: string;
124
- contextId?: string;
125
- }
126
- interface GitContext {
127
- branch: string;
128
- commit?: string;
129
- }
130
-
131
- interface UidexDevtoolsProps {
132
- components?: UidexMap;
133
- pages?: UidexPage[];
134
- features?: UidexFeature[];
135
- uiComponents?: PrimitiveEntry[];
136
- config?: UidexConfig;
137
- buttonPosition?: ButtonPosition;
138
- /** Theme for the devtools widget. Default: 'auto'. */
139
- theme?: UidexTheme;
140
- disabled?: boolean;
141
- onSelect?: (id: string) => void;
142
- /** Keyboard shortcut to toggle inspect mode. Default: Shift+Cmd+U. Set to false to disable. */
143
- inspectShortcut?: KeyboardShortcut | false;
144
- /** Ingest configuration for submitting feedback to a server. */
145
- ingest?: IngestConfig;
146
- /** Called after feedback submission with the report and result. */
147
- onSubmit?: (report: FeedbackReport, result: FeedbackResult) => void;
148
- }
149
- declare function UidexDevtools({ components, pages, features, uiComponents, config, buttonPosition, theme, disabled, onSelect, inspectShortcut, ingest, onSubmit, }: UidexDevtoolsProps): null;
150
-
151
- type DataProps = 'components' | 'pages' | 'features' | 'uiComponents';
152
- declare function createUidexDevtools(data: {
153
- components: UidexMap;
154
- pages?: UidexPage[];
155
- features?: UidexFeature[];
156
- uiComponents?: PrimitiveEntry[];
157
- }): {
158
- (props: Omit<UidexDevtoolsProps, DataProps>): null;
159
- displayName: string;
160
- };
271
+ metadata?: Record<string, string>;
272
+ screenshot?: string;
273
+ suggestedTarget?: FeedbackSuggestedTarget;
274
+ }
275
+ interface FeedbackExternalLink {
276
+ ok: boolean;
277
+ url?: string;
278
+ key?: string;
279
+ error?: string;
280
+ }
281
+ interface FeedbackResult {
282
+ id: string;
283
+ sequenceNumber: number;
284
+ externalLink?: FeedbackExternalLink;
285
+ }
286
+ interface IngestConfigIssue {
287
+ id: string;
288
+ key: string;
289
+ summary: string;
290
+ issueType: string;
291
+ }
292
+ interface IngestConfig {
293
+ hasJira: boolean;
294
+ integrationId?: string;
295
+ parentIssues?: IngestConfigIssue[];
296
+ }
297
+ /**
298
+ * Generic so third-party adapters (e.g. `uidex-cloud`) can plug in their own
299
+ * payload/result/integration shapes. SDK-bundled `cloud()` returns the
300
+ * defaulted form. `ViewContext.cloud` uses the fully-open variant; consumers
301
+ * that need the SDK shape narrow with `as CloudAdapter`.
302
+ */
303
+ interface CloudAdapter<TPayload = FeedbackPayload, TResult = FeedbackResult, TIntegrations = {
304
+ getConfig(): Promise<IngestConfig>;
305
+ /**
306
+ * Synchronous read of the eagerly-fetched config. Returns `null` until the
307
+ * initial fetch resolves; views that need a sync answer (e.g. detail
308
+ * actions deciding whether to surface a Jira button) read this.
309
+ */
310
+ getCachedConfig(): IngestConfig | null;
311
+ }> {
312
+ readonly feedback: {
313
+ submit(payload: TPayload): Promise<TResult>;
314
+ };
315
+ readonly integrations: TIntegrations;
316
+ }
317
+
318
+ interface IngestOptions {
319
+ captureConsole?: boolean;
320
+ captureNetwork?: boolean;
321
+ consoleLimit?: number;
322
+ networkLimit?: number;
323
+ consoleTarget?: ConsoleCaptureOptions["target"];
324
+ networkTarget?: NetworkCaptureOptions["target"];
325
+ now?: () => Date;
326
+ }
327
+ interface Ingest {
328
+ start(): void;
329
+ stop(): void;
330
+ readonly isActive: boolean;
331
+ readonly console: ConsoleCapture | null;
332
+ readonly network: NetworkCapture | null;
333
+ }
161
334
 
162
- interface UidexOverlayProps {
163
- target: HTMLElement | null;
335
+ interface OverlayShowOptions {
336
+ label?: string;
164
337
  color?: string;
165
- borderStyle?: BorderStyle;
338
+ padding?: number;
339
+ borderStyle?: string;
166
340
  borderWidth?: number;
167
- colors?: Record<string, string>;
341
+ fillOpacity?: number;
342
+ backdrop?: boolean;
168
343
  }
169
- declare function UidexOverlay({ target, color, borderStyle, borderWidth, colors, }: UidexOverlayProps): null;
170
344
 
171
- declare function registerComponents(components: UidexMap): void;
172
- declare function getComponents(): UidexMap | null;
173
- declare function registerPages(pages: UidexPage[]): void;
174
- declare function getPages(): UidexPage[] | null;
175
- declare function registerFeatures(features: UidexFeature[]): void;
176
- declare function getFeatures(): UidexFeature[] | null;
177
- declare function registerGitContext(ctx: GitContext): void;
345
+ type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
178
346
 
179
- declare function classNames(...classes: (string | undefined | null | false)[]): string;
180
- declare function getContrastColor(hexColor: string): string;
181
- declare function hexToRgba(hex: string, alpha: number): string;
182
- declare function resolveColor(color: string | undefined, colorMap?: Record<string, string>): string | undefined;
347
+ type ViewSurface = ListSurface | DetailSurface | FormSurface | CustomSurface;
348
+ interface ListSurface {
349
+ kind: "list";
350
+ id: string;
351
+ items: readonly ListItem[];
352
+ onSelect?(item: ListItem): void;
353
+ emptyLabel?: string;
354
+ defaultHighlight?: string;
355
+ filter?(item: ListItem, query: string): boolean;
356
+ }
357
+ interface ListItem {
358
+ value: string;
359
+ label: string;
360
+ subtitle?: string;
361
+ group?: string;
362
+ shortcut?: string;
363
+ /**
364
+ * When highlighted, the shell calls `ctx.highlight.show(preview)`.
365
+ * Cleared on unhighlight or view unmount.
366
+ */
367
+ preview?: EntityRef;
368
+ /** Renders a kind chip on the left. `entity.kind` drives icon + color. */
369
+ entityChip?: {
370
+ entity: Entity;
371
+ node?: Element | null;
372
+ };
373
+ /**
374
+ * Optional leading-icon factory used for non-entity rows (e.g. a palette
375
+ * "Feedback" command). Called per-render so the returned Node is fresh.
376
+ * The shell wraps whatever is returned in a rounded-square tile.
377
+ */
378
+ leading?: () => Node;
379
+ /** Raw data attribute tag appended to the row (for test/e2e hooks). */
380
+ tag?: string;
381
+ /** Contextual actions surfaced in the footer popup when this row is highlighted. */
382
+ actions?: readonly ShellAction[];
383
+ }
384
+ interface DetailSurface {
385
+ kind: "detail";
386
+ entityKind: EntityKind;
387
+ /** Registry lookup failed — renders the "not found" placeholder. */
388
+ notFound?: EntityRef;
389
+ /** Entity display name, rendered as the heading. */
390
+ title?: string;
391
+ subtitle?: DetailSubtitle;
392
+ actions?: readonly DetailAction[];
393
+ sections?: readonly DetailSection[];
394
+ }
395
+ interface DetailSubtitle {
396
+ rawId: string;
397
+ extra?: string;
398
+ }
399
+ interface DetailActionBase {
400
+ id: string;
401
+ label: string;
402
+ icon?: DetailActionIcon;
403
+ ariaLabel?: string;
404
+ hint?: string;
405
+ intent?: ShellActionIntent;
406
+ }
407
+ type DetailAction = (DetailActionBase & {
408
+ copy: string;
409
+ }) | (DetailActionBase & {
410
+ scrollTo: string;
411
+ }) | (DetailActionBase & {
412
+ push: {
413
+ id: string;
414
+ ref?: EntityRef | null;
415
+ };
416
+ }) | (DetailActionBase & {
417
+ navigate: EntityRef;
418
+ }) | (DetailActionBase & {
419
+ highlight: EntityRef;
420
+ }) | (DetailActionBase & {
421
+ run: (ctx: DetailActionRunContext) => void | Promise<void>;
422
+ });
423
+ type DetailActionIcon = "copy" | "camera" | "message-circle-warning" | "chevron-down" | "highlighter" | "ticket-plus" | "view";
424
+ interface DetailActionRunContext {
425
+ setLabel(next: string, durationMs?: number): void;
426
+ }
427
+ interface ResolvedFlowStep {
428
+ ordinal: number;
429
+ entity: Entity;
430
+ action?: string;
431
+ }
432
+ type DetailSection = {
433
+ id: "description";
434
+ text: string;
435
+ } | {
436
+ id: "acceptance";
437
+ items: readonly string[];
438
+ } | {
439
+ id: "composes";
440
+ label: string;
441
+ entities: readonly Entity[];
442
+ filterable?: boolean;
443
+ } | {
444
+ id: "used-by";
445
+ label: string;
446
+ entities: readonly Entity[];
447
+ filterable?: boolean;
448
+ } | {
449
+ id: "flows";
450
+ flows: readonly Flow[];
451
+ filterable?: boolean;
452
+ } | {
453
+ id: "touches";
454
+ entities: readonly Entity[];
455
+ filterable?: boolean;
456
+ } | {
457
+ id: "steps";
458
+ steps: readonly ResolvedFlowStep[];
459
+ filterable?: boolean;
460
+ } | {
461
+ id: "routes";
462
+ paths: readonly string[];
463
+ filterable?: boolean;
464
+ };
465
+ interface FormSurface {
466
+ kind: "form";
467
+ id: string;
468
+ fields: readonly FormField[];
469
+ submit: FormSubmit;
470
+ initial?: Record<string, FormValue>;
471
+ /**
472
+ * Optional Standard Schema (Zod v4, Valibot, ArkType, etc.) run against the
473
+ * collected form values before `submit.onSubmit`. On failure, issues are
474
+ * routed to the matching `<FieldError>` and submission is skipped.
475
+ */
476
+ schema?: StandardSchemaV1<Record<string, unknown>>;
477
+ /**
478
+ * Promise resolving to a base64 screenshot data URL. When provided, the
479
+ * form renderer shows a thumbnail preview above the fields.
480
+ */
481
+ screenshotPreview?: Promise<string | null>;
482
+ }
483
+ /**
484
+ * Minimal StandardSchemaV1 surface — kept inline so the SDK doesn't need a
485
+ * type-level dep on any specific validator package.
486
+ */
487
+ interface StandardSchemaV1<Input = unknown, Output = Input> {
488
+ readonly "~standard": {
489
+ readonly version: 1;
490
+ readonly vendor: string;
491
+ readonly validate: (value: unknown) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;
492
+ readonly types?: {
493
+ readonly input: Input;
494
+ readonly output: Output;
495
+ };
496
+ };
497
+ }
498
+ type StandardSchemaResult<Output> = {
499
+ readonly value: Output;
500
+ readonly issues?: undefined;
501
+ } | {
502
+ readonly issues: ReadonlyArray<StandardSchemaIssue>;
503
+ };
504
+ interface StandardSchemaIssue {
505
+ readonly message: string;
506
+ readonly path?: ReadonlyArray<PropertyKey | {
507
+ readonly key: PropertyKey;
508
+ }>;
509
+ }
510
+ interface FormSubmit {
511
+ label: string;
512
+ onSubmit: (values: Record<string, FormValue>) => FormSubmitResult | void | Promise<FormSubmitResult | void>;
513
+ }
514
+ type FormSubmitResult = {
515
+ status: "success";
516
+ message?: string;
517
+ link?: {
518
+ url: string;
519
+ label?: string;
520
+ };
521
+ resetFields?: readonly string[];
522
+ } | {
523
+ status: "error";
524
+ message: string;
525
+ /** Per-field error messages keyed by field `name`. */
526
+ fieldErrors?: Record<string, string>;
527
+ };
528
+ type FormValue = string | boolean;
529
+ interface FormFieldBase {
530
+ name: string;
531
+ label: string;
532
+ }
533
+ type FormField = (FormFieldBase & {
534
+ kind: "select";
535
+ options: readonly {
536
+ value: string;
537
+ label: string;
538
+ }[];
539
+ required?: boolean;
540
+ value?: string;
541
+ }) | (FormFieldBase & {
542
+ kind: "text";
543
+ placeholder?: string;
544
+ required?: boolean;
545
+ value?: string;
546
+ }) | (FormFieldBase & {
547
+ kind: "email";
548
+ placeholder?: string;
549
+ required?: boolean;
550
+ value?: string;
551
+ }) | (FormFieldBase & {
552
+ kind: "textarea";
553
+ placeholder?: string;
554
+ required?: boolean;
555
+ rows?: number;
556
+ value?: string;
557
+ }) | (FormFieldBase & {
558
+ kind: "checkbox";
559
+ value?: boolean;
560
+ });
561
+ interface CustomSurface {
562
+ kind: "custom";
563
+ render: (ctx: ViewContext, root: HTMLElement) => Cleanup | void;
564
+ }
565
+
566
+ interface ViewPalette {
567
+ label: string;
568
+ group?: string;
569
+ /**
570
+ * Leading-icon factory rendered as a rounded-square tile on the palette
571
+ * row. Called fresh per render (so a returned SVG isn't reparented).
572
+ */
573
+ icon?: () => Node;
574
+ shortcut?: string;
575
+ }
576
+ interface ViewDirectory {
577
+ list(): readonly View[];
578
+ recents(): readonly EntityRef[];
579
+ favorites(): readonly EntityRef[];
580
+ }
581
+ interface ViewPushTarget {
582
+ id: string;
583
+ ref?: EntityRef | null;
584
+ }
585
+ interface HighlightController {
586
+ show(ref: EntityRef, opts?: OverlayShowOptions): void;
587
+ hide(): void;
588
+ }
589
+ interface ViewContext {
590
+ ref: EntityRef | null;
591
+ registry: Registry;
592
+ cloud: CloudAdapter<unknown, unknown, unknown> | null;
593
+ sdkCloud: CloudAdapter;
594
+ views: ViewDirectory;
595
+ /** Push a view onto the stack. Unregistered ids are a no-op. */
596
+ push: (target: ViewPushTarget) => void;
597
+ /** Pop the top view off the stack. No-op when the stack is empty. */
598
+ pop: () => void;
599
+ /** Clear the entire view stack. */
600
+ close: () => void;
601
+ /** Resolve the first view matching `ref` and push it onto the stack. */
602
+ navigate: (ref: EntityRef) => void;
603
+ /** Pin the overlay to `ref` until the user presses Esc. */
604
+ pinHighlight: (ref: EntityRef) => void;
605
+ /** Toggle favorite status for an entity ref. */
606
+ toggleFavorite: (ref: EntityRef) => void;
607
+ /** Check if an entity ref is favorited. */
608
+ isFavorite: (ref: EntityRef) => boolean;
609
+ /** Shell-owned search input. The shell dispatches its value into the active surface. */
610
+ searchInput: HTMLInputElement;
611
+ /** Drives the Surface's singleton overlay from inside a custom surface. */
612
+ highlight: HighlightController;
613
+ /** Snapshot of the current view stack (top-most last). */
614
+ getStack: () => readonly ViewStackEntry[];
615
+ }
616
+ interface ShellHint {
617
+ key: string;
618
+ label: string;
619
+ }
620
+ type ShellActionIntent = {
621
+ kind: "push";
622
+ viewId: string;
623
+ refKind?: EntityKind;
624
+ } | {
625
+ kind: "pop";
626
+ } | {
627
+ kind: "close";
628
+ } | {
629
+ kind: "navigate";
630
+ refKind?: EntityKind;
631
+ } | {
632
+ kind: "external";
633
+ describe: string;
634
+ };
635
+ interface ShellAction {
636
+ id: string;
637
+ label: string;
638
+ shortcut?: string;
639
+ icon?: () => Node;
640
+ perform: () => void | Promise<void>;
641
+ intent?: ShellActionIntent;
642
+ }
643
+ type Cleanup = () => void;
644
+ interface View {
645
+ id: string;
646
+ matches?: (ref: EntityRef) => boolean;
647
+ palette?: ViewPalette;
648
+ title?: string | ((ctx: ViewContext) => string);
649
+ /** Show the shell search input when this view is on top. Default: true. */
650
+ searchable?: boolean;
651
+ hints?: ShellHint[] | ((ctx: ViewContext) => ShellHint[]);
652
+ actions?: (ctx: ViewContext) => ShellAction[];
653
+ /**
654
+ * Element focused when this view becomes the top of the stack. The shell
655
+ * falls back to the first focusable element in the host when omitted, or
656
+ * when the declared target has been removed from the host.
657
+ */
658
+ focusTarget?: (root: HTMLElement, ctx: ViewContext) => HTMLElement | null;
659
+ surface: (ctx: ViewContext) => ViewSurface;
660
+ }
661
+
662
+ interface PaletteShortcut {
663
+ /** The key value (e.g. "k", "j", ";"). Matched case-insensitively. */
664
+ key: string;
665
+ /** Require Cmd (Mac) / Ctrl (Win/Linux). Default: true. */
666
+ mod?: boolean;
667
+ /** Require Shift. Default: false. */
668
+ shift?: boolean;
669
+ }
670
+
671
+ interface ViewRegistrar {
672
+ register(view: View): void;
673
+ unregister(id: string): void;
674
+ list(): readonly View[];
675
+ get(id: string): View | undefined;
676
+ findMatch(ref: EntityRef): View | null;
677
+ navigate(ref: EntityRef): void;
678
+ recents(): readonly EntityRef[];
679
+ favorites(): readonly EntityRef[];
680
+ toggleFavorite(ref: EntityRef): void;
681
+ isFavorite(ref: EntityRef): boolean;
682
+ }
683
+
684
+ interface CreateUidexOptions {
685
+ theme?: ThemePreference;
686
+ resolvedTheme?: ResolvedTheme;
687
+ stylesheets?: string[];
688
+ initialCorner?: Corner;
689
+ /** Shown as a label at the start of the menu bar. */
690
+ appTitle?: string;
691
+ cloud?: CloudAdapter | null;
692
+ dev?: boolean;
693
+ /** Register bundled default views. Defaults to `true`. */
694
+ defaultViews?: boolean;
695
+ /** Additional views to register (after defaults). */
696
+ views?: readonly View[];
697
+ /**
698
+ * Override ingest behaviour. When `cloud` is non-null, ingest auto-enables
699
+ * (both console and network capture). Pass `null` to disable entirely, or
700
+ * an options object to override either channel.
701
+ */
702
+ ingest?: IngestOptions | null;
703
+ /** Keyboard shortcut for the command palette. Defaults to Cmd+K / Ctrl+K. */
704
+ shortcut?: PaletteShortcut;
705
+ }
706
+ interface Uidex {
707
+ mount(target?: Element): void;
708
+ unmount(): void;
709
+ readonly registry: Registry;
710
+ readonly session: SessionStore;
711
+ readonly views: ViewRegistrar;
712
+ readonly cloud: CloudAdapter | null;
713
+ readonly ingest: Ingest | null;
714
+ readonly shadowRoot: ShadowRoot | null;
715
+ }
716
+
717
+ interface UidexProviderProps {
718
+ /**
719
+ * Pre-built uidex instance (e.g. the `uidex` export from `uidex.gen.ts`).
720
+ * When provided, `projectKey`, `cloud`, and `config` are ignored.
721
+ */
722
+ instance?: Uidex;
723
+ projectKey?: string;
724
+ cloud?: CloudAdapter | null;
725
+ config?: Omit<CreateUidexOptions, "cloud">;
726
+ children?: ReactNode;
727
+ }
728
+ declare function UidexProvider({ instance: externalInstance, projectKey, cloud, config, children, }: UidexProviderProps): react_jsx_runtime.JSX.Element;
729
+
730
+ declare class UidexContextError extends Error {
731
+ constructor(hookName: string);
732
+ }
733
+ declare function useUidex(): Uidex;
734
+
735
+ interface UidexMountProps {
736
+ className?: string;
737
+ }
738
+ declare function UidexMount({ className }: UidexMountProps): react_jsx_runtime.JSX.Element;
739
+
740
+ interface ReactViewDef {
741
+ id: string;
742
+ matches?: (ref: EntityRef) => boolean;
743
+ palette?: ViewPalette;
744
+ component: ComponentType<{
745
+ ctx: ViewContext;
746
+ }>;
747
+ }
748
+ declare function createReactView(def: ReactViewDef): View;
749
+
750
+ interface KindChipProps {
751
+ kind: EntityKind;
752
+ label?: string;
753
+ withKindName?: boolean;
754
+ className?: string;
755
+ }
756
+ declare function KindChip({ kind, label, withKindName, className, }: KindChipProps): ReactElement;
183
757
 
184
- export { type BorderStyle, type ButtonPosition, type FeedbackReport, type FeedbackResult, type FeedbackSeverity, type FeedbackType, type IngestConfig, type KeyboardShortcut, type LabelPosition, type PrimitiveEntry, type UidexConfig, type UidexDefaults, UidexDevtools, type UidexDevtoolsProps, type UidexFeature, type UidexLocation, type UidexMap, UidexOverlay, type UidexOverlayProps, type UidexPage, classNames, createUidexDevtools, getComponents, getContrastColor, getFeatures, getPages, hexToRgba, registerComponents, registerFeatures, registerGitContext, registerPages, resolveColor };
758
+ export { KindChip, type KindChipProps, type ReactViewDef, UidexContextError, UidexMount, type UidexMountProps, UidexProvider, type UidexProviderProps, createReactView, useUidex };