npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pastweb/tools

v2.2.2

Published

Set of tools for web application development

Readme

@pastweb/tools

Contains a collection of utility functions to help with various common tasks in JavaScript and TypeScript application development. Below you will find descriptions of each function along with examples of how to use them.

  • Production ready
  • Treeshake optimised

Installation

$ npm i -S @pastweb/tools
$ pnpm i -S @pastweb/tools
$ yarn add -S @pastweb/tools

Summary


Async functions

createApiAgent

Creates an API agent with customizable settings for HTTP requests.

Syntax

function createApiAgent(settings?: AgentSettings): Agent;

Parameters

  • settings: AgentSettings (optional) The settings for the API agent.
    • withCredentials: boolean (optional) (default: false)
      • Indicates whether cross-site Access-Control requests should be made using credentials.
    • headers: Record<string, any> (optional) (default: {})
      • Custom headers to be sent with each request.
    • exclude: string | RegExp | Array<string | RegExp> (optional)
      • URLs or patterns to exclude from request intercepting.
    • onGetValidToken: () => Promise<Record<string, any>> (optional)
      • Function to get a valid token for authorization.
    • onUnauthorizedResponse: () => void (optional)
      • Callback for unauthorized responses.
    • pagination: boolean | Pagination (optional) (default: true)
      • Enables pagination parsing. If true, uses default settings ({ defaultPageLimit: 100, header: 'Content-Range' }). If an object, allows custom defaultPageLimit and header.
    • cache: boolean (optional) (default: false)
      • Enables response caching for GET requests.

Returns

  • Agent
    • The configured API agent.

Methods

  • setAgentOptions(options: AgentOptions): void
    • Sets the agent configuration.
  • mergeAgentConfig(newSettings: AxiosRequestConfig): void
    • Merges new settings into the existing agent configuration.
  • getPageLimit(limit?: PageLimit): number
    • Returns the page limit as a number (default: 100).
  • getPageNumber(page?: PageNumber): number
    • Returns the page number as a number (default: 1).
  • pageToOffset(page?: PageNumber, limit?: PageLimit): number
    • Converts a page number to an offset for pagination.
  • delete<T = any>(url: string, options: MutationOptions): Promise<AxiosResponse<T>>
    • Sends a DELETE request. Supports AxiosRequestConfig and onSuccess/onError callbacks if cache = true in the AgentOptions.
  • get<T = any>(url: string, options: QueryOptions): Promise<AxiosResponse<T>>
    • Sends a GET request. Supports AxiosRequestConfig and caching with queryKey and expireIn if cache = true in the AgentOptions.
  • patch<T = any>(url: string, data?: unknown, options: MutationOptions): Promise<AxiosResponse<T>>
    • Sends a PATCH request.
  • post<T = any>(url: string, data?: unknown, options: MutationOptions): Promise<AxiosResponse<T>>
    • Sends a POST request.
  • put<T = any>(url: string, data?: unknown, options: MutationOptions): Promise<AxiosResponse<T>>
    • Sends a PUT request.
  • upload(url: string, data: FormData, onUploadProgress?: (e: AxiosProgressEvent) => void): Promise<AxiosResponse>
    • Uploads a file using a POST request with multipart/form-data for file uploads.
  • download(url: string, fileName: string, domElement?: HTMLElement): Promise<AxiosResponse>
    • Downloads a file using a GET request and triggers a download in the browser.

Cache When cache: true is set, GET requests are cached using a queryKey (defaults to the URL). The cache supports:

  • get(key: string): QueryData
    • Retrieves a cached response.
  • getAll(): [string, QueryData][]
    • Returns all cache entries.
  • has(key: string): boolean
    • Checks if a key exists in the cache.
  • set(key: string, data: QueryData): Map<string, QueryData>
    • Sets a cache entry with a response, timestamp, and expiration.
  • delete(key: string): boolean
    • Removes a cache entry.
  • invalidateQuery(queryKey?: string | string[]): void
    • Invalidates cache entries by key or prefix.

Cache entries expire based on the expireIn option (e.g., '1s', '5m') using the isDateYoungerOf utility.

Pagination When pagination is enabled, the successResponseInterceptor processes responses with a Content-Range header (e.g., 0-1/20 where 0-1 is start and end index adn 20 is the items total number). For application/json responses contains the pagination additional info:

{
  data: any, // Original response data
  pagination: {
    start: number, // Start index
    end: number, // End index
    total: number, // Total items
    size: number, // Page size
    current: number, // Current page
    of: number // Total pages
  }
}

The Content-Range header is parsed to extract start, end, and total. The limit query parameter (or defaultPageLimit) determines the page size.

Example:

import { createApiAgent } from '@pastweb/tools';

const apiAgent = createApiAgent({
  withCredentials: true,
  headers: {
    Accept: 'application/json',
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token'
  },
  onGetValidToken: async () => ({ Authorization: 'Bearer newToken' }),
  onUnauthorizedResponse: () => {
    console.log('Unauthorized! Redirecting to login...');
  },
});

// Making a GET request
apiAgent.get('/api/data').then(response => {
  console.log('Data:', response.data);
});

// Uploading a file
const formData = new FormData();
formData.append('file', fileInput.files[0]);
apiAgent.upload('/api/upload', formData, (event) => {
  console.log('Upload progress:', Math.round((event.loaded * 100) / event.total));
});

// Downloading a file
apiAgent.download('/api/download', 'file.txt');

// Cached GET Request
const agent = createApiAgent({ cache: true });
await agent.get('/api/users', { queryKey: 'users', expireIn: '5m' });
await agent.get('/api/users', { queryKey: 'users' }); // Returns cached response

// Paginated GET Request
const agent = createApiAgent({ pagination: { defaultPageLimit: 10, header: 'Content-Range' } });
const response = await agent.get('/api/users?offset0&limit=10');
// Response: { data: [...], info: { start: 0, end: 9, total: 50, size: 10, current: 1, of: 5 } }

useQuery

Creates a reactive query Object that fetches data using the provided function and updates based on reactive dependencies

Syntax

function useQuery<T>(config: QueryConfig<T>): QueryInfo<T>

Parameters

  • config: QueryConfig<T> The configuration for the query.
    • fn: () => Promise<AxiosResponse<T>> The function to fetch data, typically an agent.get call from createApiAgent.
    • source?: (() => any) | Ref<any> | Array<(() => any) | Ref<any>> (optional) Reactive dependencies to track (e.g., () => page.value). Required if fn uses reactive variables in its URL or parameters.
    • immediate?: boolean | Ref<boolean> (optional) (default: true) If true or a Ref with value: true, runs the query immediately. If a Ref<boolean>, triggers the query when value becomes true.
    • initialData?: T (optional) Initial data to set before the first fetch. Sets isPlaceholderData to true until a fetch completes.
    • SSRWait (optional) (default: true) If run in server side block the thread until the fn: () => Promise<AxiosResponse<T>> is solved or generate an error.

