tempest-react-sdk 0.48.0 → 0.50.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 (198) hide show
  1. package/dist/audio/sfx-pool.cjs +1 -1
  2. package/dist/audio/sfx-pool.cjs.map +1 -1
  3. package/dist/audio/sfx-pool.js +16 -7
  4. package/dist/audio/sfx-pool.js.map +1 -1
  5. package/dist/audio/use-sfx-pool.cjs +1 -1
  6. package/dist/audio/use-sfx-pool.cjs.map +1 -1
  7. package/dist/audio/use-sfx-pool.js +3 -8
  8. package/dist/audio/use-sfx-pool.js.map +1 -1
  9. package/dist/auth/passkey.cjs +1 -1
  10. package/dist/auth/passkey.cjs.map +1 -1
  11. package/dist/auth/passkey.js +79 -81
  12. package/dist/auth/passkey.js.map +1 -1
  13. package/dist/charts.cjs +1 -1
  14. package/dist/charts.js +4 -4
  15. package/dist/components/BarList/BarList.cjs +1 -1
  16. package/dist/components/BarList/BarList.cjs.map +1 -1
  17. package/dist/components/BarList/BarList.js +31 -24
  18. package/dist/components/BarList/BarList.js.map +1 -1
  19. package/dist/components/BarList/bar-list-model.cjs +1 -1
  20. package/dist/components/BarList/bar-list-model.cjs.map +1 -1
  21. package/dist/components/BarList/bar-list-model.js +5 -5
  22. package/dist/components/BarList/bar-list-model.js.map +1 -1
  23. package/dist/components/ClickOutside/ClickOutside.cjs +1 -1
  24. package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
  25. package/dist/components/ClickOutside/ClickOutside.js +13 -14
  26. package/dist/components/ClickOutside/ClickOutside.js.map +1 -1
  27. package/dist/components/DataTable/DataTable.cjs +1 -1
  28. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  29. package/dist/components/DataTable/DataTable.js +99 -95
  30. package/dist/components/DataTable/DataTable.js.map +1 -1
  31. package/dist/components/DataTable/use-dev-warnings.cjs +1 -1
  32. package/dist/components/DataTable/use-dev-warnings.cjs.map +1 -1
  33. package/dist/components/DataTable/use-dev-warnings.js +5 -3
  34. package/dist/components/DataTable/use-dev-warnings.js.map +1 -1
  35. package/dist/components/FilterBar/filter-apply.cjs +1 -1
  36. package/dist/components/FilterBar/filter-apply.cjs.map +1 -1
  37. package/dist/components/FilterBar/filter-apply.js +35 -38
  38. package/dist/components/FilterBar/filter-apply.js.map +1 -1
  39. package/dist/components/FilterBar/filter-query.cjs +1 -1
  40. package/dist/components/FilterBar/filter-query.cjs.map +1 -1
  41. package/dist/components/FilterBar/filter-query.js +16 -13
  42. package/dist/components/FilterBar/filter-query.js.map +1 -1
  43. package/dist/geo/use-position-tracker.cjs +1 -1
  44. package/dist/geo/use-position-tracker.cjs.map +1 -1
  45. package/dist/geo/use-position-tracker.js +25 -26
  46. package/dist/geo/use-position-tracker.js.map +1 -1
  47. package/dist/hooks/use-async.cjs +1 -1
  48. package/dist/hooks/use-async.cjs.map +1 -1
  49. package/dist/hooks/use-async.js +27 -30
  50. package/dist/hooks/use-async.js.map +1 -1
  51. package/dist/hooks/use-click-outside.cjs +1 -1
  52. package/dist/hooks/use-click-outside.cjs.map +1 -1
  53. package/dist/hooks/use-click-outside.js +8 -9
  54. package/dist/hooks/use-click-outside.js.map +1 -1
  55. package/dist/hooks/use-countdown.cjs +1 -1
  56. package/dist/hooks/use-countdown.cjs.map +1 -1
  57. package/dist/hooks/use-countdown.js +8 -13
  58. package/dist/hooks/use-countdown.js.map +1 -1
  59. package/dist/hooks/use-event-listener.cjs +1 -1
  60. package/dist/hooks/use-event-listener.cjs.map +1 -1
  61. package/dist/hooks/use-event-listener.js +6 -6
  62. package/dist/hooks/use-event-listener.js.map +1 -1
  63. package/dist/hooks/use-interval.cjs +1 -1
  64. package/dist/hooks/use-interval.cjs.map +1 -1
  65. package/dist/hooks/use-interval.js +5 -6
  66. package/dist/hooks/use-interval.js.map +1 -1
  67. package/dist/hooks/use-latest-ref.cjs.map +1 -1
  68. package/dist/hooks/use-latest-ref.js.map +1 -1
  69. package/dist/hooks/use-long-press-handlers.cjs +1 -1
  70. package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
  71. package/dist/hooks/use-long-press-handlers.js +8 -10
  72. package/dist/hooks/use-long-press-handlers.js.map +1 -1
  73. package/dist/hooks/use-long-press.cjs +1 -1
  74. package/dist/hooks/use-long-press.cjs.map +1 -1
  75. package/dist/hooks/use-long-press.js +6 -6
  76. package/dist/hooks/use-long-press.js.map +1 -1
  77. package/dist/hooks/use-online.cjs +1 -1
  78. package/dist/hooks/use-online.cjs.map +1 -1
  79. package/dist/hooks/use-online.js +10 -10
  80. package/dist/hooks/use-online.js.map +1 -1
  81. package/dist/hooks/use-service-worker-update.cjs +1 -1
  82. package/dist/hooks/use-service-worker-update.cjs.map +1 -1
  83. package/dist/hooks/use-service-worker-update.js +24 -25
  84. package/dist/hooks/use-service-worker-update.js.map +1 -1
  85. package/dist/hooks/use-stable-callback.cjs +1 -1
  86. package/dist/hooks/use-stable-callback.cjs.map +1 -1
  87. package/dist/hooks/use-stable-callback.js +4 -3
  88. package/dist/hooks/use-stable-callback.js.map +1 -1
  89. package/dist/hooks/use-timeout.cjs +1 -1
  90. package/dist/hooks/use-timeout.cjs.map +1 -1
  91. package/dist/hooks/use-timeout.js +5 -6
  92. package/dist/hooks/use-timeout.js.map +1 -1
  93. package/dist/hooks/use-typewriter.cjs +1 -1
  94. package/dist/hooks/use-typewriter.cjs.map +1 -1
  95. package/dist/hooks/use-typewriter.js +9 -18
  96. package/dist/hooks/use-typewriter.js.map +1 -1
  97. package/dist/http/api-client.cjs +1 -1
  98. package/dist/http/api-client.cjs.map +1 -1
  99. package/dist/http/api-client.js +11 -16
  100. package/dist/http/api-client.js.map +1 -1
  101. package/dist/http/describe-api-error.cjs +1 -1
  102. package/dist/http/describe-api-error.cjs.map +1 -1
  103. package/dist/http/describe-api-error.js +12 -15
  104. package/dist/http/describe-api-error.js.map +1 -1
  105. package/dist/http/errors.cjs +1 -1
  106. package/dist/http/errors.cjs.map +1 -1
  107. package/dist/http/errors.js +18 -6
  108. package/dist/http/errors.js.map +1 -1
  109. package/dist/http/resumable-upload.cjs +1 -1
  110. package/dist/http/resumable-upload.cjs.map +1 -1
  111. package/dist/http/resumable-upload.js +125 -118
  112. package/dist/http/resumable-upload.js.map +1 -1
  113. package/dist/http/retry.cjs +1 -1
  114. package/dist/http/retry.cjs.map +1 -1
  115. package/dist/http/retry.js +20 -16
  116. package/dist/http/retry.js.map +1 -1
  117. package/dist/http/use-describe-api-error.cjs +1 -1
  118. package/dist/http/use-describe-api-error.cjs.map +1 -1
  119. package/dist/http/use-describe-api-error.js +2 -2
  120. package/dist/http/use-describe-api-error.js.map +1 -1
  121. package/dist/i18n/create-i18n.cjs +1 -1
  122. package/dist/i18n/create-i18n.cjs.map +1 -1
  123. package/dist/i18n/create-i18n.js +6 -6
  124. package/dist/i18n/create-i18n.js.map +1 -1
  125. package/dist/icons/material-symbols.cjs +1 -1
  126. package/dist/icons/material-symbols.cjs.map +1 -1
  127. package/dist/icons/material-symbols.js +136 -5
  128. package/dist/icons/material-symbols.js.map +1 -1
  129. package/dist/icons.d.ts +17 -5
  130. package/dist/offline/create-offline-sync.cjs +1 -1
  131. package/dist/offline/create-offline-sync.cjs.map +1 -1
  132. package/dist/offline/create-offline-sync.js +17 -9
  133. package/dist/offline/create-offline-sync.js.map +1 -1
  134. package/dist/offline/use-offline-sync.cjs +1 -1
  135. package/dist/offline/use-offline-sync.cjs.map +1 -1
  136. package/dist/offline/use-offline-sync.js +7 -8
  137. package/dist/offline/use-offline-sync.js.map +1 -1
  138. package/dist/push/use-push-subscription.cjs +1 -1
  139. package/dist/push/use-push-subscription.cjs.map +1 -1
  140. package/dist/push/use-push-subscription.js +13 -12
  141. package/dist/push/use-push-subscription.js.map +1 -1
  142. package/dist/query/retry-policy.cjs +1 -1
  143. package/dist/query/retry-policy.cjs.map +1 -1
  144. package/dist/query/retry-policy.js +3 -3
  145. package/dist/query/retry-policy.js.map +1 -1
  146. package/dist/sse/use-event-stream.cjs +1 -1
  147. package/dist/sse/use-event-stream.cjs.map +1 -1
  148. package/dist/sse/use-event-stream.js +19 -20
  149. package/dist/sse/use-event-stream.js.map +1 -1
  150. package/dist/tabular/use-tabular-predictor.cjs +1 -1
  151. package/dist/tabular/use-tabular-predictor.cjs.map +1 -1
  152. package/dist/tabular/use-tabular-predictor.js +20 -17
  153. package/dist/tabular/use-tabular-predictor.js.map +1 -1
  154. package/dist/tempest-react-sdk.cjs +1 -1
  155. package/dist/tempest-react-sdk.d.ts +381 -143
  156. package/dist/tempest-react-sdk.js +143 -143
  157. package/dist/theme/ThemeProvider.cjs +1 -1
  158. package/dist/theme/ThemeProvider.cjs.map +1 -1
  159. package/dist/theme/ThemeProvider.js +12 -17
  160. package/dist/theme/ThemeProvider.js.map +1 -1
  161. package/dist/utils/base64.cjs +2 -0
  162. package/dist/utils/base64.cjs.map +1 -0
  163. package/dist/utils/base64.js +16 -0
  164. package/dist/utils/base64.js.map +1 -0
  165. package/dist/utils/compare-values.cjs +1 -1
  166. package/dist/utils/compare-values.cjs.map +1 -1
  167. package/dist/utils/compare-values.js +4 -3
  168. package/dist/utils/compare-values.js.map +1 -1
  169. package/dist/utils/compressed-storage.cjs +1 -1
  170. package/dist/utils/compressed-storage.cjs.map +1 -1
  171. package/dist/utils/compressed-storage.js +16 -46
  172. package/dist/utils/compressed-storage.js.map +1 -1
  173. package/dist/utils/storage.cjs +1 -1
  174. package/dist/utils/storage.cjs.map +1 -1
  175. package/dist/utils/storage.js +37 -17
  176. package/dist/utils/storage.js.map +1 -1
  177. package/dist/vision/use-camera-stream.cjs +1 -1
  178. package/dist/vision/use-camera-stream.cjs.map +1 -1
  179. package/dist/vision/use-camera-stream.js +34 -33
  180. package/dist/vision/use-camera-stream.js.map +1 -1
  181. package/dist/vite/base-url.cjs +2 -0
  182. package/dist/vite/base-url.cjs.map +1 -0
  183. package/dist/vite/base-url.js +8 -0
  184. package/dist/vite/base-url.js.map +1 -0
  185. package/dist/vite/tempest-pwa-dev-sw.cjs +1 -1
  186. package/dist/vite/tempest-pwa-dev-sw.cjs.map +1 -1
  187. package/dist/vite/tempest-pwa-dev-sw.js +54 -29
  188. package/dist/vite/tempest-pwa-dev-sw.js.map +1 -1
  189. package/dist/vite/tempest-pwa-manifest.cjs +2 -2
  190. package/dist/vite/tempest-pwa-manifest.cjs.map +1 -1
  191. package/dist/vite/tempest-pwa-manifest.js +15 -14
  192. package/dist/vite/tempest-pwa-manifest.js.map +1 -1
  193. package/dist/vite.d.ts +2 -2
  194. package/dist/ws/use-web-socket.cjs +1 -1
  195. package/dist/ws/use-web-socket.cjs.map +1 -1
  196. package/dist/ws/use-web-socket.js +40 -42
  197. package/dist/ws/use-web-socket.js.map +1 -1
  198. package/package.json +1 -1
