tempest-react-sdk 0.65.0 → 0.67.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 (157) hide show
  1. package/dist/auth/create-tempest-auth.cjs +1 -1
  2. package/dist/auth/create-tempest-auth.cjs.map +1 -1
  3. package/dist/auth/create-tempest-auth.js +31 -36
  4. package/dist/auth/create-tempest-auth.js.map +1 -1
  5. package/dist/components/BottomSheet/BottomSheet.cjs +1 -1
  6. package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
  7. package/dist/components/BottomSheet/BottomSheet.js +31 -40
  8. package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
  9. package/dist/components/Combobox/Combobox.cjs +1 -1
  10. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  11. package/dist/components/Combobox/Combobox.js +94 -73
  12. package/dist/components/Combobox/Combobox.js.map +1 -1
  13. package/dist/components/Combobox/Combobox.module.cjs +1 -1
  14. package/dist/components/Combobox/Combobox.module.cjs.map +1 -1
  15. package/dist/components/Combobox/Combobox.module.js +4 -3
  16. package/dist/components/Combobox/Combobox.module.js.map +1 -1
  17. package/dist/components/ContextMenu/ContextMenu.cjs +1 -1
  18. package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
  19. package/dist/components/ContextMenu/ContextMenu.js +80 -83
  20. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  21. package/dist/components/Drawer/Drawer.cjs +1 -1
  22. package/dist/components/Drawer/Drawer.cjs.map +1 -1
  23. package/dist/components/Drawer/Drawer.js +43 -46
  24. package/dist/components/Drawer/Drawer.js.map +1 -1
  25. package/dist/components/DropdownMenu/DropdownMenu.cjs +1 -1
  26. package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
  27. package/dist/components/DropdownMenu/DropdownMenu.js +129 -105
  28. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  29. package/dist/components/DropdownMenu/DropdownMenu.module.cjs +1 -1
  30. package/dist/components/DropdownMenu/DropdownMenu.module.cjs.map +1 -1
  31. package/dist/components/DropdownMenu/DropdownMenu.module.js +12 -11
  32. package/dist/components/DropdownMenu/DropdownMenu.module.js.map +1 -1
  33. package/dist/components/HoverCard/HoverCard.cjs +1 -1
  34. package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
  35. package/dist/components/HoverCard/HoverCard.js +54 -29
  36. package/dist/components/HoverCard/HoverCard.js.map +1 -1
  37. package/dist/components/HoverCard/HoverCard.module.cjs +1 -1
  38. package/dist/components/HoverCard/HoverCard.module.cjs.map +1 -1
  39. package/dist/components/HoverCard/HoverCard.module.js +4 -3
  40. package/dist/components/HoverCard/HoverCard.module.js.map +1 -1
  41. package/dist/components/Lightbox/Lightbox.cjs +1 -1
  42. package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
  43. package/dist/components/Lightbox/Lightbox.js +86 -89
  44. package/dist/components/Lightbox/Lightbox.js.map +1 -1
  45. package/dist/components/Menubar/Menubar.cjs +1 -1
  46. package/dist/components/Menubar/Menubar.cjs.map +1 -1
  47. package/dist/components/Menubar/Menubar.js +86 -65
  48. package/dist/components/Menubar/Menubar.js.map +1 -1
  49. package/dist/components/Menubar/Menubar.module.cjs +1 -1
  50. package/dist/components/Menubar/Menubar.module.cjs.map +1 -1
  51. package/dist/components/Menubar/Menubar.module.js +4 -3
  52. package/dist/components/Menubar/Menubar.module.js.map +1 -1
  53. package/dist/components/Modal/Modal.cjs +1 -1
  54. package/dist/components/Modal/Modal.cjs.map +1 -1
  55. package/dist/components/Modal/Modal.js +44 -51
  56. package/dist/components/Modal/Modal.js.map +1 -1
  57. package/dist/components/MultiSelect/MultiSelect.cjs +1 -1
  58. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  59. package/dist/components/MultiSelect/MultiSelect.js +113 -96
  60. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  61. package/dist/components/MultiSelect/MultiSelect.module.cjs +1 -1
  62. package/dist/components/MultiSelect/MultiSelect.module.cjs.map +1 -1
  63. package/dist/components/MultiSelect/MultiSelect.module.js +4 -3
  64. package/dist/components/MultiSelect/MultiSelect.module.js.map +1 -1
  65. package/dist/components/NavigationMenu/NavigationMenu.cjs +1 -1
  66. package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
  67. package/dist/components/NavigationMenu/NavigationMenu.js +83 -61
  68. package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
  69. package/dist/components/NavigationMenu/NavigationMenu.module.cjs +1 -1
  70. package/dist/components/NavigationMenu/NavigationMenu.module.cjs.map +1 -1
  71. package/dist/components/NavigationMenu/NavigationMenu.module.js +4 -3
  72. package/dist/components/NavigationMenu/NavigationMenu.module.js.map +1 -1
  73. package/dist/components/Popover/Popover.cjs +1 -1
  74. package/dist/components/Popover/Popover.cjs.map +1 -1
  75. package/dist/components/Popover/Popover.js +57 -36
  76. package/dist/components/Popover/Popover.js.map +1 -1
  77. package/dist/components/Popover/Popover.module.cjs +1 -1
  78. package/dist/components/Popover/Popover.module.cjs.map +1 -1
  79. package/dist/components/Popover/Popover.module.js +7 -6
  80. package/dist/components/Popover/Popover.module.js.map +1 -1
  81. package/dist/components/Portal/anchor-position.cjs +2 -0
  82. package/dist/components/Portal/anchor-position.cjs.map +1 -0
  83. package/dist/components/Portal/anchor-position.js +99 -0
  84. package/dist/components/Portal/anchor-position.js.map +1 -0
  85. package/dist/components/Portal/escape-layer.cjs +2 -0
  86. package/dist/components/Portal/escape-layer.cjs.map +1 -0
  87. package/dist/components/Portal/escape-layer.js +30 -0
  88. package/dist/components/Portal/escape-layer.js.map +1 -0
  89. package/dist/components/Portal/tab-bridge.cjs +2 -0
  90. package/dist/components/Portal/tab-bridge.cjs.map +1 -0
  91. package/dist/components/Portal/tab-bridge.js +39 -0
  92. package/dist/components/Portal/tab-bridge.js.map +1 -0
  93. package/dist/components/Tooltip/Tooltip.cjs +1 -1
  94. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  95. package/dist/components/Tooltip/Tooltip.js +43 -29
  96. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  97. package/dist/components/Tooltip/Tooltip.module.cjs +1 -1
  98. package/dist/components/Tooltip/Tooltip.module.cjs.map +1 -1
  99. package/dist/components/Tooltip/Tooltip.module.js +4 -3
  100. package/dist/components/Tooltip/Tooltip.module.js.map +1 -1
  101. package/dist/hooks/use-focus-trap.cjs +1 -1
  102. package/dist/hooks/use-focus-trap.cjs.map +1 -1
  103. package/dist/hooks/use-focus-trap.js +2 -2
  104. package/dist/hooks/use-focus-trap.js.map +1 -1
  105. package/dist/hooks/use-sortable.cjs +1 -1
  106. package/dist/hooks/use-sortable.cjs.map +1 -1
  107. package/dist/hooks/use-sortable.js +3 -3
  108. package/dist/hooks/use-sortable.js.map +1 -1
  109. package/dist/http/api-client.cjs +1 -1
  110. package/dist/http/api-client.cjs.map +1 -1
  111. package/dist/http/api-client.js +87 -85
  112. package/dist/http/api-client.js.map +1 -1
  113. package/dist/http/credential-scope.cjs +2 -0
  114. package/dist/http/credential-scope.cjs.map +1 -0
  115. package/dist/http/credential-scope.js +23 -0
  116. package/dist/http/credential-scope.js.map +1 -0
  117. package/dist/http/describe-api-error.cjs +1 -1
  118. package/dist/http/describe-api-error.cjs.map +1 -1
  119. package/dist/http/describe-api-error.js +4 -2
  120. package/dist/http/describe-api-error.js.map +1 -1
  121. package/dist/http/resumable-upload.cjs +1 -1
  122. package/dist/http/resumable-upload.cjs.map +1 -1
  123. package/dist/http/resumable-upload.js +121 -120
  124. package/dist/http/resumable-upload.js.map +1 -1
  125. package/dist/http/upload-with-progress.cjs +1 -1
  126. package/dist/http/upload-with-progress.cjs.map +1 -1
  127. package/dist/http/upload-with-progress.js +35 -34
  128. package/dist/http/upload-with-progress.js.map +1 -1
  129. package/dist/styles/actions.css +3 -0
  130. package/dist/styles/advanced.css +1 -0
  131. package/dist/styles/component/Combobox.css +1 -0
  132. package/dist/styles/component/DropdownMenu.css +1 -0
  133. package/dist/styles/component/HoverCard.css +1 -0
  134. package/dist/styles/component/Menubar.css +1 -0
  135. package/dist/styles/component/MultiSelect.css +1 -0
  136. package/dist/styles/component/NavigationMenu.css +1 -0
  137. package/dist/styles/component/Popover.css +1 -0
  138. package/dist/styles/component/Tooltip.css +1 -0
  139. package/dist/styles/forms.css +2 -0
  140. package/dist/styles/navigation.css +2 -0
  141. package/dist/styles.css +1 -1
  142. package/dist/tempest-react-sdk.cjs +1 -1
  143. package/dist/tempest-react-sdk.d.ts +364 -29
  144. package/dist/tempest-react-sdk.js +335 -333
  145. package/dist/utils/absent.cjs +2 -0
  146. package/dist/utils/absent.cjs.map +1 -0
  147. package/dist/utils/absent.js +12 -0
  148. package/dist/utils/absent.js.map +1 -0
  149. package/dist/utils/format.cjs +1 -1
  150. package/dist/utils/format.cjs.map +1 -1
  151. package/dist/utils/format.js +42 -37
  152. package/dist/utils/format.js.map +1 -1
  153. package/dist/utils/numbers.cjs +1 -1
  154. package/dist/utils/numbers.cjs.map +1 -1
  155. package/dist/utils/numbers.js +14 -12
  156. package/dist/utils/numbers.js.map +1 -1
  157. package/package.json +1 -1
