Skip to content
Alpha

Hololink UI is under active development. Components, APIs and these docs may change without notice.

Contributing

This page covers working on Hololink UI itself. To use it in your app, see Installation.

You need Node.js 22.12 or later (the repo pins Node 24, the current LTS, in .nvmrc) and pnpm 12.9.1 (set by packageManager in the root package.json).

Terminal window
git clone git@github.com:Philbob-SideProjects/holocron.git
cd holocron
nvm use # or any other way of getting Node 24
corepack enable # provides the pinned pnpm
pnpm install --frozen-lockfile
pnpm build:ui # the docs and Storybook need the built components

The workspace has two packages. packages/ui holds the components, and apps/docs holds this site.

Script What it does
pnpm dev:docs Starts the docs site with hot reload
pnpm storybook Starts Storybook on port 6006
pnpm build:ui Builds the components and regenerates custom-elements.json
pnpm build:docs Builds the docs site
pnpm build:site Builds the components, docs and Storybook into apps/docs/dist
pnpm test Runs the unit and browser component tests (Vitest)
pnpm typecheck Type-checks every package that has a typecheck script
pnpm format Formats everything with Prettier (pnpm format:check only checks)
pnpm lint:design Lints DESIGN.md
pnpm changeset Writes a changeset

The docs site imports the built output in packages/ui/dist. Re-run pnpm build:ui after you change a component, then reload the docs.

The browser tests need Playwright’s Chromium. If pnpm test reports a missing browser, run pnpm --filter @philbob-sideprojects/hololink-ui exec playwright install chromium.

Read DESIGN.md first. It is the source of truth for tokens, accessibility and per-component styling.

  1. Generate the files from packages/ui:

    Terminal window
    cd packages/ui
    pnpm generate holo-thing

    Choose the stylesheet and spec/E2E options you want. Rename or delete any test file the generator creates so that it matches the conventions in step 2.

  2. Create these files in packages/ui/src/components/holo-thing/:

    File Purpose
    holo-thing.tsx The component. Tag prefix holo-, shadow: true.
    holo-thing.css Styles, scoped by Shadow DOM.
    holo-thing.stories.ts Storybook stories covering every variant and state.
    holo-thing.cmp.test.tsx Component tests (Vitest, @stencil/vitest).
    holo-thing.unit.test.ts Plain unit tests, if you have logic worth testing without the DOM.

    Look at holo-badge for a small, complete example.

  3. Follow the token rules in the CSS:

    • Consume --s-* semantic tokens only. Never use --p-* primitives or literal colours, pixel sizes, durations or shadows.
    • If no semantic token fits, add one to packages/ui/src/styles/settings/tokens.css and document it in DESIGN.md.
    • Expose styling hooks named --holo-<component>-<prop>, each with a semantic fallback: var(--holo-thing-bg, var(--s-color-bg-surface)).
    • Do not style by theme. Remap tokens instead of using [data-theme] or prefers-color-scheme.
  4. Document the API with JSDoc. Stencil reads the comments on @Prop(), @Event(), @Method() and the class, and writes them to custom-elements.json. Write each comment as a short sentence about what the member does and its allowed values.

    /** The visual style of the badge. */
    @Prop() variant: 'neutral' | 'success' = 'neutral';
  5. Add the package export in packages/ui/package.json, matching the tag name:

    "./holo-thing": {
    "types": "./dist/components/holo-thing.d.ts",
    "import": "./dist/components/holo-thing.js"
    }
  6. Add a docs page at apps/docs/src/content/docs/components/thing.mdx with live examples, a code block for each, and an API reference. Copy the structure of an existing page. Add the slug to the matching group in apps/docs/astro.config.mjs so it appears in the sidebar. The component status table picks up the new component automatically.

  7. Run pnpm build:ui, pnpm test, pnpm typecheck and pnpm build:docs.

Hololink UI targets WCAG 2.2 AA. Before you open a pull request:

  • Use native elements (<button>, <input>, <dialog>) and the Popover API where they fit, instead of rebuilding them from div and ARIA.
  • Forward labels and states through Shadow DOM: aria-invalid, aria-describedby, aria-disabled.
  • Keep focus visible with the focus ring from DESIGN.md. Never remove an outline without an equivalent replacement.
  • Open the component’s Storybook story and check the Accessibility panel (axe, WCAG 2.x A and AA rules) in both light and dark themes.
  • Do a keyboard-only pass: Tab, Shift+Tab, Enter, Space, Esc and arrow keys where relevant.
  • Respect prefers-reduced-motion.
  • If you add a colour pairing, add it to tokens.unit.test.ts so the contrast ratio is checked.

Any change that affects the published package needs a changeset. Docs-only changes do not.

Terminal window
pnpm changeset

Choose the bump type for @philbob-sideprojects/hololink-ui, then write the summary for a consumer: what changed, and what they must do. Commit the generated file in .changeset/ with your pull request. The package is below 1.0, so breaking changes go in a minor bump, and the summary must include migration steps.

The @hololink/docs app is private and is never versioned.

Pull requests to main run the checks workflow (.github/workflows/_checks.yml):

Job Checks
lint pnpm format:check (Prettier), pnpm lint:design, actionlint on the workflows, and changeset status against main (pull requests only)
typecheck pnpm build:ui, then pnpm typecheck
test pnpm test, with Playwright Chromium for the browser tests
build pnpm build:site, then confirms the package tarball contains the manifest, loader, bundles, types and styles

A pull request that touches the package without a changeset fails lint. Run pnpm format before you push to keep Prettier happy.

On pull requests, a preview job uploads a non-production Cloudflare Worker version and comments the preview URL. It is skipped for forks and Dependabot, and until the first production deploy exists.

  1. A pull request with a changeset merges to main.
  2. The on_merge workflow runs the same checks, deploys the docs and Storybook to Cloudflare Workers, and runs a smoke test against https://www.hololink-ui.co.uk.
  3. The release job opens or updates a pull request titled chore: version packages. It bumps the version and writes the entry in packages/ui/CHANGELOG.md, which feeds the changelog.
  4. Merging that pull request publishes @philbob-sideprojects/hololink-ui to GitHub Packages, tags the release and creates a GitHub release.

If a docs deploy breaks production, run the rollback workflow from the Actions tab. It returns the Worker to the previous version, or to a version ID you give it. It does not unpublish packages.