tempest-react-sdk 0.67.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.
- package/README.md +97 -93
- package/dist/auth/create-tempest-auth.cjs +1 -1
- package/dist/auth/create-tempest-auth.cjs.map +1 -1
- package/dist/auth/create-tempest-auth.js +41 -40
- package/dist/auth/create-tempest-auth.js.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.cjs +1 -1
- package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.js +34 -30
- package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
- package/dist/components/Card/Card.module.cjs.map +1 -1
- package/dist/components/Card/Card.module.js.map +1 -1
- package/dist/components/Combobox/Combobox.cjs +1 -1
- package/dist/components/Combobox/Combobox.cjs.map +1 -1
- package/dist/components/Combobox/Combobox.js +78 -77
- package/dist/components/Combobox/Combobox.js.map +1 -1
- package/dist/components/Combobox/Combobox.module.cjs.map +1 -1
- package/dist/components/Combobox/Combobox.module.js.map +1 -1
- package/dist/components/Command/Command.cjs +1 -1
- package/dist/components/Command/Command.js +4 -4
- package/dist/components/DataTable/DataTable.cjs +1 -1
- package/dist/components/DataTable/DataTable.cjs.map +1 -1
- package/dist/components/DataTable/DataTable.js +138 -127
- package/dist/components/DataTable/DataTable.js.map +1 -1
- package/dist/components/DataTable/use-dev-warnings.cjs +1 -1
- package/dist/components/DataTable/use-dev-warnings.cjs.map +1 -1
- package/dist/components/DataTable/use-dev-warnings.js +5 -3
- package/dist/components/DataTable/use-dev-warnings.js.map +1 -1
- package/dist/components/Drawer/Drawer.cjs +1 -1
- package/dist/components/Drawer/Drawer.cjs.map +1 -1
- package/dist/components/Drawer/Drawer.js +43 -40
- package/dist/components/Drawer/Drawer.js.map +1 -1
- package/dist/components/FilterPanel/FilterPanel.cjs +2 -0
- package/dist/components/FilterPanel/FilterPanel.cjs.map +1 -0
- package/dist/components/FilterPanel/FilterPanel.js +75 -0
- package/dist/components/FilterPanel/FilterPanel.js.map +1 -0
- package/dist/components/FilterPanel/FilterPanel.module.cjs +3 -0
- package/dist/components/FilterPanel/FilterPanel.module.cjs.map +1 -0
- package/dist/components/FilterPanel/FilterPanel.module.js +12 -0
- package/dist/components/FilterPanel/FilterPanel.module.js.map +1 -0
- package/dist/components/Lightbox/Lightbox.cjs +1 -1
- package/dist/components/Lightbox/Lightbox.js +5 -5
- package/dist/components/Modal/Modal.cjs +1 -1
- package/dist/components/Modal/Modal.cjs.map +1 -1
- package/dist/components/Modal/Modal.js +44 -41
- package/dist/components/Modal/Modal.js.map +1 -1
- package/dist/components/Pagination/Pagination.cjs +1 -1
- package/dist/components/Pagination/Pagination.cjs.map +1 -1
- package/dist/components/Pagination/Pagination.js +31 -30
- package/dist/components/Pagination/Pagination.js.map +1 -1
- package/dist/components/Portal/tab-bridge.cjs +1 -1
- package/dist/components/Portal/tab-bridge.cjs.map +1 -1
- package/dist/components/Portal/tab-bridge.js +21 -23
- package/dist/components/Portal/tab-bridge.js.map +1 -1
- package/dist/components/Select/CaretIcon.cjs +2 -0
- package/dist/components/Select/CaretIcon.cjs.map +1 -0
- package/dist/components/Select/CaretIcon.js +21 -0
- package/dist/components/Select/CaretIcon.js.map +1 -0
- package/dist/components/Select/Select.cjs +1 -1
- package/dist/components/Select/Select.cjs.map +1 -1
- package/dist/components/Select/Select.js +33 -47
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Select/Select.module.cjs +1 -1
- package/dist/components/Select/Select.module.cjs.map +1 -1
- package/dist/components/Select/Select.module.js +4 -3
- package/dist/components/Select/Select.module.js.map +1 -1
- package/dist/components/Select/options.cjs +2 -0
- package/dist/components/Select/options.cjs.map +1 -0
- package/dist/components/Select/options.js +25 -0
- package/dist/components/Select/options.js.map +1 -0
- package/dist/components/Sidebar/Sidebar.cjs +1 -1
- package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
- package/dist/components/Sidebar/Sidebar.js +49 -43
- package/dist/components/Sidebar/Sidebar.js.map +1 -1
- package/dist/components/Sidebar/active-nav-key.cjs +2 -0
- package/dist/components/Sidebar/active-nav-key.cjs.map +1 -0
- package/dist/components/Sidebar/active-nav-key.js +22 -0
- package/dist/components/Sidebar/active-nav-key.js.map +1 -0
- package/dist/hooks/tab-sequence.cjs +2 -0
- package/dist/hooks/tab-sequence.cjs.map +1 -0
- package/dist/hooks/tab-sequence.js +53 -0
- package/dist/hooks/tab-sequence.js.map +1 -0
- package/dist/hooks/use-deep-memo.cjs +1 -1
- package/dist/hooks/use-deep-memo.cjs.map +1 -1
- package/dist/hooks/use-deep-memo.js +1 -1
- package/dist/hooks/use-deep-memo.js.map +1 -1
- package/dist/hooks/use-draft-filters.cjs +2 -0
- package/dist/hooks/use-draft-filters.cjs.map +1 -0
- package/dist/hooks/use-draft-filters.js +49 -0
- package/dist/hooks/use-draft-filters.js.map +1 -0
- package/dist/hooks/use-focus-trap.cjs +1 -1
- package/dist/hooks/use-focus-trap.cjs.map +1 -1
- package/dist/hooks/use-focus-trap.js +31 -34
- package/dist/hooks/use-focus-trap.js.map +1 -1
- package/dist/http/api-client.cjs +1 -1
- package/dist/http/api-client.cjs.map +1 -1
- package/dist/http/api-client.js +92 -80
- package/dist/http/api-client.js.map +1 -1
- package/dist/http/credential-scope.cjs +1 -1
- package/dist/http/credential-scope.cjs.map +1 -1
- package/dist/http/credential-scope.js +5 -3
- package/dist/http/credential-scope.js.map +1 -1
- package/dist/http/csrf.cjs +2 -0
- package/dist/http/csrf.cjs.map +1 -0
- package/dist/http/csrf.js +46 -0
- package/dist/http/csrf.js.map +1 -0
- package/dist/http/resumable-upload.cjs +1 -1
- package/dist/http/resumable-upload.cjs.map +1 -1
- package/dist/http/resumable-upload.js +131 -123
- package/dist/http/resumable-upload.js.map +1 -1
- package/dist/http/upload-with-progress.cjs +1 -1
- package/dist/http/upload-with-progress.cjs.map +1 -1
- package/dist/http/upload-with-progress.js +41 -33
- package/dist/http/upload-with-progress.js.map +1 -1
- package/dist/query/use-paginated-query.cjs +1 -1
- package/dist/query/use-paginated-query.cjs.map +1 -1
- package/dist/query/use-paginated-query.js +47 -30
- package/dist/query/use-paginated-query.js.map +1 -1
- package/dist/styles/FilterPanel.css +2 -0
- package/dist/styles/component/Card.css +1 -1
- package/dist/styles/component/Combobox.css +4 -3
- package/dist/styles/component/FilterPanel.css +5 -0
- package/dist/styles/component/Select.css +13 -6
- package/dist/styles/core.css +4 -4
- package/dist/styles/data.css +4 -0
- package/dist/styles/forms.css +17 -9
- package/dist/styles/identity.css +1 -1
- package/dist/styles/manifest.json +6 -0
- package/dist/styles/tokens.css +4 -4
- package/dist/styles.css +1 -1
- package/dist/tempest-react-sdk.cjs +1 -1
- package/dist/tempest-react-sdk.d.ts +658 -22
- package/dist/tempest-react-sdk.js +347 -342
- package/dist/vite/tempest-csp.cjs +3 -0
- package/dist/vite/tempest-csp.cjs.map +1 -0
- package/dist/vite/tempest-csp.js +189 -0
- package/dist/vite/tempest-csp.js.map +1 -0
- package/dist/vite.cjs +1 -1
- package/dist/vite.d.ts +145 -0
- package/dist/vite.js +2 -1
- package/package.json +2 -2
- package/template/vite.config.ts +8 -1
- 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">
|
|
@@ -3313,6 +3389,12 @@ export declare const CPFInput: ForwardRefExoticComponent<Omit<InputProps, "value
|
|
|
3313
3389
|
* header, and a development build says so once. Declare the exceptions in
|
|
3314
3390
|
* {@link ApiClientConfig.trustedOrigins}.
|
|
3315
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
|
+
*
|
|
3316
3398
|
* **Retries** are off unless you set `retry`. See {@link ApiClientConfig.retry}
|
|
3317
3399
|
* for the built-in policy; it never replays a write. A single call overrides it
|
|
3318
3400
|
* with {@link RequestOptions.retry}, and opts out of auth entirely with
|
|
@@ -4451,6 +4533,16 @@ export declare interface CreateTempestAuthOptions<TUser> {
|
|
|
4451
4533
|
storage?: "local" | "session";
|
|
4452
4534
|
/** Send cookies (needed when the refresh token lives in an httpOnly cookie). */
|
|
4453
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;
|
|
4454
4546
|
/** Custom fetch implementation (testing / SSR). Defaults to `globalThis.fetch`. */
|
|
4455
4547
|
fetcher?: typeof fetch;
|
|
4456
4548
|
/**
|
|
@@ -4821,6 +4913,91 @@ export declare interface CredentialsContainerLike {
|
|
|
4821
4913
|
}): Promise<Credential | null>;
|
|
4822
4914
|
}
|
|
4823
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
|
+
|
|
4824
5001
|
/**
|
|
4825
5002
|
* @tempest-limits param-count — `downloadCsv(rows, columns, "usuarios.csv")` reads
|
|
4826
5003
|
* in the order the sentence does, and its two trailing parameters have defaults,
|
|
@@ -4994,7 +5171,8 @@ export declare interface DataProviderOptions {
|
|
|
4994
5171
|
* - Clicking a sortable header cycles asc → desc → unsorted.
|
|
4995
5172
|
* - Search matches a case-insensitive substring across `searchKeys`
|
|
4996
5173
|
* (or every string/number column when not provided).
|
|
4997
|
-
* - 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.
|
|
4998
5176
|
* - A column with `editable` renders a button that opens an inline editor;
|
|
4999
5177
|
* `Enter` commits, `Escape` discards, `Tab` walks to the next editable cell.
|
|
5000
5178
|
*
|
|
@@ -5015,7 +5193,7 @@ export declare interface DataProviderOptions {
|
|
|
5015
5193
|
* render without changing behaviour. That is why `exhaustive-deps` is silenced on
|
|
5016
5194
|
* that dependency array.
|
|
5017
5195
|
*/
|
|
5018
|
-
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;
|
|
5019
5197
|
|
|
5020
5198
|
/** Everything a table needs regardless of who owns paging, sorting and searching. */
|
|
5021
5199
|
export declare interface DataTableBaseProps<T> extends HTMLAttributes<HTMLDivElement> {
|
|
@@ -5029,7 +5207,13 @@ export declare interface DataTableBaseProps<T> extends HTMLAttributes<HTMLDivEle
|
|
|
5029
5207
|
data: T[];
|
|
5030
5208
|
/** Column definitions. */
|
|
5031
5209
|
columns: DataTableColumn<T>[];
|
|
5032
|
-
/**
|
|
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
|
+
*/
|
|
5033
5217
|
pageSize?: number;
|
|
5034
5218
|
/** Render a search input above the table. Default false. */
|
|
5035
5219
|
searchable?: boolean;
|
|
@@ -5141,6 +5325,40 @@ export declare interface DataTableEditLabels {
|
|
|
5141
5325
|
/** Input types an editable column can use. */
|
|
5142
5326
|
export declare type DataTableEditorType = "text" | "number" | "date" | "email" | "tel" | "url";
|
|
5143
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
|
+
|
|
5144
5362
|
/**
|
|
5145
5363
|
* Paging, as one of the three shapes that actually work.
|
|
5146
5364
|
*
|
|
@@ -5192,10 +5410,10 @@ export declare type DataTablePagingProps = {
|
|
|
5192
5410
|
};
|
|
5193
5411
|
|
|
5194
5412
|
/**
|
|
5195
|
-
* The table's props: the shared half, plus one valid
|
|
5196
|
-
* sorting
|
|
5413
|
+
* The table's props: the shared half, plus one valid shape per axis — paging,
|
|
5414
|
+
* page size, sorting and searching.
|
|
5197
5415
|
*/
|
|
5198
|
-
export declare type DataTableProps<T> = DataTableBaseProps<T> & DataTablePagingProps & DataTableSortProps<T> & DataTableSearchProps;
|
|
5416
|
+
export declare type DataTableProps<T> = DataTableBaseProps<T> & DataTablePagingProps & DataTablePageSizeProps & DataTableSortProps<T> & DataTableSearchProps;
|
|
5199
5417
|
|
|
5200
5418
|
/**
|
|
5201
5419
|
* Searching: delegated, and therefore reported, or neither.
|
|
@@ -5424,6 +5642,25 @@ export declare const DEFAULT_CHUNK_SIZE: number;
|
|
|
5424
5642
|
*/
|
|
5425
5643
|
export declare const DEFAULT_CIRCUITY_FACTOR = 1.3;
|
|
5426
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
|
+
|
|
5427
5664
|
/** Default ceiling for a per-source or master gain, as a multiplier. */
|
|
5428
5665
|
export declare const DEFAULT_MAX_GAIN = 3;
|
|
5429
5666
|
|
|
@@ -5792,9 +6029,14 @@ export declare type DocumentVisibility = "visible" | "hidden";
|
|
|
5792
6029
|
*/
|
|
5793
6030
|
export declare function downloadCsv<T>(rows: readonly T[], columns: readonly CsvColumn<T>[], fileName?: string, options?: CsvOptions): Promise<void>;
|
|
5794
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
|
+
|
|
5795
6035
|
/**
|
|
5796
6036
|
* Sliding side panel. Same building blocks as {@link Modal} but anchored to
|
|
5797
|
-
* 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.
|
|
5798
6040
|
*/
|
|
5799
6041
|
export declare function Drawer({ open, onClose, placement, title, children, footer, closeOnBackdrop, closeOnEsc, hideCloseButton, className, mobilePlacement, showHandle, }: DrawerProps): ReactPortal | null;
|
|
5800
6042
|
|
|
@@ -6289,6 +6531,95 @@ export declare type FilterFieldType = "text" | "number" | "date" | "select" | "b
|
|
|
6289
6531
|
/** Comparison a filter can make. */
|
|
6290
6532
|
export declare type FilterOperator = "eq" | "ne" | "contains" | "gt" | "gte" | "lt" | "lte" | "between" | "in" | "empty" | "notEmpty";
|
|
6291
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
|
+
|
|
6292
6623
|
export declare type FilterPredicate<T> = (item: T, search: string) => boolean;
|
|
6293
6624
|
|
|
6294
6625
|
/**
|
|
@@ -9298,6 +9629,13 @@ export declare type MicrophoneStatus = "idle" | "requesting" | "ready" | "error"
|
|
|
9298
9629
|
* Portal-rendered modal dialog with backdrop, Esc handler, and slots for
|
|
9299
9630
|
* header/body/footer. Locks body scroll while open.
|
|
9300
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
|
+
*
|
|
9301
9639
|
* The `dialog` role needs an accessible name: a `title` supplies it via
|
|
9302
9640
|
* `aria-labelledby`, and a titleless dialog should pass `aria-label`. The
|
|
9303
9641
|
* header heading is only rendered when there is a title, so a close-button-only
|
|
@@ -10204,6 +10542,26 @@ export declare interface OpenModalOptions {
|
|
|
10204
10542
|
/** The operators a field offers. */
|
|
10205
10543
|
export declare function operatorsFor(field: FilterField): FilterOperator[];
|
|
10206
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
|
+
|
|
10207
10565
|
/**
|
|
10208
10566
|
* @tempest-limits file-lines — parsing a session description, merging one
|
|
10209
10567
|
* `fmtp` line and inserting a missing one are the same pass over the same
|
|
@@ -10361,6 +10719,9 @@ declare type OverriddenDomProps_12 = "children";
|
|
|
10361
10719
|
/** DOM attributes this component redefines. */
|
|
10362
10720
|
declare type OverriddenDomProps_13 = "children" | "onChange";
|
|
10363
10721
|
|
|
10722
|
+
/** DOM attributes this component redefines. */
|
|
10723
|
+
declare type OverriddenDomProps_14 = "title" | "children" | "onSubmit";
|
|
10724
|
+
|
|
10364
10725
|
/**
|
|
10365
10726
|
* DOM attributes this component redefines.
|
|
10366
10727
|
*
|
|
@@ -10445,6 +10806,14 @@ export declare interface PaginationProps {
|
|
|
10445
10806
|
onPageChange: (page: number) => void;
|
|
10446
10807
|
pageSize?: number;
|
|
10447
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
|
+
*/
|
|
10448
10817
|
pageSizeOptions?: number[];
|
|
10449
10818
|
/** Total items count; if provided, renders the summary text. */
|
|
10450
10819
|
totalItems?: number;
|
|
@@ -12132,6 +12501,17 @@ export declare interface ResumableUploadOptions {
|
|
|
12132
12501
|
trustedOrigins?: readonly string[];
|
|
12133
12502
|
/** Send cookies. Default `false`. */
|
|
12134
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;
|
|
12135
12515
|
/**
|
|
12136
12516
|
* Resume key. Defaults to a fingerprint of endpoint + file name/size/mtime, so
|
|
12137
12517
|
* picking the same file after a reload resumes instead of restarting.
|
|
@@ -12655,7 +13035,7 @@ export declare interface SegmentedControlProps<TValue extends string = string> e
|
|
|
12655
13035
|
* Native `<select>` wrapper. Either provide `options` for a quick render, or
|
|
12656
13036
|
* pass `<option>` children directly.
|
|
12657
13037
|
*
|
|
12658
|
-
*
|
|
13038
|
+
* Three variants:
|
|
12659
13039
|
*
|
|
12660
13040
|
* - `"field"` (default) — label, control, helper text and error slot, for a form.
|
|
12661
13041
|
* - `"chip"` — the control alone, sized to its content, for a settings row where
|
|
@@ -12664,20 +13044,60 @@ export declare interface SegmentedControlProps<TValue extends string = string> e
|
|
|
12664
13044
|
* list item, which is why every app ended up hand-rolling a native `<select>`
|
|
12665
13045
|
* with `appearance: none` — and hand-rolling it loses the focus ring, the
|
|
12666
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}.
|
|
12667
13050
|
*
|
|
12668
13051
|
* @example
|
|
12669
13052
|
* <Select label="Estado" options={states} placeholder="Selecione" />
|
|
12670
13053
|
*
|
|
12671
13054
|
* @example
|
|
12672
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} />
|
|
12673
13059
|
*/
|
|
12674
13060
|
export declare const Select: ForwardRefExoticComponent<SelectProps & RefAttributes<HTMLSelectElement>>;
|
|
12675
13061
|
|
|
12676
|
-
/**
|
|
12677
|
-
|
|
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> {
|
|
12678
13084
|
options?: SelectOption[];
|
|
12679
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
|
+
*/
|
|
12680
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;
|
|
12681
13101
|
}
|
|
12682
13102
|
|
|
12683
13103
|
/**
|
|
@@ -12688,13 +13108,13 @@ declare interface SelectBaseProps extends SelectHTMLAttributes<HTMLSelectElement
|
|
|
12688
13108
|
* row's own text, which the `<select>` has no relationship to — so without this
|
|
12689
13109
|
* the screen reader announces a combobox with no name at all.
|
|
12690
13110
|
*/
|
|
12691
|
-
declare interface SelectChipProps extends SelectBaseProps {
|
|
13111
|
+
export declare interface SelectChipProps extends SelectBaseProps {
|
|
12692
13112
|
variant: "chip";
|
|
12693
13113
|
"aria-label": string;
|
|
12694
13114
|
}
|
|
12695
13115
|
|
|
12696
13116
|
/** The full form field: label, control, helper text and error slot. */
|
|
12697
|
-
declare interface SelectFieldProps extends SelectBaseProps {
|
|
13117
|
+
export declare interface SelectFieldProps extends SelectBaseProps {
|
|
12698
13118
|
variant?: "field";
|
|
12699
13119
|
label?: string;
|
|
12700
13120
|
helperText?: string;
|
|
@@ -12707,7 +13127,7 @@ export declare interface SelectOption {
|
|
|
12707
13127
|
disabled?: boolean;
|
|
12708
13128
|
}
|
|
12709
13129
|
|
|
12710
|
-
export declare type SelectProps = SelectFieldProps | SelectChipProps;
|
|
13130
|
+
export declare type SelectProps = SelectFieldProps | SelectChipProps | SelectBareProps;
|
|
12711
13131
|
|
|
12712
13132
|
/**
|
|
12713
13133
|
* Minimal subset of `@sentry/browser` used by the adapter. Lets you pass
|
|
@@ -13058,6 +13478,17 @@ export declare interface ShowProps {
|
|
|
13058
13478
|
* </Show>
|
|
13059
13479
|
*
|
|
13060
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
|
|
13061
13492
|
* <Sidebar
|
|
13062
13493
|
* items={[
|
|
13063
13494
|
* { type: "section", key: "monitoring", label: "Monitoring" },
|
|
@@ -13070,7 +13501,7 @@ export declare interface ShowProps {
|
|
|
13070
13501
|
* onChange={setTab}
|
|
13071
13502
|
* />
|
|
13072
13503
|
*/
|
|
13073
|
-
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;
|
|
13074
13505
|
|
|
13075
13506
|
/**
|
|
13076
13507
|
* One entry of the navigation list.
|
|
@@ -13109,8 +13540,28 @@ export declare interface SidebarProps extends Omit<HTMLAttributes<HTMLElement>,
|
|
|
13109
13540
|
header?: ReactNode;
|
|
13110
13541
|
/** Navigation entries. An entry with no `type` is an item. */
|
|
13111
13542
|
items: SidebarEntry[];
|
|
13112
|
-
/**
|
|
13543
|
+
/**
|
|
13544
|
+
* The active item: its `key` by default, or the current route with
|
|
13545
|
+
* `match="route"`.
|
|
13546
|
+
*/
|
|
13113
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";
|
|
13114
13565
|
/** Fires when an item is clicked. Receives the item's `key`. */
|
|
13115
13566
|
onChange?: (key: string) => void;
|
|
13116
13567
|
/** Bottom slot — typically settings/profile/logout. */
|
|
@@ -14439,6 +14890,35 @@ export declare interface TooltipProps {
|
|
|
14439
14890
|
portal?: boolean;
|
|
14440
14891
|
}
|
|
14441
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
|
+
|
|
14442
14922
|
/** Convert degrees to radians. */
|
|
14443
14923
|
export declare function toRadians(degrees: number): number;
|
|
14444
14924
|
|
|
@@ -14954,6 +15434,18 @@ export declare interface UploadWithProgressOptions {
|
|
|
14954
15434
|
trustedOrigins?: readonly string[];
|
|
14955
15435
|
/** Send cookies. Defaults to false. */
|
|
14956
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;
|
|
14957
15449
|
/** Called on every `progress` event from the XHR upload channel. */
|
|
14958
15450
|
onProgress?: (event: UploadProgressEvent) => void;
|
|
14959
15451
|
/** Abort the request. */
|
|
@@ -15551,6 +16043,80 @@ export declare function useDocumentTitle(title: string): void;
|
|
|
15551
16043
|
/** Subscribe to `document.visibilityState`. Returns `"visible"` during SSR. */
|
|
15552
16044
|
export declare function useDocumentVisibility(): DocumentVisibility;
|
|
15553
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
|
+
|
|
15554
16120
|
/**
|
|
15555
16121
|
* Hook that propagates errors to the nearest {@link ErrorBoundary}.
|
|
15556
16122
|
*
|
|
@@ -15657,9 +16223,38 @@ export { UseFieldArrayReturn }
|
|
|
15657
16223
|
export declare function useFlagValue<T extends FlagValue = FlagValue>(key: string, defaultValue?: T): T;
|
|
15658
16224
|
|
|
15659
16225
|
/**
|
|
15660
|
-
* Trap keyboard focus inside `containerRef` while `active` is true.
|
|
15661
|
-
*
|
|
15662
|
-
*
|
|
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.
|
|
15663
16258
|
*/
|
|
15664
16259
|
export declare function useFocusTrap(containerRef: RefObject<HTMLElement | null>, active: boolean): void;
|
|
15665
16260
|
|
|
@@ -16624,6 +17219,13 @@ export declare function useOptionalI18n(): I18nContextValue | null;
|
|
|
16624
17219
|
* fetcher, keeps the previous page visible while the next loads, and derives
|
|
16625
17220
|
* `hasNext`/`hasPrev`/`pageCount`.
|
|
16626
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
|
+
*
|
|
16627
17229
|
* @example
|
|
16628
17230
|
* const users = usePaginatedQuery<User>({
|
|
16629
17231
|
* queryKey: ["users"],
|
|
@@ -16635,7 +17237,11 @@ export declare function useOptionalI18n(): I18nContextValue | null;
|
|
|
16635
17237
|
export declare function usePaginatedQuery<T>(options: UsePaginatedQueryOptions<T>): UsePaginatedQueryResult<T>;
|
|
16636
17238
|
|
|
16637
17239
|
export declare interface UsePaginatedQueryOptions<T> extends Omit<UseQueryOptions<OffsetPage<T>, Error, OffsetPage<T>, QueryKey>, "queryKey" | "queryFn"> {
|
|
16638
|
-
/**
|
|
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
|
+
*/
|
|
16639
17245
|
queryKey: QueryKey;
|
|
16640
17246
|
/** Fetcher receiving the offset params; return the backend envelope. */
|
|
16641
17247
|
queryFn: (params: OffsetParams) => Promise<OffsetPage<T>> | OffsetPage<T>;
|
|
@@ -16659,7 +17265,7 @@ export declare interface UsePaginatedQueryResult<T> {
|
|
|
16659
17265
|
page: OffsetPage<T> | undefined;
|
|
16660
17266
|
/** The rows of the current page (empty array while pending). */
|
|
16661
17267
|
items: T[];
|
|
16662
|
-
/** 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`). */
|
|
16663
17269
|
pageNumber: number;
|
|
16664
17270
|
/** Total page count from the last successful response. */
|
|
16665
17271
|
pageCount: number;
|
|
@@ -18703,6 +19309,36 @@ export declare interface WindowSize {
|
|
|
18703
19309
|
height: number;
|
|
18704
19310
|
}
|
|
18705
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
|
+
|
|
18706
19342
|
/**
|
|
18707
19343
|
* A bound Zustand hook augmented with auto-generated per-field selector hooks
|
|
18708
19344
|
* under `.use`. Reading a single field via `store.use.field()` subscribes the
|