@nexia/sdk 0.5.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 (49) hide show
  1. package/dist/app-availability.d.ts +18 -0
  2. package/dist/app-availability.js +29 -0
  3. package/dist/approval.d.ts +180 -0
  4. package/dist/approval.js +9 -0
  5. package/dist/context.d.ts +49 -0
  6. package/dist/context.js +1 -0
  7. package/dist/data-migration.d.ts +123 -0
  8. package/dist/data-migration.js +70 -0
  9. package/dist/fixtures/approval-contract-negative.d.ts +1 -0
  10. package/dist/fixtures/approval-contract-negative.js +8 -0
  11. package/dist/handoff-result.d.ts +6 -0
  12. package/dist/handoff-result.js +17 -0
  13. package/dist/host.d.ts +602 -0
  14. package/dist/host.js +803 -0
  15. package/dist/index.d.ts +42 -0
  16. package/dist/index.js +21 -0
  17. package/dist/number.d.ts +2 -0
  18. package/dist/number.js +9 -0
  19. package/dist/organization-target.d.ts +101 -0
  20. package/dist/organization-target.js +105 -0
  21. package/dist/permissions.d.ts +3 -0
  22. package/dist/permissions.js +12 -0
  23. package/dist/platform.d.ts +378 -0
  24. package/dist/platform.js +114 -0
  25. package/dist/process.d.ts +98 -0
  26. package/dist/process.js +10 -0
  27. package/dist/resource-composition.d.ts +104 -0
  28. package/dist/resource-composition.js +576 -0
  29. package/dist/resource-create-destination.d.ts +17 -0
  30. package/dist/resource-create-destination.js +1 -0
  31. package/dist/resource-reference.d.ts +122 -0
  32. package/dist/resource-reference.js +203 -0
  33. package/dist/resources/resource-information.d.ts +128 -0
  34. package/dist/resources/resource-information.js +12 -0
  35. package/dist/resources/resource-list.d.ts +23 -0
  36. package/dist/resources/resource-list.js +1 -0
  37. package/dist/resources/resource-projections.d.ts +311 -0
  38. package/dist/resources/resource-projections.js +1 -0
  39. package/dist/resources/resource-transfer.d.ts +208 -0
  40. package/dist/resources/resource-transfer.js +1 -0
  41. package/dist/shell.d.ts +1297 -0
  42. package/dist/shell.js +1 -0
  43. package/dist/signature.d.ts +489 -0
  44. package/dist/signature.js +171 -0
  45. package/dist/spreadsheet.d.ts +42 -0
  46. package/dist/spreadsheet.js +15 -0
  47. package/dist/testing.d.ts +16 -0
  48. package/dist/testing.js +17 -0
  49. package/package.json +53 -0