@@ -806,6 +806,12 @@ export declare type AppBarTone = "surface" | "primary" | "transparent";
806
806
  * @example
807
807
  * const visible = applyFilters(orders, filters);
808
808
  *
809
+ * Each filter's values are normalised once, before the scan, rather than inside
810
+ * the per-row predicate: the arity, the `between` ordering and the value array
811
+ * depend only on the filter, so deriving them per row multiplied that work by
812
+ * the row count. `empty`/`notEmpty` ignore their values entirely, which is why
813
+ * the prepared shape does not need to distinguish them.
814
+ *
809
815
  * @param items - The full list.
810
816
  * @param filters - Applied filters; incomplete ones are ignored.
811
817
  * @returns A new array with the rows that satisfy every complete filter.
@@ -1504,6 +1510,15 @@ export declare interface BarcodeScanResult {
1504
1510
  * numbers on purpose: a width scaled by the total leaves every bar short in a
1505
1511
  * long list, which is when the chart is needed most.
1506
1512
  *
1513
+ * Colors come from {@link useChartColors}, the same resolver every chart in the
1514
+ * SDK uses, so a theme that declares fewer series than the eight
1515
+ * `--tempest-chart-*` slots cycles within its own palette. Reading the tokens
1516
+ * through CSS `var()` could not do that: the count lives in
1517
+ * `--tempest-chart-count`, which CSS cannot use as a modulus, so a six-color
1518
+ * brand palette got the SDK's leftover defaults in rows seven and eight — the
1519
+ * exact regression that token exists to prevent. `palette.ts` imports nothing,
1520
+ * so this pulls no chart library into the slice.
1521
+ *
1507
1522
  * @example
1508
1523
  * <BarList
1509
1524
  * items={[{ label: "Free", value: 128 }, { label: "Pro", value: 32 }]}
@@ -1571,6 +1586,9 @@ export declare type BarListSort = "desc" | "asc" | "none";
1571
1586
  * `atob` and losing the last byte — is the classic broken-WebAuthn bug, which is
1572
1587
  * why the SDK owns it instead of leaving it to each app.
1573
1588
  *
1589
+ * This is the WebAuthn-facing name for {@link base64ToBytes}; the codec itself is
1590
+ * shared, so the padding rule has one implementation rather than three.
1591
+ *
1574
1592
  * @param value - Base64url text, with or without `=` padding.
1575
1593
  * @returns The decoded bytes.
1576
1594
  */
@@ -1870,6 +1888,9 @@ export declare type ButtonVariant = "primary" | "secondary" | "danger" | "succes
1870
1888
  /**
1871
1889
  * Encode bytes as an unpadded base64url string.
1872
1890
  *
1891
+ * Normalises `ArrayBuffer` to a view — which is what the WebAuthn response
1892
+ * fields hand over — and delegates the encoding to {@link bytesToBase64}.
1893
+ *
1873
1894
  * @param value - Bytes to encode, as a view or a raw buffer.
1874
1895
  * @returns Base64url text, safe to put in JSON and in a URL.
1875
1896
  */
@@ -2607,33 +2628,17 @@ export declare function compareValues(a: unknown, b: unknown): number;
2607
2628
  /**
2608
2629
  * Typed `localStorage` wrapper that gzips what it writes.
2609
2630
  *
2610
- * Mirrors {@link storage} so the two are interchangeable at the call site; the
2611
- * difference is only in how the value is encoded.
2631
+ * {@link createJsonStorage} with {@link compressedStorageCodec}, so it is the
2632
+ * same implementation as {@link storage} and genuinely interchangeable with it —
2633
+ * `get`, `set` and `remove`, differing only in how the value is encoded. It used
2634
+ * to be a hand-written copy that had no `remove`, which made that promise false
2635
+ * for anybody who took the docstring at its word.
2636
+ *
2637
+ * When compression itself fails the value is written as plain JSON rather than
2638
+ * dropped: a slightly larger record still loads, an absent one does not. Only a
2639
+ * storage-level failure — quota, blocked storage — loses the write.
2612
2640
  */
2613
- export declare const compressedStorage: {
2614
- /**
2615
- * Read and decompress a key.
2616
- *
2617
- * @typeParam T - The expected value shape.
2618
- * @param key - Storage key.
2619
- * @param fallback - Returned when the key is absent, unreadable, or corrupt.
2620
- * @returns The stored value, or `fallback`.
2621
- */
2622
- get<T>(key: string, fallback: T): T;
2623
- /**
2624
- * Compress and write a key.
2625
- *
2626
- * When compression itself fails the value is written as plain JSON rather
2627
- * than dropped: a slightly larger record still loads, an absent one does
2628
- * not. Only a storage-level failure — quota, blocked storage — loses the
2629
- * write.
2630
- *
2631
- * @typeParam T - The value being stored.
2632
- * @param key - Storage key.
2633
- * @param value - Any JSON-serializable value.
2634
- */
2635
- set<T>(key: string, value: T): void;
2636
- };
2641
+ export declare const compressedStorage: JsonStorage;
2637
2642
 
2638
2643
  /**
2639
2644
  * Codec pair for {@link useLocalStorage}, so a compressed key gets the hook's
@@ -2642,10 +2647,7 @@ export declare const compressedStorage: {
2642
2647
  * @example
2643
2648
  * const [save, setSave] = useLocalStorage("save", EMPTY_SAVE, compressedStorageCodec);
2644
2649
  */
2645
- export declare const compressedStorageCodec: {
2646
- serialize: typeof compressToString;
2647
- deserialize: typeof decompressFromString;
2648
- };
2650
+ export declare const compressedStorageCodec: StorageCodec;
2649
2651
 
2650
2652
  /**
2651
2653
  * Serialize a value to a gzipped, base64 string carrying the format marker.
@@ -3060,6 +3062,10 @@ export declare interface CreateGrowthBookFeatureFlagsAdapterOptions {
3060
3062
  * });
3061
3063
  * i18n.t("greet", { name: "Mau" }); // "Olá, Mau"
3062
3064
  * i18n.plural("alos", 3); // "3 Alôs"
3065
+ *
3066
+ * @example
3067
+ * // A key the catalog does not define, with text to show instead of the key.
3068
+ * i18n.t("cart.empty", undefined, { default: "Seu carrinho está vazio" });
3063
3069
  */
3064
3070
  export declare function createI18n(options: CreateI18nOptions): I18n;
3065
3071
 
@@ -3120,6 +3126,34 @@ export declare function createInMemoryFlags(options?: InMemoryFlagsOptions): Fea
3120
3126
  set: (key: string, value: FlagValue) => void;
3121
3127
  };
