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

@sinups/ui-kit

v0.1.20

Published

The DocSpace UI Library (`@sinups/ui-kit`) provides a set of reusable components, utilities, and integrations for your application. This guide outlines the steps to integrate and use the library effectively in your project.

Readme

DocSpace UI Library Documentation

The DocSpace UI Library (@sinups/ui-kit) provides a set of reusable components, utilities, and integrations for your application. This guide outlines the steps to integrate and use the library effectively in your project.


Table of Contents

  1. Requirements
  2. How to start
  3. Advanced Search
  4. Developing mode
  5. Commit helper

Requirements

  • react-redux 9+
  • @reduxjs/toolkit 2+
  • @mantine/core >=8.2.7
  • @mantine/dates >=8.2.7 (for the Advanced Search date-range filter)

How to start

  1. Add env variable:
VITE_API_BASE_URL=/api
  1. Add the package link to your package.json to include the UI library locally:
npm install @sinups/ui-kit
  1. Extend mantine theme
import { theme as docspaceTheme } from '@sinups/ui-kit';

export const themeConfig = createTheme({
  ...docspaceTheme
  // project custom settings...
});
  1. Add styles file in root file like App.tsx right after mantine styles import.
import '@sinups/ui-kit/dist/ui-kit.css';
  1. If component or widget uses translations add them to your i18n instance
import { translations } from '@sinups/ui-kit';

// Under init
Object.entries(translations).forEach(([language, resources]) => {
  i18n.addResourceBundle(language, 'ds', resources);
});
  1. If widget uses redux slice add it to your store declaration. For example:
import { notificationApi as notificationApiKit } from '@sinups/ui-kit';

// Add to reducers
{
  //...
  [notificationApiKit.reducerPath]: notificationApiKit.reducer,
  /...
}

// Add to middlewares
[
  //...
  notificationApiKit.middleware
  //...
]

Advanced Search

A headless, generic search surface: the kit owns the chrome (input bar, debounce, dropdown/modal, loading / empty / error states), the consumer supplies the domain pieces through slots.

Install

npm install @mantine/core @mantine/dates @mantine/hooks @sinups/ui-kit

Import the Mantine dates styles once, right after the core styles (the date-range filter needs them):

import '@mantine/core/styles.css';
import '@mantine/dates/styles.css';

Usage

import { useCallback, useState } from 'react';
import { Stack, Text, TextInput } from '@mantine/core';
import {
  AdvancedSearchWidget,
  SearchEmptyState,
  SearchErrorState,
  SearchFilterChipsSelect,
  SearchFilterDateRange,
  SearchResultRow,
  type SearchFilterDateRangeValue
} from '@sinups/ui-kit';

interface MyItem {
  id: string;
  title: string;
  subtitle: string;
}

interface MyFilters {
  range: SearchFilterDateRangeValue;
  calendars: string[];
  place: string;
}

const DEFAULT_FILTERS: MyFilters = {
  range: { from: null, to: null },
  calendars: [],
  place: ''
};

const CALENDAR_OPTIONS = [
  { value: 'personal', label: 'Личный', color: '#339AF0' },
  { value: 'work', label: 'Работа', color: '#51CF66' }
];

export const EventSearch = () => {
  const [query, setQuery] = useState('');
  const [filters, setFilters] = useState<MyFilters>(DEFAULT_FILTERS);

  // Memoize onSearch — a new identity on every render resets the pending debounce.
  const onSearch = useCallback(
    (q: string, f: MyFilters): Promise<MyItem[]> => api.searchEvents(q, f),
    []
  );

  return (
    <AdvancedSearchWidget<MyItem, MyFilters>
      query={query}
      onQueryChange={setQuery}
      filters={filters}
      onFiltersChange={setFilters}
      defaultFilters={DEFAULT_FILTERS}
      onSearch={onSearch}
      placeholder="Поиск событий"
      renderFilters={({ filters: current, setField }) => (
        <Stack gap="xs">
          <SearchFilterDateRange
            value={current.range}
            onChange={(next) => setField('range', next)}
            fromLabel="с"
            toLabel="по"
          />
          <SearchFilterChipsSelect
            options={CALENDAR_OPTIONS}
            value={current.calendars}
            onChange={(next) => setField('calendars', next)}
            placeholder="Область поиска"
          />
          <TextInput
            size="sm"
            placeholder="Место"
            value={current.place}
            onChange={(event) => setField('place', event.currentTarget.value)}
          />
        </Stack>
      )}
      renderResultItem={(item) => (
        <SearchResultRow
          middle={
            <Stack gap={2}>
              <Text size="sm" fw={500}>
                {item.title}
              </Text>
              <Text size="xs" c="dimmed">
                {item.subtitle}
              </Text>
            </Stack>
          }
        />
      )}
      renderEmpty={
        <SearchEmptyState title="Ничего не найдено" description="Попробуйте изменить запрос" />
      }
      renderError={(_error, retry) => (
        <SearchErrorState
          title="Не удалось выполнить поиск"
          retryLabel="Повторить"
          onRetry={retry}
        />
      )}
      onSelect={(item) => openEventDetails(item.id)}
      onViewAll={(q, f) => navigateToResultsPage(q, f)}
      maxVisibleResults={5}
    />
  );
};