Returns

  • QueryInfo<T> A reactive object with query state and methods.
    • data: T | null The response data or initialData.
    • pagination: Page<any>['pagination'] | null Pagination info if available
    • isPending: boolean True during initial fetch or refetch.
    • isLoading: boolean Alias for isPending.
    • isFetching: boolean True during any fetch.
    • isError: boolean True if an error occurred.
    • error: any The error object, if any.
    • isPlaceholderData: boolean True if data is initialData.
    • fetch: () => Promise<void> Manually triggers the query.

The useQuery function creates a reactive query that automatically fetches data when initialized (if immediate is true) or when reactive dependencies in source or immediate (if a Ref) change. It integrates with createApiAgent to handle reactive AxiosResponse objects, ensuring data updates with new responses or cache changes. The source parameter is required to track reactive variables used in fn (e.g., page.value in the URL).

Example:

import { createApiAgent, createQuery, ref } from '@pastweb/tools';

// Create an API agent
const agent = createApiAgent({
  cache: true,
  pagination: true,
});

// Basic query with immediate fetch
const query = useQuery({
  fn: () => agent.get('/api/users?_page=1&_limit=10'),
});

console.log(query.data); // Initially null, updates to { data: [...], info: {...} }
console.log(query.isPending); // true during fetch, then false

// Query with reactive dependency
const page = ref(1);
const reactiveQuery = useQuery({
  fn: () => agent.get(`/api/users?_page=${page.value}&_limit=10`),
  source: page,
});

page.value = 2; // Triggers refetch with new URL

// Query with Ref<boolean> immediate
const immediate = ref(false);
const controlledQuery = useQuery({
  fn: () => agent.get('/api/users'),
  immediate,
});

immediate.value = true; // Triggers fetch

useMutation

Creates a reactive mutation that executes the provided function and updates state with lifecycle hooks.

Syntax

function useMutation<T>(config: MutationConfig<T>): MutationInfo<T>

Parameters

  • config: MutationConfig<T> The configuration for the mutation.
  • fn: (...args: any[]) => Promise<AxiosResponse<T>> The mutation function, typically agent.post, agent.put, or agent.delete from createApiAgent.
  • onMutate?: (...args: any[]) => Promise<void> | void (optional) (default: noop) Called before the mutation executes, with the same arguments as mutate.
  • onSuccess?: (...args: any[]) => Promise<void> | void (optional) (default: noop) Called after a successful mutation or error in the finally block, with the same arguments as mutate.
  • onError?: (...args: any[]) => Promise<void> | void (optional) (default: noop) Called if the mutation fails, with the error object.
  • initialData?: T (optional) (default: null) Initial data to set before the first mutation. Sets isPlaceholderData to true until a mutation completes.

Returns

  • MutationInfo<T> A reactive object with mutation state and methods.
  • data: T | null The response data or initialData.
  • isPending: boolean True during mutation execution.
  • isMutating: boolean Alias for isPending.
  • isError: boolean True if an error occurred.
  • error: any The error object, if any.
  • isPlaceholderData: boolean True if data is initialData.
  • mutate: (...args: any[]) => Promise<void> Executes the mutation with provided arguments.

The useMutation function creates a reactive mutation object for operations like POST, PUT, or DELETE requests. It supports variadic arguments for mutate and fn, allowing flexible payloads. Lifecycle hooks (onMutate, onSuccess, onError) enable custom logic before and after mutations. The function integrates with createApiAgent’s reactive AxiosResponse, ensuring data updates with new responses or cache changes. Unlike useQuery, mutations are triggered manually via mutate, not reactively.

Example:

import { createApiAgent, useMutation } from '@pastweb/tools';

// Create an API agent
const agent = createApiAgent({
  headers: { 'Content-Type': 'application/json' },
});

// Basic mutation
const mutation = useMutation({
  fn: (data: any) => agent.post('/api/users', data),
});

await mutation.mutate({ name: 'John' });
console.log(mutation.data); // { id: 1, name: 'John' }
console.log(mutation.isMutating); // false

// Mutation with lifecycle hooks
const createUser = createMutation({
  fn: (data: any) => agent.post('/api/users', data),
  onMutate: async (data) => {
    console.log('Starting mutation with:', data);
  },
  onSuccess: async (data) => {
    console.log('Mutation succeeded with:', data);
  },
  onError: async (error) => {
    console.error('Mutation failed:', error);
  },
});

await createUser.mutate({ name: 'Jane' });

// Mutation with initialData
const updateUser = useMutation({
  fn: (data: any) => agent.put('/api/users/1', data),
  initialData: { id: 1, name: 'Placeholder' },
});

console.log(updateUser.data); // { id: 1, name: 'Placeholder' }
console.log(updateUser.isPlaceholderData); // true
await updateUser.mutate({ name: 'Updated' });
console.log(updateUser.isPlaceholderData); // false 

createAsyncStore

Creates an asynchronous store with the given options. Useful to be extended for async initialisation of application state manager like redux or pinia if needs to get initialisation data from async resources as indexedDB.

Syntax

function createAsyncStore<T>(options: AsyncStoreOptions): T;

Parameters

  • options: AsyncStoreOptions
    • The options for creating the asynchronous store.
    • storeName: string
      • The name of the store. This is required for better error debugging.
    • timeout: number (optional, default: 20000)
      • The timeout limit in milliseconds for initializing the store.

Returns

  • T
    • The created asynchronous store.

Throws

  • Will throw an error if the storeName option is not set.

Example:

import { createAsyncStore } from '@pastweb/tools';

const storeOptions = {
  storeName: 'myStore',
  timeout: 30000,
};

const myStore = createAsyncStore(storeOptions);

normalizeAsyncQueue

Normalizes an array of asynchronous operations into an array of promises.

Syntax

function normalizeAsyncQueue(wait: Wait | Wait[]): Promise<any>[];

Parameters

  • wait: Wait | Wait[]
    • A single asynchronous operation or an array of asynchronous operations. Each operation can be:
      • A promise
      • A function that returns a promise
      • An object representing an asynchronous store

Returns

  • Promise<any>[]
    • An array of promises.

Throws

  • Error
    • Throws an error if an invalid type is encountered in the wait array.

Example:

import { normalizeAsyncQueue } from '@pastweb/tools';

// Single promise
const singlePromise = Promise.resolve('done');
normalizeAsyncQueue(singlePromise); // [singlePromise]

// Array of promises and functions
const promise1 = Promise.resolve('done');
const promise2 = () => Promise.resolve('done');
normalizeAsyncQueue([promise1, promise2]); // [promise1, promise2()]

