@pibbl/core 0.0.1 → 0.0.2

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 (167) hide show
  1. package/README.md +1 -1
  2. package/dist/features/machines/animation.d.ts +64 -0
  3. package/dist/features/machines/animation.js +55 -0
  4. package/dist/features/machines/animation.js.map +7 -0
  5. package/dist/features/machines/animation.mjs +1 -0
  6. package/dist/features/machines/assign.d.ts +16 -0
  7. package/dist/features/machines/assign.js +15 -0
  8. package/dist/features/machines/assign.js.map +7 -0
  9. package/dist/features/machines/callback.d.ts +9 -0
  10. package/dist/features/machines/callback.js +7 -0
  11. package/dist/features/machines/callback.js.map +7 -0
  12. package/dist/features/machines/hook.d.ts +30 -0
  13. package/dist/features/machines/hook.js +37 -0
  14. package/dist/features/machines/hook.js.map +7 -0
  15. package/dist/features/machines/index.d.ts +6 -0
  16. package/dist/features/machines/index.js +12 -0
  17. package/dist/features/machines/index.js.map +7 -0
  18. package/dist/features/machines/index.mjs +1 -0
  19. package/dist/features/machines/runtime.d.ts +18 -0
  20. package/dist/features/machines/runtime.js +363 -0
  21. package/dist/features/machines/runtime.js.map +7 -0
  22. package/dist/features/machines/types.d.ts +164 -0
  23. package/dist/features/physics/2d-geometry.d.ts +3 -3
  24. package/dist/features/physics/2d-geometry.js.map +1 -1
  25. package/dist/features/physics/2d.d.ts +115 -62
  26. package/dist/features/physics/2d.js +59 -28
  27. package/dist/features/physics/2d.js.map +2 -2
  28. package/dist/features/physics/lib/2d/query-types.d.ts +6 -0
  29. package/dist/features/physics/lib/2d/runtime/controller.d.ts +7 -6
  30. package/dist/features/physics/lib/2d/runtime/controller.js.map +2 -2
  31. package/dist/features/physics/lib/2d/types.d.ts +8 -30
  32. package/dist/features/physics/lib/2d/world/queries.d.ts +7 -6
  33. package/dist/features/physics/lib/2d/world/queries.js.map +2 -2
  34. package/dist/features/sprites/formats/aseprite.d.ts +5 -0
  35. package/dist/features/sprites/formats/texture-packer.d.ts +5 -0
  36. package/dist/features/sprites/index.d.ts +6 -0
  37. package/dist/features/sprites/loader.d.ts +25 -0
  38. package/dist/features/sprites/model.d.ts +75 -0
  39. package/dist/features/sprites/sprite.d.ts +22 -0
  40. package/dist/features/viz/index.d.ts +28 -3
  41. package/dist/features/viz/index.js +40 -4
  42. package/dist/features/viz/index.js.map +2 -2
  43. package/dist/features/viz/lib/axis-labels.d.ts +2 -0
  44. package/dist/features/viz/lib/axis-labels.js +41 -0
  45. package/dist/features/viz/lib/axis-labels.js.map +7 -0
  46. package/dist/features/viz/lib/axis-title.d.ts +23 -0
  47. package/dist/features/viz/lib/axis-title.js +23 -0
  48. package/dist/features/viz/lib/axis-title.js.map +7 -0
  49. package/dist/features/viz/lib/axis.d.ts +1 -1
  50. package/dist/features/viz/lib/axis.js +50 -50
  51. package/dist/features/viz/lib/axis.js.map +2 -2
  52. package/dist/features/viz/lib/bar-scale.d.ts +7 -0
  53. package/dist/features/viz/lib/bar-scale.js +34 -0
  54. package/dist/features/viz/lib/bar-scale.js.map +7 -0
  55. package/dist/features/viz/lib/bar-series.js +5 -4
  56. package/dist/features/viz/lib/bar-series.js.map +2 -2
  57. package/dist/features/viz/lib/chart-lines.d.ts +41 -0
  58. package/dist/features/viz/lib/chart-lines.js +32 -0
  59. package/dist/features/viz/lib/chart-lines.js.map +7 -0
  60. package/dist/features/viz/lib/hover-data.js +2 -2
  61. package/dist/features/viz/lib/hover-data.js.map +2 -2
  62. package/dist/features/viz/lib/hover-types.d.ts +5 -5
  63. package/dist/features/viz/lib/line-series.js +3 -3
  64. package/dist/features/viz/lib/line-series.js.map +2 -2
  65. package/dist/features/viz/lib/linear-scale-component.d.ts +7 -0
  66. package/dist/features/viz/lib/linear-scale-component.js +18 -0
  67. package/dist/features/viz/lib/linear-scale-component.js.map +7 -0
  68. package/dist/features/viz/lib/linear-scale.js +1 -1
  69. package/dist/features/viz/lib/linear-scale.js.map +2 -2
  70. package/dist/features/viz/lib/log-scale-component.d.ts +7 -0
  71. package/dist/features/viz/lib/log-scale-component.js +19 -0
  72. package/dist/features/viz/lib/log-scale-component.js.map +7 -0
  73. package/dist/features/viz/lib/log-scale.d.ts +2 -0
  74. package/dist/features/viz/lib/log-scale.js +53 -0
  75. package/dist/features/viz/lib/log-scale.js.map +7 -0
  76. package/dist/features/viz/lib/nearest.d.ts +9 -9
  77. package/dist/features/viz/lib/nearest.js.map +1 -1
  78. package/dist/features/viz/lib/numeric-ticks.d.ts +38 -0
  79. package/dist/features/viz/lib/numeric-ticks.js +54 -0
  80. package/dist/features/viz/lib/numeric-ticks.js.map +7 -0
  81. package/dist/features/viz/lib/plot-series.js +2 -2
  82. package/dist/features/viz/lib/plot-series.js.map +2 -2
  83. package/dist/features/viz/lib/point-scale-component.d.ts +7 -0
  84. package/dist/features/viz/lib/point-scale-component.js +19 -0
  85. package/dist/features/viz/lib/point-scale-component.js.map +7 -0
  86. package/dist/features/viz/lib/point-scale.d.ts +2 -0
  87. package/dist/features/viz/lib/point-scale.js +45 -0
  88. package/dist/features/viz/lib/point-scale.js.map +7 -0
  89. package/dist/features/viz/lib/point-series.js +2 -2
  90. package/dist/features/viz/lib/point-series.js.map +2 -2
  91. package/dist/features/viz/lib/reference-band.d.ts +16 -0
  92. package/dist/features/viz/lib/reference-band.js +27 -0
  93. package/dist/features/viz/lib/reference-band.js.map +7 -0
  94. package/dist/features/viz/lib/scale-adjust.js +9 -4
  95. package/dist/features/viz/lib/scale-adjust.js.map +2 -2
  96. package/dist/features/viz/lib/scale-context.d.ts +5 -4
  97. package/dist/features/viz/lib/scale-context.js +15 -11
  98. package/dist/features/viz/lib/scale-context.js.map +2 -2
  99. package/dist/features/viz/lib/scale-provider.d.ts +2 -0
  100. package/dist/features/viz/lib/scale-provider.js +13 -0
  101. package/dist/features/viz/lib/scale-provider.js.map +7 -0
  102. package/dist/features/viz/lib/scale-ticks.d.ts +5 -0
  103. package/dist/features/viz/lib/scale-ticks.js +49 -0
  104. package/dist/features/viz/lib/scale-ticks.js.map +7 -0
  105. package/dist/features/viz/lib/scale-view.d.ts +4 -0
  106. package/dist/features/viz/lib/scale-view.js +21 -0
  107. package/dist/features/viz/lib/scale-view.js.map +7 -0
  108. package/dist/features/viz/lib/symlog-scale-component.d.ts +7 -0
  109. package/dist/features/viz/lib/symlog-scale-component.js +19 -0
  110. package/dist/features/viz/lib/symlog-scale-component.js.map +7 -0
  111. package/dist/features/viz/lib/symlog-scale.d.ts +2 -0
  112. package/dist/features/viz/lib/symlog-scale.js +38 -0
  113. package/dist/features/viz/lib/symlog-scale.js.map +7 -0
  114. package/dist/features/viz/lib/types.d.ts +95 -18
  115. package/dist/features/viz/lib/use-bar-scale.d.ts +8 -0
  116. package/dist/features/viz/lib/use-bar-scale.js +9 -0
  117. package/dist/features/viz/lib/use-bar-scale.js.map +7 -0
  118. package/dist/features/viz/lib/use-continuous-scale.d.ts +8 -0
  119. package/dist/features/viz/lib/use-continuous-scale.js +9 -0
  120. package/dist/features/viz/lib/use-continuous-scale.js.map +7 -0
  121. package/dist/features/viz/lib/use-linear-scale.d.ts +8 -0
  122. package/dist/features/viz/lib/use-linear-scale.js +9 -0
  123. package/dist/features/viz/lib/use-linear-scale.js.map +7 -0
  124. package/dist/features/viz/lib/use-log-scale.d.ts +8 -0
  125. package/dist/features/viz/lib/use-log-scale.js +9 -0
  126. package/dist/features/viz/lib/use-log-scale.js.map +7 -0
  127. package/dist/features/viz/lib/use-point-scale.d.ts +8 -0
  128. package/dist/features/viz/lib/use-point-scale.js +9 -0
  129. package/dist/features/viz/lib/use-point-scale.js.map +7 -0
  130. package/dist/features/viz/lib/use-symlog-scale.d.ts +8 -0
  131. package/dist/features/viz/lib/use-symlog-scale.js +9 -0
  132. package/dist/features/viz/lib/use-symlog-scale.js.map +7 -0
  133. package/dist/features/viz/lib/use-utc-scale.d.ts +8 -0
  134. package/dist/features/viz/lib/use-utc-scale.js +9 -0
  135. package/dist/features/viz/lib/use-utc-scale.js.map +7 -0
  136. package/dist/features/viz/lib/utc-labels.d.ts +12 -0
  137. package/dist/features/viz/lib/utc-labels.js +27 -0
  138. package/dist/features/viz/lib/utc-labels.js.map +7 -0
  139. package/dist/features/viz/lib/utc-scale-component.d.ts +7 -0
  140. package/dist/features/viz/lib/utc-scale-component.js +18 -0
  141. package/dist/features/viz/lib/utc-scale-component.js.map +7 -0
  142. package/dist/features/viz/lib/utc-scale.d.ts +21 -0
  143. package/dist/features/viz/lib/utc-scale.js +123 -0
  144. package/dist/features/viz/lib/utc-scale.js.map +7 -0
  145. package/dist/index.d.ts +1 -1
  146. package/dist/index.js.map +1 -1
  147. package/dist/lib/animation/definition.d.ts +5 -3
  148. package/dist/lib/animation/definition.js +29 -4
  149. package/dist/lib/animation/definition.js.map +2 -2
  150. package/dist/lib/animation/playback.d.ts +8 -0
  151. package/dist/lib/animation/playback.js +33 -11
  152. package/dist/lib/animation/playback.js.map +2 -2
  153. package/dist/lib/animation/spring.d.ts +3 -1
  154. package/dist/lib/animation/spring.js.map +2 -2
  155. package/dist/lib/animation/types.d.ts +29 -73
  156. package/dist/lib/hooks/use-animated-value.d.ts +11 -21
  157. package/dist/lib/hooks/use-animated-value.js +23 -70
  158. package/dist/lib/hooks/use-animated-value.js.map +3 -3
  159. package/dist/lib/hooks/use-playback.js +1 -0
  160. package/dist/lib/hooks/use-playback.js.map +2 -2
  161. package/package.json +18 -4
  162. package/dist/features/viz/lib/scale.d.ts +0 -11
  163. package/dist/features/viz/lib/scale.js +0 -80
  164. package/dist/features/viz/lib/scale.js.map +0 -7
  165. package/dist/features/viz/lib/use-scale.d.ts +0 -20
  166. package/dist/features/viz/lib/use-scale.js +0 -10
  167. package/dist/features/viz/lib/use-scale.js.map +0 -7
