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

@capyx/components-library

v0.0.22

Published

Shared React component library for Capyx applications

Readme

Capyx Components Library

The shared React component library for all Capyx applications.

Built with TypeScript and React 19, the library ships fully-typed ESM + CJS bundles. Components are opinionated about their UI stack (see Coupled Dependencies) so that every Capyx app has a consistent look and feel without having to re-configure the same set of libraries.

Architecture

The library is organised into two layers:

Components

Self-contained visual components (currently focused on form inputs, but not restricted to them):

  • CheckInput - Checkbox input for boolean values
  • DateInput - Date picker with formatted string output (using MUI DatePicker)
  • FileInput - File upload with validation and preview
  • RichTextInput - Rich text (WYSIWYG) editor using Quill. Grows with content by default; supports height-constrained / scrollable layouts (e.g. inside a modal)
  • SelectInput - Dropdown selection for single/multiple options
  • SwitchInput - Toggle switch for on/off values
  • TagsInput - Tag management with MUI Autocomplete
  • TextAreaInput - Multiline text input with auto-growing height
  • TextInput - Single-line text input for various types (text, email, password, number, etc.)

Addons (Enhancement Wrappers)

Addons wrap existing components to add behaviour without modifying the base component:

  • AutocompleteInput - Adds autocomplete/suggestions dropdown to text inputs
  • CharacterCountInput - Adds character counting to text, textarea, or editor inputs
  • EditorAddon - Wraps TextAreaInput to add rich text editing (ReactQuill)
  • Editor (Legacy) - Standalone rich text editor (deprecated, use EditorAddon instead)

Coupled Dependencies

The packages below are production dependencies bundled with the library. Every consuming application must have compatible versions installed. They are considered part of the library's core stack and should not be removed or swapped lightly.

UI foundation

| Package | Version | Role | |---|---|---| | react | ^19 | Core framework | | react-bootstrap | ^2 | Layout, forms, modals, and all general UI primitives | | bootstrap | ^5 | CSS layer required by react-bootstrap |

Form management

| Package | Version | Role | |---|---|---| | react-hook-form | ^7 | Form state, validation, and field registration — deeply integrated into most input components |

MUI (advanced components)

| Package | Version | Role | |---|---|---| | @mui/material | ^7 | MUI component primitives (used by TagsInput, SelectInput, etc.) | | @emotion/styled | ^11 | Mandatory styling engine for MUI | | @mui/x-date-pickers | ^8 | Date picker used by DateInput |

Date & time

| Package | Version | Role | |---|---|---| | dayjs | ^1 | Date adapter required by @mui/x-date-pickers | | dateformat | ^5 | Output formatting for DateInput |

Rich text

| Package | Version | Role | |---|---|---| | react-quill-new | ^3 | Quill WYSIWYG editor used by RichTextInput |

Utilities

| Package | Version | Role | |---|---|---| | lodash.debounce | ^4 | Debouncing used in AutocompleteInput |

Features

  • React 19 compatible
  • TypeScript with full type safety and auto-generated type declarations
  • ESM and CommonJS dual module support
  • react-hook-form integration for form state management and validation
  • react-bootstrap for consistent styling
  • Material-UI (MUI) for advanced components (DatePicker, Autocomplete)
  • ✅ Standalone or form-integrated modes
  • ✅ Consistent error handling
  • ✅ Customizable styling

Installation

npm install @capyx/components-library

Peer Dependencies

This library requires the following peer dependencies to be installed in your project:

npm install react react-dom react-hook-form react-bootstrap @mui/material @mui/x-date-pickers dayjs react-quill-new react-autosuggest

TypeScript Support

This library is written in TypeScript and includes full type definitions. Type declarations are automatically provided when you install the package, giving you:

  • Full IntelliSense and autocomplete in your IDE
  • Type checking for component props
  • Improved development experience with inline documentation

No additional @types packages are needed!

Usage

Basic Component Usage

import { TextInput, CheckInput, DateInput } from '@your-package/components-library';
import { FormProvider, useForm } from 'react-hook-form';