// Async store
const asyncStore = {
  $$asyncStore: true,
  isStoreReady: false,
  isReady: new Promise(resolve => resolve(true)),
  init: () => { asyncStore.isStoreReady = true; }
};
normalizeAsyncQueue(asyncStore); // [asyncStore.isReady]

Remarks The normalizeAsyncQueue function is designed to handle various asynchronous operations and normalize them into a uniform array of promises. This is particularly useful when dealing with mixed asynchronous workflows, ensuring that all operations can be awaited in a consistent manner.

This function supports:

  • Promises
  • Functions returning promises
  • Asynchronous stores

If an asynchronous store is passed in, the function will check if the store is ready. If it is not, the init method of the store will be called to prepare it.


createAsyncMicroStore

Create an async wrapper around creteMicroStoreCollector with an onInit async function to pass into the options, in case your store/s need to be initialized with data from async resources as example indexedDB.

Syntax

function createAsyncMicroStore(options: MicroCollectorStoreOptions): MicroAsyncStore

Returns

  • MicroAsyncStore
    • An object containing stores hooks to interact with the micro stores.

Example:

import { createAsyncMicroStore } from '@pastweb/tools';
import { useCounterStore, useUserStore, useThemeStore } from '.../somewhere';

const useAsyncStores = createAsyncMicroStore({
  name: 'appStores',
  stores: [useCounterStore, useUserStore, useThemeStore],
  timeout: 15000,
  onInit: async (collectedStores) => {
    console.log('Initializing stores...', Object.keys(collectedStores));
    // Example: load user data after stores are collected
    await fetchInitialData(collectedStores.user);
  },
});

// Usage in app bootstrap
await useAsyncStores.init();

// Now safe to use stores
const counter = useAsyncStores.store.counter();
const user = useAsyncStores.store.user();

// Or wait for readiness
await useAsyncStores.isReady;

createEventEmitter

Creates an event emitter that allows subscribing to events, emitting events, and removing event listeners. It allows you to create a custom event system where you can emit events, subscribe to events with callback functions, and remove event listeners. Each listener is assigned a unique key, which is used to manage and remove listeners efficiently.

Syntax

function createEventEmitter(): EventEmitter;

Returns

  • EventEmitter
    • An object containing methods to interact with the event emitter.

Methods

  • emit(eventName: string, ...args: any[]): void

    • Emits an event, calling all subscribed event listeners with the provided arguments.
    • eventName: string
      • The name of the event to emit.
    • ...args: any[]
      • Arguments to pass to the event listeners.
  • on(eventName: string, eventCallback: EventCallback): RemoveListener

    • Subscribes an event listener to a specific event.
    • eventName: string
      • The name of the event to subscribe to.
    • eventCallback: EventCallback
      • The callback function to execute when the event is emitted.
    • Returns: RemoveListener
      • An object with a removeListener method to unsubscribe from the event.
  • removeListener(eventCallbackKey: symbol): void Removes an event listener using its unique key.

    • eventCallbackKey: symbol
      • The unique key for the event callback to remove.

Example:

import { createEventEmitter } from '@pastweb/tools';

const emitter = createEventEmitter();
const listener = emitter.on('event', (data) => console.log(data));
emitter.emit('event', 'Hello, World!');
listener.removeListener();

createLangAsyncStore

Creates a language asynchronous store with i18next integration for managing translations. The createLangAsyncStore function provides a flexible way to manage multiple languages in your application using i18next with async initialisation, in case ,as example you need to initialise the store getting or setting data to an async resource indexedDB. It supports:

  • Initialization with an initial language.
  • Dynamic support for multiple languages.
  • Integration with translation resources.
  • Custom plugins for i18next. The store is asynchronous and ensures that the language settings and resources are ready before allowing operations like language switching. It is designed to work seamlessly with both synchronous and asynchronous workflows.

Syntax

function createLangAsyncStore(options: LangOptions): LangAsyncStore;

Parameters

  • options: LangOptions
    • Configuration options for the language store. This includes initial language settings, supported languages, translation resources, and additional i18next options.

Returns

  • LangAsyncStore
    • The created language store, which integrates i18next and provides methods for managing translations and changing the language.

Methods and Properties

  • store.i18n: i18n

    • The i18next instance used for managing translations.
  • store.supported: string[] | Promise<string[]>

    • An array of supported languages. If an asynchronous function is provided, it returns a promise that resolves with the supported languages.
  • store.current: Promise<string>

    • A promise that resolves with the current language.
  • store.t: TFunction

    • A translation function provided by i18next.
  • store.changeLanguage(lng: string | undefined, callback?: Callback): Promise<TFunction<'translation', undefined>>

    • Changes the current language of the store and triggers any specified callback or the store's onLangChange function.

    • lng: string | undefined

      • The language code to switch to.
    • callback: Callback

      • An optional callback function that is called after the language is changed.
    • Returns: Promise<TFunction<'translation', undefined>>

      • A promise that resolves with the i18next translation function after the language is changed.

Example:

$ npm i -S i18next
import { createLangAsyncStore } from '@pastweb/tools/createLangAsyncStore';

const langStore = createLangAsyncStore({
  initLang: 'en',
  supported: ['en', 'fr', 'es'],
  translations: { en: { translation: { key: 'value' } } },
  i18n: { fallbackLng: 'en' },
});

langStore.changeLanguage('fr').then((t) => {
  console.log(t('key')); // Outputs the translation for 'key' in French
});

createMatchSchemeAsyncStore

Syntax

function createMatchSchemeAsyncStore(options?: SchemeOptionsAsyncStore): ColorSchemeAsyncStore;

Description

Creates an asynchronous store for managing color schemes.
This function initializes an asynchronous store specifically for handling
color scheme preferences and system theme detection. It integrates with
createMatchScheme to track and manage color mode changes.

Parameters

options (optional)

Type: SchemeOptionsAsyncStore
Configuration options for the asynchronous store.

| Property | Type | Default | Description | |---------------|-----------------------|----------------------|-------------| | storeName | string | "ColorSchemeStore" | The name of the store. | | datasetName | string \| false | false | The dataset attribute name for storing the color scheme. If false, it uses CSS class names instead. | | defaultMode | string | "auto" | The default mode ('auto', 'light', or 'dark'). | | initStore | (matchScheme: MatchScheme) => Promise<void> | noop | An asynchronous function that runs during store initialization. |

Returns

Type: ColorSchemeAsyncStore
An object that provides methods and properties for managing color schemes asynchronously.

Properties

matchScheme

Type: MatchScheme
Manages color scheme detection and provides methods to get or change the scheme.

init

Type: () => void
A no-op function for initialization.

setStoreReady

Type: () => void
Marks the store as ready after initialization.

Example Usage

