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

swoop-common

v2.2.164

Published

.# Swoop Library

Downloads

2,336

Readme

.# Swoop Library

This library is used for rendering Swoop itinerary templates. It provides tools for defining custom field types, registering custom components, rendering templates from a MasterSchema, and includes SDKs for all related services. It supports both input mode (for creating templates) and presentation mode (for rendering them for end users). The schema system is stage-aware, enabling precise control over what data is editable or displayed at which stage.

Note: This package is intended for internal use only.


Swoop Library

Initialization

Before using the Swoop Library, you must initialize it with service URLs:

import { init } from "swoop-common";

init({
  coreServiceUrl: "https://your.core.service",
  swoopServiceForwardUrl: "https://your.forward.service",
});

Service Interfaces

The library provides three primary service interfaces to interact with backend systems:

  • SwoopService — Interfaces with the Swoop API.
  • CoreService — For core service.

These interfaces offer convenient methods to work seamlessly with the underlying services required by the itinerary system.

StyledFormView

The StyledFormView component is the entry point for rendering a full itinerary template. It handles schema parsing and renderer injection based on mode and form stage.

import { StyledFormView } from "your-form-library";

<StyledFormView
  initialData={/* object */}
  schema={/* MasterSchema */}
  onChange={(val) => console.log(val)}
  pool="FORM"
  readonly={false}
  stage="Inst"
/>;

Props

| Name | Type | Description | | ----------- | -------------------- | ------------------------------------------------------------------ | | initialData | any | Initial values for the template. Should not be updated frequently. | | schema | MasterSchema | Template definition object. | | onChange | (val: any) => void | Callback with updated data. | | pool | ComponentPool | "FORM" or "PRESENTATION" depending on context. | | readonly | boolean | Disables inputs if true (only relevant in FORM pool). | | stage | Stage | Controls which data segment is being rendered. |

Stages

The template system is divided into stages:

  • Stage.Comp – Data stored on the root component, often static (e.g. metadata, titles). Does not include any dynamic or time-based fields.
  • Stage.Inst – Instance-specific data (e.g. timings, localized notes). This is the most common stage for editable fields.
  • Stage.User – Data unique to individual users (e.g. room number).

Each stage builds on the one before it. For example, Stage.User includes everything from Stage.Comp and Stage.Inst. Fields are editable based on the current stage. If a value is defined in two stages, the lower stage will take priority.


Custom Components

Custom components define how individual fields render. These can behave like typical form inputs or be used for display-only formatting in the PRESENTATION pool.

Example

const FormExample: React.FC<Props> = ({
  text,
  onChange,
  getError,
  label,
  enabled,
}) => {
  const [val, setVal] = useState(text);
  const error = getError ? getError("example")?.message : undefined;
  const onChangeDebounced = useMemo(() => debounce(onChange, 300), [onChange]);

  const update = (value: string) => {
    setVal(value);
    onChangeDebounced(value);
  };

  return (
    <Paper
      sx={{
        display: "flex",
        flexDirection: "column",
        gap: 1,
        p: 2,
        background: "#CBC3E3",
        mb: 1,
      }}
    >
      {!enabled && "THIS IS DISABLED"}
      <Typography variant="h6">{label}</Typography>
      <TextField
        label="Example label"
        value={val}
        onChange={(e) => update(e.target.value)}
        error={!!error}
        helperText={error}
        disabled={!enabled}
      />
    </Paper>
  );
};

const FormRendererExample: React.FC<ControlProps> = ({
  data,
  handleChange,
  path,
  label,
  enabled,
}) => {
  const getError = useLocalErrors(path);
  return (
    <FormExample
      text={data as string}
      onChange={(val) => handleChange(path, val)}
      getError={getError}
      label={label}
      enabled={enabled}
    />
  );
};

registerComponent("example", FormRendererExample, ComponentPool.FORM);
registerComponent("example", FormRendererExample, ComponentPool.PRESENTATION);

Important: You cannot register two components with the same name within the same pool. You can register the same component name across different pools (e.g., "example" in both "FORM" and "PRESENTATION").

Presentation Pool

The PRESENTATION pool is more than just read-only. It is designed for customer-facing output, rendering fields in a clean, non-form-like layout for readability and professionalism.


Custom Types

Custom field types define what kinds of fields can be used when building a template. These appear in the template builder UI as selectable field types and control how data is validated and configured.

Syntax

registerType(
  "typeId", // Unique type string
  "Display Name", // Name shown in template builder
  schema, // JSON Schema defining the data structure
  optionsSchema, // JSON Schema defining configuration data structure
  requiredOptions // boolean: must the options be filled?
);

Example

registerType(
  "enum",
  "Dropdown",
  { type: "array" },
  {
    type: "object",
    title: "Dropdown Options",
    properties: {
      enumValues: {
        title: "Dropdown Values",
        type: "array",
        items: { type: "string" },
      },
    },
  },
  true
);

This type defines a dropdown field where the values are defined via the enumValues property in the template configuration.

Custom Option Editors

If you want to render a custom options block (i.e., how the field type's options are displayed in the template editor), you must do the following:

  1. In the top-level optionsSchema of the type, define "x-type": "yourTypeName"
  2. Create and register a custom component with the name "yourTypeName" in the "FORM" pool.

This component will then be used to render the configuration UI for that field type.


File Locations

  • Custom components must be placed in src/renderers. They may be nested within subfolders. All files inside renderers/ will be automatically imported in the correct order.
  • Custom types must be added to src/default_registration/fields_base.tsx.

No manual import wiring is required beyond placing the file in the correct folder.


Publishing to NPM

To publish a new version of the package:

npm run build             # Compile the package
npm version patch         # Bump the patch version (or use minor/major as needed)
npm adduser               # Log in to NPM (if not already)
npm publish               # Publish the package