tempest-react-sdk 0.66.0 → 0.68.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 (232) hide show
  1. package/README.md +97 -93
  2. package/dist/auth/create-tempest-auth.cjs +1 -1
  3. package/dist/auth/create-tempest-auth.cjs.map +1 -1
  4. package/dist/auth/create-tempest-auth.js +41 -40
  5. package/dist/auth/create-tempest-auth.js.map +1 -1
  6. package/dist/components/BottomSheet/BottomSheet.cjs +1 -1
  7. package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
  8. package/dist/components/BottomSheet/BottomSheet.js +35 -40
  9. package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
  10. package/dist/components/Card/Card.module.cjs.map +1 -1
  11. package/dist/components/Card/Card.module.js.map +1 -1
  12. package/dist/components/Combobox/Combobox.cjs +1 -1
  13. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  14. package/dist/components/Combobox/Combobox.js +96 -74
  15. package/dist/components/Combobox/Combobox.js.map +1 -1
  16. package/dist/components/Combobox/Combobox.module.cjs +1 -1
  17. package/dist/components/Combobox/Combobox.module.cjs.map +1 -1
  18. package/dist/components/Combobox/Combobox.module.js +4 -3
  19. package/dist/components/Combobox/Combobox.module.js.map +1 -1
  20. package/dist/components/Command/Command.cjs +1 -1
  21. package/dist/components/Command/Command.js +4 -4
  22. package/dist/components/ContextMenu/ContextMenu.cjs +1 -1
  23. package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
  24. package/dist/components/ContextMenu/ContextMenu.js +80 -83
  25. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  26. package/dist/components/DataTable/DataTable.cjs +1 -1
  27. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  28. package/dist/components/DataTable/DataTable.js +138 -127
  29. package/dist/components/DataTable/DataTable.js.map +1 -1
  30. package/dist/components/DataTable/use-dev-warnings.cjs +1 -1
  31. package/dist/components/DataTable/use-dev-warnings.cjs.map +1 -1
  32. package/dist/components/DataTable/use-dev-warnings.js +5 -3
  33. package/dist/components/DataTable/use-dev-warnings.js.map +1 -1
  34. package/dist/components/Drawer/Drawer.cjs +1 -1
  35. package/dist/components/Drawer/Drawer.cjs.map +1 -1
  36. package/dist/components/Drawer/Drawer.js +46 -46
  37. package/dist/components/Drawer/Drawer.js.map +1 -1
  38. package/dist/components/DropdownMenu/DropdownMenu.cjs +1 -1
  39. package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
  40. package/dist/components/DropdownMenu/DropdownMenu.js +129 -105
  41. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  42. package/dist/components/DropdownMenu/DropdownMenu.module.cjs +1 -1
  43. package/dist/components/DropdownMenu/DropdownMenu.module.cjs.map +1 -1
  44. package/dist/components/DropdownMenu/DropdownMenu.module.js +12 -11
  45. package/dist/components/DropdownMenu/DropdownMenu.module.js.map +1 -1
  46. package/dist/components/FilterPanel/FilterPanel.cjs +2 -0
  47. package/dist/components/FilterPanel/FilterPanel.cjs.map +1 -0
  48. package/dist/components/FilterPanel/FilterPanel.js +75 -0
  49. package/dist/components/FilterPanel/FilterPanel.js.map +1 -0
  50. package/dist/components/FilterPanel/FilterPanel.module.cjs +3 -0
  51. package/dist/components/FilterPanel/FilterPanel.module.cjs.map +1 -0
  52. package/dist/components/FilterPanel/FilterPanel.module.js +12 -0
  53. package/dist/components/FilterPanel/FilterPanel.module.js.map +1 -0
  54. package/dist/components/HoverCard/HoverCard.cjs +1 -1
  55. package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
  56. package/dist/components/HoverCard/HoverCard.js +54 -29
  57. package/dist/components/HoverCard/HoverCard.js.map +1 -1
  58. package/dist/components/HoverCard/HoverCard.module.cjs +1 -1
  59. package/dist/components/HoverCard/HoverCard.module.cjs.map +1 -1
  60. package/dist/components/HoverCard/HoverCard.module.js +4 -3
  61. package/dist/components/HoverCard/HoverCard.module.js.map +1 -1
  62. package/dist/components/Lightbox/Lightbox.cjs +1 -1
  63. package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
  64. package/dist/components/Lightbox/Lightbox.js +84 -87
  65. package/dist/components/Lightbox/Lightbox.js.map +1 -1
  66. package/dist/components/Menubar/Menubar.cjs +1 -1
  67. package/dist/components/Menubar/Menubar.cjs.map +1 -1
  68. package/dist/components/Menubar/Menubar.js +86 -65
  69. package/dist/components/Menubar/Menubar.js.map +1 -1
  70. package/dist/components/Menubar/Menubar.module.cjs +1 -1
  71. package/dist/components/Menubar/Menubar.module.cjs.map +1 -1
  72. package/dist/components/Menubar/Menubar.module.js +4 -3
  73. package/dist/components/Menubar/Menubar.module.js.map +1 -1
  74. package/dist/components/Modal/Modal.cjs +1 -1
  75. package/dist/components/Modal/Modal.cjs.map +1 -1
  76. package/dist/components/Modal/Modal.js +47 -51
  77. package/dist/components/Modal/Modal.js.map +1 -1
  78. package/dist/components/MultiSelect/MultiSelect.cjs +1 -1
  79. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  80. package/dist/components/MultiSelect/MultiSelect.js +113 -96
  81. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  82. package/dist/components/MultiSelect/MultiSelect.module.cjs +1 -1
  83. package/dist/components/MultiSelect/MultiSelect.module.cjs.map +1 -1
  84. package/dist/components/MultiSelect/MultiSelect.module.js +4 -3
  85. package/dist/components/MultiSelect/MultiSelect.module.js.map +1 -1
  86. package/dist/components/NavigationMenu/NavigationMenu.cjs +1 -1
  87. package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
  88. package/dist/components/NavigationMenu/NavigationMenu.js +83 -61
  89. package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
  90. package/dist/components/NavigationMenu/NavigationMenu.module.cjs +1 -1
  91. package/dist/components/NavigationMenu/NavigationMenu.module.cjs.map +1 -1
  92. package/dist/components/NavigationMenu/NavigationMenu.module.js +4 -3
  93. package/dist/components/NavigationMenu/NavigationMenu.module.js.map +1 -1
  94. package/dist/components/Pagination/Pagination.cjs +1 -1
  95. package/dist/components/Pagination/Pagination.cjs.map +1 -1
  96. package/dist/components/Pagination/Pagination.js +31 -30
  97. package/dist/components/Pagination/Pagination.js.map +1 -1
  98. package/dist/components/Popover/Popover.cjs +1 -1
  99. package/dist/components/Popover/Popover.cjs.map +1 -1
  100. package/dist/components/Popover/Popover.js +57 -36
  101. package/dist/components/Popover/Popover.js.map +1 -1
  102. package/dist/components/Popover/Popover.module.cjs +1 -1
  103. package/dist/components/Popover/Popover.module.cjs.map +1 -1
  104. package/dist/components/Popover/Popover.module.js +7 -6
  105. package/dist/components/Popover/Popover.module.js.map +1 -1
  106. package/dist/components/Portal/anchor-position.cjs +2 -0
  107. package/dist/components/Portal/anchor-position.cjs.map +1 -0
  108. package/dist/components/Portal/anchor-position.js +99 -0
  109. package/dist/components/Portal/anchor-position.js.map +1 -0
  110. package/dist/components/Portal/escape-layer.cjs +2 -0
  111. package/dist/components/Portal/escape-layer.cjs.map +1 -0
  112. package/dist/components/Portal/escape-layer.js +30 -0
  113. package/dist/components/Portal/escape-layer.js.map +1 -0
  114. package/dist/components/Portal/tab-bridge.cjs +2 -0
  115. package/dist/components/Portal/tab-bridge.cjs.map +1 -0
  116. package/dist/components/Portal/tab-bridge.js +37 -0
  117. package/dist/components/Portal/tab-bridge.js.map +1 -0
  118. package/dist/components/Select/CaretIcon.cjs +2 -0
  119. package/dist/components/Select/CaretIcon.cjs.map +1 -0
  120. package/dist/components/Select/CaretIcon.js +21 -0
  121. package/dist/components/Select/CaretIcon.js.map +1 -0
  122. package/dist/components/Select/Select.cjs +1 -1
  123. package/dist/components/Select/Select.cjs.map +1 -1
  124. package/dist/components/Select/Select.js +33 -47
  125. package/dist/components/Select/Select.js.map +1 -1
  126. package/dist/components/Select/Select.module.cjs +1 -1
  127. package/dist/components/Select/Select.module.cjs.map +1 -1
  128. package/dist/components/Select/Select.module.js +4 -3
  129. package/dist/components/Select/Select.module.js.map +1 -1
  130. package/dist/components/Select/options.cjs +2 -0
  131. package/dist/components/Select/options.cjs.map +1 -0
  132. package/dist/components/Select/options.js +25 -0
  133. package/dist/components/Select/options.js.map +1 -0
  134. package/dist/components/Sidebar/Sidebar.cjs +1 -1
  135. package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
  136. package/dist/components/Sidebar/Sidebar.js +49 -43
  137. package/dist/components/Sidebar/Sidebar.js.map +1 -1
  138. package/dist/components/Sidebar/active-nav-key.cjs +2 -0
  139. package/dist/components/Sidebar/active-nav-key.cjs.map +1 -0
  140. package/dist/components/Sidebar/active-nav-key.js +22 -0
  141. package/dist/components/Sidebar/active-nav-key.js.map +1 -0
  142. package/dist/components/Tooltip/Tooltip.cjs +1 -1
  143. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  144. package/dist/components/Tooltip/Tooltip.js +43 -29
  145. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  146. package/dist/components/Tooltip/Tooltip.module.cjs +1 -1
  147. package/dist/components/Tooltip/Tooltip.module.cjs.map +1 -1
  148. package/dist/components/Tooltip/Tooltip.module.js +4 -3
  149. package/dist/components/Tooltip/Tooltip.module.js.map +1 -1
  150. package/dist/hooks/tab-sequence.cjs +2 -0
  151. package/dist/hooks/tab-sequence.cjs.map +1 -0
  152. package/dist/hooks/tab-sequence.js +53 -0
  153. package/dist/hooks/tab-sequence.js.map +1 -0
  154. package/dist/hooks/use-deep-memo.cjs +1 -1
  155. package/dist/hooks/use-deep-memo.cjs.map +1 -1
  156. package/dist/hooks/use-deep-memo.js +1 -1
  157. package/dist/hooks/use-deep-memo.js.map +1 -1
  158. package/dist/hooks/use-draft-filters.cjs +2 -0
  159. package/dist/hooks/use-draft-filters.cjs.map +1 -0
  160. package/dist/hooks/use-draft-filters.js +49 -0
  161. package/dist/hooks/use-draft-filters.js.map +1 -0
  162. package/dist/hooks/use-focus-trap.cjs +1 -1
  163. package/dist/hooks/use-focus-trap.cjs.map +1 -1
  164. package/dist/hooks/use-focus-trap.js +31 -34
  165. package/dist/hooks/use-focus-trap.js.map +1 -1
  166. package/dist/hooks/use-sortable.cjs +1 -1
  167. package/dist/hooks/use-sortable.cjs.map +1 -1
  168. package/dist/hooks/use-sortable.js +3 -3
  169. package/dist/hooks/use-sortable.js.map +1 -1
  170. package/dist/http/api-client.cjs +1 -1
  171. package/dist/http/api-client.cjs.map +1 -1
  172. package/dist/http/api-client.js +92 -80
  173. package/dist/http/api-client.js.map +1 -1
  174. package/dist/http/credential-scope.cjs +1 -1
  175. package/dist/http/credential-scope.cjs.map +1 -1
  176. package/dist/http/credential-scope.js +5 -3
  177. package/dist/http/credential-scope.js.map +1 -1
  178. package/dist/http/csrf.cjs +2 -0
  179. package/dist/http/csrf.cjs.map +1 -0
  180. package/dist/http/csrf.js +46 -0
  181. package/dist/http/csrf.js.map +1 -0
  182. package/dist/http/describe-api-error.cjs +1 -1
  183. package/dist/http/describe-api-error.cjs.map +1 -1
  184. package/dist/http/describe-api-error.js +4 -2
  185. package/dist/http/describe-api-error.js.map +1 -1
  186. package/dist/http/resumable-upload.cjs +1 -1
  187. package/dist/http/resumable-upload.cjs.map +1 -1
  188. package/dist/http/resumable-upload.js +131 -123
  189. package/dist/http/resumable-upload.js.map +1 -1
  190. package/dist/http/upload-with-progress.cjs +1 -1
  191. package/dist/http/upload-with-progress.cjs.map +1 -1
  192. package/dist/http/upload-with-progress.js +41 -33
  193. package/dist/http/upload-with-progress.js.map +1 -1
  194. package/dist/query/use-paginated-query.cjs +1 -1
  195. package/dist/query/use-paginated-query.cjs.map +1 -1
  196. package/dist/query/use-paginated-query.js +47 -30
  197. package/dist/query/use-paginated-query.js.map +1 -1
  198. package/dist/styles/FilterPanel.css +2 -0
  199. package/dist/styles/actions.css +3 -0
  200. package/dist/styles/advanced.css +1 -0
  201. package/dist/styles/component/Card.css +1 -1
  202. package/dist/styles/component/Combobox.css +5 -3
  203. package/dist/styles/component/DropdownMenu.css +1 -0
  204. package/dist/styles/component/FilterPanel.css +5 -0
  205. package/dist/styles/component/HoverCard.css +1 -0
  206. package/dist/styles/component/Menubar.css +1 -0
  207. package/dist/styles/component/MultiSelect.css +1 -0
  208. package/dist/styles/component/NavigationMenu.css +1 -0
  209. package/dist/styles/component/Popover.css +1 -0
  210. package/dist/styles/component/Select.css +13 -6
  211. package/dist/styles/component/Tooltip.css +1 -0
  212. package/dist/styles/core.css +4 -4
  213. package/dist/styles/data.css +4 -0
  214. package/dist/styles/forms.css +19 -9
  215. package/dist/styles/identity.css +1 -1
  216. package/dist/styles/manifest.json +6 -0
  217. package/dist/styles/navigation.css +2 -0
  218. package/dist/styles/tokens.css +4 -4
  219. package/dist/styles.css +1 -1
  220. package/dist/tempest-react-sdk.cjs +1 -1
  221. package/dist/tempest-react-sdk.d.ts +805 -35
  222. package/dist/tempest-react-sdk.js +347 -342
  223. package/dist/vite/tempest-csp.cjs +3 -0
  224. package/dist/vite/tempest-csp.cjs.map +1 -0
  225. package/dist/vite/tempest-csp.js +189 -0
  226. package/dist/vite/tempest-csp.js.map +1 -0
  227. package/dist/vite.cjs +1 -1
  228. package/dist/vite.d.ts +145 -0
  229. package/dist/vite.js +2 -1
  230. package/package.json +2 -2
  231. package/template/vite.config.ts +8 -1
  232. package/template-pwa/vite.config.ts +6 -0