const colorSchemeStore = createMatchSchemeAsyncStore({
  defaultMode: 'auto',
  datasetName: 'theme',
  initStore: async (matchScheme) => {
    console.log('Initializing with:', matchScheme.getInfo());
  }
});

debounce

Creates a debounced function that delays invoking fn until after timeout milliseconds have elapsed since the last time the debounced function was invoked. The debounced function includes methods cancel and flush to cancel delayed invocation and to immediately invoke them, respectively.

Syntax

function debounce(fn: DebouceCallback, timeout?: number): DebouceCallback;

Parameters

  • fn: DebouceCallback
    • The function to debounce.
  • timeout: number (optional, default: 300)
    • The number of milliseconds to delay.

Returns

  • DebouceCallback

Example:

import { debounce } from '@pastweb/tools';

const debouncedLog = debounce((msg: string) => console.log(msg), 500);

debouncedLog('Hello');  // Will log 'Hello' after 500 milliseconds if not called again within this time.
debouncedLog.cancel();  // Cancels the delayed invocation.
debouncedLog.flush();   // Immediately invokes the delayed function.

throttle

Returns a throttle function defined in the fn parameter, which is executed for each timeout passed as the second parameter. The returned throttle function includes two members:

  • cancel: A function to stop the throttling of the function.
  • flush: A function to flush the timeout.

Syntax

function throttle(fn: ThrottleCallback, timeout?: number): ThrottleCallback;

Parameters

  • fn: ThrottleCallback
    • The function to run.
  • timeout: number (optional, default: 300)
    • The timeout gap in milliseconds.

Returns

  • ThrottleCallback
    • The throttle callback function. Example:
import { throttle } from '@pastweb/tools';

const throttledLog = throttle((msg: string) => console.log(msg), 500);

throttledLog('Hello');  // Will log 'Hello' immediately.
throttledLog('World');  // Will not log 'World' if called within 500 milliseconds.
throttledLog.cancel();  // Cancels the throttling.
throttledLog.flush();   // Flushes the timeout, allowing the function to be invoked immediately.

Browser functions

createMatchDevice

Creates a utility for detecting and managing device types based on user agent strings and media queries. The createMatchDevice function is designed to help detect device types based on user agent strings and media queries. This utility is particularly useful for responsive design and ensuring that your application behaves differently depending on the device being used.

  • Device Detection: The utility supports both user agent string matching and media query matching to determine device types.
  • Server-Side Rendering (SSR): If server-side rendering is detected (isSSR), user agent-based detection is used, and media query-based detection is skipped.
  • Dynamic Updates: The utility can respond to changes in media query matches, allowing dynamic updates to the device state.
  • Event Emitter: The underlying event emitter allows you to listen for specific device match changes, enabling reactive design and behavior changes.

Syntax

function createMatchDevice(config: DevicesConfig = {}): MatchDevice;

Parameters

  • config: DevicesConfig
    • An optional configuration object that maps device names to their detection criteria. Each device's configuration can include a user agent test and/or a media query.

Returns

  • MatchDevice
    • An object with methods for getting the current matched devices, setting change listeners, and listening for specific device match events.

Methods

  • getDevices(): MatchDevicesResult

    • Returns an object representing the current state of device matches. Each key in the object corresponds to a device name, and the value is a boolean indicating whether the device matches the criteria.
  • onChange(fn: (devices: MatchDevicesResult) => void): void

    • Sets a callback function to be executed whenever the device match state changes. The callback receives an updated MatchDevicesResult object.
    • fn: (devices: MatchDevicesResult) => void
      • The callback function to be called on device state change.
  • onMatch(isDeviceName: string, fn: (result: boolean, deviceName: string) => void): void

    • Sets a listener for a specific device match event. The callback is triggered whenever the specified device's match state changes.
    • deviceName: string
      • The name of the device to listen for.
    • fn: (result: boolean, isDeviceName: string) => void
      • The callback function to be called when the device match event occurs.

Example:

import { createMatchDevice } from '@pastweb/tools';

const deviceConfig = {
  mobile: {
    userAgent: /Mobile|Android/i,
    mediaQuery: '(max-width: 767px)',
  },
  tablet: {
    mediaQuery: '(min-width: 768px) and (max-width: 1024px)',
  },
};

const matchDevice = createMatchDevice(deviceConfig);

matchDevice.onChange((devices) => {
  console.log('Device states updated:', devices);
});

matchDevice.onMatch('mobile', (deviceName) => {
  console.log('Mobile device match changed:', deviceName);
});

const currentDevices = matchDevice.getDevices();
console.log('Current matched devices:', currentDevices);

Here is the Markdown documentation in the same style as the "isType" function documentation:


createMatchScheme

Syntax

function createMatchScheme(config?: SchemeOptions): MatchScheme;

Description

Creates a match scheme manager that allows setting and tracking the color scheme mode.
It detects system preferences, provides methods to update the mode, and notifies listeners of changes.

Parameters

config (optional)

Type: SchemeOptions
An object containing configuration options for the match scheme.

| Property | Type | Default | Description | |---------------|----------|----------|-------------| | defaultMode | string | "auto" | The initial color mode: 'auto', 'light', or 'dark'. | | datasetName | string \| false | false | The dataset attribute name used to store the color scheme in the root element. If false, it uses CSS class names instead. |

Returns

Type: MatchScheme
An object with methods to manage and listen to scheme changes.

Methods

getInfo

getInfo(): { mode: string; system: string; selected: string };

Description:
Retrieves the current color scheme information.

Returns: | Property | Type | Description | |------------|--------|-------------| | mode | string | The currently set mode ('auto', 'light', or 'dark'). | | system | string | The system's detected color scheme ('light' or 'dark'). | | selected | string | The active mode (either mode or the detected system scheme if mode is 'auto'). |

Example:

const scheme = createMatchScheme();
console.log(scheme.getInfo()); 
// { mode: 'auto', system: 'light', selected: 'light' }

setMode

setMode(mode: string): void;

Description:
Updates the color mode. If 'auto' is selected, the mode will follow the system's preference.

Parameters: | Name | Type | Description | |--------|--------|-------------| | mode | string | The new mode: 'auto', 'light', or 'dark'. |

Example:

scheme.setMode('dark'); 
console.log(scheme.getInfo()); 
// { mode: 'dark', system: 'light', selected: 'dark' }

onModeChange

onModeChange(fn: (mode: string) => void): void;

Description:
Registers a callback that is triggered when the mode changes.

Parameters: | Name | Type | Description | |------|------|-------------| | fn | (mode: string) => void | A callback function that receives the new mode. |

Example:

scheme.onModeChange((mode) => {
  console.log(`Mode changed to: ${mode}`);
});
scheme.setMode('light'); 
// Logs: "Mode changed to: light"

onSysSchemeChange

onSysSchemeChange(fn: (mode: string) => void): void;

