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

@slm-solusi-digital/telescope-ui

v0.2.0

Published

UI component library built on HeroUI v2 — by SLM Solusi Digital

Readme

@slm-solusi-digital/telescope-ui

A React component library built on top of HeroUI v2. Telescope-UI wraps HeroUI primitives with project-specific defaults and ships a handful of domain components (shipping/voyage status chips, RHF-integrated form inputs, modals, headers) used across the SLM Solusi Digital maritime apps.

Distributed as an ES module with bundled CSS and .d.ts files.

Installation

npm install @slm-solusi-digital/telescope-ui @heroui/[email protected] framer-motion

Peer dependencies

| Package | Version | |---|---| | react | ^18.0.0 \|\| ^19.0.0 | | react-dom | ^18.0.0 \|\| ^19.0.0 | | @heroui/react | 2.8.0 | | framer-motion | >=10.0.0 |

Everything else (react-hook-form, react-select, react-number-format, lucide-react, @internationalized/date) is bundled into dist/index.js.

Setup

1. Configure Tailwind CSS v4

Create a HeroUI plugin file:

// src/heroui-plugin.ts
import { heroui } from "@heroui/react";
export default heroui();

Wire it into your CSS entry. This package ships no CSS — its components are styled by your app's Tailwind build, so you must point Tailwind at both the HeroUI theme and this library's dist so the utility classes used inside the components get generated:

/* src/index.css */
@import "tailwindcss";
@plugin "./heroui-plugin.ts";
@source "../../node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}";
/* Required — without this, telescope-ui components render unstyled */
@source "../../node_modules/@slm-solusi-digital/telescope-ui/dist/**/*.js";

The components also rely on a couple of project theme tokens that are not part of Tailwind's defaults. Define them in your theme so classes like text-xxxs and the primary brand color resolve:

@theme {
  --color-primary: #0550a9;
  --text-xxs: 11px;
  --text-xxxs: 10px;
}

2. Wrap your app with HeroUIProvider

import { HeroUIProvider } from "@slm-solusi-digital/telescope-ui";

function App() {
  return (
    <HeroUIProvider>
      <YourApp />
    </HeroUIProvider>
  );
}

Components

All components are named exports from the package root.

Buttons

| Export | Notes | |---|---| | ButtonActions | Three-dot actions menu trigger. | | ButtonAdd | Icon-only primary "+" button. ButtonAdd.WithText adds a label. | | ButtonDelete | Trash-icon danger button. |

import { ButtonAdd, ButtonDelete } from "@slm-solusi-digital/telescope-ui";

<ButtonAdd onPress={onCreate} />
<ButtonAdd.WithText onPress={onCreate}>New voyage</ButtonAdd.WithText>
<ButtonDelete onPress={onDelete} />

Status chips

Voyage / vessel / port-call status indicators built on HeroUI Chip.

| Export | Purpose | |---|---| | ChipBallast, ChipLaden, ChipSailing | Voyage leg state | | ChipScheduled, ChipCompleted, ChipCanceled | Lifecycle state | | ChipPol, ChipPod | Port of loading / discharge | | ChipVoyageStatus | Router — dispatches to one of the above by status string | | ChipVesselStatus | Router for vessel-level status |

import { ChipVoyageStatus } from "@slm-solusi-digital/telescope-ui";

<ChipVoyageStatus status="SAILING" />

Headers

| Export | Notes | |---|---| | HeaderBack | Back-arrow banner for detail pages. | | HeaderDetailPage | Title + actions slot for record detail screens. | | HeaderForm | Section heading for form blocks. |

Inputs

Plain HeroUI wrappers and react-hook-form (*RHF) variants:

| Export | Description | |---|---| | InputText | Themed Input with outside label + white background. InputText.WithRHFControl adds RHF support. | | InputCheckbox | Labeled CheckboxGroup over an options array. | | InputRadioGroup | Labeled RadioGroup over an options array. | | InputSelect | HeroUI Autocomplete with project styling. | | InputSelectRHF | RHF-bound Autocomplete with required handling. | | InputCreatableSelectRHF | RHF-bound react-select creatable variant. | | InputSelectMultiple | react-select multi-select with label + error display. | | InputSelectUnitRHF | Small unit dropdown that pairs with a numeric input (place: "right" \| "left"). | | InputUnit | Static unit-label chip that pairs with an input. | | InputNumericRHF | RHF-bound numeric input (react-number-format) with thousand-separators, prefix/suffix support. | | InputDateRHF | RHF-bound date picker. | | InputDateTimePickerRHF | RHF-bound date + time picker. .V2 flows values as ISO strings. | | InputDateRangePicker | Date range picker. |

import { useForm } from "react-hook-form";
import { InputText, InputNumericRHF } from "@slm-solusi-digital/telescope-ui";

function VoyageForm() {
  const { control } = useForm({ defaultValues: { vesselName: "", quantity: 0 } });
  return (
    <>
      <InputText.WithRHFControl
        control={control}
        name="vesselName"
        label="Vessel name"
        isRequired
      />
      <InputNumericRHF
        control={control}
        name="quantity"
        label="Quantity"
        suffix=" tons"
        thousandSeparator
      />
    </>
  );
}

Modals

| Export | Purpose | |---|---| | ModalAttachments | File-list + upload modal. | | ModalDelete | Confirmation dialog for destructive actions. | | ModalSuccess | Success-state confirmation. |

Feedback & misc

| Export | Notes | |---|---| | BannerError | Inline error banner. | | IconEstimate | Styled "E" badge used to mark estimated values. | | TimeStatus | Renders an absolute time + relative time chip. |

Utilities

Date formatters built on @internationalized/date, pinned to Asia/Jakarta / en-GB:

import {
  formatDateTime,
  formatDate,
  formatTime,
  formatDateISO,
  convertDaysToDuration,
  convertDateStringToLocal,
  convertParamsToDateRange,
  getYearRange,
  getYearRanges,
  type YearRange,
} from "@slm-solusi-digital/telescope-ui";

Development

npm install
npm run storybook        # Storybook on http://localhost:6006 — primary dev surface
npm run build            # tsc -b && vite build → emits dist/
npm run test:unit        # Vitest (jsdom)
npm run lint             # ESLint

Run a single test file:

npx vitest run --project unit src/components/InputText/InputText.test.tsx

Storybook stories doubling as headless-browser tests:

npx playwright install chromium    # one-time
npx vitest run --project storybook

Adding a new component

Each component lives in src/components/<Name>/ with three files:

<Name>.tsx          # default export, named after the folder
<Name>.stories.tsx  # Storybook stories under "Components/<Group>/<Name>"
<Name>.test.tsx     # Vitest + @testing-library/react

Then add the re-export to src/index.ts — components that aren't listed there are invisible to consumers.

Publishing

This is a private, internal package ("access": "restricted"). Publishing requires authentication to a registry where the @slm-solusi-digital scope is private (npm Org/Teams, GitHub Packages, or a self-hosted registry).

npm run build
npm publish

The prepublishOnly hook runs the build automatically, and publishConfig.access in package.json keeps the release restricted — do not pass --access public.

License

UNLICENSED — proprietary and confidential. © SLM Solusi Digital. Internal use only; not licensed for redistribution.