@@ -171,6 +171,47 @@ export declare interface AccordionProps {
171
171
  className?: string;
172
172
  }
173
173
 
174
+ /**
175
+ * Resolve which navigation key is active for the current route.
176
+ *
177
+ * A menu whose keys are URLs almost never has a key equal to the pathname —
178
+ * `/dashboard/tips/42` has to highlight `/dashboard/tips`. This picks the
179
+ * **longest key that covers the path on a segment boundary**, which is what fixes
180
+ * the two ways the one-line `keys.find((k) => pathname.startsWith(k))` goes wrong:
181
+ * `/dashboard` stays lit on every screen of the panel (the array order decides),
182
+ * and `/dashboard/tip` lights `/dashboard/tips`.
183
+ *
184
+ * The rules:
185
+ *
186
+ * - Query string and hash are ignored, on both sides.
187
+ * - A trailing slash, on the route or on the key, changes nothing.
188
+ * - `/` is active only on `/` itself, as with react-router's `NavLink`.
189
+ * - The comparison is case-sensitive, as URL paths are.
190
+ * - No match returns `""` — never `undefined`, never a throw — so the result can
191
+ * go straight into a `value` prop.
192
+ *
193
+ * The keys and the pathname have to live in the same space: with a router
194
+ * `basename`, pass `useLocation().pathname` (which has the basename stripped) and
195
+ * keys without it.
196
+ *
197
+ * Framework-agnostic on purpose: it takes a string, so it works with
198
+ * react-router, with `window.location.pathname`, and for `BottomNavigation`,
199
+ * `NavigationRail` or a `Drawer` menu just as for `Sidebar` — which does the same
200
+ * resolution itself with `match="route"`.
201
+ *
202
+ * @param pathname - The current route, e.g. `useLocation().pathname`.
203
+ * @param keys - The navigation keys, each one a URL path.
204
+ * @returns The active key exactly as given in `keys`, or `""` when none covers
205
+ * the route.
206
+ *
207
+ * @example
208
+ * const { pathname } = useLocation();
209
+ * const value = activeNavKey(pathname, ["/dashboard", "/dashboard/tips"]);
210
+ * // "/dashboard/tips/42" → "/dashboard/tips"
211
+ * // "/dashboard/tip" → "/dashboard"
212
+ */
213
+ export declare function activeNavKey(pathname: string, keys: readonly string[]): string;
214
+
174
215
  /**
175
216
  * A conversation with a model: role-based turns, Markdown answers, a reasoning
176
217
  * block, a streaming caret, per-turn actions and a composer that turns into a stop
@@ -518,6 +559,15 @@ export declare type AlertVariant = "neutral" | "info" | "success" | "warning" |
518
559
  /** Every symbology in the spec, used to validate what a detector reports back. */
519
560
  export declare const ALL_BARCODE_FORMATS: readonly BarcodeFormat[];
520
561
 
562
+ /**
563
+ * The value {@link withAllOption} gives its entry, exported so the filter code
564
+ * compares against a name instead of a magic string.
565
+ *
566
+ * @example
567
+ * const where = status === ALL_OPTION_VALUE ? {} : { status };
568
+ */
569
+ export declare const ALL_OPTION_VALUE = "all";
570
+
521
571
  /**
522
572
  * Announce a message to screen readers, from anywhere — a hook, an event handler,
523
573
  * a plain function outside React.
@@ -739,7 +789,6 @@ export declare interface ApiClientConfig {
739
789
  * permission the caller does not have.
740
790
  */
741
791
  retry?: boolean | RetryOptions;
742
- /** Whether to send cookies on cross-origin requests (default: false). */
743
792
  /**
744
793
  * Milliseconds before a request is abandoned. Default `15_000`. `null` turns
745
794
  * it off.
@@ -769,7 +818,32 @@ export declare interface ApiClientConfig {
769
818
  * particular call does not fit either default.
770
819
  */
771
820
  uploadTimeout?: number | null;
821
+ /** Whether to send cookies on cross-origin requests (default: false). */
772
822
  withCredentials?: boolean;
823
+ /**
824
+ * Send a CSRF token on every request that can change state. Off by default.
825
+ *
826
+ * A bearer token is immune to cross-site request forgery because the
827
+ * browser never attaches `Authorization` on its own. A cookie session is
828
+ * not: the browser sends the cookie with a request another site triggers.
829
+ * That is the mode `withCredentials: true` exists for — and before 0.68.0
830
+ * the SDK had no piece of the defense.
831
+ *
832
+ * `true` uses the defaults of `tempest-fastapi-sdk`'s `CSRFMiddleware`:
833
+ * read the `csrf_token` cookie, send it as `X-CSRF-Token`. Pass
834
+ * {@link CsrfOptions} to rename either, or to supply the token yourself.
835
+ *
836
+ * The header goes on `POST`, `PUT`, `PATCH`, `DELETE` and any other
837
+ * non-safe method, never on `GET`/`HEAD`/`OPTIONS`/`TRACE`; only to the
838
+ * origins the bearer token may reach (`baseURL`'s plus
839
+ * {@link trustedOrigins}); on `skipAuth` requests too, because login and
840
+ * refresh are the writes a cookie session exposes; and never over a CSRF
841
+ * header you set yourself.
842
+ *
843
+ * Independent of `withCredentials`: a same-origin app sends its cookies
844
+ * without it, and is exposed the same way.
845
+ */
846
+ csrf?: boolean | CsrfOptions;
773
847
  /** Default headers merged into every request. */
774
848
  headers?: Record<string, string>;
775
849
  /** Optional fetch implementation (defaults to globalThis.fetch). */
@@ -1908,7 +1982,9 @@ export declare interface BottomNavigationProps extends Omit<HTMLAttributes<HTMLE
1908
1982
 
1909
1983
  /**
1910
1984
  * Slide-up modal panel — mobile-style sheet anchored to the bottom edge.
1911
- * Uses portal + safe-area padding + scroll lock.
1985
+ * Uses portal + safe-area padding + scroll lock, and traps keyboard focus in the
1986
+ * sheet like `Modal`: focus enters on open, `Tab` cycles inside and returns to
1987
+ * the opener on close.
1912
1988
  *
1913
1989
  * @example
1914
1990
  * <BottomSheet open={open} onClose={() => setOpen(false)} title="Filters">
@@ -2952,7 +3028,7 @@ declare interface ColorScaleOptions {
2952
3028
  * Selecting an option fires `onChange(value)`. Typing filters the list.
2953
3029
  * Keyboard: ArrowUp/ArrowDown to navigate, Enter to select, Esc to close.
2954
3030
  */
