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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@pastweb/react

v1.16.0

Published

Set of tools for react web application development

Downloads

502

Readme

@pastweb/react

Set of tools for react web application development. For a better documentation clarity, the following code examples will consider a project diredtory structure as below:

.
|-- src
|   |-- App
|   |   |-- App.tsx
|   |   `-- Layout
|   |       `-- Layout.tsx
|   |-- lib
|   |   |-- portals.ts
|   |   `-- router.ts
|   |-- react
|   |   |-- components
|   |   |-- getEntry
|   |   |-- portals
|   |   |-- redux
|   |   `-- router
|   `-- Views
|       |-- index.ts
|       |-- Views.tsx
|       `-- Home
|           `-- Home.tsx

Where the alias @ inside the import path is intended to point to the src directory. The reason of this structure is to keep all the Framework indipendent settings in a different code base area (lib) in order to be consistant and reusable even for other frameworks. Also there will be a set of custom hooks with a specific lifecile name in order to be consistant in the code implementation as in the documentation even for other frameworks:

Summary


Async

AsyncComponent

As a code base application can grow in complexity and quantity of code, this component helps to split your bundle using the import() ES6 standard function for the component to be loaded as for its own dependencies if needed.

Props

  • component: () => Promise<any>
  • the function which returns the component module Promise.
  • dependencies: (Dependency | DependencyInfo)[] (optional)
  • an array of dependencies to be loaded before the component rendering.
  • fallback: ReactElement | null (optional)
  • the placehoder component to be rendered waiting the the component and the dependencies a ready.

Example: Immaging we want to load dynamically a react component and a redux reducer. We can extend our AsyncComponent as in the example below using the injectReducer function.

// @/react/components/Async.tsx
import { useRef } from 'react';
import { AsyncComponent, normalizeDependency, Dependency, DependencyInfo, ComponentModule } from '@pastweb/react';
import { injectReducer } from '@/react/redux';

export interface ReducerInfo {
  [reducerName: string]: Dependency | DependencyInfo;
}

export interface AsyncProps {
  component:  () => Promise<ComponentModule>;
  reducer?: ReducerInfo;
};

export function Async(props: AsyncProps) {
  const { component, reducer, ...rest } = props;
  const dep = useRef<undefined | DependencyInfo[]>(((reducer?: ReducerInfo): undefined | DependencyInfo[] => {
    if (!reducer) return;

    const [ reducerName ] = Object.keys(reducer);
    const dependency = normalizeDependency(reducer[reducerName]);
    
    dependency.onSuccess = (reducer: any) => {
      injectReducer(reducerName as string, reducer);
    };

    return [ dependency ];
  })(reducer));

  return (
    <AsyncComponent
      component={component}
      dependencies={dep.current}
      fallback={<div>Loading...</div>}
      {...rest}
    />
  );
}

Then we can use the Async component:

import { Async } from '@/react/components/Async';

export function MyComponent() {
  return (
    <Async
      component={() => import('@/react/components/MyAsyncComponent')}
      reducer={{ myReducer: () => import('@/react/redux/myReducer') }}
    />
  );
}

Below the detail of the normalizeDependency function.


normalizeDependency

The normalizeDependency function standardizes a given dependency into a consistent DependencyInfo structure. This is particularly useful in scenarios where dependencies can be provided in multiple formats, such as functions, promises, or objects, and need to be normalized for consistent handling.

Syntax

function normalizeDependency(dependency: Dependency | DependencyInfo): DependencyInfo;

Parameters

  • dependency: Dependency | DependencyInfo
    • The dependency to be normalized. It can be either:
      • A Dependency: A function that returns a promise or a promise directly.
      • A DependencyInfo: An object containing detailed information about the dependency, including an optional exportName.

Returns

  • DependencyInfo:
    • An object containing the normalized dependency information. The DependencyInfo object includes:
      • dependency: A promise representing the resolved dependency.
      • exportName: A string indicating the name of the export from the module. If not provided, it defaults to 'default'.

createReduxAsyncStore

Generally there is not any need to initialise redux asyncronusly, even if you are using a micro-frontends loader helper as Module Federation or Native Federation cares about it, anyway there are other cases where this functionality is a need, as example if you need to initialise the redux store getting data from indexedDB. The createReduxAsyncStore function sets up and configures an asynchronous Redux store that supports dynamically adding and removing reducers after the store has been created. It also provides hooks for dispatching actions and selecting state within a TypeScript-safe environment.

Syntax

function createReduxAsyncStore(options: ReduxStoreOptions): ReduxAsyncStore;

Parameters

  • options: ReduxStoreOptions
    • An object containing configuration options for the Redux store.
      • settings: object
        • The settings object used to configure the Redux store, passed directly to configureStore from Redux Toolkit.
      • onInit: (store: Store) => Promise<void> | void
        • An optional initialization function that is executed when the store is initialized. This can be used for custom setup logic, such as loading initial data or middleware.

Returns

  • ReduxAsyncStore: An object that represents the custom Redux store with enhanced functionality. It includes:
    • store: The underlying Redux store, with added support for asynchronous reducers.
    • asyncReducers: An object that stores the dynamically added reducers, keyed by their names.
    • useDispatch: A typed hook for dispatching actions in a type-safe manner.
    • useSelector: A typed hook for selecting state from the store, ensuring type safety.
    • init(): A method that initializes the store and executes the onInit function.
      • Initializes the store and executes the optional onInit function provided in the options.
    • addReducer(reducerKey: string, reducer: Reducer): A method for dynamically adding a new reducer to the store.
      • Adds a new reducer to the store, keyed by reducerKey. If a reducer with the same key already exists, it won't be added again.
    • removeReducer(reducerKey: string): A method for dynamically removing an existing reducer from the store.
      • Removes an existing reducer from the store based on the provided reducerKey. If the reducer does not exist, the store remains unchanged.

Example:

$ npm i -S @reduxjs/toolkit
// @/react/redux/index.ts
import { createReduxAsyncStore } from '@pastweb/react';

export const redux = createReduxAsyncStore({
  settings: {
    reducer: { /* initial reducers */ },
  },
  onInit: async (store) => {
    // Custom initialization logic, e.g., loading initial data
  },
});

// Dynamically adding a reducer
redux.addReducer('newFeature', newFeatureReducer);

// Dynamically removing a reducer
redux.removeReducer('oldFeature');

// Using typed hooks in your components
export const injectReducer = redux.addReducer;
export const useSelector = redux.useSelector;
export const useDispatch = redux.useDispatch;

Then in your Providers component you can use the ReduxProvider for the asyncReduxStore:

// @/react/getEntry/Providers.tsx
import type { ReactNode } from 'react'; 
import { ReduxProvider } from '@pastweb/react';
import { redux } from '@/react/redux';

interface ProvidersProps {
  children: ReactNode;
}

export default function Providers({ children }: ProvidersProps) {
  return (
    <ReduxProvider reduxStore={redux} fallback={<div>Loading...</div>}>
      { children }
    </ReduxProvider>
  );
}

ReduxProvider

The ReduxProvider is a React component that ensures your application is wrapped with the Redux Provider only when the asynchronous Redux store is fully initialized. It provides a convenient way to handle the async setup of a Redux store and offers an optional fallback UI to be displayed while the store is preparing as in the example above.

Syntax

function ReduxProvider(props: ReduxProviderProps): JSX.Element;

Props

  • reduxStore: ReduxStore
    • The Redux store object, which includes the isReady promise and store itself.
  • children: React.ReactNode
    • The React elements (usually components) to be rendered inside the Redux Provider once the store is ready.
  • fallback: React.ReactElement (optional)
    • An optional React element to be displayed as a fallback UI while the Redux store is initializing.

Browser

ViewRouter

The ViewRouter use path-to-regexp and history libraries covering the most common functionalities implemented in other router UI Frameworks like react-router. The goal of this implementation is to obtain a consistant set of API and terminology cross framework. You can get more information about ViewRouter here.


router setup

The router setup will be the same regardless the FE framework used. The 2 mandatory options are:

  • routes configuration
  • RouterView componet as is use from the router to handle nested routes.

Example:

// @/lib/router.ts
import { createViewRouter, RouterOptions, Route } from '@pastweb/tools';
import { RouterView } from '@pastweb/react';
import { routes } from '@/views';

const options: RouterOptions = {
  routes: routes as Route[],
  RouterView,
  // other options
};

export const router = createViewRouter(options);

RouterProvider

The RouterProvider component is a React context provider that manages and provides routing-related data to its child components. It integrates with the ViewRouter instance to handle route changes and supplies the current route, router instance, and route depth through React context.

Syntax

function RouterProvider(props: { router: ViewRouter; base?: string; children: ReactNode }): JSX.Element;

Props

  • router: ViewRouter
    • The router instance responsible for managing application routing. This instance should be created and configured outside the component.
  • base: string (Optional)
    • The base path for the routing system. If provided, this value sets the base path for all routes handled by the ViewRouter instance.
  • children: ReactNode
    • The child components that will consume the routing context provided by RouterProvider.

Example:

// @/react/getEntry/Providers.tsx
import type { ReactNode } from 'react'; 
import { router } from '@/lib/router';
import { ProvidersProps } from './types';

interface ProvidersProps {
  children: ReactNode;
}

export default function Providers({ children }: ProvidersProps) {
  return (
    <RouterProvider router={router}>
      { children }
    </RouterProvider>
  );
}

RouterView

The RouterView component dynamically renders a view component based on the current route and the route depth. It supports nested routing by managing the route depth context and provides a mechanism to preprocess the selected route before rendering the view.

Syntax

function RouterView({ name, beforeShow, ...rest }: RouterViewProps): JSX.Element | null;

Props

  • name: string (Optional)
  • The name of the view to render from the views object in the selected route. Defaults to 'default'.
  • beforeShow: (route: SelectedRoute) => SelectedRoute (Optional)
  • A callback function that runs before the view is shown. It receives the selected route and allows for modification of the route (e.g., for conditional logic or preprocessing).
  • rest: Record<string, any> (Optional)
  • Additional props that are passed to the rendered view component.

Description

The RouterView component enables dynamic rendering of views in a nested routing setup. It determines the appropriate view to render by diving into the route structure using the routeDive function and adjusts the route depth context accordingly.

How It Works

  1. Route and Depth Management:

    • The component retrieves the current route using the useRoute hook and calculates the current depth by incrementing the value from useRouteDepth.
  2. Route Selection:

    • The routeDive function is used to traverse the route structure up to the specified depth, ensuring that the correct nested route is selected.
  3. Preprocessing with beforeShow:

    • If the beforeShow prop is provided, it is invoked with the selected route, allowing for any modifications before extracting the view components.
  4. View Component Selection:

    • The appropriate view is determined from the views object in the selected route using the name prop.
  5. Rendering and Context Update:

    • If a matching view is found, it is rendered with the additional props passed to RouterView. The routeDepthContext is updated to reflect the current depth.

Basic Example:

// @/Views/Views.tsx
import { RouterView } from '@pastweb/react';

export function Views() {
  return (
    <RouterView />
  );
}

Using beforeShow for Preprocessing:

// @/Views/Views.tsx
import { RouterView } from '@pastweb/react';

export function Views() {
  const beforeShow = (route) => {
    // Modify the route if necessary
    if (route.meta.requiresAuth && !isLoggedIn()) {
      return { ...route, views: { main: LoginView } };
    }
    return route;
  };

  return (
    <RouterView beforeShow={beforeShow} />
  );
}

Notes

  1. Default View:
    • If no name is provided, the RouterView defaults to rendering the default view from the selected route.
  2. Error Handling:
    • If a view matching the name is not found in the selected route's views object, the component renders null.
  3. Route Depth Context: The routeDepthContext ensures that nested RouterView components correctly manage their depth relative to the root.
  4. Composable with Context:
    • Use alongside other components that consume the routeContext or routerContext for a fully integrated routing solution.

Practical Use Cases

  1. Dynamic Component Rendering:
    • Dynamically load components based on route configuration.
  2. Nested Routing:
    • Handle complex, multi-level routes with ease.
  3. Custom Route Logic:
  • Preprocess routes with the beforeShow prop for authentication, redirection, or custom logic.
  1. Flexible Route Configuration:
    • Support a configurable views structure within routes, enabling modular and reusable routing setups.

RouterLink

The RouterLink component is a custom navigational link designed to work seamlessly with the application's routing system. It enables navigation without triggering a full page reload, supporting features such as route parameters, query parameters, and fragment identifiers.

Syntax

export const RouterLink: React.ForwardRefExoticComponent<
  React.PropsWithoutRef<{
    path: string;
    params?: Record<string, string | number | boolean | null | undefined>;
    searchParams?: URLSearchParams;
    hash?: string;
    className?: string;
    preventNavigate?: boolean;
    children: React.ReactNode;
  }> & React.RefAttributes<HTMLAnchorElement>
>;

Props

  • path: string
    • The target path for the link.
  • params: Record<string, string | number | boolean | null | undefined> (Optional)
    • An object containing route parameters to be interpolated into the path.
  • searchParams: URLSearchParams (Optional)
    • A URLSearchParams object representing query parameters to append to the path.
  • hash: string (Optional)
    • A string representing the fragment identifier (e.g., #section) for the link.
  • className: string (Optional)
    • A string of classes to apply to the anchor (<a>) element.
  • preventNavigate: boolean (Optional)
    • A boolean that, if set to true, prevents navigation when the link is clicked. Defaults to false.
  • ref: React.Ref<HTMLAnchorElement>(Optional)
    • A React ref that is forwarded to the anchor (<a>) element.
  • children: ReactNode

The content to be displayed inside the link.

Basic Link:

<RouterLink path="/home" className="nav-link">
  Home
</RouterLink>

With Route Parameters:

<RouterLink 
  path="/user/:id" 
  params={{ id: 123 }} 
  className="user-link"
>
  View User
</RouterLink>

With Query Parameters:

const searchParams = new URLSearchParams({ q: 'search term', page: '1' });

<RouterLink 
  path="/search" 
  searchParams={searchParams} 
  hash="results" 
  className="search-link"
>
  Search Results
</RouterLink>

Prevent Navigation:

<RouterLink 
  path="/example" 
  preventNavigate={true}
  className="inactive-link"
>
  Inactive Link
</RouterLink>

useLocation

The useLocation hook provides the current location object from the router, updating automatically on route changes.

Returns

  • Location: An object containing information about the current route, such as the path and query parameters.

Example:

const location = useLocation();
console.log(`Current path: ${location.pathname}`);

useNavigate

The useNavigate hook provides a function to programmatically navigate within the application.

Returns

  • navigate(path: string, state?: any): void A function to change routes, optionally passing additional state.

Example:

const navigate = useNavigate();
navigate('/dashboard', { from: 'login' });

usePaths

The usePaths hook filters and returns a list of routes based on specified criteria.

Parameters

  • filter: FilterDescriptor (optional) An object defining the filter criteria. Defaults to {}, returning all routes.

Returns

  • Route[] An array of routes that match the filter criteria.

Example:

const adminPaths = usePaths({ role: 'admin' });
console.log(adminPaths); // Logs routes accessible by an admin

How It Works

  • Retrieves all routes from the router using useRouter.
  • Filters the routes using the filterRoutes utility.
  • Updates the list dynamically when new routes are added.

useRoute

The useRoute hook retrieves the currently active route at the specified depth in the routing hierarchy.

Returns

  • SelectedRoute The active route object at the current depth.

Example:

const currentRoute = useRoute();
console.log(`Current route path: ${currentRoute.path}`);

How It Works

  1. Retrieves the router instance with useRouter.
  2. Determines the route depth using useRouteDepth.
  3. Initializes the current route using routeDive to get the route at the specified depth.
  4. Dynamically updates the route whenever it changes.

useRouteDepth

The useRouteDepth hook retrieves the current route depth from the routeDepthContext.

Returns

  • number The current route depth.

Example:

const depth = useRouteDepth();
console.log(`Current route depth is: ${depth}`);

How It Works

  • Uses the useContext utility to access the routeDepthContext.
  • Ensures that the hook is used within a valid context provider by throwing an error if the context is missing.

useRouter

The useRouter hook provides access to the ViewRouter instance from the routerContext.

Returns

  • ViewRouter The router instance, offering methods like navigation and route management.

Example:

const router = useRouter();
router.navigate('/home'); // Navigate to the '/home' route

How It Works

  • Uses the useContext utility to fetch the ViewRouter instance from the routerContext.
  • Ensures proper usage within a valid context provider by throwing an error if the routerContext is unavailable.

useRouterLink

The useRouterLink hook creates a dynamic link object for routing, including path generation, active state detection, and navigation functionality.

Parameters

  • props: Object containing the following properties:
    • path: string The target path for the link.
    • params: Object of route parameters. (Optional)
    • searchParams: URLSearchParams object for query parameters. (Optional)
    • hash: string representing a fragment identifier (e.g., #section). (Optional)

Returns

An object with the following properties:

  • pathname: string The computed pathname for the link.
  • isActive: boolean Whether the current route matches the link's path.
  • isExactActive: boolean Whether the current route exactly matches the link's path.
  • navigate: function A function to navigate to the path or an alternative route if specified.

Example:

const link = useRouterLink({
  path: '/about',
  params: { id: 123 },
  searchParams: new URLSearchParams('query=test'),
  hash: 'section',
});

// In JSX:
<a href={link.pathname} onClick={link.navigate}>
  Go to About
</a>;

How It Works

  1. Link Creation:
  • Uses router.getRouterLink to generate the link object based on the given path, params, searchParams, and hash.
  1. Route Change Handling:
  • Listens for route changes to update the link's state dynamically.
  1. Navigation:
  • The navigate method facilitates programmatic navigation to the specified route.

useMatchDevice

The useMatchDevice hook provides device matching functionality based on a given configuration. It tracks the matched devices and allows manual updates.

Parameters

  • config: An object of type DevicesConfig defining the criteria for matching devices. This configuration determines which devices are considered a match.

Returns

An object of type DevicesResult with the following properties:

  • devices: The current matched devices as a MatchDevicesResult object.
  • onMatch: A function to manually trigger the matching logic.

Example:

const cvonfig = {
  phone: { mediaQuery: '(max-width: 320px)' },
  tablet: { mediaQuery: '(max-width: 600px)' },
  desktop: { mediaQuery: '(max-width: 1024px)' },
};
const { devices, onMatch } = useMatchDevice(config);

console.log(devices); // Logs the current matched devices
onMatch('phone', (result: boolean: device: string) => console.log(`${device}: ${result}`)); // Manually triggers the matching logic

How It Works

  1. Device Matcher Creation:
  • Uses createMatchDevice to create a matcher instance based on the provided config.
  1. State Management:
  • Tracks the current matched devices using useState.
  1. Updates on Change: Subscribes to the matcher's onChange event to update the state whenever the matched devices change.
  2. Manual Trigger:
  • Exposes onMatch for manually invoking the match logic.

Element

createEntry

The createEntry function simplifies the process of setting up, rendering, and unmounting a React component in a web application. It includes support for asynchronous dependencies and customizable providers.

Parameters

  • options: ReactEntryOptions An object that defines the configuration for the React entry. This includes options for providers, initial data, fallback components, and asynchronous dependencies.

Properties of options:

  1. Providers: React.ComponentType | React.Fragment
  • A wrapper component or React.Fragment to provide context or functionality to the entry component.
  • Default: Fragment.
  1. initData: { [key: string]: any }
  • Initial data passed as props to the entry component.
  1. waitFor: Array<Promise<any>>
  • A list of promises to resolve before rendering the entry component. This allows for data fetching or other asynchronous operations to complete before display.
  1. fallback: React.ReactNode
  • A component or element to render while waiting for the promises in waitFor to resolve.
  • Default: Fragment.

Returns

A ReactEntry object containing methods for managing the lifecycle of the React component. For more info about the Entry Object click here.

Example:

// @/react/getEntry/getEntry.ts
import { createEntry } from '@pastweb/react';
import { redux } from '@/react/redux';
import { Providers } from './Providers';

type EntryParams = {
  entry?: Component | ReactElement;
  props?: Record<string, any>;
  entryElement?: HTMLElement;
};

export function getEntry(params: EntryParams = {}): ReactEntry {
  const { entry, entryElement, props = {} } = params;

  return createEntry({
    entryElement,
    EntryComponent: entry,
    Providers,
    initData: props,
    waitFor: [ redux ],
    fallback: <LoadingSpinner />,
  });
}

// @/main.tsx
import { getEntry } from '@/react/getEntry';
import { App } fgrom './App';

const entry = getEntry({
  entry: App,
  entryElement: document.querySelector('#root') as HTMLElement,
});
// Mount the component
entry.mount();

// Later, unmount it
entry.unmount();

portals

React provide already support for portals, the goal of this implementation is to provide a set of functionalities portals related with consistant apis crtoss framework.


portals setup

Portals Entrys as micro-apps to render the component inside the correct DOM Element called anchor. You need to setup the anchors using generateAnchors function which accept an array of strings representring an Object path . dot separated in order to be better organised.

Example:

// @/lib/portals.ts
import { generateAnchors } from '@pastweb/tools';

export const anchors = generateAnchors([
  'window',
  'slider.menu',
  'slider.view',
  'toaster',
]);

The anchors Object created is an Object organised as below:

{
  window: '_aslkdaj',
  slider: {
    menu: '_sdkdjkp',
    view: '_ndikalq',
  },
  toaster: '_tiubvjs'
}

These strings are unique in the document and will be used as id HTML attribute for the element which will be used for renter the component inside.


PortalsProvider

The PortalsProvider component establishes and manages contexts for handling portals and portal anchors in a React application. It uses the portalsContext and portalAnchorsContext to make portal-related functionality accessible to its descendant components.

Props

  • anchors: { [key: string]: string }
    • A mapping of anchor names to their corresponding DOM identifiers or references.
    • Purpose: Specifies the target locations (anchors) where portals can be rendered.
  • descriptor: object (Optional)
    • Configuration object describing how portals should be managed.
    • Default: {} (an empty object).
  • getEntry: (id: string) => any (Optional)
    • A function to retrieve entries from the portals cache.
    • Purpose: Provides a mechanism for fetching portal-specific data.
  • idChahe Map<string, any> (Optional)
    • The cache for portal IDs, used to store and manage portal instances.
    • Default: DEFAULT_ID_CACHE.
  • portalsCache: Map<string, any> (Optional)
    • The cache for portal instances, storing the content or state of active portals.
    • Default: DEFAULT_PORTALS_CACHE.
  • children: React.ReactNode
    • The child elements that will have access to the portals and portal anchors contexts.

Example:

// @/react/getEntry/Providers.tsx
import { ReduxProvider, PortalsProvider, RouterProvider, ReactEntry } from '@pastweb/react';
import { anchors } from '@/lib/portals';
import { ProvidersProps } from './types';

export default (getEntry: () => ReactEntry) => function Providers({ children }: ProvidersProps) {
  return (
    <PortalsProvider getEntry={getEntry} anchors={anchors}>
      { children }
    </PortalsProvider>
  );
}

How you can see t in the example above the Providers.tsx exports a function getting the the getEntry function as paramenter and returns the Providers component. This is because the PortalsProvider needs the getEntry function to be used the set correctly the Entry object in order to be able to render the component. It is possioble customise the rendered Component with a comonent wrapper as in the example below:

// @/react/portals.ts
import { usePortals as UP, usePortalAnchors as UPA, EntryDescriptor } from '@pastweb/react';
import { getEntry } from '@/react/getEntry';
import { Window } from '@/react/components/Window';
import { PortalAnchorsId } from '@/lib/portals';

export type Portals = {
  window: PortalFunction,
  slider: {
    menu: PortalFunction,
    view: PortalFunction,
  },
  toaster: PortalFunction,
};

export const usePortals = (): Portals => UP<Portals>();
export const usePortalAnchors = (): PortalAnchorsId => UPA<PortalAnchorsId>();

// descriptor definition
export const descriptor: EntryDescriptor = {
  window: () => getEntry({ entry: Window }),
};

Tghe EntryDescriptor object kkeps the same structure of the anchors object, but redefine the getEntry function for thet pecific portal.


usePortalAnchors

The usePortalAnchors hook provides access to the portalAnchorsContext, which manages the identifiers (IDs) of portal anchors in a React application. This hook ensures that components can interact with and utilize the portal anchor IDs efficiently, supporting type safety and customizable context types.

Example:

import { usePortalAnchors } from '@pastweb/react';

function ExampleComponent() {
  // Access the portal anchors context with a custom type
  const portalAnchors = usePortalAnchors<{ mainAnchorId: string }>();

  console.log(`Main anchor ID: ${portalAnchors.mainAnchorId}`);

  return <div>Check the console for the main anchor ID.</div>;
}

usePortals

The usePortals hook provides access to the portalsContext, enabling interaction with the application's portal system. This hook facilitates managing dynamic UI elements such as modals, tooltips, and other overlays.

Syntax

function usePortals<T>(): T

Returns

The current portals context cast to the specified type T.

Example:

import { usePortals } from '@/react/portals';

function ExampleComponent() {
  // Access the portals context with a custom type
  const portals = usePortals<{ modal: { open: (content: JSX.Element) => void } }>();

  const openModal = () => {
    portals.modal.open(<div>My Modal Content</div>);
  };

  return <button onClick={openModal}>Open Modal</button>;
}

usePortal

The usePortal hook provides access to a PortalHandler object, which offers methods and properties for managing and interacting with portals in the application. This utility ensures that the PortalHandler object is initialized before the component mounts, allowing consistent access to portal management functionalities and must be used with the Portal Component.

Returns
  • PortalHandler:
    • An object with methods and properties related to portal management, including an id property and an internal identifier $$portalHandler.

Portal

The Portal component integrates seamlessly with a portal management system, enabling the rendering of its children into specific portal locations. It handles the portal lifecycle through a set of tools provided by the PortalHandler object, including methods to open, update, and close portals.

Props

  • path: string
    • The path identifying the target portal where the content should be rendered.
  • use: PortalHandler
    • A PortalHandler object used to manage the portal's lifecycle. Must include an id property and a $$portalHandler identifier.
  • children: ReactNode
    • The content to render inside the portal.
  • rest: Record<string, any>
    • Additional props to be passed to the rendered content inside the portal.

Example:

import { Portal, usePortal } from '@pastweb/react';

function MyComponent() {
  const tools = usePortal();

  return (
    <>
      <button onClick={() => tools.open()} />
      <Portal path='my.portal.path' use={tools}>
        <div>Content to render in the portal</div>
      </Portal>
    </>
  );
}

Hooks

All the following hooks less useMediator are just a rename for consistant reference cross frameworks,

useBeforeMount

The useBeforeMount hook provides a simple way to execute a function exactly once, before the component mounts. This is particularly useful for performing setup logic that needs to occur before the initial render.

Syntax

function useBeforeMount(fn: () => void): void

Example:

import { useBeforeMount } from '@pastweb/react';

function ExampleComponent() {
  useBeforeMount(() => {
    console.log('Component is about to mount!');
  });

  return <div>Hello, world!</div>;
}

useBeforeUnmount

The useBeforeUnmount hook provides a simple way to execute a function just before a React component unmounts. This is particularly useful for cleanup operations, such as unsubscribing from services, clearing timers, or resetting global states.

Syntax

function useBeforeUnmount(fn: () => void): void

Example:

import { useBeforeUnmount } from '@pastweb/react';

function ExampleComponent() {
  useBeforeUnmount(() => {
    console.log('Component is about to unmount!');
  });

  return <div>Hello, world!</div>;
}

useForceUpdate

The useForceUpdate hook allows you to force a React component to re-render by triggering a state update. This is useful in situations where changes do not automatically trigger a re-render, such as when working with external libraries or non-reactive data sources.

Syntax

export const useForceUpdate = (): () => void;

Example:

import { useForceUpdate } from '@pastweb/react';

function ExampleComponent() {
  const forceUpdate = useForceUpdate();

  return (
    <div>
      <p>Rendered at: {new Date().toLocaleTimeString()}</p>
      <button onClick={forceUpdate}>Force Re-render</button>
    </div>
  );
}

useFunction

The useFunction hook is designed to return a stable, memoized reference of a provided function, preventing unnecessary re-creation across renders. This is especially useful when passing functions as dependencies in useEffect, useMemo, or as props to child components.

Syntax

function useFunction<T extends (...args: any[]) => any>(fn: T): T;

Example:

import { useFunction } from '@pastweb/react';

function ExampleComponent() {
  const memoizedLog = useFunction((message: string) => {
    console.log(message);
  });

  return (
    <button onClick={() => memoizedLog('Button clicked!')}>
      Click Me
    </button>
  );
}

useMediator

The useMediator hook manages a component's state and props using a mediator pattern, which allows centralized state management and logic control. It provides a flexible way to handle complex state and prop interactions while keeping the component logic organized.

Syntax

function useMediator<T extends Mediator>(
  mediator: MediatorFunction,
  props: any & object = {},
  extras: T['extras'] = {} as T['extras'],
): Omit<T, 'state' | 'props' | 'extras'> & { props: T['props'], state: T['state'], extras: T['extras'] };

Type Parameters

  • T: extends Mediator
    • A type that extends the Mediator type, representing the mediator object used for managing state, props, and logic.

Parameters

  • mediator: MediatorFunction

    • A function that initializes and returns a mediator object managing state and logic. The mediator often encapsulates complex business logic.
  • props: any & object = {}

    • Component props passed to the mediator. This defaults to an empty object if no props are provided.
  • extras: T['extras'] = {} as T['extras']

    • Additional data passed to the mediator for handling extra configurations or logic. Defaults to an empty object.

Returns

An object that contains:

  • state: The state managed by the mediator.
  • props: The props passed to the mediator, including the component’s children.
  • extras: The extras passed to the mediator.
  • Additional properties defined by the mediator, excluding state, props, and extras.

Example:

import { useMediator } from '@pastweb/react';

function myMediator(props, extras) {
  const { initialCount } = props;
  const { log } = extras;
  const state = { count: initialCount };

  function incrtement() {
    state.count = state.count + 1;
    if (log) console.log('count:', state.count);
  }

  return {
    state,
    props,
    extras,
    incrtement,
  };
}

function Counter() {
  const { state, increment } = useMediator(myMediator, { initialCount: 0 }, { log: true });
  const { count } = state;

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

useMounted

The useMounted hook is a simple, yet powerful hook that executes a provided effect function only once, when the component mounts. It is particularly useful for performing setup logic or starting side effects such as API calls, subscriptions, or event listeners.

Syntax

function useMounted(fn: EffectCallback): void;

Example:

import { useMounted } from '@pastweb/react';

function ExampleComponent() {
  useMounted(() => {
    console.log('Component mounted');
  });

  return <div>Hello, World!</div>;
}

Utility

setRef

The setRef utility function provides a convenient way to assign values to React refs. It supports both MutableRefObject refs and callback refs, ensuring compatibility with various ref handling patterns in React.

Syntax

function setRef<T>(ref: MutableRefObject<T> | ((ref: T) => void), value: any): void

Example:

import { forwardRef, useCallback } from 'react';
import { setRef } from '@pastweb/react';

const ExampleComponent = forwardRef((props, ref) => {
  const myRef = useCallback((node: null | <HTMLDivElement>) => {
    if (node) {
      node.focus();
      // Set the ref value
      setRef(ref, node);
    }
  }, []);

  return <div ref={myRef}>Hello, world!</div>;
});

License

This project is licensed under the MIT License.This project is licensed under the MIT License.