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
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
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
Returns
(self) => Style
Call Signature
(self, that): Style;Parameters
self
that
Returns
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
held
readonly string[]
Returns
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
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
Returns
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
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
Returns
Values
Example
Style.valuesAt({ opacity: [0, 0.5, 1], x: 10 }, "first") // { x: 10, opacity: 0 }