Description:
Registers a callback that triggers when the system's preferred color scheme changes.

Parameters: | Name | Type | Description | |------|------|-------------| | fn | (mode: string) => void | A callback function that receives the new system scheme ('light' or 'dark'). |

Example:

scheme.onSysSchemeChange((systemMode) => {
  console.log(`System scheme changed to: ${systemMode}`);
});

Example Usage

const scheme = createMatchScheme({ defaultMode: 'auto', datasetName: 'theme' });

console.log(scheme.getInfo()); 
// { mode: 'auto', system: 'dark', selected: 'dark' }

scheme.onModeChange((mode) => {
  console.log(`Color mode changed to: ${mode}`);
});

scheme.setMode('light');
// Logs: "Color mode changed to: light"

createStorage

Creates a versatile storage utility that supports both IndexedDB and localStorage. This utility allows for custom storage handling, default settings, and hooks for various operations.

Syntax

function createStorage(config: StorageConfig = {}): Storage;

Parameters

  • config: StorageConfig
    • An object containing configuration options for the storage utility. The available options include:
    • dbName: string (optional)
      • The name of the database when using IndexedDB. Default is 'storage'.
    • storeName: string (optional)
      • The name of the object store within the database when using IndexedDB. Default is 'storage'.
    • type: 'indexedDB' | 'localStorage' (optional)
      • The type of storage to use. Defaults to 'indexedDB' if supported; otherwise, it falls back to 'localStorage'.
    • defaultSettings: Record<string, any> (optional)
      • An object representing default settings to be applied when the store is first created.
    • onSet: Record<string, (storage: Storage, value: any, store: boolean) => Promise<any>> (optional)
      • Hooks to run custom logic when a value is set in the store.
    • onGet: Record<string, (storage: Storage, value: any) => Promise<any>> (optional)
      • Hooks to run custom logic when a value is retrieved from the store.
    • onRemove: Record<string, (storage: Storage, path: string, justLocalStorage: boolean) => Promise<void>> (optional)
      • Hooks to run custom logic when a value is removed from the store.

Returns

  • Storage
    • An object with methods for interacting with the storage, including getting, setting, and removing data.

Methods

  • storage.get(path: string): Promise<any> Retrieves a value from the storage.

    • path: string
      • The path to the value in the storage.
    • Returns: Promise<any>
      • A promise that resolves to the stored value.
  • storage.set(path: string, value: any, store = false): Promise<void> Sets a value in the storage.

    • path: string
      • The path to store the value at.
    • value: any
      • The value to store.
    • store: boolean (optional)
      • Whether to store the value in the underlying storage (e.g., IndexedDB or localStorage). Default is false.
    • Returns: Promise<void>
      • A promise that resolves once the value is set.
  • storage.remove(path: string, justLocalStorage = false): Promise<void> Removes a value from the storage.

    • path: string
      • The path to remove.
    • justLocalStorage: boolean (optional)
      • Whether to only remove the value from local storage. Default is false.
    • Returns: Promise<void>
      • A promise that resolves once the value is removed.
  • storage.isStored(path: string): boolean Checks if a specific path is stored in the storage.

    • path: string
      • The path to check.
    • Returns: boolean
      • True if the path is stored, false otherwise.
  • storage.isStoreReady: Promise<true>

    • A promise that resolves when the storage is fully initialized and ready to be used.

Example:

import { } from '@pastweb/tools';

const storage = createStorage({
  dbName: 'myDatabase',
  storeName: 'myStore',
  type: 'indexedDB',
  defaultSettings: { theme: 'dark' },
 });
 
 // Set a value in storage
 await storage.set('theme', 'light');
 
 // Get a value from storage
 const theme = await storage.get('theme');
 
 // Remove a value from storage
 await storage.remove('theme');

createViewRouter

The createViewRouter function is a core utility for managing routing in a single-page application (SPA). It provides the ability to define routes, navigate between them, and react to route changes within the application. The ViewRouter history library covering the most common functionalities implemented in other router UI Frameworks like react-router or vue-router. The goal of this implementation is to obtain a consistant set of API and terminology cross framework.

Syntax

function createViewRouter(options: RouterOptions): ViewRouter;

Parameters

  • options: RouterOptions
    • An object containing configuration options for the router. The available options include:
    • base: string (optional)
      • The base path for all routes.
    • debug: boolean (optional)
      • If true, enables debug logging for the router.
    • history: History (optional)
      • The history object for managing session history.
    • routes: Route[] (mandatory)
      • An array of route definitions.
    • preloader: () => void (optional)
      • A function to execute before a route is loaded.
    • RouterView: Component (mandatory)
      • The component to render for matched routes.
    • beforeRouteParse: (route: Route) => Route | void | Promise<Route | void> (optional)
      • A function to execute before parsing a route, if you want to modify a Route.
    • beforeRouteSelect: (route: SelectedRoute) => SelectedRoute | void | Promise<SelectedRoute | void> (optional)
      • A function to execute before selecting a route, as example for the route authentication/authirization.
    • sensitive: boolean (optional)
      • If true, route matching will be case-sensitive.

Returns

  • ViewRouter
    • An object that represents the router. This object contains properties and methods to manage routing within the application.

Example:

import { createViewRouter } from '@pastweb/tools';
import { RouterView } from '@pastweb/x';

const router = createViewRouter({
  routes: [
    { path: '/', component: HomePage },
    { path: '/about', component: AboutPage },
  ],
  preloader: MyProloaderComponent,
  RouterView,
});

Note : pastweb/x is intended to be a specific framework package (react, preact, vue, svelte ...).

Core Features

  • Route Parsing and Matching:
    • The router parses and normalizes routes, creating a structure that allows efficient matching of paths against the defined routes.
  • Event-Driven:
    • It uses an event emitter to notify listeners about route changes or when new routes are added.
  • Navigation:
    • The router offers methods to programmatically navigate, push, replace, or go back and forward in the history stack.
  • Base Path Management:
    • Allows setting and managing a base path, which is useful for applications hosted under subdirectories.
  • Route Preloading:
    • Supports route preloading, enabling efficient loading of route components.
  • Custom Hooks:
    • Provides hooks (beforeRouteParse, beforeRouteSelect) that allow custom logic to be executed during route parsing and selection.

Example:

  beforeRouteParse: async (route) => {
    // You can now do async work (API calls, config loading, etc.)
    const extraData = await fetch(`/api/route-config${route.path}`);
    return { ...route, meta: { ...route.meta, extraData } };
  },

  beforeRouteSelect: async (route) => {
    if (route.path === '/admin' && !(await isUserAdmin())) {
      return { ...route, redirect: '/login' }; // or throw new Error(...)
    }
    return route;
  }

