Style

An element's style as a binding builds it: its starting style, what it's drawn with before any animation runs, from its initial (or its animate, with initial: false); how an app's own style and Wardic's are layered (over, without); and a drag element's default style. A server render draws the starting style, so an element is drawn where it starts before any code runs.

import * as Style from "@wardic/dom/Style"

const start = Style.resolveInitial({ initial: { opacity: 0, y: 8 }, animate: { opacity: 1, y: 0 } })
Style.starting(undefined, start) // { style: { transform: "translateY(8px)", opacity: 0 }, attrs: {} }

Interfaces

InitialConfig

What of an element's config its starting style is read from. Its values are typed object, so a binding's own value types fit as they are.

Properties

animate?
readonly animate?: string | object | readonly string[];

What initial: false starts at: a values map, the name of a variants entry, or a list of names.

initial?
readonly initial?: string | false | object | readonly string[];

Its start: values used as they are, the name of a variants entry, a list of names merged in order, a later one's winning, or false, to start at animate, as Motion's initial={false}.

variants?
readonly variants?: Readonly<Record<string, object | undefined>>;

Its variants: the values each name stands for.


SplitValues

A values map's own values and its keyframes: splitValues' result.

Properties

keyframes
readonly keyframes: Option<Readonly<Record<string, Stops>>>;

Its Keyframes, if it has any.

values
readonly values: Values;

Its numbers and strings, each Keyframes value at one of its stops.

Type Aliases

DragDefaults

type DragDefaults = Readonly<Record<string, string>>;

A drag element's default style for its axis.


Input

type Input = object | string | undefined;

A style as a binding hands it over: a record of CSS properties, CSS text ("color: red", which JSX allows), or none.


StopAt

type StopAt = "first" | "last";

Where a keyframes value is read: initial's at its first stop, a target's at its last.


Stops

type Stops = ReadonlyArray<number | string | null>;

A keyframes value's stops, as Motion's: each a value, or null, for where the key is (the first) or the stop before (a later one).


Style

type Style = Readonly<Record<string, unknown>>;

A style record: CSS properties to their values.

Variables

DRAG_DEFAULT_ATTRIBUTES

const DRAG_DEFAULT_ATTRIBUTES: Readonly<{
  draggable: "false";
}>;

The attribute every drag element gets: no native drag of the element or its content.


dragDefaults

const dragDefaults: (axis) => DragDefaults;

The default style of a drag element: touch-action none for a free drag, pan-y for an x drag and pan-x for a y drag, with no text selection or iOS callout. One frozen object per axis.

Parameters

axis

boolean | "x" | "y"

Returns

DragDefaults


heldTouches

const heldTouches: {
  (prev, next): (self) => boolean;
  (self, prev, next): boolean;
};

Whether the keys the flush gate holds, changing from prev to next, change self's without: whether a key taken or let go of is one self sets, by its name or its name dash-cased. Most changes touch none, and a binding then leaves its style alone.

Call Signature

(prev, next): (self) => boolean;
Parameters
prev

readonly string[]

next

readonly string[]

Returns

(self) => boolean

Call Signature

(
   self, 
   prev, 
   next
): boolean;
Parameters
self

Style

prev

readonly string[]

next

readonly string[]

Returns

boolean


over

const over: {
  (that): (self) => Style;
  (self, that): Style;
};

self laid over that: self's keys win, and that's others stay. A chain reads from the top layer down: an element's style is its drag defaults, under its base, under the app's, under what Wardic animates. A side given as CSS text is parsed, so a framework never writes cssText over the keys Wardic holds, and a side that's undefined leaves the other as it is, the same object. Whatever self sets for user-select or -webkit-user-select it sets for both: one property in Chromium.

Call Signature

(that): (self) => Style;
Parameters
that

Input

Returns

(self) => Style

Call Signature

(self, that): Style;
Parameters
self

Input

that

Input

Returns

Style

Example

// Before the first commit: the starting style over the app's, over a base and a drag element's defaults.
pipe(starting, Style.over(user), Style.over(base), Style.over(Style.dragDefaults("x")))

reorderTouchAction

const reorderTouchAction: (axis) => string;

A Reorder group item's touch-action for the group's axis: a y list keeps sideways panning, an x row vertical panning, and a grid none.

Parameters

axis

"x" | "y" | "xy"

Returns

string


without

const without: {
  (held): (self) => Style;
  (self, held): Style;
};

self without the keys the flush gate holds on the element (held, by patch key, matched by CSS property): the style once its first frame is committed. Wardic writes those while it drives them, and the app's style is their fallback, so a key the gate lets go of comes back.

Call Signature

(held): (self) => Style;
Parameters
held

readonly string[]

Returns

(self) => Style

Call Signature

(self, held): Style;
Parameters
self

Input

held

readonly string[]

Returns

Style

Example

pipe(user, Style.over(base), Style.without(held))

Functions

keyframesOf()

function keyframesOf(v): Option<Readonly<Record<string, Stops>>>;

A values map's keyframes values: each array of stops an animation can take, one with a stop that isn't null. None when it has none, so a target without any makes nothing.

Parameters

v

object | undefined

Returns

Option<Readonly<Record<string, Stops>>>

Example

Style.keyframesOf({ opacity: [0, 0.5, 1], x: 10 }) // { opacity: [0, 0.5, 1] }

resolveInitial()

function resolveInitial(config): Values;

The values an element starts from: its initial values, or the variants entries its initial names, an unknown name empty, or nothing. With initial: false, its animate, resolved the same way, so it starts at its target and nothing animates at mount, as Motion's. A keyframes value starts at its first stop, or, with initial: false, at animate's last, where the animation it skips would end. Read once, at setup: the starting style is where it starts, never a live target.

Parameters

config

InitialConfig

Returns

Values

Example

Style.resolveInitial({ initial: false, animate: { opacity: 1 } }) // { opacity: 1 }

splitValues()

function splitValues(v, at): SplitValues;

A values map's values, each keyframes value read at one of its stops, and its keyframes, in one pass over its keys: a target's resolution reads both, and a target with no keyframes makes nothing toValues doesn't.

Parameters

v

object | undefined

at

StopAt

Returns

SplitValues


starting()

function starting(tag, values): SplitPatch;

The starting style of a tag element starting from values: projected as the renderer projects a Frame, then split by tag, an SVG element's keys inside an <svg> as attributes, and the rest as style. undefined is an HTML element, as for a spread that doesn't know its tag.

Parameters

tag

string | undefined

values

Readonly<Record<string, unknown>>

Returns

SplitPatch


toValues()

function toValues(v): Values;

A values map with only the keys an animation can take: numbers and strings (custom properties included). undefined and anything else drop out, so the engine never sees them.

Parameters

v

object | undefined

Returns

Values


valuesAt()

function valuesAt(v, at): Values;

A values map with only the keys an animation can take, each keyframes value read at one of its stops: initial's first, a target's last. A keyframes value with no such stop drops out, as does an array keyframesOf doesn't take, and anything that isn't a number or a string. One pass over its keys, as toValues'.

Parameters

v

object | undefined

at

StopAt

Returns

Values

Example

Style.valuesAt({ opacity: [0, 0.5, 1], x: 10 }, "first") // { x: 10, opacity: 0 }