Skip to content

Commit

Permalink
Merge pull request #84 from DDtMM/17.x
Browse files Browse the repository at this point in the history
Closes #83
  • Loading branch information
DDtMM authored Apr 25, 2024
2 parents d82436b + 1dcf4db commit a826c56
Show file tree
Hide file tree
Showing 22 changed files with 122 additions and 59 deletions.
2 changes: 1 addition & 1 deletion projects/demo/src/app/controls/demo-host.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface DemoHostSourceFile extends SourceFile {
imports: [CopyButtonComponent, CommonModule, FontAwesomeModule, HighlightModule],
template: `
<div class="flex flex-row gap-3">
<div class="mx-1 mb-1 text-xl text-secondary">{{$name()}}</div>
<div class="mb-1 text-xl text-secondary">{{$name()}}</div>
<button type="button" class="btn btn-secondary btn-outline btn-sm" (click)="openProject()" title="Open in StackBlitz">
<img class="w-4" alt="Open in StackBlitz" src="assets/stackblitz-icon.svg"/>
<span class="hidden sm:inline">StackBlitz</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ import { CustomerDemoComponent } from './customer-demo/customer-demo.component';
</p>
<p>
To avoid confusion an observable of observables is not "flattened." This is so observables passed in as the valueSource can
create a writable signal. The function <code class="inline p-1">toSignal</code> can be used if this behavior is necessary.
create a writable signal. The function <code class="inline">toSignal</code> can be used if this behavior is necessary.
</p>
<p>
This function is most convenient when you need to execute an asynchronous request when a signal changes.
As seen in the example below, you can mix signals and observables by wrapping them in an anonymous function.
This function is converted to a computed signal that returns an observable.
Every time a signal changes, <b>asyncSignal</b> will unsubscribe from the old observable and
subscribe to the new one, behaving similarly to an Rxjs <code class="inline p-1">switchMap</code>.
subscribe to the new one, behaving similarly to an Rxjs <code class="inline">switchMap</code>.
</p>
<app-demo-host name="Execute Async Requests When a Signal Changes"
pattern="async-signal/customer-demo/"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This is very similar to rxjs's <i>debounce</i> operator.
This has two overloads - one where it accepts a signal and the value is debounced in a readonly signal,
and one where it has a <i>set</i> and <i>update</i> method and the change of the value occurs after debounce time elapses.
</p>
<div class="flex flex-col gap-3">
<div class="flex flex-col gap-6">
<app-demo-host name="Directly set debounced signal" pattern="debounce-signal/direct-demo/">
<app-direct-demo />
</app-demo-host>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ import { DemoHostComponent } from '../../controls/demo-host.component';
When implementing a new method, a proxy of the original signal will be passed (this could be the original signal if no method hiding occurs).
</p>
<p>
This is essentially just a wrapper for <code class="inline p-1">Object.assign</code>.
The <span class="italic">only</span> advantage over <code class="inline p-1">assign</code> is
This is essentially just a wrapper for <code class="inline">Object.assign</code>.
The <span class="italic">only</span> advantage over <code class="inline">assign</code> is
this allows you to hide the original implementation of the source signal's methods.
For example, you can have a set method that multiplies a value and uses the original set to actually set the signal's value.
</p>
<p>
If changing how a signal's original methods work isn't something you need, then just use
<code class="inline p-1">Object.assign</code> or assign the functions directly.
<code class="inline">Object.assign</code> or assign the functions directly.
</p>
<app-demo-host name="Signal with specialized setters" pattern="extend-signal/extend-signal-demo/">
<app-extend-signal-demo />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import { MathDemoComponent } from './math-demo/math-demo.component';
This creates a signal whose input value is automatically mapped to an output value.
The selector function can include signals or can be mapped directly from an array of signals.
</p>
<p>
The writable version of this signal is basically just a writable signal combined with a computed function,
while the version that accepts multiple signal-like sources (signals, observables, computed functions, etc...) is essentially just a computed signal that
has more brevity in certain circumstances.
</p>
<app-demo-host name="A Writable Mapped Signal and Map from other Signals" pattern="map-signal/math-demo/">
<app-math-demo />
</app-demo-host>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="inline-block ">
<div class="grid grid-cols-2 gap-3 ">
<label class="label" for="inputVal">Input Value</label>
<input class="input input-bordered w-32 text-right" id="inputVal" type="number" [ngModel]="$inputVal.input()" (ngModelChange)="$inputVal.set($event)" />
<input class="input input-bordered w-32 text-right" id="inputVal" type="number" [(ngModel)]="$inputVal.input" />
<label class="label" for="multiplier">Multiplier</label>
<input class="input input-bordered w-32 text-right" id="multiplier" type="number" [(ngModel)]="$multiplier" />
<label class="label" >Output</label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { SearchHistoryDemoComponent } from './search-history-demo/search-history
template: `
<app-signal-header fnName="reduceSignal" />
<p>
Creates a signal similar to <code class="inline p-1">Array.reduce</code> or Rxjs's <code class="inline p-1">scan</code> operator. When
Creates a signal similar to <code class="inline">Array.reduce</code> or Rxjs's <code class="inline">scan</code> operator. When
the signal is set, the callback function is executed with the prior and currently set value as arguments, returning a new value.
</p>
<p>Like other reduce-like functions the value set to the signal does not have to be the same type returned from it.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ToggleDemoComponent } from './toggle-demo/toggle-demo.component';
This accepts a sequence of values, and moves to the next value after every call to next.
The sequence can be something simple as a toggle between states, or a complex sequence generated by a function.
</p>
<div class="flex flex-col gap-3">
<div class="flex flex-col gap-6">
<app-demo-host name="Simple Toggle" pattern="sequence-signal/toggle-demo/toggle-demo.component">
<app-toggle-demo />
</app-demo-host>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { SignalHeaderComponent } from '../../controls/signal-header.component';
<p>
This converts a signal into an AsyncIterator.
The emissions from the signal will build up, and then released each time next is called.
The iterator can be used in a <code class="inline p-1">for async</code> loop.
The iterator can be used in a <code class="inline">for async</code> loop.
This uses an effect under the hood, so be sure to pass injector if it isn't created in the constructor.
</p>
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ A signal that uses a secondary storage system to store values, ideally beyond th
When the signal is initialized it will check the store for an existing value and fallback to the initialValue if it wasn't present.
</p>
<p>
The <i>storageSignal</i> implementation requires a store to be specified,
but two built-in implementations exist: <i>localStorageSignal</i> and <i>sessionStorageSignal</i>.
The <b>storageSignal</b> implementation requires a store to be specified,
but two built-in implementations exist: <b>localStorageSignal</b> and <b>sessionStorageSignal</b>.
</p>
<div class="flex flex-col gap-3">
<div class="flex flex-col gap-6">
<app-demo-host name="Built-in Browser Storage Signal with Custom Serialization" pattern="storage-signal/built-in-storage-demo">
<app-built-in-storage-demo />
</app-demo-host>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
</p>
<div class="flex flex-row gap-3 items-center pb-3">
<span>Easing Function</span>
<app-easing-selector [(easingFn)]="$easingFn" />
<app-easing-selector [(easingFn)]="$easingFn" (easingFnChange)="$coords.setOptions({ easing: $easingFn() })" />
</div>
<div class="cursor-pointer w-36 h-36 bg-green-600 rounded-lg border-slate-900 border-solid border"
(click)="$coords.set([$event.offsetX - 8, $event.offsetY - 8], { easing: $easingFn() }) ">
(click)="$coords.set([$event.offsetX - 8, $event.offsetY - 8])">
<div class="w-4 h-4 bg-slate-900 rounded-full"
[ngStyle]="{ 'translate': $coords()[0] + 'px ' + $coords()[1] + 'px' }">
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ import { EasingSelectorComponent } from '../shared/easing-selector.component';
})
export class MultipleNumbersDemoComponent {
readonly $easingFn = signal<EasingFn>(easeInBack);
readonly $coords = tweenSignal([0, 0]);
readonly $coords = tweenSignal([0, 0], { easing: this.$easingFn() });
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<div class="flex flex-row gap-3 items-center pb-3">
<span>Easing Function</span>
<app-easing-selector [(easingFn)]="$easingFn" />
<app-easing-selector [(easingFn)]="$easingFn" (easingFnChange)="$sliderValue.setOptions({ easing: $easingFn() })" />
</div>
<div class="flex flex-col w-full sm:flex-row items-center">
<div class="flex-none">
<div class="join pr-3">
<button type="button" class="btn btn-primary join-item" (click)="tweenSignalSimple.set(0, { easing: $easingFn() })">0%</button>
<button type="button" class="btn btn-primary join-item" (click)="tweenSignalSimple.set(50, { easing: $easingFn() })">50%</button>
<button type="button" class="btn btn-primary join-item" (click)="tweenSignalSimple.set(100, { easing: $easingFn() })">100%</button>
<button type="button" class="btn btn-primary join-item" (click)="$sliderValue.set(0)">0%</button>
<button type="button" class="btn btn-primary join-item" (click)="$sliderValue.set(50)">50%</button>
<button type="button" class="btn btn-primary join-item" (click)="$sliderValue.set(100)">100%</button>
</div>
</div>
<div>
<input class="range range-primary" type="range" [value]="tweenSignalSimple()" min="0" max="100" />
<input class="range range-primary" type="range" [value]="$sliderValue()" min="0" max="100" />
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ import { EasingSelectorComponent } from '../shared/easing-selector.component';
})
export class SimpleDemoComponent {
readonly $easingFn = signal<EasingFn>(easeInBack);
readonly tweenSignalSimple = tweenSignal(0);
readonly $sliderValue = tweenSignal(0, { easing: this.$easingFn() });
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,23 @@ import { SimpleDemoComponent } from './simple-demo/simple-demo.component';
By default this can automatically tween between a number, array of numbers, or Record of numbers.
You can also pass an interpolation function to tween between objects of any type.
</p>
<h2>Animation Options</h2>
<p>
As a convenience a collection of easing functions are provided such as <i>easeInBack</i>.
They can also be retrieved as a collection of all easing functions by importing <i>easings</i>.
Animation options can be passed when creating the signal along with signal creation options.
They can also be changed by calling <code class="inline">setOptions</code> on the signal or by passing an optional parameter when setting the signal.
The values passed while setting the signal will only be used for the duration of the animation.
</p>
<div class="flex flex-col gap-3">
<h2>Easings</h2>
<p>
As a convenience a collection of easing functions are provided such as <b>easeInBack</b>.
They can also be retrieved as a collection of all easing functions by importing <b>easings</b>.
</p>
<p>
You can pass your own easing function.
It should have a single numeric parameter that accepts a value between 0 and 1 and returns a value around 0 and 1.
It is acceptable that a value might be slightly outside this range during animation, but is should always start at 0 and end at 1.
</p>
<div class="flex flex-col gap-6">
<app-demo-host name="Simple Value Changes"
pattern="tween-signal/(simple-demo|shared)"
hiddenPattern="easing-selector"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { ContentsClassDirective } from '../controls/contents-class.directive';
template: `
<app-home-box fnName="reduceSignal">
<div>
Creates a signal similar to <code class="inline p-1">Array.reduce</code> or Rxjs's <code class="inline p-1">scan</code> operator,
Creates a signal similar to <code class="inline">Array.reduce</code> or Rxjs's <code class="inline">scan</code> operator,
using a reducer function to create a new value from the current and prior values.
</div>
<div class="divider">Example</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { HomeBoxComponent } from '../controls/home-box.component';
template: `
<app-home-box fnName="signalToIterator">
<div>
This converts a signal into an AsyncIterator where is can be used in a <code class="inline p-1">for async</code> loop.
This converts a signal into an AsyncIterator where is can be used in a <code class="inline">for async</code> loop.
</div>
<div class="divider">Example</div>
<app-example-code><pre>
Expand Down
Loading

0 comments on commit a826c56

Please sign in to comment.