@bquery/bquery 1.8.2 → 1.9.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 (75) hide show
  1. package/README.md +96 -24
  2. package/dist/{a11y-DVBCy09c.js → a11y-_9X-kt-_.js} +2 -2
  3. package/dist/{a11y-DVBCy09c.js.map → a11y-_9X-kt-_.js.map} +1 -1
  4. package/dist/a11y.es.mjs +1 -1
  5. package/dist/{forms-UcRHsYxC.js → forms-UhAeJEoO.js} +13 -13
  6. package/dist/{forms-UcRHsYxC.js.map → forms-UhAeJEoO.js.map} +1 -1
  7. package/dist/forms.es.mjs +1 -1
  8. package/dist/full.d.ts +4 -4
  9. package/dist/full.d.ts.map +1 -1
  10. package/dist/full.es.mjs +201 -196
  11. package/dist/full.iife.js +20 -20
  12. package/dist/full.iife.js.map +1 -1
  13. package/dist/full.umd.js +20 -20
  14. package/dist/full.umd.js.map +1 -1
  15. package/dist/index.es.mjs +214 -209
  16. package/dist/media/index.d.ts +10 -3
  17. package/dist/media/index.d.ts.map +1 -1
  18. package/dist/media/observers.d.ts +99 -0
  19. package/dist/media/observers.d.ts.map +1 -0
  20. package/dist/media/types.d.ts +125 -0
  21. package/dist/media/types.d.ts.map +1 -1
  22. package/dist/media-D4zLj9t-.js +514 -0
  23. package/dist/media-D4zLj9t-.js.map +1 -0
  24. package/dist/media.es.mjs +12 -9
  25. package/dist/mount-B-JvH6Y0.js +449 -0
  26. package/dist/mount-B-JvH6Y0.js.map +1 -0
  27. package/dist/reactive/index.d.ts +2 -2
  28. package/dist/reactive/index.d.ts.map +1 -1
  29. package/dist/reactive/signal.d.ts +2 -1
  30. package/dist/reactive/signal.d.ts.map +1 -1
  31. package/dist/reactive/watch.d.ts +49 -0
  32. package/dist/reactive/watch.d.ts.map +1 -1
  33. package/dist/reactive-BjpLkclt.js +1184 -0
  34. package/dist/{reactive-DwkhUJfP.js.map → reactive-BjpLkclt.js.map} +1 -1
  35. package/dist/reactive.es.mjs +35 -33
  36. package/dist/{router-CQikC9Ed.js → router-BieVwgci.js} +2 -2
  37. package/dist/{router-CQikC9Ed.js.map → router-BieVwgci.js.map} +1 -1
  38. package/dist/router.es.mjs +1 -1
  39. package/dist/{ssr-_dAcGdzu.js → ssr-CrGSJySz.js} +3 -3
  40. package/dist/{ssr-_dAcGdzu.js.map → ssr-CrGSJySz.js.map} +1 -1
  41. package/dist/ssr.es.mjs +1 -1
  42. package/dist/{store-Cb3gPRve.js → store-CY6sjTW3.js} +2 -2
  43. package/dist/{store-Cb3gPRve.js.map → store-CY6sjTW3.js.map} +1 -1
  44. package/dist/store.es.mjs +1 -1
  45. package/dist/{testing-C5Sjfsna.js → testing-UjAtu9aQ.js} +9 -9
  46. package/dist/{testing-C5Sjfsna.js.map → testing-UjAtu9aQ.js.map} +1 -1
  47. package/dist/testing.es.mjs +1 -1
  48. package/dist/view/directives/aria.d.ts +7 -0
  49. package/dist/view/directives/aria.d.ts.map +1 -0
  50. package/dist/view/directives/error.d.ts +7 -0
  51. package/dist/view/directives/error.d.ts.map +1 -0
  52. package/dist/view/directives/index.d.ts +2 -0
  53. package/dist/view/directives/index.d.ts.map +1 -1
  54. package/dist/view/mount.d.ts.map +1 -1
  55. package/dist/view/process.d.ts +2 -0
  56. package/dist/view/process.d.ts.map +1 -1
  57. package/dist/view.es.mjs +2 -2
  58. package/package.json +5 -5
  59. package/src/full.ts +12 -0
  60. package/src/media/index.ts +20 -2
  61. package/src/media/observers.ts +421 -0
  62. package/src/media/types.ts +136 -0
  63. package/src/reactive/index.ts +3 -0
  64. package/src/reactive/signal.ts +2 -1
  65. package/src/reactive/watch.ts +137 -0
  66. package/src/view/directives/aria.ts +72 -0
  67. package/src/view/directives/error.ts +56 -0
  68. package/src/view/directives/index.ts +2 -0
  69. package/src/view/mount.ts +4 -0
  70. package/src/view/process.ts +6 -0
  71. package/dist/media-i-fB5WxI.js +0 -340
  72. package/dist/media-i-fB5WxI.js.map +0 -1
  73. package/dist/mount-B4Y8bk8Z.js +0 -403
  74. package/dist/mount-B4Y8bk8Z.js.map +0 -1
  75. package/dist/reactive-DwkhUJfP.js +0 -1148
