@vizejs/composable 0.343.0 → 0.347.7

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 (42) hide show
  1. package/dist/abort-signal.d.mts +96 -0
  2. package/dist/abort-signal.mjs +203 -0
  3. package/dist/async-resource.d.mts +97 -0
  4. package/dist/async-resource.mjs +99 -0
  5. package/dist/capability-BNpkvSy5.d.mts +93 -0
  6. package/dist/capability.d.mts +2 -0
  7. package/dist/capability.mjs +37 -0
  8. package/dist/catalog-CuWhR-0q.d.mts +506 -0
  9. package/dist/catalog-DOXTbk4r.mjs +529 -0
  10. package/dist/catalog.d.mts +2 -0
  11. package/dist/catalog.mjs +2 -0
  12. package/dist/disposal-scope.d.mts +93 -0
  13. package/dist/disposal-scope.mjs +119 -0
  14. package/dist/event-listener.d.mts +85 -0
  15. package/dist/event-listener.mjs +55 -0
  16. package/dist/index.d.mts +19 -786
  17. package/dist/index.mjs +19 -751
  18. package/dist/locale.d.mts +65 -0
  19. package/dist/locale.mjs +72 -0
  20. package/dist/media-query.d.mts +56 -0
  21. package/dist/media-query.mjs +56 -0
  22. package/dist/retry-async.d.mts +91 -0
  23. package/dist/retry-async.mjs +136 -0
  24. package/dist/retry-delay.d.mts +73 -0
  25. package/dist/retry-delay.mjs +50 -0
  26. package/dist/scope.d.mts +18 -0
  27. package/dist/scope.mjs +23 -0
  28. package/dist/timeout-scheduler.d.mts +18 -0
  29. package/dist/timeout-scheduler.mjs +1 -0
  30. package/dist/use-counter.d.mts +91 -0
  31. package/dist/use-counter.mjs +67 -0
  32. package/dist/use-debounced.d.mts +87 -0
  33. package/dist/use-debounced.mjs +98 -0
  34. package/dist/use-history.d.mts +105 -0
  35. package/dist/use-history.mjs +137 -0
  36. package/dist/use-previous.d.mts +43 -0
  37. package/dist/use-previous.mjs +11 -0
  38. package/dist/use-throttled.d.mts +107 -0
  39. package/dist/use-throttled.mjs +124 -0
  40. package/dist/use-toggle.d.mts +45 -0
  41. package/dist/use-toggle.mjs +34 -0
  42. package/package.json +91 -1