Methods

  • setBase(base: string): Promise<void>
    • Sets the base path for the router. The base path is the common prefix for all routes.
  • addRoute(route: Route): Promise<void>
    • Adds a new route to the router dynamically after the router has been initialized.
  • onRouteChange(fn: (route: SelectedRoute) => void): RemoveListener
    • Subscribes to route change events. The provided callback function will be called whenever the route changes.
  • onRouteAdded(fn: (routes: Route[]) => void): RemoveListener
    • Subscribes to route added events. The provided callback function will be called whenever a new route is added to the router.
  • navigate(path: string, state?: any): Promise<void>
    • Navigates to a specific path programmatically.
  • push(path: string, state?: any): Promise<void>
    • Pushes a new state onto the history stack and navigates to the specified path.
  • replace(path: string, state?: any): void
    • Replaces the current state in the history stack with a new state and navigates to the specified path.
  • go(delta: number): void
    • Moves forward or backward in the history stack by a specified number of steps.
  • setSearchParams(searchParams: URLSearchParams): void
    • Sets the search parameters for the current location without reloading the page.
  • setHash(hash?: string): void
    • Sets the hash for the current location without reloading the page.
  • getRoute(pathname: string): Promise<Route | false>
    • Find and return the current route or false for not route found.
  • setRequest(request: ServerRequest): Promise<void>
    • Sets a new location and refreshes the current route. Useful in SSR context to initialize the router with the server request URL.
  • getRouterLink(options: RouterLinkOptions): RouterLink
    • Creates a router link object that contains methods for navigation and checks if the link is active or exactly active.

Edge Cases

  • No Matching Route:
    • If no route matches the current path, the router will warn in the console and return a default empty route.
  • Base Path Changes:
    • When the base path is changed, the router adjusts all existing routes accordingly to ensure consistent matching.

Debugging If the debug option is enabled, the router logs detailed information about its internal state, such as the current paths, parsed routes, and the selected route. This can be helpful for debugging route configuration issues.


Route Object

The Route Object contains the information to define a route for ViewRouter.

Syntax

interface Route {
  path: string;
  redirect?: string;
  view?: View;
  views?: Record<string, View>;
  children?: Route[];
  [optionName: string]: any;
};

Props

  • path: string
    • the path string description for the route match.
  • redirect: string (optional)
    • the URL to be redirected if the route match the path rule.
  • view: View = any | (() => Promise<{ default: any, [prop: string]: any }>) (optional)
    • the View component or a function returning the View component module exported as default.
  • views: Record<string, View> (optional)
    • An Object of named views to be handled from a RouterView component.
  • children: Route[] (optional)
    • An array of nested Routes.

The Route object can be extended with any other custom property which will be present in the SelectedRoute structure as described below:

Example:

const routes: Route[] = [
  {
    path: '/home',
    view: HomeComponent,
    icon: 'homeIcon',
  },
  {
    path: '/category/:name',
    view: CategoryComponent,
    icon: 'categoryIcon',
    children: [
      {
        path: '/product/?:id',
        view: ProductComponent,
      }
    ],
  },
  {
    path: '/',
    redirect: '/home',
  },
];

Parameters

The parameters declared in the roue path will be present in the SelectedRoute structure described below under the property params. | Syntax | Meaning | Example Path | Resulting Params | |-------------------------|----------------------------------|-------------------------------|------------------| | :name | Required parameter | /user/john | { name: 'john' } | | ?:surname | Optional parameter | /user/john or /user/john/doe | { name: 'john', surname?: 'doe' } | | :surname? | Optional parameter (alternative) | /user/john or /user/john/doe | { name: 'john', surname?: 'doe' } | | *slug | Catch-all (rest) parameter | /user/john/profile/edit | { name: 'john', slug: ['profile', 'edit'] } | | ?*slug | Optional catch-all | /user/john or /user/john/a/b | { name: 'john', slug?: [...] } | | *slug? | Optional catch-all (alternative) | /user/john or /user/john/a/b | { name: 'john', slug?: [...] } |

When the browser URL will match one of the Routes, the SelectedRoute will be available in the router.currentRoute property having this structure:

interface SelectedRoute {
  parent: SelectedRoute | boolean;
  regex: RegExp;
  path: string;
  params: RouteParams;
  searchParams: URLSearchParams;
  setSearchParams: (params: URLSearchParams) => void;
  hash: string;
  setHash: (hash?: string) => void;
  views: Record<string, View>;
  options: RouteOptions;
  child: SelectedRoute | boolean;
}

In the example above the icon property will be present in the options parameters, (router.currentRoute.options.icon).


filterRoutes

The filterRoutes function filters a list of routes based on specified criteria. It allows you to filter out routes that do not meet the conditions defined in the provided filter descriptor.

Syntax

function filterRoutes(routes: Route[] = [], filter: FilterDescriptor = {}): Route[];

Parameters

  • routes: Route[] (default: [])
    • An array of route objects to be filtered. Each Route object represents a route in the application and may contain properties such as path, component, redirect, children, and others.
  • filter: FilterDescriptor
    • An object describing the filter criteria. The keys in this object represent the properties of the Route objects to filter on, and the values are the criteria that those properties must match. The value can be a specific value to match or a function that returns a boolean indicating whether the route matches the criteria.

Returns

  • Route[]:
    • An array of Route objects that match the filter criteria. If a route has children, the function will recursively filter them based on the same criteria. If no routes match, an empty array is returned.

Example:

import { filterRoutes, type Route } from '@pastweb/tools';

const routes: Route[] = [
  { path: '/home', component: HomeComponent },
  { path: '/about', component: AboutComponent, hideInPaths: true },
  { path: '/user/:id', component: UserComponent },
];

const filter = { component: HomeComponent };

const filteredRoutes = filterRoutes(routes, filter);
console.log(filteredRoutes); 
// Outputs: [{ path: '/home', component: HomeComponent }]

routeDive

The routeDive function is designed to traverse a nested route structure and return the route found at a specified depth. This is useful in scenarios where routes have nested children, and you need to access a route at a certain level within that hierarchy.

Syntax

function routeDive(route: SelectedRoute, depth: number): SelectedRoute;

Parameters

  • route: SelectedRoute
    • The initial SelectedRoute object representing the current route from which the traversal begins. This route may contain nested child routes.
  • depth: number
    • The number of levels to traverse into the nested route structure. A depth of 0 returns the initial route, while a higher depth traverses deeper into the nested child routes.

Returns

  • SelectedRoute:
    • The SelectedRoute object located at the specified depth. If the specified depth exceeds the available levels of nesting, the function returns the deepest child route available.

Example:

import { routeDive, type SelectedRoute } from '@pastweb/tools';

const currentRoute: SelectedRoute = {
  path: '/parent',
  child: {
    path: '/parent/child',
    child: {
      path: '/parent/child/grandchild',
    },
  },
};