@@ -99,6 +99,17 @@ import { useWatch } from 'react-hook-form';
99
99
  import { WheelEventHandler } from 'react';
100
100
  import { z } from 'zod';
101
101
 
102
+ /**
103
+ * What every formatter prints when it has nothing to print.
104
+ *
105
+ * An em dash rather than an empty string, because in a table those are two
106
+ * different claims: a blank cell reads as "this column does not apply here",
107
+ * while `—` reads as "this value is missing". `formatDurationMs` in `/perf` has
108
+ * answered this way since it shipped, and `formatPercent` joined it in 0.65.0;
109
+ * this constant is what stops the third answer from appearing.
110
+ */
111
+ export declare const ABSENT_TEXT = "\u2014";
112
+
102
113
  /**
103
114
  * A pluggable access-control strategy. Implementations decide whether a given
104
115
  * action is allowed, returning a plain boolean, a {@link CanResult}, or a
@@ -652,6 +663,25 @@ export declare interface ApiClientConfig {
652
663
  prefix?: string;
653
664
  /** Returns the current bearer token (or null/undefined). Called per request. */
654
665
  getToken?: () => string | null | undefined;
666
+ /**
667
+ * Origins besides `baseURL`'s that may receive the `getToken` credential.
668
+ *
669
+ * Since 0.66.0 the bearer token is scoped to the origin of `baseURL`. A
670
+ * request to any other origin still goes out — it just goes without the
671
+ * header. That matters because a path may be an absolute URL, in which case
672
+ * it overrides `baseURL` completely, so the destination of a credentialed
673
+ * request could be decided by a value the app read off the network: a
674
+ * pagination link, a `download_url`, a `Location`.
675
+ *
676
+ * List the second host here when it genuinely needs the API's token — a CDN
677
+ * behind the same identity, a sibling service. An origin compares as an
678
+ * origin (`"https://cdn.acme.com"`), so path and trailing slash are
679
+ * ignored.
680
+ *
681
+ * A relative `baseURL` needs nothing here: a relative target resolves
682
+ * against the document and cannot cross an origin.
683
+ */
684
+ trustedOrigins?: readonly string[];
655
685
  /**
656
686
  * Per-request correlation id sent as the `X-Request-ID` header, matching the
657
687
  * Tempest FastAPI SDK `RequestIDMiddleware`. Defaults to a generated id.
@@ -2922,7 +2952,7 @@ declare interface ColorScaleOptions {
2922
2952
  * Selecting an option fires `onChange(value)`. Typing filters the list.
2923
2953
  * Keyboard: ArrowUp/ArrowDown to navigate, Enter to select, Esc to close.
2924
2954
  */