@@ -0,0 +1,1297 @@
1
+ import type { AnchorHTMLAttributes, ButtonHTMLAttributes, ComponentType, FieldsetHTMLAttributes, FormEvent, HTMLAttributes, InputHTMLAttributes, ReactElement, ReactNode, TextareaHTMLAttributes } from "react";
2
+ import type { QueryClient } from "@tanstack/react-query";
3
+ import type { PermissionsResponse } from "./context";
4
+ import type { ResourcePickerRevalidation, ResourceReferenceIdentity } from "./resource-reference";
5
+ import type { ResourceListSchema } from "./resources/resource-list";
6
+ import type { ResourceTransferMeta } from "./resources/resource-transfer";
7
+ /** A server-authorized, durable favorite identity. */
8
+ export type FavoriteTarget = {
9
+ kind: "page";
10
+ key: string;
11
+ } | {
12
+ kind: "record";
13
+ resourceKey: string;
14
+ resourceId: string;
15
+ };
16
+ export interface WorkTabRef<TData = unknown> {
17
+ type: string;
18
+ id: string;
19
+ label?: string;
20
+ route?: string;
21
+ data?: TData;
22
+ /** Omitted unless the server authorizes this resource as favoriteable. */
23
+ favorite_target?: FavoriteTarget | null;
24
+ }
25
+ /** @deprecated Use WorkTabRef. Kept for one release for App source compatibility. */
26
+ export type ResourceRef<TData = unknown> = WorkTabRef<TData>;
27
+ /** Identifies the picker that launched a route-backed Resource create flow. */
28
+ export interface ResourceCreateContinuationTarget {
29
+ receiverKey: string;
30
+ /** Localized human field label shown by Shell continuation chrome. */
31
+ receiverLabel?: string;
32
+ resourceKey: string;
33
+ }
34
+ export interface ResourceCreateCompletionInput {
35
+ resourceId: string;
36
+ /** Optional owner-provided label used when no generic resolver exists. */
37
+ display?: string;
38
+ }
39
+ export interface ResourceCreateCompletion {
40
+ /** Complete a contextual create flow; returns true when the host handled navigation. */
41
+ complete: (input: ResourceCreateCompletionInput) => Promise<boolean>;
42
+ /** Cancel a contextual create flow; returns true when the host returned to its origin. */
43
+ cancel: () => boolean;
44
+ isContextual: boolean;
45
+ }
46
+ export interface ResourceCreateReceiverRegistration {
47
+ target: ResourceCreateContinuationTarget;
48
+ onCreated: (reference: ResourceReferenceIdentity) => void;
49
+ }
50
+ export interface ResourceInspectorStack {
51
+ readonly entries: ReadonlyArray<WorkTabRef>;
52
+ readonly index: number;
53
+ readonly current: WorkTabRef | null;
54
+ readonly isRoot: boolean;
55
+ readonly isEmpty: boolean;
56
+ push: (resource: WorkTabRef) => void;
57
+ back: () => void;
58
+ jumpTo: (index: number) => void;
59
+ reset: () => void;
60
+ openInTab: (resource: WorkTabRef) => void;
61
+ }
62
+ export interface ResourceInspectorAdapterProps<TData = unknown> {
63
+ resource: WorkTabRef<TData>;
64
+ stack: ResourceInspectorStack;
65
+ }
66
+ export type ResourceInspectorAdapter<TData = unknown> = (props: ResourceInspectorAdapterProps<TData>) => ReactNode;
67
+ export type ResourceInspectorAdapterLoader<TData = never> = () => Promise<{
68
+ default: ResourceInspectorAdapter<TData>;
69
+ }>;
70
+ export interface ResourceInspectorAdapterRegistry {
71
+ register: <TData = never>(type: string, loader: ResourceInspectorAdapterLoader<NoInfer<TData>>) => void;
72
+ get: (type: string) => ComponentType<ResourceInspectorAdapterProps> | undefined;
73
+ ids: () => string[];
74
+ subscribe: (listener: () => void) => () => void;
75
+ snapshot: () => number;
76
+ resetForTests: () => void;
77
+ }
78
+ /** App-facing registration capability. Inspection remains host/test-only. */
79
+ export interface ResourceInspectorAdapterRegistrar {
80
+ register: <TData = never>(type: string, loader: ResourceInspectorAdapterLoader<NoInfer<TData>>) => void;
81
+ }
82
+ export interface NxAlertProps {
83
+ variant?: "info" | "success" | "warning" | "error";
84
+ title?: ReactNode;
85
+ icon?: ReactNode;
86
+ actions?: ReactNode;
87
+ onDismiss?: () => void;
88
+ dismissLabel?: string;
89
+ children?: ReactNode;
90
+ className?: string;
91
+ }
92
+ export interface NxModalDialogProps {
93
+ open: boolean;
94
+ onClose: () => void;
95
+ title?: ReactNode;
96
+ description?: ReactNode;
97
+ children: ReactNode;
98
+ footer?: ReactNode;
99
+ width?: "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl";
100
+ height?: "auto" | "compact" | "tall";
101
+ placement?: "center" | "upper" | "top";
102
+ dismissOnBackdrop?: boolean;
103
+ dismissOnEscape?: boolean;
104
+ labelledBy?: string;
105
+ showClose?: boolean;
106
+ }
107
+ export interface NxColumnNode {
108
+ value: string;
109
+ label: string;
110
+ children?: NxColumnNode[];
111
+ icon?: ReactNode;
112
+ meta?: ReactNode;
113
+ disabled?: boolean;
114
+ keywords?: string;
115
+ }
116
+ export interface NxColumnBrowserLabels {
117
+ searchEmptyTitle?: string;
118
+ searchEmptyHint?: string;
119
+ previewEmpty?: string;
120
+ previewLabel?: string;
121
+ breadcrumbSeparator?: string;
122
+ }
123
+ export interface NxColumnBrowserProps {
124
+ roots: NxColumnNode[];
125
+ value?: string | null;
126
+ selectedValues?: readonly string[];
127
+ multiple?: boolean;
128
+ onSelect: (value: string, node: NxColumnNode) => void;
129
+ onClearSelection?: () => void;
130
+ onActivate?: (value: string, node: NxColumnNode) => void;
131
+ renderPreview?: (node: NxColumnNode) => ReactNode;
132
+ allLabel?: string;
133
+ searchable?: boolean;
134
+ autoFocus?: boolean;
135
+ searchPlaceholder?: string;
136
+ labels?: NxColumnBrowserLabels;
137
+ ariaLabel: string;
138
+ heightClassName?: string;
139
+ testId?: string;
140
+ }
141
+ export interface NxColumnPickerLabels extends NxColumnBrowserLabels {
142
+ clear?: string;
143
+ cancel?: string;
144
+ select?: string;
145
+ }
146
+ interface NxColumnPickerBaseProps {
147
+ open: boolean;
148
+ onClose: () => void;
149
+ title: string;
150
+ roots: NxColumnNode[];
151
+ onClear?: () => void;
152
+ allLabel?: string;
153
+ searchable?: boolean;
154
+ searchPlaceholder?: string;
155
+ labels?: NxColumnPickerLabels;
156
+ width?: "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl";
157
+ testId?: string;
158
+ }
159
+ interface NxColumnPickerSingleProps {
160
+ multiple?: false;
161
+ value?: string | null;
162
+ onSelect: (value: string, node: NxColumnNode) => void;
163
+ renderPreview?: (node: NxColumnNode) => ReactNode;
164
+ renderSelectionPreview?: never;
165
+ values?: never;
166
+ onSelectMany?: never;
167
+ }
168
+ interface NxColumnPickerMultipleProps {
169
+ multiple: true;
170
+ values?: readonly string[];
171
+ onSelectMany: (values: string[], nodes: NxColumnNode[]) => void;
172
+ renderSelectionPreview?: (nodes: NxColumnNode[], onRemove: (value: string) => void) => ReactNode;
173
+ renderPreview?: never;
174
+ value?: never;
175
+ onSelect?: never;
176
+ }
177
+ export type NxColumnPickerProps = NxColumnPickerBaseProps & (NxColumnPickerSingleProps | NxColumnPickerMultipleProps);
178
+ export interface NxMissingRequiredReferenceItem {
179
+ key: string;
180
+ label: string;
181
+ createLabel?: string;
182
+ onCreate?: () => void;
183
+ }
184
+ export interface NxMissingRequiredReferencesAlertProps {
185
+ title: string;
186
+ items: readonly NxMissingRequiredReferenceItem[];
187
+ }
188
+ export interface NxPaginationProps {
189
+ current: number;
190
+ total: number;
191
+ onChange: (page: number) => void;
192
+ disabled?: boolean;
193
+ className?: string;
194
+ }
195
+ export interface ResourceInspectorPanelProps {
196
+ testId?: string;
197
+ badges?: ReactNode;
198
+ actions?: ReactNode;
199
+ children?: ReactNode;
200
+ }
201
+ export interface ResourceInspectorStateProps {
202
+ testId?: string;
203
+ children: ReactNode;
204
+ }
205
+ export interface ResourceInspectorStackHostProps {
206
+ root?: WorkTabRef | null;
207
+ onClose?: () => void;
208
+ onOpenInTab?: (resource: WorkTabRef) => void;
209
+ emptyState?: ReactNode;
210
+ testId?: string;
211
+ }
212
+ export interface ResourceInspectorStackProviderProps {
213
+ root: WorkTabRef | null;
214
+ initialEntries?: WorkTabRef[];
215
+ onEntriesChange?: (entries: ReadonlyArray<WorkTabRef>) => void;
216
+ onOpenInTab?: (resource: WorkTabRef) => void;
217
+ children: ReactNode;
218
+ }
219
+ export interface NxComboboxOption<TValue extends string | number> {
220
+ value: TValue;
221
+ label: ReactNode;
222
+ meta?: ReactNode;
223
+ trailing?: ReactNode;
224
+ disabled?: boolean;
225
+ searchText?: string;
226
+ }
227
+ interface NxComboboxBaseProps<TValue extends string | number> {
228
+ options: readonly NxComboboxOption<TValue>[];
229
+ placeholder: ReactNode;
230
+ ariaLabel: string;
231
+ searchPlaceholder?: string;
232
+ emptyLabel?: ReactNode;
233
+ searchValue?: string;
234
+ onSearchChange?: (query: string) => void;
235
+ loading?: boolean;
236
+ id?: string;
237
+ describedBy?: string;
238
+ invalid?: boolean;
239
+ fullWidth?: boolean;
240
+ disabled?: boolean;
241
+ size?: "xs" | "sm" | "md";
242
+ triggerClassName?: string;
243
+ /** Optional panel width. By default the panel matches its trigger. */
244
+ panelWidth?: number | string;
245
+ testId?: string;
246
+ renderSummary?: (selected: NxComboboxOption<TValue>[]) => ReactNode;
247
+ closeLabel?: ReactNode;
248
+ showSelectedItems?: boolean;
249
+ selectedItemsAriaLabel?: string;
250
+ removeSelectedItemLabel?: (option: NxComboboxOption<TValue>) => string;
251
+ createAction?: {
252
+ label: string;
253
+ onCreate: (searchValue: string) => void;
254
+ disabled?: boolean;
255
+ };
256
+ revalidateOnOpen?: ResourcePickerRevalidation;
257
+ /** Registers this picker as the return target for a route-backed create flow. */
258
+ resourceCreateContinuation?: TValue extends string ? ResourceCreateContinuationTarget : never;
259
+ }
260
+ export type NxComboboxProps<TValue extends string | number> = (NxComboboxBaseProps<TValue> & {
261
+ multiple?: false;
262
+ value: TValue | null;
263
+ onChange: (value: TValue, option: NxComboboxOption<TValue>) => void;
264
+ }) | (NxComboboxBaseProps<TValue> & {
265
+ multiple: true;
266
+ value: readonly TValue[];
267
+ onChange: (values: TValue[], option: NxComboboxOption<TValue>) => void;
268
+ });
269
+ /**
270
+ * Standard manual refresh control. The host owns its icon, label, sizing, and
271
+ * visual emphasis so App surfaces only choose the semantic placement.
272
+ */
273
+ export interface NxRefreshControlProps {
274
+ context: "compact" | "section" | "snapshot";
275
+ onRefresh: () => void | Promise<void>;
276
+ isRefreshing?: boolean;
277
+ disabled?: boolean;
278
+ /** Optional status rendered beside a snapshot refresh action. */
279
+ status?: ReactNode;
280
+ /** Optional pending status for a snapshot refresh action. */
281
+ refreshingLabel?: ReactNode;
282
+ testId?: string;
283
+ className?: string;
284
+ }
285
+ export interface InspectorActionProps {
286
+ id: string;
287
+ label: string;
288
+ permission: string;
289
+ onSelect: () => void;
290
+ icon?: ReactNode;
291
+ destructive?: boolean;
292
+ disabled?: boolean;
293
+ testId?: string;
294
+ }
295
+ /**
296
+ * Presentation-neutral Resource action shared by row menus and Inspectors.
297
+ *
298
+ * `id` is deliberately open-ended: the host applies canonical presentation
299
+ * for known IDs and a neutral fallback for App-specific operations.
300
+ */
301
+ export interface ResourceActionDescriptor extends NxDropdownMenuItem {
302
+ permissions?: readonly string[];
303
+ }
304
+ export interface InspectorResourceActionsProps {
305
+ actions: readonly ResourceActionDescriptor[];
306
+ }
307
+ interface ResourceLinkOwnProps {
308
+ /** Reference identity pushed into the active Inspector stack by default. */
309
+ resource: WorkTabRef;
310
+ children: ReactNode;
311
+ /**
312
+ * Optional owner activation for row identity or another local selection.
313
+ * When supplied, it runs instead of the Inspector stack/navigation fallback.
314
+ */
315
+ onActivate?: (resource: WorkTabRef) => void;
316
+ /** Stop the click from also activating an enclosing clickable row. */
317
+ stopPropagation?: boolean;
318
+ }
319
+ export type ResourceLinkProps = ResourceLinkOwnProps & Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof ResourceLinkOwnProps | "children">;
320
+ export type ResourceListFilterValue = string | string[];
321
+ export type ResourceListFilters = Record<string, ResourceListFilterValue>;
322
+ export interface ResourceTableSort {
323
+ key: string;
324
+ dir: "asc" | "desc";
325
+ }
326
+ export interface ResourceListParams {
327
+ search: string;
328
+ sort: ResourceTableSort | null;
329
+ filters: ResourceListFilters;
330
+ page: number;
331
+ perPage?: number;
332
+ }
333
+ export interface ResourceListParamsControls extends ResourceListParams {
334
+ setSearch: (value: string) => void;
335
+ setSort: (value: ResourceTableSort | null) => void;
336
+ setFilter: (key: string, value: ResourceListFilterValue | null) => void;
337
+ setFilters: (value: ResourceListFilters) => void;
338
+ setParams: (partial: Partial<Pick<ResourceListParams, "search" | "filters" | "sort">>) => void;
339
+ setPage: (value: number) => void;
340
+ setPerPage: (value: number | undefined) => void;
341
+ reset: () => void;
342
+ }
343
+ export interface UseResourceListParamsOptions {
344
+ scope?: string;
345
+ filterKeys?: readonly string[];
346
+ sortKeys?: readonly string[];
347
+ defaultSort?: ResourceTableSort | null;
348
+ defaultPage?: number;
349
+ searchDebounceMs?: number;
350
+ }
351
+ export interface ResourceListToolbarConfig {
352
+ leading?: ReactNode;
353
+ actions?: ReactNode;
354
+ filters?: ReactNode;
355
+ refresh?: ReactNode;
356
+ more?: ReactNode;
357
+ testId?: string;
358
+ }
359
+ export interface ResourceListRefreshConfig {
360
+ onRefresh: () => void | Promise<void>;
361
+ isRefreshing?: boolean;
362
+ }
363
+ export interface ResourceListFooterConfig {
364
+ pagination?: {
365
+ current: number;
366
+ total: number;
367
+ onChange: (page: number) => void;
368
+ disabled?: boolean;
369
+ } | null;
370
+ pageSize?: {
371
+ value: number;
372
+ onChange: (pageSize: number) => void;
373
+ options?: readonly number[];
374
+ disabled?: boolean;
375
+ } | null;
376
+ testId?: string;
377
+ }
378
+ export interface ResourceTableColumn<T> {
379
+ key: string;
380
+ header: ReactNode;
381
+ cell: (row: T, index: number) => ReactNode;
382
+ size?: "primary" | "text" | "meta" | "compact" | "actions";
383
+ colClassName?: string;
384
+ headerClassName?: string;
385
+ cellClassName?: string;
386
+ align?: "left" | "right";
387
+ priority?: 1 | 2;
388
+ sortable?: false;
389
+ sortKey?: string;
390
+ hideable?: false;
391
+ defaultVisible?: false;
392
+ }
393
+ export type ResourceTableDensity = "compact" | "standard" | "comfortable";
394
+ export type ResourceTableStyle = "striped" | "grid";
395
+ export interface ResourceTableSummaryRow {
396
+ cells: Partial<Record<string, ReactNode>>;
397
+ label?: string;
398
+ testId?: string;
399
+ }
400
+ export interface ResourceTableProps<T> {
401
+ tableId?: string;
402
+ label: string;
403
+ showLabel?: boolean;
404
+ labelTooltip?: ReactNode;
405
+ rows: T[];
406
+ columns: ResourceTableColumn<T>[];
407
+ /** Opt in to the host's card presentation. Omit for table-only list semantics. */
408
+ renderCard?: (row: T, index: number) => ReactNode;
409
+ /** Initial view when no actor-scoped table preference has been saved. */
410
+ defaultView?: "table" | "cards";
411
+ getKey: (row: T, index: number) => string | number;
412
+ toolbar?: true | ResourceListToolbarConfig;
413
+ footer?: true | ResourceListFooterConfig;
414
+ density?: ResourceTableDensity;
415
+ summaryRow?: ResourceTableSummaryRow;
416
+ refresh?: ResourceListRefreshConfig;
417
+ schema?: ResourceListSchema;
418
+ filters?: ResourceListFilters;
419
+ onFiltersChange?: (next: ResourceListFilters) => void;
420
+ transferMeta?: ResourceTransferMeta | null;
421
+ onTransferImported?: () => void | Promise<void>;
422
+ pagination?: {
423
+ current_page: number;
424
+ last_page: number;
425
+ per_page?: number;
426
+ total: number;
427
+ };
428
+ onPageChange?: (page: number) => void;
429
+ onPerPageChange?: (pageSize: number) => void;
430
+ paginationDisabled?: boolean;
431
+ loading?: boolean;
432
+ loadingLabel?: ReactNode;
433
+ loadingRows?: number;
434
+ empty?: ReactNode;
435
+ emptyState?: {
436
+ kind?: "empty" | "noResults";
437
+ title?: ReactNode;
438
+ description?: ReactNode;
439
+ action?: ReactNode;
440
+ testId?: string;
441
+ };
442
+ hasActiveQuery?: boolean;
443
+ error?: boolean;
444
+ errorDescription?: ReactNode;
445
+ onRetry?: () => void;
446
+ retryLabel?: ReactNode;
447
+ rowTestId?: (row: T, index: number) => string;
448
+ rowAttributes?: (row: T, index: number) => {
449
+ className?: string;
450
+ "aria-label"?: string;
451
+ "data-testid"?: string;
452
+ } | undefined;
453
+ rowSelected?: (row: T, index: number) => boolean;
454
+ onRowClick?: (row: T, index: number) => void;
455
+ tableMinWidth?: number;
456
+ responsiveMode?: "auto" | "table";
457
+ sort?: ResourceTableSort | null;
458
+ onSortChange?: (next: ResourceTableSort | null) => void;
459
+ className?: string;
460
+ headerTestId?: string;
461
+ tableTestId?: string;
462
+ }
463
+ export interface NxDropdownMenuItem {
464
+ id: string;
465
+ label: ReactNode;
466
+ href?: string;
467
+ testId?: string;
468
+ icon?: ReactNode;
469
+ trailing?: ReactNode;
470
+ destructive?: boolean;
471
+ separatorBefore?: boolean;
472
+ disabled?: boolean;
473
+ onSelect?: () => void;
474
+ }
475
+ export interface NxDropdownMenuProps {
476
+ /** A single element (typically an `NxButton`) that opens the menu. */
477
+ trigger: ReactElement;
478
+ items: NxDropdownMenuItem[];
479
+ /** Accessible label announced for the menu. Defaults to "Actions". */
480
+ "aria-label"?: string;
481
+ side?: "top" | "bottom";
482
+ align?: "start" | "end";
483
+ className?: string;
484
+ }
485
+ export interface ResourceListToolbarViewOption<TValue extends string> {
486
+ value: TValue;
487
+ label: ReactNode;
488
+ icon?: ReactNode;
489
+ disabled?: boolean;
490
+ }
491
+ export interface ResourceListToolbarMoreMenuProps<TValue extends string = string> {
492
+ label: string;
493
+ items?: NxDropdownMenuItem[];
494
+ viewOptions?: {
495
+ label: string;
496
+ value: TValue;
497
+ items: readonly ResourceListToolbarViewOption<TValue>[];
498
+ onChange: (value: TValue) => void;
499
+ };
500
+ testId?: string;
501
+ }
502
+ export interface ResourcePrimaryCellProps {
503
+ resource: WorkTabRef;
504
+ label: ReactNode;
505
+ onActivate?: (resource: WorkTabRef) => void;
506
+ meta?: Array<{
507
+ kind: "resource";
508
+ key: string;
509
+ label: ReactNode;
510
+ resource: WorkTabRef;
511
+ onActivate?: (resource: WorkTabRef) => void;
512
+ testId?: string;
513
+ className?: string;
514
+ } | {
515
+ kind: "text" | "badge";
516
+ key: string;
517
+ label: ReactNode;
518
+ testId?: string;
519
+ className?: string;
520
+ }>;
521
+ testId?: string;
522
+ className?: string;
523
+ labelClassName?: string;
524
+ /** Canonical server-authorized favorite target for this primary row. */
525
+ favoriteTarget?: FavoriteTarget;
526
+ /** Record identity the host must authorize before rendering a favorite control. */
527
+ favoriteCandidate?: Extract<FavoriteTarget, {
528
+ kind: "record";
529
+ }>;
530
+ /** Set false when this cell links to a related record, not the row record. */
531
+ favoriteable?: boolean;
532
+ }
533
+ export interface ResourceTextCellProps {
534
+ primary: ReactNode;
535
+ secondary?: ReactNode;
536
+ resource?: WorkTabRef;
537
+ onActivate?: (resource: WorkTabRef) => void;
538
+ testId?: string;
539
+ primaryClassName?: string;
540
+ secondaryClassName?: string;
541
+ }
542
+ export interface ResourceRowActionsMenuProps {
543
+ label: string;
544
+ items: readonly ResourceActionDescriptor[];
545
+ testId?: string;
546
+ className?: string;
547
+ }
548
+ export interface ResourceStatusBadgeProps {
549
+ status: string | boolean | null | undefined;
550
+ resourceKey?: string;
551
+ field?: string;
552
+ keyPrefix?: string;
553
+ children?: ReactNode;
554
+ className?: string;
555
+ }
556
+ export type NxActionKind = "view" | "edit" | "create" | "save" | "claim" | "complete" | "unassign" | "reassign" | "retry" | "submit" | "send" | "invite" | "saveDraft" | "cancel" | "close" | "back" | "delete";
557
+ export type NxActionVariant = "primary" | "accent" | "secondary" | "ghost" | "success" | "warning" | "danger" | "dangerGhost";
558
+ export type NxButtonRadius = "full" | "control";
559
+ export interface NxActionButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "aria-label" | "children" | "size"> {
560
+ kind: NxActionKind;
561
+ label?: string;
562
+ loading?: boolean;
563
+ size?: "xs" | "sm" | "md";
564
+ variant?: NxActionVariant;
565
+ }
566
+ export interface NxButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "size"> {
567
+ variant?: NxActionVariant;
568
+ size?: "xs" | "sm" | "md";
569
+ radius?: NxButtonRadius;
570
+ selected?: boolean;
571
+ fullWidth?: boolean;
572
+ selectTrigger?: boolean;
573
+ loading?: boolean;
574
+ leadingIcon?: ReactNode;
575
+ trailingIcon?: ReactNode;
576
+ tooltip?: ReactNode;
577
+ asChild?: boolean;
578
+ truncate?: boolean;
579
+ }
580
+ /** Anchor navigation with the shared NxButton visual contract. */
581
+ export interface NxLinkButtonProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "children" | "href" | "onClick">, Pick<NxButtonProps, "variant" | "size" | "radius" | "selected" | "fullWidth" | "loading" | "leadingIcon" | "trailingIcon" | "truncate"> {
582
+ href: string;
583
+ children: ReactNode;
584
+ onNavigate?: (href: string) => void;
585
+ }
586
+ export interface NxIconButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "aria-label" | "children" | "size"> {
587
+ "aria-label": string;
588
+ children: ReactNode;
589
+ variant?: NxActionVariant;
590
+ size?: "2xs" | "xs" | "sm" | "md";
591
+ radius?: NxButtonRadius;
592
+ selected?: boolean;
593
+ className?: string;
594
+ }
595
+ export interface NxIconLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "aria-label" | "children" | "href" | "onClick" | "size"> {
596
+ href: string;
597
+ "aria-label": string;
598
+ children: ReactNode;
599
+ variant?: NxActionVariant;
600
+ size?: "2xs" | "xs" | "sm" | "md";
601
+ radius?: NxButtonRadius;
602
+ selected?: boolean;
603
+ className?: string;
604
+ }
605
+ export interface NxCheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
606
+ inputSize?: "sm" | "md";
607
+ indeterminate?: boolean;
608
+ label?: string;
609
+ }
610
+ export interface NxRadioGroupProps {
611
+ name?: string;
612
+ value?: string;
613
+ onChange?: (value: string) => void;
614
+ disabled?: boolean;
615
+ "aria-label"?: string;
616
+ "aria-labelledby"?: string;
617
+ orientation?: "vertical" | "horizontal";
618
+ children: ReactNode;
619
+ className?: string;
620
+ }
621
+ export interface NxRadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type" | "value" | "onChange"> {
622
+ /** Card presentation retains the native radio and group selection behavior. */
623
+ variant?: "default" | "card";
624
+ inputSize?: "sm" | "md";
625
+ label?: ReactNode;
626
+ value: string;
627
+ }
628
+ export interface NxDetailRowProps {
629
+ label: ReactNode;
630
+ children: ReactNode;
631
+ className?: string;
632
+ testId?: string;
633
+ }
634
+ export type NxAdaptiveSplitDensity = "compact" | "default";
635
+ export type NxAdaptiveSplitAsideWidth = "narrow" | "default" | "wide";
636
+ export type NxAdaptiveSplitBreakpoint = "compact" | "default" | "wide";
637
+ export interface NxResponsiveRegionProps extends HTMLAttributes<HTMLDivElement> {
638
+ children: ReactNode;
639
+ }
640
+ export interface NxAdaptiveSplitProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
641
+ children: ReactNode;
642
+ containerClassName?: string;
643
+ density?: NxAdaptiveSplitDensity;
644
+ asideWidth?: NxAdaptiveSplitAsideWidth;
645
+ twoColumnAt?: NxAdaptiveSplitBreakpoint;
646
+ }
647
+ export interface NxEmptyViewProps {
648
+ kind: "permission" | "empty" | "noResults" | "notFound" | "error";
649
+ icon?: ReactNode;
650
+ title?: ReactNode;
651
+ description?: ReactNode;
652
+ children?: ReactNode;
653
+ "data-testid"?: string;
654
+ className?: string;
655
+ }
656
+ export type NxFieldGroupProps = HTMLAttributes<HTMLDivElement>;
657
+ export type NxFieldsetProps = FieldsetHTMLAttributes<HTMLFieldSetElement>;
658
+ export type NxFieldLegendProps = HTMLAttributes<HTMLLegendElement>;
659
+ export interface NxFileDropzoneProps {
660
+ accept?: string;
661
+ disabled?: boolean;
662
+ onFile: (file: File) => void;
663
+ prompt: ReactNode;
664
+ browseLabel: string;
665
+ hint?: ReactNode;
666
+ selectedFileName?: string | null;
667
+ inputLabel: string;
668
+ "data-testid"?: string;
669
+ }
670
+ export interface NxOrgChartMember {
671
+ id: string;
672
+ label: string;
673
+ description?: string | null;
674
+ }
675
+ export interface NxOrgChartItem {
676
+ id: string;
677
+ parentId: string | null;
678
+ label: string;
679
+ description?: string | null;
680
+ classification?: string | null;
681
+ meta?: string | null;
682
+ secondaryMeta?: string | null;
683
+ accentColor?: string | null;
684
+ members?: readonly NxOrgChartMember[] | null;
685
+ membersExpanded?: boolean;
686
+ selectable?: boolean;
687
+ }
688
+ export interface NxOrgChartLabels {
689
+ canvas: string;
690
+ focusNode: (label: string) => string;
691
+ clearFocus: string;
692
+ expandSubtree: (label: string) => string;
693
+ collapseSubtree: (label: string) => string;
694
+ showAllMembers: string;
695
+ hideAllMembers: string;
696
+ showMembers: (label: string, count: number) => string;
697
+ hideMembers: (label: string, count: number) => string;
698
+ memberList: (label: string) => string;
699
+ arrangeCards: string;
700
+ resetLayout: string;
701
+ moveCard: (label: string) => string;
702
+ addChild: (label: string) => string;
703
+ addMember: (label: string) => string;
704
+ editColor: (label: string) => string;
705
+ visibleCount: (visible: number, total: number) => string;
706
+ truncated: (limit: number, total: number) => string;
707
+ root: string;
708
+ moveNode: (label: string) => string;
709
+ moveKeyboardHint: string;
710
+ movePreview: (movingLabel: string, parentLabel: string, position: number, total: number) => string;
711
+ }
712
+ /** Read-only App boundary for the host-owned organization chart renderer. */
713
+ export interface NxOrgChartProps {
714
+ items: readonly NxOrgChartItem[];
715
+ searchQuery?: string;
716
+ selectedId?: string | null;
717
+ onSelect?: (id: string) => void;
718
+ labels: NxOrgChartLabels;
719
+ nodeLimit?: number;
720
+ className?: string;
721
+ testId?: string;
722
+ }
723
+ export interface NxFormFieldProps {
724
+ label: ReactNode;
725
+ labelTooltip?: ReactNode;
726
+ children: (context: {
727
+ id: string;
728
+ describedBy?: string;
729
+ invalid: boolean;
730
+ }) => ReactNode;
731
+ help?: ReactNode;
732
+ error?: ReactNode;
733
+ /** Blocks persistence when the owning form enforces the same constraint. */
734
+ required?: boolean;
735
+ /** Does not block Save; marks information needed before the resource is ready to use. */
736
+ readinessRequired?: boolean;
737
+ compact?: boolean;
738
+ className?: string;
739
+ }
740
+ export interface NxFormSectionProps {
741
+ id?: string;
742
+ children: ReactNode;
743
+ onSubmit?: (event: FormEvent<HTMLFormElement>) => void;
744
+ error?: ReactNode;
745
+ actions?: ReactNode;
746
+ destructiveSlot?: ReactNode;
747
+ actionsVariant?: "default" | "wizard";
748
+ placement?: "footer" | "header";
749
+ mirrorBottom?: boolean;
750
+ testId?: string;
751
+ className?: string;
752
+ /**
753
+ * Use `stack` for fields within one section and `section` when the direct
754
+ * children are independent top-level section cards.
755
+ */
756
+ spacing: "stack" | "section";
757
+ contentClassName?: string;
758
+ actionsClassName?: string;
759
+ }
760
+ export interface NxLoadingBlockProps {
761
+ shape: "text" | "members" | "tree";
762
+ label: string;
763
+ lines?: number;
764
+ "data-testid"?: string;
765
+ }
766
+ export interface NxPageFrameProps {
767
+ title?: ReactNode;
768
+ subtitle?: ReactNode;
769
+ showHeader?: boolean;
770
+ actions?: ReactNode;
771
+ /** Compact controls for the current breadcrumb destination. */
772
+ breadcrumbActions?: ReactNode;
773
+ /** Page-owned organization read scope, rendered separately from command actions. */
774
+ organizationScope?: ReactNode;
775
+ breadcrumb?: ReactNode | false;
776
+ currentLabel?: ReactNode;
777
+ sidebar?: ReactNode;
778
+ sidebarLabel?: string;
779
+ maxWidth?: "3xl" | "5xl" | "7xl" | "none";
780
+ children: ReactNode;
781
+ beforeContent?: ReactNode;
782
+ testId?: string;
783
+ }
784
+ export interface NxTabNavItem {
785
+ id: string;
786
+ label: ReactNode;
787
+ badge?: ReactNode;
788
+ testId?: string;
789
+ disabled?: boolean;
790
+ }
791
+ /** Shared underline tab navigation for in-place App workspace sections. */
792
+ export interface NxTabNavProps {
793
+ items: NxTabNavItem[];
794
+ value: string;
795
+ onChange: (id: string) => void;
796
+ "aria-label"?: string;
797
+ className?: string;
798
+ scrollable?: boolean;
799
+ }
800
+ export interface NxSearchFieldProps {
801
+ id?: string;
802
+ name?: string;
803
+ value: string;
804
+ onChange: (value: string) => void;
805
+ placeholder?: string;
806
+ autoFocus?: boolean;
807
+ disabled?: boolean;
808
+ className?: string;
809
+ "aria-label"?: string;
810
+ "data-testid"?: string;
811
+ }
812
+ export interface NxSectionCardProps {
813
+ title?: ReactNode;
814
+ description?: ReactNode;
815
+ actions?: ReactNode;
816
+ headerTestId?: string;
817
+ bodyTestId?: string;
818
+ children: ReactNode;
819
+ className?: string;
820
+ layout?: "default" | "rows" | "fullBleed";
821
+ as?: "section" | "div" | "article";
822
+ bordered?: boolean;
823
+ }
824
+ /** Canonical vertical rhythm for sibling sections outside a route frame. */
825
+ export type NxSectionStackProps = HTMLAttributes<HTMLDivElement>;
826
+ export interface NxSelectOption<TValue extends string | number> {
827
+ value: TValue;
828
+ label: ReactNode;
829
+ disabled?: boolean;
830
+ }
831
+ export interface NxSelectProps<TValue extends string | number> {
832
+ value: TValue | null;
833
+ options: readonly NxSelectOption<TValue>[];
834
+ onChange: (value: TValue) => void;
835
+ placeholder: ReactNode;
836
+ ariaLabel: string;
837
+ id?: string;
838
+ describedBy?: string;
839
+ invalid?: boolean;
840
+ disabled?: boolean;
841
+ fullWidth?: boolean;
842
+ size?: "xs" | "sm" | "md";
843
+ align?: "start" | "end";
844
+ side?: "top" | "bottom" | "left" | "right";
845
+ className?: string;
846
+ contentClassName?: string;
847
+ }
848
+ /** Arrow glyph for a period-over-period change. */
849
+ export type NxStatDeltaDirection = "up" | "down" | "flat";
850
+ /**
851
+ * Whether the change is good, bad, or neither *for this metric*. Kept
852
+ * independent of the direction: a rising defect count is `up`/`negative`.
853
+ */
854
+ export type NxStatDeltaTone = "positive" | "negative" | "neutral";
855
+ export interface NxStatDelta {
856
+ /** Already-formatted change, e.g. `+12`. The caller owns the unit. */
857
+ value: ReactNode;
858
+ direction: NxStatDeltaDirection;
859
+ tone: NxStatDeltaTone;
860
+ /** Sentence for assistive tech, e.g. "12 more than the previous 30 days". */
861
+ srLabel?: string;
862
+ }
863
+ export interface NxOverviewBandCard {
864
+ key: string;
865
+ label: ReactNode;
866
+ /**
867
+ * Raw count; the band applies locale formatting. `undefined` means the
868
+ * figure could not be counted — the band prints the shared empty-cell
869
+ * text rather than a `0`, and an attention card gets no verdict glyph.
870
+ */
871
+ value: number | undefined;
872
+ hint?: ReactNode;
873
+ /** Period-over-period change, where one genuinely exists. */
874
+ delta?: NxStatDelta;
875
+ /** First load only — a figure already on screen must not re-shimmer. */
876
+ loading?: boolean;
877
+ /** Canonical route for the list the card counts. */
878
+ href?: string;
879
+ testId?: string;
880
+ }
881
+ export interface NxOverviewBandProps {
882
+ title: ReactNode;
883
+ description?: ReactNode;
884
+ /**
885
+ * Effective date or timestamp exactly as the API returned it; the band
886
+ * formats it in the reader's locale and the tenant's business timezone.
887
+ * A date-only value prints as a date, a timestamp as a date and time.
888
+ */
889
+ asOf?: Date | string | null;
890
+ /**
891
+ * `attention` bands carry the 0-is-good state glyph on each card:
892
+ * a check when clear, a warning triangle when someone has to act.
893
+ */
894
+ variant?: "attention" | "default";
895
+ /** Band-level control right of the heading — typically a retry. */
896
+ actions?: ReactNode;
897
+ /** An empty list renders nothing — no aspirational empty bands. */
898
+ cards: NxOverviewBandCard[];
899
+ testId?: string;
900
+ }
901
+ export interface NxStatCardProps {
902
+ label: ReactNode;
903
+ value: ReactNode;
904
+ hint?: ReactNode;
905
+ icon?: ReactNode;
906
+ /** Optional — a card counting rows has no previous period to compare. */
907
+ delta?: NxStatDelta;
908
+ /**
909
+ * Data freshness, rendered last so a stale figure cannot read as live.
910
+ * A free slot on this primitive: it takes already-rendered content.
911
+ * Apps should reach for `NxOverviewBand`, which takes the API's raw
912
+ * value and formats it for them.
913
+ */
914
+ asOf?: ReactNode;
915
+ /** Optional canonical route. A static card omits it. */
916
+ href?: string;
917
+ /** Swaps the value for a same-height skeleton (no layout shift). */
918
+ loading?: boolean;
919
+ bordered?: boolean;
920
+ className?: string;
921
+ testId?: string;
922
+ }
923
+ /** Ranges the shell resolves itself. `custom` defers to explicit dates. */
924
+ export type InsightRangePreset = "7d" | "30d" | "90d" | "qtd" | "ytd" | "custom";
925
+ export interface InsightFilterState {
926
+ range: InsightRangePreset;
927
+ /** Resolved inclusive start, `YYYY-MM-DD` — ready to send as a param. */
928
+ from: string;
929
+ /** Resolved inclusive end, `YYYY-MM-DD`. */
930
+ through: string;
931
+ isCustom: boolean;
932
+ }
933
+ export interface InsightFilterControls extends InsightFilterState {
934
+ setRange: (preset: InsightRangePreset) => void;
935
+ /** Switches to `custom` and writes both dates in one URL update. */
936
+ setCustomRange: (from: string, through: string) => void;
937
+ reset: () => void;
938
+ }
939
+ export interface UseInsightFilterStateOptions {
940
+ /** Preset used when the URL says nothing. Default `30d`. */
941
+ defaultRange?: InsightRangePreset;
942
+ /** Query-param namespace for pages holding more than one range. */
943
+ scope?: string;
944
+ /** Reference "today" as `YYYY-MM-DD`; pins the window in tests. */
945
+ today?: string;
946
+ }
947
+ export interface NxInsightFilterBarProps {
948
+ filter: InsightFilterControls;
949
+ /** Presets to offer, in order. Trim when a window makes no sense. */
950
+ presets?: readonly InsightRangePreset[];
951
+ /** App-specific dimension filters. */
952
+ children?: ReactNode;
953
+ testId?: string;
954
+ }
955
+ /** The subset of a react-query result `NxInsightSurface` reads. */
956
+ export interface InsightQueryLike {
957
+ isLoading: boolean;
958
+ isError: boolean;
959
+ isFetching?: boolean;
960
+ refetch?: () => unknown;
961
+ }
962
+ export interface NxInsightSurfaceProps {
963
+ appKey: string;
964
+ title: string;
965
+ subtitle: string;
966
+ context: {
967
+ isLoading: boolean;
968
+ isError: boolean;
969
+ legalEntityPublicId: string | null;
970
+ };
971
+ /** False for a missing permission or a 401/403; neither offers retry. */
972
+ canRead: boolean;
973
+ query: InsightQueryLike;
974
+ /** True when the query succeeded but the window holds nothing. */
975
+ isEmpty?: boolean;
976
+ /** Override the normal-state refresh when one insight owns multiple queries. */
977
+ refresh?: {
978
+ onRefresh: () => void | Promise<void>;
979
+ isRefreshing?: boolean;
980
+ };
981
+ /**
982
+ * Freshness as the API returned it (typically `generated_at`); the
983
+ * surface formats it, so a raw ISO instant never reaches the screen.
984
+ */
985
+ asOf?: ReactNode;
986
+ /** App-owned content rendered before the standard date filter. */
987
+ beforeFilter?: ReactNode;
988
+ filter?: ReactNode;
989
+ stats?: ReactNode;
990
+ chart?: ReactNode;
991
+ chartTitle?: string;
992
+ chartDescription?: string;
993
+ /** A compact `ResourceTable`; omit toolbar and footer for an embedded view. */
994
+ table?: ReactNode;
995
+ tableTitle?: string;
996
+ tableDescription?: string;
997
+ children?: ReactNode;
998
+ actions?: ReactNode;
999
+ organizationScope?: ReactNode;
1000
+ testId?: string;
1001
+ }
1002
+ export interface NxStatusBadgeProps {
1003
+ variant?: "neutral" | "muted" | "accent" | "info" | "success" | "warning" | "error";
1004
+ children: ReactNode;
1005
+ className?: string;
1006
+ testId?: string;
1007
+ }
1008
+ export interface NxTextAreaProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, "size"> {
1009
+ inputSize?: "md" | "lg";
1010
+ mono?: boolean;
1011
+ invalid?: boolean;
1012
+ autoResize?: boolean;
1013
+ resizable?: boolean;
1014
+ }
1015
+ export interface NxTextInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size"> {
1016
+ inputSize?: "md" | "lg";
1017
+ appearance?: "field" | "title";
1018
+ mono?: boolean;
1019
+ invalid?: boolean;
1020
+ }
1021
+ export interface NxDatePickerLabels {
1022
+ calendar: string;
1023
+ clear: string;
1024
+ nextMonth: string;
1025
+ openCalendar: string;
1026
+ previousMonth: string;
1027
+ today: string;
1028
+ }
1029
+ export interface NxDatePickerProps {
1030
+ value: string | null;
1031
+ onChange: (value: string | null) => void;
1032
+ label?: ReactNode;
1033
+ labelTooltip?: ReactNode;
1034
+ "aria-label"?: string;
1035
+ "aria-describedby"?: string;
1036
+ placeholder?: string;
1037
+ min?: string;
1038
+ max?: string;
1039
+ disabled?: boolean;
1040
+ required?: boolean;
1041
+ clearable?: boolean;
1042
+ help?: ReactNode;
1043
+ error?: ReactNode;
1044
+ /** Invalid state supplied by a surrounding form field. */
1045
+ invalid?: boolean;
1046
+ locale?: string;
1047
+ labels?: Partial<NxDatePickerLabels>;
1048
+ id?: string;
1049
+ name?: string;
1050
+ className?: string;
1051
+ "data-testid"?: string;
1052
+ }
1053
+ export interface NxDateRangeValue {
1054
+ start: string | null;
1055
+ end: string | null;
1056
+ }
1057
+ export interface NxDateRangePickerProps {
1058
+ value: NxDateRangeValue;
1059
+ onChange: (value: NxDateRangeValue) => void;
1060
+ label?: ReactNode;
1061
+ labelTooltip?: ReactNode;
1062
+ "aria-label"?: string;
1063
+ "aria-describedby"?: string;
1064
+ invalid?: boolean;
1065
+ placeholder?: string;
1066
+ min?: string;
1067
+ max?: string;
1068
+ disabled?: boolean;
1069
+ required?: boolean;
1070
+ clearable?: boolean;
1071
+ help?: ReactNode;
1072
+ error?: ReactNode;
1073
+ locale?: string;
1074
+ labels?: Partial<NxDatePickerLabels>;
1075
+ id?: string;
1076
+ startName?: string;
1077
+ endName?: string;
1078
+ className?: string;
1079
+ "data-testid"?: string;
1080
+ }
1081
+ export type NxTooltipSide = "top" | "bottom" | "left" | "right";
1082
+ export type NxTooltipAlign = "start" | "center" | "end";
1083
+ export interface NxTooltipProps {
1084
+ content: ReactNode;
1085
+ children: ReactElement;
1086
+ side?: NxTooltipSide;
1087
+ align?: NxTooltipAlign;
1088
+ delay?: number;
1089
+ disabled?: boolean;
1090
+ className?: string;
1091
+ }
1092
+ export interface NxHelpTooltipProps {
1093
+ content: ReactNode;
1094
+ label?: string;
1095
+ side?: NxTooltipSide;
1096
+ align?: NxTooltipAlign;
1097
+ className?: string;
1098
+ }
1099
+ export interface AppRouteFrameProps {
1100
+ appKey: string;
1101
+ title: string;
1102
+ subtitle: string;
1103
+ actions?: ReactNode;
1104
+ /** Page-owned organization read scope, rendered separately from command actions. */
1105
+ organizationScope?: ReactNode;
1106
+ breadcrumbs?: Array<{
1107
+ label: ReactNode;
1108
+ href?: string;
1109
+ current?: boolean;
1110
+ }>;
1111
+ currentLabel?: ReactNode;
1112
+ maxWidth?: "3xl" | "5xl" | "7xl" | "none";
1113
+ testId?: string;
1114
+ children: ReactNode;
1115
+ }
1116
+ /** Host-rendered canonical route inside a management workspace side pane. */
1117
+ export interface NxCanonicalRoutePaneProps {
1118
+ open: boolean;
1119
+ route: string;
1120
+ closeRoute?: string;
1121
+ title: string;
1122
+ onOpenChange: (open: boolean) => void;
1123
+ testId?: string;
1124
+ }
1125
+ export interface WorkSurfaceProps {
1126
+ primary: ReactNode;
1127
+ primaryLabel?: string;
1128
+ inspector?: ReactNode;
1129
+ inspectorTestId?: string;
1130
+ inspectorLabel?: string;
1131
+ resizeLabel?: string;
1132
+ }
1133
+ export interface WorkSectionProps {
1134
+ title?: ReactNode;
1135
+ description?: ReactNode;
1136
+ actions?: ReactNode;
1137
+ children: ReactNode;
1138
+ testId?: string;
1139
+ headerTestId?: string;
1140
+ bodyTestId?: string;
1141
+ className?: string;
1142
+ bodyClassName?: string;
1143
+ layout?: "default" | "rows" | "fullBleed";
1144
+ }
1145
+ export type WorkSurfaceAction = "list" | "show" | "create" | "edit";
1146
+ export interface TabContextActionResult {
1147
+ ok: boolean;
1148
+ message: string;
1149
+ data?: Record<string, unknown>;
1150
+ issues?: string[];
1151
+ }
1152
+ export interface TabContextActionContext {
1153
+ tabId: string;
1154
+ signal?: AbortSignal;
1155
+ }
1156
+ export interface TabContextActionRegistration {
1157
+ type: string;
1158
+ label: string;
1159
+ description?: string;
1160
+ inputSchema?: Record<string, unknown>;
1161
+ run: (payload: Record<string, unknown>, context: TabContextActionContext) => TabContextActionResult | Promise<TabContextActionResult>;
1162
+ }
1163
+ export interface WorkSurfaceLabelInput {
1164
+ action: WorkSurfaceAction;
1165
+ resourceLabel: string;
1166
+ recordLabel?: string | null;
1167
+ }
1168
+ export interface WorkSurfaceLabels {
1169
+ title: string;
1170
+ breadcrumbLabel: string;
1171
+ tabLabel: string;
1172
+ createButtonLabel: string;
1173
+ submitLabel: string | null;
1174
+ }
1175
+ export type ToastSource = "local" | "operation" | "notification" | "agent" | "background" | "system";
1176
+ export interface ToastOptions {
1177
+ description?: string;
1178
+ duration?: number;
1179
+ action?: {
1180
+ label: string;
1181
+ onAction: () => void;
1182
+ };
1183
+ /** Stable, namespaced identity used to refresh instead of duplicate. */
1184
+ dedupeKey?: string;
1185
+ source?: ToastSource;
1186
+ }
1187
+ export interface MessageApi {
1188
+ toast: Record<"info" | "success" | "warning" | "error", (title: string, options?: ToastOptions) => void>;
1189
+ banner: Record<"info" | "success" | "warning" | "error", (title: string, options?: {
1190
+ description?: string;
1191
+ dismissible?: boolean;
1192
+ }) => void>;
1193
+ confirm: (title: string, options?: {
1194
+ description?: string;
1195
+ confirmLabel?: string;
1196
+ cancelLabel?: string;
1197
+ variant?: "default" | "destructive";
1198
+ }) => Promise<boolean>;
1199
+ prompt: (title: string, options?: {
1200
+ description?: string;
1201
+ label?: string;
1202
+ placeholder?: string;
1203
+ defaultValue?: string;
1204
+ inputType?: "text" | "password";
1205
+ maxLength?: number;
1206
+ submitLabel?: string;
1207
+ cancelLabel?: string;
1208
+ required?: boolean;
1209
+ normalizeValue?: (value: string) => string;
1210
+ validate?: (value: string) => string | null;
1211
+ }) => Promise<string | null>;
1212
+ }
1213
+ export interface ListLocateRecord {
1214
+ id: string;
1215
+ label?: string;
1216
+ hint?: string;
1217
+ showUrl?: string;
1218
+ editUrl?: string;
1219
+ }
1220
+ export interface UseRegisterListLocateActionOptions<Row> {
1221
+ actionType: string;
1222
+ label: string;
1223
+ description?: string;
1224
+ enabled: boolean;
1225
+ schema: ResourceListSchema | undefined;
1226
+ params: Pick<ResourceListParamsControls, "setParams" | "perPage">;
1227
+ fetchPage: (params: ResourceListParams) => Promise<{
1228
+ rows: Row[];
1229
+ total: number | null;
1230
+ }>;
1231
+ resolveRow: (row: Row) => ListLocateRecord;
1232
+ onMatch: (row: Row) => void;
1233
+ }
1234
+ export interface OpenResourceWorkTabOptions {
1235
+ route?: string;
1236
+ label?: string;
1237
+ icon?: string;
1238
+ resourceType?: string;
1239
+ resourceId?: string;
1240
+ openInNewTab?: boolean;
1241
+ contextualCreate?: ResourceCreateContinuationTarget;
1242
+ }
1243
+ export type OpenResourceWorkTab = (resource: WorkTabRef, options?: OpenResourceWorkTabOptions) => void;
1244
+ export type PackageSurfaceLoader = () => Promise<{
1245
+ default: ComponentType<Record<never, never>>;
1246
+ }>;
1247
+ /**
1248
+ * Explicit override registration that also carries a *synchronous* route
1249
+ * prefetcher, i.e. one that seeds its queries without first awaiting the
1250
+ * surface chunk.
1251
+ *
1252
+ * A bare loader override still works and stays the default: its module-level
1253
+ * `prefetch` export runs after the chunk resolves, so data loading serializes
1254
+ * behind the chunk download. Supplying `routePrefetcher` moves the data
1255
+ * request onto the same tick as the chunk request.
1256
+ *
1257
+ * Returning `true` marks the route as handled and suppresses the module-level
1258
+ * `prefetch` fallback. Returning `false` — e.g. when the actor lacks the
1259
+ * Permission or a required route param is missing — falls back to the
1260
+ * module-level `prefetch`.
1261
+ *
1262
+ * The prefetcher must not import the surface component module eagerly, or the
1263
+ * surface is pulled into the package entry chunk and code-splitting is lost.
1264
+ */
1265
+ export interface PackageSurfaceOverrideRegistration {
1266
+ load: PackageSurfaceLoader;
1267
+ routePrefetcher?: AppRoutePrefetcher;
1268
+ }
1269
+ export type PackageSurfaceOverride = PackageSurfaceLoader | PackageSurfaceOverrideRegistration;
1270
+ export interface AutoRegisterPackageSurfacesOptions {
1271
+ appPrefix: string;
1272
+ appKey?: string;
1273
+ overview?: PackageSurfaceLoader;
1274
+ surfaces: Record<string, () => Promise<unknown>>;
1275
+ overrides?: Record<string, PackageSurfaceOverride>;
1276
+ }
1277
+ export interface AppRoutePrefetchContext {
1278
+ queryClient: QueryClient;
1279
+ tenantId: string;
1280
+ legalEntityPublicId: string | null;
1281
+ permissions: PermissionsResponse;
1282
+ pathname: string;
1283
+ searchParams: URLSearchParams;
1284
+ routePattern: string;
1285
+ params: Readonly<Record<string, string | undefined>>;
1286
+ }
1287
+ /**
1288
+ * Route-level prefetcher. Resolves to `true` when the route was handled and
1289
+ * the module-level `prefetch` fallback should be skipped.
1290
+ */
1291
+ export type AppRoutePrefetcher = (context: AppRoutePrefetchContext) => Promise<boolean> | boolean;
1292
+ export type FormFieldErrors = Record<string, string>;
1293
+ export interface MutationFormError {
1294
+ formError: string | null;
1295
+ fieldErrors: FormFieldErrors;
1296
+ }
1297
+ export {};