const grandchildRoute = routeDive(currentRoute, 2);
console.log(grandchildRoute.path); // Output: '/parent/child/grandchild'

Edge Cases

  • Zero Depth:
    • If the depth parameter is 0, the function returns the initial route without any traversal. Exceeding Depth:
    • If the specified depth is greater than the actual number of nested levels, the function returns the last available child route.

Practical Use Cases

  • View Rendering:
    • In a UI framework where different views are rendered based on the current route, routeDive can be used to determine which nested route corresponds to the current view depth.
  • Breadcrumb Navigation:
    • For generating breadcrumb navigation, routeDive can help in identifying the route at different levels, enabling dynamic breadcrumb creation.

Example of Nested Route Traversal Given a route structure with multiple levels of nesting, routeDive will traverse through each level until it either reaches the specified depth or the deepest available route. This allows developers to dynamically access deeply nested routes without manually iterating through each level.


Date and Time

isDateYoungerOf

The isDateYoungerOf function checks whether a given date is younger (i.e., more recent) than a specified duration. The duration is provided as a string composed of multiple time components such as years, months, days, hours, minutes, and seconds.

Syntax

function isDateYoungerOf(date: Date, duration: string): boolean;

Parameters

  • date: Date
    • The date object to be checked against the specified duration.
  • duration: string
    • A string representing the duration composed of various time units:
      • Y for years
      • M for months
      • D for days
      • h for hours
      • m for minutes
      • s for seconds
  • The string can contain multiple components, e.g., "2Y3M1D" for 2 years, 3 months, and 1 day.

Returns

  • boolean:
    • Returns true if the given date is younger than the specified duration relative to the current date and time. Returns false otherwise.

Example:

import { isDateYoungerOf } from '@pastweb/tools';

const date = new Date();
date.setDate(date.getDate() - 1); // 1 day ago
console.log(isDateYoungerOf(date, '1D')); // Output: true
console.log(isDateYoungerOf(date, '2D')); // Output: true
console.log(isDateYoungerOf(date, '12h')); // Output: false

Edge Cases

  • Past and Future Dates: The function checks the date against the current date and time, so it works for both past and future dates relative to now.
  • Zero or Negative Durations: If the duration components result in zero or negative values, the function will consider the date as not younger and will return false.

Element functions

cl

Combines class names using the clsx library.

Syntax

function cl(...args: ClassValue[]): string;

Parameters

  • ...args: ClassValue[]
    • A list of class values to combine. Each ClassValue can be a string, an object, or an array.

Returns

  • string
    • The combined class names as a single string.

Example:

import { cl } from '@pastweb/tools';

const classNames = cl('btn', { 'btn-primary': true }, 'extra-class');
// Output: 'btn btn-primary extra-class'

Methods

  • cl.setClasses
    • Sets custom CSS module classes and returns a function to combine class names with these classes.

Syntax

cl.setClasses(classes: CSSModuleClasses | CSSModuleClasses[], mode: 'merge' | 'replace' = 'merge'): (...args: ClassValue[]) => string;

Parameters

  • classes: CSSModuleClasses | CSSModuleClasses[]

    • An object or array of objects representing CSS module classes to use for mapping class names.
  • mode: 'merge' | 'replace' (optional) The mode for combining classes:

    • 'merge': Combines the custom classes with the existing classes.
    • 'replace': Replaces existing class names with the custom classes.

Returns

  • (...args: ClassValue[]) => string A function that takes class values as arguments and returns the combined class names as a string.

Throws

  • Error Throws an error if a provided class object is not a valid object.

The setClasses method returns a function which it works as the cl function, but returns the scoped classes presents in the CSS Module if present or the class string itself if not.

Example:

import { cl } from '@pastweb/tools';

const cssModules = {
  'btn': 'btn_hash',
  'btn-primary': 'btn-primary_hash',
};

const cls = cl.setClasses(cssModules);
const classNames = cls('btn', 'btn-primary', 'some-other-class');
// Output: 'btn_hash btn-primary_hash some-other-class'

It is possible combine the classes of multiple CSS Modules:

Example:

import { cl } from '@pastweb/tools';

const cssModules1 = {
  'btn': 'btn_hash1',
  'btn-primary': 'btn-primary_hash1',
};

const cssModules2 = {
  'btn-primary': 'btn-primary_hash2',
};

const clsMerge = cl.setClasses([ cssModules1, cssModules2 ], 'merge' /** you can omit the second parameter as it is 'merge' by default */);
const classNames = clsMerge('btn', 'btn-primary');
// Output: 'btn_hash1 btn-primary_hash1 btn-primary_hash2'

const clsReplace = cl.setClasses([ cssModules1, cssModules2 ], 'replace');
const replacedClassNames = clsReplace('btn', 'btn-primary');
// Output: 'btn_hash1 btn-primary_hash2'

Or is it possible make a composition with different ClassProcessor. Key Features:

  1. Type Definition: Added ClassProcessor interface to define the shape of our function with both the call signature and setClasses method.
  2. Composable setClasses: Each setClasses call:
  • Creates a new processor function
  • Maintains its own classes and mode
  • Returns a new function with its own setClasses method
  • Concatenates classes when composing

Example:

import { cl } from '@pastweb/tools';
// Basic usage
cl('btn', 'active'); // 'btn active'

// Single module
const module1 = { btn: 'btn_123', active: 'active_456' };
const cl1 = cl.setClasses(module1);
cl1('btn', 'active'); // 'btn_123 active_456'

// Multiple modules composition
const module2 = { btn: 'btn_789', hover: 'hover_abc' };
const cl2 = cl1.setClasses(module2);
cl2('btn', 'hover'); // 'btn_123 btn_789 hover_abc'

// Different modes
const cl3 = cl2.setClasses({ btn: 'btn_xyz' }, 'replace');
cl3('btn', 'active'); // 'btn_xyz active_456'

// Each instance remains independent
cl('btn');     // 'btn'
cl1('btn');    // 'btn_123'
cl2('btn');    // 'btn_123 btn_789'
cl3('btn');    // 'btn_xyz'

// Example CSS modules
const module1 = { foo: 'foo_1', bar: 'bar_1' };
const module2 = { foo: 'foo_2', baz: 'baz_2' };
const module3 = { bar: 'bar_3' };

// Chained setClasses calls
const cx = cl
  .setClasses(module1, 'merge')        // First set of classes
  .setClasses(module2, 'replace')      // Override with second set
  .setClasses(module3, 'merge');       // Add third set

// Usage
console.log(cx('foo', 'bar', 'baz')); 
// Output depends on final composition, likely "foo_2 bar_3 baz_2"

Benefits:

  1. Chainable: You can keep adding modules with .setClasses().
  2. Immutable: Each call creates a new processor without modifying previous ones.
  3. Flexible: Maintains mode control at each composition level.
  4. Type-safe: TypeScript will properly infer types throughout the chain.

