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

@archetypeai/ds-ui-svelte-console

v0.10.0

Published

Archetype AI Design System Console Primitives (Svelte 5 + ds-lib-tokens Integration)

Readme

@archetypeai/ds-ui-svelte-console

Console primitives of the Archetype AI design system. Svelte 5 primitives built on bits-ui, styled with Tailwind v4 and tailwind-variants, and wired to the @archetypeai/ds-lib-tokens theme. TypeScript source ships as .svelte files (no precompilation) so consumers get full type-checking and IDE go-to-definition.

The console flavor ships two ways from the same source, with different roles:

  • npm package (this document's default) - how apps consume primitives: they stay in node_modules, imported per-subpath, updated by version bump. The package is the source of truth.
  • shadcn-svelte registry - how primitives get modified or extended: pull a primitive's editable source into your app, change it, then port the change back into the package. See Modifying a primitive (registry workflow).

Install

npm i @archetypeai/ds-ui-svelte-console

Then install all peer dependencies:

npm i svelte tailwindcss bits-ui tailwind-variants tailwind-merge clsx @lucide/svelte @archetypeai/ds-lib-tokens svelte-sonner shiki yaml @cfworker/json-schema

Tailwind v4 setup (mandatory)

Tailwind v4 does not scan node_modules by default. Without the @source directive below, every class in this package is purged at consumer build time and components render unstyled - this is the single most common silent failure.

In your consumer's app.css, in this order:

@import 'tailwindcss';
@import '@archetypeai/ds-lib-tokens/theme.css';
@source "../node_modules/@archetypeai/ds-ui-svelte-console/dist";

Order matters:

  • tailwindcss registers the engine.
  • @archetypeai/ds-lib-tokens/theme.css declares the CSS variables that component classes consume (atai-neutral, bg-card, stroke-icon-default, etc.).
  • @source makes Tailwind scan this package's .svelte files so utility classes used inside the package are emitted into your consumer bundle.

Adjust the @source path if your app.css lives elsewhere - it must resolve to the package's dist/ directory.

TypeScript setup

In your consumer's tsconfig.json (or jsconfig.json), set:

{
  "compilerOptions": {
    "moduleResolution": "bundler"
  }
}

"node16" and "nodenext" also work. Without one of these, the types condition in this package's exports map is bypassed, types fall back to the default JS file, and editor features degrade.

Usage

Each primitive lives at its own subpath. There is no barrel import { Button } from '@archetypeai/ds-ui-svelte-console' - subpaths keep svelte-sonner, shiki, yaml, and @cfworker/json-schema out of bundles for consumers who never touch the codeblock or sonner primitives.

<script lang="ts">
  import { Button } from '@archetypeai/ds-ui-svelte-console/primitives/button'
  import { Badge } from '@archetypeai/ds-ui-svelte-console/primitives/badge'

  let buttonRef: HTMLButtonElement | null = $state(null)
</script>

<Badge variant="default">Hello</Badge>
<Button bind:ref={buttonRef} variant="primary" size="md">Click me</Button>

Per-primitive subpaths

| Primitive | Import path | |---|---| | Alert | @archetypeai/ds-ui-svelte-console/primitives/alert | | Badge | @archetypeai/ds-ui-svelte-console/primitives/badge | | Button | @archetypeai/ds-ui-svelte-console/primitives/button | | Card | @archetypeai/ds-ui-svelte-console/primitives/card | | Checkbox | @archetypeai/ds-ui-svelte-console/primitives/checkbox | | CodeBlock | @archetypeai/ds-ui-svelte-console/primitives/codeblock | | Collapsible | @archetypeai/ds-ui-svelte-console/primitives/collapsible | | Dialog | @archetypeai/ds-ui-svelte-console/primitives/dialog | | DropdownMenu | @archetypeai/ds-ui-svelte-console/primitives/dropdown-menu | | DropZone | @archetypeai/ds-ui-svelte-console/primitives/dropzone | | EmptyState | @archetypeai/ds-ui-svelte-console/primitives/empty-state | | Input | @archetypeai/ds-ui-svelte-console/primitives/input | | InputGroup | @archetypeai/ds-ui-svelte-console/primitives/input-group | | Item | @archetypeai/ds-ui-svelte-console/primitives/item | | Label | @archetypeai/ds-ui-svelte-console/primitives/label | | Progress | @archetypeai/ds-ui-svelte-console/primitives/progress | | Select | @archetypeai/ds-ui-svelte-console/primitives/select | | Separator | @archetypeai/ds-ui-svelte-console/primitives/separator | | Sonner | @archetypeai/ds-ui-svelte-console/primitives/sonner | | Spinner | @archetypeai/ds-ui-svelte-console/primitives/spinner | | Table | @archetypeai/ds-ui-svelte-console/primitives/table | | Tabs | @archetypeai/ds-ui-svelte-console/primitives/tabs | | Textarea | @archetypeai/ds-ui-svelte-console/primitives/textarea | | Tooltip | @archetypeai/ds-ui-svelte-console/primitives/tooltip |

The cn() helper and shared TS type helpers (WithElementRef, WithoutChild, WithoutChildren, WithoutChildrenOrChild) are exported from @archetypeai/ds-ui-svelte-console/primitives/utils. The dark-mode controller lives at @archetypeai/ds-ui-svelte-console/primitives/theme (see below).

Composition patterns will arrive at @archetypeai/ds-ui-svelte-console/patterns/<name> in a later release without breaking any of the primitive paths above.

Dark mode (primitives/theme)

The package manages dark mode without any external dependency. darkMode is a reactive singleton that mirrors the dark class on <html>:

<script lang="ts">
  import { darkMode } from '@archetypeai/ds-ui-svelte-console/primitives/theme'
</script>

<button onclick={() => darkMode.toggle()}>
  {darkMode.current ? 'Switch to light' : 'Switch to dark'}
</button>
  • darkMode.current - reactive boolean, true while <html> carries the dark class. Safe to read in $derived/$effect.
  • darkMode.set(value) - adds/removes the class. CSS transitions are suppressed for one frame during the swap, so the whole page flips at once instead of staggering per-element.
  • darkMode.toggle() - convenience for set(!current).

A MutationObserver keeps current in sync even when something else toggles the class (e.g. an app-level theme store or SSR-rendered markup), and the module is SSR-safe - it no-ops without a document. Theme-aware primitives (e.g. CodeBlock's syntax highlighting) consume darkMode internally.

CodeBlock editor & validation

primitives/codeblock exports two components: CodeBlock (read-only, shiki-highlighted) and CodeBlockEditor (editable, with a YAML + JSON Schema validation pipeline):

<script lang="ts">
  import { CodeBlockEditor } from '@archetypeai/ds-ui-svelte-console/primitives/codeblock'

  let value = $state('name: my-config')
  let valid = $state(true)
</script>

<CodeBlockEditor bind:value bind:valid schema={mySchema} showDownload downloadBaseName="config" />
  • value (bindable) - the YAML text being edited.
  • schema - optional JSON Schema object; when provided, the parsed YAML is validated with @cfworker/json-schema.
  • valid (bindable) - true while the text parses and passes the schema.
  • schemaUnavailable (bindable) - true when the schema itself can't be compiled into a validator.
  • placeholder, showDownload, downloadBaseName - editor chrome.

Validation is debounced (250 ms) and errors are mapped back to source lines with human-readable messages and fix suggestions. The shiki highlighter is lazy-loaded and follows darkMode for its light/dark theme. This pipeline is why yaml and @cfworker/json-schema are peer dependencies.

API conventions

  • bind:ref for element handles. Every primitive exposes ref as a $bindable prop. Use <Button bind:ref={el} /> to capture the underlying DOM element.
  • data-* attributes are public API. Every variant slot carries data-slot plus variant attributes (data-variant, data-size, data-state, data-typography, etc.). Use them as descendant-selector hooks. Renaming requires a major version bump.
  • Composite primitives compose by sub-part. Card, Dialog, Item, Select, DropdownMenu, Tabs, Collapsible, Tooltip, InputGroup, and DropZone export their sub-parts (e.g. Dialog.Trigger, Dialog.Content). Pass class to each sub-part directly - there is no headerClass/contentClass shorthand on the root.
  • child snippet on Item is the bits-ui asChild render-prop pattern, not a typo for children.
  • Variant configs are exported. Each index.ts re-exports its tv() configs (e.g. buttonVariants, inputGroupButtonVariants) so consumers can compose variants without forking source.

Modifying a primitive (registry workflow)

The npm package is the source of truth for primitives - consume every primitive from it, and don't keep local forks or hand-roll one-offs. What you will hit is a primitive that needs to change: an internal refactor, a variant's styling adjusted, or the API extended with a new variant or prop axis. For that, the same primitives are served as a shadcn-svelte registry at https://design-system-console.archetypeai.workers.dev/, so you can work on the real source inside your app and upstream the result:

  1. Pull the editable source into your app:

    npx shadcn-svelte@latest add https://design-system-console.archetypeai.workers.dev/r/button.json

    Components install flat under your ui alias - $lib/components/ui/{button,codeblock,...}/, plus utils.ts and theme.svelte.ts at the ui root. Cross-component dependencies are declared with the registry's local: prefix, so installing one component pulls everything it needs from the same registry - e.g. codeblock pulls button, spinner, theme, and console-utils.

  2. Make the change against the local source and validate it in-app.

  3. Port the change back into ds-ui-svelte/console/primitives/ in the design-system repo and release. Then bump the package version in your app, delete the local copy, and import from primitives/<name> again. A copy living long-term in ui/ is drift - the package, not the app, owns primitives.

A genuinely new primitive follows the same path in reverse: build it in ui/ mirroring the existing primitives (a tailwind-variants config, cn from utils, data-slot/data-variant attributes, runes, token classes throughout - read an installed primitive's source as the template), then ship it into the package.

Notes:

  • Always install via the full registry URL (or a project script wired to it - the console app exposes npm run ds [<name>] for exactly this). A bare npx shadcn-svelte@latest add button resolves against the default shadcn-svelte registry and installs the generic upstream component, not the Archetype one.
  • The utils item is named console-utils (shadcn-svelte reserves utils); it ships the console cn() with the rounded-interactive tailwind-merge extension. Without it, class merging on interactive radii silently breaks.
  • /r/all.json lists all component URLs for programmatic access.
  • Registry-installed files don't need the Tailwind @source directive (they live in your repo and are scanned normally), but the @archetypeai/ds-lib-tokens/theme.css import remains mandatory.

Extending in labs

Console is the stable base tier: its API contract is frozen and its data-* attributes are public API that only a major version may change. When you need new or experimental behavior on top of a console primitive, build it in the labs tier (@archetypeai/ds-ui-svelte-labs) - never fork or mutate console to accommodate a one-off.

Labs adapts console without changing it, using an escape-hatch ladder - reach for the lowest rung that solves the problem:

  1. class prop override. Every primitive forwards class to its root slot; pass Tailwind utilities to restyle in place.
  2. data-slot / data-* selectors in your CSS. Target the public attributes ([data-slot="..."], [data-variant="..."], data-state) with descendant selectors - no source changes.
  3. tv({ extend }) on the exported variant cluster. Each primitive re-exports its tailwind-variants config (e.g. buttonVariants); extend it to add a variant or override defaults without forking the component.
  4. A labs wrapper component (rare). When the first three can't express it, compose the console primitive inside a labs primitive.

This ladder keeps the modification surface inside labs. Behavior that proves itself there graduates back into console in a deliberate, API-hardening change - the flow is always labs → console, never console reaching up into labs. See the labs README for the consumer-side view of the same ladder.

License

MIT. See LICENSE.