2955
- export declare function Combobox({ options, value, onChange, label, placeholder, helperText, error, disabled, filter, emptyMessage, className, }: ComboboxProps): JSX.Element;
3031
+ export declare function Combobox({ options, value, onChange, label, placeholder, helperText, error, disabled, filter, emptyMessage, portal, className, }: ComboboxProps): JSX.Element;
2956
3032
 
2957
3033
  export declare interface ComboboxOption {
2958
3034
  value: string;
@@ -2973,6 +3049,16 @@ export declare interface ComboboxProps {
2973
3049
  filter?: (option: ComboboxOption, query: string) => boolean;
2974
3050
  /** Message shown when no option matches. */
2975
3051
  emptyMessage?: string;
3052
+ /**
3053
+ * Render the list in a portal, positioned under the field. Default `true`.
3054
+ *
3055
+ * In flow, an ancestor with `overflow` other than `visible` clips the list —
3056
+ * in the last row of a `DataTable` none of it was visible (measured in Chrome
3057
+ * at 1440 px). In a portal it escapes the clip, takes the field's width,
3058
+ * flips above the field when there is no room below, and follows it on
3059
+ * scroll, resize and when the field or the list changes size.
3060
+ */
3061
+ portal?: boolean;
2976
3062
  className?: string;
2977
3063
  }
2978
3064
 
@@ -3303,6 +3389,12 @@ export declare const CPFInput: ForwardRefExoticComponent<Omit<InputProps, "value
3303
3389
  * header, and a development build says so once. Declare the exceptions in
3304
3390
  * {@link ApiClientConfig.trustedOrigins}.
3305
3391
  *
3392
+ * **CSRF** is off unless you set `csrf`. With it, every unsafe request (anything
3393
+ * but `GET`/`HEAD`/`OPTIONS`/`TRACE`) echoes the `csrf_token` cookie in an
3394
+ * `X-CSRF-Token` header — the double-submit contract of `tempest-fastapi-sdk`'s
3395
+ * `CSRFMiddleware` — scoped to the same origins as the bearer token and sent on
3396
+ * `skipAuth` requests too. See {@link ApiClientConfig.csrf}.
3397
+ *
3306
3398
  * **Retries** are off unless you set `retry`. See {@link ApiClientConfig.retry}
3307
3399
  * for the built-in policy; it never replays a write. A single call overrides it
3308
3400
  * with {@link RequestOptions.retry}, and opts out of auth entirely with
@@ -4441,6 +4533,16 @@ export declare interface CreateTempestAuthOptions<TUser> {
4441
4533
  storage?: "local" | "session";
4442
4534
  /** Send cookies (needed when the refresh token lives in an httpOnly cookie). */
4443
4535
  withCredentials?: boolean;
4536
+ /**
4537
+ * CSRF token for every write, forwarded to `createApiClient`'s `csrf`. Off
4538
+ * by default; `true` echoes the `csrf_token` cookie as `X-CSRF-Token`.
4539
+ *
4540
+ * The pair to `withCredentials`: once the refresh token lives in a cookie,
4541
+ * the browser attaches it to a `POST /auth/refresh` that another site
4542
+ * triggers. Login and refresh carry the header too — they go out with
4543
+ * `skipAuth`, and the CSRF header does not follow auth.
4544
+ */
4545
+ csrf?: boolean | CsrfOptions;
4444
4546
  /** Custom fetch implementation (testing / SSR). Defaults to `globalThis.fetch`. */
4445
4547
  fetcher?: typeof fetch;
4446
4548
  /**
@@ -4811,6 +4913,91 @@ export declare interface CredentialsContainerLike {
4811
4913
  }): Promise<Credential | null>;
4812
4914
  }
4813
4915
 
4916
+ /**
4917
+ * The CSRF header a request should carry, or an empty object.
4918
+ *
4919
+ * Every request path in the SDK — `createApiClient`, `uploadWithProgress`,
4920
+ * `createResumableUpload` — asks this function, so the rules are one rule:
4921
+ *
4922
+ * - **Off unless configured.** Without `csrf`, nothing changes.
4923
+ * - **Unsafe methods only.** `GET`, `HEAD`, `OPTIONS` and `TRACE` never carry
4924
+ * it; they must not change state, and a token in a `GET` ends up in logs
4925
+ * and caches for nothing.
4926
+ * - **Never across an origin.** The token follows the same scope as the bearer
4927
+ * credential ({@link isTrustedCredentialTarget}), because a URL can come off
4928
+ * the network — a tus `Location`, a pagination link — and a CSRF token sent
4929
+ * to a third party is a token that third party can replay. Withheld tokens
4930
+ * are reported once per origin in a development build.
4931
+ * - **Your header wins.** A CSRF header you set by hand, in any casing, is
4932
+ * left alone.
4933
+ * - **Independent of auth.** It is sent on `skipAuth` requests too: login and
4934
+ * refresh are exactly the writes a cookie session exposes to forgery.
4935
+ *
4936
+ * Exported for the request you build by hand, so it follows the same rules.
4937
+ *
4938
+ * @example
4939
+ * const headers = csrfHeaders({
4940
+ * method: "POST",
4941
+ * url: "https://api.acme.com/orders",
4942
+ * reference: "https://api.acme.com",
4943
+ * csrf: true,
4944
+ * });
4945
+ * // { "X-CSRF-Token": "<value of the csrf_token cookie>" }
4946
+ *
4947
+ * @param input - The request and the CSRF config.
4948
+ * @returns A header record to spread into the request's headers.
4949
+ */
4950
+ export declare function csrfHeaders(input: CsrfHeadersInput): Record<string, string>;
4951
+
4952
+ /** What {@link csrfHeaders} needs to decide. */
4953
+ export declare interface CsrfHeadersInput {
4954
+ /** The HTTP method of the request. Case-insensitive. */
4955
+ method: string;
4956
+ /** The URL the request is going to. */
4957
+ url: string;
4958
+ /**
4959
+ * The origin the token belongs to, normally the API's `baseURL`. The token
4960
+ * is only sent to this origin or to one listed in `trustedOrigins`.
4961
+ */
4962
+ reference: string;
4963
+ /** The CSRF config. `undefined` or `false` turns the header off. */
4964
+ csrf: boolean | CsrfOptions | undefined;
4965
+ /** Extra origins allowed to receive the token. */
4966
+ trustedOrigins?: readonly string[];
4967
+ /** Headers the caller already set. A CSRF header among them is never replaced. */
4968
+ headers?: HeadersInit;
4969
+ }
4970
+
4971
+ /**
4972
+ * Where the CSRF token comes from and which header carries it.
4973
+ *
4974
+ * The default is the **double-submit cookie**: the server sets a cookie that is
4975
+ * deliberately not `HttpOnly`, the client reads it and echoes the value in a
4976
+ * header, and the server rejects a write whose header does not match the
4977
+ * cookie. A page on another site can make the browser *send* the cookie, but
4978
+ * cannot *read* it, so it cannot write the header.
4979
+ *
4980
+ * The token is read again on every request, so a server that rotates the
4981
+ * cookie is followed without any capture step: the browser's cookie jar is the
4982
+ * store. That is also why there is no "read the token from a response header"
4983
+ * mode — it would depend on `Access-Control-Expose-Headers`, and a missing
4984
+ * expose header fails silently, as a `403` on the second write.
4985
+ */
4986
+ export declare interface CsrfOptions {
4987
+ /** Cookie to read the token from. Default {@link DEFAULT_CSRF_COOKIE_NAME}. */
4988
+ cookieName?: string;
4989
+ /** Header to send the token in. Default {@link DEFAULT_CSRF_HEADER_NAME}. */
4990
+ headerName?: string;
4991
+ /**
4992
+ * Supply the token yourself instead of reading `cookieName`.
4993
+ *
4994
+ * For the cases the cookie cannot serve: an API on another **site**, whose
4995
+ * cookie `document.cookie` cannot see, or a backend that hands the token
4996
+ * out in a response body. Called per request, like `getToken`.
4997
+ */
4998
+ getToken?: () => string | null | undefined;
4999
+ }
5000
+
4814
5001
  /**
4815
5002
  * @tempest-limits param-count — `downloadCsv(rows, columns, "usuarios.csv")` reads
4816
5003
  * in the order the sentence does, and its two trailing parameters have defaults,
@@ -4984,7 +5171,8 @@ export declare interface DataProviderOptions {
4984
5171
  * - Clicking a sortable header cycles asc → desc → unsorted.
4985
5172
  * - Search matches a case-insensitive substring across `searchKeys`
4986
5173
  * (or every string/number column when not provided).
4987
- * - Pagination is hidden when the result fits on a single page.
5174
+ * - Pagination is hidden when the result fits on a single page — unless
5175
+ * `onPageSizeChange` is set, because the footer then carries the size selector.
4988
5176
  * - A column with `editable` renders a button that opens an inline editor;
4989
5177
  * `Enter` commits, `Escape` discards, `Tab` walks to the next editable cell.
4990
5178
  *
@@ -5005,7 +5193,7 @@ export declare interface DataProviderOptions {
5005
5193
  * render without changing behaviour. That is why `exhaustive-deps` is silenced on
5006
5194
  * that dependency array.
5007
5195
  */
5008
- export declare function DataTable<T>({ data, columns, pageSize, searchable, searchKeys, initialSort, rowKey, emptyMessage, onCellChange, editLabels, totalItems, page: controlledPage, onPageChange, manualSort, onSortChange, manualSearch, onSearchChange, loading, className, ...rest }: DataTableProps<T>): JSX.Element;
5196
+ export declare function DataTable<T>({ data, columns, pageSize: pageSizeProp, searchable, searchKeys, initialSort, rowKey, emptyMessage, onCellChange, editLabels, totalItems, page: controlledPage, onPageChange, onPageSizeChange, pageSizeOptions, manualSort, onSortChange, manualSearch, onSearchChange, loading, className, ...rest }: DataTableProps<T>): JSX.Element;
5009
5197
 
5010
5198
  /** Everything a table needs regardless of who owns paging, sorting and searching. */
5011
5199
  export declare interface DataTableBaseProps<T> extends HTMLAttributes<HTMLDivElement> {
@@ -5019,7 +5207,13 @@ export declare interface DataTableBaseProps<T> extends HTMLAttributes<HTMLDivEle
5019
5207
  data: T[];
5020
5208
  /** Column definitions. */
5021
5209
  columns: DataTableColumn<T>[];
5022
- /** Rows per page. Default 10. */
5210
+ /**
5211
+ * Rows per page. Default 10.
5212
+ *
5213
+ * Always read on every render, so it is already a controlled value; what turns
5214
+ * it into a user-facing choice is `onPageSizeChange` (see
5215
+ * {@link DataTablePageSizeProps}), which then makes it required.
5216
+ */
5023
5217
  pageSize?: number;
5024
5218
  /** Render a search input above the table. Default false. */
5025
5219
  searchable?: boolean;
@@ -5131,6 +5325,40 @@ export declare interface DataTableEditLabels {
5131
5325
  /** Input types an editable column can use. */
5132
5326
  export declare type DataTableEditorType = "text" | "number" | "date" | "email" | "tel" | "url";
5133
5327
 
5328
+ /**
5329
+ * The items-per-page selector: owned by the caller, or absent.
5330
+ *
5331
+ * The footer is the SDK's own `Pagination`, which already renders a size
5332
+ * `<select>`; this is the channel that reaches it. Two shapes only, for the same
5333
+ * reason as {@link DataTablePagingProps}: `pageSizeOptions` with no
5334
+ * `onPageSizeChange` is a selector that changes nothing, and `onPageSizeChange`
5335
+ * with no `pageSize` is one whose choice never comes back — the table would keep
5336
+ * counting pages by the default 10 while the selector claims 50. Both are build
5337
+ * errors instead.
5338
+ */
5339
+ export declare type DataTablePageSizeProps = {
5340
+ /** No selector: `pageSize` is fixed by the caller. */
5341
+ onPageSizeChange?: never;
5342
+ /** Nothing to choose from. */
5343
+ pageSizeOptions?: never;
5344
+ } | {
5345
+ /** The size currently shown. Required, since the selector reports and you feed it back. */
5346
+ pageSize: number;
5347
+ /**
5348
+ * Called with the size the user picked. Passing it renders the selector in the
5349
+ * footer, and keeps the footer on screen even when everything fits on one page
5350
+ * — otherwise picking 100 for 40 rows would remove the only control that can
5351
+ * pick 10 again.
5352
+ *
5353
+ * The table also moves back to page 1 (through `onPageChange` when the page
5354
+ * is controlled), after this call. Page 7 of 10-per-page has no meaning at
5355
+ * 100-per-page, and 1 is the only page guaranteed to exist under the new size.
5356
+ */
5357
+ onPageSizeChange: (size: number) => void;
5358
+ /** Sizes offered. Default `[10, 25, 50, 100]`; the current `pageSize` is always included. */
5359
+ pageSizeOptions?: number[];
5360
+ };
5361
+
5134
5362
  /**
5135
5363
  * Paging, as one of the three shapes that actually work.
5136
5364
  *
@@ -5182,10 +5410,10 @@ export declare type DataTablePagingProps = {
5182
5410
  };
5183
5411
 
5184
5412
  /**
5185
- * The table's props: the shared half, plus one valid paging shape and one valid
5186
- * sorting shape.
5413
+ * The table's props: the shared half, plus one valid shape per axis — paging,
5414
+ * page size, sorting and searching.
5187
5415
  */
5188
- export declare type DataTableProps<T> = DataTableBaseProps<T> & DataTablePagingProps & DataTableSortProps<T> & DataTableSearchProps;
5416
+ export declare type DataTableProps<T> = DataTableBaseProps<T> & DataTablePagingProps & DataTablePageSizeProps & DataTableSortProps<T> & DataTableSearchProps;
5189
5417
 
5190
5418
  /**
5191
5419
  * Searching: delegated, and therefore reported, or neither.
@@ -5414,6 +5642,25 @@ export declare const DEFAULT_CHUNK_SIZE: number;
5414
5642
  */
5415
5643
  export declare const DEFAULT_CIRCUITY_FACTOR = 1.3;
5416
5644
 
5645
+ /**
5646
+ * Default cookie the CSRF token is read from.
5647
+ *
5648
+ * Ported from `tempest-fastapi-sdk`'s `CSRF_COOKIE_NAME`
5649
+ * (`tempest_fastapi_sdk/api/middlewares/csrf.py`), which is the cookie its
5650
+ * `make_csrf_token_dependency()` sets and its `CSRFMiddleware` compares against.
5651
+ * Matching it is what lets `csrf: true` work against that backend with no
5652
+ * configuration on either side.
5653
+ */
5654
+ export declare const DEFAULT_CSRF_COOKIE_NAME = "csrf_token";
5655
+
5656
+ /**
5657
+ * Default header the CSRF token is echoed in.
5658
+ *
5659
+ * Ported from `tempest-fastapi-sdk`'s `CSRF_HEADER_NAME`, the header its
5660
+ * `CSRFMiddleware` reads on every unsafe request.
5661
+ */
5662
+ export declare const DEFAULT_CSRF_HEADER_NAME = "X-CSRF-Token";
5663
+
5417
5664
  /** Default ceiling for a per-source or master gain, as a multiplier. */
5418
5665
  export declare const DEFAULT_MAX_GAIN = 3;
5419
5666
 
@@ -5503,6 +5750,11 @@ export declare function defineRoutes(routes: TempestRouteObject[]): TempestRoute
5503
5750
  * 0. `codes[error.code]` — the sentence you wrote for that exact backend case.
5504
5751
  * Checked first because nothing the funnel derives can beat it, and because a
5505
5752
  * request that never landed carries no `code` for it to shadow.
5753
+ * 0.5. `statuses[error.status]` — the sentence for a whole class of failure,
5754
+ * for the errors that arrive with no useful body. It beats the backend's
5755
+ * `detail`, because a generic line emitted by the framework is worse than the
5756
+ * one the app wrote for that status, and it beats the offline sentence when
5757
+ * the caller maps `0` explicitly.
5506
5758
  * 1. A request that never reached the server — `status === 0`, or a non-API
5507
5759
  * error thrown while the browser reports itself offline — produces the
5508
5760
  * offline sentence. This is the step apps skip, and skipping it renders
@@ -5590,6 +5842,29 @@ export declare interface DescribeApiErrorOptions extends Partial<ApiErrorStrings
5590
5842
  * knew both the backend contract and the screen it lands on.
5591
5843
  */
5592
5844
  codes?: Readonly<Record<string, string>>;
5845
+ /**
5846
+ * Maps an HTTP status to a sentence, for the failures that arrive with no
5847
+ * useful body.
5848
+ *
5849
+ * `codes` covers the cases the backend named; this covers the ones it did
5850
+ * not. The reference case is the `403` of an admin-only route: the body
5851
+ * carries a generic `detail` (or none), so the funnel fell through to the
5852
+ * fallback and an administrator read "Não foi possível carregar" when the
5853
+ * fact that answers their question is "esta listagem é só para
5854
+ * administradores".
5855
+ *
5856
+ * Checked after `codes` and **before** the backend's `detail`: a generic
5857
+ * sentence emitted by the framework is worse than the one the app wrote for
5858
+ * that status. `useDetail: false` remains the way to suppress `detail`
5859
+ * entirely.
5860
+ *
5861
+ * A `0` key is honoured like any other, ahead of the offline sentence —
5862
+ * `statuses` is the caller's explicit map, and the fixed `offline` string is
5863
+ * already the way to reword that case. Status `0` covers a request that
5864
+ * never landed **and** one abandoned by the client timeout, so an app that
5865
+ * maps it is taking both.
5866
+ */
5867
+ statuses?: Readonly<Record<number, string>>;
5593
5868
  /**
5594
5869
  * Whether the backend's `detail` may be shown when no `code` matched.
5595
5870
  * Default `true`.
@@ -5754,9 +6029,14 @@ export declare type DocumentVisibility = "visible" | "hidden";
5754
6029
  */
5755
6030
  export declare function downloadCsv<T>(rows: readonly T[], columns: readonly CsvColumn<T>[], fileName?: string, options?: CsvOptions): Promise<void>;
5756
6031
 
6032
+ /** An edit to the draft: a partial object merged over it, or an updater. */
6033
+ export declare type DraftFiltersPatch<T> = Partial<T> | ((draft: T) => T);
6034
+
5757
6035
  /**
5758
6036
  * Sliding side panel. Same building blocks as {@link Modal} but anchored to
5759
- * an edge. Locks body scroll while open.
6037
+ * an edge. Locks body scroll while open, and traps keyboard focus in the panel
6038
+ * the same way `Modal` does: focus enters on open, `Tab` cycles inside (portalled
6039
+ * panels opened from it included) and returns to the opener on close.
5760
6040
  */
5761
6041
  export declare function Drawer({ open, onClose, placement, title, children, footer, closeOnBackdrop, closeOnEsc, hideCloseButton, className, mobilePlacement, showHandle, }: DrawerProps): ReactPortal | null;
5762
6042
 
@@ -5794,13 +6074,17 @@ export declare interface DrawerProps {
5794
6074
  * - `ArrowUp` / `ArrowDown` move with wrap, `Home` / `End` jump to the ends.
5795
6075
  * - `Escape` closes and returns focus to the trigger, so the next `Tab` continues
5796
6076
  * from where the user was rather than from the top of the document.
5797
- * - `Tab` closes the menu and lets the page's own tab order take over.
6077
+ * - `Tab` closes the menu and lets the page's own tab order take over, counted
6078
+ * from the trigger: focus goes back to the trigger synchronously and the key's
6079
+ * default action then moves on from there. Without that, a portalled menu —
6080
+ * the last thing in `body` — would hand `Tab` to whatever follows it, which
6081
+ * inside a `Modal` is outside the dialog.
5798
6082
  * - Focus is managed: entries carry `tabIndex={-1}` and only the active one is
5799
6083
  * `0`, which is what stops `Tab` from walking the menu one entry at a time.
5800
6084
  *
5801
6085
  * Disabled entries, separators and labels are skipped by every movement.
5802
6086
  */
5803
- export declare function DropdownMenu({ trigger, items, placement, className, }: DropdownMenuProps): JSX.Element;
6087
+ export declare function DropdownMenu({ trigger, items, placement, portal, className, }: DropdownMenuProps): JSX.Element;
5804
6088
 
5805
6089
  export declare type DropdownMenuEntry = {
5806
6090
  type: "item";
@@ -5848,6 +6132,23 @@ export declare interface DropdownMenuProps {
5848
6132
  }>;
5849
6133
  items: DropdownMenuEntry[];
5850
6134
  placement?: DropdownMenuPlacement;
6135
+ /**
6136
+ * Render the menu in a portal, positioned against the trigger. Default `true`.
6137
+ *
6138
+ * Without it the menu is `position: absolute` inside the trigger's wrapper,
6139
+ * and any ancestor with `overflow` other than `visible` clips it. The ordinary
6140
+ * victim is the action column of a `DataTable`: its wrapper scrolls
6141
+ * horizontally, `overflow-x: auto` forces `overflow-y` to `auto` too, and the
6142
+ * menu of the last row showed one of three entries (measured in Chrome at
6143
+ * 1440 px). In a portal the menu escapes the clip, flips above the trigger
6144
+ * when there is no room below, and follows the trigger on scroll and resize.
6145
+ *
6146
+ * The portalled menu stacks at `--tempest-z-popover`, above
6147
+ * `--tempest-z-modal`, so a menu opened inside a `Modal` still paints on top.
6148
+ * `false` keeps the in-flow menu, for a container that must own the menu's
6149
+ * stacking or clipping on purpose.
6150
+ */
6151
+ portal?: boolean;
5851
6152
  className?: string;
5852
6153
  }
5853
6154
 
@@ -6230,6 +6531,95 @@ export declare type FilterFieldType = "text" | "number" | "date" | "select" | "b
6230
6531
  /** Comparison a filter can make. */
6231
6532
  export declare type FilterOperator = "eq" | "ne" | "contains" | "gt" | "gte" | "lt" | "lte" | "between" | "in" | "empty" | "notEmpty";
6232
6533
 
6534
+ /**
6535
+ * The frame around a fixed set of filters: a card with a title, a grid of the
6536
+ * fields the screen declares, and the actions that belong to no field — clear,
6537
+ * apply, export.
6538
+ *
6539
+ * It holds no state and has no opinion on the fields. `FilterBar` is for ad hoc
6540
+ * querying (the user picks field, operator and value); this is for the set a
6541
+ * screen already knows — município, UF, situação, a search box. Pair it with
6542
+ * `useDraftFilters`: the fields edit `draft`, `onApply` and `onClear` are the
6543
+ * hook's `apply` and `clear`.
6544
+ *
6545
+ * What it settles, each measured in Chromium against the `Card` + `Grid`
6546
+ * composition it replaces:
6547
+ *
6548
+ * - **The grid follows the panel, not the viewport.** `Grid` switches columns on
6549
+ * viewport breakpoints, so the same filters in a 360 px column of a 1280 px
6550
+ * screen got four 57.5 px fields. The default here is
6551
+ * `repeat(auto-fill, minmax(min(100%, minFieldWidth), 1fr))`: the column count
6552
+ * comes from the room the panel has, and `min(100%, …)` keeps a floor wider than
6553
+ * the phone from overflowing it.
6554
+ * - **Cells align to the top.** A field showing an error is taller; with the grid
6555
+ * default (`stretch`), its row-mates' boxes grew to match.
6556
+ * - **The header wraps.** Three actions next to the title measured 527 px in a
6557
+ * 308 px header at 390 px wide, and scrolled the whole page sideways. `Card`'s
6558
+ * header now wraps, and so do the actions inside it.
6559
+ * - **Clear and apply have a fixed place**, at the end of the header, apply last.
6560
+ *
6561
+ * @example
6562
+ * const filters = useDraftFilters({ search: "", uf: "" });
6563
+ * <FilterPanel
6564
+ * onApply={() => filters.apply()}
6565
+ * onClear={filters.clear}
6566
+ * applyDisabled={!filters.isDirty}
6567
+ * >
6568
+ * <Input label="Busca" value={filters.draft.search}
6569
+ * onChange={(e) => filters.set({ search: e.target.value })} />
6570
+ * <Select label="UF" options={UFS} value={filters.draft.uf}
6571
+ * onChange={(e) => filters.set({ uf: e.target.value })} />
6572
+ * </FilterPanel>
6573
+ */
6574
+ export declare function FilterPanel({ children, title, actions, onClear, onApply, applyDisabled, locale, labels, minFieldWidth, columns, className, style, ...props }: FilterPanelProps): JSX.Element;
6575
+
6576
+ /** Labels the panel writes itself. */
6577
+ export declare interface FilterPanelLabels {
6578
+ /** Default title. `"Filtros"` / `"Filters"`. */
6579
+ title: string;
6580
+ /** The clear button. `"Limpar filtros"` / `"Clear filters"`. */
6581
+ clear: string;
6582
+ /** The apply button. `"Filtrar"` / `"Apply filters"`. */
6583
+ apply: string;
6584
+ }
6585
+
6586
+ export declare interface FilterPanelProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_14> {
6587
+ /** The filter controls the screen declares — `Input`, `Select`, a date picker. One grid cell each. */
6588
+ children: ReactNode;
6589
+ /** Heading. Default from `locale`. A string renders as an `h3`; a node renders as given. */
6590
+ title?: ReactNode;
6591
+ /** Header actions that are not fields — "Atualizar a cada 30s", "Exportar CSV". */
6592
+ actions?: ReactNode;
6593
+ /** Return the screen to its initial filters. Renders the clear button only when set. */
6594
+ onClear?: () => void;
6595
+ /**
6596
+ * Publish the draft. When set, the fields sit in a `<form>`: the apply button
6597
+ * submits it and Enter in any text field applies.
6598
+ */
6599
+ onApply?: () => void;
6600
+ /**
6601
+ * Disable the apply button — pass `!filters.isDirty`. Enter follows the button:
6602
+ * it is the form's default button, so a disabled one blocks implicit submission
6603
+ * too, and nothing is re-applied when nothing changed.
6604
+ */
6605
+ applyDisabled?: boolean;
6606
+ /** Locale for the default title and button labels. Default `"pt-BR"`. */
6607
+ locale?: "pt-BR" | "en";
6608
+ /** Override any of the labels. */
6609
+ labels?: Partial<FilterPanelLabels>;
6610
+ /**
6611
+ * Narrowest a field may get before the grid drops a column. Default `"12rem"`.
6612
+ * The count follows the **panel's** width, so the same panel fits a page and a
6613
+ * sidebar.
6614
+ */
6615
+ minFieldWidth?: string;
6616
+ /**
6617
+ * Fixed columns per viewport, as in `Grid` — `{ mobile: 1, tablet: 2, desktop: 4 }`.
6618
+ * Replaces `minFieldWidth`, and follows the **viewport**, not the panel.
6619
+ */
6620
+ columns?: ResponsiveValue<number | string>;
6621
+ }
6622
+
6233
6623
  export declare type FilterPredicate<T> = (item: T, search: string) => boolean;
6234
6624
 
6235
6625
  /**
@@ -7134,13 +7524,18 @@ export declare function higherVersionWins<T>(local: T | undefined, remote: T, ge
7134
7524
  *
7135
7525
  * - Opens after `openDelay` on `mouseenter`/`focus`.
7136
7526
  * - Closes after `closeDelay` on `mouseleave`/`blur`.
7137
- * - Positioned relative to the trigger via `placement`.
7527
+ * - Positioned relative to the trigger via `placement`, in a portal by default.
7528
+ * - Moving the pointer from the trigger into the card keeps it open: React
7529
+ * dispatches `mouseenter`/`mouseleave` along the component tree, and the
7530
+ * portalled card is still inside the trigger's wrapper there.
7531
+ * - A link or button in the card is the next `Tab` stop after the trigger, as it
7532
+ * was in flow.
7138
7533
  * - The card is rendered as a labelled `role="dialog"` region; the trigger stays keyboard focusable.
7139
7534
  *
7140
7535
  * @param props - The hover card props.
7141
7536
  * @returns The trigger wrapper and the anchored card when open.
7142
7537
  */
7143
- export declare function HoverCard({ trigger, children, openDelay, closeDelay, placement, className, ...rest }: HoverCardProps): JSX.Element;
7538
+ export declare function HoverCard({ trigger, children, openDelay, closeDelay, placement, portal, className, style, ...rest }: HoverCardProps): JSX.Element;
7144
7539
 
7145
7540
  export declare type HoverCardPlacement = "top" | "bottom" | "left" | "right";
7146
7541
 
@@ -7155,6 +7550,15 @@ export declare interface HoverCardProps extends HTMLAttributes<HTMLDivElement> {
7155
7550
  closeDelay?: number;
7156
7551
  /** Where the card is anchored relative to the trigger. Default "bottom". */
7157
7552
  placement?: HoverCardPlacement;
7553
+ /**
7554
+ * Render the card in a portal, positioned against the trigger. Default `true`.
7555
+ *
7556
+ * In flow, an ancestor with `overflow` other than `visible` clips the card — a
7557
+ * user handle in the last row of a `DataTable` showed 17% of it (measured in
7558
+ * Chrome at 1440 px). In a portal it escapes the clip and flips to the
7559
+ * opposite side at the viewport edge.
7560
+ */
7561
+ portal?: boolean;
7158
7562
  }
7159
7563
 
7160
7564
  export declare interface I18n {
@@ -9011,7 +9415,7 @@ export { MemoryRouter }
9011
9415
  * ]}
9012
9416
  * />
9013
9417
  */
9014
- export declare function Menubar({ menus, className, ...props }: MenubarProps): JSX.Element;
9418
+ export declare function Menubar({ menus, portal, className, ...props }: MenubarProps): JSX.Element;
9015
9419
 
9016
9420
  export declare type MenubarItem = {
9017
9421
  /** Visible label for the action. */
@@ -9036,6 +9440,18 @@ export declare interface MenubarMenu {
9036
9440
  export declare interface MenubarProps extends HTMLAttributes<HTMLDivElement> {
9037
9441
  /** Top-level menus rendered left-to-right. */
9038
9442
  menus: MenubarMenu[];
9443
+ /**
9444
+ * Render the open panel in a portal, positioned under its trigger. Default
9445
+ * `true`.
9446
+ *
9447
+ * In flow, an ancestor with `overflow` other than `visible` clips the panel,
9448
+ * and the SDK's own `Navbar` is one: its `nav` slot scrolls horizontally, and
9449
+ * `overflow-x: auto` forces `overflow-y` to `auto` too — a menu showed
9450
+ * 0% of its panel there (measured in Chrome at 1440 px). In a portal the
9451
+ * panel escapes the clip, flips at the viewport edge, stays in the tab order
9452
+ * right after its trigger, and follows it on scroll and resize.
9453
+ */
9454
+ portal?: boolean;
9039
9455
  }
9040
9456
 
9041
9457
  /**
@@ -9213,6 +9629,13 @@ export declare type MicrophoneStatus = "idle" | "requesting" | "ready" | "error"
9213
9629
  * Portal-rendered modal dialog with backdrop, Esc handler, and slots for
9214
9630
  * header/body/footer. Locks body scroll while open.
9215
9631
  *
9632
+ * Keyboard focus is trapped in the dialog while it is open (`useFocusTrap`): it
9633
+ * enters on the first tab stop — or the dialog itself when there is none —,
9634
+ * `Tab`/`Shift+Tab` cycle inside it, including the panels of a `Popover` or
9635
+ * `HoverCard` opened from it, and closing returns focus to the element that
9636
+ * opened it. `aria-modal="true"` tells a screen reader the page behind is inert;
9637
+ * the trap is what makes that true for the keyboard.
9638
+ *
9216
9639
  * The `dialog` role needs an accessible name: a `title` supplies it via
9217
9640
  * `aria-labelledby`, and a titleless dialog should pass `aria-label`. The
9218
9641
  * header heading is only rendered when there is a title, so a close-button-only
@@ -9371,7 +9794,7 @@ export declare function moveItem<T>(items: T[], from: number, to: number): T[];
9371
9794
  * Keyboard: ArrowUp/ArrowDown navigate, Enter toggles the active option, Esc
9372
9795
  * closes, Backspace (empty input) pops the last chip.
9373
9796
  */
9374
- export declare function MultiSelect({ options, value, onChange, label, placeholder, helperText, error, disabled, maxItems, filter, emptyMessage, className, }: MultiSelectProps): JSX.Element;
9797
+ export declare function MultiSelect({ options, value, onChange, label, placeholder, helperText, error, disabled, maxItems, filter, emptyMessage, portal, className, }: MultiSelectProps): JSX.Element;
9375
9798
 
9376
9799
  export declare interface MultiSelectOption {
9377
9800
  value: string;
@@ -9395,6 +9818,16 @@ export declare interface MultiSelectProps {
9395
9818
  filter?: (option: MultiSelectOption, query: string) => boolean;
9396
9819
  /** Message shown when no option matches. */
9397
9820
  emptyMessage?: string;
9821
+ /**
9822
+ * Render the list in a portal, positioned under the field. Default `true`.
9823
+ *
9824
+ * In flow, an ancestor with `overflow` other than `visible` clips the list —
9825
+ * in the last row of a `DataTable` none of it was visible (measured in Chrome
9826
+ * at 1440 px). In a portal it escapes the clip, takes the field's width,
9827
+ * flips above the field when there is no room below, and follows it on
9828
+ * scroll, resize and when the field grows a line of chips.
9829
+ */
9830
+ portal?: boolean;
9398
9831
  className?: string;
9399
9832
  }
9400
9833
 
@@ -9458,7 +9891,7 @@ export { NavigateOptions }
9458
9891
  * ]}
9459
9892
  * />
9460
9893
  */
9461
- export declare function NavigationMenu({ items, className, ...props }: NavigationMenuProps): JSX.Element;
9894
+ export declare function NavigationMenu({ items, portal, className, ...props }: NavigationMenuProps): JSX.Element;
9462
9895
 
9463
9896
  export declare interface NavigationMenuItem {
9464
9897
  /** Visible label for the entry. */
@@ -9474,6 +9907,18 @@ export declare interface NavigationMenuItem {
9474
9907
  export declare interface NavigationMenuProps extends HTMLAttributes<HTMLElement> {
9475
9908
  /** Top-level navigation entries. */
9476
9909
  items: NavigationMenuItem[];
9910
+ /**
9911
+ * Render the open panel in a portal, positioned under its trigger. Default
9912
+ * `true`.
9913
+ *
9914
+ * In flow, an ancestor with `overflow` other than `visible` clips the panel,
9915
+ * and the SDK's own `Navbar` is one: its `nav` slot scrolls horizontally, and
9916
+ * `overflow-x: auto` forces `overflow-y` to `auto` too — a submenu showed
9917
+ * 0% of its panel there (measured in Chrome at 1440 px). In a portal the
9918
+ * panel escapes the clip, flips at the viewport edge, stays in the tab order
9919
+ * right after its trigger, and follows it on scroll and resize.
9920
+ */
9921
+ portal?: boolean;
9477
9922
  }
9478
9923
 
9479
9924
  /**
@@ -10097,6 +10542,26 @@ export declare interface OpenModalOptions {
10097
10542
  /** The operators a field offers. */
10098
10543
  export declare function operatorsFor(field: FilterField): FilterOperator[];
10099
10544
 
10545
+ /**
10546
+ * The shape every option list in the SDK shares: `Select`, `MultiSelect` and
10547
+ * `Combobox` all accept an array of it.
10548
+ *
10549
+ * `value` is always a `string` here, because that is what a `<select>` hands
10550
+ * back in `event.target.value` whatever the option was built from: an option
10551
+ * built with the number `0` comes back as the string `"0"`, so a list that kept
10552
+ * numbers could never be compared with `===` against what the control emits.
10553
+ */
10554
+ export declare interface OptionEntry {
10555
+ value: string;
10556
+ label: string;
10557
+ }
10558
+
10559
+ /** The minimum an option needs for the helpers to prepend to its list. */
10560
+ declare type OptionLike = {
10561
+ value: string | number;
10562
+ label: string;
10563
+ };
10564
+
10100
10565
  /**
10101
10566
  * @tempest-limits file-lines — parsing a session description, merging one
10102
10567
  * `fmtp` line and inserting a missing one are the same pass over the same
@@ -10254,6 +10719,9 @@ declare type OverriddenDomProps_12 = "children";
10254
10719
  /** DOM attributes this component redefines. */
10255
10720
  declare type OverriddenDomProps_13 = "children" | "onChange";
10256
10721
 
10722
+ /** DOM attributes this component redefines. */
10723
+ declare type OverriddenDomProps_14 = "title" | "children" | "onSubmit";
10724
+
10257
10725
  /**
10258
10726
  * DOM attributes this component redefines.
10259
10727
  *
@@ -10338,6 +10806,14 @@ export declare interface PaginationProps {
10338
10806
  onPageChange: (page: number) => void;
10339
10807
  pageSize?: number;
10340
10808
  onPageSizeChange?: (size: number) => void;
10809
+ /**
10810
+ * Sizes offered in the selector. Default `[10, 25, 50, 100]`.
10811
+ *
10812
+ * The current `pageSize` is always offered too, merged in ascending order. A
10813
+ * `<select>` whose value matches no option displays its first option, so
10814
+ * `pageSize={20}` against the default list used to read "10 / página" over a
10815
+ * table showing 20 rows.
10816
+ */
10341
10817
  pageSizeOptions?: number[];
10342
10818
  /** Total items count; if provided, renders the summary text. */
10343
10819
  totalItems?: number;
@@ -10987,11 +11463,14 @@ export declare interface PlaySfxOptions {
10987
11463
  export declare function pluralize(count: number, singular: string, plural?: string): string;
10988
11464
 
10989
11465
  /**
10990
- * Lightweight popover. Renders a positioned panel anchored to a trigger,
10991
- * dismissed on outside click / Escape. Does NOT include collision detection
10992
- * or smart positioning — pair with Floating UI if you need that.
11466
+ * Lightweight popover. Renders a panel anchored to a trigger, dismissed on
11467
+ * outside click / Escape.
11468
+ *
11469
+ * Portalled by default, with viewport-aware placement: the panel flips to the
11470
+ * opposite side when the requested one overflows, and is clamped inside the
11471
+ * viewport otherwise.
10993
11472
  */
10994
- export declare function Popover({ trigger, children, placement, open, onOpenChange, defaultOpen, closeOnEsc, closeOnOutsideClick, className, }: PopoverProps): JSX.Element;
11473
+ export declare function Popover({ trigger, children, placement, portal, open, onOpenChange, defaultOpen, closeOnEsc, closeOnOutsideClick, className, }: PopoverProps): JSX.Element;
10995
11474
 
10996
11475
  export declare type PopoverPlacement = "top" | "bottom" | "left" | "right";
10997
11476
 
@@ -11004,6 +11483,16 @@ export declare interface PopoverProps {
11004
11483
  }>;
11005
11484
  children: ReactNode;
11006
11485
  placement?: PopoverPlacement;
11486
+ /**
11487
+ * Render the panel in a portal, positioned against the trigger. Default `true`.
11488
+ *
11489
+ * In flow, any ancestor with `overflow` other than `visible` clips the panel —
11490
+ * inside a `DataTable` cell only 3% of it was visible (measured in Chrome at
11491
+ * 1440 px). In a portal it escapes the clip, flips to the opposite side when
11492
+ * the requested one has no room, and follows the trigger on scroll and resize.
11493
+ * `false` keeps the in-flow panel.
11494
+ */
11495
+ portal?: boolean;
11007
11496
  /** Controlled open state. */
11008
11497
  open?: boolean;
11009
11498
  /** Called when the user toggles or dismisses. */
@@ -12012,6 +12501,17 @@ export declare interface ResumableUploadOptions {
12012
12501
  trustedOrigins?: readonly string[];
12013
12502
  /** Send cookies. Default `false`. */
12014
12503
  withCredentials?: boolean;
12504
+ /**
12505
+ * Send a CSRF token on the creation `POST`, every chunk `PATCH` and the
12506
+ * discarding `DELETE` — never on the offset `HEAD`. Off by default; `true`
12507
+ * reads the `csrf_token` cookie into `X-CSRF-Token`, as `createApiClient`
12508
+ * does.
12509
+ *
12510
+ * Scoped like the bearer token, to `endpoint`'s origin plus
12511
+ * {@link trustedOrigins}: a `Location` pointing at object storage on
12512
+ * another host gets neither.
12513
+ */
12514
+ csrf?: boolean | CsrfOptions;
12015
12515
  /**
12016
12516
  * Resume key. Defaults to a fingerprint of endpoint + file name/size/mtime, so
12017
12517
  * picking the same file after a reload resumes instead of restarting.
@@ -12535,7 +13035,7 @@ export declare interface SegmentedControlProps<TValue extends string = string> e
12535
13035
  * Native `<select>` wrapper. Either provide `options` for a quick render, or
12536
13036
  * pass `<option>` children directly.
12537
13037
  *
12538
- * Two variants:
13038
+ * Three variants:
12539
13039
  *
12540
13040
  * - `"field"` (default) — label, control, helper text and error slot, for a form.
12541
13041
  * - `"chip"` — the control alone, sized to its content, for a settings row where
@@ -12544,20 +13044,60 @@ export declare interface SegmentedControlProps<TValue extends string = string> e
12544
13044
  * list item, which is why every app ended up hand-rolling a native `<select>`
12545
13045
  * with `appearance: none` — and hand-rolling it loses the focus ring, the
12546
13046
  * disabled styling and the caret this component already solves.
13047
+ * - `"bare"` — the same mechanism with none of the look, for an app with its own
13048
+ * visual identity: the shell renders `wrapper > select + caret`, and the app
13049
+ * dresses the wrapper through `wrapperClassName`. See {@link SelectBareProps}.
12547
13050
  *
12548
13051
  * @example
12549
13052
  * <Select label="Estado" options={states} placeholder="Selecione" />
12550
13053
  *
12551
13054
  * @example
12552
13055
  * <ListTile title="Idioma" trailing={<Select variant="chip" aria-label="Idioma" options={langs} />} />
13056
+ *
13057
+ * @example
13058
+ * <Select variant="bare" wrapperClassName={styles.filtro} aria-label="Status" options={status} />
12553
13059
  */
12554
13060
  export declare const Select: ForwardRefExoticComponent<SelectProps & RefAttributes<HTMLSelectElement>>;
12555
13061
 
12556
- /** What both variants of {@link Select} accept. */
12557
- declare interface SelectBaseProps extends SelectHTMLAttributes<HTMLSelectElement> {
13062
+ /**
13063
+ * The mechanism without the look: `appearance: none`, the caret and the focus
13064
+ * ring, and no border, background, radius, shadow or height.
13065
+ *
13066
+ * The `<select>` inherits `background-color` and `color` from the shell (the
13067
+ * element `wrapperClassName` lands on). The background is not cosmetic: the
13068
+ * native popup paints each `<option>` from the `<select>`'s background, so a
13069
+ * transparent control would hand the menu back to the system white.
13070
+ *
13071
+ * Like `"chip"`, the variant has no visible label, so an accessible name is
13072
+ * required — through `aria-label` or `aria-labelledby`.
13073
+ */
13074
+ export declare type SelectBareProps = SelectBaseProps & {
13075
+ variant: "bare";
13076
+ } & ({
13077
+ "aria-label": string;
13078
+ } | {
13079
+ "aria-labelledby": string;
13080
+ });
13081
+
13082
+ /** What every variant of {@link Select} accepts. */
13083
+ export declare interface SelectBaseProps extends SelectHTMLAttributes<HTMLSelectElement> {
12558
13084
  options?: SelectOption[];
12559
13085
  placeholder?: string;
13086
+ /**
13087
+ * Class for the outermost element. On `"bare"` that element is the shell
13088
+ * holding the `<select>` and the caret, which is where the app's own look goes.
13089
+ */
12560
13090
  wrapperClassName?: string;
13091
+ /**
13092
+ * Replaces the built-in chevron, following the `icon?: ReactNode` convention
13093
+ * the rest of the SDK uses.
13094
+ *
13095
+ * The icon is drawn in the caret slot, which is positioned by
13096
+ * `--tempest-control-caret-offset` and sized by `--tempest-control-caret-size`;
13097
+ * an `<svg>` passed here is stretched to that size, so the token — not the
13098
+ * icon's own `width`/`height` — decides how big the caret is in every density.
13099
+ */
13100
+ caretIcon?: ReactNode;
12561
13101
  }
12562
13102
 
12563
13103
  /**
@@ -12568,13 +13108,13 @@ declare interface SelectBaseProps extends SelectHTMLAttributes<HTMLSelectElement
12568
13108
  * row's own text, which the `<select>` has no relationship to — so without this
12569
13109
  * the screen reader announces a combobox with no name at all.
12570
13110
  */
12571
- declare interface SelectChipProps extends SelectBaseProps {
13111
+ export declare interface SelectChipProps extends SelectBaseProps {
12572
13112
  variant: "chip";
12573
13113
  "aria-label": string;
12574
13114
  }
12575
13115
 
12576
13116
  /** The full form field: label, control, helper text and error slot. */
12577
- declare interface SelectFieldProps extends SelectBaseProps {
13117
+ export declare interface SelectFieldProps extends SelectBaseProps {
12578
13118
  variant?: "field";
12579
13119
  label?: string;
12580
13120
  helperText?: string;
@@ -12587,7 +13127,7 @@ export declare interface SelectOption {
12587
13127
  disabled?: boolean;
12588
13128
  }
12589
13129
 
12590
- export declare type SelectProps = SelectFieldProps | SelectChipProps;
13130
+ export declare type SelectProps = SelectFieldProps | SelectChipProps | SelectBareProps;
12591
13131
 
12592
13132
  /**
12593
13133
  * Minimal subset of `@sentry/browser` used by the adapter. Lets you pass
@@ -12938,6 +13478,17 @@ export declare interface ShowProps {
12938
13478
  * </Show>
12939
13479
  *
12940
13480
  * @example
13481
+ * const { pathname } = useLocation();
13482
+ * <Sidebar
13483
+ * match="route"
13484
+ * value={pathname}
13485
+ * items={[
13486
+ * { key: "overview", label: "Overview", href: "/dashboard" },
13487
+ * { key: "tips", label: "Tips", href: "/dashboard/tips" },
13488
+ * ]}
13489
+ * />
13490
+ *
13491
+ * @example
12941
13492
  * <Sidebar
12942
13493
  * items={[
12943
13494
  * { type: "section", key: "monitoring", label: "Monitoring" },
@@ -12950,7 +13501,7 @@ export declare interface ShowProps {
12950
13501
  * onChange={setTab}
12951
13502
  * />
12952
13503
  */
12953
- export declare function Sidebar({ header, items, value, onChange, footer, collapsed, width, collapsedWidth, className, style, ...props }: SidebarProps): JSX.Element;
13504
+ export declare function Sidebar({ header, items, value, onChange, match, footer, collapsed, width, collapsedWidth, className, style, ...props }: SidebarProps): JSX.Element;
12954
13505
 
12955
13506
  /**
12956
13507
  * One entry of the navigation list.
@@ -12989,8 +13540,28 @@ export declare interface SidebarProps extends Omit<HTMLAttributes<HTMLElement>,
12989
13540
  header?: ReactNode;
12990
13541
  /** Navigation entries. An entry with no `type` is an item. */
12991
13542
  items: SidebarEntry[];
12992
- /** Active item key. */
13543
+ /**
13544
+ * The active item: its `key` by default, or the current route with
13545
+ * `match="route"`.
13546
+ */
12993
13547
  value?: string;
13548
+ /**
13549
+ * How `value` picks the active item.
13550
+ *
13551
+ * - `"key"` (default): the item whose `key` equals `value`.
13552
+ * - `"route"`: `value` is the current pathname, and the active item is the one
13553
+ * whose `href` (or `key`, when it has no `href`) is the longest path covering
13554
+ * it on a segment boundary — see `activeNavKey`. `/dashboard/tips/42` lights
13555
+ * `/dashboard/tips`, not `/dashboard`, and `/users-admin` never lights
13556
+ * `/users`. Sections and separators take no part.
13557
+ *
13558
+ * `"route"` is what lets the app pass `useLocation().pathname` and stop
13559
+ * computing a key: the component already holds the entries the resolution runs
13560
+ * against, so asking the app to repeat them is how the two drift apart. It
13561
+ * reads no router itself — the value comes in as a string — so the component
13562
+ * keeps working with no router mounted.
13563
+ */
13564
+ match?: "key" | "route";
12994
13565
  /** Fires when an item is clicked. Receives the item's `key`. */
12995
13566
  onChange?: (key: string) => void;
12996
13567
  /** Bottom slot — typically settings/profile/logout. */
@@ -14287,8 +14858,13 @@ export declare type TokenKind = "plain" | "comment" | "string" | "number" | "key
14287
14858
  * Lightweight tooltip. Shows on hover and on focus (keyboard-friendly). Wraps
14288
14859
  * a single child element via `cloneElement`, so the trigger keeps its own ref
14289
14860
  * and props.
14861
+ *
14862
+ * `Escape` hides it without moving the pointer or the focus, which is what
14863
+ * WCAG 2.2 SC 1.4.13 (Content on Hover or Focus) asks of content that appears on
14864
+ * hover. It is an `Escape` layer like the overlays, so inside a `Modal` the first
14865
+ * press hides the tooltip and the second closes the modal.
14290
14866
  */
14291
- export declare function Tooltip({ content, placement, children, disabled, openDelay, }: TooltipProps): JSX.Element;
14867
+ export declare function Tooltip({ content, placement, children, disabled, openDelay, portal, }: TooltipProps): JSX.Element;
14292
14868
 
14293
14869
  export declare type TooltipPlacement = "top" | "bottom" | "left" | "right";
14294
14870
 
@@ -14303,8 +14879,46 @@ export declare interface TooltipProps {
14303
14879
  disabled?: boolean;
14304
14880
  /** Delay (ms) before showing the tooltip. Default: 150. */
14305
14881
  openDelay?: number;
14882
+ /**
14883
+ * Render the bubble in a portal, positioned against the trigger. Default `true`.
14884
+ *
14885
+ * In flow, an ancestor with `overflow` other than `visible` clips the bubble —
14886
+ * a `DataTable` cell cut it 23 px short (measured in Chrome at 1440 px). In a
14887
+ * portal it escapes the clip and flips to the opposite side at the viewport
14888
+ * edge. `false` keeps the in-flow bubble.
14889
+ */
14890
+ portal?: boolean;
14306
14891
  }
14307
14892
 
14893
+ /**
14894
+ * Turn a `value → label` map into the option list `Select`, `MultiSelect` and
14895
+ * `Combobox` take.
14896
+ *
14897
+ * Every key becomes a string `value` (see {@link OptionEntry} for why), so the
14898
+ * result is assignable to `SelectOption[]`, `MultiSelectOption[]` and
14899
+ * `ComboboxOption[]` alike.
14900
+ *
14901
+ * **Order.** A `Map` keeps the order it was written in, always. A plain object
14902
+ * does too — **except for integer-like keys**, which JavaScript enumerates first
14903
+ * and in ascending order whatever order they were written in
14904
+ * (`OrdinaryOwnPropertyKeys`, ECMA-262 §10.1.11.1). Measured in Node 24:
14905
+ * `Object.keys({ 5: "Ótimo", 3: "Ok", 1: "Ruim" })` is `["1", "3", "5"]`, and
14906
+ * `{ baixa, 10, 2, alta }` enumerates as `["2", "10", "baixa", "alta"]`. When
14907
+ * the business order of a numeric scale is not ascending, pass a `Map`.
14908
+ *
14909
+ * @param source - A record or a `Map` from value to label.
14910
+ * @returns A new array, one entry per key, in the order described above.
14911
+ *
14912
+ * @example
14913
+ * const STATUS = { active: "Ativo", paused: "Pausado" };
14914
+ * <Select aria-label="Status" variant="chip" options={toOptions(STATUS)} />
14915
+ *
14916
+ * @example
14917
+ * const HUMOR = new Map([[5, "Ótimo"], [3, "Ok"], [1, "Ruim"]]);
14918
+ * toOptions(HUMOR); // 5, 3, 1 — the order written
14919
+ */
14920
+ export declare function toOptions(source: Readonly<Record<string, string>> | ReadonlyMap<string | number, string>): OptionEntry[];
14921
+
14308
14922
  /** Convert degrees to radians. */
14309
14923
  export declare function toRadians(degrees: number): number;
14310
14924
 
@@ -14820,6 +15434,18 @@ export declare interface UploadWithProgressOptions {
14820
15434
  trustedOrigins?: readonly string[];
14821
15435
  /** Send cookies. Defaults to false. */
14822
15436
  withCredentials?: boolean;
15437
+ /**
15438
+ * Send a CSRF token with the upload, as `createApiClient`'s `csrf` does.
15439
+ * Off by default; `true` reads the `csrf_token` cookie into `X-CSRF-Token`.
15440
+ *
15441
+ * Scoped to {@link credentialOrigin} plus {@link trustedOrigins} — and,
15442
+ * unlike the bearer token, scoped even when `credentialOrigin` is unset:
15443
+ * then the scope is the page's own origin. The bearer default stays open
15444
+ * only for compatibility with every version before 0.66.0; this option is
15445
+ * new, so it starts closed. An API on another origin sets
15446
+ * `credentialOrigin` to receive the token.
15447
+ */
15448
+ csrf?: boolean | CsrfOptions;
14823
15449
  /** Called on every `progress` event from the XHR upload channel. */
14824
15450
  onProgress?: (event: UploadProgressEvent) => void;
14825
15451
  /** Abort the request. */
@@ -15417,6 +16043,80 @@ export declare function useDocumentTitle(title: string): void;
15417
16043
  /** Subscribe to `document.visibilityState`. Returns `"visible"` during SSR. */
15418
16044
  export declare function useDocumentVisibility(): DocumentVisibility;
15419
16045
 
16046
+ /**
16047
+ * Draft vs applied state for a server-side filter: the controls edit a draft
16048
+ * freely, and the query only sees it when the user applies (a click, or Enter).
16049
+ *
16050
+ * A server-side filter cannot react to every keystroke — each character typed in
16051
+ * a search box would be a request. Every admin screen then writes the same pair of
16052
+ * `useState`s, and gets the same three details wrong:
16053
+ *
16054
+ * - **Clearing moves both halves.** Resetting only the draft leaves a filtered
16055
+ * list under an empty bar; resetting only the applied value leaves the opposite.
16056
+ * - **Applying a value that is not in state yet.** "Filter by this code" has to
16057
+ * write the draft and publish it in one gesture; calling `setDraft(x)` and then
16058
+ * publishing `draft` reads the previous value. `apply(patch)` computes the next
16059
+ * draft from a ref that every call keeps current, so it never depends on the
16060
+ * order React flushes state in.
16061
+ * - **Resetting the page.** Filtering while on page 7 of a result that now has two
16062
+ * pages shows an empty table. `usePaginatedQuery` handles it by itself when
16063
+ * `applied` is in its `queryKey`; a page kept elsewhere resets in `onApply`.
16064
+ *
16065
+ * There is no effect in here: applying happens inside the event that asked for it,
16066
+ * so one click is one request. `applied` keeps its reference while nothing new is
16067
+ * applied, so it can sit in a `queryKey` without a phantom refetch.
16068
+ *
16069
+ * Like `useState`, the initial value is read on the first render only; `clear()`
16070
+ * returns to it.
16071
+ *
16072
+ * @param initial - The empty filter form: what the screen shows and queries first.
16073
+ * @param options - `onApply` and `isEqual`.
16074
+ * @returns The draft, the applied value and the gestures between them.
16075
+ *
16076
+ * @example
16077
+ * const filters = useDraftFilters({ code: "", level: "all" });
16078
+ * const logs = usePaginatedQuery({
16079
+ * queryKey: ["logs", filters.applied],
16080
+ * queryFn: (params) => api.listLogs({ ...params, ...toQuery(filters.applied) }),
16081
+ * });
16082
+ * // <Input value={filters.draft.code} onChange={(e) => filters.set({ code: e.target.value })} />
16083
+ * // <Button disabled={!filters.isDirty} onClick={() => filters.apply()}>Filtrar</Button>
16084
+ */
16085
+ export declare function useDraftFilters<T extends object>(initial: T, options?: UseDraftFiltersOptions<T>): UseDraftFiltersResult<T>;
16086
+
16087
+ export declare interface UseDraftFiltersOptions<T> {
16088
+ /**
16089
+ * Called with the applied value on every `apply()` and `clear()` — the place to
16090
+ * reset a page number you keep yourself. `usePaginatedQuery` does not need it:
16091
+ * it goes back to page 1 on its own when `applied` changes its `queryKey`.
16092
+ */
16093
+ onApply?: (applied: T) => void;
16094
+ /** Equality behind `isDirty` and the stable `applied`. Default: structural. */
16095
+ isEqual?: (a: T, b: T) => boolean;
16096
+ }
16097
+
16098
+ export declare interface UseDraftFiltersResult<T> {
16099
+ /** What the filter controls edit. Changes on every keystroke. */
16100
+ draft: T;
16101
+ /**
16102
+ * What the query reads. Changes only on `apply()`/`clear()`, and keeps its
16103
+ * reference when the value applied is equal to the current one — safe to put
16104
+ * in a `queryKey`.
16105
+ */
16106
+ applied: T;
16107
+ /** Whether the draft differs from what is applied — enable the apply button on it. */
16108
+ isDirty: boolean;
16109
+ /** Edit the draft, merging a partial object or running an updater. Never applies. */
16110
+ set: (patch: DraftFiltersPatch<T>) => void;
16111
+ /**
16112
+ * Publish the draft. With a patch, merge it into the draft **and** publish the
16113
+ * result in the same call — "filter by this code" from a table row.
16114
+ */
16115
+ apply: (patch?: DraftFiltersPatch<T>) => void;
16116
+ /** Reset the draft and the applied value to the initial one, together. */
16117
+ clear: () => void;
16118
+ }
16119
+
15420
16120
  /**
15421
16121
  * Hook that propagates errors to the nearest {@link ErrorBoundary}.
15422
16122
  *
@@ -15523,9 +16223,38 @@ export { UseFieldArrayReturn }
15523
16223
  export declare function useFlagValue<T extends FlagValue = FlagValue>(key: string, defaultValue?: T): T;
15524
16224
 
15525
16225
  /**
15526
- * Trap keyboard focus inside `containerRef` while `active` is true. Cycles
15527
- * Tab and Shift+Tab between the first and last focusable descendants. Pair
15528
- * with Modal/Drawer for fully-accessible overlays.
16226
+ * Trap keyboard focus inside `containerRef` while `active` is true.
16227
+ *
16228
+ * - **On activation** focus moves to the first tab stop, or to the container
16229
+ * itself when it has none (give it `tabIndex={-1}`). Content that already put
16230
+ * focus inside — an `autoFocus` input — is left where it is.
16231
+ * - **`Tab` / `Shift+Tab`** wrap between the first and the last stop, and pull
16232
+ * focus back in when it sits outside.
16233
+ * - **On release** focus returns to the element that held it when the trap
16234
+ * armed. That element is read during the render that arms the trap, before
16235
+ * React commits: an `autoFocus` child takes focus in the commit, ahead of any
16236
+ * effect, and reading it there would "restore" to the child that is about to
16237
+ * unmount — which dropped focus on `body` in `Command`.
16238
+ *
16239
+ * **Portalled panels stay reachable.** A `Popover` or `HoverCard` opened from
16240
+ * inside the container renders at the end of `body`, outside it. Those panels
16241
+ * register themselves (see `usePortalTabOrder`), and the trap treats them as
16242
+ * part of the container, spliced right after their trigger. A `Tab` another
16243
+ * layer already consumed is not moved again, unless it moved focus out of the
16244
+ * container and its panels — the portal bridge leaving the last panel stop for
16245
+ * whatever follows the trap in the page.
16246
+ *
16247
+ * **Traps stack.** Only the most recent active trap handles `Tab`, so a modal
16248
+ * opened over another owns the keyboard until it closes, and then hands focus
16249
+ * back to the element it was opened from, inside the one below.
16250
+ *
16251
+ * The listener is on `document` in the bubble phase, after React's own
16252
+ * handlers: a menu that closes on `Tab` and returns focus to its trigger has
16253
+ * already done so when the trap looks at where focus is.
16254
+ *
16255
+ * @param containerRef - The element focus is confined to.
16256
+ * @param active - Whether the trap is armed.
16257
+ * @returns Nothing.
15529
16258
  */
15530
16259
  export declare function useFocusTrap(containerRef: RefObject<HTMLElement | null>, active: boolean): void;
15531
16260
 
@@ -16490,6 +17219,13 @@ export declare function useOptionalI18n(): I18nContextValue | null;
16490
17219
  * fetcher, keeps the previous page visible while the next loads, and derives
16491
17220
  * `hasNext`/`hasPrev`/`pageCount`.
16492
17221
  *
17222
+ * A structurally different `queryKey` (compared with TanStack's `hashKey`) is a
17223
+ * different result set, so the page returns to 1. The reset is applied during
17224
+ * render rather than in an effect: an effect would let one render go out with the
17225
+ * new key and the old page, and that render is a request — on page 7 of an
17226
+ * unfiltered list, applying a filter used to ask for page 7 of a two-page result
17227
+ * and show an empty table (#356).
17228
+ *
16493
17229
  * @example
16494
17230
  * const users = usePaginatedQuery<User>({
16495
17231
  * queryKey: ["users"],
@@ -16501,7 +17237,11 @@ export declare function useOptionalI18n(): I18nContextValue | null;
16501
17237
  export declare function usePaginatedQuery<T>(options: UsePaginatedQueryOptions<T>): UsePaginatedQueryResult<T>;
16502
17238
 
16503
17239
  export declare interface UsePaginatedQueryOptions<T> extends Omit<UseQueryOptions<OffsetPage<T>, Error, OffsetPage<T>, QueryKey>, "queryKey" | "queryFn"> {
16504
- /** Base query key — the current page/sort is appended for cache isolation. */
17240
+ /**
17241
+ * Base query key — the current page/sort is appended for cache isolation.
17242
+ * Put the applied filters here: when the key changes structurally, the page
17243
+ * goes back to 1 in the same render.
17244
+ */
16505
17245
  queryKey: QueryKey;
16506
17246
  /** Fetcher receiving the offset params; return the backend envelope. */
16507
17247
  queryFn: (params: OffsetParams) => Promise<OffsetPage<T>> | OffsetPage<T>;
@@ -16525,7 +17265,7 @@ export declare interface UsePaginatedQueryResult<T> {
16525
17265
  page: OffsetPage<T> | undefined;
16526
17266
  /** The rows of the current page (empty array while pending). */
16527
17267
  items: T[];
16528
- /** Current 1-based page number (controlled by the hook). */
17268
+ /** Current 1-based page number (controlled by the hook; back to 1 on a new `queryKey`). */
16529
17269
  pageNumber: number;
16530
17270
  /** Total page count from the last successful response. */
16531
17271
  pageCount: number;
@@ -18569,6 +19309,36 @@ export declare interface WindowSize {
18569
19309
  height: number;
18570
19310
  }
18571
19311
 
19312
+ /**
19313
+ * Prepend the "no filter" entry to an option list.
19314
+ *
19315
+ * A filter needs this as a real option, not as the select's placeholder: a
19316
+ * placeholder reads as "nothing chosen yet", so the screen cannot tell whether
19317
+ * the column is filtered. The entry uses {@link ALL_OPTION_VALUE}.
19318
+ *
19319
+ * @param options - The list to extend. It is not mutated.
19320
+ * @param label - The entry's label. Defaults to `"Todos"`.
19321
+ * @returns A new array with the entry first.
19322
+ */
19323
+ export declare function withAllOption<T extends OptionLike>(options: readonly T[], label?: string): (T | OptionEntry)[];
19324
+
19325
+ /**
19326
+ * Prepend the empty entry a nullable field needs.
19327
+ *
19328
+ * Without it a `<select>` has no way to show "unset": a controlled
19329
+ * `value=""` with no matching option reads back as the **first option** (measured
19330
+ * in jsdom: `select.value === "a"`), so opening an edit form and saving it
19331
+ * writes a value nobody chose. `Select`'s `placeholder` does not cover this — its
19332
+ * entry is `disabled hidden`, so once something is picked the field can never be
19333
+ * cleared again. The entry's value is `""`, which is what an unanswered nullable field
19334
+ * submits.
19335
+ *
19336
+ * @param options - The list to extend. It is not mutated.
19337
+ * @param label - The entry's label. Defaults to `"— Não definido —"`.
19338
+ * @returns A new array with the entry first.
19339
+ */
19340
+ export declare function withEmptyOption<T extends OptionLike>(options: readonly T[], label?: string): (T | OptionEntry)[];
19341
+
18572
19342
  /**
18573
19343
  * A bound Zustand hook augmented with auto-generated per-field selector hooks
18574
19344
  * under `.use`. Reading a single field via `store.use.field()` subscribes the