3122
3128
 
3129
+ /**
3130
+ * Build a typed `localStorage` wrapper around a codec.
3131
+ *
3132
+ * One implementation behind every store the SDK ships, so they cannot drift in
3133
+ * surface. {@link storage} and {@link compressedStorage} are both this function —
3134
+ * before it, the compressed one was a hand-written copy of the same guards and
3135
+ * had no `remove`, while its own docstring promised the two were interchangeable
3136
+ * at the call site. They were not, and the promise failed exactly where somebody
3137
+ * followed it.
3138
+ *
3139
+ * @example
3140
+ * const session = createJsonStorage();
3141
+ * session.set("draft", { title: "Sem título" });
3142
+ *
3143
+ * @example
3144
+ * const packed = createJsonStorage(compressedStorageCodec);
3145
+ *
3146
+ * @param codec - Encoder pair. Defaults to plain JSON.
3147
+ * @returns A store with `get` / `set` / `remove`.
3148
+ *
3149
+ * @tempest-limits empty-catch — every method is best-effort by contract:
3150
+ * `localStorage` throws on quota exhaustion, in Safari private mode, and when a
3151
+ * cross-origin frame has storage blocked. A caller persisting a preference has no
3152
+ * recovery to run and no user-facing message to show, so the write is dropped and
3153
+ * the app keeps the value in memory for the session.
3154
+ */
3155
+ export declare function createJsonStorage(codec?: StorageCodec): JsonStorage;
3156
+
3123
3157
  /**
3124
3158
  * Build a [[FeatureFlagsAdapter]] backed by a LaunchDarkly JS client. Apps
3125
3159
  * initialise the client themselves (`LDClient.initialize(envKey, ctx)`) and
@@ -3630,34 +3664,6 @@ export declare interface CreateSentryTelemetryAdapterOptions {
3630
3664
  breadcrumbCategory?: string;
3631
3665
  }
3632
3666
 
3633
- /**
3634
- * A pool of preallocated `<audio>` elements for short sound effects.
3635
- *
3636
- * `new Audio(src)` on every play allocates an element and re-enters the network
3637
- * stack for a file the browser already has, which is the wrong shape for a
3638
- * sound that fires dozens of times a minute — a UI blip, a hit, a pickup. The
3639
- * pool allocates once per source and replays.
3640
- *
3641
- * This is deliberately not {@link createAudioPlayer}: that handle tracks a
3642
- * single "current" clip with loop, sink routing and lifecycle callbacks, which
3643
- * is what background music needs. Effects are the opposite case — many
3644
- * sources, all short, fire-and-forget, and the only thing that matters is that
3645
- * firing one is cheap.
3646
- *
3647
- * A blocked `play()` is swallowed. Browsers reject playback until the user has
3648
- * interacted with the page, and a sound effect is by definition not worth
3649
- * interrupting anything over; call {@link SfxPool.preload} after the first
3650
- * interaction if you want the pool warm.
3651
- *
3652
- * @param options - Master volume, base URL, voices per source and pool size.
3653
- * @returns The pool handle.
3654
- *
3655
- * @example
3656
- * const sfx = createSfxPool({ volume: 0.6, baseUrl: import.meta.env.BASE_URL });
3657
- * sfx.preload(["sfx/select.mp3", "sfx/back.mp3"]);
3658
- *
3659
- * <button onClick={() => sfx.play("sfx/select.mp3")}>Confirmar</button>
3660
- */
3661
3667
  export declare function createSfxPool(options?: SfxPoolOptions): SfxPool;