function MyForm() {
  const methods = useForm();

  return (
    <FormProvider {...methods}>
      <form>
        <TextInput
          name='username'
          label='Username'
          required
          maxLength={50}
        />

        <CheckInput
          name='terms'
          label='I agree to terms'
          required
        />

        <DateInput
          name='birthdate'
          label='Date of Birth'
          required
        />
      </form>
    </FormProvider>
  );
}

RichTextInput

RichTextInput is a Quill-based WYSIWYG editor that grows with its content by default.

Basic usage

import { RichTextInput } from '@your-package/components-library';

function MyForm() {
  const [content, setContent] = useState('');

  return (
    <RichTextInput
      value={content}
      onChange={setContent}
      maxLength={5000}
    />
  );
}

Height-constrained layout (e.g. inside a modal)

By default the editor has no maximum height. In a constrained context — such as a Bootstrap Modal — you want the editor to grow until the modal fills the viewport, then scroll inside the editor instead of overflowing the page.

Use the constrainHeight prop together with a style that sets the height. Three things are required:

  1. <Modal scrollable> — Bootstrap caps the modal body at the available viewport height.
  2. d-flex flex-column overflow-hidden on <Modal.Body> — turns the body into a flex column that constrains its children to the available height.
  3. constrainHeight + style={{ flex: 1, minHeight: 0 }} on <RichTextInput>constrainHeight activates the CSS flex chain through Quill's internal DOM nodes; flex: 1 fills the remaining space; minHeight: 0 is required in a flex context so the wrapper can shrink below its natural size.
import { RichTextInput } from '@your-package/components-library';
import { Modal, Button } from 'react-bootstrap';

function MyModal({ show, onHide }) {
  const [content, setContent] = useState('');

  return (
    <Modal show={show} onHide={onHide} scrollable>
      <Modal.Header closeButton>
        <Modal.Title>Edit content</Modal.Title>
      </Modal.Header>

      {/* flex column + overflow-hidden constrains children to available height */}
      <Modal.Body className="d-flex flex-column overflow-hidden">
        <RichTextInput
          value={content}
          onChange={setContent}
          constrainHeight
          {/* flex:1 fills remaining space; minHeight:0 enables overflow */}
          style={{ flex: 1, minHeight: 0 }}
        />
      </Modal.Body>

      <Modal.Footer>
        <Button variant="secondary" onClick={onHide}>Cancel</Button>
        <Button variant="primary" onClick={onHide}>Save</Button>
      </Modal.Footer>
    </Modal>
  );
}

Props

| Prop | Type | Default | Description | |---|---|---|---| | value | string | '' | Current editor content as an HTML string | | onChange | (value: string) => void | — | Fired on every content change | | readonly | boolean | false | Hides the toolbar and disables editing | | maxLength | number | — | Hard character limit (measured against the raw HTML string). Shows a counter below the editor | | isInvalid | boolean | false | Applies Bootstrap is-invalid border styling | | formats | FormatType[] | ['header','bold','italic','underline','list'] | Allowed Quill formats | | style | CSSProperties | — | Inline styles on the outer wrapper div. Use to constrain height in a flex context | | wrapperClassName | string | — | Extra CSS class names on the outer wrapper div | | constrainHeight | boolean | false | Activates internal flex chain so the editor scrolls inside itself. Requires a height to be set via style (e.g. style={{ flex: 1, minHeight: 0 }} or style={{ height: '40vh' }}) |

TextAreaInput

TextAreaInput is a multiline text input that auto-grows with its content using a row-counting approach. There are no inline style height overrides, so consumers can freely customise appearance with plain CSS.

Basic usage

import { TextAreaInput } from '@capyx/components-library';
import { FormProvider, useForm } from 'react-hook-form';

function MyForm() {
  const methods = useForm();
  return (
    <FormProvider {...methods}>
      <TextAreaInput name="notes" label="Notes" placeholder="Enter notes…" />
    </FormProvider>
  );
}

Controlling row height