Search lifecycle: typing fires onSearch live (debounced), while filter edits commit only on «Найти» (or with liveFilters enabled). onViewAll renders the «show all» footer link (only when maxVisibleResults hides matches) and is also bound to Enter in the search field.

filtersApi contract

renderFilters receives an API object instead of owning the lifecycle:

  • filters — current filter values;
  • setField(key, value) — single-field update; multiple calls within one tick compose (none are lost);
  • setFilters(next) — bulk replace of the whole filter object;
  • reset() — restore defaultFilters, clear query + results, remount the form;
  • submit() — run the search now (the «Найти» trigger).

Customization

| Prop | Purpose | | ----------------------- | ---------------------------------------------------------------------------------------- | | inputProps | Passthrough for the search TextInput (styles are slot-merged over the kit defaults) | | actionIconProps | Passthrough for the clear/filter icons (variant is controlled while the panel is open) | | popoverProps | Desktop Popover overrides (position, width, shadow, radius…) | | modalProps | Mobile fullscreen Modal overrides (used when isMobile) | | classNames / styles | Per-slot overrides: dropdown, filters, results (see the AdvancedSearchSlot type) | | maxDropdownHeight | Scroll cap for the results area, default 360 | | debounceMs | Query debounce, default 300 (filterDebounceMs for liveFilters) | | getItemKey | Stable row key, defaults to the array index |

i18n: the widget chrome strings (reset / find / clear / errors…) live in the kit's ds:search.* namespace — consumers who register the kit translations (via uiKitPlugin or the resource-bundle snippet in step 4 above) get them automatically in both ru/en. Set isMobile to render the fullscreen modal layout instead of the desktop popover.

Developing Mode

If you want to develop new component and widget you can link this library to you parent project and have it working in developing mode.

  1. Add package link. Change package version to specific path to file. You can use pwd command inside project directory to get it.
 "@sinups/ui-kit": "file:/home/quest76/ui-kit",
  1. Add ts config alias (parent project) in tsconfig.json
{
  compilerOptions: {
    paths: {
	    "@sinups/ui-kit": ["/home/quest76/code/ui-kit/src"],
    	"@ds/*": ["/home/quest76/code/ui-kit/src/*"],
    }
  }
}
  1. Add Vite aliases (parent project) in vite.config.ts
{
  resolve: {
    alias: {
      '@sinups/ui-kit': '/home/quest76/code/ui-kit/src',
      '@ds': '/home/quest76/code/ui-kit/src',
    }
  }
}

Commit Helper

The repository includes an interactive commit message generator based on scripts/commit.sh.

Available commands:

yarn commit:claude
yarn commit:codex
yarn commit:ai

What each command does:

  • yarn commit:claude runs the helper with Claude prefill
  • yarn commit:codex runs the helper with Codex prefill
  • yarn commit:ai runs the helper in AI mode and uses Claude by default

Requirements:

  • claude CLI must be installed for commit:claude
  • codex CLI must be installed for commit:codex
  • if the selected AI CLI is unavailable, the script falls back to manual mode

Typical flow:

  1. Stage your changes with git add ...
  2. Run one of the commands above
  3. Optionally paste BFT/specification text into the terminal
  4. Review or edit the suggested fields step by step
  5. Confirm the preview and create the commit

What the script asks for:

  • commit type emoji
  • board/task id
  • short title
  • what changed
  • why changed
  • what was tested
  • RC / REQ / OWNER / AC
  • public description
  • TEST / DOC / optional CR, DCR, ADR trailers

Behavior details:

  • the script reads the current branch name and tries to detect the board id automatically
  • it reads staged diff first; if nothing is staged, it uses the working tree diff for AI analysis
  • on commit, if nothing is staged, it runs git add -u before git commit
  • the last entered metadata is stored in .commit-prefill.json and reused for the next commit on the same branch

Useful notes:

  • press Enter to accept the suggested or default value
  • for multiline sections like What changed, enter one item per line and finish with an empty line
  • when BFT text is provided, the AI tries to extract RC, REQ, OWNER, and AC automatically