@@ -0,0 +1,421 @@
1
+ /**
2
+ * Reactive wrappers for browser Observer APIs.
3
+ *
4
+ * Provides composables for IntersectionObserver, ResizeObserver, and
5
+ * MutationObserver that expose reactive signals updated on every callback.
6
+ *
7
+ * @module bquery/media
8
+ */
9
+
10
+ import { readonly, signal } from '../reactive/index';
11
+ import type {
12
+ IntersectionObserverOptions,
13
+ IntersectionObserverSignal,
14
+ IntersectionObserverState,
15
+ MutationObserverOptions,
16
+ MutationObserverSignal,
17
+ MutationObserverState,
18
+ ResizeObserverOptions,
19
+ ResizeObserverSignal,
20
+ ResizeObserverState,
21
+ } from './types';
22
+
23
+ type ResizeObserverBoxSizeLike = {
24
+ inlineSize: number;
25
+ blockSize: number;
26
+ };
27
+
28
+ const getResizeDimensions = (
29
+ entry: ResizeObserverEntry,
30
+ box: ResizeObserverBoxOptions
31
+ ): Pick<ResizeObserverState, 'width' | 'height'> => {
32
+ let boxSize:
33
+ | ResizeObserverBoxSizeLike
34
+ | readonly ResizeObserverBoxSizeLike[]
35
+ | undefined;
36
+
37
+ if (box === 'border-box') {
38
+ boxSize = entry.borderBoxSize;
39
+ } else if (box === 'device-pixel-content-box') {
40
+ boxSize = (
41
+ entry as ResizeObserverEntry & {
42
+ devicePixelContentBoxSize?:
43
+ | ResizeObserverBoxSizeLike
44
+ | readonly ResizeObserverBoxSizeLike[];
45
+ }
46
+ ).devicePixelContentBoxSize;
47
+ } else {
48
+ boxSize = entry.contentBoxSize;
49
+ }
50
+
51
+ const resolvedBoxSize = Array.isArray(boxSize) ? boxSize[0] : boxSize;
52
+ if (
53
+ resolvedBoxSize &&
54
+ typeof resolvedBoxSize.inlineSize === 'number' &&
55
+ typeof resolvedBoxSize.blockSize === 'number'
56
+ ) {
57
+ return {
58
+ width: resolvedBoxSize.inlineSize,
59
+ height: resolvedBoxSize.blockSize,
60
+ };
61
+ }
62
+
63
+ return {
64
+ width: entry.contentRect.width,
65
+ height: entry.contentRect.height,
66
+ };
67
+ };
68
+
69
+ // ─── useIntersectionObserver ────────────────────────────────────────────────
70
+
71
+ /**
72
+ * Returns a reactive signal tracking element intersection with a root viewport.
73
+ *
74
+ * The returned handle exposes `observe()` / `unobserve()` methods so you can
75
+ * control which elements are watched. If an initial `target` is provided it is
76
+ * observed immediately.
77
+ *
78
+ * @param target - Optional element or array of elements to observe immediately.
79
+ * @param options - Standard `IntersectionObserver` init options.
80
+ * @returns A readonly reactive signal with intersection state, plus `observe`,
81
+ * `unobserve`, and `destroy` methods.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * import { useIntersectionObserver } from '@bquery/bquery/media';
86
+ * import { effect } from '@bquery/bquery/reactive';
87
+ *
88
+ * const el = document.querySelector('#lazy-image')!;
89
+ * const io = useIntersectionObserver(el, { threshold: 0.5 });
90
+ *
91
+ * effect(() => {
92
+ * if (io.value.isIntersecting) {
93
+ * console.log('Element is 50% visible');
94
+ * }
95
+ * });
96
+ *
97
+ * // Cleanup when done
98
+ * io.destroy();
99
+ * ```
100
+ */
101
+ export const useIntersectionObserver = (
102
+ target?: Element | Element[] | null,
103
+ options?: IntersectionObserverOptions,
104
+ ): IntersectionObserverSignal => {
105
+ const initial: IntersectionObserverState = {
106
+ isIntersecting: false,
107
+ intersectionRatio: 0,
108
+ entry: null,
109
+ };
110
+
111
+ const s = signal<IntersectionObserverState>(initial);
112
+ let observer: IntersectionObserver | undefined;
113
+ let destroyed = false;
114
+
115
+ if (typeof window !== 'undefined' && typeof IntersectionObserver !== 'undefined') {
116
+ try {
117
+ observer = new IntersectionObserver(
118
+ (entries: IntersectionObserverEntry[]) => {
119
+ if (destroyed) return;
120
+ const last = entries[entries.length - 1];
121
+ if (last) {
122
+ s.value = {
123
+ isIntersecting: last.isIntersecting,
124
+ intersectionRatio: last.intersectionRatio,
125
+ entry: last,
126
+ };
127
+ }
128
+ },
129
+ {
130
+ root: options?.root ?? null,
131
+ rootMargin: options?.rootMargin ?? '0px',
132
+ threshold: options?.threshold ?? 0,
133
+ },
134
+ );
135
+
136
+ // Observe initial targets
137
+ if (target) {
138
+ const targets = Array.isArray(target) ? target : [target];
139
+ for (const el of targets) {
140
+ observer.observe(el);
141
+ }
142
+ }
143
+ } catch {
144
+ if (observer) observer.disconnect();
145
+ observer = undefined;
146
+ }
147
+ }
148
+
149
+ const ro = readonly(s) as IntersectionObserverSignal;
150
+
151
+ Object.defineProperties(ro, {
152
+ observe: {
153
+ enumerable: false,
154
+ configurable: true,
155
+ value(el: Element): void {
156
+ if (!destroyed) {
157
+ try {
158
+ observer?.observe(el);
159
+ } catch {}
160
+ }
161
+ },
162
+ },
163
+ unobserve: {
164
+ enumerable: false,
165
+ configurable: true,
166
+ value(el: Element): void {
167
+ if (!destroyed) observer?.unobserve(el);
168
+ },
169
+ },
170
+ destroy: {
171
+ enumerable: false,
172
+ configurable: true,
173
+ value(): void {
174
+ if (destroyed) return;
175
+ destroyed = true;
176
+ observer?.disconnect();
177
+ observer = undefined;
178
+ s.dispose();
179
+ },
180
+ },
181
+ });
182
+
183
+ return ro;
184
+ };
185
+
186
+ // ─── useResizeObserver ──────────────────────────────────────────────────────
187
+
188
+ /**
189
+ * Returns a reactive signal tracking the size of observed elements.
190
+ *
191
+ * By default it uses the `content-box`, but you can configure the observed box
192
+ * via the underlying `ResizeObserver` options (e.g. `{ box: 'border-box' }`).
193
+ *
194
+ * The returned handle exposes `observe()` / `unobserve()` methods. If an
195
+ * initial `target` is provided it is observed immediately.
196
+ *
197
+ * @param target - Optional element or array of elements to observe immediately.
198
+ * @param options - ResizeObserver options (e.g. `{ box: 'border-box' }`).
199
+ * @returns A readonly reactive signal with `{ width, height, entry }` derived
200
+ * from the configured box, plus `observe`, `unobserve`, and `destroy` methods.
201
+ *
202
+ * @example
203
+ * ```ts
204
+ * import { useResizeObserver } from '@bquery/bquery/media';
205
+ * import { effect } from '@bquery/bquery/reactive';
206
+ *
207
+ * const el = document.querySelector('#panel')!;
208
+ * const size = useResizeObserver(el);
209
+ *
210
+ * effect(() => {
211
+ * console.log(`Panel size: ${size.value.width}x${size.value.height}`);
212
+ * });
213
+ *
214
+ * size.destroy();
215
+ * ```
216
+ */
217
+ export const useResizeObserver = (
218
+ target?: Element | Element[] | null,
219
+ options?: ResizeObserverOptions,
220
+ ): ResizeObserverSignal => {
221
+ const initial: ResizeObserverState = {
222
+ width: 0,
223
+ height: 0,
224
+ entry: null,
225
+ };
226
+
227
+ const s = signal<ResizeObserverState>(initial);
228
+ let observer: ResizeObserver | undefined;
229
+ let destroyed = false;
230
+ const box = options?.box ?? 'content-box';
231
+ const observeOptions = options?.box ? { box: options.box } : undefined;
232
+
233
+ if (typeof window !== 'undefined' && typeof ResizeObserver !== 'undefined') {
234
+ try {
235
+ observer = new ResizeObserver((entries: ResizeObserverEntry[]) => {
236
+ if (destroyed) return;
237
+ const last = entries[entries.length - 1];
238
+ if (last) {
239
+ const { width, height } = getResizeDimensions(last, box);
240
+ s.value = {
241
+ width,
242
+ height,
243
+ entry: last,
244
+ };
245
+ }
246
+ });
247
+
248
+ // Observe initial targets
249
+ if (target) {
250
+ const targets = Array.isArray(target) ? target : [target];
251
+ for (const el of targets) {
252
+ observer.observe(el, observeOptions);
253
+ }
254
+ }
255
+ } catch {
256
+ if (observer) observer.disconnect();
257
+ observer = undefined;
258
+ }
259
+ }
260
+
261
+ const ro = readonly(s) as ResizeObserverSignal;
262
+
263
+ Object.defineProperties(ro, {
264
+ observe: {
265
+ enumerable: false,
266
+ configurable: true,
267
+ value(el: Element): void {
268
+ if (!destroyed) {
269
+ try {
270
+ observer?.observe(el, observeOptions);
271
+ } catch {}
272
+ }
273
+ },
274
+ },
275
+ unobserve: {
276
+ enumerable: false,
277
+ configurable: true,
278
+ value(el: Element): void {
279
+ if (!destroyed) observer?.unobserve(el);
280
+ },
281
+ },
282
+ destroy: {
283
+ enumerable: false,
284
+ configurable: true,
285
+ value(): void {
286
+ if (destroyed) return;
287
+ destroyed = true;
288
+ observer?.disconnect();
289
+ observer = undefined;
290
+ s.dispose();
291
+ },
292
+ },
293
+ });
294
+
295
+ return ro;
296
+ };
297
+
298
+ // ─── useMutationObserver ────────────────────────────────────────────────────
299
+
300
+ /**
301
+ * Returns a reactive signal tracking DOM mutations on observed nodes.
302
+ *
303
+ * The returned handle exposes `observe()` and `takeRecords()` for manual
304
+ * lifecycle control. If an initial `target` is provided it is observed
305
+ * immediately.
306
+ *
307
+ * @param target - Optional node to observe immediately.
308
+ * @param options - MutationObserver init options. Defaults to `{ attributes: true }`.
309
+ * @returns A readonly reactive signal with `{ mutations, count }`, plus
310
+ * `observe`, `takeRecords`, and `destroy` methods.
311
+ *
312
+ * @example
313
+ * ```ts
314
+ * import { useMutationObserver } from '@bquery/bquery/media';
315
+ * import { effect } from '@bquery/bquery/reactive';
316
+ *
317
+ * const el = document.querySelector('#dynamic-content')!;
318
+ * const mo = useMutationObserver(el, { childList: true, subtree: true });
319
+ *
320
+ * effect(() => {
321
+ * console.log(`${mo.value.count} mutation batches observed`);
322
+ * });
323
+ *
324
+ * mo.destroy();
325
+ * ```
326
+ */
327
+ export const useMutationObserver = (
328
+ target?: Node | null,
329
+ options?: MutationObserverOptions,
330
+ ): MutationObserverSignal => {
331
+ const initial: MutationObserverState = {
332
+ mutations: [],
333
+ count: 0,
334
+ };
335
+
336
+ const s = signal<MutationObserverState>(initial);
337
+ let observer: MutationObserver | undefined;
338
+ let destroyed = false;
339
+ let totalCount = 0;
340
+
341
+ const resolvedOptions: MutationObserverInit = {
342
+ attributes: options?.attributes ?? true,
343
+ childList: options?.childList ?? false,
344
+ characterData: options?.characterData ?? false,
345
+ subtree: options?.subtree ?? false,
346
+ attributeOldValue: options?.attributeOldValue ?? false,
347
+ characterDataOldValue: options?.characterDataOldValue ?? false,
348
+ ...(options && options.attributeFilter !== undefined
349
+ ? { attributeFilter: options.attributeFilter }
350
+ : {}),
351
+ };
352
+
353
+ if (!resolvedOptions.attributes && !resolvedOptions.childList && !resolvedOptions.characterData) {
354
+ resolvedOptions.attributes = true;
355
+ }
356
+
357
+ if (!resolvedOptions.attributes) {
358
+ resolvedOptions.attributeOldValue = false;
359
+ delete resolvedOptions.attributeFilter;
360
+ }
361
+
362
+ if (!resolvedOptions.characterData) {
363
+ resolvedOptions.characterDataOldValue = false;
364
+ }
365
+
366
+ if (typeof window !== 'undefined' && typeof MutationObserver !== 'undefined') {
367
+ try {
368
+ observer = new MutationObserver((mutations: MutationRecord[]) => {
369
+ if (destroyed) return;
370
+ totalCount += 1;
371
+ s.value = {
372
+ mutations,
373
+ count: totalCount,
374
+ };
375
+ });
376
+
377
+ if (target) {
378
+ observer.observe(target, resolvedOptions);
379
+ }
380
+ } catch {
381
+ if (observer) observer.disconnect();
382
+ observer = undefined;
383
+ }
384
+ }
385
+
386
+ const ro = readonly(s) as MutationObserverSignal;
387
+
388
+ Object.defineProperties(ro, {
389
+ observe: {
390
+ enumerable: false,
391
+ configurable: true,
392
+ value(node: Node): void {
393
+ if (!destroyed) {
394
+ try {
395
+ observer?.observe(node, resolvedOptions);
396
+ } catch {}
397
+ }
398
+ },
399
+ },
400
+ takeRecords: {
401
+ enumerable: false,
402
+ configurable: true,
403
+ value(): MutationRecord[] {
404
+ return observer?.takeRecords() ?? [];
405
+ },
406
+ },
407
+ destroy: {
408
+ enumerable: false,
409
+ configurable: true,
410
+ value(): void {
411
+ if (destroyed) return;
412
+ destroyed = true;
413
+ observer?.disconnect();
414
+ observer = undefined;
415
+ s.dispose();
416
+ },
417
+ },
418
+ });
419
+
420
+ return ro;
421
+ };
@@ -175,3 +175,139 @@ export interface ClipboardAPI {
175
175
  /** Write text to the clipboard. */
176
176
  write: (text: string) => Promise<void>;
177
177
  }
