From 9fb9ace144c4f666be51e1f526edaafbd2481063 Mon Sep 17 00:00:00 2001 From: Daniel Gimenez <4720650+DDtMM@users.noreply.github.com> Date: Wed, 27 Nov 2024 19:40:48 -0500 Subject: [PATCH] Fix bad manualCleanups: false, and improve springSignal --- .../spring-signal-page.component.ts | 8 ++- .../tween-signal-page.component.ts | 2 +- projects/demo/src/app/demo-configuration.ts | 4 +- ...ultiple-spring-numbers-demo.component.html | 16 +++++ .../multiple-spring-numbers-demo.component.ts | 21 ++++++ .../demo/src/app/services/demos-sources.ts | 2 + projects/signal-generators/package.json | 2 +- .../animated/animated-signal-base.spec.ts | 65 ++++++++++++++----- .../signals/animated/animated-signal-base.ts | 57 ++++++++-------- .../src/lib/signals/animated/spring-signal.ts | 6 +- .../src/lib/signals/media-query-signal.ts | 2 +- .../src/lib/utilities/inspect.ts | 2 +- .../signal-generators/src/lib/value-source.ts | 2 +- 13 files changed, 134 insertions(+), 55 deletions(-) create mode 100644 projects/demo/src/app/demos/spring-signal/multiple-spring-numbers-demo/multiple-spring-numbers-demo.component.html create mode 100644 projects/demo/src/app/demos/spring-signal/multiple-spring-numbers-demo/multiple-spring-numbers-demo.component.ts diff --git a/projects/demo/src/app/content/signal-factories/spring-signal-page.component.ts b/projects/demo/src/app/content/signal-factories/spring-signal-page.component.ts index ad574b6..6b9ca3e 100644 --- a/projects/demo/src/app/content/signal-factories/spring-signal-page.component.ts +++ b/projects/demo/src/app/content/signal-factories/spring-signal-page.component.ts @@ -3,6 +3,7 @@ import { RouterLink } from '@angular/router'; import { DemoHostComponent } from '../../controls/demo-host.component'; import { MemberPageHeaderComponent } from '../../controls/member-page-header.component'; import { SimpleSpringDemoComponent } from '../../demos/spring-signal/simple-spring-demo/simple-spring-demo.component'; +import { MultipleSpringNumbersDemoComponent } from '../../demos/spring-signal/multiple-spring-numbers-demo/multiple-spring-numbers-demo.component'; @Component({ @@ -10,6 +11,7 @@ import { SimpleSpringDemoComponent } from '../../demos/spring-signal/simple-spri imports: [ DemoHostComponent, MemberPageHeaderComponent, + MultipleSpringNumbersDemoComponent, RouterLink, SimpleSpringDemoComponent ], @@ -41,7 +43,11 @@ import { SimpleSpringDemoComponent } from '../../demos/spring-signal/simple-spri hiddenPattern="spring-options" > - + + + `, changeDetection: ChangeDetectionStrategy.OnPush diff --git a/projects/demo/src/app/content/signal-factories/tween-signal-page.component.ts b/projects/demo/src/app/content/signal-factories/tween-signal-page.component.ts index 87972d0..116d889 100644 --- a/projects/demo/src/app/content/signal-factories/tween-signal-page.component.ts +++ b/projects/demo/src/app/content/signal-factories/tween-signal-page.component.ts @@ -48,7 +48,7 @@ import { SimpleTweenDemoComponent } from '../../demos/tween-signal/simple-tween- hiddenPattern="easing-selector"> - diff --git a/projects/demo/src/app/demo-configuration.ts b/projects/demo/src/app/demo-configuration.ts index cbd36b1..e24f3cd 100644 --- a/projects/demo/src/app/demo-configuration.ts +++ b/projects/demo/src/app/demo-configuration.ts @@ -192,7 +192,7 @@ export const DEMO_CONFIGURATIONS = [ name: 'springSignal', page: () => import('./content/signal-factories/spring-signal-page.component').then(x => x.SpringSignalPageComponent), route: 'spring-signal', - sourceUrl: 'signals/dom-observers/spring-signal.ts', + sourceUrl: 'signals/animation/spring-signal.ts', usages: ['generator', 'writableSignal'] }, { @@ -242,7 +242,7 @@ export const DEMO_CONFIGURATIONS = [ name: 'tweenSignal', page: () => import('./content/signal-factories/tween-signal-page.component').then(x => x.TweenSignalPageComponent), route: 'tween-signal', - sourceUrl: 'signals/tween-signal.ts', + sourceUrl: 'signals/animation/tween-signal.ts', usages: ['generator', 'writableSignal'] } ] satisfies DemoConfigurationItem[]; diff --git a/projects/demo/src/app/demos/spring-signal/multiple-spring-numbers-demo/multiple-spring-numbers-demo.component.html b/projects/demo/src/app/demos/spring-signal/multiple-spring-numbers-demo/multiple-spring-numbers-demo.component.html new file mode 100644 index 0000000..9e0ab95 --- /dev/null +++ b/projects/demo/src/app/demos/spring-signal/multiple-spring-numbers-demo/multiple-spring-numbers-demo.component.html @@ -0,0 +1,16 @@ + + +
+ +
+
+
+
+
+ ({{$coords()[0] | number: '1.1-2'}}, {{$coords()[1] | number: '1.1-2'}}) +
+
+ diff --git a/projects/demo/src/app/demos/spring-signal/multiple-spring-numbers-demo/multiple-spring-numbers-demo.component.ts b/projects/demo/src/app/demos/spring-signal/multiple-spring-numbers-demo/multiple-spring-numbers-demo.component.ts new file mode 100644 index 0000000..bf80819 --- /dev/null +++ b/projects/demo/src/app/demos/spring-signal/multiple-spring-numbers-demo/multiple-spring-numbers-demo.component.ts @@ -0,0 +1,21 @@ +import { CommonModule } from '@angular/common'; +import { ChangeDetectionStrategy, Component, signal } from '@angular/core'; +import { SpringOptions, springSignal } from '@ddtmm/angular-signal-generators'; +import { SpringOptionsComponent } from "../shared/spring-options.component"; + +@Component({ + selector: 'app-multiple-spring-numbers-demo', + templateUrl: './multiple-spring-numbers-demo.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [CommonModule, SpringOptionsComponent] +}) +export class MultipleSpringNumbersDemoComponent { + readonly $springOptions = signal>({ damping: 7, stiffness: 150 }); + readonly $coords = springSignal([0, 0], { ...this.$springOptions() }); + + setCords(event: MouseEvent, desiredTarget: HTMLElement) { + if (event.target === desiredTarget) { + this.$coords.set([event.offsetX - 8, event.offsetY - 8]); + } + } +} diff --git a/projects/demo/src/app/services/demos-sources.ts b/projects/demo/src/app/services/demos-sources.ts index 70cdb5f..d9b4607 100644 --- a/projects/demo/src/app/services/demos-sources.ts +++ b/projects/demo/src/app/services/demos-sources.ts @@ -15,6 +15,8 @@ export default { "spring-signal/simple-spring-demo/simple-spring-demo.component.ts": "import { ChangeDetectionStrategy, Component, signal } from '@angular/core';\r\nimport { SpringOptions, springSignal } from '@ddtmm/angular-signal-generators';\r\nimport { SpringOptionsComponent } from \"../shared/spring-options.component\";\r\n\r\n@Component({\r\n selector: 'app-simple-spring-demo',\r\n templateUrl: './simple-spring-demo.component.html',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [SpringOptionsComponent]\r\n})\r\nexport class SimpleSpringDemoComponent {\r\n readonly $springOptions = signal>({ damping: 3, stiffness: 100 });\r\n readonly $sliderValue = springSignal(0, { clamp: true, ...this.$springOptions() });\r\n}\r\n", "spring-signal/simple-spring-demo/simple-spring-demo.component.html": "
\r\n \r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n \r\n
\r\n
\r\n", "spring-signal/shared/spring-options.component.ts": "import { CommonModule } from '@angular/common';\r\nimport { ChangeDetectionStrategy, Component, model } from '@angular/core';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { SpringOptions } from '@ddtmm/angular-signal-generators';\r\n\r\n\r\n@Component({\r\n selector: 'app-spring-options',\r\n imports: [CommonModule, FormsModule],\r\n template: `\r\n
\r\n
\r\n \r\n \r\n {{ ($springOptions().damping || 0) | number: '1.1-1' }} \r\n
\r\n
\r\n \r\n \r\n {{ ($springOptions().stiffness || 0) | number: '1.1-1' }} \r\n
\r\n
\r\n `,\r\n changeDetection: ChangeDetectionStrategy.OnPush\r\n})\r\nexport class SpringOptionsComponent {\r\n readonly $springOptions = model.required>(\r\n { alias: 'springOptions' }\r\n );\r\n\r\n patchOptions(partialOptions: Partial): void {\r\n this.$springOptions.update((x) => ({ ...x, ...partialOptions }));\r\n }\r\n}\r\n", + "spring-signal/multiple-spring-numbers-demo/multiple-spring-numbers-demo.component.ts": "import { CommonModule } from '@angular/common';\r\nimport { ChangeDetectionStrategy, Component, signal } from '@angular/core';\r\nimport { SpringOptions, springSignal } from '@ddtmm/angular-signal-generators';\r\nimport { SpringOptionsComponent } from \"../shared/spring-options.component\";\r\n\r\n@Component({\r\n selector: 'app-multiple-spring-numbers-demo',\r\n templateUrl: './multiple-spring-numbers-demo.component.html',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [CommonModule, SpringOptionsComponent]\r\n})\r\nexport class MultipleSpringNumbersDemoComponent {\r\n readonly $springOptions = signal>({ damping: 7, stiffness: 150 });\r\n readonly $coords = springSignal([0, 0], { ...this.$springOptions() });\r\n\r\n setCords(event: MouseEvent, desiredTarget: HTMLElement) {\r\n if (event.target === desiredTarget) {\r\n this.$coords.set([event.offsetX - 8, event.offsetY - 8]);\r\n }\r\n }\r\n}\r\n", + "spring-signal/multiple-spring-numbers-demo/multiple-spring-numbers-demo.component.html": "\r\n\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n ({{$coords()[0] | number: '1.1-2'}}, {{$coords()[1] | number: '1.1-2'}})\r\n
\r\n
\r\n\r\n", "sequence-signal/toggle-demo/toggle-demo.component.ts": "import { ChangeDetectionStrategy, Component } from '@angular/core';\r\nimport { sequenceSignal } from '@ddtmm/angular-signal-generators';\r\n\r\n@Component({\n selector: 'app-toggle-demo',\n imports: [],\n templateUrl: './toggle-demo.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\r\nexport class ToggleDemoComponent {\r\n readonly $trueFalseToggle = sequenceSignal([true, false]);\r\n}\r\n", "sequence-signal/toggle-demo/toggle-demo.component.html": "
\r\n \r\n
Current Value
\r\n
{{$trueFalseToggle()}}
\r\n
\r\n", "sequence-signal/fibonacci-demo/fibonacci-demo.component.ts": "import { ChangeDetectionStrategy, Component } from '@angular/core';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { sequenceSignal } from '@ddtmm/angular-signal-generators';\r\n\r\n@Component({\n selector: 'app-fibonacci-demo',\n imports: [FormsModule],\n templateUrl: './fibonacci-demo.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\r\nexport class FibonacciDemoComponent {\r\n readonly $fibonacci = sequenceSignal((() => {\r\n let values = [1, 2];\r\n return {\r\n next: (relativeChange: number) => {\r\n for (let i = 0; i < relativeChange; i++) {\r\n values = [values[1], values[0] + values[1]];\r\n }\r\n for (let i = relativeChange; i < 0; i++) {\r\n values = [Math.max(1, values[1] - values[0]), Math.max(values[0], 2)];\r\n }\r\n return { hasValue: true, value: values[0] };\r\n },\r\n reset: () => values = [1, 2]\r\n };\r\n })());\r\n fibonacciStepSize = 1;\r\n}\r\n", diff --git a/projects/signal-generators/package.json b/projects/signal-generators/package.json index ba1f939..1b37edc 100644 --- a/projects/signal-generators/package.json +++ b/projects/signal-generators/package.json @@ -1,6 +1,6 @@ { "name": "@ddtmm/angular-signal-generators", - "version": "3.0.2", + "version": "3.0.3", "license": "MIT", "description": "Specialized Angular signals to help with frequently encountered situations.", "peerDependencies": { diff --git a/projects/signal-generators/src/lib/signals/animated/animated-signal-base.spec.ts b/projects/signal-generators/src/lib/signals/animated/animated-signal-base.spec.ts index b042f23..300ba6b 100644 --- a/projects/signal-generators/src/lib/signals/animated/animated-signal-base.spec.ts +++ b/projects/signal-generators/src/lib/signals/animated/animated-signal-base.spec.ts @@ -8,11 +8,18 @@ import { runTypeGuardTests } from '../../../testing/common-signal-tests'; import { createFixture, tickAndAssertValues } from '../../../testing/testing-utilities'; -import { AnimatedSignal, animatedSignalFactory, AnimatedSignalOptions, AnimationOptions, AnimationStepFn, WritableAnimatedSignal } from './animated-signal-base'; +import { + AnimatedSignal, + animatedSignalFactory, + AnimatedSignalOptions, + AnimationOptions, + AnimationState, + AnimationStepFn, + WritableAnimatedSignal +} from './animated-signal-base'; import { ValueSource } from '../../value-source'; import { ReactiveSource } from '../../reactive-source'; - describe('animatedSignalFactory', () => { describe('when passed a value', () => { runDebugNameOptionTest((debugName) => createAnimationSignalForTest(1, { debugName })); @@ -90,7 +97,7 @@ describe('animatedSignalFactory', () => { ] ); })); - + it('returns an interpolated value when interpolator is passed', fakeAsync(() => { const sut = TestBed.runInInjectionContext(() => createAnimationSignalForTest(1, { @@ -158,12 +165,36 @@ describe('animatedSignalFactory', () => { ] ); })); - it('updates after next effect if duration is less than 0', fakeAsync(() => { + it('updates to final value after first effect if step function determines it should be done.', fakeAsync(() => { const sut = TestBed.runInInjectionContext(() => createAnimationSignalForTest(1, { duration: -100 })); sut.set(5); tick(); expect(sut()).toBe(5); })); + it('maintains the previous state if a new animation starts before the previous one is finished', fakeAsync(() => { + /* + Because state is not immutable spy.toHaveBeenCalledWith will just contain the state of the last call. + So, we keep track of the tickCount in the step function and use that to determine that the state was maintained. + */ + const initialState = { tickCount: 0 }; + let tickCountOuter = 0; + + const stepFn = jasmine.createSpy().and.callFake((state: AnimationState, options: TestAnimationOptions) => { + state.progress = options.duration > 0 ? Math.min(1, state.timeElapsed / options.duration) : 1; + state.isDone = state.progress === 1; + tickCountOuter = ++state.tickCount; + }); + const sut = TestBed.runInInjectionContext(() => createAnimationSignalForTest(1, { duration: 100 }, stepFn, initialState)); + sut.set(5); + tick(50); + const tickCountAtChange = tickCountOuter; + expect(tickCountAtChange).toBeGreaterThan(0); + expect(stepFn).toHaveBeenCalledWith(jasmine.objectContaining({ tickCount: tickCountAtChange }), jasmine.anything()); + sut.set(9); + tick(0); + expect(tickCountOuter).toBe(tickCountAtChange + 1); + + })); // fit('updates predictably if for some reason multiple frames occur within the same time interval', fakeAsync(() => { // const sut = TestBed.runInInjectionContext(() => createAnimationSignalForTest(1, { duration: 500 })); // sut.set(5); @@ -278,7 +309,9 @@ describe('animatedSignalFactory', () => { })); it('returns the end value if there are not a matching property to transition from in the original object', fakeAsync(() => { - const sut = TestBed.runInInjectionContext(() => createAnimationSignalForTest>({ x: 0 }, { duration: 500 })); + const sut = TestBed.runInInjectionContext(() => + createAnimationSignalForTest, {}>({ x: 0 }, { duration: 500 }) + ); sut.set({ x: 10, y: -10 }); tickAndAssertValues( () => ({ x: Math.round(sut()['x']), y: Math.round(sut()['y']) }), @@ -339,27 +372,27 @@ describe('animatedSignalFactory', () => { }); }); -function createStepFunctionSpy(): jasmine.Spy> { - return jasmine.createSpy>('stepFunction').and.callFake((progress: number) => progress); -} - interface TestAnimationOptions extends AnimationOptions { duration: number; } + /** * Creates an animated signal for testing. * @param source The value source for the signal * @param signalOptions Animation options to the signal that came from the user. * @param stepFn A step function to use, if none is passed a linear step function will be used. * @param initialState A state bag, if none is provided then an empty object will be used. - * @returns + * @returns */ -function createAnimationSignalForTest( - source: ValueSource, - signalOptions?: Partial>, - stepFn?: AnimationStepFn<{ duration: number }, TestAnimationOptions>, +function createAnimationSignalForTest( + source: ValueSource, + signalOptions?: Partial>, + stepFn?: AnimationStepFn, initialState?: any -): typeof source extends ReactiveSource ? AnimatedSignal : WritableAnimatedSignal { +): typeof source extends ReactiveSource + ? AnimatedSignal + : WritableAnimatedSignal { + return animatedSignalFactory( source, signalOptions, @@ -370,4 +403,4 @@ function createAnimationSignalForTest( state.isDone = state.progress === 1; }) ) as any; // can't seem to get the types right here. -} \ No newline at end of file +} diff --git a/projects/signal-generators/src/lib/signals/animated/animated-signal-base.ts b/projects/signal-generators/src/lib/signals/animated/animated-signal-base.ts index 826369c..9bf46e7 100644 --- a/projects/signal-generators/src/lib/signals/animated/animated-signal-base.ts +++ b/projects/signal-generators/src/lib/signals/animated/animated-signal-base.ts @@ -1,10 +1,10 @@ import { CreateSignalOptions, Injector, Signal, WritableSignal, effect, signal, untracked } from '@angular/core'; import { SIGNAL, SignalGetter, createSignal, signalSetFn, signalUpdateFn } from '@angular/core/primitives/signals'; -import { AnimationFrameFn, getRequestAnimationFrame } from './animation-utilities'; import { isReactive } from '../../internal/reactive-source-utilities'; import { coerceSignal } from '../../internal/signal-coercion'; import { ReactiveSource } from '../../reactive-source'; import { ValueSource } from '../../value-source'; +import { AnimationFrameFn, getRequestAnimationFrame } from './animation-utilities'; import { InterpolateFactoryFn, NumericValues, createInterpolator } from './interpolation'; /** Request animation frame function */ @@ -46,21 +46,21 @@ export type AnimatedSignalOptions = Partial }; /** Same as regular {@link AnimatedSignalOptions}, but interpolator is not required. */ -export type AnimatedNumericSignalOptions = Omit< - AnimatedSignalOptions, +export type AnimatedNumericSignalOptions = Omit< + AnimatedSignalOptions, 'interpolator' > & - Partial, 'interpolator'>>; + Partial, 'interpolator'>>; export interface AnimatedSignal extends Signal { - /** Sets the default animation parameters for the signal. This won't updated a running animation. */ - setOptions(options: Partial }>): void; + /** Sets the default animation parameters for the signal. */ + setOptions(options: Partial>): void; } export interface WritableAnimatedSignal extends AnimatedSignal { - /** Sets the value of signal with optional options. */ - set(value: TVal, options?: Partial & { interpolator?: InterpolateFactoryFn }): void; - /** Update the value of the signal based on its current value. */ - update(updateFn: (value: TVal) => TVal, options?: Partial }>): void; + /** Sets the value of signal with optional animation options during the next transition. */ + set(value: TVal, oneTimeOptions?: Partial>): void; + /** Update the value of the signal based on its current value, with optional animation options used during the next transition. */ + update(updateFn: (value: TVal) => TVal, oneTimeOptions?: Partial>): void; /** Returns a readonly version of this signal */ asReadonly(): Signal; } @@ -124,18 +124,19 @@ export function animatedSignalFactory, O extends Ani let delayTimeoutId: ReturnType | undefined = undefined; let instanceId = 0; - + let state: AnimationState; effect((onCleanup) => { const priorValue = untracked($output); const [nextValue, overrideOptions] = signalValueFn(); if (nextValue === priorValue) { - return; // this should only occur at the initial effect run. + // since an array is being passed from signalValueFn, it could be the same value was sent. + return; } const animationOptions = overrideOptions ? { ...overwriteProperties({ ...defaults }, overrideOptions) } : defaults; const interpolate = (overrideOptions?.interpolator || defaults.interpolator)(priorValue, nextValue); const thisInstanceId = ++instanceId; - let state: AnimationState; + // in case a previous animation was delayed then clear it before it starts. clearTimeout(delayTimeoutId); @@ -145,17 +146,21 @@ export function animatedSignalFactory, O extends Ani start(); } + + function start(): void { const timeCurrent = Date.now(); state = { + ...initialState, + ...state, isDone: false, progress: 0, timeCurrent, timeElapsed: 0, timeDelta: 0, timeStart: timeCurrent, - ...initialState }; + stepFn(state, animationOptions); // run initial step function in case animation isn't necessary. if (state.isDone) { // don't bother with the animation since its done already. @@ -195,36 +200,34 @@ export function animatedSignalFactory, O extends Ani /** Coerces a source signal from signal input and creates the output signal.. */ function createFromReactiveSource( reactiveSource: ReactiveSource, - options: Partial> | undefined + signalOptions: Partial> | undefined ): [ output: SignalGetter & WritableAnimatedSignal, - valueFn: () => Readonly<[value: T, options: Partial }> | undefined]> + valueFn: () => Readonly<[value: T]> ] { - const $source = coerceSignal(reactiveSource, options); - const $output = signal(untracked($source), options) as SignalGetter & WritableSignal & AnimatedSignal; + const $source = coerceSignal(reactiveSource, signalOptions); + const $output = signal(untracked($source), signalOptions) as SignalGetter & WritableSignal & AnimatedSignal; $output.setOptions = (options) => overwriteProperties(defaults, options); - const signalValueFn = () => [$source(), undefined] as const; + const signalValueFn = () => [$source()] as const; return [$output, signalValueFn]; } /** Creates a writable source signal and output signal from the initial value. */ function createFromValue( sourceValue: T, - options: Partial> | undefined + signalOptions: Partial> | undefined ): [ output: SignalGetter & WritableAnimatedSignal, - valueFn: () => Readonly<[value: T, options: Partial }> | undefined]> + valueFn: () => Readonly<[value: T, oneTimeOptions: Partial> | undefined]> ] { - const $output = signal(sourceValue, options) as SignalGetter & WritableSignal & AnimatedSignal; + const $output = signal(sourceValue, signalOptions) as SignalGetter & WritableSignal & AnimatedSignal; const $source = createSignal< - Readonly<[value: T, options: Partial }> | undefined]> + Readonly<[value: T, options: Partial> | undefined]> >([sourceValue as T, undefined]); const sourceNode = $source[SIGNAL]; - $output.set = (x, options?: Partial }>) => + $output.set = (x, options?: Partial>) => signalSetFn(sourceNode, [x, options] as const); $output.setOptions = (options) => overwriteProperties(defaults, options); - - $output.update = (updateFn: (value: T) => T, options?: Partial }>) => signalUpdateFn(sourceNode, ([value]) => [updateFn(value), options] as const); const signalValueFn = $source; @@ -236,7 +239,7 @@ export function animatedSignalFactory, O extends Ani * Different then spread operator as it will ignore undefined values. * @returns The value of {@link target}. */ -export function overwriteProperties(target: T, values: Partial): T { +function overwriteProperties(target: T, values: Partial): T { Object.entries(values).forEach(([key, value]) => { if (key in target && value !== undefined) { target[key as keyof T] = value as T[keyof T]; diff --git a/projects/signal-generators/src/lib/signals/animated/spring-signal.ts b/projects/signal-generators/src/lib/signals/animated/spring-signal.ts index 9ae6943..fc17ec6 100644 --- a/projects/signal-generators/src/lib/signals/animated/spring-signal.ts +++ b/projects/signal-generators/src/lib/signals/animated/spring-signal.ts @@ -56,11 +56,9 @@ export function springSignal(source: ValueSource, options: SpringSignalOpt * is passed then this is not required. Otherwise an interpolator is required to translate the change of the value. * @example * ```ts - * const fastLinearChange = springSignal(1); - * const slowEaseInChange = springSignal(1, { duration: 5000, easing: easeInQuad }); + * const $animatedValue = springSignal(1, { damping: 3, stiffness: 100 }); * function demo(): void { - * fastLinearChange.set(5); // in 400ms will display something like 1, 1.453, 2.134, 3.521, 4.123, 5. - * slowEaseInChange.set(5, { duration: 10000 }); // in 10000ms will display something like 1, 1.21, 1.4301... + * $animatedValue.set(5); * } * ``` */ diff --git a/projects/signal-generators/src/lib/signals/media-query-signal.ts b/projects/signal-generators/src/lib/signals/media-query-signal.ts index 90bbeb6..0a01d06 100644 --- a/projects/signal-generators/src/lib/signals/media-query-signal.ts +++ b/projects/signal-generators/src/lib/signals/media-query-signal.ts @@ -93,7 +93,7 @@ export function mediaQuerySignal( effectRef.destroy(); // make sure the effect is destroyed. handleDestroy(); }; - getDestroyRef(mediaQuerySignal, options?.injector).onDestroy(handleDestroy); + getDestroyRef(mediaQuerySignal, options?.injector).onDestroy($output.destroy); return $output; } diff --git a/projects/signal-generators/src/lib/utilities/inspect.ts b/projects/signal-generators/src/lib/utilities/inspect.ts index f19f90c..9a25af9 100644 --- a/projects/signal-generators/src/lib/utilities/inspect.ts +++ b/projects/signal-generators/src/lib/utilities/inspect.ts @@ -58,5 +58,5 @@ export function inspect(subject: T, options?: InspectOptions): void { reporter = () => reporter = nextReporter; } const $input = nestSignal(subject, options); - effect(() => reporter($input()), { ...options, manualCleanup: true }); + effect(() => reporter($input()), { ...options }); } diff --git a/projects/signal-generators/src/lib/value-source.ts b/projects/signal-generators/src/lib/value-source.ts index 2d928c4..10417c2 100644 --- a/projects/signal-generators/src/lib/value-source.ts +++ b/projects/signal-generators/src/lib/value-source.ts @@ -34,6 +34,6 @@ export function watchValueSourceFn( injector?: Injector ): void { if (isSignal(valueSrcFn)) { - effect(() => callback(valueSrcFn()), { injector: injector, manualCleanup: true }); + effect(() => callback(valueSrcFn()), { injector: injector }); } }