{/* Starts at 5 rows, grows without limit */}
<TextAreaInput name="bio" label="Biography" minRows={5} />

{/* Starts at 2 rows, scrolls internally after 8 rows */}
<TextAreaInput name="summary" label="Summary" maxRows={8} />

{/* Fixed band: always between 3 and 6 rows */}
<TextAreaInput name="notes" label="Notes" minRows={3} maxRows={6} />

Props

| Prop | Type | Default | Description | |---|---|---|---| | name | string | — | Field name for form registration | | label | string | — | Label text | | required | boolean | false | Marks the field as required | | maxLength | number | — | Maximum number of characters allowed | | placeholder | string | — | Placeholder text | | value | string | — | Controlled value (standalone mode) | | onChange | (value: string) => void | — | Change callback | | disabled | boolean | false | Disables the field | | isReadOnly | boolean | false | Makes the field read-only | | isPlainText | boolean | false | Renders as plain text (no border) | | controlSize | 'sm' \| 'lg' | — | Bootstrap size variant | | debounceMs | number | — | Debounce delay in milliseconds for onChange | | minRows | number | 2 | Minimum number of visible rows | | maxRows | number | — | Maximum rows before the textarea scrolls internally. Unset = grows without limit |

Using Addons

Autocomplete Addon

import { TextInput, AutocompleteInput } from '@your-package/components-library';

function MyForm() {
  const countries = ['USA', 'Canada', 'UK', 'Australia'];

  return (
    <AutocompleteInput suggestions={countries}>
      <TextInput
        name='country'
        label='Country'
        placeholder='Type to search...'
      />
    </AutocompleteInput>
  );
}

Character Count Addon

import { TextInput, CharacterCountInput } from '@your-package/components-library';

function MyForm() {
  return (
    <CharacterCountInput>
      <TextInput
        name='bio'
        label='Biography'
        maxLength={200}
      />
    </CharacterCountInput>
  );
}

Editor Addon (Rich Text)

import { EditorAddon } from '@your-package/components-library';
import { Controller, useFormContext } from 'react-hook-form';

function MyForm() {
  const { control } = useFormContext();

  return (
    <Controller
      name='content'
      control={control}
      render={({ field }) => (
        <EditorAddon
          value={field.value}
          onChange={field.onChange}
          maxLength={5000}
        />
      )}
    />
  );
}

Combining Addons

Addons can be nested to combine their functionality:

import { TextInput, AutocompleteInput, CharacterCountInput } from '@your-package/components-library';

function MyForm() {
  const cities = ['New York', 'Los Angeles', 'Chicago', 'Houston'];

  return (
    <CharacterCountInput>
      <AutocompleteInput suggestions={cities}>
        <TextInput
          name='city'
          label='City'
          maxLength={50}
        />
      </AutocompleteInput>
    </CharacterCountInput>
  );
}

Component API

Common Props

All components support these common props when used with react-hook-form:

  • name: string (required) - Field name for form registration
  • label?: string - Label text
  • required?: boolean - Whether the field is required
  • disabled?: boolean - Whether the field is disabled

Standalone Mode

All components can be used without react-hook-form by providing value and onChange props:

<TextInput
  name='standalone'
  value={value}
  onChange={(newValue) => setValue(newValue)}
/>

Styling

Components use react-bootstrap and MUI components, making them easy to customize:

  • Override Bootstrap variables for global theming
  • Use MUI theme provider for MUI components
  • Add custom className props (where supported)

TypeScript Support

All components are fully typed with TypeScript. Import types as needed:

import type { TextAreaInputProps, CheckInputProps } from '@your-package/components-library';

React 19 Compatibility

This library is built and tested with React 19. All components use modern React patterns:

  • Functional components with hooks
  • No deprecated lifecycle methods
  • No unsafe React APIs
  • Full concurrent mode support

Contributing

When adding new components:

  1. Components go in lib/components/ - base input types
  2. Addons go in lib/addons/ - wrappers that enhance components
  3. All components must support both react-hook-form and standalone modes
  4. Export types alongside components
  5. Update index files for proper exports