@tailor-platform/app-shell 0.33.0 → 0.34.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.
@@ -20,6 +20,7 @@ import { Menu as Menu_2 } from '@base-ui/react/menu';
20
20
  import * as React_2 from 'react';
21
21
  import { ReactNode } from 'react';
22
22
  import { Select as Select_2 } from '@base-ui/react/select';
23
+ import { StandardSchemaV1 } from '@standard-schema/spec';
23
24
  import { toast } from 'sonner';
24
25
  import { Tooltip as Tooltip_2 } from '@base-ui/react/tooltip';
25
26
  import { useFilter } from 'node_modules/@base-ui/react/esm/combobox/index.parts';
@@ -59,6 +60,15 @@ declare interface ActionItem {
59
60
  * When an action has `loading: true`, the row shows a spinner in the icon slot and is
60
61
  * non-interactive (useful for backend-driven actions: parent sets loading from mutation/request state).
61
62
  *
63
+ * **CommandPalette integration** — Actions that are enabled (not `disabled`,
64
+ * not `loading`, and have an `onClick` handler) are automatically registered
65
+ * to the CommandPalette so users can discover and trigger them via keyboard
66
+ * shortcut. The actions are grouped under the panel's `title`. Registration
67
+ * is cleaned up when the ActionPanel unmounts.
68
+ *
69
+ * NOTE: This component must be rendered inside `AppShell` (which provides
70
+ * `CommandPaletteProvider`). Rendering it outside that tree will throw.
71
+ *
62
72
  * @example
63
73
  * ```tsx
64
74
  * const navigate = useNavigate();
@@ -418,6 +428,10 @@ declare type AuthProviderProps = {
418
428
  * Guard UI component to show when loading or unauthenticated.
419
429
  *
420
430
  * If not provided, children will be just rendered in any auth state.
431
+ *
432
+ * Note: This prop only takes effect when AuthProvider wraps an AppShell
433
+ * component. The guard is rendered by the router's root route element,
434
+ * so it requires RouterContainer to be present in the component tree.
421
435
  */
422
436
  guardComponent?: () => React.ReactNode;
423
437
  };
@@ -459,9 +473,9 @@ export declare const Autocomplete: typeof AutocompleteStandalone & {
459
473
  GroupLabel: typeof AutocompleteGroupLabel;
460
474
  Collection: typeof AutocompleteCollection;
461
475
  Status: AutocompleteStatus;
462
- useFilter: (options?: AutocompleteFilterOptions) => AutocompleteFilter;
463
- useAsync: typeof useAsync_2;
464
476
  };
477
+ useAsync: typeof useAsync_3;
478
+ useFilter: (options?: AutocompleteFilterOptions) => AutocompleteFilter;
465
479
  };
466
480
 
467
481
  /** Fetcher type for `Autocomplete.Async`. */
@@ -492,7 +506,9 @@ declare namespace AutocompleteCollection {
492
506
  var displayName: string;
493
507
  }
494
508
 
495
- declare function AutocompleteContent({ className, ...props }: React_2.ComponentProps<typeof Autocomplete_2.Popup>): JSX.Element;
509
+ declare function AutocompleteContent({ className, container, ...props }: React_2.ComponentProps<typeof Autocomplete_2.Popup> & {
510
+ container?: React_2.ComponentProps<typeof Autocomplete_2.Portal>["container"];
511
+ }): JSX.Element;
496
512
 
497
513
  declare namespace AutocompleteContent {
498
514
  var displayName: string;
@@ -561,6 +577,8 @@ declare interface AutocompletePropsBase<T> {
561
577
  className?: string;
562
578
  /** Whether the autocomplete is disabled */
563
579
  disabled?: boolean;
580
+ /** A parent element to render the portal into (e.g. a modal/drawer ref). */
581
+ container?: React_2.ComponentProps<typeof AutocompleteContent>["container"];
564
582
  /** Current value (controlled) */
565
583
  value?: string;
566
584
  /** Default value (uncontrolled) */
@@ -788,10 +806,10 @@ export declare const Combobox: typeof ComboboxStandalone & {
788
806
  Value: typeof ComboboxValue;
789
807
  Collection: typeof ComboboxCollection;
790
808
  Status: ComboboxStatus;
791
- useFilter: useFilter;
792
- useCreatable: typeof useCreatable;
793
- useAsync: typeof useAsync;
794
809
  };
810
+ useAsync: typeof useAsync_2;
811
+ useFilter: useFilter;
812
+ useCreatable: typeof useCreatable;
795
813
  };
796
814
 
797
815
  declare type ComboboxAsyncCreatableProps<T extends object> = (ComboboxAsyncOwnProps<T> & CreatableProps<T> & Omit<ComboboxPropsSingle<T>, "mapItem">) | (ComboboxAsyncOwnProps<T> & CreatableProps<T> & Omit<ComboboxPropsMultiple<T>, "mapItem">);
@@ -842,7 +860,9 @@ declare namespace ComboboxCollection {
842
860
  var displayName: string;
843
861
  }
844
862
 
845
- declare function ComboboxContent({ className, ...props }: React_2.ComponentProps<typeof Combobox_2.Popup>): JSX.Element;
863
+ declare function ComboboxContent({ className, container, ...props }: React_2.ComponentProps<typeof Combobox_2.Popup> & {
864
+ container?: React_2.ComponentProps<typeof Combobox_2.Portal>["container"];
865
+ }): JSX.Element;
846
866
 
847
867
  declare namespace ComboboxContent {
848
868
  var displayName: string;
@@ -901,6 +921,8 @@ declare interface ComboboxPropsBase<T> {
901
921
  className?: string;
902
922
  /** Whether the combobox is disabled */
903
923
  disabled?: boolean;
924
+ /** A parent element to render the portal into (e.g. a modal/drawer ref). */
925
+ container?: React_2.ComponentProps<typeof ComboboxContent>["container"];
904
926
  }
905
927
 
906
928
  declare interface ComboboxPropsMultiple<T> extends ComboboxPropsBase<T> {
@@ -977,6 +999,30 @@ declare namespace ComboboxValue {
977
999
  */
978
1000
  export declare function CommandPalette(): JSX.Element;
979
1001
 
1002
+ /**
1003
+ * An action entry displayed in the CommandPalette.
1004
+ *
1005
+ * Actions registered via `useRegisterCommandPaletteActions` (or implicitly
1006
+ * through `ActionPanel`) appear in the "Actions" section of the palette and
1007
+ * are searchable by `label`.
1008
+ */
1009
+ export declare type CommandPaletteAction = {
1010
+ /** Unique key for React reconciliation */
1011
+ key: string;
1012
+ /** Visible label shown in the palette (also used for search matching) */
1013
+ label: string;
1014
+ /** Optional icon rendered next to the label */
1015
+ icon?: ReactNode;
1016
+ /**
1017
+ * Group name used to categorise the action (e.g. the ActionPanel title).
1018
+ * When using `useRegisterCommandPaletteActions`, the hook fills this from
1019
+ * its `group` parameter if not already set.
1020
+ */
1021
+ group?: string;
1022
+ /** Callback invoked when the action is selected */
1023
+ onSelect: () => void | Promise<void>;
1024
+ };
1025
+
980
1026
  declare type CommonModuleProps = {
981
1027
  /**
982
1028
  * Resource associated to the module.
@@ -1179,6 +1225,135 @@ export declare function createAuthClient(config: AuthClientConfig): EnhancedAuth
1179
1225
  */
1180
1226
  export declare function createTypedPaths<TRoutes extends Record<string, Record<string, string>>>(): TypedPaths<TRoutes>;
1181
1227
 
1228
+ /** Built-in Standard Schema helpers for common CSV column types. */
1229
+ export declare const csv: {
1230
+ /** Pass-through with optional length constraints. `min: 1` serves as a required check. */
1231
+ string(options?: {
1232
+ min?: number;
1233
+ max?: number;
1234
+ }): StandardSchemaV1<string, string>;
1235
+ /** Coerces the raw CSV string to a number. Rejects `NaN`. */
1236
+ number(options?: {
1237
+ min?: number;
1238
+ max?: number;
1239
+ integer?: boolean;
1240
+ }): StandardSchemaV1<string, number>;
1241
+ /** Coerces common CSV boolean representations to `true`/`false`. Case-insensitive. */
1242
+ boolean(options?: {
1243
+ truthy?: string[];
1244
+ falsy?: string[];
1245
+ }): StandardSchemaV1<string, boolean>;
1246
+ /** Coerces the raw CSV string to a `Date` object. Rejects unparseable values. */
1247
+ date(): StandardSchemaV1<string, Date>;
1248
+ /** Validates the value is one of the allowed strings. Case-sensitive. */
1249
+ enum<T extends string>(values: T[]): StandardSchemaV1<string, T>;
1250
+ };
1251
+
1252
+ /** A single cell-level issue found during validation. */
1253
+ export declare type CsvCellIssue = {
1254
+ /** 0-based row index. */
1255
+ rowIndex: number;
1256
+ /** The schema column key. */
1257
+ columnKey: string;
1258
+ /** "error" blocks import; "warning" allows import but shows a warning. */
1259
+ level: "error" | "warning";
1260
+ /** Human-readable message. */
1261
+ message: string;
1262
+ };
1263
+
1264
+ /** Schema definition for a single column in the CSV. */
1265
+ export declare type CsvColumn = {
1266
+ /** Internal key — becomes the object key in import results. */
1267
+ key: string;
1268
+ /** Display label shown in the mapping UI. */
1269
+ label: string;
1270
+ /** Optional description shown as a hint in the mapping UI. */
1271
+ description?: string;
1272
+ /** Whether this column must be mapped (default: false). */
1273
+ required?: boolean;
1274
+ /** Alternative CSV header names for automatic matching. */
1275
+ aliases?: readonly string[];
1276
+ /**
1277
+ * A Standard Schema-compatible validator for this column.
1278
+ * Handles both coercion (transform) and validation in a single declaration.
1279
+ * The raw CSV string is passed to `schema["~standard"].validate(value)`.
1280
+ * On success, the output value is used for the parsed row.
1281
+ * On failure, each issue is rendered as a cell error in the Review table.
1282
+ *
1283
+ * @see https://github.com/standard-schema/standard-schema
1284
+ */
1285
+ schema?: StandardSchemaV1;
1286
+ };
1287
+
1288
+ /** A mapping from a CSV header to a schema column key. */
1289
+ export declare type CsvColumnMapping = {
1290
+ /** The header name from the CSV file. */
1291
+ csvHeader: string;
1292
+ /** The schema column key to map to, or null to skip this column. */
1293
+ columnKey: string | null;
1294
+ };
1295
+
1296
+ /** A single correction made by the user in the review step. */
1297
+ export declare type CsvCorrection = {
1298
+ /** 0-based row index. */
1299
+ row: number;
1300
+ /** The schema column key. */
1301
+ columnKey: string;
1302
+ /** The value before correction. */
1303
+ oldValue: unknown;
1304
+ /** The value after correction. */
1305
+ newValue: unknown;
1306
+ };
1307
+
1308
+ export declare function CsvImporter<T extends CsvSchema>({ open, onOpenChange, schema, maxFileSize, onImport, onValidate, }: CsvImporterProps<T>): JSX.Element;
1309
+
1310
+ /** Internal props for the CsvImporter component (managed by useCsvImporter). */
1311
+ declare type CsvImporterProps<T extends CsvSchema = CsvSchema> = {
1312
+ open: boolean;
1313
+ onOpenChange: (open: boolean) => void;
1314
+ schema: T;
1315
+ maxFileSize: number;
1316
+ onImport: (event: CsvImportEvent<T>) => void | Promise<void>;
1317
+ onValidate?: (rows: ParsedRow[]) => Promise<CsvCellIssue[]>;
1318
+ };
1319
+
1320
+ /** The event payload passed to the onImport callback. */
1321
+ export declare type CsvImportEvent<T extends CsvSchema = CsvSchema> = {
1322
+ /** The original file selected by the user. */
1323
+ file: File;
1324
+ /** The confirmed column mappings. */
1325
+ mappings: CsvColumnMapping[];
1326
+ /** The corrections made by the user in the review step. */
1327
+ corrections: CsvCorrection[];
1328
+ /** Any remaining issues (warnings only — errors are resolved before import). */
1329
+ issues: CsvCellIssue[];
1330
+ /** Summary statistics. */
1331
+ summary: {
1332
+ /** Total number of data rows in the CSV (excluding the header row). */
1333
+ totalRows: number;
1334
+ /** Rows with no warning-level issues. */
1335
+ validRows: number;
1336
+ /** Distinct rows where the user made at least one correction. */
1337
+ correctedRows: number;
1338
+ /** Rows that were skipped during import. */
1339
+ skippedRows: number;
1340
+ /** Rows that have at least one warning-level issue. */
1341
+ warningRows: number;
1342
+ };
1343
+ /**
1344
+ * Reconstruct parsed rows from the original file, applying mappings,
1345
+ * schema coercion, and user corrections.
1346
+ *
1347
+ * The return type is inferred from the schema definition.
1348
+ */
1349
+ buildRows: () => Promise<InferCsvRow<T>[]>;
1350
+ };
1351
+
1352
+ /** The full schema definition for a CSV import. */
1353
+ export declare type CsvSchema = {
1354
+ columns: readonly CsvColumn[];
1355
+ };
1356
+
1182
1357
  /**
1183
1358
  * Date format options
1184
1359
  */
@@ -2054,6 +2229,17 @@ declare namespace Image_2 {
2054
2229
  var displayName: string;
2055
2230
  }
2056
2231
 
2232
+ /**
2233
+ * Infer the row object type from a CsvSchema definition.
2234
+ * Each column key becomes a property; the value type is derived from the
2235
+ * column's Standard Schema output type (falls back to `unknown`).
2236
+ */
2237
+ export declare type InferCsvRow<T extends CsvSchema> = {
2238
+ [C in T["columns"][number] as C["key"]]: C extends {
2239
+ schema: StandardSchemaV1<infer _I, infer O>;
2240
+ } ? O : unknown;
2241
+ };
2242
+
2057
2243
  /**
2058
2244
  * A styled input component.
2059
2245
  *
@@ -2383,6 +2569,14 @@ export declare type PageMeta = {
2383
2569
  icon?: ReactNode;
2384
2570
  };
2385
2571
 
2572
+ /** The row data passed to `onValidate`, after transforms have been applied. */
2573
+ export declare type ParsedRow = {
2574
+ /** 0-based row index, stable across edits. */
2575
+ rowIndex: number;
2576
+ /** Column key → transformed value. Only mapped columns are included. */
2577
+ data: Record<string, unknown>;
2578
+ };
2579
+
2386
2580
  /**
2387
2581
  * Allow access to the route. Continue to next guard or render component.
2388
2582
  *
@@ -2738,6 +2932,7 @@ export declare const Select: typeof SelectStandalone & {
2738
2932
  GroupLabel: typeof SelectGroupLabel;
2739
2933
  Separator: SelectSeparator;
2740
2934
  };
2935
+ useAsync: typeof useAsync;
2741
2936
  };
2742
2937
 
2743
2938
  /**
@@ -2777,7 +2972,9 @@ declare type SelectAsyncProps<T> = (SelectAsyncOwnProps<T> & SelectPropsSingle<T
2777
2972
 
2778
2973
  declare function SelectAsyncStandalone<T>(props: SelectAsyncProps<T>): JSX.Element;
2779
2974
 
2780
- declare function SelectContent({ className, ...props }: React_2.ComponentProps<typeof Select_2.Popup>): JSX.Element;
2975
+ declare function SelectContent({ className, container, ...props }: React_2.ComponentProps<typeof Select_2.Popup> & {
2976
+ container?: React_2.ComponentProps<typeof Select_2.Portal>["container"];
2977
+ }): JSX.Element;
2781
2978
 
2782
2979
  declare namespace SelectContent {
2783
2980
  var displayName: string;
@@ -2810,6 +3007,8 @@ declare interface SelectPropsBase<T> {
2810
3007
  className?: string;
2811
3008
  /** Whether the select is disabled */
2812
3009
  disabled?: boolean;
3010
+ /** A parent element to render the portal into (e.g. a modal/drawer ref). */
3011
+ container?: React_2.ComponentProps<typeof SelectContent>["container"];
2813
3012
  }
2814
3013
 
2815
3014
  declare interface SelectPropsMultiple<T> extends SelectPropsBase<T> {
@@ -3328,6 +3527,41 @@ export declare const useAppShellConfig: () => AppShellConfigContextType;
3328
3527
  */
3329
3528
  export declare const useAppShellData: () => AppShellDataContextType;
3330
3529
 
3530
+ /**
3531
+ * Hook that encapsulates the async select pattern — fetching on open,
3532
+ * request cancellation via `AbortController`, and loading/error state.
3533
+ *
3534
+ * Unlike `Combobox.useAsync`, this does **not** involve a search query
3535
+ * or debouncing — Select has no text input. The fetcher is called each
3536
+ * time the dropdown opens.
3537
+ *
3538
+ * @example
3539
+ * ```tsx
3540
+ * const countries = Select.useAsync({
3541
+ * fetcher: async ({ signal }) => {
3542
+ * const res = await fetch("/api/countries", { signal });
3543
+ * return res.json();
3544
+ * },
3545
+ * });
3546
+ *
3547
+ * <Select.Parts.Root
3548
+ * onOpenChange={countries.onOpenChange}
3549
+ * >
3550
+ * <Select.Parts.Trigger>
3551
+ * <Select.Parts.Value placeholder="Select a country" />
3552
+ * </Select.Parts.Trigger>
3553
+ * <Select.Parts.Content>
3554
+ * {countries.loading
3555
+ * ? "Loading..."
3556
+ * : countries.items.map((c) => (
3557
+ * <Select.Parts.Item key={c.id} value={c}>{c.name}</Select.Parts.Item>
3558
+ * ))}
3559
+ * </Select.Parts.Content>
3560
+ * </Select.Parts.Root>
3561
+ * ```
3562
+ */
3563
+ declare function useAsync<T>({ fetcher }: UseSelectAsyncOptions<T>): UseSelectAsyncReturn<T>;
3564
+
3331
3565
  /**
3332
3566
  * Hook that encapsulates the async combobox pattern — debounced fetching,
3333
3567
  * request cancellation via `AbortController`, and loading state.
@@ -3368,7 +3602,7 @@ export declare const useAppShellData: () => AppShellDataContextType;
3368
3602
  * </Combobox.Root>
3369
3603
  * ```
3370
3604
  */
3371
- declare function useAsync<T>(options: UseAsyncItemsOptions<T>): UseAsyncItemsReturn<T>;
3605
+ declare function useAsync_2<T>(options: UseAsyncItemsOptions<T>): UseAsyncItemsReturn<T>;
3372
3606
 
3373
3607
  /**
3374
3608
  * Hook that encapsulates the async autocomplete pattern — debounced fetching,
@@ -3412,7 +3646,7 @@ declare function useAsync<T>(options: UseAsyncItemsOptions<T>): UseAsyncItemsRet
3412
3646
  * </Autocomplete.Root>
3413
3647
  * ```
3414
3648
  */
3415
- declare function useAsync_2<T>(options: UseAsyncItemsOptions<T>): AutocompleteUseAsyncReturn<T>;
3649
+ declare function useAsync_3<T>(options: UseAsyncItemsOptions<T>): AutocompleteUseAsyncReturn<T>;
3416
3650
 
3417
3651
  declare interface UseAsyncItemsOptions<T> {
3418
3652
  /**
@@ -3688,6 +3922,18 @@ declare interface UseCreatableReturnSingle<T> extends UseCreatableReturnBase<T>
3688
3922
  multiple: false;
3689
3923
  }
3690
3924
 
3925
+ export declare function useCsvImporter<const T extends CsvSchema>(options: UseCsvImporterOptions<T>): {
3926
+ open: () => void;
3927
+ props: CsvImporterProps<T>;
3928
+ };
3929
+
3930
+ declare type UseCsvImporterOptions<T extends CsvSchema> = {
3931
+ schema: T;
3932
+ onImport: (event: CsvImportEvent<T>) => void | Promise<void>;
3933
+ onValidate?: (rows: ParsedRow[]) => Promise<CsvCellIssue[]>;
3934
+ maxFileSize?: number;
3935
+ };
3936
+
3691
3937
  export { useLocation }
3692
3938
 
3693
3939
  export { useNavigate }
@@ -3729,10 +3975,49 @@ export declare const usePageMeta: (path: string) => PageMeta | null;
3729
3975
 
3730
3976
  export { useParams }
3731
3977
 
3978
+ /**
3979
+ * Declaratively register contextual actions to the CommandPalette.
3980
+ *
3981
+ * Actions are registered while the calling component is mounted and
3982
+ * automatically unregistered on unmount. Re-registering with new actions
3983
+ * replaces the previous set.
3984
+ *
3985
+ * Note: `icon` changes alone do not trigger re-registration. If you need
3986
+ * dynamic icons, also change the action's `key` or `label`.
3987
+ *
3988
+ * @example
3989
+ * ```tsx
3990
+ * import { useRegisterCommandPaletteActions } from "@tailor-platform/app-shell";
3991
+ *
3992
+ * function MyComponent() {
3993
+ * useRegisterCommandPaletteActions("My Page", [
3994
+ * { key: "refresh", label: "Refresh data", onSelect: () => refetch() },
3995
+ * ]);
3996
+ * }
3997
+ * ```
3998
+ */
3999
+ export declare function useRegisterCommandPaletteActions(group: string, actions: CommandPaletteAction[]): void;
4000
+
3732
4001
  export { useRouteError }
3733
4002
 
3734
4003
  export { useSearchParams }
3735
4004
 
4005
+ declare interface UseSelectAsyncOptions<T> {
4006
+ /** Fetcher for async item loading. Called each time the dropdown is opened. */
4007
+ fetcher: SelectAsyncFetcher<T>;
4008
+ }
4009
+
4010
+ declare interface UseSelectAsyncReturn<T> {
4011
+ /** Fetched items — pass to the Root `items` prop or render manually */
4012
+ items: T[];
4013
+ /** Whether a fetch is currently in-flight */
4014
+ loading: boolean;
4015
+ /** The error thrown by the last fetch, if any */
4016
+ error: unknown;
4017
+ /** Open change handler — pass to the Root `onOpenChange` prop */
4018
+ onOpenChange: (open: boolean) => void;
4019
+ }
4020
+
3736
4021
  export declare const useTheme: () => ThemeProviderState;
3737
4022
 
3738
4023
  export declare const useToast: () => typeof toast;