diff --git a/AGENTS.md b/AGENTS.md index 744824e..d339114 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,339 +1,91 @@ -# Basecoat – Agent Guide +# Agent Rules -## What is Basecoat? +## Communication +- Keep answers concise, technical, and to the point. +- Do not use filler or glazing openers. +- Keep explanations MECE: separate facts, decisions, risks, and open questions. +- If scope is partial, state exactly what was not included. +- Challenge incorrect assumptions with evidence from code, docs, or upstream sources. -Basecoat is a vanilla JavaScript/HTML/CSS port of shadcn/ui components. It reuses shadcn/ui's design patterns and Tailwind CSS classes while maintaining semantic HTML, native browser elements, and full accessibility (ARIA attributes, proper hierarchies, keyboard navigation). The goal is to provide shadcn-quality components without React dependencies. +## Project Intent +- Basecoat is a Tailwind CSS, vanilla HTML, CSS, and JavaScript implementation of shadcn/ui's visual language for non-React stacks. +- Basecoat maps upstream shadcn/ui concepts onto simpler semantic markup; it is not a React, Radix, Base UI, `cn-*`, or `data-slot` DOM port. +- Prefer the browser platform: native elements, semantic HTML, CSS state selectors, and small vanilla JS only when needed. -Basecoat is not a literal DOM port of shadcn/ui. It is an alternative implementation with the same visual language and comparable component coverage, but with simpler markup, less JavaScript, less CSS, and no React/runtime primitive dependency. +## Source Boundaries +- Do not hand-edit build outputs: + - `packages/*/dist/**` + - `_site/**` +- Generated source entrypoints such as `src/css/basecoat-vega.css` are committed, but must be regenerated through `scripts/generate-css-entrypoints.js` or build scripts, not manually maintained. -## Quickstart +## Public API and Markup +- Keep public component APIs small: usually one root class, semantic child elements, documented ARIA/data attributes only when needed, and minimal JS for behavior. +- Avoid required child classes when meaningful markup can identify children: `input`, `textarea`, `select`, `button`, `a`, `label`, `fieldset`, `legend`, `header`, `section`, `footer`, `svg`, `kbd`, `hr`. +- Add new child classes, wrappers, `data-*` attributes, macro arguments, or public selectors only as intentional API. +- Do not add roles for styling; ARIA must describe behavior or accessibility state. +- Prefer intentional divergence over awkward imitation when upstream markup does not map cleanly to Basecoat. -- Install deps: `npm i` -- Dev docs server: `npm run docs:dev` -- Build CSS/JS: `npm run build` -- Build static docs: `npm run docs:build` +## Accessibility +- Start with the native element that matches the control. +- Use `
` and `` for grouped form controls when appropriate. +- Use native `` where possible. +- Keep composite-widget keyboard behavior predictable: skip disabled items, respect orientation, and handle Escape/Enter/Space according to role. +- Disabled custom items must be skipped by pointer and keyboard interactions. +- Use logical CSS utilities/properties for RTL; flip only icons whose meaning is directional. -## What to edit (and what not) +## CSS +- Component CSS in `src/css/components/*.css` owns structure, layout primitives, accessibility selectors, and behavior hooks. +- Style-pack CSS in `src/css/styles/*.css` owns visual choices: color, radius, shadow/ring, typography, spacing, variants, and state visuals. +- Each style bundle must stand alone. Do not load Vega/default and then undo it in another style. +- Avoid defensive resets that only compensate for another style pack. +- Prefer Tailwind logical utilities (`ps`, `pe`, `ms`, `me`, `start`, `end`, `rounded-s`, `rounded-e`) over physical left/right utilities. +- Prefer `border` for lines and separators. +- Avoid `!important`; if unavoidable, keep the selector narrow and document why. -- Edit sources only: - - `src/css/base/base.css` – Shared base layer, tokens, and semantic utility classes - - `src/css/components/*.css` – Component CSS classes (Tailwind + custom) - - `src/css/styles/*.css` – Style-pack visual rules (`vega`, `nova`, `maia`, `lyra`, `mira`, `luma`, `sera`, `rhea`) - - `src/css/basecoat.css` – Aggregate CSS entrypoint - - `src/js/*.js` – Individual component JS files (kebab-case, ESM) + `basecoat.js` (component registry) - - `src/nunjucks/*.njk` and `src/jinja/*.html.jinja` – Component template macros - - `docs/src/components/*.md` – Component documentation pages with examples; Markdown can embed Nunjucks macros - - `docs/src/_includes/` – Layout templates, partials, and navigation -- Do not edit build outputs: - - `packages/*/dist` – built CSS/JS bundles - - `_site/` – generated docs site +## JavaScript +- JavaScript is behavior only; do not use JS to paper over CSS architecture issues. +- Register JS components with `window.basecoat.register()` and make initialization idempotent with `data-*-initialized` flags. +- Keep generated DOM minimal and aligned with documented HTML. +- Prefer native browser APIs and events. +- Keep scroll management scoped to component containers. Do not use `scrollIntoView()` when it can scroll the page unexpectedly. +- Emit custom events only for meaningful integration points. -## Project layout +## Upstream Migration +- Always check the upstream shadcn/ui repo before changing a migrated component: `https://github.com/shadcn-ui/ui`. +- Use a local copy of the upstream repo for migration work. +- Review these upstream repo paths: + - components: `apps/v4/registry/bases/base/ui/` + - docs: `apps/v4/content/docs/components/` + - examples: `apps/v4/registry/bases/base/examples/` + - styles: `apps/v4/registry/styles/style-{vega,nova,maia,lyra,mira,luma,sera,rhea}.css` +- Review Basecoat files in the same pass: + - component CSS: `src/css/components/.css` + - style packs: `src/css/styles/{vega,nova,maia,lyra,mira,luma,sera,rhea}.css` + - JS: `src/js/.js` when behavior changes + - templates: `src/nunjucks/*.njk` and `src/jinja/*.html.jinja` when markup changes + - docs: `docs/src/components/.md` +- Map upstream concepts, not implementation details. Do not port `cn-*` selectors directly. +- Classify differences as `drift fixed`, `intentional`, or `deferred`. -- Workspaces: root npm workspace with publishable packages in `packages/*`. -- Packages: - - `packages/css` – built CSS and JS bundles under `dist/`. - - `packages/cli` – CLI; distributed assets live under `dist/`. -- Docs site: `docs/src` (Eleventy); output goes to `_site/`. +## Docs +- Docs are Basecoat API docs, not React docs. +- Update docs when supported markup, variants, states, JS behavior, templates, or macros change. +- Prefer concrete HTML examples over abstract composition trees. +- Do not include React-only APIs such as `asChild`. +- Do not add "Composition" sections unless they describe stable Basecoat markup. +- Do not add API Reference sections for native/CSS-only components unless there is a real Basecoat API. +- Keep snippets minimal and aligned with current behavior. +- Document intentional differences from upstream near the relevant example. -## Style system +## Validation +- Run `npm run build` after source/package changes. +- Run `npm run docs:build` after docs or docs asset changes. +- Manually verify changed components in docs across light/dark mode, style packs, variants, RTL when supported, and relevant interaction states. -- Basecoat keeps its own component class API (`btn`, `dialog`, `popover`, etc.). Do not introduce shadcn `cn-*` classes into Basecoat source. -- Shadcn/ui style packs are used as reference material, but must be mapped onto Basecoat markup and selectors. -- Style-pack architecture is one file per style: - - `src/css/styles/vega.css` - - `src/css/styles/nova.css` - - `src/css/styles/maia.css` - - `src/css/styles/lyra.css` - - `src/css/styles/mira.css` - - `src/css/styles/luma.css` - - `src/css/styles/sera.css` - - `src/css/styles/rhea.css` -- `basecoat.css` and the default CDN bundle remain Vega-compatible for Basecoat backward compatibility. This is a Basecoat compatibility decision; upstream shadcn/ui's current default generated config is Nova. -- Non-default styles must be selected through standalone style bundles (`basecoat-