artboard-deluxe
Version:
Touch-friendly draggable artboard
1,501 lines (1,483 loc) • 62.4 kB
text/typescript
type Size = {
width: number;
height: number;
};
type Coord = {
x: number;
y: number;
};
/**
* Edges of a rectangle.
*/
type Edge = {
top: number;
right: number;
bottom: number;
left: number;
};
type Rectangle = Size & Coord;
type Boundaries = {
xMin: number;
xMax: number;
yMin: number;
yMax: number;
};
/**
* The 'origin', similar to how the CSS `transform-origin` property works:
* - horizontal: 'left' | 'center' | 'right'
* - vertical: 'top' | 'center' | 'bottom'
*/
type Origin = 'top-left' | 'center-left' | 'bottom-left' | 'top-center' | 'center-center' | 'bottom-center' | 'top-right' | 'center-right' | 'bottom-right';
declare function createOptions(initOptions?: ArtboardOptions): {
setAllOptions: (newOptions?: ArtboardOptions) => void;
set: <T extends keyof ArtboardOptions>(key: T, value: ArtboardOptions[T]) => void;
readonly hasBlockingRects: boolean;
readonly overscrollBounds: Edge;
readonly minScale: number;
readonly maxScale: number;
readonly scrollStepAmount: number;
readonly margin: number;
readonly momentumDeceleration: number;
readonly springDamping: number;
readonly direction: Direction;
readonly rootClientRectMaxStale: number;
readonly blockingRects: Rectangle[];
};
type Options = ReturnType<typeof createOptions>;
declare function easeOutQuad(x: number): number;
declare function easeOutBack(x: number): number;
declare function easeOutElastic(x: number): number;
declare function easeOutCirc(x: number): number;
declare function easeInOutExpo(x: number): number;
declare function easeOutCubic(x: number): number;
declare function easeInSine(x: number): number;
declare function easeInOutSine(x: number): number;
declare function easeInOutQuad(x: number): number;
declare function easeInOutQuart(x: number): number;
declare function easeInOutCirc(x: number): number;
declare function easeInOutQuint(x: number): number;
declare function linear(x: number): number;
type EasingFunction = (x: number) => number;
declare const EASINGS: {
readonly easeInOutExpo: typeof easeInOutExpo;
readonly easeOutCirc: typeof easeOutCirc;
readonly easeOutElastic: typeof easeOutElastic;
readonly easeOutQuad: typeof easeOutQuad;
readonly easeOutBack: typeof easeOutBack;
readonly easeOutCubic: typeof easeOutCubic;
readonly easeInSine: typeof easeInSine;
readonly easeInOutSine: typeof easeInOutSine;
readonly easeInOutQuad: typeof easeInOutQuad;
readonly easeInOutQuart: typeof easeInOutQuart;
readonly easeInOutCirc: typeof easeInOutCirc;
readonly easeInOutQuint: typeof easeInOutQuint;
readonly linear: typeof linear;
};
type AnimationEasing = keyof typeof EASINGS | EasingFunction;
type ArtboardAnimation = Coord & {
key: string;
/** The target scale for the animation. */
scale: number;
/** The offset X value when the animation started. */
startX: number;
/** The offset Y value when the animation started. */
startY: number;
/** The scale value when the animation started. */
startScale: number;
/** The easing method to use for the animation. */
easing: AnimationEasing;
/** The timestamp when the animation started. */
startTime: number;
/** The duration of the animation. */
duration: number;
};
type AnimationOptions = {
/**
* The easing function to use when animating.
*
* Can either be the name of one of the built in easing functions or a custom function.
* If a custom function is provided, it will receive the current progress (a value from 0 to 1) as the only argument and should return the eased progress.
*/
easing?: AnimationEasing;
/** The speed of the animation. */
duration?: number;
};
type PluginOptions<T> = T extends ArtboardPluginDefinition<infer O, any> ? O : never;
type PluginInstance<T> = T extends ArtboardPluginDefinition<infer O extends object, infer R extends object> ? ArtboardPluginInstance<O, R> : never;
type ObserverSizeChangeCallback<T extends Element> = (entry: ResizeObserverEntry & {
target: T;
}) => void;
type ObserverSizeChangeContext = {
unobserve: () => void;
};
/**
* Defines possible scroll directions.
*/
type Direction = 'horizontal' | 'vertical' | 'both' | 'none';
/**
* A possible return type for the getBlockingRects() method.
*
* You may either return an object compatible with `Rectangle` (such as the return value of `element.getBoundingClientRect()`) or an array of four numbers representing `[x, y, width, height]`.
*/
type PossibleBlockingRect = Rectangle | [number, number, number, number];
/**
* A fully initialised plugin instance.
*/
type ArtboardPluginInstance<O extends object = object, R extends object = object> = {
/**
* The options helper.
*/
options: ArtboardPluginOptions<O>;
/**
* Remove event listeners and clean up.
*/
destroy?: () => void;
/**
* Called in the main animation loop.
*
* Receives the state of the artboard at the time of the animation loop as an argument.
*/
loop?: (ctx: ArtboardLoopContext) => void;
} & R;
type ArtboardPluginOptions<T extends object> = {
/**
* Get an option value.
*/
get<K extends keyof T>(key: K): T[K];
/**
* Get a required option value. If the option is not set an error is thrown.
*/
getRequired<K extends keyof T>(key: K): T[K];
/**
* Get an option that is either a DOM element or a selector.
*
* Throws an error if no element could be found.
*/
getElement<K extends keyof T>(key: K, fallbackSelector: string, parent: HTMLElement): HTMLElement;
/**
* Returns the boolean representation of an option.
*/
should<K extends keyof T>(key: K, defaultValue?: T[K]): boolean;
/**
* Get an option value with a default value.
*/
get<K extends keyof T>(key: K, defaultValue: T[K]): NonNullable<T[K]>;
/**
* Set an option.
*/
set<K extends keyof T>(key: K, value: T[K]): void;
/**
* Set all options at once.
*/
setAll(newOptions: T): void;
/**
* Set multiple options at once.
*/
setMultiple(newOptions: Partial<T>): void;
/**
* Compute and cache a value based on the current options.
*
* If any option is changed (via set or setAll), the cache is cleared.
*/
computed<R>(callback: (options: T) => R): {
value: R;
};
};
type ArtboardPluginInit<O extends object, R extends object = object> = (artboard: Artboard, options: ArtboardPluginOptions<O>) => ArtboardPluginInstance<O, R>;
/**
* Defines a plugin definition.
*
* This is the return value when you create a plugin, e.g. using `mouse()`.
* The plugin definition can then be passed as the second argument in an array to `createArtboard` or by manually adding the plugin after the artboard has been initialised using `artboard.addPlugin()`.
*/
type ArtboardPluginDefinition<T extends object, R extends object> = {
/**
* The options instance.
*/
options: ArtboardPluginOptions<T>;
/**
* The method to initlise the plugin.
*
* @internal
*/
init: ArtboardPluginInit<T, R>;
};
/**
* Options for createArtboard().
*/
type ArtboardOptions = {
/**
* The initial offset.
*
* @example
* ```typescript
* {
* initTransform: {
* x: 500,
* y: 20,
* scale: 1
* }
* }
* ```
*/
initTransform?: Coord & {
scale: number;
};
/**
* How much of the artboard should remain visible when overscrolling.
*
* A value of 0 means the artboard can be dragged right to every edge of the
* root element. A value of e.g. 100 means that there is always at least 100px
* of the artboard visible. A negative value means the artboard can be dragged
* outside the root element.
*
* You can also provide an object with top, right, bottom and left properties
* to define individual values per edge.
*
* @example
* Initialise with same bounds on all edges.
* ```typescript
* {
* overscrollBounds: 20
* }
* ```
*
* @example
* Initialise with individual bounds per edge.
* ```typescript
* {
* overscrollBounds: {
* top: 50,
* bottom: 50,
* left: 100,
* right: 70,
* }
* }
* ```
*/
overscrollBounds?: number | Edge;
/**
* The margin used when aligning the artboard, for example when calling the
* `scaleToFit()` method. In this case, a value of `0` would scale the artboard to
* fill all the available width or height. A value of `50` would scale it so that
* there is at least 50px between the artboard and the root element.
*
* @example
* ```typescript
* Keeps at least 10px space between the artboard and the root element when aligning.
* {
* margin: 10,
* }
* ```
*/
margin?: number;
/**
* The amount to scroll per step, in pixels. This is used by methods like
* `artboard.scrollUp()`.
*
* @example
* Scrolls by 200px when calling for example the scrollUp() method, e.g. when
* pressing the ArrowUp key.
* ```typescript
* {
* scrollStepAmount: 200,
* }
* ```
*/
scrollStepAmount?: number;
/**
* The minimum amount the artboard can scale.
*
* @example
* Prevents scaling below 0.1.
*
* ```typescript
* {
* minScale: 0.1,
* }
* ```
*/
minScale?: number;
/**
* The maximum amount the artboard can scale.
*
* @example
* Prevents scaling above 9.
* ```typescript
* {
* maxScale: 9,
* }
* ```
*/
maxScale?: number;
/**
* The deceleration of the momentum scrolling. The higher the value the longer the momentum scrolling is applied.
*
* @example
* ```typescript
* {
* momentumDeceleration: 0.96
* }
* ```
*/
momentumDeceleration?: number;
/**
* Which directions can be scrolled.
*
* Possible values are `'none'`, `'horizontal'`, `'vertical'` or `'both'` (default).
*
* @example
* Restrict scrolling to the Y axis on a mobile viewport.
* ```typescript
* {
* direction: window.innerWidth < 768 ? 'vertical' : 'both'
* }
* ```
*/
direction?: Direction;
springDamping?: number;
/**
* A method that should return an array of rectangles (relative to viewport)
* that in some way overlap the root element.
*
* This information is used to center the artboard so that it (ideally)
* remains as visible as possible.
*
* @example
* ```typescript
* function getBlockingRects() {
* const toolbar = document.getElementById('toolbar')
* const rect = toolbar.getBoundingClientRect()
* return [rect]
* }
* ```
*/
getBlockingRects?: () => PossibleBlockingRect[];
/**
* How often the getBoundingClientRect() method should be called on the
* root element.
*
* Some calculations require knowing the exact location of the root element
* relative to the viewport. For this it will call getBoundingClientRect()
* on the root element. However, doing this too much can have a negative
* impact on performance, which is why this is only done sporadically.
*
* If you anticipate that the root element regularly changes its position
* relative to the viewport, you may set a lower value. If the position
* rarely or never changes, you may set a high value.
*
* Note the position is always updated when the ResizeObserver callback is
* triggered for the root element.
*
* @example
* Only refresh the root rect every minute.
*
* ```typescript
* {
* rootClientRectMaxStale: 60 * 1000,
* }
* ```
*/
rootClientRectMaxStale?: number;
};
/**
* Options for scrolling an area of the artboard into view.
*/
type ArtboardScrollIntoViewOptions = AnimationOptions & {
/**
* Define whether the artboard should be scaled.
*
* - None: Keeps the current artboard scale.
* - Full: Scales the artboard so that the target element fully covers the
* available space.
* - Blocking: Scales the artboard so that the target element covers the
* non-blocking area.
*/
scale?: 'none' | 'full' | 'blocking';
/**
* The scroll behaviour.
*
* - Smooth: Always animates the transition.
* - Instant: Directly apply the transform and scale.
* - Auto: Uses smooth, but switches to instant if an animation is currently
* running.
*/
behavior?: 'smooth' | 'instant' | 'auto';
/** Which axis to scroll. */
axis?: 'x' | 'y' | 'both';
/**
* Vertical alignment of the target rect within the effective viewport area.
*
* - `start`: Align the top edge of the target with the top of the viewport.
* - `center`: Center the target vertically (default).
* - `end`: Align the bottom edge of the target with the bottom of the viewport.
* - `nearest`: Scroll the minimum distance needed. No-op if already visible.
* If larger than the viewport, aligns `start`.
* - `auto`: Center if the target fits within the viewport, otherwise align
* `start`.
*/
block?: 'start' | 'center' | 'end' | 'nearest' | 'auto';
/**
* Horizontal alignment of the target rect within the effective viewport area.
*
* - `start`: Align the left edge of the target with the left of the viewport.
* - `center`: Center the target horizontally (default).
* - `end`: Align the right edge of the target with the right of the viewport.
* - `nearest`: Scroll the minimum distance needed. No-op if already visible.
* If larger than the viewport, aligns `start`.
* - `auto`: Center if the target fits within the viewport, otherwise align
* `start`.
*/
inline?: 'start' | 'center' | 'end' | 'nearest' | 'auto';
/**
* Padding insets from the viewport edges defining the effective area
* for both positioning and scaling.
*
* Accepts a uniform number or per-edge values using the `Edge` type.
*/
padding?: number | Partial<Edge>;
/**
* Defines the effective horizontal area used for positioning.
*
* - `viewport`: Use the full root element (minus padding). Default.
* - `blocking`: Use the non-blocked area computed from blocking rects.
* This positions the target within the available space without affecting
* scaling. Implied automatically when `scale` is `'blocking'`.
*/
area?: 'viewport' | 'blocking';
};
/**
* The animation-relevant state of the artboard at the time the animation frame
* was issued. These values might differ to the ones obtained using
* artboard.getOffset(), etc.
*/
type ArtboardLoopContext = {
/**
* The size of the root element.
*/
rootSize: Size;
/**
* The (unscaled) size of the artboard.
*
* When the artboard instance is initialised, the size of the artboard is null.
* When using the dom plugin, the size is set automatically from the artboard DOM
* element.
*
* When not using the dom plugin to render on a canvas, the size is available only
* when calling `artboard.setArtboardSize()`.
*/
artboardSize: Size | null;
/**
* The current scale.
*
* During a pinch gesture the scale value can go below minScale or above maxScale.
*/
scale: number;
/**
* The current artboard offset.
*
* During overscrolling the offset values can go outside the defined boundaries.
*/
offset: Coord;
/**
* The min/max boundaries for the artboard offset.
*/
boundaries: Boundaries;
/**
* The current timestamp for this animation iteration.
*
* When using the raf() plugin, this is the timestamp provided by the browser to the requestAnimationFrame callback.
* When manually calling `artboard.loop()` this will be the same value you pass as the argument to the loop method.
*/
currentTime: number;
};
/**
* The current interaction of the artboard.
*
* `'dragging'` - The artboard is being dragged using a mouse or finger.
* `'scaling'` - The artboard is being scaled using a mouse or finger.
* `'momentum'` - Momentum scrolling is being applied after a dragging interaction.
* `'momentumScaling'` - Momentum scaling is being applied after a scaling interaction.
* `'none'` - THe artboard is not being interacted with.
*/
type Interaction = 'dragging' | 'scaling' | 'momentum' | 'momentumScaling' | 'none';
/**
* The artboard instance.
*/
type Artboard = {
/**
* Add a plugin.
*
* Use this method if you conditionally need to add or remove plugins.
*
* @example
* ```typescript
* import { createArtboard, mouse } from 'artboard-deluxe'
*
* const artboard = createArtboard(document.body)
* const mousePlugin = mouse()
* artboard.addPlugin(mousePlugin)
* ```
*
* @param plugin - The plugin to add.
*/
addPlugin<T extends ArtboardPluginDefinition<any, any>>(plugin: T): T extends ArtboardPluginDefinition<infer O, infer R> ? ArtboardPluginInstance<O, R> : never;
/**
* Removes a previously added plugin.
*
* @example
* ```typescript
* import { createArtboard, clickZoom } from 'artboard-deluxe'
*
* const artboard = createArtboard(document.body)
* const plugin = clickZoom()
* artboard.addPlugin(plugin)
*
* function disableClickZoom() {
* artboard.removePlugin(plugin)
* }
* ```
*
* @param plugin - The plugin to remove. Must be the same instance that has been added using addPlugin.
*/
removePlugin(plugin: ArtboardPluginInstance): void;
/**
* Get the current applied scale of the artboard.
*
* @returns The current applied scale of the artboard.
*/
getScale(): number;
/**
* If there is an animation running, it returns the target scale of the animation.
* Else the current applied scale is returned.
*
* @returns The finale scale of the artboard.
*/
getFinalScale(): number;
/**
* Get the current applied offset of the artboard.
*
* @returns The offset.
*/
getOffset(): Coord;
/**
* Get the final offset. If there is currently an animation, the method will return the target offset of the animation.
*
* @returns The offset.
*/
getFinalOffset(): Coord;
/**
* Update all options.
*
* Note that this will reset option properties back to defaults if they are
* missing from the provided options.
*
* @example
* ```typescript
* import { createArtboard, type ArtboardOptions } from 'artboard-deluxe'
*
* function getOptions(): ArtboardOptions {
* const isMobile = window.innerWidth < 768
* const minScale = isMobile ? 1 : 0.1
* const maxScale = isMobile ? 5 : 10
* return {
* minScale,
* maxScale
* }
* }
*
* const artboard = createArtboard(document.body, [], getOptions())
*
* function updateOptions() {
* artboard.setOptions(getOptions())
* }
* ```
*
* @param options - The full options to update.
*/
setOptions(options: ArtboardOptions): void;
/**
* Update a single option.
*
* @example
* Update the minScale option when the viewport changes.
*
* ```typescript
* import { createArtboard } from 'artboard-deluxe'
*
* function getMinScale() {
* const isMobile = window.innerWidth < 768
* return isMobile ? 1 : 0.1
* }
*
* const artboard = createArtboard(document.body, [], {
* minScale: getMinScale(),
* })
*
* function onViewportChange() {
* artboard.setOption('minScale', getMinScale())
* }
* ```
*
* @param key - The name of the option to set.
* @param value - The value of the option to set.
*/
setOption<T extends keyof ArtboardOptions>(key: T, value: ArtboardOptions[T]): void;
/**
* Destroys the artboard instance, removes all event listeners, plugins and observers.
*/
destroy(): void;
/**
* Starts an animation if the current offset and scale of the artboard is
* outside the possible boundaries.
*/
animateToBoundary(): void;
/**
* The main animation handler.
*
* This method should be called from within a requestAnimationFrame callback.
* The method updates the internal state, applies momentum scrolling and
* animations.
*
* The method returns a snapshot of the state at the time of the animation
* frame. For the best experience you should use these values as the
* "source of truth", for example when using a canvas for rendering.
*
* @example
* ```typescript
* import { createArtboard, dom } from 'artboard-deluxe'
*
* const artboard = createArtboard(
* document.body,
* [
* dom(document.getElementById('artboard')))
* ]
* )
*
* function loop(timestamp: number) {
* artboard.loop(timestamp)
* window.requestAnimationFrame(loop)
* }
*
* loop()
* ```
*
* @param currentTime - The current time.
*
* @returns The loop context that contains a snapshot of the state that is applied.
*/
loop(currentTime: number): ArtboardLoopContext;
/**
* Returns the x offset that perfectly centers the artboard within the
* possible bounds.
*
* If the getBlockingRects option is provided, the method will also take
* blocking rects into account, if possible.
*
* @param targetScale - The target scale for which to calculate the offset.
*
* @returns The x offset.
*/
getCenterX(targetScale?: number): number;
/**
* Animate to the given state.
*
* If an animation is currently running, it will be overriden.
* If momentum scrolling is currently applied, it will be stopped.
*
* @param key - The name of the animation.
* @param x - The target x offset.
* @param y - The target y offset.
* @param targetScale - The target scale.
* @param options - The animation options.
*/
animateTo(key: string, x: number, y: number, targetScale?: number, options?: AnimationOptions | null): void;
/**
* Returns the size of the artboard.
*
* When using "infinite mode" (without any artboard size) this value will be null.
*
* @returns The artboard size.
*/
getArtboardSize(): Size | null;
/**
* Returns the size of the root element.
*
* @returns The size of the root element.
*/
getRootSize(): Size;
/**
* Animate or jump by the given offset.
*
* If there is an animation running currently and it's last animation frame timestamp is less than 300ms ago, the animation will be stopped and the offset applied immediately.
*
* @param providedX - How much pixels on the X axis to jump.
* @param providedY - How much pixels on the y axis to jump.
* @param options - The animation options.
*/
animateOrJumpBy(providedX?: number | null, providedY?: number | null, options?: AnimationOptions): void;
/**
* Animate or scroll to the given offset.
*
* If there is an animation running currently and it's last animation frame timestamp is less than 300ms ago, the animation will be stopped and the offset applied immediately.
*
* @param providedX - The new offset on the x axis.
* @param providedY - The new offset on the y axis.
* @param options - The animation options.
*/
animateOrJumpTo(providedX?: number | null, providedY?: number | null, options?: AnimationOptions): void;
/**
* Scroll one page up.
*
* @param options - The animation options.
*/
scrollPageUp(options?: AnimationOptions): void;
/**
* Scroll up by one page.
*
* @param options - The animation options.
*/
scrollPageUp(options?: AnimationOptions): void;
/**
* Scroll down by one page.
*
* @param options - The animation options.
*/
scrollPageDown(options?: AnimationOptions): void;
/**
* Scroll left by one page.
*
* @param options - The animation options.
*/
scrollPageLeft(options?: AnimationOptions): void;
/**
* Scroll right by one page.
*
* @param options - The animation options.
*/
scrollPageRight(options?: AnimationOptions): void;
/**
* Scroll up one step.
*
* @param options - The animation options.
*/
scrollUp(amount?: number, options?: AnimationOptions): void;
/**
* Scroll down one step.
*
* @param options - The animation options.
*/
scrollDown(amount?: number, options?: AnimationOptions): void;
/**
* Scroll left one step.
*
* @param options - The animation options.
*/
scrollLeft(amount?: number, options?: AnimationOptions): void;
/**
* Scroll right one step.
*
* @param options - The animation options.
*/
scrollRight(amount?: number, options?: AnimationOptions): void;
/**
* Scroll to the top of the artboard.
*
* @param options - The animation options.
*/
scrollToTop(options?: AnimationOptions): void;
/**
* Scroll to the end of the artboard.
*
* @param options - The animation options.
*/
scrollToEnd(options?: AnimationOptions): void;
/**
* Scale the artboard so it fits within the height of the root element.
*
* @param options - Animation options.
*/
scaleToFit(options?: AnimationOptions): void;
/**
* Reset zoom and center artboard on the x axis.
*
* @param options - The animation options.
*/
resetZoom(options?: AnimationOptions): void;
/**
* Set the scale of the artboard.
*
* @param newScale - The new scale to set.
* @param immediate - If true, the scale is applied immediately.
*/
setScale(newScale: number, immediate?: boolean): void;
/**
* Zoom in the artboard by the given amount.
*
* @param delta - The amount to zoom in.
*/
zoomIn(delta?: number): void;
/**
* Zoom out the artboard by the given amount.
*
* @param delta - The amount to zoom out.
*/
zoomOut(delta?: number): void;
/**
* Set the offset.
*
* @param providedX - The new x offset.
* @param providedY - The new y offset.
* @param immediate - If set the offset is applied immediately.
*/
setOffset(providedX?: number | null, providedY?: number | null, immediate?: boolean): void;
/**
* Cancels the current animation.
*/
cancelAnimation(): void;
/**
* Scale the artboard around the given point.
*
* @param pageX - The x coordinate relative to the page.
* @param pageY - The y coordinate relative to the page.
* @param targetScale - The target scale.
* @param animation - If provided, the scale is animated.
*/
scaleAroundPoint(pageX: number, pageY: number, targetScale: number, animation?: AnimationOptions | boolean): void;
/**
* Scales around the given point and returns what the offset should be so that the point remains centered.
*
* @param pageX - The x coordinate relative to the page.
* @param pageY - The y coordinate relative to the page.
* @param targetScale - The target scale.
*/
calculateScaleAroundPoint(pageX: number, pageY: number, targetScale: number, providedOffset?: Coord, providedScale?: number): Coord & {
scale: number;
};
/**
* Scrolls the given rectangle into view.
*
* The rectangle's coordinates and sizes should be relative to the artboard,
* _not_ the result of getBoundingClientRect(). For example, if the artboard
* is 1000x1000 big and it contains a 500x500 rectangle that is centered
* horizontally with a 50px margin on top, the value for targetRect would be:
* { x: 250 // Because (1000 - 500) / 2 = 250, y: 50, width: 500, height: 500,
* }
*
* @param targetRect - The rectangle to scroll into view. The coordinates and size of the rectangle should be uncaled and relative to the artboard.
* @param options - Options for the scroll behaviour and animation.
*/
scrollIntoView(targetRect: Rectangle, options?: ArtboardScrollIntoViewOptions): void;
/**
* Set the artboard size.
*
* When using the dom plugin, the artboard size is already set and updated automatically.
* Without the plugin (e.g. when using a canvas) it's expected to set the size manually.
*/
setArtboardSize(width: number, height: number): void;
/**
* Observe the size of the given element.
*
* @param element - The element to observe.
*/
observeSizeChange<T extends HTMLElement = HTMLElement>(element: T, cb: ObserverSizeChangeCallback<T>): ObserverSizeChangeContext;
/**
* Returns the root element.
*
* @returns The root element.
*/
getRootElement(): HTMLElement;
/**
* Returns the current artboard interaction.
*
* @returns The current interaction.
*/
getInteraction(): Interaction;
/**
* Set the current interaction.
*
* @param interaction - The new interaction.
*/
setInteraction(interaction?: Interaction): void;
/**
* Get the current velocity.
*
* @returns The velocity.
*/
getMomentum(): Coord | null;
/**
* Update the current velocity.
*
* If an argument is null, the current velocity value for that axis is kept.
*
* @param x - The velocity on the x axis.
* @param y - The velocity on the y axis.
*/
setMomentum(x: number, y: number, deceleration?: number): void;
/**
* Stop momentum.
*/
setMomentum(): void;
/**
* Get the current touch direction.
*
* @returns The touch direction.
*/
getTouchDirection(): Direction;
/**
* Set the current touch direction.
*
* @param direction - The new touch direction. Defaults to 'none'.
*/
setTouchDirection(direction?: Direction): void;
/**
* The artboard options.
*/
options: Options;
/**
* Apply the given momentum.
*
* @param velocity - The momentum to apply. If undefined, the velocity is reset and no momentum scrolling is applied.
*/
startMomentum(velocity?: Coord): void;
/**
* Updates the offset based on the current touchDirection.
*
* For example, if the current touchDirection is 'vertical', then only the Y offset is updated.
*
* @param x - The new x offset.
* @param y - The new y offset.
*/
setDirectionOffset(x: number, y: number): void;
/**
* Scrolls the given element into view.
*
* Only elements that are either a direct child of the root element or elements that are anchored to the artboard's location can be scrolled into view.
*
* @param targetEl - The element to scroll into view.
* @param options - Options for the scroll behaviour.
*/
scrollElementIntoView(targetEl: HTMLElement, options?: ArtboardScrollIntoViewOptions): void;
/**
* Get the current boundaries.
*
* @param providedTargetScale - Calculate the boundaries if the given scale were applied.
* @returns The boundaries.
*/
getBoundaries(providedTargetScale?: number): Boundaries;
/**
* Get the current target scale.
*
* Returns null when there is no target scale.
*
* @returns The target scale.
*/
getScaleTarget(): ScaleTarget | null;
/**
* Set the scale target.
*
* @param x - The target x offset.
* @param y - The target y offset.
* @param scale - The target scale.
*/
setScaleTarget(x: number, y: number, scale: number): void;
/**
* Get the currently running animation.
*
* @returns The animation if it exists.
*/
getAnimation(): ArtboardAnimation | null;
/**
* Determine whether the interaction before the current was momentum scrolling.
*
* This is used by plugins such as the `mouse()` plugin to prevent clicking on an element of the artboard if the user was previously momentum scrolling and clicking to stop the animation.
*
* @returns True if the previous interaction was momentum scrolling.
*/
wasMomentumScrolling(): boolean;
};
/**
* The target of the scale interaction.
*/
type ScaleTarget = Coord & {
scale: number;
};
/**
* The current momentum.
*/
type Momentum = Coord & {
deceleration: number;
};
type ArtboardState = {
/**
* The current arboard offset/translation.
*/
offset: Coord;
/**
* The current scale of the artboard.
*/
scale: number;
/**
* The target state for the current animation.
*/
animation: ArtboardAnimation | null;
/**
* The calculated velocity of a drag gesture.
*/
momentum: Momentum | null;
/**
* The timestamp when momentum was stopped.
*/
momentumStopTimestamp: number;
/**
* The native size of the artboard (without any scaling).
*/
artboardSize: Size | null;
/**
* The current interaction.
*/
interaction: Interaction;
/**
* The detected touch direction.
*/
touchDirection: Direction;
/**
* The timestamp of the last call to animateTo().
*/
lastAnimateToTimestamp: number;
/**
* The timestamp of the last animation loop.
*/
lastLoopTimestamp: number;
/**
* The position of the root element relative to the viewport.
*/
rootRect: DOMRect;
/**
* The native size of the root element.
*/
rootSize: Size;
/**
* The current scaling velocity.
*/
scaleVelocity: ScaleTarget | null;
};
/**
* Create a new artboard instance.
*/
declare function createArtboard(
/**
* The root element.
*
* Must be an element that creates a new stacking context (e.g. `position: relative`) when using the dom() plugin.
* When using canvas rendering, this should be the canvas.
*/
providedRootEl: HTMLElement | HTMLCanvasElement,
/**
* The plugins to initialise the artboard with.
*
* Plugins can also be added afterwards using the `artboard.addPlugin()` method.
*/
initPlugins?: ArtboardPluginDefinition<any, any>[],
/**
* The init options.
*
* To update options after the artboard is initialised, use the `artboard.setOption()` and `artboard.setOptions()` methods.
*/
initOptions?: ArtboardOptions): Artboard;
type OnlyWritable<T> = {
[P in keyof T as T[P] extends string ? P extends `set${string}` | `get${string}` ? never : P : never]: T[P];
};
type WritableStyleProperty = keyof OnlyWritable<CSSStyleDeclaration>;
type CssProperty = `--${string}`;
type InlineStyleOverrider = {
/**
* Sets the given style property value on the element.
*
* @param property - The style property to set.
* @param value - The value to set. If a number, the value is applied as pixels.
*/
set(property: WritableStyleProperty, value: string | number): void;
/**
* Sets the given custom property value on the element.
*
* @param property - The name of the CSS property.
* @param value - The value to set. If a number, the value is applied as pixels.
*/
setProperty(property: CssProperty, value: string | number): void;
/**
* Sets the transform value.
*/
setTransform(x: number, y: number, scale?: number, scaleY?: number): void;
/**
* Applies the provided overrides on the element.
*/
setMultiple(styles: Partial<Record<WritableStyleProperty, string | number>>): void;
/**
* Restores the original style values.
*/
restore(): void;
};
/**
* Override inline styles on an element and keep track of the original styles.
*/
declare function inlineStyleOverrider(element: HTMLElement): InlineStyleOverrider;
/**
* Implements a "click to zoom".
*
* Note this plugin only handles click events originating from mouse pointers.
* For touch devices, use the doubleTapToZoom plugin.
*
* @example
* ```typescript
* import { createArtboard, clickZoom } from 'artboard-deluxe'
*
* const root = document.elementById('root')
* const artboard = createArtboard(root, [clickZoom()])
* ```
*/
declare const clickZoom: (options?: {
animation?: Required<AnimationOptions>;
} | undefined) => ArtboardPluginDefinition<{
animation?: Required<AnimationOptions>;
}, object>;
type Property = '--artboard-offset-x' | '--artboard-offset-y' | '--artboard-scale' | '--artboard-size-width' | '--artboard-size-height' | '--artboard-root-width' | '--artboard-root-height';
/**
* Sets the artboard state as CSS custom properties/variables on the given element or root element.
*/
declare const cssProperties: (options: {
/**
* The element on which the CSS properties should be set.
* Falls back to the root element.
*/
element?: HTMLElement;
/**
* How precise the set values should be.
*
* A value of 1 (default) means that only whole pixels are applied (e.g. 20px).
* A value of 0.5 means the values are rounded to the next 0.5 increment (e.g. 20.5px or 21px).
* A value of 10 would round to 20px, 30px, 0px, etc.
*/
precision?: number;
/**
* Adds unitless property values.
*
* If true, instead of `--artboard-offset-x: -582px` it will set `--artboard-offset-x: -582`.
* Useful if you want to do CSS calculations with purely numeric values.
*/
unitless?: boolean;
/**
* Define which CSS properties to set.
*/
properties: Property[];
/**
* Restore original CSS properties on destroy.
*
* If true, the plugin will restore the CSS properties to their value before the plugin was initialised.
*/
restoreProperties?: boolean;
}) => ArtboardPluginDefinition<{
/**
* The element on which the CSS properties should be set.
* Falls back to the root element.
*/
element?: HTMLElement;
/**
* How precise the set values should be.
*
* A value of 1 (default) means that only whole pixels are applied (e.g. 20px).
* A value of 0.5 means the values are rounded to the next 0.5 increment (e.g. 20.5px or 21px).
* A value of 10 would round to 20px, 30px, 0px, etc.
*/
precision?: number;
/**
* Adds unitless property values.
*
* If true, instead of `--artboard-offset-x: -582px` it will set `--artboard-offset-x: -582`.
* Useful if you want to do CSS calculations with purely numeric values.
*/
unitless?: boolean;
/**
* Define which CSS properties to set.
*/
properties: Property[];
/**
* Restore original CSS properties on destroy.
*
* If true, the plugin will restore the CSS properties to their value before the plugin was initialised.
*/
restoreProperties?: boolean;
}, object>;
declare function defineArtboardPlugin<O extends object, R extends object = object, HasOptions = object extends O ? true : false>(init: ArtboardPluginInit<O, R>): HasOptions extends true ? (options?: O) => ArtboardPluginDefinition<O, R> : (options: O) => ArtboardPluginDefinition<O, R>;
/**
* The DOM plugin adds support for using a DOM element as the artboard.
*/
declare const dom: (options: {
/**
* The artboard element.
*/
element: HTMLElement;
/**
* If set, the initial offset and scale is set based on the current position
* of the artboard element in the viewport, relative to the root element.
*
* Use this if you want to determine the initial position of the artboard
* using CSS, such as grid, flex or using transform. The plugin will override
* any applied transform styles when it's initialised.
*/
setInitTransformFromRect?: boolean;
/**
* How precise the translate3d() values should be.
*
* A value of 1 (default) means the only whole pixels are applied (e.g. 20px).
* A value of 0.5 means the values are rounded to the next 0.5 increment (e.g. 20.5px or 21px).
* A value of 10 would round to 20px, 30px, 0px, etc.
*
* Note that internally the offset is kept as a floating point number. The
* precision only defines how the number is rounded when setting the transform style.
*/
precision?: number;
/**
* Calculate the applied scale so that the resulting scaled element's visible size is rounded to the target precision.
*/
applyScalePrecision?: boolean;
/**
* Whether to restore the original styles after destroying the plugin instance.
*/
restoreStyles?: boolean;
}) => ArtboardPluginDefinition<{
/**
* The artboard element.
*/
element: HTMLElement;
/**
* If set, the initial offset and scale is set based on the current position
* of the artboard element in the viewport, relative to the root element.
*
* Use this if you want to determine the initial position of the artboard
* using CSS, such as grid, flex or using transform. The plugin will override
* any applied transform styles when it's initialised.
*/
setInitTransformFromRect?: boolean;
/**
* How precise the translate3d() values should be.
*
* A value of 1 (default) means the only whole pixels are applied (e.g. 20px).
* A value of 0.5 means the values are rounded to the next 0.5 increment (e.g. 20.5px or 21px).
* A value of 10 would round to 20px, 30px, 0px, etc.
*
* Note that internally the offset is kept as a floating point number. The
* precision only defines how the number is rounded when setting the transform style.
*/
precision?: number;
/**
* Calculate the applied scale so that the resulting scaled element's visible size is rounded to the target precision.
*/
applyScalePrecision?: boolean;
/**
* Whether to restore the original styles after destroying the plugin instance.
*/
restoreStyles?: boolean;
}, object>;
/**
* Zooms the artboard using a double tap gesture.
*
* Note that this plugin only handles touch events. For mouse support, use
* the clickZoom plugin.
*/
declare const doubleTapZoom: (options?: {
animation?: AnimationOptions;
} | undefined) => ArtboardPluginDefinition<{
animation?: AnimationOptions;
}, object>;
type KeyboardModifier = 'ctrl' | 'meta' | 'alt' | 'ctrlmeta';
type PickMatching<T, V> = {
[K in keyof T as T[K] extends V ? K : never]: T[K];
};
type ExtractMethods<T> = PickMatching<T, () => void>;
type ArtboardMethods = ExtractMethods<Artboard>;
type Keymap = Record<string, [keyof ArtboardMethods, boolean?]>;
declare const keyboard: (options?: {
/**
* The modifier key to check.
*
* Defaults to 'ctrl'.
*/
modifier?: KeyboardModifier;
/**
* Override the default keymap.
*
* Should be an object whose properties are the keyboard code (according to
* KeyboardEvent['code']) and the values is an array where the first item is
* the name of the Artboard method to call and the second (optional value) is
* whether a modifier key is required.
*/
keymap?: Keymap;
} | undefined) => ArtboardPluginDefinition<{
/**
* The modifier key to check.
*
* Defaults to 'ctrl'.
*/
modifier?: KeyboardModifier;
/**
* Override the default keymap.
*
* Should be an object whose properties are the keyboard code (according to
* KeyboardEvent['code']) and the values is an array where the first item is
* the name of the Artboard method to call and the second (optional value) is
* whether a modifier key is required.
*/
keymap?: Keymap;
}, object>;
/**
* Options for the velocity queue used to determine the velocity for momentum
* scrolling.
*/
type VelocityQueueOptions = {
/**
* The time span to look at for calculating the velocity in milliseconds.
*
* A value of 400 means only positions registered in the last 400ms will
* determine the velocity.
*/
maxTimeWindow: number;
/**
* The minimum velocity.
*/
minVelocity: number;
/**
* The maximum velocity to calculate before applying the multiplicator.
*/
maxVelocity: number;
/**
* The multiplicator to apply to the final velocity.
*/
multiplicator: number;
};
declare const mouse: (options?: {
/**
* Whether to set the cursor on the root element to indicate when dragging.
*
* Note by default this is disabled because changing the cursor can trigger style recalculation, see https://gist.github.com/paulirish/5d52fb081b3570c81e3a/565c05680b27c9cfd9f5e971d295cd558c3e1843.
*/
setCursor?: boolean;
/**
* Only allow dragging while holding the spacebar.
*/
useSpacebar?: boolean;
/**
* Options for the velocity queue.
*/
velocity?: Partial<VelocityQueueOptions>;
scrollDirectionThreshold?: number;
} | undefined) => ArtboardPluginDefinition<{
/**
* Whether to set the cursor on the root element to indicate when dragging.
*
* Note by default this is disabled because changing the cursor can trigger style recalculation, see https://gist.github.com/paulirish/5d52fb081b3570c81e3a/565c05680b27c9cfd9f5e971d295cd558c3e1843.
*/
setCursor?: boolean;
/**
* Only allow dragging while holding the spacebar.
*/
useSpacebar?: boolean;
/**
* Options for the velocity queue.
*/
velocity?: Partial<VelocityQueueOptions>;
scrollDirectionThreshold?: number;
}, object>;
type OverviewOptions = {
element: HTMLElement;
/** The element or selector for the artboard element in the overview. */
artboardElement?: HTMLElement | string;
/** The element or selector for the visible area element in the overview. */
visibleAreaElement?: HTMLElement | string;
/** The padding to apply inside the overview element, in pixels. */
padding?: number;
/**
* Whether to restore the original styles after destroying the plugin instance.
*/
restoreStyles?: boolean;
/**
* If enabled the height of the overview element is adjusted automatically
* to the size of the artboard.
*
* The element must have a width. The height is calculated based on the
* aspect ratio of the artboard.
*/
autoHeight?: boolean;
/**
* The maximum height for the overview element when autoHeight is enabled.
*
* If the calculated height exceeds this value, the height will be capped
* and the artboard will be scaled to fit within the constrained dimensions.
*
* This is useful for preventing the overview from exceeding the viewport height.
*/
maxHeight?: number;
};
declare const overview: (options: OverviewOptions) => ArtboardPluginDefinition<OverviewOptions, object>;
/**
* Registers a requestAnimationFrame callback for the artboard.
*/
declare const raf: (options?: {
/**
* Cap the frame rate to the given value (e.g. 30, 60, 120).
*
* When set, artboard.loop() is only called when the elapsed time since the
* last frame exceeds the target interval. Useful for debugging frame-rate
* dependent behavior.
*
* When not set, artboard.loop() is called on every animation frame.
*/
fps?: number;
} | undefined) => ArtboardPluginDefinition<{
/**
* Cap the frame rate to the given value (e.g. 30, 60, 120).
*
* When set, artboard.loop() is only called when the elapsed time since the
* last frame exceeds the target interval. Useful for debugging frame-rate
* dependent behavior.
*
* When not set, artboard.loop() is called on every animation frame.
*/
fps?: number;
}, object>;
type ScrollbarOrientation = 'x' | 'y';
declare const scrollbar: (options: {
/** The element representing the scrollbar. */
element: HTMLElement;
/** The element or selector representing the scrollbar thumb. */
thumbElement?: string | HTMLElement;
/** The orientation. */
orientation: ScrollbarOrientation;
/** The minimum size of the thumb. */
minThumbSize?: number;
/**
* Whether to restore the original styles after destroying the plugin instance.
*/
restoreStyles?: boolean;
}) => ArtboardPluginDefinition<{
/** The element representing the scrollbar. */
element: HTMLElement;
/** The element or selector representing the scrollbar thumb. */
thumbElement?: string | HTMLElement;
/** The orientation. */
orientation: ScrollbarOrientation;
/** The minimum size of the thumb. */
minThumbSize?: number;
/**
* Whether to restore the original styles after destroying the plugin instance.
*/
restoreStyles?: boolean;
}, object>;
declare const touch: (options?: {
/**
* Whether to require two touch points to interact with the artboard.
*
* The default is false, which will scroll the artboard using a single touch
* point. Set this to true to require two touch points, which will scale and
* scroll the artboard at the same time. Useful if you have some sort of
* draw