3662
3668
 
3663
3669
  /**
@@ -4159,6 +4165,53 @@ export declare interface DataProviderOptions {
4159
4165
  */
4160
4166
  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;
4161
4167
 
4168
+ /** Everything a table needs regardless of who owns paging, sorting and searching. */
4169
+ export declare interface DataTableBaseProps<T> extends HTMLAttributes<HTMLDivElement> {
4170
+ /**
4171
+ * The rows to work with.
4172
+ *
4173
+ * By default this is the **full** dataset and sorting, searching and paging
4174
+ * all happen in memory. Pass `totalItems` and it becomes the current page as
4175
+ * the server returned it, with those three delegated to the caller.
4176
+ */
4177
+ data: T[];
4178
+ /** Column definitions. */
4179
+ columns: DataTableColumn<T>[];
4180
+ /** Rows per page. Default 10. */
4181
+ pageSize?: number;
4182
+ /** Render a search input above the table. Default false. */
4183
+ searchable?: boolean;
4184
+ /**
4185
+ * Keys to match the search term against. When omitted, every column whose
4186
+ * value is a string or number is searched.
4187
+ */
4188
+ searchKeys?: (keyof T)[];
4189
+ /** Initial sort applied before any header interaction. */
4190
+ initialSort?: DataTableSort<T>;
4191
+ /** Stable key extractor for rows. Defaults to the row index. */
4192
+ rowKey?: (row: T, index: number) => string | number;
4193
+ /** Content shown when no rows match. */
4194
+ emptyMessage?: ReactNode;
4195
+ /**
4196
+ * Persist an accepted cell edit. Return a promise: while it is pending the cell
4197
+ * already shows the new value, and a rejection rolls that back and surfaces the
4198
+ * error in the cell. Without this prop no column is editable.
4199
+ */
4200
+ onCellChange?: (change: DataTableCellChange<T>) => void | Promise<void>;
4201
+ /** Override the PT-BR copy of the editing affordances. */
4202
+ editLabels?: Partial<DataTableEditLabels>;
4203
+ /**
4204
+ * A fetch is in flight.
4205
+ *
4206
+ * With rows already on screen they stay put, dimmed and `aria-busy`, so the
4207
+ * page does not jump under the cursor between pages. With no rows yet it
4208
+ * renders placeholder lines at full height, which is a different statement
4209
+ * from `emptyMessage`: "loading" and "there is nothing" are not the same
4210
+ * screen.
4211
+ */
4212
+ loading?: boolean;
4213
+ }
4214
+
4162
4215
  /** One accepted cell edit, handed to `onCellChange`. */