@@ -0,0 +1,107 @@
1
+ import { TimeoutScheduler } from "./timeout-scheduler.mjs";
2
+ import { MaybeRefOrGetter, ShallowRef } from "vue";
3
+
4
+ //#region src/use-throttled.d.ts
5
+ /** Options for {@link useThrottled}. */
6
+ interface UseThrottledOptions {
7
+ /**
8
+ * Apply the first change of a cooldown window immediately.
9
+ *
10
+ * @default true
11
+ */
12
+ readonly leading?: boolean;
13
+ /**
14
+ * Apply the newest change collected during a cooldown window when the
15
+ * window ends. When disabled, changes inside a window are dropped.
16
+ *
17
+ * @default true
18
+ */
19
+ readonly trailing?: boolean;
20
+ /**
21
+ * Applies the timing policy when no browser `window` is available.
22
+ *
23
+ * Keep this disabled during server rendering, where the throttled view
24
+ * mirrors the source synchronously instead of starting timers. Enable it
25
+ * for native, desktop, worker, and test runtimes whose scheduler is
26
+ * lifecycle-bound.
27
+ *
28
+ * @default false
29
+ */
30
+ readonly runOnServer?: boolean;
31
+ /**
32
+ * Owns the single-shot cooldown timer.
33
+ *
34
+ * @default globalThis timer functions
35
+ */
36
+ readonly scheduler?: TimeoutScheduler;
37
+ }
38
+ /** Reactive throttled view and controls returned by {@link useThrottled}. */
39
+ interface ThrottledControls<Value> {
40
+ /** Readonly view of the source updated at most once per cooldown window. */
41
+ readonly throttled: Readonly<ShallowRef<Value>>;
42
+ /** Whether a trailing update is waiting for the current window to end. */
43
+ readonly pending: Readonly<ShallowRef<boolean>>;
44
+ /**
45
+ * Discard the waiting trailing update and close the cooldown window, so
46
+ * the next change starts fresh on a leading edge.
47
+ *
48
+ * @returns Whether a waiting trailing update was discarded.
49
+ */
50
+ readonly cancel: () => boolean;
51
+ /**
52
+ * Apply the waiting trailing update immediately and close the cooldown
53
+ * window. Without a waiting update the window is left untouched.
54
+ *
55
+ * @returns Whether a waiting trailing update was applied.
56
+ */
57
+ readonly flush: () => boolean;
58
+ }
59
+ /**
60
+ * Create a readonly throttled view of a reactive source.
61
+ *
62
+ * Changes are observed with `flush: "sync"`, so every synchronous write
63
+ * counts. Outside a cooldown window, a change applies immediately when
64
+ * {@link UseThrottledOptions.leading} is enabled (otherwise it waits as a
65
+ * trailing update) and opens a window of `waitMs` milliseconds. Changes
66
+ * inside a window are collected as the trailing candidate; when the window
67
+ * ends with a candidate waiting, the source value current at that moment is
68
+ * applied and the next window opens back to back, keeping applications
69
+ * spaced by `waitMs`. A window that ends without a candidate closes silently.
70
+ * `waitMs` is reactive and is read each time a window opens; changing it
71
+ * never disturbs an already-open window. A wait of `0` still defers trailing
72
+ * updates to the next scheduler tick.
73
+ *
74
+ * Server rendering is explicit: without a browser `window` (and with
75
+ * {@link UseThrottledOptions.runOnServer} disabled) no timer ever starts and
76
+ * the view mirrors the source synchronously, so server-rendered output shows
77
+ * current values and nothing leaks. `pending` stays `false` and the controls
78
+ * report `false` in that mode.
79
+ *
80
+ * Cleanup rule: the watcher and any open window timer are released when the
81
+ * owning reactive scope stops; call inside an active scope. Outside one, the
82
+ * watcher lives as long as the source and `cancel()` only clears the window.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * const scrollY = shallowRef(0);
87
+ * const { throttled } = useThrottled(scrollY, 100);
88
+ * scrollY.value = 40; // applied immediately (leading edge)
89
+ * scrollY.value = 80; // applied when the 100ms window ends
90
+ * ```
91
+ *
92
+ * @param source Reactive source to throttle.
93
+ * @param waitMs Reactive cooldown in milliseconds; must be finite and at
94
+ * least zero. Fractions are truncated.
95
+ * @param options Edge policy and runtime scheduling overrides.
96
+ * @default options {}
97
+ * @throws `RangeError` tagged `VIZE_COMPOSE_THROTTLE_INVALID_WAIT` when the
98
+ * resolved wait is not finite or is negative, both synchronously at creation
99
+ * (even in mirror mode) and again each time a window opens.
100
+ * @throws `TypeError` tagged `VIZE_COMPOSE_THROTTLE_INVALID_EDGES` when both
101
+ * `leading` and `trailing` are disabled, because updates could then never
102
+ * propagate.
103
+ * @returns Readonly throttled view, pending flag, and cancel/flush controls.
104
+ */
105
+ declare function useThrottled<Value>(source: MaybeRefOrGetter<Value>, waitMs: MaybeRefOrGetter<number>, options?: UseThrottledOptions): ThrottledControls<Value>;
106
+ //#endregion
107
+ export { ThrottledControls, UseThrottledOptions, useThrottled };
@@ -0,0 +1,124 @@
1
+ import { tryOnScopeDispose } from "./scope.mjs";
2
+ import { shallowRef, toValue, watch } from "vue";
3
+ //#region src/use-throttled.ts
4
+ const defaultScheduler = {
5
+ setTimeout: (callback, delayMs) => globalThis.setTimeout(callback, delayMs),
6
+ clearTimeout: (handle) => {
7
+ globalThis.clearTimeout(handle);
8
+ }
9
+ };
10
+ /**
11
+ * Create a readonly throttled view of a reactive source.
12
+ *
13
+ * Changes are observed with `flush: "sync"`, so every synchronous write
14
+ * counts. Outside a cooldown window, a change applies immediately when
15
+ * {@link UseThrottledOptions.leading} is enabled (otherwise it waits as a
16
+ * trailing update) and opens a window of `waitMs` milliseconds. Changes
17
+ * inside a window are collected as the trailing candidate; when the window
18
+ * ends with a candidate waiting, the source value current at that moment is
19
+ * applied and the next window opens back to back, keeping applications
20
+ * spaced by `waitMs`. A window that ends without a candidate closes silently.
21
+ * `waitMs` is reactive and is read each time a window opens; changing it
22
+ * never disturbs an already-open window. A wait of `0` still defers trailing
23
+ * updates to the next scheduler tick.
24
+ *
25
+ * Server rendering is explicit: without a browser `window` (and with
26
+ * {@link UseThrottledOptions.runOnServer} disabled) no timer ever starts and
27
+ * the view mirrors the source synchronously, so server-rendered output shows
28
+ * current values and nothing leaks. `pending` stays `false` and the controls
29
+ * report `false` in that mode.
30
+ *
31
+ * Cleanup rule: the watcher and any open window timer are released when the
32
+ * owning reactive scope stops; call inside an active scope. Outside one, the
33
+ * watcher lives as long as the source and `cancel()` only clears the window.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * const scrollY = shallowRef(0);
38
+ * const { throttled } = useThrottled(scrollY, 100);
39
+ * scrollY.value = 40; // applied immediately (leading edge)
40
+ * scrollY.value = 80; // applied when the 100ms window ends
41
+ * ```
42
+ *
43
+ * @param source Reactive source to throttle.
44
+ * @param waitMs Reactive cooldown in milliseconds; must be finite and at
45
+ * least zero. Fractions are truncated.
46
+ * @param options Edge policy and runtime scheduling overrides.
47
+ * @default options {}
48
+ * @throws `RangeError` tagged `VIZE_COMPOSE_THROTTLE_INVALID_WAIT` when the
49
+ * resolved wait is not finite or is negative, both synchronously at creation
50
+ * (even in mirror mode) and again each time a window opens.
51
+ * @throws `TypeError` tagged `VIZE_COMPOSE_THROTTLE_INVALID_EDGES` when both
52
+ * `leading` and `trailing` are disabled, because updates could then never
53
+ * propagate.
54
+ * @returns Readonly throttled view, pending flag, and cancel/flush controls.
55
+ */
56
+ function useThrottled(source, waitMs, options = {}) {
57
+ const leading = options.leading ?? true;
58
+ const trailing = options.trailing ?? true;
59
+ if (!leading && !trailing) throw new TypeError("[VIZE_COMPOSE_THROTTLE_INVALID_EDGES] at least one of leading or trailing must be enabled");
60
+ const scheduler = options.scheduler ?? defaultScheduler;
61
+ const throttled = shallowRef(toValue(source));
62
+ const pending = shallowRef(false);
63
+ let windowHandle;
64
+ let windowOpen = false;
65
+ resolveWaitMs(toValue(waitMs));
66
+ const openWindow = () => {
67
+ windowOpen = true;
68
+ windowHandle = scheduler.setTimeout(() => {
69
+ windowHandle = void 0;
70
+ if (!pending.value) {
71
+ windowOpen = false;
72
+ return;
73
+ }
74
+ pending.value = false;
75
+ throttled.value = toValue(source);
76
+ openWindow();
77
+ }, resolveWaitMs(toValue(waitMs)));
78
+ };
79
+ const closeWindow = () => {
80
+ if (windowOpen) scheduler.clearTimeout(windowHandle);
81
+ windowHandle = void 0;
82
+ windowOpen = false;
83
+ pending.value = false;
84
+ };
85
+ const cancel = () => {
86
+ const hadTrailing = pending.value;
87
+ closeWindow();
88
+ return hadTrailing;
89
+ };
90
+ const flush = () => {
91
+ if (!pending.value) return false;
92
+ closeWindow();
93
+ throttled.value = toValue(source);
94
+ return true;
95
+ };
96
+ watch(() => toValue(source), (next) => {
97
+ if (typeof window === "undefined" && !(options.runOnServer ?? false)) {
98
+ throttled.value = next;
99
+ return;
100
+ }
101
+ if (windowOpen) {
102
+ if (trailing) pending.value = true;
103
+ return;
104
+ }
105
+ if (leading) throttled.value = next;
106
+ else pending.value = true;
107
+ openWindow();
108
+ }, { flush: "sync" });
109
+ tryOnScopeDispose(() => {
110
+ cancel();
111
+ });
112
+ return {
113
+ throttled,
114
+ pending,
115
+ cancel,
116
+ flush
117
+ };
118
+ }
119
+ function resolveWaitMs(value) {
120
+ if (!Number.isFinite(value) || value < 0) throw new RangeError(`[VIZE_COMPOSE_THROTTLE_INVALID_WAIT] waitMs must be finite and at least zero; received ${String(value)}`);
121
+ return Math.trunc(value);
122
+ }
123
+ //#endregion
124
+ export { useThrottled };
@@ -0,0 +1,45 @@
1
+ import { Ref } from "vue";
2
+
3
+ //#region src/use-toggle.d.ts
4
+ /** Reactive controls returned by {@link useToggle}. */
5
+ interface ToggleControls {
6
+ /**
7
+ * Owned boolean state.
8
+ *
9
+ * Deliberately writable: unlike the derived views elsewhere in this
10
+ * package, the toggle owns its state, so assigning the ref directly (for
11
+ * example through `v-model`) is equivalent to calling
12
+ * {@link ToggleControls.toggle} with a forced value.
13
+ */
14
+ readonly state: Ref<boolean>;
15
+ /**
16
+ * Invert the state, or force it to `force` when the argument is given.
17
+ * Passing an explicit `undefined` behaves like passing no argument.
18
+ *
19
+ * @param force Value assigned instead of inverting.
20
+ * @returns The state after the change.
21
+ */
22
+ readonly toggle: (force?: boolean) => boolean;
23
+ }
24
+ /**
25
+ * Create owned boolean state with an inverting control.
26
+ *
27
+ * Purely synchronous state: safe during server rendering (no browser
28
+ * globals, no timers) and nothing to dispose, so it works inside and
29
+ * outside reactive scopes alike.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const { state: open, toggle } = useToggle();
34
+ * toggle(); // true
35
+ * toggle(false); // false
36
+ * open.value; // false
37
+ * ```
38
+ *
39
+ * @param initial State before the first toggle.
40
+ * @default initial false
41
+ * @returns The writable state and its toggle control.
42
+ */
43
+ declare function useToggle(initial?: boolean): ToggleControls;
44
+ //#endregion
45
+ export { ToggleControls, useToggle };
@@ -0,0 +1,34 @@
1
+ import { shallowRef } from "vue";
2
+ //#region src/use-toggle.ts
3
+ /**
4
+ * Create owned boolean state with an inverting control.
5
+ *
6
+ * Purely synchronous state: safe during server rendering (no browser
7
+ * globals, no timers) and nothing to dispose, so it works inside and
8
+ * outside reactive scopes alike.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const { state: open, toggle } = useToggle();
13
+ * toggle(); // true
14
+ * toggle(false); // false
15
+ * open.value; // false
16
+ * ```
17
+ *
18
+ * @param initial State before the first toggle.
19
+ * @default initial false
20
+ * @returns The writable state and its toggle control.
21
+ */
22
+ function useToggle(initial = false) {
23
+ const state = shallowRef(initial);
24
+ const toggle = (force) => {
25
+ state.value = force ?? !state.value;
26
+ return state.value;
27
+ };
28
+ return {
29
+ state,
30
+ toggle
31
+ };
32
+ }
33
+ //#endregion
34
+ export { useToggle };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizejs/composable",
3
- "version": "0.343.0",
3
+ "version": "0.347.7",
4
4
  "description": "Lifecycle-safe composable foundations for Vize applications",
