[docs] adds jsdoc for most functions in runtime API

pull/7235/head
ehsan 5 years ago
parent eb6fb66f19
commit d0e716a802

@ -237,12 +237,43 @@ if (typeof HTMLElement === 'function') {
export class SvelteComponent {
$$: T$$;
$$set?: ($$props: any) => void;
/**
*
* ```ts
* component.$destroy()
* ```
*
* Removes a component from the DOM and triggers any `onDestroy` handlers.
*
*/
$destroy() {
destroy_component(this, 1);
this.$destroy = noop;
}
/**
*
* ```ts
* component.$on(event, callback)
* ```
*
* ---
*
* Causes the `callback` function to be called whenever the component dispatches an `event`.
*
* A function is returned that will remove the event listener when called.
*
* ```ts
* const off = app.$on('selected', event => {
* console.log(event.detail.selection);
* });
*
* off();
* ```
*
* @param type
* @param callback
* @returns a function that will remove the event listener when called.
*/
$on(type, callback) {
const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));
callbacks.push(callback);
@ -252,7 +283,23 @@ export class SvelteComponent {
if (index !== -1) callbacks.splice(index, 1);
};
}
/**
* *
* ```ts
* component.$set(props)
* ```
*
* ---
*
* Programmatically sets props on an instance. `component.$set({ x: 1 })` is equivalent to `x = 1` inside the component's `<script>` block.
*
* Calling this method schedules an update for the next microtask the DOM is *not* updated synchronously.
*
* ```ts
* component.$set({ answer: 42 });
* ```
*
*/
$set($$props) {
if (this.$$set && !is_empty($$props)) {
this.$$.skip_bound = true;

@ -10,23 +10,174 @@ export function get_current_component() {
if (!current_component) throw new Error('Function called outside component initialization');
return current_component;
}
/**
* ```ts
* beforeUpdate(callback: () => void)
* ```
*
* ---
*
* Schedules a callback to run immediately before the component is updated after any state change.
*
* > The first time the callback runs will be before the initial `onMount`
*
* ```html
* <script>
* import { beforeUpdate } from 'svelte';
*
* beforeUpdate(() => {
* console.log('the component is about to update');
* });
* </script>
* ```
*
* @param fn callback
*/
export function beforeUpdate(fn: () => any) {
get_current_component().$$.before_update.push(fn);
}
export function onMount(fn: () => any) {
/**
*
* ```ts
* onMount(callback: () => void)
* ```
* ```ts
* onMount(callback: () => () => void)
* ```
*
* ---
*
* The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM. It must be called during the component's initialisation (but doesn't need to live *inside* the component; it can be called from an external module).
*
* `onMount` does not run inside a [server-side component](https://svelte.dev/docs#run-time-server-side-component-api).
*
* ```html
* <script>
* import { onMount } from 'svelte';
*
* onMount(() => {
* console.log('the component has mounted');
* });
* </script>
* ```
*
* ---
*
* If a function is returned from `onMount`, it will be called when the component is unmounted.
*
* ```html
* <script>
* import { onMount } from 'svelte';
*
* onMount(() => {
* const interval = setInterval(() => {
* console.log('beep');
* }, 1000);
*
* return () => clearInterval(interval);
* });
* </script>
* ```
*
* > This behaviour will only work when the function passed to `onMount` *synchronously* returns a value. `async` functions always return a `Promise`, and as such cannot *synchronously* return a function.
*
* @param fn callback function
*/
export function onMount(fn: () => any | (() => any)) {
get_current_component().$$.on_mount.push(fn);
}
/**
*
* ```ts
* afterUpdate(callback: () => void)
* ```
*
* ---
*
* Schedules a callback to run immediately after the component has been updated.
*
* > The first time the callback runs will be after the initial `onMount`
*
* ```html
* <script>
* import { afterUpdate } from 'svelte';
*
* afterUpdate(() => {
* console.log('the component just updated');
* });
* </script>
* ```
*
* @param fn callback function
*/
export function afterUpdate(fn: () => any) {
get_current_component().$$.after_update.push(fn);
}
/**
*
* ```ts
* onDestroy(callback: () => void)
* ```
*
* ---
*
* Schedules a callback to run immediately before the component is unmounted.
*
* Out of `onMount`, `beforeUpdate`, `afterUpdate` and `onDestroy`, this is the only one that runs inside a server-side component.
*
* ```html
* <script>
* import { onDestroy } from 'svelte';
*
* onDestroy(() => {
* console.log('the component is being destroyed');
* });
* </script>
* ```
*
* @param fn callback function
*/
export function onDestroy(fn: () => any) {
get_current_component().$$.on_destroy.push(fn);
}
/**
*
* ```ts
* dispatch: ((name: string, detail?: any) => void) = createEventDispatcher();
* ```
*
* ---
*
* Creates an event dispatcher that can be used to dispatch [component events](https://svelte.dev/docs#template-syntax-component-directives-on-eventname). Event dispatchers are functions that can take two arguments: `name` and `detail`.
*
* Component events created with `createEventDispatcher` create a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture) and are not cancellable with `event.preventDefault()`. The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) property and can contain any type of data.
*
* ```html
* <script>
* import { createEventDispatcher } from 'svelte';
*
* const dispatch = createEventDispatcher();
* </script>
*
* <button on:click="{() => dispatch('notify', 'detail value')}">Fire Event</button>
* ```
*
* ---
*
* Events dispatched from child components can be listened to in their parent. Any data provided when the event was dispatched is available on the `detail` property of the event object.
*
* ```html
* <script>
* function callbackFunction(event) {
* console.log(`Notify fired! Detail: ${event.detail}`)
* }
* </script>
*
* <Child on:notify="{callbackFunction}"/>
* ```
*
* @returns event dispatcher
*/
export function createEventDispatcher<
EventMap extends {} = any
>(): <EventKey extends Extract<keyof EventMap, string>>(type: EventKey, detail?: EventMap[EventKey]) => void {
@ -45,20 +196,105 @@ export function createEventDispatcher<
}
};
}
export function setContext<T>(key, context: T) {
/**
*
* ```ts
* setContext(key: any, context: any)
* ```
*
* ---
*
* Associates an arbitrary `context` object with the current component and the specified `key`. The context is then available to children of the component (including slotted content) with `getContext`.
*
* Like lifecycle functions, this must be called during component initialisation.
*
* ```html
* <script>
* import { setContext } from 'svelte';
*
* setContext('answer', 42);
* </script>
* ```
*
* > Context is not inherently reactive. If you need reactive values in context then you can pass a store into context, which *will* be reactive.
*
* @param key context key (Symbols are recommended)
* @param context context value
*/
export function setContext<T>(key: any, context: T) {
get_current_component().$$.context.set(key, context);
}
export function getContext<T>(key): T {
/**
*
* ```ts
* context: any = getContext(key: any)
* ```
*
* ---
*
* Retrieves the context that belongs to the closest parent component with the specified `key`. Must be called during component initialisation.
*
* ```html
* <script>
* import { getContext } from 'svelte';
*
* const answer = getContext('answer');
* </script>
* ```
*
* @param key context key (Symbols are recommended)
* @returns context value
*/
export function getContext<T>(key: any): T {
return get_current_component().$$.context.get(key);
}
/**
*
* ```ts
* contexts: Map<any, any> = getAllContexts()
* ```
*
* ---
*
* Retrieves the whole context map that belongs to the closest parent component. Must be called during component initialisation. Useful, for example, if you programmatically create a component and want to pass the existing context to it.
*
* ```html
* <script>
* import { getAllContexts } from 'svelte';
*
* const contexts = getAllContexts();
* </script>
* ```
*
* @returns whole context map that belongs to the closest parent component
*/
export function getAllContexts<T extends Map<any, any> = Map<any, any>>(): T {
return get_current_component().$$.context;
}
export function hasContext(key): boolean {
/**
*
* ```ts
* hasContext: boolean = hasContext(key: any)
* ```
*
* ---
*
* Checks whether a given `key` has been set in the context of a parent component. Must be called during component initialisation.
*
* ```html
* <script>
* import { hasContext } from 'svelte';
*
* if (hasContext('answer')) {
* // do something
* }
* </script>
* ```
*
* @param key context key (Symbols are recommended)
* @returns boolean indicates whether the context has been set
*/
export function hasContext(key:any): boolean {
return get_current_component().$$.context.has(key);
}

@ -17,7 +17,30 @@ export function schedule_update() {
resolved_promise.then(flush);
}
}
/**
*
* ```ts
* promise: Promise = tick()
* ```
*
* ---
*
* Returns a promise that resolves once any pending state changes have been applied, or in the next microtask if there are none.
*
* ```html
* <script>
* import { beforeUpdate, tick } from 'svelte';
*
* beforeUpdate(async () => {
* console.log('the component is about to update');
* await tick();
* console.log('the component just updated');
* });
* </script>
* ```
*
* @returns a promise that resolves once any pending state changes have been applied, or in the next microtask if there are none
*/
export function tick() {
schedule_update();
return resolved_promise;

@ -71,7 +71,28 @@ export function subscribe(store, ...callbacks) {
const unsub = store.subscribe(...callbacks);
return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub;
}
/**
*
* ```ts
* value: any = get(store)
* ```
*
* ---
*
* Generally, you should read the value of a store by subscribing to it and using the value as it changes over time. Occasionally, you may need to retrieve the value of a store to which you're not subscribed. `get` allows you to do so.
*
* > This works by creating a subscription, reading the value, then unsubscribing. It's therefore not recommended in hot code paths.
*
* ```ts
* import { get } from 'svelte/store';
*
* const value = get(store);
* ```
*
*
* @param store
* @returns
*/
export function get_store_value<T>(store: Readable<T>): T {
let value;
subscribe(store, _ => value = _)();

@ -45,50 +45,101 @@ function tick_spring<T>(ctx: TickContext<T>, last_value: T, current_value: T, ta
}
}
interface SpringOpts {
export interface SpringOptions {
/**(`number`, default `0.15`) — a value between 0 and 1 where higher means a 'tighter' spring */
stiffness?: number;
/**(`number`, default `0.8`) — a value between 0 and 1 where lower means a 'springier' spring */
damping?: number;
/**(`number`, default `0.01`) — determines the threshold at which the spring is considered to have 'settled', where lower means more precise */
precision?: number;
}
interface SpringUpdateOpts {
export interface SpringUpdateOptions {
/**`{ hard: true }` sets the target value immediately */
hard?: any;
/** `{ soft: n }` preserves existing momentum for `n` seconds before settling. `{ soft: true }` is equivalent to `{ soft: 0.5 }` */
soft?: string | number | boolean;
}
type Updater<T> = (target_value: T, value: T) => T;
export type SpringUpdater<T> = (target_value: T, value: T) => T;
export interface Spring<T> extends Readable<T>{
set: (new_value: T, opts?: SpringUpdateOpts) => Promise<void>;
update: (fn: Updater<T>, opts?: SpringUpdateOpts) => Promise<void>;
precision: number;
damping: number;
set: (new_value: T, opts?: SpringUpdateOptions) => Promise<void>;
update: (fn: SpringUpdater<T>, opts?: SpringUpdateOptions) => Promise<void>;
/**(`number`, default `0.15`) — a value between 0 and 1 where higher means a 'tighter' spring */
stiffness: number;
/**(`number`, default `0.8`) — a value between 0 and 1 where lower means a 'springier' spring */
damping: number;
/**(`number`, default `0.01`) — determines the threshold at which the spring is considered to have 'settled', where lower means more precise */
precision: number;
}
export function spring<T=any>(value?: T, opts: SpringOpts = {}): Spring<T> {
const store = writable(value);
/**
*
* ```ts
* store = spring(value: any, options)
* ```
*
* A `spring` store gradually changes to its target value based on its `stiffness` and `damping` parameters. Whereas `tweened` stores change their values over a fixed duration, `spring` stores change over a duration that is determined by their existing velocity, allowing for more natural-seeming motion in many situations. The following options are available:
*
* * `stiffness` (`number`, default `0.15`) a value between 0 and 1 where higher means a 'tighter' spring
* * `damping` (`number`, default `0.8`) a value between 0 and 1 where lower means a 'springier' spring
* * `precision` (`number`, default `0.01`) determines the threshold at which the spring is considered to have 'settled', where lower means more precise
*
* ---
*
* As with [`tweened`](https://svelte.dev/docs#run-time-svelte-motion-tweened) stores, `set` and `update` return a Promise that resolves if the spring settles. The `store.stiffness` and `store.damping` properties can be changed while the spring is in motion, and will take immediate effect.
*
* Both `set` and `update` can take a second argument an object with `hard` or `soft` properties. `{ hard: true }` sets the target value immediately; `{ soft: n }` preserves existing momentum for `n` seconds before settling. `{ soft: true }` is equivalent to `{ soft: 0.5 }`.
*
* [See a full example on the spring tutorial.](https://svelte.dev/tutorial/spring)
*
* ```html
* <script>
* import { spring } from 'svelte/motion';
*
* const coords = spring({ x: 50, y: 50 }, {
* stiffness: 0.1,
* damping: 0.25
* });
* </script>
* ```
*
* ---
*
* If the initial value is `undefined` or `null`, the first value change will take effect immediately, just as with `tweened` values (see above).
*
* ```ts
* const size = spring();
* $: $size = big ? 100 : 10;
* ```
*
* @param initialValue
* @param opts
* @returns spring store
*/
export function spring<T=any>(initialValue?: T, opts: SpringOptions = {}): Spring<T> {
const store = writable(initialValue);
const { stiffness = 0.15, damping = 0.8, precision = 0.01 } = opts;
let last_time: number;
let task: Task;
let current_token: object;
let last_value: T = value;
let target_value: T = value;
let last_value: T = initialValue;
let target_value: T = initialValue;
let inv_mass = 1;
let inv_mass_recovery_rate = 0;
let cancel_task = false;
function set(new_value: T, opts: SpringUpdateOpts = {}): Promise<void> {
function set(new_value: T, opts: SpringUpdateOptions = {}): Promise<void> {
target_value = new_value;
const token = current_token = {};
if (value == null || opts.hard || (spring.stiffness >= 1 && spring.damping >= 1)) {
if (initialValue == null || opts.hard || (spring.stiffness >= 1 && spring.damping >= 1)) {
cancel_task = true; // cancel any running animation
last_time = now();
last_value = new_value;
store.set(value = target_value);
store.set(initialValue = target_value);
return Promise.resolve();
} else if (opts.soft) {
const rate = opts.soft === true ? .5 : +opts.soft;
@ -116,11 +167,11 @@ export function spring<T=any>(value?: T, opts: SpringOpts = {}): Spring<T> {
settled: true, // tick_spring may signal false
dt: (now - last_time) * 60 / 1000
};
const next_value = tick_spring(ctx, last_value, value, target_value);
const next_value = tick_spring(ctx, last_value, initialValue, target_value);
last_time = now;
last_value = value;
store.set(value = next_value);
last_value = initialValue;
store.set(initialValue = next_value);
if (ctx.settled) {
task = null;
@ -138,7 +189,7 @@ export function spring<T=any>(value?: T, opts: SpringOpts = {}): Spring<T> {
const spring: Spring<T> = {
set,
update: (fn, opts: SpringUpdateOpts) => set(fn(target_value, value), opts),
update: (fn, opts: SpringUpdateOptions) => set(fn(target_value, initialValue), opts),
subscribe: store.subscribe,
stiffness,
damping,

@ -54,30 +54,127 @@ function get_interpolator(a, b) {
throw new Error(`Cannot interpolate ${type} values`);
}
interface Options<T> {
export interface TweenedOptions<T> {
/**(`number`, default 0) — milliseconds before starting */
delay?: number;
/** (`number` | `function`, default 400) — milliseconds the tween lasts*/
duration?: number | ((from: T, to: T) => number);
/** (`function`, default `t => t`) — an [easing function](https://svelte.dev/docs#run-time-svelte-easing) */
easing?: (t: number) => number;
/**
* (`function`) it allows you to tween between *any* arbitrary values. It must be an `(a, b) => t => value` function, where `a` is the starting value, `b` is the target value, `t` is a number between 0 and 1, and `value` is the result. For example, we can use the [d3-interpolate](https://github.com/d3/d3-interpolate) package to smoothly interpolate between two colours
*/
interpolate?: (a: T, b: T) => (t: number) => T;
}
type Updater<T> = (target_value: T, value: T) => T;
export type TweenedUpdater<T> = (target_value: T, value: T) => T;
export interface Tweened<T> extends Readable<T> {
set(value: T, opts?: Options<T>): Promise<void>;
update(updater: Updater<T>, opts?: Options<T>): Promise<void>;
}
export function tweened<T>(value?: T, defaults: Options<T> = {}): Tweened<T> {
const store = writable(value);
set(value: T, opts?: TweenedOptions<T>): Promise<void>;
update(updater: TweenedUpdater<T>, opts?: TweenedOptions<T>): Promise<void>;
}
/**
*
* ```ts
* store = tweened(value: any, options)
* ```
*
* Tweened stores update their values over a fixed duration. The following options are available:
*
* * `delay` (`number`, default 0) milliseconds before starting
* * `duration` (`number` | `function`, default 400) milliseconds the tween lasts
* * `easing` (`function`, default `t => t`) an [easing function](https://svelte.dev/docs#run-time-svelte-easing)
* * `interpolate` (`function`) see below
*
* `store.set` and `store.update` can accept a second `options` argument that will override the options passed in upon instantiation.
*
* Both functions return a Promise that resolves when the tween completes. If the tween is interrupted, the promise will never resolve.
*
* ---
*
* Out of the box, Svelte will interpolate between two numbers, two arrays or two objects (as long as the arrays and objects are the same 'shape', and their 'leaf' properties are also numbers).
*
* ```html
* <script>
* import { tweened } from 'svelte/motion';
* import { cubicOut } from 'svelte/easing';
*
* const size = tweened(1, {
* duration: 300,
* easing: cubicOut
* });
*
* function handleClick() {
* // this is equivalent to size.update(n => n + 1)
* $size += 1;
* }
* </script>
*
* <button
* on:click={handleClick}
* style="transform: scale({$size}); transform-origin: 0 0"
* >embiggen</button>
* ```
*
* ---
*
* If the initial value is `undefined` or `null`, the first value change will take effect immediately. This is useful when you have tweened values that are based on props, and don't want any motion when the component first renders.
*
* ```ts
* const size = tweened(undefined, {
* duration: 300,
* easing: cubicOut
* });
*
* $: $size = big ? 100 : 10;
* ```
*
* ---
*
* The `interpolate` option allows you to tween between *any* arbitrary values. It must be an `(a, b) => t => value` function, where `a` is the starting value, `b` is the target value, `t` is a number between 0 and 1, and `value` is the result. For example, we can use the [d3-interpolate](https://github.com/d3/d3-interpolate) package to smoothly interpolate between two colours.
*
* ```html
* <script>
* import { interpolateLab } from 'd3-interpolate';
* import { tweened } from 'svelte/motion';
*
* const colors = [
* 'rgb(255, 62, 0)',
* 'rgb(64, 179, 255)',
* 'rgb(103, 103, 120)'
* ];
*
* const color = tweened(colors[0], {
* duration: 800,
* interpolate: interpolateLab
* });
* </script>
*
* {#each colors as c}
* <button
* style="background-color: {c}; color: white; border: none;"
* on:click="{e => color.set(c)}"
* >{c}</button>
* {/each}
*
* <h1 style="color: {$color}">{$color}</h1>
* ```
*
* @param initialValue
* @param defaults
* @returns tweened store
*/
export function tweened<T>(initialValue?: T, defaults: TweenedOptions<T> = {}): Tweened<T> {
const store = writable(initialValue);
let task: Task;
let target_value = value;
let target_value = initialValue;
function set(new_value: T, opts?: Options<T>) {
if (value == null) {
store.set(value = new_value);
function set(new_value: T, opts?: TweenedOptions<T>) {
if (initialValue == null) {
store.set(initialValue = new_value);
return Promise.resolve();
}
@ -99,7 +196,7 @@ export function tweened<T>(value?: T, defaults: Options<T> = {}): Tweened<T> {
previous_task = null;
}
store.set(value = target_value);
store.set(initialValue = target_value);
return Promise.resolve();
}
@ -110,8 +207,8 @@ export function tweened<T>(value?: T, defaults: Options<T> = {}): Tweened<T> {
if (now < start) return true;
if (!started) {
fn = interpolate(value, new_value);
if (typeof duration === 'function') duration = duration(value, new_value);
fn = interpolate(initialValue, new_value);
if (typeof duration === 'function') duration = duration(initialValue, new_value);
started = true;
}
@ -123,12 +220,12 @@ export function tweened<T>(value?: T, defaults: Options<T> = {}): Tweened<T> {
const elapsed = now - start;
if (elapsed > duration) {
store.set(value = new_value);
store.set(initialValue = new_value);
return false;
}
// @ts-ignore
store.set(value = fn(easing(elapsed / duration)));
store.set(initialValue = fn(easing(elapsed / duration)));
return true;
});
@ -137,7 +234,7 @@ export function tweened<T>(value?: T, defaults: Options<T> = {}): Tweened<T> {
return {
set,
update: (fn, opts?: Options<T>) => set(fn(target_value, value), opts),
update: (fn, opts?: TweenedOptions<T>) => set(fn(target_value, initialValue), opts),
subscribe: store.subscribe
};
}

@ -46,33 +46,109 @@ type SubscribeInvalidateTuple<T> = [Subscriber<T>, Invalidator<T>];
const subscriber_queue = [];
/**
* Creates a `Readable` store that allows reading by subscription.
* @param value initial value
* @param {StartStopNotifier}start start and stop notifications for subscriptions
*
* ```ts
* store = readable(value?: any, start?: (set: (value: any) => void) => () => void)
* ```
*
* ---
*
* Creates a store whose value cannot be set from 'outside', the first argument is the store's initial value, and the second argument to `readable` is the same as the second argument to `writable`.
*
* ```ts
* import { readable } from 'svelte/store';
*
* const time = readable(null, set => {
* set(new Date());
*
* const interval = setInterval(() => {
* set(new Date());
* }, 1000);
*
* return () => clearInterval(interval);
* });
* ```
*
* @param initialValue
* @param start
* @returns
*/
export function readable<T>(value?: T, start?: StartStopNotifier<T>): Readable<T> {
export function readable<T>(initialValue?: T, start?: StartStopNotifier<T>): Readable<T> {
return {
subscribe: writable(value, start).subscribe
subscribe: writable(initialValue, start).subscribe
};
}
/**
* Create a `Writable` store that allows both updating and reading by subscription.
* @param {*=}value initial value
* @param {StartStopNotifier=}start start and stop notifications for subscriptions
*
* ```ts
* store = writable(initial_value?: any)
* ```
* ```ts
* store = writable(initial_value?: any, start?: (set: (value: any) => void) => () => void)
* ```
*
* ---
*
* Function that creates a store which has values that can be set from 'outside' components. It gets created as an object with additional `set` and `update` methods.
*
* `set` is a method that takes one argument which is the value to be set. The store value gets set to the value of the argument if the store value is not already equal to it.
*
* `update` is a method that takes one argument which is a callback. The callback takes the existing store value as its argument and returns the new value to be set to the store.
*
* ```ts
* import { writable } from 'svelte/store';
*
* const count = writable(0);
*
* count.subscribe(value => {
* console.log(value);
* }); // logs '0'
*
* count.set(1); // logs '1'
*
* count.update(n => n + 1); // logs '2'
* ```
*
* ---
*
* If a function is passed as the second argument, it will be called when the number of subscribers goes from zero to one (but not from one to two, etc). That function will be passed a `set` function which changes the value of the store. It must return a `stop` function that is called when the subscriber count goes from one to zero.
*
* ```ts
* import { writable } from 'svelte/store';
*
* const count = writable(0, () => {
* console.log('got a subscriber');
* return () => console.log('no more subscribers');
* });
*
* count.set(1); // does nothing
*
* const unsubscribe = count.subscribe(value => {
* console.log(value);
* }); // logs 'got a subscriber', then '1'
*
* unsubscribe(); // logs 'no more subscribers'
* ```
*
* Note that the value of a `writable` is lost when it is destroyed, for example when the page is refreshed. However, you can write your own logic to sync the value to for example the `localStorage`.
*
* @param initial_value
* @param start
* @returns
*/
export function writable<T>(value?: T, start: StartStopNotifier<T> = noop): Writable<T> {
export function writable<T>(initialValue?: T, start: StartStopNotifier<T> = noop): Writable<T> {
let stop: Unsubscriber;
const subscribers: Set<SubscribeInvalidateTuple<T>> = new Set();
function set(new_value: T): void {
if (safe_not_equal(value, new_value)) {
value = new_value;
if (safe_not_equal(initialValue, new_value)) {
initialValue = new_value;
if (stop) { // store is ready
const run_queue = !subscriber_queue.length;
for (const subscriber of subscribers) {
subscriber[1]();
subscriber_queue.push(subscriber, value);
subscriber_queue.push(subscriber, initialValue);
}
if (run_queue) {
for (let i = 0; i < subscriber_queue.length; i += 2) {
@ -85,7 +161,7 @@ export function writable<T>(value?: T, start: StartStopNotifier<T> = noop): Writ
}
function update(fn: Updater<T>): void {
set(fn(value));
set(fn(initialValue));
}
function subscribe(run: Subscriber<T>, invalidate: Invalidator<T> = noop): Unsubscriber {
@ -94,7 +170,7 @@ export function writable<T>(value?: T, start: StartStopNotifier<T> = noop): Writ
if (subscribers.size === 1) {
stop = start(set) || noop;
}
run(value);
run(initialValue);
return () => {
subscribers.delete(subscriber);
@ -116,12 +192,84 @@ type StoresValues<T> = T extends Readable<infer U> ? U :
{ [K in keyof T]: T[K] extends Readable<infer U> ? U : never };
/**
* Derived value store by synchronizing one or more readable stores and
* applying an aggregation function over its input values.
*
* @param stores - input stores
* @param fn - function callback that aggregates the values
* @param initial_value - when used asynchronously
* ```ts
* store = derived(a, callback: (a: any) => any)
* ```
* ---
* ```ts
* store = derived(a, callback: (a: any, set: (value: any) => void) => void | () => void, initial_value: any)
* ```
* ---
* ```ts
* store = derived([a, ...b], callback: ([a: any, ...b: any[]]) => any)
* ```
* ---
* ```ts
* store = derived([a, ...b], callback: ([a: any, ...b: any[]], set: (value: any) => void) => void | () => void, initial_value: any)
* ```
*
* ---
*
* Derives a store from one or more other stores. The callback runs initially when the first subscriber subscribes and then whenever the store dependencies change.
*
* In the simplest version, `derived` takes a single store, and the callback returns a derived value.
*
* ```ts
* import { derived } from 'svelte/store';
*
* const doubled = derived(a, $a => $a * 2);
* ```
*
* ---
*
* The callback can set a value asynchronously by accepting a second argument, `set`, and calling it when appropriate.
*
* In this case, you can also pass a third argument to `derived` the initial value of the derived store before `set` is first called.
*
* ```ts
* import { derived } from 'svelte/store';
*
* const delayed = derived(a, ($a, set) => {
* setTimeout(() => set($a), 1000);
* }, 'one moment...');
* ```
*
* ---
*
* If you return a function from the callback, it will be called when a) the callback runs again, or b) the last subscriber unsubscribes.
*
* ```ts
* import { derived } from 'svelte/store';
*
* const tick = derived(frequency, ($frequency, set) => {
* const interval = setInterval(() => {
* set(Date.now());
* }, 1000 / $frequency);
*
* return () => {
* clearInterval(interval);
* };
* }, 'one moment...');
* ```
*
* ---
*
* In both cases, an array of arguments can be passed as the first argument instead of a single store.
*
* ```ts
* import { derived } from 'svelte/store';
*
* const summed = derived([a, b], ([$a, $b]) => $a + $b);
*
* const delayed = derived([a, b], ([$a, $b], set) => {
* setTimeout(() => set($a + $b), 1000);
* });
* ```
*
* @param stores
* @param fn
* @param initial_value
*/
export function derived<S extends Stores, T>(
stores: S,

@ -1,6 +1,27 @@
import { cubicOut, cubicInOut, linear } from 'svelte/easing';
import { assign, is_function } from 'svelte/internal';
/**
*
* Easing functions specify the rate of change over time and are useful when working with Svelte's built-in transitions and animations as well as the tweened and spring utilities. `svelte/easing` contains 31 named exports, a `linear` ease and 3 variants of 10 different easing functions: `in`, `out` and `inOut`.
*
* You can explore the various eases using the [ease visualiser](https://svelte.dev/examples/easing) in the [examples section](https://svelte.dev/examples).
*
*
* | ease | in | out | inOut |
* | --- | --- | --- | --- |
* | **back** | `backIn` | `backOut` | `backInOut` |
* | **bounce** | `bounceIn` | `bounceOut` | `bounceInOut` |
* | **circ** | `circIn` | `circOut` | `circInOut` |
* | **cubic** | `cubicIn` | `cubicOut` | `cubicInOut` |
* | **elastic** | `elasticIn` | `elasticOut` | `elasticInOut` |
* | **expo** | `expoIn` | `expoOut` | `expoInOut` |
* | **quad** | `quadIn` | `quadOut` | `quadInOut` |
* | **quart** | `quartIn` | `quartOut` | `quartInOut` |
* | **quint** | `quintIn` | `quintOut` | `quintInOut` |
* | **sine** | `sineIn` | `sineOut` | `sineInOut` |
*
*
*/
export type EasingFunction = (t: number) => number;
export interface TransitionConfig {
@ -12,13 +33,57 @@ export interface TransitionConfig {
}
export interface BlurParams {
/** (`number`, default 0) — milliseconds before starting */
delay?: number;
/** (`number`, default 400) — milliseconds the transition lasts */
duration?: number;
/** (`function`, default `cubicInOut`) — an [easing function](https://svelte.dev/docs#run-time-svelte-easing) */
easing?: EasingFunction;
/** (`number`, default 5) - the size of the blur in pixels */
amount?: number;
/** (`number`, default 0) - the opacity value to animate out to and in from */
opacity?: number;
}
/**
*
* ```html
* transition:blur={params}
* ```
* ```html
* in:blur={params}
* ```
* ```html
* out:blur={params}
* ```
*
* ---
*
* Animates a `blur` filter alongside an element's opacity.
*
* `blur` accepts the following parameters:
*
* * `delay` (`number`, default 0) milliseconds before starting
* * `duration` (`number`, default 400) milliseconds the transition lasts
* * `easing` (`function`, default `cubicInOut`) an [easing function](https://svelte.dev/docs#run-time-svelte-easing)
* * `opacity` (`number`, default 0) - the opacity value to animate out to and in from
* * `amount` (`number`, default 5) - the size of the blur in pixels
*
* ```html
* <script>
* import { blur } from 'svelte/transition';
* </script>
*
* {#if condition}
* <div transition:blur="{{amount: 10}}">
* fades in and out
* </div>
* {/if}
* ```
*
* @param node
* @param options
* @returns transition config
*/
export function blur(node: Element, {
delay = 0,
duration = 400,
@ -41,11 +106,52 @@ export function blur(node: Element, {
}
export interface FadeParams {
/** (`number`, default 0) — milliseconds before starting */
delay?: number;
/** (`number`, default 400) — milliseconds the transition lasts */
duration?: number;
/** (`function`, default `linear`) — an [easing function](https://svelte.dev/docs#run-time-svelte-easing) */
easing?: EasingFunction;
}
/**
*
* ```html
* transition:fade={params}
* ```
* ```html
* in:fade={params}
* ```
* ```html
* out:fade={params}
* ```
*
* ---
*
* Animates the opacity of an element from 0 to the current opacity for `in` transitions and from the current opacity to 0 for `out` transitions.
*
* `fade` accepts the following parameters:
*
* * `delay` (`number`, default 0) milliseconds before starting
* * `duration` (`number`, default 400) milliseconds the transition lasts
* * `easing` (`function`, default `linear`) an [easing function](https://svelte.dev/docs#run-time-svelte-easing)
*
* You can see the `fade` transition in action in the [transition tutorial](https://svelte.dev/tutorial/transition).
*
* ```html
* <script>
* import { fade } from 'svelte/transition';
* </script>
*
* {#if condition}
* <div transition:fade="{{delay: 250, duration: 300}}">
* fades in and out
* </div>
* {/if}
* ```
* @param node
* @param param1
* @returns
*/
export function fade(node: Element, {
delay = 0,
duration = 400,
@ -62,14 +168,63 @@ export function fade(node: Element, {
}
export interface FlyParams {
/** (`number`, default 0) — milliseconds before starting */
delay?: number;
/** (`number`, default 400) — milliseconds the transition lasts */
duration?: number;
/** (`function`, default `cubicOut`) — an [easing function](https://svelte.dev/docs#run-time-svelte-easing) */
easing?: EasingFunction;
/** (`number`, default 0) - the x offset to animate out to and in from */
x?: number;
/** (`number`, default 0) - the y offset to animate out to and in from */
y?: number;
/** (`number`, default 0) - the opacity value to animate out to and in from */
opacity?: number;
}
/**
*
* ```html
* transition:fly={params}
* ```
* ```html
* in:fly={params}
* ```
* ```html
* out:fly={params}
* ```
*
* ---
*
* Animates the x and y positions and the opacity of an element. `in` transitions animate from an element's current (default) values to the provided values, passed as parameters. `out` transitions animate from the provided values to an element's default values.
*
* `fly` accepts the following parameters:
*
* * `delay` (`number`, default 0) milliseconds before starting
* * `duration` (`number`, default 400) milliseconds the transition lasts
* * `easing` (`function`, default `cubicOut`) an [easing function](https://svelte.dev/docs#run-time-svelte-easing)
* * `x` (`number`, default 0) - the x offset to animate out to and in from
* * `y` (`number`, default 0) - the y offset to animate out to and in from
* * `opacity` (`number`, default 0) - the opacity value to animate out to and in from
*
* You can see the `fly` transition in action in the [transition tutorial](https://svelte.dev/tutorial/adding-parameters-to-transitions).
*
* ```html
* <script>
* import { fly } from 'svelte/transition';
* import { quintOut } from 'svelte/easing';
* </script>
*
* {#if condition}
* <div transition:fly="{{delay: 250, duration: 300, x: 100, y: 500, opacity: 0.5, easing: quintOut}}">
* flies in and out
* </div>
* {/if}
* ```
*
* @param node
* @param options
* @returns transition config
*/
export function fly(node: Element, {
delay = 0,
duration = 400,
@ -95,11 +250,52 @@ export function fly(node: Element, {
}
export interface SlideParams {
/** (`number`, default 0) — milliseconds before starting */
delay?: number;
/** (`number`, default 400) — milliseconds the transition lasts */
duration?: number;
/** (`function`, default `cubicOut`) — an [easing function](https://svelte.dev/docs#run-time-svelte-easing) */
easing?: EasingFunction;
}
/**
*
* ```html
* transition:slide={params}
* ```
* ```html
* in:slide={params}
* ```
* ```html
* out:slide={params}
* ```
*
* ---
*
* Slides an element in and out.
*
* `slide` accepts the following parameters:
*
* * `delay` (`number`, default 0) milliseconds before starting
* * `duration` (`number`, default 400) milliseconds the transition lasts
* * `easing` (`function`, default `cubicOut`) an [easing function](https://svelte.dev/docs#run-time-svelte-easing)
*
* ```html
* <script>
* import { slide } from 'svelte/transition';
* import { quintOut } from 'svelte/easing';
* </script>
*
* {#if condition}
* <div transition:slide="{{delay: 250, duration: 300, easing: quintOut }}">
* slides in and out
* </div>
* {/if}
* ```
*
* @param node
* @param options
* @returns transition config
*/
export function slide(node: Element, {
delay = 0,
duration = 400,
@ -133,13 +329,57 @@ export function slide(node: Element, {
}
export interface ScaleParams {
/** (`number`, default 0) — milliseconds before starting */
delay?: number;
/** (`number`, default 400) — milliseconds the transition lasts */
duration?: number;
/** (`function`, default `cubicOut`) — an [easing function](https://svelte.dev/docs#run-time-svelte-easing) */
easing?: EasingFunction;
/** (`number`, default 0) - the scale value to animate out to and in from */
start?: number;
/** (`number`, default 0) - the opacity value to animate out to and in from */
opacity?: number;
}
/**
*
* ```html
* transition:scale={params}
* ```
* ```html
* in:scale={params}
* ```
* ```html
* out:scale={params}
* ```
*
* ---
*
* Animates the opacity and scale of an element. `in` transitions animate from an element's current (default) values to the provided values, passed as parameters. `out` transitions animate from the provided values to an element's default values.
*
* `scale` accepts the following parameters:
*
* * `delay` (`number`, default 0) milliseconds before starting
* * `duration` (`number`, default 400) milliseconds the transition lasts
* * `easing` (`function`, default `cubicOut`) an [easing function](https://svelte.dev/docs#run-time-svelte-easing)
* * `start` (`number`, default 0) - the scale value to animate out to and in from
* * `opacity` (`number`, default 0) - the opacity value to animate out to and in from
*
* ```html
* <script>
* import { scale } from 'svelte/transition';
* import { quintOut } from 'svelte/easing';
* </script>
*
* {#if condition}
* <div transition:scale="{{duration: 500, delay: 500, opacity: 0.5, start: 0.5, easing: quintOut}}">
* scales in and out
* </div>
* {/if}
* ```
* @param node
* @param options
* @returns transition config
*/
export function scale(node: Element, {
delay = 0,
duration = 400,
@ -166,12 +406,68 @@ export function scale(node: Element, {
}
export interface DrawParams {
/** (`number`, default 0) — milliseconds before starting */
delay?: number;
/** (`number`, default undefined) - the speed of the animation
*
* The `speed` parameter is a means of setting the duration of the transition relative to the path's length. It is a modifier that is applied to the length of the path: `duration = length / speed`. A path that is 1000 pixels with a speed of 1 will have a duration of `1000ms`, setting the speed to `0.5` will double that duration and setting it to `2` will halve it
*/
speed?: number;
/** (`number` | `function`, default 800) — milliseconds the transition lasts */
duration?: number | ((len: number) => number);
/** (`function`, default `cubicInOut`) — an [easing function](https://svelte.dev/docs#run-time-svelte-easing) */
easing?: EasingFunction;
}
/**
*
* ```html
* transition:draw={params}
* ```
* ```html
* in:draw={params}
* ```
* ```html
* out:draw={params}
* ```
*
* ---
*
* Animates the stroke of an SVG element, like a snake in a tube. `in` transitions begin with the path invisible and draw the path to the screen over time. `out` transitions start in a visible state and gradually erase the path. `draw` only works with elements that have a `getTotalLength` method, like `<path>` and `<polyline>`.
*
* `draw` accepts the following parameters:
*
* * `delay` (`number`, default 0) milliseconds before starting
* * `speed` (`number`, default undefined) - the speed of the animation, see below.
* * `duration` (`number` | `function`, default 800) milliseconds the transition lasts
* * `easing` (`function`, default `cubicInOut`) an [easing function](https://svelte.dev/docs#run-time-svelte-easing)
*
* The `speed` parameter is a means of setting the duration of the transition relative to the path's length. It is a modifier that is applied to the length of the path: `duration = length / speed`. A path that is 1000 pixels with a speed of 1 will have a duration of `1000ms`, setting the speed to `0.5` will double that duration and setting it to `2` will halve it.
*
* ```html
* <script>
* import { draw } from 'svelte/transition';
* import { quintOut } from 'svelte/easing';
* </script>
*
* <svg viewBox="0 0 5 5" xmlns="http://www.w3.org/2000/svg">
* {#if condition}
* <path transition:draw="{{duration: 5000, delay: 500, easing: quintOut}}"
* d="M2 1 h1 v1 h1 v1 h-1 v1 h-1 v-1 h-1 v-1 h1 z"
* fill="none"
* stroke="cornflowerblue"
* stroke-width="0.1px"
* stroke-linejoin="round"
* />
* {/if}
* </svg>
*
* ```
*
*
* @param node
* @param options
* @returns transition config
*/
export function draw(node: SVGElement & { getTotalLength(): number }, {
delay = 0,
speed,
@ -203,16 +499,53 @@ export function draw(node: SVGElement & { getTotalLength(): number }, {
}
export interface CrossfadeParams {
/** (`number`, default 0) — milliseconds before starting */
delay?: number;
/** (`number` | `function`, default 800) — milliseconds the transition lasts */
duration?: number | ((len: number) => number);
/** (`function`, default `cubicOut`) — an [easing function](https://svelte.dev/docs#run-time-svelte-easing) */
easing?: EasingFunction;
/** (`function`) — A fallback [transition](https://svelte.dev/docs#template-syntax-element-directives-transition-fn) to use for send when there is no matching element being received, and for receive when there is no element being sent. */
fallback?: (node: Element, params: CrossfadeParams, intro: boolean) => TransitionConfig;
}
type ClientRectMap = Map<any, { rect: ClientRect }>;
export function crossfade({ fallback, ...defaults }: CrossfadeParams & {
fallback?: (node: Element, params: CrossfadeParams, intro: boolean) => TransitionConfig;
}): [
/**
*
* The `crossfade` function creates a pair of [transitions](https://svelte.dev/docs#template-syntax-element-directives-transition-fn) called `send` and `receive`. When an element is 'sent', it looks for a corresponding element being 'received', and generates a transition that transforms the element to its counterpart's position and fades it out. When an element is 'received', the reverse happens. If there is no counterpart, the `fallback` transition is used.
*
* ---
*
* `crossfade` accepts the following parameters:
*
* * `delay` (`number`, default 0) milliseconds before starting
* * `duration` (`number` | `function`, default 800) milliseconds the transition lasts
* * `easing` (`function`, default `cubicOut`) an [easing function](https://svelte.dev/docs#run-time-svelte-easing)
* * `fallback` (`function`) A fallback [transition](https://svelte.dev/docs#template-syntax-element-directives-transition-fn) to use for send when there is no matching element being received, and for receive when there is no element being sent.
*
* ```html
* <script>
* import { crossfade } from 'svelte/transition';
* import { quintOut } from 'svelte/easing';
*
* const [send, receive] = crossfade({
* duration:1500,
* easing: quintOut
* });
* </script>
*
* {#if condition}
* <h1 in:send={{key}} out:receive={{key}}>BIG ELEM</h1>
* {:else}
* <small in:send={{key}} out:receive={{key}}>small elem</small>
* {/if}
* ```
*
*
* @param options
* @returns a pair of transitions
*/
export function crossfade({ fallback, ...defaults }: CrossfadeParams): [
(
node: Element,
params: CrossfadeParams & {

Loading…
Cancel
Save