Performance Benefits:

  1. Frequent calls with the same arguments will return cached results.
  2. Each processor instance maintains its own cache.
  3. Reduces computation for repeated class combinations.

createEntry

Creates an entry object with event emitter capabilities and various utility methods to be extended for a specific frontend framework.

An Entry is the shorthend for Entrypoint, to be intended (in this case) as Javascript entrypoint and the DOM mount element where the Javascript Framework should apply its effect. The createEntry function gives an high level interface to other frameworks for implement the mount, unmount and update methods with some additional support for the SSR. For the SSR process, because the Entries could be nested, as example for a framework migration process, and considering different frameworks could have a sync or async function for the Server Side Rendering, the Entry object has other 2 methos to solve this problem.

  • memoSSR(htmlPromiseFunction: () => Promise<string>): void;
    • This method must be used inside the mount method and memorise the HTML string produced from the SSR framework function, returning a unique ssrId.
  • getComposedSSR(): Promise<string>
    • Is an async function wich compose the final HTML string replacing the sseId with the previous memorised HTML for each Entry Object.

Syntax

function createEntry<E extends Entry<O>, O extends EntryOptions>(options?: O): E;

Parameters

  • options: O Options configuration for the entry. The options are of type EntryOptions and may include the following properties:
    • EntryComponent: any (optional)
      • The component to be set as the entry component.
    • entryElement: HTMLElement (optional)
      • The HTML element that represents the entry point in the DOM.
    • querySelector: string (optional)
      • A CSS selector string that can be used to find the entry element within the DOM.
    • initData: Record<string, any> (optional)
      • An object containing initial data to be passed into the entry during its creation.

Returns

  • E
    • The created entry object, which includes event emitter functionalities and various utility methods.

Methods The entry object returned by createEntry includes the following methods:

  • entry.memoSSR(htmlPromiseFunction: () => Promise<string>): void;: Stores the SSR HTML promise function.
    • htmlPromiseFunction: () => Promise<string>: The function that returns an HTML promise.
  • entry.getComposedSSR(): Promise<string>: Composes the SSR HTML from the stored promises.
    • Returns: Promise<string>: The composed SSR HTML.
  • entry.setEntryElement(entryElement: HTMLElement): void;: Sets the entry element.
  • entry.setQuerySelector(querySelector: string): void;: Sets the query selector.
  • entry.setOptions(options: O): void;: Sets the options for the entry.
  • entry.mergeOptions(options: O): void;: Merges the options for the entry.
  • entry.setEntryComponent(Component: any): void;: Sets the entry component.

Events The entry object also has event emitter capabilities with the following methods:

  • on: Registers an event listener.
  • emit: Emits an event.
  • removeListener: Removes an event listener.

the events used to handle the entry are:

  • mount: called when the entry must be mounted to the DOM.
  • update: called when the some data in the entry nust be updated.
  • unmount: called when the entry must be unmounted from the DOM.

Example>

import { createEntry } from '@pastweb/tools';

const entry = createEntry({
  EntryComponent: MyComponent,
  entryElement: document.getElementById('app'),
  querySelector: '#app',
  initData: { key: 'value' },
});

// Usage of the entry object
entry.on('someEvent', () => console.log('Event triggered'));
entry.emit('someEvent');

createPortal

Creates a Portal object that manages the lifecycle of portal entries, including opening, updating, and closing portal instances. Portal is a common term used to identify a mechanism usually implemented in a Front End framework for render and handle components in a not nested DOM element a good example is a rendering of a modal window you can see an example implementation for react, vue or angualr. This function abstract the mechanism in order to have a consistant api cross Frameworks useing the Entry object.

Syntax

function createPortal(
  entry: (props: Record<string, any>, component: any) => Entry<any>,
  defaults?: Record<string, any>
): Portal;

Parameters

  • entry: ((props: Record<string, any>, component: any) => Entry<any>)
    • A function that takes props and a component, returning an Entry object that represents the portal entry. This function defines how the portal entry is created.
  • defaults: Record<string, any> (optional)
    • An optional object containing default properties that will be merged with the props when creating a portal entry. This allows for setting default behavior or configuration for the portal.

Returns

  • Portal An object that provides methods for managing portal entries, such as opening, updating, closing, and removing them.

Example:

import { createPortal } from '@pastweb/tools';
import { MyComponent } from './MyComponent';

const myPortal = createPortal((props, component) => new MyComponent(props), { defaultProp: 'defaultValue' });

const portalId = myPortal.open(MyComponent, { prop1: 'value1' });
myPortal.update(portalId, { prop1: 'newValue' });
myPortal.close(portalId);
myPortal.remove(portalId);

Methods of Portal The returned Portal object contains several methods for managing portal instances:

  • open(component: any, props?: Record<string, any>, defaults?: Record<string, any>): string | false
    • Opens a new portal entry with the specified component and props. Returns the entry ID if successful, or false if the portal could not be opened.
  • update(entryId: string, entryData?: any): boolean
    • Updates an existing portal entry with the given entry ID and new data. Returns true if the update was successful, or false otherwise.
  • close(entryId: string): void
    • Closes the portal entry associated with the given entry ID.
  • remove(entryId: string): boolean
    • Removes the portal entry associated with the given entry ID from the portals cache. Returns true if the removal was successful, or false otherwise.
  • setIdCache(newCache: any): void
    • Sets a new cache for managing entry IDs within the portal.
  • setPortalElement(newElement: HTMLElement | (() => HTMLElement)): void
    • Sets a new portal element or a function that returns the portal element, which is used for rendering the portal's content.
  • setPortalsCache(newPortals: any): void
    • Replaces the current portals cache with a new one.
  • setOnRemove(fn: (entryId: string) => void): void
    • Sets a callback function that will be called whenever a portal entry is removed.

Example with Custom Configuration:

import { createPortal } from '@pastweb/tools';
import { CustomComponent } from './CustomComponent';

const customPortal = createPortal((props, component) => new CustomComponent(props), { color: 'blue' });

const entryId = customPortal.open(CustomComponent, { size: 'large' });
customPortal.setOnRemove(id => console.log(`Removed portal entry with ID: ${id}`));
customPortal.close(entryId);

In this example, a custom portal is created, opened with specific props, and then closed. The setOnRemove method is used to log a message whenever a portal entry is removed.


anchorsSetup

Sets up a structure of portals based on provided anchor IDs, descriptors, and configurations. This function is designed to initialize a tree of portal functions that can manage portal entries across different elements identified by their IDs.

Syntax

function anchorsSetup(
  anchors: PortalAnchorsIds,
  descriptor: EntryDescriptor,
  getEntry: (...args: any[]) => any,
  i