5
5
  "keywords": [
6
6
  "composables",
@@ -32,10 +32,100 @@
32
32
  "import": "./dist/index.mjs",
33
33
  "default": "./dist/index.mjs"
34
34
  },
35
+ "./abort-signal": {
36
+ "types": "./dist/abort-signal.d.mts",
37
+ "import": "./dist/abort-signal.mjs",
38
+ "default": "./dist/abort-signal.mjs"
39
+ },
40
+ "./async-resource": {
41
+ "types": "./dist/async-resource.d.mts",
42
+ "import": "./dist/async-resource.mjs",
43
+ "default": "./dist/async-resource.mjs"
44
+ },
45
+ "./capability": {
46
+ "types": "./dist/capability.d.mts",
47
+ "import": "./dist/capability.mjs",
48
+ "default": "./dist/capability.mjs"
49
+ },
50
+ "./catalog": {
51
+ "types": "./dist/catalog.d.mts",
52
+ "import": "./dist/catalog.mjs",
53
+ "default": "./dist/catalog.mjs"
54
+ },
55
+ "./disposal-scope": {
56
+ "types": "./dist/disposal-scope.d.mts",
57
+ "import": "./dist/disposal-scope.mjs",
58
+ "default": "./dist/disposal-scope.mjs"
59
+ },
60
+ "./event-listener": {
61
+ "types": "./dist/event-listener.d.mts",
62
+ "import": "./dist/event-listener.mjs",
63
+ "default": "./dist/event-listener.mjs"
64
+ },
65
+ "./locale": {
66
+ "types": "./dist/locale.d.mts",
67
+ "import": "./dist/locale.mjs",
68
+ "default": "./dist/locale.mjs"
69
+ },
70
+ "./media-query": {
71
+ "types": "./dist/media-query.d.mts",
72
+ "import": "./dist/media-query.mjs",
73
+ "default": "./dist/media-query.mjs"
74
+ },
75
+ "./retry-async": {
76
+ "types": "./dist/retry-async.d.mts",
77
+ "import": "./dist/retry-async.mjs",
78
+ "default": "./dist/retry-async.mjs"
79
+ },
80
+ "./retry-delay": {
81
+ "types": "./dist/retry-delay.d.mts",
82
+ "import": "./dist/retry-delay.mjs",
83
+ "default": "./dist/retry-delay.mjs"
84
+ },
85
+ "./scope": {
86
+ "types": "./dist/scope.d.mts",
87
+ "import": "./dist/scope.mjs",
88
+ "default": "./dist/scope.mjs"
89
+ },
35
90
  "./temporal": {
36
91
  "types": "./dist/temporal.d.mts",
37
92
  "import": "./dist/temporal.mjs",
38
93
  "default": "./dist/temporal.mjs"
94
+ },
95
+ "./timeout-scheduler": {
96
+ "types": "./dist/timeout-scheduler.d.mts",
97
+ "import": "./dist/timeout-scheduler.mjs",
98
+ "default": "./dist/timeout-scheduler.mjs"
99
+ },
100
+ "./use-counter": {
101
+ "types": "./dist/use-counter.d.mts",
102
+ "import": "./dist/use-counter.mjs",
103
+ "default": "./dist/use-counter.mjs"
104
+ },
105
+ "./use-debounced": {
106
+ "types": "./dist/use-debounced.d.mts",
107
+ "import": "./dist/use-debounced.mjs",
108
+ "default": "./dist/use-debounced.mjs"
109
+ },
110
+ "./use-history": {
111
+ "types": "./dist/use-history.d.mts",
112
+ "import": "./dist/use-history.mjs",
113
+ "default": "./dist/use-history.mjs"
114
+ },
115
+ "./use-previous": {
116
+ "types": "./dist/use-previous.d.mts",
117
+ "import": "./dist/use-previous.mjs",
118
+ "default": "./dist/use-previous.mjs"
119
+ },
120
+ "./use-throttled": {
121
+ "types": "./dist/use-throttled.d.mts",
122
+ "import": "./dist/use-throttled.mjs",
123
+ "default": "./dist/use-throttled.mjs"
124
+ },
125
+ "./use-toggle": {
126
+ "types": "./dist/use-toggle.d.mts",
127
+ "import": "./dist/use-toggle.mjs",
128
+ "default": "./dist/use-toggle.mjs"
39
129
  }
40
130
  },
41
131
  "publishConfig": {