UNPKG

@neodrag/svelte

Version:

Svelte Action to add dragging to your apps 😉

285 lines (282 loc) • 11.1 kB
type DragBoundsCoords = { /** Number of pixels from left of the document */ left: number; /** Number of pixels from top of the document */ top: number; /** Number of pixels from the right side of document */ right: number; /** Number of pixels from the bottom of the document */ bottom: number; }; type DragAxis = 'both' | 'x' | 'y' | 'none'; type DragBounds = HTMLElement | Partial<DragBoundsCoords> | 'parent' | 'body' | (string & Record<never, never>); type DragEventData = { /** How much element moved from its original position horizontally */ offsetX: number; /** How much element moved from its original position vertically */ offsetY: number; /** The node on which the draggable is applied */ rootNode: HTMLElement; /** The element being dragged */ currentNode: HTMLElement; /** The pointer event that triggered the drag */ event: PointerEvent; }; type DragOptions = { /** * Optionally limit the drag area * * Accepts `parent` as prefixed value, and limits it to its parent. * * Or, you can specify any selector and it will be bound to that. * * **Note**: We don't check whether the selector is bigger than the node element. * You yourself will have to make sure of that, or it may lead to strange behavior * * Or, finally, you can pass an object of type `{ top: number; right: number; bottom: number; left: number }`. * These mimic the css `top`, `right`, `bottom` and `left`, in the sense that `bottom` starts from the bottom of the window, and `right` from right of window. * If any of these properties are unspecified, they are assumed to be `0`. */ bounds?: DragBounds; /** * When to recalculate the dimensions of the `bounds` element. * * By default, bounds are recomputed only on dragStart. Use this options to change that behavior. * * @default '{ dragStart: true, drag: false, dragEnd: false }' */ recomputeBounds?: { dragStart?: boolean; drag?: boolean; dragEnd?: boolean; }; /** * Axis on which the element can be dragged on. Valid values: `both`, `x`, `y`, `none`. * * - `both` - Element can move in any direction * - `x` - Only horizontal movement possible * - `y` - Only vertical movement possible * - `none` - No movement at all * * @default 'both' */ axis?: DragAxis; /** * If false, uses the new translate property instead of transform: translate(); to move the element around. * * At present this is true by default, but will be changed to false in a future major version. * * @default false * @deprecated Use `transform` option instead for transform: translate() or any other custom transform. Will be removed in v3. */ legacyTranslate?: boolean; /** * If true, uses `translate3d` instead of `translate` to move the element around, and the hardware acceleration kicks in. * * `true` by default, but can be set to `false` if [blurry text issue](https://developpaper.com/question/why-does-the-use-of-css3-translate3d-result-in-blurred-display/) occur * * @default true * @deprecated Use `transform` option instead with translate(x, y, 1px). 1px forces some browsers to use GPU acceleration. Will be removed in v3 */ gpuAcceleration?: boolean; /** * Custom transform function. If provided, this function will be used to apply the DOM transformations to the root node to move it. * Existing transform logic, including `gpuAcceleration` and `legacyTranslate`, will be ignored. * * You can return a string to apply to a `transform` property, or not return anything and apply your transformations using `rootNode.style.transform = VALUE` * * @default undefined */ transform?: ({ offsetX, offsetY, rootNode, }: { offsetX: number; offsetY: number; rootNode: HTMLElement; }) => string | undefined | void; /** * Applies `user-select: none` on `<body />` element when dragging, * to prevent the irritating effect where dragging doesn't happen and the text is selected. * Applied when dragging starts and removed when it stops. * * Can be disabled using this option * * @default true */ applyUserSelectHack?: boolean; /** * Ignores touch events with more than 1 touch. * This helps when you have multiple elements on a canvas where you want to implement * pinch-to-zoom behaviour. * * @default false * */ ignoreMultitouch?: boolean; /** * Disables dragging altogether. * * @default false */ disabled?: boolean; /** * Applies a grid on the page to which the element snaps to when dragging, rather than the default continuous grid. * * `Note`: If you're programmatically creating the grid, do not set it to [0, 0] ever, that will stop drag at all. Set it to `undefined`. * * @default undefined */ grid?: [number, number]; /** * Threshold for dragging to start. If the user moves the mouse/finger less than this distance, the dragging won't start. * * @default { delay: 0, distance: 3 } */ threshold?: { /** * Threshold in milliseconds for a pointer movement to be considered a drag * * @default 0 */ delay?: number; /** * Threshold in pixels for movement to be considered a drag * * @default 3 */ distance?: number; }; /** * Control the position manually with your own state * * By default, the element will be draggable by mouse/finger, and all options will work as default while dragging. * * But changing the `position` option will also move the draggable around. These parameters are reactive, * so using Svelte's reactive variables as values for position will work like a charm. * * * Note: If you set `disabled: true`, you'll still be able to move the draggable through state variables. Only the user interactions won't work * */ position?: { x: number; y: number; }; /** * CSS Selector of an element or multiple elements inside the parent node(on which `use:draggable` is applied). * * Can be an element or elements too. If it is provided, Trying to drag inside the `cancel` element(s) will prevent dragging. * * @default undefined */ cancel?: string | HTMLElement | HTMLElement[]; /** * CSS Selector of an element or multiple elements inside the parent node(on which `use:draggable` is applied). Can be an element or elements too. * * If it is provided, Only clicking and dragging on this element will allow the parent to drag, anywhere else on the parent won't work. * * @default undefined */ handle?: string | HTMLElement | HTMLElement[]; /** * Class to apply on the element on which `use:draggable` is applied. * Note that if `handle` is provided, it will still apply class on the element to which this action is applied, **NOT** the handle * */ defaultClass?: string; /** * Class to apply on the element when it is dragging * * @default 'neodrag-dragging' */ defaultClassDragging?: string; /** * Class to apply on the element if it has been dragged at least once. * * @default 'neodrag-dragged' */ defaultClassDragged?: string; /** * Offsets your element to the position you specify in the very beginning. * `x` and `y` should be in pixels * */ defaultPosition?: { x: number; y: number; }; /** * Fires when dragging start */ onDragStart?: (data: DragEventData) => void; /** * Fires when dragging is going on */ onDrag?: (data: DragEventData) => void; /** * Fires when dragging ends */ onDragEnd?: (data: DragEventData) => void; }; /** * Actions can return an object containing the two properties defined in this interface. Both are optional. * - update: An action can have a parameter. This method will be called whenever that parameter changes, * immediately after Svelte has applied updates to the markup. `ActionReturn` and `ActionReturn<undefined>` both * mean that the action accepts no parameters. * - destroy: Method that is called after the element is unmounted * * Additionally, you can specify which additional attributes and events the action enables on the applied element. * This applies to TypeScript typings only and has no effect at runtime. * * Example usage: * ```ts * interface Attributes { * newprop?: string; * 'on:event': (e: CustomEvent<boolean>) => void; * } * * export function myAction(node: HTMLElement, parameter: Parameter): ActionReturn<Parameter, Attributes> { * // ... * return { * update: (updatedParameter) => {...}, * destroy: () => {...} * }; * } * ``` * * Docs: https://svelte.dev/docs/svelte-action */ interface ActionReturn<Parameter = undefined, Attributes extends Record<string, any> = Record<never, any>> { update?: (parameter: Parameter) => void; destroy?: () => void; /** * ### DO NOT USE THIS * This exists solely for type-checking and has no effect at runtime. * Set this through the `Attributes` generic instead. */ $$_attributes?: Attributes; } /** * Actions are functions that are called when an element is created. * You can use this interface to type such actions. * The following example defines an action that only works on `<div>` elements * and optionally accepts a parameter which it has a default value for: * ```ts * export const myAction: Action<HTMLDivElement, { someProperty: boolean } | undefined> = (node, param = { someProperty: true }) => { * // ... * } * ``` * `Action<HTMLDivElement>` and `Action<HTMLDivElement, undefined>` both signal that the action accepts no parameters. * * You can return an object with methods `update` and `destroy` from the function and type which additional attributes and events it has. * See interface `ActionReturn` for more details. * * Docs: https://svelte.dev/docs/svelte-action */ interface Action<Element = HTMLElement, Parameter = undefined, Attributes extends Record<string, any> = Record<never, any>> { <Node extends Element>(...args: undefined extends Parameter ? [node: Node, parameter?: Parameter] : [node: Node, parameter: Parameter]): void | ActionReturn<Parameter, Attributes>; } declare const draggable: Action<HTMLElement, DragOptions | undefined, { "on:neodrag:start": (e: CustomEvent<DragEventData>) => void; "on:neodrag": (e: CustomEvent<DragEventData>) => void; "on:neodrag:end": (e: CustomEvent<DragEventData>) => void; }>; export { type Action, type ActionReturn, type DragAxis, type DragBounds, type DragBoundsCoords, type DragEventData, type DragOptions, draggable };