Frontend: Svelte Actions
Relevant source files
The following files were used as context for generating this wiki page:
The client/actions directory is a dedicated workspace package within the Tidigit monorepo, named @21n/actions. It provides a collection of reusable Svelte actions that encapsulate common DOM-level logic and behaviors. These actions are designed to be generic and can be applied to various elements across the different frontend applications like Nucleus, Memotron, and Pointron, promoting code reuse and a consistent user experience.
This package is a fundamental part of the frontend architecture, allowing developers to easily add complex functionalities such as drag-and-drop, popovers, and lazy loading to Svelte components with a simple use: directive. The package is defined as a workspace in the root package.json and is consumed as a dependency by the product applications.
Sources: package.json:8, client/actions/package.json:2, apps/nucleus/package.json:68
Available Actions
The following table summarizes the Svelte actions provided by the @21n/actions package.
| Action | Description | Key Dependencies | Source File |
|---|---|---|---|
dragAndDrop | Enables list items to be reordered via drag and drop, dispatching events to handle the final state. | - | dragAndDrop.action.ts |
popover | Positions a floating element (popover) relative to a trigger element. | @floating-ui/dom | popover.action.ts |
lazyload | Defers the loading of an element until it enters the viewport, using the IntersectionObserver API. | - | lazyload.action.ts |
dragAndDrop Action
This action provides functionality for reordering items in a list. When applied to a container element, it makes its children draggable.
Sources: client/actions/dragAndDrop.action.ts
Usage
The action is applied to a list container. It requires an object with the list of items and a type string that acts as a unique identifier for the drag-and-drop context.
// client/actions/dragAndDrop.action.ts:13-16
export const dragAndDrop = (
node: HTMLElement,
params: { items: any[]; type: string }
): ActionReturn<{ 'on:finalize': (e: any) => void; 'on:consider': (e: any) => void }> => {
Parameters
| Name | Type | Description |
|---|---|---|
items | any[] | The array of items that are being rendered in the list. The action uses this array to manage the reordering. |
type | string | A string identifier for the drop zone. This is used to ensure items are only dropped into compatible zones. |
Sources: client/actions/dragAndDrop.action.ts:14
Dispatched Events
The action dispatches two custom events to communicate with the parent Svelte component.
| Event | Payload | Description |
|---|---|---|
on:consider | { items: any[]; info: { index: number; id: any } } | Fired continuously as a dragged item is moved over a potential drop target. |
on:finalize | { items: any[]; info: { index: number; id: any } } | Fired once when the item is dropped, containing the newly reordered list. |
Sources: client/actions/dragAndDrop.action.ts:15, client/actions/dragAndDrop.action.ts:108, client/actions/dragAndDrop.action.ts:127
Logic Flow
The action attaches several event listeners (dragstart, dragenter, dragover, drop, dragend) to the container node and its children to manage the drag-and-drop lifecycle. It uses a "ghost" element to provide visual feedback during the drag and an indicator element to show the potential drop position.
This diagram illustrates the event sequence and state changes managed by the dragAndDrop action.
popover Action
This action is used to create and manage a popover element, positioning it relative to a specified trigger element. It leverages the @floating-ui/dom library for robust positioning logic.
Sources: client/actions/popover.action.ts
Usage
The action is applied to the popover element itself and requires a trigger element to position against.
// client/actions/popover.action.ts:12-15
export const popover = (
node: HTMLElement,
{ trigger, opts }: { trigger: HTMLElement; opts?: Partial<ComputePositionConfig> }
) => {
Parameters
| Name | Type | Description |
|---|---|---|
trigger | HTMLElement | The element that the popover should be positioned relative to. |
opts | Partial<ComputePositionConfig> | Optional configuration object passed directly to @floating-ui/dom's computePosition function. This can include placement, middleware (e.g., offset, flip, shift), etc. |
Sources: client/actions/popover.action.ts:13
Logic Flow
When the action is initialized, it computes the popover's position based on the trigger element. It also sets up a click event listener on the document to detect clicks outside the popover and trigger, which will then hide the popover. The update function allows for re-computing the position if the trigger or options change.
The following sequence diagram shows the interaction for displaying and hiding a popover.
lazyload Action
This action defers the initialization or loading of an element until it becomes visible in the user's viewport. It is a performance optimization technique, commonly used for images or other heavy components.
Sources: client/actions/lazyload.action.ts
Usage
The action is applied to the element that should be lazy-loaded. It accepts an optional threshold parameter.
// client/actions/lazyload.action.ts:8-11
export const lazyload = (
node: HTMLElement,
threshold = 0
): ActionReturn<{ 'on:intersect': (e: any) => void }> => {
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
threshold | number | 0 | A value between 0.0 and 1.0 indicating the percentage of the element's visibility needed to trigger the intersect event. |
Sources: client/actions/lazyload.action.ts:9
Dispatched Events
| Event | Payload | Description |
|---|---|---|
on:intersect | (none) | Fired once when the element enters the viewport according to the specified threshold. |
Sources: client/actions/lazyload.action.ts:10, client/actions/lazyload.action.ts:21
Logic Flow
The action utilizes the browser's IntersectionObserver API. It creates an observer that watches the element. When the element intersects the viewport, the observer's callback fires the on:intersect custom event and then disconnects itself to prevent further unnecessary event dispatches.
This diagram shows the simple lifecycle of the lazyload action.