mirror of
https://github.com/hunvreus/basecoat.git
synced 2026-11-12 13:18:22 +00:00
docs: tighten repo and agent guidance
This commit is contained in:
@@ -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 `<fieldset>` and `<legend>` for grouped form controls when appropriate.
|
||||
- Use native `<dialog>` 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/<component>.css`
|
||||
- style packs: `src/css/styles/{vega,nova,maia,lyra,mira,luma,sera,rhea}.css`
|
||||
- JS: `src/js/<component>.js` when behavior changes
|
||||
- templates: `src/nunjucks/*.njk` and `src/jinja/*.html.jinja` when markup changes
|
||||
- docs: `docs/src/components/<component>.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-<style>.css`, `basecoat-<style>.cdn.css`, or docs `styles-<style>.css`). Do not load Vega/default first and then layer another style file on top.
|
||||
- Split style files under `src/css/styles/*.css` are for source organization and advanced composition only. They must map upstream style intent directly and should not contain defensive resets whose only purpose is undoing another style pack.
|
||||
- During migration, each component must be reviewed in two layers:
|
||||
- shared/base component CSS
|
||||
- style-pack CSS visual rules
|
||||
- Do not assume existing Basecoat component CSS is still the right baseline. Reassess shared rules vs style-owned rules component by component.
|
||||
- When Basecoat differs from upstream shadcn/ui, classify the difference as either intentional or drift, and prefer explicit decisions over silent divergence.
|
||||
|
||||
## Implementation philosophy
|
||||
|
||||
- Prefer the browser platform:
|
||||
- native elements before custom widgets
|
||||
- semantic HTML before generic `<div>` structures
|
||||
- CSS state selectors before JavaScript state when reliable
|
||||
- small vanilla JS behavior only when native HTML/CSS cannot provide the interaction
|
||||
- Keep public markup small and obvious. A user should be able to read a component example and understand the DOM without learning shadcn/ui internals.
|
||||
- Use the least JavaScript that preserves expected behavior, accessibility, and keyboard support.
|
||||
- Use the least CSS that preserves the visual contract and style-pack differences.
|
||||
- Use the least markup that remains semantic and accessible.
|
||||
- Prefer a single public class on the component root. Avoid requiring child classes when semantic elements, native controls, ARIA roles, or documented attributes can identify the child.
|
||||
- Child selectors should usually target meaningful HTML (`input`, `textarea`, `select`, `button`, `kbd`, `svg`, `header`, `footer`, `label`) or accessibility semantics (`role`, `aria-*`) rather than invented slot classes.
|
||||
- Do not create classes or DOM structures just because shadcn/ui has internal slots. Map upstream intent onto Basecoat's existing selectors first.
|
||||
- If a new public class, wrapper, `data-*` attribute, or macro argument is needed, treat it as API design. Make it explicit and document it.
|
||||
- Prefer direct semantic selectors where Basecoat already has a semantic structure:
|
||||
- field labels: `.field > label`, not invented `.field-label`
|
||||
- field groups: semantic `fieldset`, `[role='group']`, or `[role='radiogroup']`, not arbitrary wrappers unless documented
|
||||
- native inputs/selects/textarea should remain actual native controls where possible
|
||||
- Avoid purely decorative components when composition is enough. Document patterns instead of adding API surface.
|
||||
- Keep generated or copied shadcn/ui implementation details out of Basecoat:
|
||||
- no `cn-*` classes
|
||||
- no `data-slot` dependency unless Basecoat explicitly owns that API
|
||||
- no React/Base UI/Radix-specific DOM assumptions
|
||||
- Prefer intentional divergence over awkward imitation. If upstream behavior does not map cleanly to native markup, document the Basecoat behavior and why.
|
||||
|
||||
## Markup and accessibility rules
|
||||
|
||||
- Start from the semantic element that matches the control:
|
||||
- button action: `<button>`
|
||||
- navigation/action link: `<a>`
|
||||
- text input: `<input>`
|
||||
- multiline input: `<textarea>`
|
||||
- native select: `<select>`
|
||||
- grouped form controls: `<fieldset>` + `<legend>` when appropriate
|
||||
- dialog: native `<dialog>` when possible
|
||||
- Add ARIA only when native semantics are insufficient or a custom interaction needs it.
|
||||
- ARIA must reflect behavior, not styling. Do not add roles just to target CSS.
|
||||
- Disabled items must be excluded from keyboard and pointer interactions where custom JS is involved.
|
||||
- For composite widgets, keep keyboard behavior predictable:
|
||||
- roving/highlight state should skip disabled items
|
||||
- Escape closes popovers/dialogs where expected
|
||||
- Arrow keys should match orientation
|
||||
- Enter/Space behavior should match the control role
|
||||
- RTL support should use logical properties/utilities by default. Use explicit `:dir(rtl)` only when logical utilities cannot express the behavior.
|
||||
- Directional icons are not automatically flipped. Flip only icons whose meaning is directional.
|
||||
|
||||
## CSS architecture rules
|
||||
|
||||
- Shared component CSS in `src/css/components/*.css` should own structure, layout primitives, accessibility selectors, and behavior hooks.
|
||||
- Style-pack CSS in `src/css/styles/*.css` should own visual choices:
|
||||
- color
|
||||
- radius
|
||||
- shadow/ring
|
||||
- typography
|
||||
- spacing that is style-specific
|
||||
- variant visuals
|
||||
- state visuals that differ by style
|
||||
- Do not put style-pack defaults in component CSS and then override them later. Each style bundle must stand on its own.
|
||||
- Avoid defensive resets that exist only because another style was loaded first. Non-default style bundles should not depend on Vega/default being loaded.
|
||||
- Use Tailwind logical utilities (`ps`, `pe`, `ms`, `me`, `start`, `end`, `rounded-s`, `rounded-e`) instead of physical left/right when possible.
|
||||
- Prefer compact selectors with `:is()` and `:has()`, but only when they keep the public API clearer.
|
||||
- Use `border` for separators and lines, especially `<hr>`/separator elements. Avoid fake separator backgrounds unless upstream behavior requires it and markup supports it.
|
||||
- Keep visual rules close to the component style block. Do not scatter one component's style-pack rules across unrelated sections.
|
||||
- When using pseudo-elements for native controls, keep the native control accessible and form-submittable.
|
||||
- Avoid `!important`. Use it only when matching upstream behavior or browser-native styling makes it unavoidable, and keep the selector narrow.
|
||||
|
||||
## JavaScript rules
|
||||
|
||||
- JavaScript files are behavior only. Do not use JS to paper over CSS architecture issues.
|
||||
- Every JS component must register with `window.basecoat.register()` and be safe to initialize multiple times.
|
||||
- Use `data-*-initialized` flags for idempotence.
|
||||
- Emit custom events for meaningful user actions when useful for integration.
|
||||
- Keep generated DOM minimal and consistent with the documented HTML structure.
|
||||
- Do not couple unrelated components through hidden assumptions. If Select and Combobox share behavior, factor it deliberately or keep their files separate when the UX differs.
|
||||
- Prefer native browser APIs:
|
||||
- native `<dialog>` before custom modal stacks
|
||||
- native form controls before custom controls
|
||||
- native events before synthetic abstractions
|
||||
- If JS is needed only to sync visual state, keep it small and local. Example: `range.js` only syncs `--slider-value`.
|
||||
|
||||
## Basecoat vs upstream shadcn/ui
|
||||
|
||||
- Always check upstream before changing a migrated component:
|
||||
- component source under `../_sandbox/shadcn-ui/apps/v4/registry/bases/base/ui/`
|
||||
- docs under `../_sandbox/shadcn-ui/apps/v4/content/docs/components/`
|
||||
- examples under `../_sandbox/shadcn-ui/apps/v4/registry/bases/base/examples/`
|
||||
- all eight style packs under `../_sandbox/shadcn-ui/apps/v4/registry/styles/`
|
||||
- Map upstream concepts, not upstream implementation details.
|
||||
- When upstream uses composed React subcomponents, decide whether Basecoat needs:
|
||||
- one semantic element
|
||||
- a small documented structure
|
||||
- a macro helper
|
||||
- a JS component
|
||||
- only docs, with no new component
|
||||
- When upstream supports behavior that does not map to Basecoat's native implementation, document the gap instead of faking it.
|
||||
- Example: Basecoat Slider uses native single-thumb range inputs; upstream Slider supports multi-thumb and vertical orientation.
|
||||
- Example: Basecoat Tooltip is CSS-only text content; upstream Tooltip supports portalled arbitrary content.
|
||||
- Example: Basecoat Select/Combobox popovers remain inline-positioned rather than matching every portalled positioning behavior.
|
||||
- Style parity matters, but not at the cost of worse Basecoat markup.
|
||||
- If a discrepancy is found, classify it:
|
||||
- `drift fixed`: Basecoat was simply out of date
|
||||
- `intentional`: Basecoat differs because of semantic/native/vanilla constraints
|
||||
- `deferred`: valid upstream feature, not implemented yet
|
||||
|
||||
## Documentation rules
|
||||
|
||||
- Component docs are part of the component API. Update docs whenever CSS, JS, templates, variants, supported states, or supported markup changes.
|
||||
- Docs should be Basecoat docs, not copied React docs. Do not include useless React-specific API tables, `asChild`, or composition diagrams that do not match Basecoat markup.
|
||||
- Prefer concrete HTML examples over abstract component trees.
|
||||
- Each component page should generally include:
|
||||
- frontmatter title/description/toc
|
||||
- a top preview using the most common/default example
|
||||
- `Usage`
|
||||
- install/include notes for JS components
|
||||
- a minimal HTML example
|
||||
- `HTML structure` or class/API notes when the markup is not self-evident
|
||||
- examples aligned with upstream where they apply
|
||||
- Basecoat-specific differences and unsupported upstream features
|
||||
- RTL example or an explicit note if RTL is deferred
|
||||
- For JS components, include:
|
||||
- required script tags (`basecoat.min.js` plus component file, unless included in all bundle)
|
||||
- initialization expectations
|
||||
- custom events when relevant
|
||||
- config object shape when relevant
|
||||
- macro links if Nunjucks/Jinja macros exist
|
||||
- For CSS-only/native components, do not invent an API Reference section unless there is a real Basecoat API to document.
|
||||
- Do not add "Composition" sections unless the component truly has a stable Basecoat composition pattern. If the section only mirrors shadcn/ui React internals, remove it.
|
||||
- Examples should be realistic and named clearly:
|
||||
- `Default`
|
||||
- `Disabled`
|
||||
- `Invalid`
|
||||
- `Groups`
|
||||
- `Scrollable`
|
||||
- `RTL`
|
||||
- style/variant/size examples when applicable
|
||||
- If Basecoat intentionally differs from upstream, say it near the relevant usage/example section.
|
||||
- Keep snippets minimal. Avoid giant copied examples unless the structure is genuinely important.
|
||||
- For deprecated or removed APIs, update the page and `CHANGELOG.md`/migration notes rather than leaving stale examples.
|
||||
|
||||
## Component migration workflow
|
||||
|
||||
For each component migration, follow this sequence:
|
||||
|
||||
1. Review the current Basecoat component CSS and markup/templates first.
|
||||
2. Review the latest upstream shadcn/ui base component source for the equivalent component.
|
||||
3. Review the relevant sections in all eight upstream style packs (`vega`, `nova`, `maia`, `lyra`, `mira`, `luma`, `sera`, `rhea`).
|
||||
4. Decide what belongs in shared Basecoat component CSS versus what belongs in style-pack CSS.
|
||||
5. Keep Basecoat selectors and markup. Do not port shadcn `cn-*` selectors directly.
|
||||
6. Remove outdated Basecoat visual rules from the shared component CSS if those rules are now style-owned.
|
||||
7. Audit RTL support:
|
||||
- check upstream `*-rtl` examples and generated `ui-rtl` component code when present
|
||||
- prefer logical utilities/properties (`ps`, `pe`, `rounded-s`, `rounded-e`, `border-s`, `start`, `end`) over duplicated `:dir(rtl)` branches
|
||||
- flip only directional icons explicitly; do not auto-flip all icons
|
||||
8. Audit standalone style behavior:
|
||||
- verify each style in its own full bundle, not layered over another style pack
|
||||
- compare state selectors (`focus-visible`, `aria-invalid`, `hover`, open/selected states) against upstream for that specific style
|
||||
- avoid `!important` unless upstream behavior or Basecoat markup truly requires it
|
||||
9. Implement or update the component section in:
|
||||
- `src/css/components/<component>.css`
|
||||
- `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`
|
||||
10. Document any non-trivial difference from upstream as either:
|
||||
- intentional
|
||||
- drift fixed
|
||||
- deferred
|
||||
11. Update the migration tracker entry for the component.
|
||||
12. Review and align the component docs against the current upstream docs page:
|
||||
- include equivalent examples where they apply
|
||||
- rename labels/anchors to match upstream where reasonable
|
||||
- document Basecoat-specific differences and extras
|
||||
- add or update the Basecoat class/API reference
|
||||
- call out unsupported or deferred upstream features explicitly
|
||||
- include an RTL section when supported, or document RTL as deferred
|
||||
13. Run `npm run build` after each component migration.
|
||||
14. Run `npm run docs:build` when docs or docs style assets change.
|
||||
15. Manually verify the component in docs for:
|
||||
- light and dark mode
|
||||
- all supported variants and sizes
|
||||
- RTL with `dir="rtl"` when supported
|
||||
- interaction states (`hover`, `focus`, `disabled`, `aria-invalid`, open/selected states when relevant)
|
||||
|
||||
Per-component file checklist:
|
||||
|
||||
1. Basecoat component CSS: `src/css/components/<component>.css`
|
||||
2. Basecoat templates/macros if relevant: `src/nunjucks/*.njk`, `src/jinja/*.html.jinja`
|
||||
3. Basecoat docs page: `docs/src/components/<component>.md`
|
||||
4. Upstream base component: `../_sandbox/shadcn-ui/apps/v4/registry/bases/base/ui/<component>.tsx`
|
||||
5. Upstream docs page: `../_sandbox/shadcn-ui/apps/v4/content/docs/components/{base,radix}/<component>.mdx`
|
||||
6. Upstream styles: `../_sandbox/shadcn-ui/apps/v4/registry/styles/style-{vega,nova,maia,lyra,mira,luma,sera,rhea}.css`
|
||||
7. Basecoat styles: `src/css/styles/{vega,nova,maia,lyra,mira,luma,sera,rhea}.css`
|
||||
|
||||
## Conventions
|
||||
|
||||
- ESM everywhere (`import`/`export`).
|
||||
- Prettier defaults (2 spaces; single quotes per file preference).
|
||||
- Filenames for assets: kebab-case (e.g., `dropdown-menu.js`, `basecoat.cdn.css`).
|
||||
- JS naming: `camelCase` for vars/functions; `PascalCase` for DOM classes and exported component names when applicable.
|
||||
|
||||
## Design Principles
|
||||
|
||||
- **Minimal code**: Prefer native HTML elements and browser behavior over JavaScript abstractions
|
||||
- **Accessibility-first**: Semantic HTML, proper ARIA attributes, keyboard navigation
|
||||
- **CSS patterns**:
|
||||
- Use `border` for lines/separators (not `background` on `<hr>`)
|
||||
- Use `:is()` and `:has()` for compact selectors
|
||||
- Use `isolation: isolate` to contain z-index stacking contexts
|
||||
- Use `data-*` attributes for styling states, `aria-*` for accessibility semantics
|
||||
- **Component patterns**:
|
||||
- Dialog variants use wrapper classes (e.g., `.command-dialog` wraps `.command`)
|
||||
- JavaScript components register with `window.basecoat.register()`
|
||||
- Emit custom events for user actions (e.g., `command:select`)
|
||||
- Filter disabled options (`aria-disabled="true"`) from all interactions
|
||||
- **When NOT to create a component**:
|
||||
- If it's just composition of existing elements (users can do it with standard HTML/Tailwind)
|
||||
- If behavior is fully native (e.g., fieldset, legend)
|
||||
|
||||
## Adding new components
|
||||
|
||||
Before creating a component, ask:
|
||||
1. Does shadcn/ui have it? → Port it
|
||||
2. Is it pure composition? → Document pattern, no component
|
||||
3. Does it need JS behavior? → Create component
|
||||
4. Is it just CSS? → Add to basecoat.css, document usage
|
||||
|
||||
Examples:
|
||||
- Field/Fieldset: CSS-only patterns (no JS component)
|
||||
- Empty/Item: Pure composition unless a future pass proves a root class is needed
|
||||
- Input Group: Lightweight CSS component with a single `.input-group` root class, semantic children, optional `data-align`, and `data-control` for custom controls
|
||||
- Command/Select: JS behavior required (full component)
|
||||
|
||||
## Common tasks
|
||||
|
||||
- Update a component's CSS/JS: Edit `src/css/basecoat.css` and/or `src/js/*.js`.
|
||||
- Update a component's CSS/JS: Edit the relevant file in `src/css/components/*.css`, `src/css/styles/*.css`, and/or `src/js/*.js`.
|
||||
- Update a component template: Edit `src/nunjucks/*.njk` and/or `src/jinja/*.html.jinja`.
|
||||
- Add a new component: Create JS, CSS, templates, and docs page under `docs/src/components/*.md`.
|
||||
- Update navigation: Edit files in `docs/src/_includes/partials/`.
|
||||
|
||||
## Testing
|
||||
|
||||
No automated testing configured. User validates manually via the docs site (`npm run docs:dev`).
|
||||
|
||||
## Commits and PRs
|
||||
|
||||
- Commits: concise, imperative (≤72 chars), optional scope.
|
||||
- Example: `select: prevent change event on init`.
|
||||
- PRs: include description, linked issues (e.g., `Closes #123`), and before/after screenshots or code snippets for visual/behavioral changes.
|
||||
- Keep PRs focused; update docs examples when components or APIs change.
|
||||
|
||||
## Environment and tooling
|
||||
|
||||
- Node 18+ recommended.
|
||||
- Eleventy config: `.eleventy.js`.
|
||||
- Tailwind via `@tailwindcss/cli` v4.
|
||||
- Build uses Tailwind CLI and `terser`; both are provided via devDependencies.
|
||||
|
||||
## Git workflow
|
||||
|
||||
- `.gitattributes` configures merge strategies for generated files
|
||||
- `docs/src/assets/styles.css` auto-resolves to incoming changes (regenerated by Tailwind)
|
||||
- Always run `npm run build` before publishing packages
|
||||
|
||||
## Publishing packages
|
||||
|
||||
1. Bump version in root `package.json`
|
||||
2. Run `npm run build` to generate dist files
|
||||
3. Run `npm publish --workspaces` to publish both packages
|
||||
|
||||
## Package references
|
||||
|
||||
- `packages/css` usage and details: see `packages/css/README.md`.
|
||||
- `packages/cli` usage and details: see `packages/cli/README.md`.
|
||||
## Change Management
|
||||
- Ask before removing intentional functionality or public API.
|
||||
- Preserve backward compatibility when the repo already depends on it, especially package exports and default `basecoat.css` behavior.
|
||||
- Keep generated outputs and docs consistent with source changes.
|
||||
- Remove stale comments/docs during refactors.
|
||||
- Keep commits focused and imperative.
|
||||
- Keep release-visible changes in `CHANGELOG.md` under `## [Unreleased]`; put backlog or incomplete work in `TODO.md` or the migration tracker.
|
||||
|
||||
@@ -1,29 +1,125 @@
|
||||
# Basecoat
|
||||
|
||||
A collection of modern UI components built with Tailwind CSS that works with any web stack. Basecoat brings the magic of [shadcn/ui](https://ui.shadcn.com) to traditional web applications, no React required.
|
||||
Basecoat is a Tailwind CSS, vanilla HTML/CSS/JavaScript implementation of the shadcn/ui design system. It provides shadcn-style components for any web stack without React, Radix, or framework runtime dependencies.
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
- **Lightweight**: no runtime JS, just CSS and a tiny bit of vanilla JavaScript for the more interactive components.
|
||||
- **Easy to use**: add classes like `btn` or `input` and you're done.
|
||||
- **Framework-agnostic**: works with any backend or frontend stack.
|
||||
- **Accessible**: components follow accessibility best practices.
|
||||
- **Dark mode ready**: respects your Tailwind config.
|
||||
- **Extendable**: tweak styles with Tailwind or CSS variables.
|
||||
- **Themable**: fully compatible with shadcn/ui themes.
|
||||
- **Readable**: no class soup, just clean markup.
|
||||
- **Free and open source**: MIT licensed.
|
||||
- Semantic HTML-first components.
|
||||
- Tailwind CSS v4 source files and generated CSS bundles.
|
||||
- Small vanilla JavaScript for components that need behavior.
|
||||
- Nunjucks and Jinja template macros.
|
||||
- Standalone style packs: Vega, Nova, Maia, Lyra, Mira, Luma, Sera, and Rhea.
|
||||
- Dark mode and CSS variable theming.
|
||||
- CDN, npm, and CLI usage paths.
|
||||
|
||||
## Documentation
|
||||
|
||||
Visit [basecoatui.com](https://basecoatui.com).
|
||||
- Website: [basecoatui.com](https://basecoatui.com)
|
||||
- Installation: [basecoatui.com/installation](https://basecoatui.com/installation)
|
||||
- Customization: [basecoatui.com/customization](https://basecoatui.com/customization)
|
||||
|
||||
## Installation
|
||||
## Packages
|
||||
|
||||
Visit [basecoatui.com/installation](https://basecoatui.com/installation)
|
||||
This repository publishes two workspace packages:
|
||||
|
||||
- `basecoat-css`: CSS, JavaScript, Nunjucks macros, and Jinja macros.
|
||||
- `basecoat-cli`: CLI for adding Basecoat assets to a project.
|
||||
|
||||
Package details live in:
|
||||
|
||||
- `packages/css/README.md`
|
||||
- `packages/cli/README.md`
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install basecoat-css
|
||||
```
|
||||
|
||||
Use the default bundle:
|
||||
|
||||
```css
|
||||
@import "tailwindcss";
|
||||
@import "basecoat-css";
|
||||
```
|
||||
|
||||
Use a specific style bundle:
|
||||
|
||||
```css
|
||||
@import "tailwindcss";
|
||||
@import "basecoat-css/nova";
|
||||
```
|
||||
|
||||
Use the styleless base plus a custom style file:
|
||||
|
||||
```css
|
||||
@import "tailwindcss";
|
||||
@import "basecoat-css/base";
|
||||
@import "./style-acme.css";
|
||||
```
|
||||
|
||||
## Repository Layout
|
||||
|
||||
```text
|
||||
.
|
||||
├── docs/
|
||||
│ └── src/ Eleventy documentation site
|
||||
├── packages/
|
||||
│ ├── cli/ Published CLI package
|
||||
│ └── css/ Published CSS package
|
||||
├── scripts/ Build and generation scripts
|
||||
└── src/
|
||||
├── css/
|
||||
│ ├── base/ Shared tokens, base layer, and semantic utilities
|
||||
│ ├── components/ Component structure and behavior hooks
|
||||
│ └── styles/ Style-pack visual rules
|
||||
├── jinja/ Jinja component macros
|
||||
├── js/ Vanilla JS components and registry
|
||||
└── nunjucks/ Nunjucks component macros
|
||||
```
|
||||
|
||||
## CSS Architecture
|
||||
|
||||
Basecoat separates structure from style:
|
||||
|
||||
- `src/css/base/base.css`: shared tokens and semantic utilities.
|
||||
- `src/css/components/*.css`: component layout, structure, accessibility selectors, and behavior hooks.
|
||||
- `src/css/styles/*.css`: style-pack visuals such as color, radius, shadow, typography, spacing, variants, and state styles.
|
||||
|
||||
Generated source entrypoints are committed for transparency and package imports:
|
||||
|
||||
- `src/css/basecoat.css`: default backward-compatible Vega bundle.
|
||||
- `src/css/basecoat-base.css`: base plus components, no style pack.
|
||||
- `src/css/basecoat-components.css`: component imports only.
|
||||
- `src/css/basecoat-<style>.css`: base plus one style pack.
|
||||
- `src/css/basecoat-<style>.cdn.css`: CDN-compatible wrapper.
|
||||
|
||||
These entrypoints are generated by `scripts/generate-css-entrypoints.js` and by the build scripts.
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm i
|
||||
|
||||
# Run the docs site
|
||||
npm run docs:dev
|
||||
|
||||
# Build package assets
|
||||
npm run build
|
||||
|
||||
# Build the static docs site
|
||||
npm run docs:build
|
||||
|
||||
# Run the Workers docs site locally
|
||||
npm run workers:dev
|
||||
|
||||
# Deploy the Workers docs site
|
||||
npm run workers:deploy
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](/LICENSE.md)
|
||||
[MIT](LICENSE.md)
|
||||
|
||||
Reference in New Issue
Block a user