@@ -2,8 +2,8 @@ import type { Signal } from "../signals/types.js";
2
2
  import type { defineAnimation, keyframes, spring, stepper, tween } from "./definition.js";
3
3
  import type { marker, parallel, repeat } from "./program.js";
4
4
  import type { useAnimatedValue } from "../hooks/use-animated-value.js";
5
- import type { SignalEquals } from "../signals/types.js";
6
5
  import type { usePlayback } from "../hooks/use-playback.js";
6
+ import type { SignalEquals } from '../signals/types.js';
7
7
  declare const pibblAnimationDefinitionBrand: unique symbol;
8
8
  declare const pibblAnimationProgramBrand: unique symbol;
9
9
  /**
@@ -14,7 +14,6 @@ declare const pibblAnimationProgramBrand: unique symbol;
14
14
  *
15
15
  * @see {@link PibblKeyframesOptions}
16
16
  * @see {@link PibblTweenOptions}
17
- * @see {@link PibblTweenAnimatedValueOptions}
18
17
  */
19
18
  export type PibblEasing = (progress: number) => number;
20
19
  /**
@@ -27,7 +26,6 @@ export type PibblEasing = (progress: number) => number;
27
26
  *
28
27
  * @see {@link PibblKeyframesOptions}
29
28
  * @see {@link PibblTweenOptions}
30
- * @see {@link PibblTweenAnimatedValueOptions}
31
29
  */
32
30
  export type PibblInterpolator<T> = (from: T, to: T, progress: number) => T;
33
31
  /**
@@ -78,8 +76,8 @@ export interface PibblAnimationRepeatOptions {
78
76
  export interface PibblTweenOptions<T> {
79
77
  /** Starting endpoint or value. See {@link PibblTweenOptions}. */
80
78
  readonly from?: T;
81
- /** Destination endpoint or value. See {@link PibblTweenOptions}. */
82
- readonly to: T;
79
+ /** Destination endpoint; omit when useAnimatedValue supplies the target. See {@link PibblTweenOptions}. */
80
+ readonly to?: T;
83
81
  /** Duration of the animation or transition in milliseconds. See {@link PibblTweenOptions}. */
84
82
  readonly duration: number;
85
83
  /** Maps normalized progress before interpolation. See {@link PibblEasing}. */