4163
4216
  export declare interface DataTableCellChange<T> {
4164
4217
  /** The row as it was before the edit. */
@@ -4236,40 +4289,24 @@ export declare interface DataTableEditLabels {
4236
4289
  /** Input types an editable column can use. */
4237
4290
  export declare type DataTableEditorType = "text" | "number" | "date" | "email" | "tel" | "url";
4238
4291
 
4239
- export declare interface DataTableProps<T> extends HTMLAttributes<HTMLDivElement> {
4240
- /**
4241
- * The rows to work with.
4242
- *
4243
- * By default this is the **full** dataset and sorting, searching and paging
4244
- * all happen in memory. Pass `totalItems` and it becomes the current page as
4245
- * the server returned it, with those three delegated to the caller.
4246
- */
4247
- data: T[];
4248
- /** Column definitions. */
4249
- columns: DataTableColumn<T>[];
4250
- /** Rows per page. Default 10. */
4251
- pageSize?: number;
4252
- /** Render a search input above the table. Default false. */
4253
- searchable?: boolean;
4254
- /**
4255
- * Keys to match the search term against. When omitted, every column whose
4256
- * value is a string or number is searched.
4257
- */
4258
- searchKeys?: (keyof T)[];
4259
- /** Initial sort applied before any header interaction. */
4260
- initialSort?: DataTableSort<T>;
4261
- /** Stable key extractor for rows. Defaults to the row index. */
4262
- rowKey?: (row: T, index: number) => string | number;
4263
- /** Content shown when no rows match. */
4264
- emptyMessage?: ReactNode;
4265
- /**
4266
- * Persist an accepted cell edit. Return a promise: while it is pending the cell
4267
- * already shows the new value, and a rejection rolls that back and surfaces the
4268
- * error in the cell. Without this prop no column is editable.
4269
- */
4270
- onCellChange?: (change: DataTableCellChange<T>) => void | Promise<void>;
4271
- /** Override the PT-BR copy of the editing affordances. */
4272
- editLabels?: Partial<DataTableEditLabels>;
4292
+ /**
4293
+ * Paging, as one of the three shapes that actually work.
4294
+ *
4295
+ * These used to be three optional props, so the compiler accepted
4296
+ * `totalItems` with no `page` a table whose pager moves an internal page while
4297
+ * `data` keeps showing page one. Every prop was optional on its own, so the only
4298
+ * place left to catch it was a `console.warn` in dev, in the browser, with the
4299
+ * component mounted. As a union the same mistake is a build error at the call
4300
+ * site, for free, everywhere.
4301
+ */
4302
+ export declare type DataTablePagingProps = {
4303
+ /** Not server mode. */
4304
+ totalItems?: never;
4305
+ /** The table owns the page. */
4306
+ page?: never;
4307
+ /** Nothing to report to. */
4308
+ onPageChange?: never;
4309
+ } | {
4273
4310
  /**
4274
4311
  * Total row count across every page — the `total` of a paginated envelope.
4275
4312
  *
@@ -4279,49 +4316,99 @@ export declare interface DataTableProps<T> extends HTMLAttributes<HTMLDivElement
4279
4316
  * (see `manualSort` / `manualSearch`, which are implied here). Pair it with
4280
4317
  * `page` and `onPageChange`.
4281
4318
  */
4282
- totalItems?: number;
4319
+ totalItems?: never;
4283
4320
  /** Current page, 1-based. Controlled — required in server mode. */
4284
- page?: number;
4321
+ page: number;
4285
4322
  /** Called with the next page. Required whenever `page` is controlled. */
4286
- onPageChange?: (page: number) => void;
4323
+ onPageChange: (page: number) => void;
4324
+ } | {
4287
4325
  /**
4288
- * Sorting is the caller's job: clicking a header reports through
4289
- * `onSortChange` and the rows are left in the order they arrived.
4326
+ * Total row count across every page — the `total` of a paginated envelope.
4290
4327
  *
4291
- * Implied by `totalItems`, because sorting the page in memory would sort
4292
- * *that page only* while the header claims the whole table is ordered.
4328
+ * Passing it switches the table to **server mode**: `data` is read as the
4329
+ * current page, the page count comes from this number instead of
4330
+ * `data.length`, and sorting and searching are delegated to the caller
4331
+ * (see `manualSort` / `manualSearch`, which are implied here). `page` and
4332
+ * `onPageChange` come with it — the type says so, because a server-mode
4333
+ * table without them silently shows page one forever.
4293
4334
  */
4294
- manualSort?: boolean;
4295
- /** Called with the next sort state `null` when the header cycles back to unsorted. */
4296
- onSortChange?: (sort: DataTableSort<T> | null) => void;
4335
+ totalItems: number;
4336
+ /** Current page, 1-based. Controlled, and required in server mode. */
4337
+ page: number;
4338
+ /** Called with the next page. */
4339
+ onPageChange: (page: number) => void;
4340
+ };
4341
+
4342
+ /**
4343
+ * The table's props: the shared half, plus one valid paging shape and one valid
4344
+ * sorting shape.
4345
+ */
4346
+ export declare type DataTableProps<T> = DataTableBaseProps<T> & DataTablePagingProps & DataTableSortProps<T> & DataTableSearchProps;
4347
+
4348
+ /**
4349
+ * Searching: delegated, and therefore reported, or neither.
4350
+ *
4351
+ * `manualSearch` without `onSearchChange` renders a search box that filters
4352
+ * nothing and tells nobody — the same shape of lie as a header arrow that turns
4353
+ * without sorting.
4354
+ *
4355
+ * Independent of the paging axis on purpose, and that leaves one gap this type
4356
+ * does not close: `totalItems` *implies* `manualSearch`, so a server-mode table
4357
+ * with `searchable` and no `onSearchChange` falls into the same hole without ever
4358
+ * writing `manualSearch`. Closing it means the search axis has to read the paging
4359
+ * axis, which crosses two three-member unions into nine and turns every mismatch
4360
+ * into a wall of candidate shapes. That case is a dev warning instead — the one
4361
+ * spot where runtime really is the cheaper check, and `use-dev-warnings.ts` says
4362
+ * so at the call site.
4363
+ */
4364
+ export declare type DataTableSearchProps = {
4365
+ /** The table filters the rows it has. */
4366
+ manualSearch?: false;
4367
+ /** Called with the current search term (debouncing, if any, is the caller's). */
4368
+ onSearchChange?: (term: string) => void;
4369
+ } | {
4297
4370
  /**
4298
- * Searching is the caller's job: typing reports through `onSearchChange` and
4299
- * the rows are left as they arrived.
4371
+ * Searching is the caller's job: typing reports through `onSearchChange`
4372
+ * and the rows are left as they arrived.
4300
4373
  *
4301
4374
  * Implied by `totalItems`. Filtering the current page would hide the rows
4302
4375
  * that do not match *on this page* and show nothing for a term that only
4303
4376
  * matches on page three — an empty table that looks like "no results".
4304
4377
  */
4305
- manualSearch?: boolean;
4306
- /** Called with the current search term (debouncing, if any, is the caller's). */
4307
- onSearchChange?: (term: string) => void;
4308
- /**
4309
- * A fetch is in flight.
4310
- *
4311
- * With rows already on screen they stay put, dimmed and `aria-busy`, so the
4312
- * page does not jump under the cursor between pages. With no rows yet it
4313
- * renders placeholder lines at full height, which is a different statement
4314
- * from `emptyMessage`: "loading" and "there is nothing" are not the same
4315
- * screen.
4316
- */
4317
- loading?: boolean;
4318
- }
4378
+ manualSearch: true;
4379
+ /** Where the typing goes. Required, since nothing else acts on it. */
4380
+ onSearchChange: (term: string) => void;
4381
+ };
4319
4382
 
4320
4383
  export declare interface DataTableSort<T> {
4321
4384
  key: keyof T;
4322
4385
  direction: SortDirection;
4323
4386
  }
4324
4387
 
4388
+ /**
4389
+ * Sorting: delegated, and therefore reported, or neither.
4390
+ *
4391
+ * `manualSort` without `onSortChange` renders a header that moves its arrow and
4392
+ * changes nothing else — the arrow is a lie the compiler can now catch.
4393
+ */
4394
+ export declare type DataTableSortProps<T> = {
4395
+ /** The table sorts the rows it has. */
4396
+ manualSort?: false;
4397
+ /** Called with the next sort state — `null` when the header cycles back to unsorted. */
4398
+ onSortChange?: (sort: DataTableSort<T> | null) => void;
4399
+ } | {
4400
+ /**
4401
+ * Sorting is the caller's job: clicking a header reports through
4402
+ * `onSortChange` and the rows are left in the order they arrived.
4403
+ *
4404
+ * Implied by `totalItems`, because sorting the page in memory would sort
4405
+ * *that page only* while the header claims the whole table is ordered.
4406
+ */
4407
+ manualSort: true;
4408
+ /** Where the click goes. Required, since nothing else acts on it. */
4409
+ onSortChange: (sort: DataTableSort<T> | null) => void;
4410
+ };
4411
+
4325
4412
  /**
4326
4413
  * Thin wrapper around the native `<input type="date">` (or `datetime-local`,
4327
4414
  * `time`, `month`). For richer pickers, pair with `react-datepicker` directly
@@ -5215,15 +5302,55 @@ export declare function filtersFromSearchParams(params: URLSearchParams, fields:
5215
5302
  * will not answer an `empty` filter, while {@link applyFilters} treats blank
5216
5303
  * text as empty.
5217
5304
  *
5305
+ * The defaults are that dialect, not a universal truth. A backend that names its
5306
+ * substring column something other than `name`, or that spells its operators
5307
+ * differently, passes `options` — the alternative was an encoder whose special
5308
+ * cases were a wall for anyone not on the Tempest stack.
5309
+ *
5218
5310
  * @example
5219
5311
  * const params = filtersToQueryParams(filters);
5220
5312
  * params.set("page", String(page));
5221
5313
  * const data = await api.get(`/orders?${params}`);
5222
5314
  *
5315
+ * @example
5316
+ * // A backend whose searchable column is `razao_social` and that spells `ne`
5317
+ * // the Django way.
5318
+ * const params = filtersToQueryParams(filters, {
5319
+ * substringColumns: ["razao_social"],
5320
+ * operatorSuffix: { ne: "__exclude" },
5321
+ * });
5322
+ *
5223
5323
  * @param filters - Applied filters; incomplete ones are ignored.
5324
+ * @param options - Dialect overrides. Defaults to the `tempest-fastapi-sdk` one.
5224
5325
  * @returns Params ready to append to a request URL.
5225
5326
  */
5226
- export declare function filtersToQueryParams(filters: readonly Filter[]): URLSearchParams;
5327
+ export declare function filtersToQueryParams(filters: readonly Filter[], options?: FiltersToQueryParamsOptions): URLSearchParams;
5328
+
5329
+ /** Overrides for the backend dialect {@link filtersToQueryParams} encodes into. */
5330
+ export declare interface FiltersToQueryParamsOptions {
5331
+ /**
5332
+ * Columns whose `eq` is emitted as `<column>__iexact` rather than as the bare
5333
+ * column name. Default `["name"]`, which is what `build_filter_condition`
5334
+ * special-cases.
5335
+ *
5336
+ * Pass the columns **your** backend treats that way — `nome`, `titulo`,
5337
+ * `razao_social` — or `[]` when it treats none of them specially and a bare
5338
+ * `eq` should stay bare.
5339
+ */
5340
+ substringColumns?: readonly string[];
5341
+ /**
5342
+ * Operator suffixes, merged over the `tempest-fastapi-sdk` dialect, so an
5343
+ * override names only the operators that differ.
5344
+ *
5345
+ * @example
5346
+ * // A DRF-style backend
5347
+ * filtersToQueryParams(filters, {
5348
+ * substringColumns: [],
5349
+ * operatorSuffix: { contains: "__icontains", ne: "__exclude" },
5350
+ * });
5351
+ */
5352
+ operatorSuffix?: Partial<Record<FilterOperator, string>>;
5353
+ }
5227
5354
 
5228
5355
  /**
5229
5356
  * Serialize filters into URL search params.
@@ -5914,14 +6041,16 @@ export declare interface I18n {
5914
6041
  fallbackLocale: string | null;
5915
6042
  /**
5916
6043
  * Translate `key`, interpolating `{name}` placeholders from `params`.
5917
- * Falls back to the configured fallback locale, then to the key itself.
6044
+ * Falls back to the configured fallback locale, then to `options.default`,
6045
+ * then to the key itself.
5918
6046
  */
5919
- t: (key: string, params?: InterpolationValues) => string;
6047
+ t: (key: string, params?: InterpolationValues, options?: TranslateOptions) => string;
5920
6048
  /**
5921
6049
  * Plural-aware translation. Tries `${key}_one` for `count === 1` and
5922
6050
  * `${key}_other` otherwise, with `{count}` available for interpolation.
6051
+ * Falls back to `options.default`, then to the key itself.
5923
6052
  */
5924
- plural: (key: string, count: number, params?: InterpolationValues) => string;
6053
+ plural: (key: string, count: number, params?: InterpolationValues, options?: TranslateOptions) => string;
5925
6054
  /** Format a number using `Intl.NumberFormat` on the active locale. */
5926
6055
  formatNumber: (value: number, options?: Intl.NumberFormatOptions) => string;
5927
6056
  /** Format a Date using `Intl.DateTimeFormat` on the active locale. */
@@ -6563,6 +6692,31 @@ export declare function isPlatformAuthenticatorAvailable(): Promise<boolean>;
6563
6692
  */
6564
6693
  export declare function isPushSupported(): boolean;
6565
6694
 
6695
+ /**
6696
+ * Whether an HTTP status describes a condition a replay can plausibly fix.
6697
+ *
6698
+ * The single owner of that decision. It used to be spelled out in three places —
6699
+ * the client's own policy, the react-query default and the bare `retry()` helper
6700
+ * — and they had already drifted: the query default was missing `425`, so the
6701
+ * same `425 Too Early` was replayed through `createApiClient({ retry: true })`
6702
+ * and not replayed through `useQuery`. Same app, same error, two behaviours, and
6703
+ * no test caught it because each file asserted against its own copy.
6704
+ *
6705
+ * Deliberately about the status and nothing else. Whether a *non*-API error is
6706
+ * worth replaying, and whether the request's method may be replayed at all, are
6707
+ * the caller's calls: {@link createApiClient} refuses a non-idempotent method,
6708
+ * while a bare `retry()` has no method to inspect.
6709
+ *
6710
+ * @example
6711
+ * await api.get("/report", {
6712
+ * retry: { shouldRetry: (error) => isApiError(error) && isRetriableStatus(error.status) },
6713
+ * });
6714
+ *
6715
+ * @param status - The HTTP status, where `0` means the request never landed.
6716
+ * @returns Whether a retry is worth attempting.
6717
+ */
6718
+ export declare function isRetriableStatus(status: number): boolean;
6719
+
6566
6720
  /** Whether `getDisplayMedia` is reachable at all. */
6567
6721
  export declare function isScreenCaptureSupported(): boolean;
6568
6722
 
@@ -6599,6 +6753,33 @@ export declare function isValidLongitude(value: number): boolean;
6599
6753
  /** Whether `MediaRecorder` exists and can produce at least one video container. */
6600
6754
  export declare function isVideoRecordingSupported(): boolean;
6601
6755
 
6756
+ /** The surface every store built by {@link createJsonStorage} exposes. */
6757
+ export declare interface JsonStorage {
6758
+ /**
6759
+ * Read and decode a key.
6760
+ *
6761
+ * @typeParam T - The expected value shape.
6762
+ * @param key - Storage key.
6763
+ * @param fallback - Returned when the key is absent, unreadable, or corrupt.
6764
+ * @returns The stored value, or `fallback`.
6765
+ */
6766
+ get<T>(key: string, fallback: T): T;
6767
+ /**
6768
+ * Encode and write a key.
6769
+ *
6770
+ * @typeParam T - The value being stored.
6771
+ * @param key - Storage key.
6772
+ * @param value - Any value the codec can represent.
6773
+ */
6774
+ set<T>(key: string, value: T): void;
6775
+ /**
6776
+ * Delete a key.
6777
+ *
6778
+ * @param key - Storage key.
6779
+ */
6780
+ remove(key: string): void;
6781
+ }
6782
+
6602
6783
  /**
6603
6784
  * Kanban board: columns of cards, reorderable within a column and movable across
6604
6785
  * columns, by pointer **or** keyboard.
@@ -9703,7 +9884,12 @@ export declare interface RetryOptions {
9703
9884
  respectRetryAfter?: boolean;
9704
9885
  /**
9705
9886
  * Return false to stop retrying for a specific error.
9706
- * Default: retry on any thrown error.
9887
+ *
9888
+ * Default: replay anything that is not a recognisable API error — a
9889
+ * transport failure has no status to judge — and, for one that is, only the
9890
+ * statuses {@link isRetriableStatus} accepts. A `403` on an admin-only
9891
+ * endpoint and a `404` for a deleted record are the server's final answer;
9892
+ * repeating them spends the caller's time to show the same error twice.
9707
9893
  */
9708
9894
  shouldRetry?: (error: unknown, attempt: number) => boolean;
9709
9895
  /** Called before each retry with the upcoming delay. */
@@ -10221,6 +10407,11 @@ export declare interface ShareResult {
10221
10407
  * of another round trip. A network failure or a 5xx is a different thing: it may
10222
10408
  * well succeed on the next try, so those keep the previous behaviour.
10223
10409
  *
10410
+ * The status list is {@link isRetriableStatus}, shared with the client's own
10411
+ * policy. It used to be a second copy here, and the copy was missing `425` — so
10412
+ * a `425 Too Early` was replayed by `createApiClient({ retry: true })` and not
10413
+ * by a query, for the same error in the same app.
10414
+ *
10224
10415
  * @example
10225
10416
  * new QueryClient({ defaultOptions: { queries: { retry: shouldRetryQuery } } });
10226
10417
  *
@@ -10810,20 +11001,18 @@ export declare interface StepperProps {
10810
11001
  export declare function stopAudio(): void;
10811
11002
 
10812
11003
  /**
10813
- * Typed wrapper around `localStorage` that JSON-encodes values and
10814
- * silently handles environments where storage is unavailable (SSR, private mode).
10815
- *
10816
- * @tempest-limits empty-catch — every method here is best-effort by contract:
10817
- * `localStorage` throws on quota exhaustion, in Safari private mode, and when a
10818
- * cross-origin frame has storage blocked. A caller persisting a preference has no
10819
- * recovery to run and no user-facing message to show, so the write is dropped and
10820
- * the app keeps the value in memory for the session.
11004
+ * Typed wrapper around `localStorage` that JSON-encodes values and silently
11005
+ * handles environments where storage is unavailable (SSR, private mode).
10821
11006
  */
10822
- export declare const storage: {
10823
- get<T>(key: string, fallback: T): T;
10824
- set<T>(key: string, value: T): void;
10825
- remove(key: string): void;
10826
- };
11007
+ export declare const storage: JsonStorage;
11008
+
11009
+ /** How a {@link createJsonStorage} store turns values into text and back. */
11010
+ export declare interface StorageCodec {
11011
+ /** Encode a value for storage. */
11012
+ serialize: <T>(value: T) => string;
11013
+ /** Decode a stored string. */
11014
+ deserialize: <T>(raw: string) => T;
11015
+ }
10827
11016
 
10828
11017
  /** Raw usage/quota reading from the Storage API, in bytes. */
10829
11018
  declare interface StorageEstimate_2 {
@@ -10863,6 +11052,16 @@ export declare interface SyncRunSummary {
10863
11052
  succeeded: number;
10864
11053
  /** Entries that failed and stay queued for the next run. */
10865
11054
  failed: number;
11055
+ /**
11056
+ * Entries left untried because an earlier entry for the **same record**
11057
+ * failed this run.
11058
+ *
11059
+ * They stay queued and are attempted next run, in order. Counted apart from
11060
+ * `failed` because they were never sent: reporting them as failures would
11061
+ * blame the server for a decision this engine made, and folding them in would
11062
+ * make `succeeded + failed` stop accounting for the queue.
11063
+ */
11064
+ deferred: number;
10866
11065
  /** Total wall-clock milliseconds the run took. */
10867
11066
  durationMs: number;
10868
11067
  /** `true` when the run was skipped because the device was offline. */
@@ -11768,6 +11967,23 @@ export declare interface TransferProps extends Omit<HTMLAttributes<HTMLDivElemen
11768
11967
  /** Which pane an operation is about. */
11769
11968
  export declare type TransferSide = "source" | "target";
11770
11969
 
11970
+ /** Per-call options for {@link I18n.t} and {@link I18n.plural}. */
11971
+ export declare interface TranslateOptions {
11972
+ /**
11973
+ * Text to use when the catalog defines neither the key nor its fallback.
11974
+ *
11975
+ * Without this, a miss returns the key, and a caller that wants its own text
11976
+ * instead has to *detect* the miss — which from the outside means comparing
11977
+ * the result against the key it just passed in. That heuristic is wrong for a
11978
+ * catalog that legitimately maps a key to itself, and it is what every
11979
+ * translatable string the SDK ships would otherwise have to copy.
11980
+ *
11981
+ * Interpolated like any other message, so a default carries `{placeholders}`
11982
+ * too and is not second-class.
11983
+ */
11984
+ default?: string;
11985
+ }
11986
+
11771
11987
  /**
11772
11988
  * Estimated travel between two coordinates. Mirrors the `TravelEstimate`
11773
11989
  * schema from `tempest-fastapi-sdk` (`geo/schemas.py`), snake_case preserved so
@@ -12426,7 +12642,8 @@ export declare interface UseClipboardResult {
12426
12642
  * which a counter held in state cannot do.
12427
12643
  *
12428
12644
  * The interval stops once it reaches zero instead of ticking forever behind a
12429
- * clamp.
12645
+ * clamp — `useInterval` pauses on a `null` delay, so reaching zero is what tears
12646
+ * the timer down.
12430
12647
  *
12431
12648
  * @param durationMs - Length of the window.
12432
12649
  * @param startedAt - Epoch ms the window opened (`Date.now()` when it started).
@@ -12886,6 +13103,17 @@ export declare interface UseKeyboardShortcutOptions {
12886
13103
  * want to *call* — it hands back a callable with a stable identity, rather than
12887
13104
  * making every call site reach through `.current`.
12888
13105
  *
13106
+ * **List the returned ref in your effect's dependencies.** It is a stable object,
13107
+ * so the effect never re-runs because of it, but `react-hooks/exhaustive-deps`
13108
+ * cannot prove that for a custom hook the way it does for a bare `useRef`.
13109
+ * Listing it lets the rule verify the array instead of taking an omission on
13110
+ * trust.
13111
+ *
13112
+ * **Not for holding the previous value.** The write happens during render, so
13113
+ * `.current` is already the current value by the time any effect reads it. A hook
13114
+ * that wants the value from the *previous* commit — `usePrevious` — needs the
13115
+ * effect-based write, and swapping it for this would make it return the present.
13116
+ *
12889
13117
  * @typeParam T - The tracked value.
12890
13118
  * @param value - The value to track. Written on every render.
12891
13119
  * @returns A stable ref whose `current` holds the latest `value`.
@@ -14098,7 +14326,9 @@ export declare interface UseSetResult<T> {
14098
14326
  * `volume` is tracked separately: changing it calls `setVolume` on the existing
14099
14327
  * pool rather than rebuilding it, which would throw away every clip the user
14100
14328
  * has already downloaded — exactly the cost the pool exists to avoid.
14101
- * `baseUrl`, `voices` and `maxSources` are read once, at creation.
14329
+ * `baseUrl`, `voices` and `maxSources` are read once, at creation. The options
14330
+ * object is forwarded whole rather than rebuilt field by field, so a field added
14331
+ * to {@link SfxPoolOptions} does not silently stop reaching the pool.
14102
14332
  *
14103
14333
  * @param options - Passed through to {@link createSfxPool}.
14104
14334
  * @returns A stable pool handle.
@@ -14316,12 +14546,15 @@ export declare interface UseSpeechRecognitionResult {
14316
14546
  * `callback` argument. Use to break dependency cycles in effects without
14317
14547
  * triggering re-runs when the callback identity changes.
14318
14548
  *
14319
- * The assignment happens **during render** on purpose. Moving it into an effect
14320
- * would satisfy the React Compiler rules but open a one-commit staleness window:
14321
- * an effect declared before this hook's own effect, in the same commit, would call
14322
- * the previous render's callback. This is a primitive other hooks build on, so a
14323
- * subtle staleness here is worse than the rule violation. Prefer React's
14549
+ * Built on {@link useLatestRef}, which owns the render-time assignment and the
14550
+ * reason it is not an effect: an effect would satisfy the React Compiler rules
14551
+ * but open a one-commit staleness window. What this adds is the callable with a
14552
+ * stable identity, so callers do not reach through `.current`. Prefer React's
14324
14553
  * `useEffectEvent` once it ships as stable.
14554
+ *
14555
+ * The ref is listed as a dependency because it is one — a stable object across
14556
+ * renders, so the returned identity never changes. Listing it is what lets the
14557
+ * exhaustive-deps rule verify that instead of taking an empty array on trust.
14325
14558
  */
14326
14559
  export declare function useStableCallback<TArgs extends unknown[], TReturn>(callback: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
14327
14560
 
@@ -14472,6 +14705,11 @@ export declare function useTranslate(): I18nContextValue["t"];
14472
14705
  * Always give the reader a way out: an animation that cannot be skipped is a
14473
14706
  * tax on anyone re-reading or moving fast, which is what `skip` is for.
14474
14707
  *
14708
+ * How far the reveal got is derived rather than stored: a `speedMs` of `0` reads
14709
+ * as "all of it" without a state write, and `useInterval` pausing on a `null`
14710
+ * delay is what stops the timer at the end. Both used to need an effect that
14711
+ * cleared its own interval from inside a state updater.
14712
+ *
14475
14713
  * @param text - The full string to reveal. Nullish is treated as empty.
14476
14714
  * @param speedMs - Delay between characters. `0` or less renders instantly,
14477
14715
  * which is the hook-safe way to honour `prefers-reduced-motion`.