178
+
179
+ // ─── Observer Composable Types ───────────────────────────────────────────────
180
+
181
+ /**
182
+ * Options for {@link useIntersectionObserver}.
183
+ */
184
+ export interface IntersectionObserverOptions {
185
+ /**
186
+ * Root element or document to use as the viewport.
187
+ * Defaults to the browser viewport when `null` or omitted.
188
+ */
189
+ root?: Element | Document | null;
190
+ /** Margin around the root, using CSS margin syntax (e.g. `'10px 20px'`). */
191
+ rootMargin?: string;
192
+ /**
193
+ * Thresholds at which the callback fires.
194
+ * A single number or an array of numbers between 0 and 1.
195
+ */
196
+ threshold?: number | number[];
197
+ }
198
+
199
+ /**
200
+ * State tracked by {@link useIntersectionObserver}.
201
+ *
202
+ * Reflects the most recent {@link IntersectionObserverEntry} reported by the
203
+ * underlying `IntersectionObserver` callback, not an aggregate across all
204
+ * observed targets.
205
+ */
206
+ export interface IntersectionObserverState {
207
+ /**
208
+ * Whether the most recently reported entry is intersecting.
209
+ *
210
+ * This is equivalent to `entry?.isIntersecting ?? false` and does not
211
+ * represent an aggregate across all observed targets.
212
+ */
213
+ isIntersecting: boolean;
214
+ /**
215
+ * The intersection ratio (0–1) from the most recent entry.
216
+ *
217
+ * This is equivalent to `entry?.intersectionRatio ?? 0`.
218
+ */
219
+ intersectionRatio: number;
220
+ /** The most recent `IntersectionObserverEntry`, or `null` before the first callback. */
221
+ entry: IntersectionObserverEntry | null;
222
+ }
223
+
224
+ /**
225
+ * Extended handle returned by {@link useIntersectionObserver}.
226
+ *
227
+ * In addition to the reactive signal, exposes `observe()` and `unobserve()`
228
+ * so elements can be added or removed after creation.
229
+ */
230
+ export interface IntersectionObserverSignal extends MediaSignalHandle<IntersectionObserverState> {
231
+ /** Start observing the given element. */
232
+ observe(target: Element): void;
233
+ /** Stop observing the given element. */
234
+ unobserve(target: Element): void;
235
+ }
236
+
237
+ /**
238
+ * Options for {@link useResizeObserver}.
239
+ */
240
+ export interface ResizeObserverOptions {
241
+ /**
242
+ * Which CSS box model to observe.
243
+ * @default 'content-box'
244
+ */
245
+ box?: ResizeObserverBoxOptions;
246
+ }
247
+
248
+ /**
249
+ * State tracked by {@link useResizeObserver}.
250
+ */
251
+ export interface ResizeObserverState {
252
+ /** Observed box width of the element in pixels (based on the configured `box`). */
253
+ width: number;
254
+ /** Observed box height of the element in pixels (based on the configured `box`). */
255
+ height: number;
256
+ /** The most recent `ResizeObserverEntry`, or `null` before the first callback. */
257
+ entry: ResizeObserverEntry | null;
258
+ }
259
+
260
+ /**
261
+ * Extended handle returned by {@link useResizeObserver}.
262
+ *
263
+ * Exposes `observe()` and `unobserve()` so elements can be added or removed
264
+ * after creation.
265
+ */
266
+ export interface ResizeObserverSignal extends MediaSignalHandle<ResizeObserverState> {
267
+ /** Start observing the given element. */
268
+ observe(target: Element): void;
269
+ /** Stop observing the given element. */
270
+ unobserve(target: Element): void;
271
+ }
272
+
273
+ /**
274
+ * Options for {@link useMutationObserver}.
275
+ */
276
+ export interface MutationObserverOptions {
277
+ /** Observe attribute changes. @default true */
278
+ attributes?: boolean;
279
+ /** Observe child list changes. @default false */
280
+ childList?: boolean;
281
+ /** Observe character data changes. @default false */
282
+ characterData?: boolean;
283
+ /** Observe the entire subtree. @default false */
284
+ subtree?: boolean;
285
+ /** Record previous attribute values. @default false */
286
+ attributeOldValue?: boolean;
287
+ /** Record previous character data values. @default false */
288
+ characterDataOldValue?: boolean;
289
+ /** Filter observed attributes to this list. */
290
+ attributeFilter?: string[];
291
+ }
292
+
293
+ /**
294
+ * State tracked by {@link useMutationObserver}.
295
+ */
296
+ export interface MutationObserverState {
297
+ /** The list of mutations from the most recent callback. */
298
+ mutations: MutationRecord[];
299
+ /** Total number of mutation callbacks received. */
300
+ count: number;
301
+ }
302
+
303
+ /**
304
+ * Extended handle returned by {@link useMutationObserver}.
305
+ *
306
+ * Exposes `observe()`, `takeRecords()`, and `destroy()` for manual lifecycle control.
307
+ */
308
+ export interface MutationObserverSignal extends MediaSignalHandle<MutationObserverState> {
309
+ /** Start observing mutations on the given target. Uses the options from construction time. */
310
+ observe(target: Node): void;
311
+ /** Take and clear any pending mutation records. */
312
+ takeRecords(): MutationRecord[];
313
+ }
@@ -40,6 +40,8 @@ export {
40
40
  useWebSocketChannel,
41
41
  untrack,
42
42
  watch,
43
+ watchDebounce,
44
+ watchThrottle,
43
45
  } from './signal';
44
46
 
45
47
  export type {
@@ -90,6 +92,7 @@ export type {
90
92
  UseWebSocketChannelReturn,
91
93
  UseWebSocketOptions,
92
94
  UseWebSocketReturn,
95
+ WatchOptions,
93
96
  WebSocketHeartbeatConfig,
94
97
  WebSocketReconnectConfig,
95
98
  WebSocketSerializer,
@@ -26,7 +26,7 @@ export { effectScope, getCurrentScope, onScopeDispose } from './scope';
26
26
  export { isComputed, isSignal } from './type-guards';
27
27
  export { toValue } from './to-value';
28
28
  export { untrack } from './untrack';
29
- export { watch } from './watch';
29
+ export { watch, watchDebounce, watchThrottle } from './watch';
30
30
  export { useEventSource, useWebSocket, useWebSocketChannel } from './websocket';
31
31
 
32
32
  export type { CleanupFn, Observer } from './internals';
@@ -57,6 +57,7 @@ export type {
57
57
  UsePaginatedFetchOptions,
58
58
  } from './pagination';
59
59
  export type { PollingState, UsePollingOptions } from './polling';
60
+ export type { WatchOptions } from './watch';
60
61
  export type {
61
62
  IdExtractor,
62
63
  ResourceListActions,