2925
- export declare function Combobox({ options, value, onChange, label, placeholder, helperText, error, disabled, filter, emptyMessage, className, }: ComboboxProps): JSX.Element;
2955
+ export declare function Combobox({ options, value, onChange, label, placeholder, helperText, error, disabled, filter, emptyMessage, portal, className, }: ComboboxProps): JSX.Element;
2926
2956
 
2927
2957
  export declare interface ComboboxOption {
2928
2958
  value: string;
@@ -2943,6 +2973,16 @@ export declare interface ComboboxProps {
2943
2973
  filter?: (option: ComboboxOption, query: string) => boolean;
2944
2974
  /** Message shown when no option matches. */
2945
2975
  emptyMessage?: string;
2976
+ /**
2977
+ * Render the list in a portal, positioned under the field. Default `true`.
2978
+ *
2979
+ * In flow, an ancestor with `overflow` other than `visible` clips the list —
2980
+ * in the last row of a `DataTable` none of it was visible (measured in Chrome
2981
+ * at 1440 px). In a portal it escapes the clip, takes the field's width,
2982
+ * flips above the field when there is no room below, and follows it on
2983
+ * scroll, resize and when the field or the list changes size.
2984
+ */
2985
+ portal?: boolean;
2946
2986
  className?: string;
2947
2987
  }
2948
2988
 
@@ -3266,8 +3306,17 @@ export declare const CPFInput: ForwardRefExoticComponent<Omit<InputProps, "value
3266
3306
  * a development build, because reading `image/jpeg` as UTF-8 destroyed the bytes
3267
3307
  * on the way in.
3268
3308
  *
3309
+ * **The bearer token is scoped to `baseURL`'s origin** since 0.66.0. A path may
3310
+ * be an absolute URL, which overrides the base entirely, so without a scope the
3311
+ * destination of a credentialed request could come from a value read off the
3312
+ * network. A request to another origin still goes out; it goes without the
3313
+ * header, and a development build says so once. Declare the exceptions in
3314
+ * {@link ApiClientConfig.trustedOrigins}.
3315
+ *
3269
3316
  * **Retries** are off unless you set `retry`. See {@link ApiClientConfig.retry}
3270
- * for the built-in policy; it never replays a write.
3317
+ * for the built-in policy; it never replays a write. A single call overrides it
3318
+ * with {@link RequestOptions.retry}, and opts out of auth entirely with
3319
+ * {@link RequestOptions.skipAuth}.
3271
3320
  *
3272
3321
  * **Logging** is off unless you pass a `logger`. With one, every finished attempt
3273
3322
  * writes a line — `debug` under 400, `warn` from 400 up, plus a `warn` when
@@ -5464,6 +5513,11 @@ export declare function defineRoutes(routes: TempestRouteObject[]): TempestRoute
5464
5513
  * 0. `codes[error.code]` — the sentence you wrote for that exact backend case.
5465
5514
  * Checked first because nothing the funnel derives can beat it, and because a
5466
5515
  * request that never landed carries no `code` for it to shadow.
5516
+ * 0.5. `statuses[error.status]` — the sentence for a whole class of failure,
5517
+ * for the errors that arrive with no useful body. It beats the backend's
5518
+ * `detail`, because a generic line emitted by the framework is worse than the
5519
+ * one the app wrote for that status, and it beats the offline sentence when
5520
+ * the caller maps `0` explicitly.
5467
5521
  * 1. A request that never reached the server — `status === 0`, or a non-API
5468
5522
  * error thrown while the browser reports itself offline — produces the
5469
5523
  * offline sentence. This is the step apps skip, and skipping it renders
@@ -5551,6 +5605,29 @@ export declare interface DescribeApiErrorOptions extends Partial<ApiErrorStrings
5551
5605
  * knew both the backend contract and the screen it lands on.
5552
5606
  */
5553
5607
  codes?: Readonly<Record<string, string>>;
5608
+ /**
5609
+ * Maps an HTTP status to a sentence, for the failures that arrive with no
5610
+ * useful body.
5611
+ *
5612
+ * `codes` covers the cases the backend named; this covers the ones it did
5613
+ * not. The reference case is the `403` of an admin-only route: the body
5614
+ * carries a generic `detail` (or none), so the funnel fell through to the
5615
+ * fallback and an administrator read "Não foi possível carregar" when the
5616
+ * fact that answers their question is "esta listagem é só para
5617
+ * administradores".
5618
+ *
5619
+ * Checked after `codes` and **before** the backend's `detail`: a generic
5620
+ * sentence emitted by the framework is worse than the one the app wrote for
5621
+ * that status. `useDetail: false` remains the way to suppress `detail`
5622
+ * entirely.
5623
+ *
5624
+ * A `0` key is honoured like any other, ahead of the offline sentence —
5625
+ * `statuses` is the caller's explicit map, and the fixed `offline` string is
5626
+ * already the way to reword that case. Status `0` covers a request that
5627
+ * never landed **and** one abandoned by the client timeout, so an app that
5628
+ * maps it is taking both.
5629
+ */
5630
+ statuses?: Readonly<Record<number, string>>;
5554
5631
  /**
5555
5632
  * Whether the backend's `detail` may be shown when no `code` matched.
5556
5633
  * Default `true`.
@@ -5755,13 +5832,17 @@ export declare interface DrawerProps {
5755
5832
  * - `ArrowUp` / `ArrowDown` move with wrap, `Home` / `End` jump to the ends.
5756
5833
  * - `Escape` closes and returns focus to the trigger, so the next `Tab` continues
5757
5834
  * from where the user was rather than from the top of the document.
5758
- * - `Tab` closes the menu and lets the page's own tab order take over.
5835
+ * - `Tab` closes the menu and lets the page's own tab order take over, counted
5836
+ * from the trigger: focus goes back to the trigger synchronously and the key's
5837
+ * default action then moves on from there. Without that, a portalled menu —
5838
+ * the last thing in `body` — would hand `Tab` to whatever follows it, which
5839
+ * inside a `Modal` is outside the dialog.
5759
5840
  * - Focus is managed: entries carry `tabIndex={-1}` and only the active one is
5760
5841
  * `0`, which is what stops `Tab` from walking the menu one entry at a time.
5761
5842
  *
5762
5843
  * Disabled entries, separators and labels are skipped by every movement.
5763
5844
  */
5764
- export declare function DropdownMenu({ trigger, items, placement, className, }: DropdownMenuProps): JSX.Element;
5845
+ export declare function DropdownMenu({ trigger, items, placement, portal, className, }: DropdownMenuProps): JSX.Element;
5765
5846
 
5766
5847
  export declare type DropdownMenuEntry = {
5767
5848
  type: "item";
@@ -5809,6 +5890,23 @@ export declare interface DropdownMenuProps {
5809
5890
  }>;
5810
5891
  items: DropdownMenuEntry[];
5811
5892
  placement?: DropdownMenuPlacement;
5893
+ /**
5894
+ * Render the menu in a portal, positioned against the trigger. Default `true`.
5895
+ *
5896
+ * Without it the menu is `position: absolute` inside the trigger's wrapper,
5897
+ * and any ancestor with `overflow` other than `visible` clips it. The ordinary
5898
+ * victim is the action column of a `DataTable`: its wrapper scrolls
5899
+ * horizontally, `overflow-x: auto` forces `overflow-y` to `auto` too, and the
5900
+ * menu of the last row showed one of three entries (measured in Chrome at
5901
+ * 1440 px). In a portal the menu escapes the clip, flips above the trigger
5902
+ * when there is no room below, and follows the trigger on scroll and resize.
5903
+ *
5904
+ * The portalled menu stacks at `--tempest-z-popover`, above
5905
+ * `--tempest-z-modal`, so a menu opened inside a `Modal` still paints on top.
5906
+ * `false` keeps the in-flow menu, for a container that must own the menu's
5907
+ * stacking or clipping on purpose.
5908
+ */
5909
+ portal?: boolean;
5812
5910
  className?: string;
5813
5911
  }
5814
5912
 
@@ -6443,13 +6541,19 @@ export declare interface FormActionsProps extends HTMLAttributes<HTMLDivElement>
6443
6541
  * controls the fractional digits for scaled units (default 1); `0` bytes
6444
6542
  * always renders as `"0 B"`.
6445
6543
  *
6544
+ * An absent or unrepresentable count renders as `"—"`. It used to render as
6545
+ * **`"NaN undefined"`**: `Math.log(NaN)` walks the exponent off the end of the
6546
+ * unit table, so the unit itself came out `undefined` — the size was not merely
6547
+ * unreadable, it claimed a unit that does not exist.
6548
+ *
6446
6549
  * @example
6447
6550
  * formatBytes(0); // "0 B"
6448
6551
  * formatBytes(1536); // "1.5 KB"
6449
6552
  * formatBytes(1048576); // "1 MB"
6450
6553
  * formatBytes(1536, 2); // "1.50 KB"
6554
+ * formatBytes(null); // "—"
6451
6555
  */
6452
- export declare function formatBytes(bytes: number, decimals?: number): string;
6556
+ export declare function formatBytes(bytes: number | null | undefined, decimals?: number, options?: FormatFallbackOptions): string;
6453
6557
 
6454
6558
  /** Format an 11-digit Brazilian CEP-like value as `00000-000`. */
6455
6559
  export declare function formatCEP(value: string): string;
@@ -6463,12 +6567,17 @@ export declare function formatCNPJ(value: string): string;
6463
6567
  * Wraps `Intl.NumberFormat` with `notation: "compact"`. The `locale` defaults
6464
6568
  * to `"en-US"`.
6465
6569
  *
6570
+ * An absent or unrepresentable value renders as `"—"`. The `null` case is the
6571
+ * one that matters: `Intl` coerces it to zero, so a count the backend left out
6572
+ * used to read as **`"0"`** — a number the reader has no reason to doubt.
6573
+ *
6466
6574
  * @example
6467
6575
  * formatCompactNumber(1234); // "1.2K"
6468
6576
  * formatCompactNumber(5600000); // "5.6M"
6469
6577
  * formatCompactNumber(1234, "pt-BR"); // "1,2 mil"
6578
+ * formatCompactNumber(null); // "—"
6470
6579
  */
6471
- export declare function formatCompactNumber(value: number, locale?: string): string;
6580
+ export declare function formatCompactNumber(value: number | null | undefined, locale?: string, options?: FormatFallbackOptions): string;
6472
6581
 
6473
6582
  /**
6474
6583
  * Apply the Brazilian CPF mask `XXX.XXX.XXX-XX`.
@@ -6481,18 +6590,50 @@ export declare function formatCPF(value: string): string;
6481
6590
  /**
6482
6591
  * Format a number as Brazilian Real currency.
6483
6592
  *
6484
- * @param value - The amount in BRL.
6593
+ * An absent or unrepresentable amount renders as `"—"` rather than as a number.
6594
+ * That branch is a data-correctness fix, not cosmetics: `Intl` coerces `null` to
6595
+ * zero, so an amount the backend left out used to reach the screen as
6596
+ * **`"R$ 0,00"`** — a plausible figure a reader has no way to question — and
6597
+ * `undefined` as `"R$ NaN"`.
6598
+ *
6599
+ * @example
6600
+ * ```typescript
6601
+ * formatCurrency(1234.56); // "R$ 1.234,56"
6602
+ * formatCurrency(null); // "—"
6603
+ * formatCurrency(null, { fallback: "sem valor" }); // "sem valor"
6604
+ * ```
6605
+ *
6606
+ * @param value - The amount in BRL, or `null`/`undefined` when there is none.
6607
+ * @param options - Text to render when there is nothing to format.
6485
6608
  * @returns A locale-formatted string, e.g. "R$ 1.234,56".
6486
6609
  */
6487
- export declare function formatCurrency(value: number): string;
6610
+ export declare function formatCurrency(value: number | null | undefined, options?: FormatFallbackOptions): string;
6488
6611
 
6489
6612
  /**
6490
6613
  * Format an ISO date or Date instance as `dd/MM/yyyy`.
6491
6614
  *
6492
- * @param value - ISO string or Date.
6493
- * @returns Formatted date string, or empty string when input is invalid.
6615
+ * Absent input answers `"—"`. It used to **throw**: `new Date(null)` is epoch and
6616
+ * `null.getTime` is a `TypeError`, so a nullable column — which is every
6617
+ * `deleted_at`, `expires_at` and half the `updated_at` a FastAPI backend sends —
6618
+ * took the screen down instead of rendering a gap.
6619
+ *
6620
+ * A value that is present and unparseable still answers `""`, deliberately: on a
6621
+ * screen that reads a log, "nobody filled this in" and "what they filled in is
6622
+ * broken" are different findings, and the second is the one worth chasing.
6623
+ *
6624
+ * @example
6625
+ * ```typescript
6626
+ * formatDate("2026-05-16T12:00:00Z"); // "16/05/2026"
6627
+ * formatDate(null); // "—"
6628
+ * formatDate("banana"); // ""
6629
+ * ```
6630
+ *
6631
+ * @param value - ISO string, Date, or `null`/`undefined`.
6632
+ * @param options - Text to render when the value is absent.
6633
+ * @returns Formatted date string, the fallback when absent, or empty string when
6634
+ * the value is present and invalid.
6494
6635
  */
6495
- export declare function formatDate(value: string | Date): string;
6636
+ export declare function formatDate(value: string | Date | null | undefined, options?: FormatFallbackOptions): string;
6496
6637
 
6497
6638
  /**
6498
6639
  * Format an ISO date or Date instance as `yyyy-MM-dd`, the value an
@@ -6512,19 +6653,29 @@ export declare function formatDate(value: string | Date): string;
6512
6653
  * @example
6513
6654
  * <input type="date" defaultValue={formatDateForInput(order.createdAt)} />
6514
6655
  *
6515
- * @param value - ISO string or Date.
6656
+ * Absent input answers `""` here — **not** the em dash the reading formatters
6657
+ * use — because that is what an input reads as "no value"; an em dash would
6658
+ * arrive as content the user has to delete before typing a date.
6659
+ *
6660
+ * @param value - ISO string, Date, or `null`/`undefined`.
6661
+ * @param options - Text for an absent value; defaults to `""`.
6516
6662
  * @returns The `yyyy-MM-dd` value, or an empty string when the input is invalid —
6517
6663
  * which is what a date input reads as "no value", unlike `"Invalid Date"`.
6518
6664
  */
6519
- export declare function formatDateForInput(value: string | Date): string;
6665
+ export declare function formatDateForInput(value: string | Date | null | undefined, options?: FormatFallbackOptions): string;
6520
6666
 
6521
6667
  /**
6522
6668
  * Format an ISO date or Date instance as `dd/MM/yyyy HH:mm`.
6523
6669
  *
6524
- * @param value - ISO string or Date.
6525
- * @returns Formatted datetime string, or empty string when input is invalid.
6670
+ * Same contract as {@link formatDate}: absent answers the fallback (`"—"` by
6671
+ * default) instead of throwing, and present-but-invalid answers `""`.
6672
+ *
6673
+ * @param value - ISO string, Date, or `null`/`undefined`.
6674
+ * @param options - Text to render when the value is absent.
6675
+ * @returns Formatted datetime string, the fallback when absent, or empty string
6676
+ * when the value is present and invalid.
6526
6677
  */
6527
- export declare function formatDateTime(value: string | Date): string;
6678
+ export declare function formatDateTime(value: string | Date | null | undefined, options?: FormatFallbackOptions): string;
6528
6679
 
6529
6680
  /**
6530
6681
  * Format an ISO date or Date instance as `yyyy-MM-ddTHH:mm`, the value an
@@ -6556,7 +6707,7 @@ export declare function formatDateTime(value: string | Date): string;
6556
6707
  * invalid — which is what a datetime input reads as "no value", unlike
6557
6708
  * `"Invalid Date"`.
6558
6709
  */
6559
- export declare function formatDateTimeForInput(value: string | Date): string;
6710
+ export declare function formatDateTimeForInput(value: string | Date | null | undefined, options?: FormatFallbackOptions): string;
6560
6711
 
6561
6712
  /**
6562
6713
  * Rendering helpers for the numbers a profiler produces.
@@ -6583,6 +6734,19 @@ export declare function formatDateTimeForInput(value: string | Date): string;
6583
6734
  */
6584
6735
  export declare function formatDurationMs(value: number): string;
6585
6736
 
6737
+ /** The text a formatter falls back to when the value cannot be rendered. */
6738
+ export declare interface FormatFallbackOptions {
6739
+ /**
6740
+ * Text for a value that is absent (`null`/`undefined`) or unrepresentable
6741
+ * (`NaN`, `Infinity`). Defaults to {@link ABSENT_TEXT}.
6742
+ *
6743
+ * The formatters that feed an `<input>` default to `""` instead, because an
6744
+ * input reads an empty string as "no value" and would render an em dash as
6745
+ * content the user has to delete.
6746
+ */
6747
+ fallback?: string;
6748
+ }
6749
+
6586
6750
  /**
6587
6751
  * Format a fraction (0-1) as a percentage.
6588
6752
  *
@@ -6601,10 +6765,10 @@ export declare function formatDurationMs(value: number): string;
6601
6765
  * @param options - Rendering options; `decimals` defaults to 1.
6602
6766
  * @returns Formatted percent string, e.g. "12,5%", or `"—"` for a non-finite input.
6603
6767
  */
6604
- export declare function formatPercent(value: number, options?: FormatPercentOptions): string;
6768
+ export declare function formatPercent(value: number | null | undefined, options?: FormatPercentOptions): string;
6605
6769
 
6606
6770
  /** How {@link formatPercent} renders a fraction. */
6607
- export declare interface FormatPercentOptions {
6771
+ export declare interface FormatPercentOptions extends FormatFallbackOptions {
6608
6772
  /**
6609
6773
  * Decimal places to show, fixed (padded as well as truncated).
6610
6774
  *
@@ -7029,13 +7193,18 @@ export declare function higherVersionWins<T>(local: T | undefined, remote: T, ge
7029
7193
  *
7030
7194
  * - Opens after `openDelay` on `mouseenter`/`focus`.
7031
7195
  * - Closes after `closeDelay` on `mouseleave`/`blur`.
7032
- * - Positioned relative to the trigger via `placement`.
7196
+ * - Positioned relative to the trigger via `placement`, in a portal by default.
7197
+ * - Moving the pointer from the trigger into the card keeps it open: React
7198
+ * dispatches `mouseenter`/`mouseleave` along the component tree, and the
7199
+ * portalled card is still inside the trigger's wrapper there.
7200
+ * - A link or button in the card is the next `Tab` stop after the trigger, as it
7201
+ * was in flow.
7033
7202
  * - The card is rendered as a labelled `role="dialog"` region; the trigger stays keyboard focusable.
7034
7203
  *
7035
7204
  * @param props - The hover card props.
7036
7205
  * @returns The trigger wrapper and the anchored card when open.
7037
7206
  */
7038
- export declare function HoverCard({ trigger, children, openDelay, closeDelay, placement, className, ...rest }: HoverCardProps): JSX.Element;
7207
+ export declare function HoverCard({ trigger, children, openDelay, closeDelay, placement, portal, className, style, ...rest }: HoverCardProps): JSX.Element;
7039
7208
 
7040
7209
  export declare type HoverCardPlacement = "top" | "bottom" | "left" | "right";
7041
7210
 
@@ -7050,6 +7219,15 @@ export declare interface HoverCardProps extends HTMLAttributes<HTMLDivElement> {
7050
7219
  closeDelay?: number;
7051
7220
  /** Where the card is anchored relative to the trigger. Default "bottom". */
7052
7221
  placement?: HoverCardPlacement;
7222
+ /**
7223
+ * Render the card in a portal, positioned against the trigger. Default `true`.
7224
+ *
7225
+ * In flow, an ancestor with `overflow` other than `visible` clips the card — a
7226
+ * user handle in the last row of a `DataTable` showed 17% of it (measured in
7227
+ * Chrome at 1440 px). In a portal it escapes the clip and flips to the
7228
+ * opposite side at the viewport edge.
7229
+ */
7230
+ portal?: boolean;
7053
7231
  }
7054
7232
 
7055
7233
  export declare interface I18n {
@@ -7866,6 +8044,42 @@ declare type IssuePathSegment = PropertyKey | {
7866
8044
  readonly key: PropertyKey;
7867
8045
  };
7868
8046
 
8047
+ /**
8048
+ * Whether a request to `target` may carry the caller's credential.
8049
+ *
8050
+ * The SDK writes `Authorization: Bearer` in three places, and until 0.66.0 none
8051
+ * of them looked at where the request was going. That is only safe while every
8052
+ * target URL is written by the app: a resumable upload takes its URL from the
8053
+ * server's `Location` header, and `createApiClient` lets an absolute path
8054
+ * override `baseURL` entirely, so a URL arriving over the network could decide
8055
+ * which origin received the token — and the file bytes with it.
8056
+ *
8057
+ * Handing an upload off to object storage on another host is ordinary `tus`
8058
+ * deployment, not an attack, which is exactly why the credential must be scoped
8059
+ * rather than the request blocked: the upload still goes through, it just goes
8060
+ * without the API's bearer token.
8061
+ *
8062
+ * Both sides are resolved against the document first, so a relative `baseURL`
8063
+ * or `endpoint` — the shape behind a dev-server or reverse proxy — compares
8064
+ * equal to the absolute URL the request actually goes to. Outside a browsing
8065
+ * context a relative target resolves to nothing and is allowed: there is no
8066
+ * origin for it to cross.
8067
+ *
8068
+ * @param target - The URL the request is about to go to.
8069
+ * @param reference - The origin the credential belongs to, normally the
8070
+ * client's `baseURL` or the upload `endpoint`.
8071
+ * @param trustedOrigins - Extra origins the app declared, for the legitimate
8072
+ * second host: a CDN, a signed upload endpoint.
8073
+ * @returns Whether the credential may be attached.
8074
+ *
8075
+ * @example
8076
+ * isTrustedCredentialTarget("https://api.acme.com/me", "https://api.acme.com");
8077
+ * // true
8078
+ * isTrustedCredentialTarget("https://cdn.other/u/1", "https://api.acme.com");
8079
+ * // false
8080
+ */
8081
+ export declare function isTrustedCredentialTarget(target: string, reference: string, trustedOrigins?: readonly string[]): boolean;
8082
+
7869
8083
  /** True when `value` is a finite latitude in `[-90, 90]`. */
7870
8084
  export declare function isValidLatitude(value: number): boolean;
7871
8085
 
@@ -8870,7 +9084,7 @@ export { MemoryRouter }
8870
9084
  * ]}
8871
9085
  * />
8872
9086
  */
8873
- export declare function Menubar({ menus, className, ...props }: MenubarProps): JSX.Element;
9087
+ export declare function Menubar({ menus, portal, className, ...props }: MenubarProps): JSX.Element;
8874
9088
 
8875
9089
  export declare type MenubarItem = {
8876
9090
  /** Visible label for the action. */
@@ -8895,6 +9109,18 @@ export declare interface MenubarMenu {
8895
9109
  export declare interface MenubarProps extends HTMLAttributes<HTMLDivElement> {
8896
9110
  /** Top-level menus rendered left-to-right. */
8897
9111
  menus: MenubarMenu[];
9112
+ /**
9113
+ * Render the open panel in a portal, positioned under its trigger. Default
9114
+ * `true`.
9115
+ *
9116
+ * In flow, an ancestor with `overflow` other than `visible` clips the panel,
9117
+ * and the SDK's own `Navbar` is one: its `nav` slot scrolls horizontally, and
9118
+ * `overflow-x: auto` forces `overflow-y` to `auto` too — a menu showed
9119
+ * 0% of its panel there (measured in Chrome at 1440 px). In a portal the
9120
+ * panel escapes the clip, flips at the viewport edge, stays in the tab order
9121
+ * right after its trigger, and follows it on scroll and resize.
9122
+ */
9123
+ portal?: boolean;
8898
9124
  }
8899
9125
 
8900
9126
  /**
@@ -9230,7 +9456,7 @@ export declare function moveItem<T>(items: T[], from: number, to: number): T[];
9230
9456
  * Keyboard: ArrowUp/ArrowDown navigate, Enter toggles the active option, Esc
9231
9457
  * closes, Backspace (empty input) pops the last chip.
9232
9458
  */
9233
- export declare function MultiSelect({ options, value, onChange, label, placeholder, helperText, error, disabled, maxItems, filter, emptyMessage, className, }: MultiSelectProps): JSX.Element;
9459
+ export declare function MultiSelect({ options, value, onChange, label, placeholder, helperText, error, disabled, maxItems, filter, emptyMessage, portal, className, }: MultiSelectProps): JSX.Element;
9234
9460
 
9235
9461
  export declare interface MultiSelectOption {
9236
9462
  value: string;
@@ -9254,6 +9480,16 @@ export declare interface MultiSelectProps {
9254
9480
  filter?: (option: MultiSelectOption, query: string) => boolean;
9255
9481
  /** Message shown when no option matches. */
9256
9482
  emptyMessage?: string;
9483
+ /**
9484
+ * Render the list in a portal, positioned under the field. Default `true`.
9485
+ *
9486
+ * In flow, an ancestor with `overflow` other than `visible` clips the list —
9487
+ * in the last row of a `DataTable` none of it was visible (measured in Chrome
9488
+ * at 1440 px). In a portal it escapes the clip, takes the field's width,
9489
+ * flips above the field when there is no room below, and follows it on
9490
+ * scroll, resize and when the field grows a line of chips.
9491
+ */
9492
+ portal?: boolean;
9257
9493
  className?: string;
9258
9494
  }
9259
9495
 
@@ -9317,7 +9553,7 @@ export { NavigateOptions }
9317
9553
  * ]}
9318
9554
  * />
9319
9555
  */
9320
- export declare function NavigationMenu({ items, className, ...props }: NavigationMenuProps): JSX.Element;
9556
+ export declare function NavigationMenu({ items, portal, className, ...props }: NavigationMenuProps): JSX.Element;
9321
9557
 
9322
9558
  export declare interface NavigationMenuItem {
9323
9559
  /** Visible label for the entry. */
@@ -9333,6 +9569,18 @@ export declare interface NavigationMenuItem {
9333
9569
  export declare interface NavigationMenuProps extends HTMLAttributes<HTMLElement> {
9334
9570
  /** Top-level navigation entries. */
9335
9571
  items: NavigationMenuItem[];
9572
+ /**
9573
+ * Render the open panel in a portal, positioned under its trigger. Default
9574
+ * `true`.
9575
+ *
9576
+ * In flow, an ancestor with `overflow` other than `visible` clips the panel,
9577
+ * and the SDK's own `Navbar` is one: its `nav` slot scrolls horizontally, and
9578
+ * `overflow-x: auto` forces `overflow-y` to `auto` too — a submenu showed
9579
+ * 0% of its panel there (measured in Chrome at 1440 px). In a portal the
9580
+ * panel escapes the clip, flips at the viewport edge, stays in the tab order
9581
+ * right after its trigger, and follows it on scroll and resize.
9582
+ */
9583
+ portal?: boolean;
9336
9584
  }
9337
9585
 
9338
9586
  /**
@@ -10846,11 +11094,14 @@ export declare interface PlaySfxOptions {
10846
11094
  export declare function pluralize(count: number, singular: string, plural?: string): string;
10847
11095
 
10848
11096
  /**
10849
- * Lightweight popover. Renders a positioned panel anchored to a trigger,
10850
- * dismissed on outside click / Escape. Does NOT include collision detection
10851
- * or smart positioning — pair with Floating UI if you need that.
11097
+ * Lightweight popover. Renders a panel anchored to a trigger, dismissed on
11098
+ * outside click / Escape.
11099
+ *
11100
+ * Portalled by default, with viewport-aware placement: the panel flips to the
11101
+ * opposite side when the requested one overflows, and is clamped inside the
11102
+ * viewport otherwise.
10852
11103
  */
10853
- export declare function Popover({ trigger, children, placement, open, onOpenChange, defaultOpen, closeOnEsc, closeOnOutsideClick, className, }: PopoverProps): JSX.Element;
11104
+ export declare function Popover({ trigger, children, placement, portal, open, onOpenChange, defaultOpen, closeOnEsc, closeOnOutsideClick, className, }: PopoverProps): JSX.Element;
10854
11105
 
10855
11106
  export declare type PopoverPlacement = "top" | "bottom" | "left" | "right";
10856
11107
 
@@ -10863,6 +11114,16 @@ export declare interface PopoverProps {
10863
11114
  }>;
10864
11115
  children: ReactNode;
10865
11116
  placement?: PopoverPlacement;
11117
+ /**
11118
+ * Render the panel in a portal, positioned against the trigger. Default `true`.
11119
+ *
11120
+ * In flow, any ancestor with `overflow` other than `visible` clips the panel —
11121
+ * inside a `DataTable` cell only 3% of it was visible (measured in Chrome at
11122
+ * 1440 px). In a portal it escapes the clip, flips to the opposite side when
11123
+ * the requested one has no room, and follows the trigger on scroll and resize.
11124
+ * `false` keeps the in-flow panel.
11125
+ */
11126
+ portal?: boolean;
10866
11127
  /** Controlled open state. */
10867
11128
  open?: boolean;
10868
11129
  /** Called when the user toggles or dismisses. */
@@ -11670,6 +11931,38 @@ export declare interface RequestOptions extends Omit<RequestInit, "body"> {
11670
11931
  * a `queryFn` and the request is cancelled on unmount and on refetch.
11671
11932
  */
11672
11933
  signal?: AbortSignal | null;
11934
+ /**
11935
+ * Send this request with no `Authorization` header, and never enter the
11936
+ * refresh-and-replay cycle on a `401`.
11937
+ *
11938
+ * This is what login and refresh need: a route that must not carry the
11939
+ * token it is about to obtain, and whose own `401` must surface rather than
11940
+ * call `refresh()` again — which would recurse. Before 0.66.0 the only way
11941
+ * to get it was a second client, which is why `createTempestAuth` used to
11942
+ * build three.
11943
+ */
11944
+ skipAuth?: boolean;
11945
+ /**
11946
+ * Send the `Authorization` header, but let a `401` surface instead of
11947
+ * refreshing and replaying.
11948
+ *
11949
+ * The narrower half of {@link skipAuth}, for a call that is authenticated
11950
+ * but whose failure the caller wants to see — a token probe, a background
11951
+ * poll that should not fight for the refresh lock.
11952
+ */
11953
+ skipAuthRetry?: boolean;
11954
+ /**
11955
+ * Retry policy for this request, overriding the client's.
11956
+ *
11957
+ * Replaces `config.retry` entirely rather than merging into it, the same
11958
+ * way `config.retry` is read today: a merged `shouldRetry` would silently
11959
+ * combine two policies that were each written to be complete.
11960
+ *
11961
+ * `false` turns retrying off for one call on a client that has it on;
11962
+ * `true` or {@link RetryOptions} turns it on for one call on a client that
11963
+ * does not.
11964
+ */
11965
+ retry?: boolean | RetryOptions;
11673
11966
  /**
11674
11967
  * Override the client's timeout for this request, in milliseconds. `null`
11675
11968
  * disables it, which is the escape hatch for a stream or a long poll.
@@ -11825,6 +12118,18 @@ export declare interface ResumableUploadOptions {
11825
12118
  headers?: Record<string, string>;
11826
12119
  /** Returns the current bearer token, read before each request. */
11827
12120
  getToken?: () => string | null | undefined;
12121
+ /**
12122
+ * Origins besides `endpoint`'s that may receive the `getToken` credential.
12123
+ *
12124
+ * Since 0.66.0 the bearer token is scoped to the origin of `endpoint`, and
12125
+ * the creation response's `Location` no longer decides where it goes. A
12126
+ * server that hands the upload to object storage on another host still
12127
+ * works — the `PATCH` requests simply carry no `Authorization`, which is
12128
+ * what a presigned storage URL expects anyway.
12129
+ *
12130
+ * List the storage origin here when it does need the API's token.
12131
+ */
12132
+ trustedOrigins?: readonly string[];
11828
12133
  /** Send cookies. Default `false`. */
11829
12134
  withCredentials?: boolean;
11830
12135
  /**
@@ -14102,8 +14407,13 @@ export declare type TokenKind = "plain" | "comment" | "string" | "number" | "key
14102
14407
  * Lightweight tooltip. Shows on hover and on focus (keyboard-friendly). Wraps
14103
14408
  * a single child element via `cloneElement`, so the trigger keeps its own ref
14104
14409
  * and props.
14410
+ *
14411
+ * `Escape` hides it without moving the pointer or the focus, which is what
14412
+ * WCAG 2.2 SC 1.4.13 (Content on Hover or Focus) asks of content that appears on
14413
+ * hover. It is an `Escape` layer like the overlays, so inside a `Modal` the first
14414
+ * press hides the tooltip and the second closes the modal.
14105
14415
  */
14106
- export declare function Tooltip({ content, placement, children, disabled, openDelay, }: TooltipProps): JSX.Element;
14416
+ export declare function Tooltip({ content, placement, children, disabled, openDelay, portal, }: TooltipProps): JSX.Element;
14107
14417
 
14108
14418
  export declare type TooltipPlacement = "top" | "bottom" | "left" | "right";
14109
14419
 
@@ -14118,6 +14428,15 @@ export declare interface TooltipProps {
14118
14428
  disabled?: boolean;
14119
14429
  /** Delay (ms) before showing the tooltip. Default: 150. */
14120
14430
  openDelay?: number;
14431
+ /**
14432
+ * Render the bubble in a portal, positioned against the trigger. Default `true`.
14433
+ *
14434
+ * In flow, an ancestor with `overflow` other than `visible` clips the bubble —
14435
+ * a `DataTable` cell cut it 23 px short (measured in Chrome at 1440 px). In a
14436
+ * portal it escapes the clip and flips to the opposite side at the viewport
14437
+ * edge. `false` keeps the in-flow bubble.
14438
+ */
14439
+ portal?: boolean;
14121
14440
  }
14122
14441
 
14123
14442
  /** Convert degrees to radians. */
@@ -14617,6 +14936,22 @@ export declare interface UploadWithProgressOptions {
14617
14936
  headers?: Record<string, string>;
14618
14937
  /** Returns the current bearer token. */
14619
14938
  getToken?: () => string | null | undefined;
14939
+ /**
14940
+ * Origin the `getToken` credential belongs to, normally the API's.
14941
+ *
14942
+ * Unlike `createApiClient`, this helper has no base URL to infer a scope
14943
+ * from — the caller names the destination on every call. Set this when the
14944
+ * `url` can come from somewhere other than your own code (a signed URL the
14945
+ * API handed back, a value from a response body) and the token must not
14946
+ * follow it off-origin. Left unset, the header goes wherever `url` points,
14947
+ * which is the behaviour every version before 0.66.0 had.
14948
+ */
14949
+ credentialOrigin?: string;
14950
+ /**
14951
+ * Extra origins allowed to receive the credential, on top of
14952
+ * {@link credentialOrigin}. Ignored when that one is unset.
14953
+ */
14954
+ trustedOrigins?: readonly string[];
14620
14955
  /** Send cookies. Defaults to false. */
14621
14956
  withCredentials?: boolean;
14622
14957
  /** Called on every `progress` event from the XHR upload channel. */