@@ -126,8 +124,8 @@ export interface PibblKeyframesOptions<T> {
126
124
  export interface PibblSpringOptions {
127
125
  /** Starting endpoint or value. See {@link PibblSpringOptions}. */
128
126
  readonly from?: number;
129
- /** Destination endpoint or value. See {@link PibblSpringOptions}. */
130
- readonly to: number;
127
+ /** Destination endpoint; omit when useAnimatedValue supplies the target. See {@link PibblSpringOptions}. */
128
+ readonly to?: number;
131
129
  /** Mass used by the spring or physics calculation. See {@link PibblSpringOptions}. */
132
130
  readonly mass?: number;
133
131
  /** Spring stiffness controlling acceleration toward the target. See {@link PibblSpringOptions}. */
@@ -155,79 +153,37 @@ export interface PibblSpringOptions {
155
153
  readonly debugName?: string;
156
154
  }
157
155
  /**
158
- * Target-driven tween configuration for an animated value hook.
159
- *
160
- * @see {@link PibblEasing}
161
- * @see {@link PibblInterpolator}
162
- * @see {@link SignalEquals}
156
+ * Current endpoints and optional committed spring velocity supplied to an animation factory.
157
+ * @see {@link PibblAnimatedValueOptions}
163
158
  */
164
- export interface PibblTweenAnimatedValueOptions<T> {
165
- /** The literal "tween" identifying this variant. See {@link PibblTweenAnimatedValueOptions}. */
166
- readonly type: 'tween';
167
- /**
168
- * Duration of the animation or transition in milliseconds. See
169
- * {@link PibblTweenAnimatedValueOptions}.
170
- */
171
- readonly duration: number;
172
- /** Maps normalized progress before interpolation. See {@link PibblEasing}. */
173
- readonly easing?: PibblEasing;
174
- /**
175
- * Produces a value between two endpoints at the supplied progress. See {@link PibblInterpolator}.
176
- */
177
- readonly interpolate?: PibblInterpolator<T>;
178
- /**
179
- * Compares old and new values to suppress equivalent updates. See
180
- * {@link PibblTweenAnimatedValueOptions}.
181
- */
182
- readonly equals?: import('../signals/types.js').SignalEquals<T>;
183
- /** Initial animated value used when the hook mounts. See {@link PibblTweenAnimatedValueOptions}. */
184
- readonly initial?: T;
185
- /** Optional label used in diagnostics. See {@link PibblTweenAnimatedValueOptions}. */
186
- readonly debugName?: string;
159
+ export interface PibblAnimationTarget<T> {
160
+ /** Last presented value, or the explicit mount initial value. See {@link useAnimatedValue}. */
161
+ readonly from: T;
162
+ /** Latest requested target. See {@link useAnimatedValue}. */
163
+ readonly to: T;
164
+ /** Committed analytic spring velocity, when the previous run is a spring. See {@link spring}. */
165
+ readonly velocity?: number;
187
166
  }
188
167
  /**
189
- * Target-driven spring configuration for an animated value hook.
190
- *
168
+ * Definition-based target animation with mount-owned equality and initial presentation.
191
169
  * @see {@link useAnimatedValue}
192
- * @see {@link SignalEquals}
170
+ * @see {@link PibblAnimationDefinition}
193
171
  */
194
- export interface PibblSpringAnimatedValueOptions {
195
- /** The literal "spring" identifying this variant. See {@link PibblSpringAnimatedValueOptions}. */
196
- readonly type: 'spring';
197
- /** Mass used by the spring or physics calculation. See {@link PibblSpringAnimatedValueOptions}. */
198
- readonly mass?: number;
199
- /**
200
- * Spring stiffness controlling acceleration toward the target. See
201
- * {@link PibblSpringAnimatedValueOptions}.
202
- */
203
- readonly stiffness?: number;
204
- /** Spring damping controlling the loss of velocity. See {@link PibblSpringAnimatedValueOptions}. */
205
- readonly damping?: number;
206
- /** Starting velocity of the spring. See {@link PibblSpringAnimatedValueOptions}. */
207
- readonly initialVelocity?: number;
208
- /**
209
- * Velocity threshold used to determine when the spring has settled. See
210
- * {@link PibblSpringAnimatedValueOptions}.
211
- */
212
- readonly restSpeed?: number;
213
- /**
214
- * Distance-from-target threshold used to determine when the spring has settled. See
215
- * {@link PibblSpringAnimatedValueOptions}.
216
- */
217
- readonly restDelta?: number;
172
+ export interface PibblAnimatedValueOptions<T> {
218
173
  /**
219
- * Maximum duration allowed before the spring is forced to complete. See
220
- * {@link PibblSpringAnimatedValueOptions}.
174
+ * Immutable definition or pure factory receiving the hook-owned endpoints. Factories run
175
+ * synchronously during render and cannot write signals or call hooks.
176
+ * @see {@link PibblAnimationTarget}
177
+ * @see {@link PibblAnimationDefinition}
178
+ * @param target - Current endpoints and previous spring velocity. See {@link PibblAnimationTarget}.
179
+ * @returns A concrete animation definition. See {@link PibblAnimationDefinition}.
221
180
  */
222
- readonly maxDuration?: number;
223
- /**
224
- * Compares old and new values to suppress equivalent updates. See
225
- * {@link PibblSpringAnimatedValueOptions}.
226
- */
227
- readonly equals?: import('../signals/types.js').SignalEquals<number>;
228
- /** Initial animated value used when the hook mounts. See {@link PibblSpringAnimatedValueOptions}. */
229
- readonly initial?: number;
230
- /** Optional label used in diagnostics. See {@link PibblSpringAnimatedValueOptions}. */
181
+ readonly animation: PibblAnimationDefinition<T> | ((target: PibblAnimationTarget<T>) => PibblAnimationDefinition<T>);
182
+ /** Comparison used to suppress equal targets. See {@link SignalEquals}. */
183
+ readonly equals?: SignalEquals<T>;
184
+ /** Initial presented value; omitted initial values present the target without entrance motion. See {@link useAnimatedValue}. */
185
+ readonly initial?: T;
186
+ /** Optional playback diagnostic label. See {@link useAnimatedValue}. */
231
187
  readonly debugName?: string;
232
188
  }
233
189
  /**
@@ -1,24 +1,14 @@
1
- import type { PibblSpringAnimatedValueOptions, PibblTweenAnimatedValueOptions } from '../animation/types.js';
1
+ import type { PibblAnimatedValueOptions } from '../animation/types.js';
2
2
  import type { Signal, SignalValue } from '../signals/types.js';
3
+ type AnimatedValueInputs<T> = {
4
+ readonly [K in keyof PibblAnimatedValueOptions<T>]: SignalValue<PibblAnimatedValueOptions<T>[K]>;
5
+ };
3
6
  /**
4
- * Animates a numeric target using an analytic spring. See {@link PibblSpringAnimatedValueOptions}
5
- * and {@link Signal}.
6
- * @param target - Target value or signal whose changes start transitions. See {@link SignalValue}.
7
- * @param options - Spring or tween configuration, including signal-backed fields. See
8
- * {@link SignalValue} , {@link PibblSpringAnimatedValueOptions} .
9
- * @returns A readonly signal containing the animated value. See {@link Signal}.
7
+ * Presents a target through an immutable animation definition or a pure animation factory.
8
+ * @param targetInput - Target value or signal. See {@link SignalValue}.
9
+ * @param optionsInput - Animation definition, initial value, equality, and diagnostic settings;
10
+ * fields and the options object may be signals. See {@link PibblAnimatedValueOptions}.
11
+ * @returns One stable readonly animated signal. See {@link Signal}.
10
12
  */
11
- export declare function useAnimatedValue(target: SignalValue<number>, options: SignalValue<{
12
- readonly [K in keyof PibblSpringAnimatedValueOptions]: SignalValue<PibblSpringAnimatedValueOptions[K]>;
13
- }>): Signal<number>;
14
- /**
15
- * Animates a target using a tween and optional custom interpolation. See
16
- * {@link PibblTweenAnimatedValueOptions} and {@link Signal}.
17
- * @param target - Target value or signal whose changes start transitions. See {@link SignalValue}.
18
- * @param options - Spring or tween configuration, including signal-backed fields. See
19
- * {@link SignalValue} , {@link PibblTweenAnimatedValueOptions} .
20
- * @returns A readonly signal containing the animated value. See {@link Signal}.
21
- */
22
- export declare function useAnimatedValue<T>(target: SignalValue<T>, options: SignalValue<{
23
- readonly [K in keyof PibblTweenAnimatedValueOptions<T>]: SignalValue<PibblTweenAnimatedValueOptions<T>[K]>;
24
- }>): Signal<T>;
13
+ export declare function useAnimatedValue<T>(targetInput: SignalValue<T>, optionsInput: SignalValue<AnimatedValueInputs<NoInfer<T>>>): Signal<T>;
14
+ export {};
@@ -1,8 +1,9 @@
1
+ import { bindAnimationTarget } from "../animation/definition.js";
2
+ import { drive } from "../animation/program.js";
3
+ import { withSignalWriteForbidden } from "../signals/graph.js";
1
4
  import {
2
5
  createAnimationPlaybackController
3
6
  } from "../animation/playback.js";
4
- import { spring, tween } from "../animation/definition.js";
5
- import { drive } from "../animation/program.js";
6
7
  import { GLOBAL_STATE } from "../global-state.js";
7
8
  import {
8
9
  isSignal,
@@ -11,45 +12,16 @@ import {
11
12
  untracked
12
13
  } from "../signals/graph.js";
13
14
  import { resolveSignalValue } from "../signals/resolve-signal-value.js";
14
- import { requireHookContext, useHookSlot } from "./hook-slot.js";
15
- function hasOwn(value, key) {
16
- return Object.prototype.hasOwnProperty.call(value, key);
17
- }
15
+ import { requireHookContext, useHookSlot, withHooksForbidden } from "./hook-slot.js";
18
16
  function normalizeCandidate(target, options) {
19
17
  if (typeof options !== "object" || options === null) {
20
- throw new TypeError("Pibbl transition options must be an object.");
21
- }
22
- if (options.type !== "tween" && options.type !== "spring") {
23
- throw new TypeError('Pibbl transition type must be "tween" or "spring".');
18
+ throw new TypeError("useAnimatedValue options must be an object.");
24
19
  }
25
20
  if (options.equals !== void 0 && typeof options.equals !== "function") {
26
21
  throw new TypeError("Pibbl transition equals must be a function.");
27
22
  }
28
23
  const snapshot = Object.freeze({ ...options });
29
- if (snapshot.type === "spring") {
30
- spring({
31
- from: target,
32
- to: target,
33
- mass: snapshot.mass,
34
- stiffness: snapshot.stiffness,
35
- damping: snapshot.damping,
36
- initialVelocity: snapshot.initialVelocity,
37
- restSpeed: snapshot.restSpeed,
38
- restDelta: snapshot.restDelta,
39
- maxDuration: snapshot.maxDuration,
40
- debugName: snapshot.debugName
41
- });
42
- } else {
43
- tween({
44
- from: target,
45
- to: target,
46
- duration: snapshot.duration,
47
- easing: snapshot.easing,
48
- interpolate: snapshot.interpolate,
49
- debugName: snapshot.debugName
50
- });
51
- }
52
- const hasInitial = hasOwn(options, "initial");
24
+ const hasInitial = Object.prototype.hasOwnProperty.call(options, "initial");
53
25
  return Object.freeze({
54
26
  options: snapshot,
55
27
  equals: snapshot.equals ?? Object.is,
@@ -58,31 +30,6 @@ function normalizeCandidate(target, options) {
58
30
  target
59
31
  });
60
32
  }
61
- function programFor(output, from, candidate, springVelocity) {
62
- const options = candidate.options;
63
- if (options.type === "spring") {
64
- return drive(output, spring({
65
- from,
66
- to: candidate.target,
67
- mass: options.mass,
68
- stiffness: options.stiffness,
69
- damping: options.damping,
70
- initialVelocity: springVelocity ?? options.initialVelocity,
71
- restSpeed: options.restSpeed,
72
- restDelta: options.restDelta,
73
- maxDuration: options.maxDuration,
74
- debugName: options.debugName
75
- }));
76
- }
77
- return drive(output, tween({
78
- from,
79
- to: candidate.target,
80
- duration: options.duration,
81
- easing: options.easing,
82
- interpolate: options.interpolate,
83
- debugName: options.debugName
84
- }));
85
- }
86
33
  function isCurrentSlot(slot) {
87
34
  return !slot.componentRefs.teardowns.closed && !slot.pibblInstance.mainTeardowns.closed && GLOBAL_STATE.pibblInstances.get(slot.pibblInstance.canvas) === slot.pibblInstance && slot.pibblInstance.refs.get(slot.componentRefs.id) === slot.componentRefs;
88
35
  }
@@ -91,13 +38,14 @@ function useAnimatedValue(targetInput, optionsInput) {
91
38
  const target = resolveSignalValue(targetInput);
92
39
  const options = resolveTransitionOptions(optionsInput);
93
40
  const candidate = normalizeCandidate(target, options);
94
- const slot = useHookSlot("transition", (teardowns) => {
41
+ const slot = useHookSlot("animatedValue", (teardowns) => {
95
42
  const output = signal(candidate.initial);
96
- const program = programFor(output, candidate.initial, candidate);
97
- const controller = createAnimationPlaybackController(program, {
43
+ const program2 = programFor(output, candidate.initial, candidate);
44
+ const controller = createAnimationPlaybackController(program2, {
98
45
  conflict: "replace",
99
46
  debugName: candidate.options.debugName
100
47
  });
48
+ controller.setDeferredStatusCommandOwner(pibblInstance.mainTeardowns);
101
49
  const value = {
102
50
  componentRefs,
103
51
  controller,
@@ -111,6 +59,12 @@ function useAnimatedValue(targetInput, optionsInput) {
111
59
  teardowns.add(() => controller.dispose());
112
60
  return value;
113
61
  }).value;
62
+ const program = programFor(
63
+ slot.output,
64
+ slot.settled ? untracked(() => slot.output.get()) : candidate.initial,
65
+ candidate,
66
+ slot.settled ? slot.controller.committedSpringSnapshot()?.velocity : void 0
67
+ );
114
68
  const shouldEnter = !slot.settled && candidate.hasInitial && !candidate.equals(candidate.initial, candidate.target);
115
69
  const shouldRetarget = slot.settled && !candidate.equals(slot.target, candidate.target);
116
70
  const previousProvisionalValue = untracked(() => slot.output.get());
@@ -130,7 +84,7 @@ function useAnimatedValue(targetInput, optionsInput) {
130
84
  slot.target = candidate.target;
131
85
  if (!shouldEnter && !shouldRetarget) {
132
86
  slot.controller.adopt(
133
- programFor(slot.output, slot.output.get(), candidate),
87
+ program,
134
88
  {
135
89
  conflict: "replace",
136
90
  debugName: candidate.options.debugName
@@ -138,13 +92,6 @@ function useAnimatedValue(targetInput, optionsInput) {
138
92
  );
139
93
  return;
140
94
  }
141
- const springVelocity = candidate.options.type === "spring" ? slot.controller.committedSpringSnapshot()?.velocity : void 0;
142
- const program = programFor(
143
- slot.output,
144
- slot.output.get(),
145
- candidate,
146
- springVelocity
147
- );
148
95
  slot.controller.retarget(program, {
149
96
  conflict: "replace",
150
97
  debugName: candidate.options.debugName
@@ -163,6 +110,12 @@ function resolveTransitionOptions(input) {
163
110
  }
164
111
  return resolved ?? source;
165
112
  }
113
+ function programFor(output, from, candidate, velocity) {
114
+ const context = Object.freeze({ from, to: candidate.target, velocity });
115
+ const animation = candidate.options.animation;
116
+ const definition = typeof animation === "function" ? withHooksForbidden("Animation factories cannot call hooks.", () => withSignalWriteForbidden("Animation factories cannot write to signals.", () => animation(context))) : animation;
117
+ return drive(output, bindAnimationTarget(definition, context));
118
+ }
166
119
  export {
167
120
  useAnimatedValue
168
121
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/hooks/use-animated-value.ts"],
4
- "sourcesContent": ["import {\n createAnimationPlaybackController,\n type AnimationPlaybackController,\n} from '../animation/playback.js';\nimport { spring, tween } from '../animation/definition.js';\nimport { drive } from '../animation/program.js';\nimport type {\n PibblAnimationProgram,\n PibblSpringAnimatedValueOptions,\n PibblTweenAnimatedValueOptions,\n} from '../animation/types.js';\nimport { GLOBAL_STATE } from '../global-state.js';\nimport {\n isSignal,\n provisionSignalValueForRender,\n signal,\n untracked,\n} from '../signals/graph.js';\nimport { resolveSignalValue } from '../signals/resolve-signal-value.js';\nimport type {\n Signal,\n SignalEquals,\n SignalValue,\n WritableSignal,\n} from '../signals/types.js';\nimport type { PibblComponentRefs, PibblInstance } from '../types.js';\nimport { requireHookContext, useHookSlot } from './hook-slot.js';\n\ntype PibblTransitionOptions<T> =\n | PibblTweenAnimatedValueOptions<T>\n | PibblSpringAnimatedValueOptions;\n\ntype PibblTransitionOptionsInput<T> =\n | {\n readonly [K in keyof PibblTweenAnimatedValueOptions<T>]:\n SignalValue<PibblTweenAnimatedValueOptions<T>[K]>;\n }\n | {\n readonly [K in keyof PibblSpringAnimatedValueOptions]:\n SignalValue<PibblSpringAnimatedValueOptions[K]>;\n };\n\ninterface PibblTransitionCandidate<T> {\n readonly options: PibblTransitionOptions<T>;\n readonly equals: SignalEquals<T>;\n readonly hasInitial: boolean;\n readonly initial: T;\n readonly target: T;\n}\n\ninterface PibblTransitionHookSlot<T> {\n readonly componentRefs: PibblComponentRefs<any>;\n readonly controller: AnimationPlaybackController;\n readonly pibblInstance: PibblInstance;\n readonly output: WritableSignal<T>;\n readonly readonlyOutput: Signal<T>;\n renderRevision: number;\n settled: boolean;\n target: T;\n}\n\nfunction hasOwn(value: object, key: PropertyKey): boolean {\n return Object.prototype.hasOwnProperty.call(value, key);\n}\n\nfunction normalizeCandidate<T>(\n target: T,\n options: PibblTransitionOptions<T>,\n): PibblTransitionCandidate<T> {\n if (typeof options !== 'object' || options === null) {\n throw new TypeError('Pibbl transition options must be an object.');\n }\n if (options.type !== 'tween' && options.type !== 'spring') {\n throw new TypeError('Pibbl transition type must be \"tween\" or \"spring\".');\n }\n if (options.equals !== undefined && typeof options.equals !== 'function') {\n throw new TypeError('Pibbl transition equals must be a function.');\n }\n const snapshot = Object.freeze({ ...options }) as PibblTransitionOptions<T>;\n if (snapshot.type === 'spring') {\n spring({\n from: target as number,\n to: target as number,\n mass: snapshot.mass,\n stiffness: snapshot.stiffness,\n damping: snapshot.damping,\n initialVelocity: snapshot.initialVelocity,\n restSpeed: snapshot.restSpeed,\n restDelta: snapshot.restDelta,\n maxDuration: snapshot.maxDuration,\n debugName: snapshot.debugName,\n });\n } else {\n tween({\n from: target,\n to: target,\n duration: snapshot.duration,\n easing: snapshot.easing,\n interpolate: snapshot.interpolate,\n debugName: snapshot.debugName,\n });\n }\n const hasInitial = hasOwn(options, 'initial');\n return Object.freeze({\n options: snapshot,\n equals: (snapshot.equals ?? Object.is) as SignalEquals<T>,\n hasInitial,\n initial: (hasInitial ? snapshot.initial : target) as T,\n target,\n });\n}\n\nfunction programFor<T>(\n output: WritableSignal<T>,\n from: T,\n candidate: PibblTransitionCandidate<T>,\n springVelocity?: number,\n): PibblAnimationProgram {\n const options = candidate.options;\n if (options.type === 'spring') {\n return drive(output as unknown as WritableSignal<number>, spring({\n from: from as number,\n to: candidate.target as number,\n mass: options.mass,\n stiffness: options.stiffness,\n damping: options.damping,\n initialVelocity: springVelocity ?? options.initialVelocity,\n restSpeed: options.restSpeed,\n restDelta: options.restDelta,\n maxDuration: options.maxDuration,\n debugName: options.debugName,\n }));\n }\n return drive(output, tween({\n from,\n to: candidate.target,\n duration: options.duration,\n easing: options.easing,\n interpolate: options.interpolate,\n debugName: options.debugName,\n }));\n}\n\nfunction isCurrentSlot<T>(slot: PibblTransitionHookSlot<T>): boolean {\n return !slot.componentRefs.teardowns.closed &&\n !slot.pibblInstance.mainTeardowns.closed &&\n GLOBAL_STATE.pibblInstances.get(slot.pibblInstance.canvas) === slot.pibblInstance &&\n slot.pibblInstance.refs.get(slot.componentRefs.id) === slot.componentRefs;\n}\n\n/**\n * Animates a numeric target using an analytic spring. See {@link PibblSpringAnimatedValueOptions}\n * and {@link Signal}.\n * @param target - Target value or signal whose changes start transitions. See {@link SignalValue}.\n * @param options - Spring or tween configuration, including signal-backed fields. See\n * {@link SignalValue} , {@link PibblSpringAnimatedValueOptions} .\n * @returns A readonly signal containing the animated value. See {@link Signal}.\n */\nexport function useAnimatedValue(\n target: SignalValue<number>,\n options: SignalValue<{\n readonly [K in keyof PibblSpringAnimatedValueOptions]:\n SignalValue<PibblSpringAnimatedValueOptions[K]>;\n }>,\n): Signal<number>;\n/**\n * Animates a target using a tween and optional custom interpolation. See\n * {@link PibblTweenAnimatedValueOptions} and {@link Signal}.\n * @param target - Target value or signal whose changes start transitions. See {@link SignalValue}.\n * @param options - Spring or tween configuration, including signal-backed fields. See\n * {@link SignalValue} , {@link PibblTweenAnimatedValueOptions} .\n * @returns A readonly signal containing the animated value. See {@link Signal}.\n */\nexport function useAnimatedValue<T>(\n target: SignalValue<T>,\n options: SignalValue<{\n readonly [K in keyof PibblTweenAnimatedValueOptions<T>]:\n SignalValue<PibblTweenAnimatedValueOptions<T>[K]>;\n }>,\n): Signal<T>;\n/**\n * Returns a mount-owned signal that animates toward the current target using the supplied\n * transition options.\n *\n * @param targetInput - Target value or signal whose changes start transitions. See\n * {@link SignalValue} .\n * @param optionsInput - Spring or tween configuration, including signal-backed fields. See\n * {@link SignalValue} , {@link PibblTransitionOptionsInput} .\n * @returns A readonly signal containing the animated value. See {@link Signal}.\n *\n * @see {@link SignalValue}\n * @see {@link Signal}\n */\nexport function useAnimatedValue<T>(\n targetInput: SignalValue<T>,\n optionsInput: SignalValue<PibblTransitionOptionsInput<T>>,\n): Signal<T> {\n const { componentRefs, pibblInstance } = requireHookContext();\n const target = resolveSignalValue(targetInput);\n const options = resolveTransitionOptions(optionsInput);\n const candidate = normalizeCandidate(target, options);\n const slot = useHookSlot<PibblTransitionHookSlot<T>>('transition', teardowns => {\n const output = signal(candidate.initial);\n const program = programFor(output, candidate.initial, candidate);\n const controller = createAnimationPlaybackController(program, {\n conflict: 'replace',\n debugName: candidate.options.debugName,\n });\n const value: PibblTransitionHookSlot<T> = {\n componentRefs,\n controller,\n pibblInstance,\n output,\n readonlyOutput: output.asReadonly(),\n renderRevision: 0,\n settled: false,\n target: candidate.target,\n };\n teardowns.add(() => controller.dispose());\n return value;\n }).value;\n\n const shouldEnter = !slot.settled && candidate.hasInitial &&\n !candidate.equals(candidate.initial, candidate.target);\n const shouldRetarget = slot.settled &&\n !candidate.equals(slot.target, candidate.target);\n const previousProvisionalValue = untracked(() => slot.output.get());\n const hasProvisionalValue = !slot.settled &&\n !Object.is(previousProvisionalValue, candidate.initial);\n const transaction = GLOBAL_STATE.renderTransaction;\n if (!transaction) {\n throw new Error('useAnimatedValue requires an active Pibbl render transaction.');\n }\n if (hasProvisionalValue) {\n provisionSignalValueForRender(slot.output, candidate.initial, transaction);\n }\n const revision = ++slot.renderRevision;\n transaction.onFinish(success => {\n if (!success) return;\n if (revision !== slot.renderRevision || !isCurrentSlot(slot)) return;\n slot.settled = true;\n slot.target = candidate.target;\n if (!shouldEnter && !shouldRetarget) {\n slot.controller.adopt(\n programFor(slot.output, slot.output.get(), candidate),\n {\n conflict: 'replace',\n debugName: candidate.options.debugName,\n },\n );\n return;\n }\n const springVelocity = candidate.options.type === 'spring' ?\n slot.controller.committedSpringSnapshot()?.velocity : undefined;\n const program = programFor(\n slot.output,\n slot.output.get(),\n candidate,\n springVelocity,\n );\n slot.controller.retarget(program, {\n conflict: 'replace',\n debugName: candidate.options.debugName,\n });\n });\n return slot.readonlyOutput;\n}\n\nfunction resolveTransitionOptions<T>(\n input: SignalValue<PibblTransitionOptionsInput<T>>,\n): PibblTransitionOptions<T> {\n const source = resolveSignalValue(input);\n let resolved: Record<PropertyKey, unknown> | undefined;\n for (const key in source) {\n const value = source[key as keyof typeof source];\n if (!isSignal(value)) continue;\n resolved ??= { ...source };\n resolved[key] = resolveSignalValue(value as SignalValue<unknown>);\n }\n return (resolved ?? source) as PibblTransitionOptions<T>;\n}\n"],
5
- "mappings": "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",
6
- "names": []
4
+ "sourcesContent": ["import { bindAnimationTarget } from '../animation/definition.js';\nimport { drive } from '../animation/program.js';\nimport { withSignalWriteForbidden } from '../signals/graph.js';\nimport {\n createAnimationPlaybackController,\n type AnimationPlaybackController,\n} from '../animation/playback.js';\nimport type {\n PibblAnimatedValueOptions,\n} from '../animation/types.js';\nimport { GLOBAL_STATE } from '../global-state.js';\nimport {\n isSignal,\n provisionSignalValueForRender,\n signal,\n untracked,\n} from '../signals/graph.js';\nimport { resolveSignalValue } from '../signals/resolve-signal-value.js';\nimport type {\n Signal,\n SignalEquals,\n SignalValue,\n WritableSignal,\n} from '../signals/types.js';\nimport type { PibblComponentRefs, PibblInstance } from '../types.js';\nimport { requireHookContext, useHookSlot, withHooksForbidden } from './hook-slot.js';\n\ntype AnimatedValueInputs<T> = {\n readonly [K in keyof PibblAnimatedValueOptions<T>]: SignalValue<PibblAnimatedValueOptions<T>[K]>;\n};\n\ninterface PibblTransitionCandidate<T> {\n readonly options: PibblAnimatedValueOptions<T>;\n readonly equals: SignalEquals<T>;\n readonly hasInitial: boolean;\n readonly initial: T;\n readonly target: T;\n}\n\ninterface PibblTransitionHookSlot<T> {\n readonly componentRefs: PibblComponentRefs<any>;\n readonly controller: AnimationPlaybackController;\n readonly pibblInstance: PibblInstance;\n readonly output: WritableSignal<T>;\n readonly readonlyOutput: Signal<T>;\n renderRevision: number;\n settled: boolean;\n target: T;\n}\n\nfunction normalizeCandidate<T>(\n target: T,\n options: PibblAnimatedValueOptions<T>,\n): PibblTransitionCandidate<T> {\n if (typeof options !== 'object' || options === null) {\n throw new TypeError('useAnimatedValue options must be an object.');\n }\n if (options.equals !== undefined && typeof options.equals !== 'function') {\n throw new TypeError('Pibbl transition equals must be a function.');\n }\n const snapshot = Object.freeze({ ...options });\n const hasInitial = Object.prototype.hasOwnProperty.call(options, 'initial');\n return Object.freeze({\n options: snapshot,\n equals: snapshot.equals ?? Object.is,\n hasInitial,\n initial: (hasInitial ? snapshot.initial : target) as T,\n target,\n });\n}\n\nfunction isCurrentSlot<T>(slot: PibblTransitionHookSlot<T>): boolean {\n return !slot.componentRefs.teardowns.closed &&\n !slot.pibblInstance.mainTeardowns.closed &&\n GLOBAL_STATE.pibblInstances.get(slot.pibblInstance.canvas) === slot.pibblInstance &&\n slot.pibblInstance.refs.get(slot.componentRefs.id) === slot.componentRefs;\n}\n\n/**\n * Presents a target through an immutable animation definition or a pure animation factory.\n * @param targetInput - Target value or signal. See {@link SignalValue}.\n * @param optionsInput - Animation definition, initial value, equality, and diagnostic settings;\n * fields and the options object may be signals. See {@link PibblAnimatedValueOptions}.\n * @returns One stable readonly animated signal. See {@link Signal}.\n */\nexport function useAnimatedValue<T>(\n targetInput: SignalValue<T>,\n optionsInput: SignalValue<AnimatedValueInputs<NoInfer<T>>>,\n): Signal<T> {\n const { componentRefs, pibblInstance } = requireHookContext();\n const target = resolveSignalValue(targetInput);\n const options = resolveTransitionOptions<T>(optionsInput);\n const candidate = normalizeCandidate(target, options);\n const slot = useHookSlot<PibblTransitionHookSlot<T>>('animatedValue', teardowns => {\n const output = signal(candidate.initial);\n const program = programFor(output, candidate.initial, candidate);\n const controller = createAnimationPlaybackController(program, {\n conflict: 'replace',\n debugName: candidate.options.debugName,\n });\n controller.setDeferredStatusCommandOwner(pibblInstance.mainTeardowns);\n const value: PibblTransitionHookSlot<T> = {\n componentRefs,\n controller,\n pibblInstance,\n output,\n readonlyOutput: output.asReadonly(),\n renderRevision: 0,\n settled: false,\n target: candidate.target,\n };\n teardowns.add(() => controller.dispose());\n return value;\n }).value;\n\n // Prepare user-defined work while Render can still fail transactionally. No factory runs\n // in onFinish, where a late exception could otherwise adopt only part of the update.\n const program = programFor(slot.output,\n slot.settled ? untracked(() => slot.output.get()) : candidate.initial,\n candidate, slot.settled ? slot.controller.committedSpringSnapshot()?.velocity : undefined);\n\n const shouldEnter = !slot.settled && candidate.hasInitial &&\n !candidate.equals(candidate.initial, candidate.target);\n const shouldRetarget = slot.settled &&\n !candidate.equals(slot.target, candidate.target);\n const previousProvisionalValue = untracked(() => slot.output.get());\n const hasProvisionalValue = !slot.settled &&\n !Object.is(previousProvisionalValue, candidate.initial);\n const transaction = GLOBAL_STATE.renderTransaction;\n if (!transaction) {\n throw new Error('useAnimatedValue requires an active Pibbl render transaction.');\n }\n if (hasProvisionalValue) {\n provisionSignalValueForRender(slot.output, candidate.initial, transaction);\n }\n const revision = ++slot.renderRevision;\n transaction.onFinish(success => {\n if (!success) return;\n if (revision !== slot.renderRevision || !isCurrentSlot(slot)) return;\n slot.settled = true;\n slot.target = candidate.target;\n if (!shouldEnter && !shouldRetarget) {\n slot.controller.adopt(\n program,\n {\n conflict: 'replace',\n debugName: candidate.options.debugName,\n },\n );\n return;\n }\n slot.controller.retarget(program, {\n conflict: 'replace',\n debugName: candidate.options.debugName,\n });\n });\n return slot.readonlyOutput;\n}\n\nfunction resolveTransitionOptions<T>(\n input: SignalValue<AnimatedValueInputs<T>>,\n): PibblAnimatedValueOptions<T> {\n const source = resolveSignalValue(input);\n let resolved: Record<PropertyKey, unknown> | undefined;\n for (const key in source) {\n const value = source[key as keyof typeof source];\n if (!isSignal(value)) continue;\n resolved ??= { ...source };\n resolved[key] = resolveSignalValue(value as SignalValue<unknown>);\n }\n return (resolved ?? source) as PibblAnimatedValueOptions<T>;\n}\n\nfunction programFor<T>(\n output: WritableSignal<T>, from: T, candidate: PibblTransitionCandidate<T>, velocity?: number,\n) {\n const context = Object.freeze({ from, to: candidate.target, velocity });\n const animation = candidate.options.animation;\n const definition = typeof animation === 'function'\n ? withHooksForbidden('Animation factories cannot call hooks.', () =>\n withSignalWriteForbidden('Animation factories cannot write to signals.', () => animation(context)))\n : animation;\n return drive(output, bindAnimationTarget(definition, context));\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["program"]
7
7
  }
@@ -28,6 +28,7 @@ function usePlayback(programInput, optionsInput = {}) {
28
28
  candidate.program,
29
29
  candidateOptions
30
30
  );
31
+ controller.setDeferredStatusCommandOwner(pibblInstance.mainTeardowns);
31
32
  const onEvent = (event) => {
32
33
  if (isCurrentSlot(value)) value.latestOptions.onEvent?.(event);
33
34
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/hooks/use-playback.ts"],
4
- "sourcesContent": ["import {\n createAnimationPlaybackController,\n normalizeAnimationPlaybackCandidate,\n type AnimationPlaybackController,\n} from '../animation/playback.js';\nimport type {\n PibblAnimationProgram,\n PibblPlayback,\n PibblPlaybackEvent,\n PibblPlaybackOptions,\n} from '../animation/types.js';\nimport { GLOBAL_STATE } from '../global-state.js';\nimport { isSignal } from '../signals/graph.js';\nimport { resolveSignalValue } from '../signals/resolve-signal-value.js';\nimport type { SignalValue } from '../signals/types.js';\nimport type { PibblComponentRefs, PibblInstance } from '../types.js';\nimport { requireHookContext, useHookSlot } from './hook-slot.js';\n\ntype PibblPlaybackOptionsInput = {\n readonly [K in keyof PibblPlaybackOptions]: SignalValue<PibblPlaybackOptions[K]>;\n};\n\ninterface PibblPlaybackHookSlot {\n readonly controller: AnimationPlaybackController;\n readonly componentRefs: PibblComponentRefs<any>;\n readonly pibblInstance: PibblInstance;\n latestOptions: PibblPlaybackOptions;\n mountSettled: boolean;\n readonly onError: (error: unknown) => void;\n readonly onEvent: (event: PibblPlaybackEvent) => void;\n renderRevision: number;\n}\n\nfunction isCurrentSlot(slot: PibblPlaybackHookSlot): boolean {\n return !slot.componentRefs.teardowns.closed &&\n !slot.pibblInstance.mainTeardowns.closed &&\n GLOBAL_STATE.pibblInstances.get(slot.pibblInstance.canvas) === slot.pibblInstance &&\n slot.pibblInstance.refs.get(slot.componentRefs.id) === slot.componentRefs;\n}\n\nfunction controllerOptions(\n candidate: PibblPlaybackOptions,\n onEvent: (event: PibblPlaybackEvent) => void,\n onError: (error: unknown) => void,\n): PibblPlaybackOptions {\n return {\n ...candidate,\n onEvent: typeof candidate.onEvent === 'function' ?\n onEvent : candidate.onEvent,\n onError: typeof candidate.onError === 'function' ?\n onError : candidate.onError,\n };\n}\n\n/**\n * Creates one component-owned animation playback handle for a hook slot.\n *\n * @param programInput - Animation program, optionally supplied by a signal. See\n * {@link SignalValue} , {@link PibblAnimationProgram} .\n * @param optionsInput - Playback configuration, optionally supplied by a signal. See\n * {@link SignalValue} , {@link PibblPlaybackOptionsInput} .\n * @returns Stable mount-owned playback controls and reactive status/time values. See\n * {@link PibblPlayback} .\n *\n * @see {@link SignalValue}\n * @see {@link PibblAnimationProgram}\n * @see {@link PibblPlayback}\n */\nexport function usePlayback(\n programInput: SignalValue<PibblAnimationProgram>,\n optionsInput: SignalValue<PibblPlaybackOptionsInput> = {},\n): PibblPlayback {\n const { componentRefs, pibblInstance } = requireHookContext();\n const program = resolveSignalValue(programInput);\n const options = resolvePlaybackOptions(optionsInput);\n const candidate = normalizeAnimationPlaybackCandidate(program, options);\n const candidateOptions = candidate.options;\n const slot = useHookSlot<PibblPlaybackHookSlot>('playback', teardowns => {\n let value!: PibblPlaybackHookSlot;\n const controller = createAnimationPlaybackController(\n candidate.program,\n candidateOptions,\n );\n const onEvent = (event: PibblPlaybackEvent): void => {\n if (isCurrentSlot(value)) value.latestOptions.onEvent?.(event);\n };\n const onError = (error: unknown): void => {\n if (isCurrentSlot(value)) value.latestOptions.onError?.(error);\n };\n value = {\n controller,\n componentRefs,\n pibblInstance,\n latestOptions: {},\n mountSettled: false,\n onError,\n onEvent,\n renderRevision: 0,\n };\n controller.adopt(\n candidate.program,\n controllerOptions(candidateOptions, onEvent, onError),\n );\n teardowns.add(() => controller.dispose());\n return value;\n }).value;\n const revision = ++slot.renderRevision;\n const transaction = GLOBAL_STATE.renderTransaction;\n if (!transaction) {\n throw new Error('usePlayback requires an active Pibbl render transaction.');\n }\n transaction.onFinish(success => {\n if (!success || revision !== slot.renderRevision || !isCurrentSlot(slot)) return;\n slot.controller.adopt(\n candidate.program,\n controllerOptions(candidateOptions, slot.onEvent, slot.onError),\n );\n slot.latestOptions = candidateOptions;\n if (!slot.mountSettled) {\n slot.mountSettled = true;\n if (candidateOptions.autoplay === true) slot.controller.handle.play();\n }\n });\n return slot.controller.handle;\n}\n\nfunction resolvePlaybackOptions(\n input: SignalValue<PibblPlaybackOptionsInput>,\n): PibblPlaybackOptions {\n const source = resolveSignalValue(input);\n let resolved: Record<PropertyKey, unknown> | undefined;\n for (const key in source) {\n const value = source[key as keyof PibblPlaybackOptionsInput];\n if (!isSignal(value)) continue;\n resolved ??= { ...source };\n resolved[key] = resolveSignalValue(value as SignalValue<unknown>);\n }\n return (resolved ?? source) as PibblPlaybackOptions;\n}\n"],
5
- "mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAOP,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB;AACzB,SAAS,0BAA0B;AAGnC,SAAS,oBAAoB,mBAAmB;AAiBhD,SAAS,cAAc,MAAsC;AAC3D,SAAO,CAAC,KAAK,cAAc,UAAU,UACnC,CAAC,KAAK,cAAc,cAAc,UAClC,aAAa,eAAe,IAAI,KAAK,cAAc,MAAM,MAAM,KAAK,iBACpE,KAAK,cAAc,KAAK,IAAI,KAAK,cAAc,EAAE,MAAM,KAAK;AAChE;AAEA,SAAS,kBACP,WACA,SACA,SACsB;AACtB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS,OAAO,UAAU,YAAY,aACpC,UAAU,UAAU;AAAA,IACtB,SAAS,OAAO,UAAU,YAAY,aACpC,UAAU,UAAU;AAAA,EACxB;AACF;AAgBO,SAAS,YACd,cACA,eAAuD,CAAC,GACzC;AACf,QAAM,EAAE,eAAe,cAAc,IAAI,mBAAmB;AAC5D,QAAM,UAAU,mBAAmB,YAAY;AAC/C,QAAM,UAAU,uBAAuB,YAAY;AACnD,QAAM,YAAY,oCAAoC,SAAS,OAAO;AACtE,QAAM,mBAAmB,UAAU;AACnC,QAAM,OAAO,YAAmC,YAAY,eAAa;AACvE,QAAI;AACJ,UAAM,aAAa;AAAA,MACjB,UAAU;AAAA,MACV;AAAA,IACF;AACA,UAAM,UAAU,CAAC,UAAoC;AACnD,UAAI,cAAc,KAAK,EAAG,OAAM,cAAc,UAAU,KAAK;AAAA,IAC/D;AACA,UAAM,UAAU,CAAC,UAAyB;AACxC,UAAI,cAAc,KAAK,EAAG,OAAM,cAAc,UAAU,KAAK;AAAA,IAC/D;AACA,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA,eAAe,CAAC;AAAA,MAChB,cAAc;AAAA,MACd;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,IAClB;AACA,eAAW;AAAA,MACT,UAAU;AAAA,MACV,kBAAkB,kBAAkB,SAAS,OAAO;AAAA,IACtD;AACA,cAAU,IAAI,MAAM,WAAW,QAAQ,CAAC;AACxC,WAAO;AAAA,EACT,CAAC,EAAE;AACH,QAAM,WAAW,EAAE,KAAK;AACxB,QAAM,cAAc,aAAa;AACjC,MAAI,CAAC,aAAa;AAChB,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AACA,cAAY,SAAS,aAAW;AAC9B,QAAI,CAAC,WAAW,aAAa,KAAK,kBAAkB,CAAC,cAAc,IAAI,EAAG;AAC1E,SAAK,WAAW;AAAA,MACd,UAAU;AAAA,MACV,kBAAkB,kBAAkB,KAAK,SAAS,KAAK,OAAO;AAAA,IAChE;AACA,SAAK,gBAAgB;AACrB,QAAI,CAAC,KAAK,cAAc;AACtB,WAAK,eAAe;AACpB,UAAI,iBAAiB,aAAa,KAAM,MAAK,WAAW,OAAO,KAAK;AAAA,IACtE;AAAA,EACF,CAAC;AACD,SAAO,KAAK,WAAW;AACzB;AAEA,SAAS,uBACP,OACsB;AACtB,QAAM,SAAS,mBAAmB,KAAK;AACvC,MAAI;AACJ,aAAW,OAAO,QAAQ;AACxB,UAAM,QAAQ,OAAO,GAAsC;AAC3D,QAAI,CAAC,SAAS,KAAK,EAAG;AACtB,iBAAa,EAAE,GAAG,OAAO;AACzB,aAAS,GAAG,IAAI,mBAAmB,KAA6B;AAAA,EAClE;AACA,SAAQ,YAAY;AACtB;",
4
+ "sourcesContent": ["import {\n createAnimationPlaybackController,\n normalizeAnimationPlaybackCandidate,\n type AnimationPlaybackController,\n} from '../animation/playback.js';\nimport type {\n PibblAnimationProgram,\n PibblPlayback,\n PibblPlaybackEvent,\n PibblPlaybackOptions,\n} from '../animation/types.js';\nimport { GLOBAL_STATE } from '../global-state.js';\nimport { isSignal } from '../signals/graph.js';\nimport { resolveSignalValue } from '../signals/resolve-signal-value.js';\nimport type { SignalValue } from '../signals/types.js';\nimport type { PibblComponentRefs, PibblInstance } from '../types.js';\nimport { requireHookContext, useHookSlot } from './hook-slot.js';\n\ntype PibblPlaybackOptionsInput = {\n readonly [K in keyof PibblPlaybackOptions]: SignalValue<PibblPlaybackOptions[K]>;\n};\n\ninterface PibblPlaybackHookSlot {\n readonly controller: AnimationPlaybackController;\n readonly componentRefs: PibblComponentRefs<any>;\n readonly pibblInstance: PibblInstance;\n latestOptions: PibblPlaybackOptions;\n mountSettled: boolean;\n readonly onError: (error: unknown) => void;\n readonly onEvent: (event: PibblPlaybackEvent) => void;\n renderRevision: number;\n}\n\nfunction isCurrentSlot(slot: PibblPlaybackHookSlot): boolean {\n return !slot.componentRefs.teardowns.closed &&\n !slot.pibblInstance.mainTeardowns.closed &&\n GLOBAL_STATE.pibblInstances.get(slot.pibblInstance.canvas) === slot.pibblInstance &&\n slot.pibblInstance.refs.get(slot.componentRefs.id) === slot.componentRefs;\n}\n\nfunction controllerOptions(\n candidate: PibblPlaybackOptions,\n onEvent: (event: PibblPlaybackEvent) => void,\n onError: (error: unknown) => void,\n): PibblPlaybackOptions {\n return {\n ...candidate,\n onEvent: typeof candidate.onEvent === 'function' ?\n onEvent : candidate.onEvent,\n onError: typeof candidate.onError === 'function' ?\n onError : candidate.onError,\n };\n}\n\n/**\n * Creates one component-owned animation playback handle for a hook slot.\n *\n * @param programInput - Animation program, optionally supplied by a signal. See\n * {@link SignalValue} , {@link PibblAnimationProgram} .\n * @param optionsInput - Playback configuration, optionally supplied by a signal. See\n * {@link SignalValue} , {@link PibblPlaybackOptionsInput} .\n * @returns Stable mount-owned playback controls and reactive status/time values. See\n * {@link PibblPlayback} .\n *\n * @see {@link SignalValue}\n * @see {@link PibblAnimationProgram}\n * @see {@link PibblPlayback}\n */\nexport function usePlayback(\n programInput: SignalValue<PibblAnimationProgram>,\n optionsInput: SignalValue<PibblPlaybackOptionsInput> = {},\n): PibblPlayback {\n const { componentRefs, pibblInstance } = requireHookContext();\n const program = resolveSignalValue(programInput);\n const options = resolvePlaybackOptions(optionsInput);\n const candidate = normalizeAnimationPlaybackCandidate(program, options);\n const candidateOptions = candidate.options;\n const slot = useHookSlot<PibblPlaybackHookSlot>('playback', teardowns => {\n let value!: PibblPlaybackHookSlot;\n const controller = createAnimationPlaybackController(\n candidate.program,\n candidateOptions,\n );\n controller.setDeferredStatusCommandOwner(pibblInstance.mainTeardowns);\n const onEvent = (event: PibblPlaybackEvent): void => {\n if (isCurrentSlot(value)) value.latestOptions.onEvent?.(event);\n };\n const onError = (error: unknown): void => {\n if (isCurrentSlot(value)) value.latestOptions.onError?.(error);\n };\n value = {\n controller,\n componentRefs,\n pibblInstance,\n latestOptions: {},\n mountSettled: false,\n onError,\n onEvent,\n renderRevision: 0,\n };\n controller.adopt(\n candidate.program,\n controllerOptions(candidateOptions, onEvent, onError),\n );\n teardowns.add(() => controller.dispose());\n return value;\n }).value;\n const revision = ++slot.renderRevision;\n const transaction = GLOBAL_STATE.renderTransaction;\n if (!transaction) {\n throw new Error('usePlayback requires an active Pibbl render transaction.');\n }\n transaction.onFinish(success => {\n if (!success || revision !== slot.renderRevision || !isCurrentSlot(slot)) return;\n slot.controller.adopt(\n candidate.program,\n controllerOptions(candidateOptions, slot.onEvent, slot.onError),\n );\n slot.latestOptions = candidateOptions;\n if (!slot.mountSettled) {\n slot.mountSettled = true;\n if (candidateOptions.autoplay === true) slot.controller.handle.play();\n }\n });\n return slot.controller.handle;\n}\n\nfunction resolvePlaybackOptions(\n input: SignalValue<PibblPlaybackOptionsInput>,\n): PibblPlaybackOptions {\n const source = resolveSignalValue(input);\n let resolved: Record<PropertyKey, unknown> | undefined;\n for (const key in source) {\n const value = source[key as keyof PibblPlaybackOptionsInput];\n if (!isSignal(value)) continue;\n resolved ??= { ...source };\n resolved[key] = resolveSignalValue(value as SignalValue<unknown>);\n }\n return (resolved ?? source) as PibblPlaybackOptions;\n}\n"],
5
+ "mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAOP,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB;AACzB,SAAS,0BAA0B;AAGnC,SAAS,oBAAoB,mBAAmB;AAiBhD,SAAS,cAAc,MAAsC;AAC3D,SAAO,CAAC,KAAK,cAAc,UAAU,UACnC,CAAC,KAAK,cAAc,cAAc,UAClC,aAAa,eAAe,IAAI,KAAK,cAAc,MAAM,MAAM,KAAK,iBACpE,KAAK,cAAc,KAAK,IAAI,KAAK,cAAc,EAAE,MAAM,KAAK;AAChE;AAEA,SAAS,kBACP,WACA,SACA,SACsB;AACtB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS,OAAO,UAAU,YAAY,aACpC,UAAU,UAAU;AAAA,IACtB,SAAS,OAAO,UAAU,YAAY,aACpC,UAAU,UAAU;AAAA,EACxB;AACF;AAgBO,SAAS,YACd,cACA,eAAuD,CAAC,GACzC;AACf,QAAM,EAAE,eAAe,cAAc,IAAI,mBAAmB;AAC5D,QAAM,UAAU,mBAAmB,YAAY;AAC/C,QAAM,UAAU,uBAAuB,YAAY;AACnD,QAAM,YAAY,oCAAoC,SAAS,OAAO;AACtE,QAAM,mBAAmB,UAAU;AACnC,QAAM,OAAO,YAAmC,YAAY,eAAa;AACvE,QAAI;AACJ,UAAM,aAAa;AAAA,MACjB,UAAU;AAAA,MACV;AAAA,IACF;AACA,eAAW,8BAA8B,cAAc,aAAa;AACpE,UAAM,UAAU,CAAC,UAAoC;AACnD,UAAI,cAAc,KAAK,EAAG,OAAM,cAAc,UAAU,KAAK;AAAA,IAC/D;AACA,UAAM,UAAU,CAAC,UAAyB;AACxC,UAAI,cAAc,KAAK,EAAG,OAAM,cAAc,UAAU,KAAK;AAAA,IAC/D;AACA,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA,eAAe,CAAC;AAAA,MAChB,cAAc;AAAA,MACd;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,IAClB;AACA,eAAW;AAAA,MACT,UAAU;AAAA,MACV,kBAAkB,kBAAkB,SAAS,OAAO;AAAA,IACtD;AACA,cAAU,IAAI,MAAM,WAAW,QAAQ,CAAC;AACxC,WAAO;AAAA,EACT,CAAC,EAAE;AACH,QAAM,WAAW,EAAE,KAAK;AACxB,QAAM,cAAc,aAAa;AACjC,MAAI,CAAC,aAAa;AAChB,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AACA,cAAY,SAAS,aAAW;AAC9B,QAAI,CAAC,WAAW,aAAa,KAAK,kBAAkB,CAAC,cAAc,IAAI,EAAG;AAC1E,SAAK,WAAW;AAAA,MACd,UAAU;AAAA,MACV,kBAAkB,kBAAkB,KAAK,SAAS,KAAK,OAAO;AAAA,IAChE;AACA,SAAK,gBAAgB;AACrB,QAAI,CAAC,KAAK,cAAc;AACtB,WAAK,eAAe;AACpB,UAAI,iBAAiB,aAAa,KAAM,MAAK,WAAW,OAAO,KAAK;AAAA,IACtE;AAAA,EACF,CAAC;AACD,SAAO,KAAK,WAAW;AACzB;AAEA,SAAS,uBACP,OACsB;AACtB,QAAM,SAAS,mBAAmB,KAAK;AACvC,MAAI;AACJ,aAAW,OAAO,QAAQ;AACxB,UAAM,QAAQ,OAAO,GAAsC;AAC3D,QAAI,CAAC,SAAS,KAAK,EAAG;AACtB,iBAAa,EAAE,GAAG,OAAO;AACzB,aAAS,GAAG,IAAI,mBAAmB,KAA6B;AAAA,EAClE;AACA,SAAQ,YAAY;AACtB;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@pibbl/core",
3
3
  "type": "module",
4
- "version": "0.0.1",
4
+ "version": "0.0.2",
5
5
  "description": "Canvas 2D component runtime with JSX and createElement authoring",
6
6
  "author": "Ben Lesh <ben@benlesh.com>",
7
7
  "license": "MIT",
8
- "homepage": "https://github.com/benlesh/crc",
8
+ "homepage": "https://github.com/benlesh/pibbl",
9
9
  "repository": {
10
10
  "type": "git",
11
- "url": "git+https://github.com/benlesh/crc.git",
11
+ "url": "git+https://github.com/benlesh/pibbl.git",
12
12
  "directory": "packages/core"
13
13
  },
14
- "bugs": "https://github.com/benlesh/crc/issues",
14
+ "bugs": "https://github.com/benlesh/pibbl/issues",
15
15
  "keywords": [
16
16
  "canvas",
17
17
  "jsx",
@@ -78,6 +78,14 @@
78
78
  "./sprites/formats/texture-packer": {
79
79
  "types": "./dist/features/sprites/formats/texture-packer.d.ts",
80
80
  "default": "./dist/features/sprites/formats/texture-packer.mjs"
81
+ },
82
+ "./machines": {
83
+ "types": "./dist/features/machines/index.d.ts",
84
+ "default": "./dist/features/machines/index.mjs"
85
+ },
86
+ "./machines/animation": {
87
+ "types": "./dist/features/machines/animation.d.ts",
88
+ "default": "./dist/features/machines/animation.mjs"
81
89
  }
82
90
  },
83
91
  "main": "./dist/index.mjs",
@@ -130,6 +138,12 @@
130
138
  ],
131
139
  "sprites/formats/texture-packer": [
132
140
  "./dist/features/sprites/formats/texture-packer.d.ts"
141
+ ],
142
+ "machines": [
143
+ "./dist/features/machines/index.d.ts"
144
+ ],
145
+ "machines/animation": [
146
+ "./dist/features/machines/animation.d.ts"
133
147
  ]
134
148
  }
135
149
  },
@@ -1,11 +0,0 @@
1
- import type { ScaleProps } from "./types.js";
2
- /**
3
- * Declares a named linear or band scale in the current layout for descendant visualization
4
- * components.
5
- *
6
- * @param props - Scale identity, domain, range, and child content. See {@link ScaleProps}.
7
- * @returns The scale's child content with the scale registered for descendants.
8
- *
9
- * @see {@link ScaleProps}
10
- */
11
- export declare function Scale(props: ScaleProps): import("@pibbl/core").PibblNode;
@@ -1,80 +0,0 @@
1
- import { resolveSignalValue, useComputed, useLayoutBox } from "@pibbl/core";
2
- import { equalScale, resolveLinearScale } from "./linear-scale.js";
3
- import { resolveBandScale } from "./band-scale.js";
4
- import { captureScaleLookup, provideScale } from "./scale-context.js";
5
- function Scale(props) {
6
- if ((typeof props.id !== "string" || props.id.length === 0) && typeof props.id !== "symbol")
7
- throw new TypeError("Scale id requires a nonempty string or symbol.");
8
- if (props.type !== "linear" && props.type !== "band")
9
- throw new TypeError(`Scale supports type="linear" or type="band".`);
10
- const { width, height } = useLayoutBox();
11
- const lookup = captureScaleLookup("Scale bandwidthOf");
12
- function resolveParent() {
13
- const range = resolveSignalValue(props.range);
14
- if (props.type !== "band" || typeof range !== "object" || range === null || !("bandwidthOf" in range))
15
- return void 0;
16
- const parent2 = lookup(range.bandwidthOf, "band")?.get();
17
- if (!parent2 || parent2.type !== "band")
18
- throw new TypeError("Scale bandwidthOf requires an ancestor band scale.");
19
- return parent2;
20
- }
21
- const parent = useComputed(resolveParent, [
22
- props.type,
23
- props.range,
24
- lookup
25
- ]).get();
26
- function resolvedRange() {
27
- const currentParent = resolveParent();
28
- return currentParent ? [0, currentParent.bandwidth] : resolveSignalValue(props.range);
29
- }
30
- const dependencies = [
31
- parent,
32
- props.type,
33
- props.domain,
34
- props.range,
35
- props.reverse,
36
- props.type === "band" ? props.paddingInner : void 0,
37
- props.type === "band" ? props.paddingOuter : void 0,
38
- width,
39
- height
40
- ];
41
- const value = useComputed(
42
- () => props.type === "band" ? resolveBandScale(
43
- resolveSignalValue(props.domain),
44
- resolvedRange(),
45
- resolveSignalValue(props.reverse ?? false),
46
- width,
47
- height,
48
- resolveSignalValue(props.paddingInner ?? 0),
49
- resolveSignalValue(props.paddingOuter ?? 0)
50
- ) : resolveLinearScale(
51
- resolveSignalValue(props.domain),
52
- resolvedRange(),
53
- resolveSignalValue(props.reverse ?? false),
54
- width,
55
- height
56
- ),
57
- dependencies,
58
- { equals: equalScale }
59
- );
60
- const linear = useComputed(() => {
61
- const resolved = value.get();
62
- if (resolved.type !== "linear")
63
- throw new TypeError(
64
- 'useScale requires type=linear; use useScale(id, "band") for band scales.'
65
- );
66
- return resolved;
67
- }, dependencies);
68
- const band = useComputed(() => {
69
- const resolved = value.get();
70
- if (resolved.type !== "band")
71
- throw new TypeError("useScale requires type=band.");
72
- return resolved;
73
- }, dependencies);
74
- provideScale(props.id, value, linear, band);
75
- return props.children;
76
- }
77
- export {
78
- Scale
79
- };
80
- //# sourceMappingURL=scale.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../src/features/viz/lib/scale.ts"],
4
- "sourcesContent": ["import { resolveSignalValue, useComputed, useLayoutBox } from \"@pibbl/core\";\nimport type { ScaleProps, ScaleRange } from \"./types.js\";\nimport { equalScale, resolveLinearScale } from \"./linear-scale.js\";\nimport { resolveBandScale } from \"./band-scale.js\";\nimport { captureScaleLookup, provideScale } from \"./scale-context.js\";\n/**\n * Declares a named linear or band scale in the current layout for descendant visualization\n * components.\n *\n * @param props - Scale identity, domain, range, and child content. See {@link ScaleProps}.\n * @returns The scale's child content with the scale registered for descendants.\n *\n * @see {@link ScaleProps}\n */\nexport function Scale(props: ScaleProps) {\n if (\n (typeof props.id !== \"string\" || props.id.length === 0) &&\n typeof props.id !== \"symbol\"\n )\n throw new TypeError(\"Scale id requires a nonempty string or symbol.\");\n if (props.type !== \"linear\" && props.type !== \"band\")\n throw new TypeError(`Scale supports type=\"linear\" or type=\"band\".`);\n const { width, height } = useLayoutBox();\n const lookup = captureScaleLookup(\"Scale bandwidthOf\");\n function resolveParent() {\n const range = resolveSignalValue(props.range);\n if (\n props.type !== \"band\" ||\n typeof range !== \"object\" ||\n range === null ||\n !(\"bandwidthOf\" in range)\n )\n return undefined;\n const parent = lookup(range.bandwidthOf, \"band\")?.get();\n if (!parent || parent.type !== \"band\")\n throw new TypeError(\"Scale bandwidthOf requires an ancestor band scale.\");\n return parent;\n }\n // This snapshot admits allocation changes into the current render transaction.\n // The formula also reads the live ancestor, preserving synchronous signal reads.\n const parent = useComputed(resolveParent, [\n props.type,\n props.range,\n lookup,\n ]).get();\n function resolvedRange(): ScaleRange {\n const currentParent = resolveParent();\n return currentParent\n ? [0, currentParent.bandwidth]\n : (resolveSignalValue(props.range) as ScaleRange);\n }\n const dependencies = [\n parent,\n props.type,\n props.domain,\n props.range,\n props.reverse,\n props.type === \"band\" ? props.paddingInner : undefined,\n props.type === \"band\" ? props.paddingOuter : undefined,\n width,\n height,\n ];\n const value = useComputed(\n () =>\n props.type === \"band\"\n ? resolveBandScale(\n resolveSignalValue(props.domain),\n resolvedRange(),\n resolveSignalValue(props.reverse ?? false),\n width,\n height,\n resolveSignalValue(props.paddingInner ?? 0),\n resolveSignalValue(props.paddingOuter ?? 0),\n )\n : resolveLinearScale(\n resolveSignalValue(props.domain),\n resolvedRange(),\n resolveSignalValue(props.reverse ?? false),\n width,\n height,\n ),\n dependencies,\n { equals: equalScale },\n );\n const linear = useComputed(() => {\n const resolved = value.get();\n if (resolved.type !== \"linear\")\n throw new TypeError(\n 'useScale requires type=linear; use useScale(id, \"band\") for band scales.',\n );\n return resolved;\n }, dependencies);\n const band = useComputed(() => {\n const resolved = value.get();\n if (resolved.type !== \"band\")\n throw new TypeError(\"useScale requires type=band.\");\n return resolved;\n }, dependencies);\n provideScale(props.id, value, linear, band);\n return props.children;\n}\n"],
5
- "mappings": "AAAA,SAAS,oBAAoB,aAAa,oBAAoB;AAE9D,SAAS,YAAY,0BAA0B;AAC/C,SAAS,wBAAwB;AACjC,SAAS,oBAAoB,oBAAoB;AAU1C,SAAS,MAAM,OAAmB;AACvC,OACG,OAAO,MAAM,OAAO,YAAY,MAAM,GAAG,WAAW,MACrD,OAAO,MAAM,OAAO;AAEpB,UAAM,IAAI,UAAU,gDAAgD;AACtE,MAAI,MAAM,SAAS,YAAY,MAAM,SAAS;AAC5C,UAAM,IAAI,UAAU,8CAA8C;AACpE,QAAM,EAAE,OAAO,OAAO,IAAI,aAAa;AACvC,QAAM,SAAS,mBAAmB,mBAAmB;AACrD,WAAS,gBAAgB;AACvB,UAAM,QAAQ,mBAAmB,MAAM,KAAK;AAC5C,QACE,MAAM,SAAS,UACf,OAAO,UAAU,YACjB,UAAU,QACV,EAAE,iBAAiB;AAEnB,aAAO;AACT,UAAMA,UAAS,OAAO,MAAM,aAAa,MAAM,GAAG,IAAI;AACtD,QAAI,CAACA,WAAUA,QAAO,SAAS;AAC7B,YAAM,IAAI,UAAU,oDAAoD;AAC1E,WAAOA;AAAA,EACT;AAGA,QAAM,SAAS,YAAY,eAAe;AAAA,IACxC,MAAM;AAAA,IACN,MAAM;AAAA,IACN;AAAA,EACF,CAAC,EAAE,IAAI;AACP,WAAS,gBAA4B;AACnC,UAAM,gBAAgB,cAAc;AACpC,WAAO,gBACH,CAAC,GAAG,cAAc,SAAS,IAC1B,mBAAmB,MAAM,KAAK;AAAA,EACrC;AACA,QAAM,eAAe;AAAA,IACnB;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM,SAAS,SAAS,MAAM,eAAe;AAAA,IAC7C,MAAM,SAAS,SAAS,MAAM,eAAe;AAAA,IAC7C;AAAA,IACA;AAAA,EACF;AACA,QAAM,QAAQ;AAAA,IACZ,MACE,MAAM,SAAS,SACX;AAAA,MACE,mBAAmB,MAAM,MAAM;AAAA,MAC/B,cAAc;AAAA,MACd,mBAAmB,MAAM,WAAW,KAAK;AAAA,MACzC;AAAA,MACA;AAAA,MACA,mBAAmB,MAAM,gBAAgB,CAAC;AAAA,MAC1C,mBAAmB,MAAM,gBAAgB,CAAC;AAAA,IAC5C,IACA;AAAA,MACE,mBAAmB,MAAM,MAAM;AAAA,MAC/B,cAAc;AAAA,MACd,mBAAmB,MAAM,WAAW,KAAK;AAAA,MACzC;AAAA,MACA;AAAA,IACF;AAAA,IACN;AAAA,IACA,EAAE,QAAQ,WAAW;AAAA,EACvB;AACA,QAAM,SAAS,YAAY,MAAM;AAC/B,UAAM,WAAW,MAAM,IAAI;AAC3B,QAAI,SAAS,SAAS;AACpB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AACF,WAAO;AAAA,EACT,GAAG,YAAY;AACf,QAAM,OAAO,YAAY,MAAM;AAC7B,UAAM,WAAW,MAAM,IAAI;AAC3B,QAAI,SAAS,SAAS;AACpB,YAAM,IAAI,UAAU,8BAA8B;AACpD,WAAO;AAAA,EACT,GAAG,YAAY;AACf,eAAa,MAAM,IAAI,OAAO,QAAQ,IAAI;AAC1C,SAAO,MAAM;AACf;",
6
- "names": ["parent"]
7
- }