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

smartsell-ui-kit

v0.1.6

Published

Public UI primitives and modal helpers for SmartSell applications.

Readme

smartsell-ui-kit

smartsell-ui-kit is the shared React component package for SmartSell custom modules, tenant extensions, and isolated integrations.

It provides the public UI contract that external consumers should rely on instead of importing private SmartSell app internals. The package is built around a few core goals:

  • theme-aware components powered by smartsell-theme
  • self-contained styling with no dependency on private SmartSell CSS files
  • predictable APIs for forms, modals, data tables, and common surfaces
  • async-friendly primitives for remote search and server-driven datasets

Highlights

  • React 18-first component API
  • Consistent theme integration through smartsell-theme
  • Form primitives such as Input, Textarea, Checkbox, DatePicker, Select, and SelectAsync
  • Display and layout primitives such as Card, CardSmall, and Separator
  • Modal helpers including Modal, ComposableModal, and createModalSlotIds
  • Data components including Table and TableAsync
  • Brand images published from the dedicated smartsell-ui-kit/img subpath
  • Local Storybook workspace for visual QA before release

Requirements

  • React 18+
  • React DOM 18+
  • smartsell-theme

Installation

npm install react@^18 react-dom@^18 smartsell-theme smartsell-ui-kit

Quick start

Wrap your module with ThemeProvider from smartsell-theme, then consume the UI kit components normally.

import { ThemeProvider } from 'smartsell-theme';
import { Button, Card } from 'smartsell-ui-kit';

export default function ExamplePage() {
  return (
    <ThemeProvider>
      <Card title="Example" eyebrow="UI kit">
        <Button onClick={() => window.history.back()}>
          Go back
        </Button>
      </Card>
    </ThemeProvider>
  );
}

Main exports

  • Button, Checkbox, DatePicker, Input, Textarea, Select, SelectAsync
  • Card, CardSmall, Separator
  • Modal, ComposableModal, createModalSlotIds
  • Table, TableAsync
  • useUiKitTheme
  • smartsell-ui-kit/img for branded logo, icon, favicon, and background image components

Images subpath

Import brand images from the dedicated img subpath so the main entrypoint stays focused on UI primitives.

import { Icon192, Logo, Texture1 } from 'smartsell-ui-kit/img';

export default function BrandHeader() {
  return (
    <div style={{ display: 'grid', gap: 16 }}>
      <Logo style={{ width: 240 }} />
      <Icon192 size={72} alt="SmartSell app icon" />
      <Texture1 decorative style={{ width: '100%', maxWidth: 420 }} />
    </div>
  );
}

All image components resolve their source from the active smartsell-theme context. Right now light and dark modes point to the same files, but the submodule already swaps sources by theme variant so future dark-specific images only require changing the mapped filenames.

Composable modal pattern

Use ComposableModal when the page should own modal state and business logic, while host applications or extension layers customize the header, body, and footer through stable slot ids.

import { useState } from 'react';

import { Button, ComposableModal, createModalSlotIds } from 'smartsell-ui-kit';

const slotIds = createModalSlotIds('order-review');

export default function ExamplePage() {
  const [isOpen, setIsOpen] = useState(false);

  const submitOrder = () => {
    setIsOpen(false);
  };

  return (
    <>
      <Button onClick={() => setIsOpen(true)}>Open order review</Button>

      <ComposableModal
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        onConfirm={submitOrder}
        title="Order review"
        slotBaseId="order-review"
        renderSlot={({ id, context, children }) => {
          if (id === slotIds.footer) {
            return (
              <Button onClick={() => context.confirm?.()}>
                Send order {context.payload?.orderNumber}
              </Button>
            );
          }

          return children;
        }}
        payload={{ orderNumber: 'SO-1001', total: 421.9 }}
      >
        <div>Default modal body</div>
      </ComposableModal>
    </>
  );
}

Slot ids generated by createModalSlotIds('order-review'):

  • order-review:modal-header
  • order-review:modal-body
  • order-review:modal-footer

This pattern is useful when:

  • the page owns data loading, permissions, and submission flow
  • the host app needs stable extension points instead of private imports
  • multiple modal variants should reuse the same contract

Async components

SelectAsync is designed for remote option sources while preserving the same interaction model as the regular Select.

import { useState } from 'react';

import { SelectAsync, type SelectAsyncOption } from 'smartsell-ui-kit';

type CustomerOption = SelectAsyncOption<string>;

function CustomerField() {
  const [value, setValue] = useState<CustomerOption | null>(null);

  return (
    <SelectAsync
      label="Customer"
      value={value}
      onChange={setValue}
      loadOptions={async (query, loadedOptions, { page, signal }) => {
        const response = await fetch(`/api/customers?search=${query}&page=${page}`, { signal });
        const data = await response.json();

        return {
          options: data.items.map((item: { id: string; tradeName: string }) => ({
            value: item.id,
            label: item.tradeName,
          })),
          hasMore: data.hasMore,
        };
      }}
    />
  );
}

TableAsync follows the same idea for remote datasets, with debounced search and request cancellation support built into the component flow.

Development workflow

Useful local commands:

npm run storybook
npm run test
npm run validate
npm run validate:release

Run Storybook in Docker when you want containerized local development:

docker compose up --build

Storybook workspace

The repository includes a local Storybook workspace for component review and design QA.

  • grouped navigation for buttons, surfaces, forms, modals, and tables
  • a dedicated Images section covering logos, icons, and backgrounds from smartsell-ui-kit/img
  • live Controls for props and responsive behavior
  • a local ThemeProvider preview using the same smartsell-theme contract expected by host apps
  • a Theme/Colors playground for temporary Storybook-only token overrides

Storybook is development-only. It is not published to npm because the package only ships dist, README.md, and LICENSE.

Theme overrides from the Theme/Colors story affect only the local Storybook session. Runtime consumers still read theme values from their host application's smartsell-theme integration.

Release checklist

Before publishing a new version:

npm run validate
npm run build:storybook
npm pack --dry-run
npm publish

License

This package is distributed under the SmartSell proprietary license described in LICENSE.