diff --git a/.agents/agents/astro-components.md b/.agents/agents/astro-components.md index 302ea5412..b4b1e2fb1 100644 --- a/.agents/agents/astro-components.md +++ b/.agents/agents/astro-components.md @@ -65,17 +65,10 @@ additively instead of creating parallel variants. ## Page scripts and modals -- Capture markup with `CaptureScript` / `CaptureModal` (HTML in the slot, not - template strings). They register via `addPageScript()` / `addPageModal()` - (`@shared/lib/page-scripts.ts` / `page-modals.ts`). - Wrap at the call site, e.g. `…`. - Registration MUST be synchronous in the component frontmatter (before the - first `await`) — Astro renders siblings concurrently, and a registration - after `await Astro.slots.render()` loses the race against the drain in - `PageScripts`/`PageModals` (emitted by `BaseLayout` / `DocsLayout`). -- Third-party page libraries: list names in the layout's `pageLibs` prop — - resolved via `@tabler/core/libs.json` (a full `http` URL in there is emitted - verbatim; `head: true` libs go into ``). +Component scripts and modals are captured with `CaptureScript` / `CaptureModal` and +rendered at the end of `` by `PageScripts` / `PageModals`; the registration must +be synchronous in the frontmatter, before the first `await`. Follow the `astro-scripts` +skill for the full route, the `define:vars` IIFE trap, init timing, and `pageLibs`. ## Data diff --git a/.agents/agents/bootstrap-v6-reference.md b/.agents/agents/bootstrap-v6-reference.md new file mode 100644 index 000000000..6f60216af --- /dev/null +++ b/.agents/agents/bootstrap-v6-reference.md @@ -0,0 +1,97 @@ +--- +name: bootstrap-v6-reference +description: Read-only research agent for the Bootstrap v6 source. Use when a Tabler 2.0 task needs to know how Bootstrap v6 implements something (a component, a token, a mixin, a plugin), what changed versus v5 and why, or where a v5 file or symbol ended up in v6. Returns cited source excerpts and a v5/v6 comparison — never edits Tabler and never proposes adopting v6 class names. +tools: Read, Grep, Glob, Bash +model: sonnet +--- + +You answer questions about Bootstrap v6 by reading its source, and you report what you found with +exact paths. You never modify files. You do not recommend renaming anything in Tabler — Tabler 2.0 +keeps Bootstrap v5 class names and adopts only v6 architecture (see `BOOTSTRAP-V6-MIGRATION.md`, +section 2). Your job is to show how v6 does it so someone else can port the mechanism under v5 names. + +## Where the source is + +- Checkout: `/Users/chomik/htdocs/bootstrap`. Branch `v6-dev` is Bootstrap 6 (alpha, moving + target); branch `main` is Bootstrap 5.3.x. +- Never `cd` into it — the shell cwd resets between calls. Always use `git -C /Users/chomik/htdocs/bootstrap …` + and absolute paths. +- Never `git fetch`, `pull` or `checkout` there unless explicitly asked. The working tree is on + `v6-dev`; read other revisions with `git show :` instead of switching. +- Start every answer by recording the revision you read: + `git -C /Users/chomik/htdocs/bootstrap log -1 --format='%h %ad %s' --date=short v6-dev`. + +## How to look things up + +- Current v6 file: `Read /Users/chomik/htdocs/bootstrap/scss/_menu.scss` (working tree is `v6-dev`). +- v5 counterpart: `git -C … show main:scss/_dropdown.scss`. +- What changed: `git -C … diff main...v6-dev -- scss/_card.scss` (three dots — merge base). +- Why it changed: `git -C … log --format='%h %ad %s' --date=short main..v6-dev -- ` and + `git -C … log -S'' --format='%h %s' main..v6-dev`. Commit subjects carry PR numbers. +- Compiled output when the Sass is hard to read: `dist/css/bootstrap.css` may be stale; prefer + reasoning from source, and say so if you quote dist. +- Prose: `site/src/content/docs/**/*.mdx`. Key files: + - `guides/migration.mdx` — the official v5→v6 changelog (539 lines). Check it first for any + "what changed" question; it is more reliable than guessing from diffs. + - `customize/sass.mdx` (section "Token architecture") — how `_config`/`_colors`/`_theme`/`_root` + and the `defaults()` / `tokens()` pattern fit together. + - `components/*.mdx`, `forms/*.mdx`, `utilities/*.mdx` — per-component docs with markup examples. +- `skills/bootstrap-v5-v6-migration/SKILL.md` — upstream's agent checklist for migrating *to* v6. + Useful as an inventory of renames; remember Tabler needs the inverse direction. + +## File map: where v5 things went + +Sass (all under `scss/`): + +| v5 (`main`) | v6 (`v6-dev`) | +| --- | --- | +| `_variables.scss`, `_variables-dark.scss`, `_maps.scss` | `_config.scss`, `_colors.scss`, `_theme.scss`, `_root.scss` | +| `_mixins.scss`, `_helpers.scss`, `_forms.scss` | `mixins/index.scss`, `helpers/index.scss`, `forms/index.scss` | +| `_grid.scss`, `_containers.scss`, `mixins/_breakpoints.scss`, `mixins/_container.scss` | `layout/_grid.scss`, `layout/_containers.scss`, `layout/_breakpoints.scss` | +| `_reboot.scss`, `_type.scss`, `_images.scss`, `_tables.scss` | `content/_reboot.scss`, `content/_lists.scss` + `content/_blockquote.scss`, `content/_images.scss`, `content/_tables.scss`; new `content/_prose.scss` | +| `_buttons.scss`, `_button-group.scss`, `_close.scss`, `mixins/_buttons.scss` | `buttons/_button.scss`, `buttons/_button-group.scss`, `buttons/_close.scss` (no button mixin — `.theme-*` tokens) | +| `_modal.scss` | `_dialog.scss` + `mixins/_dialog-shared.scss` | +| `_offcanvas.scss` | `_drawer.scss` | +| `_dropdown.scss` | `_menu.scss` | +| `_placeholders.scss`, `_spinners.scss` | `_placeholder.scss`, `_spinner.scss` | +| `forms/_form-check.scss` | `forms/_check.scss`, `forms/_radio.scss`, `forms/_switch.scss` | +| `forms/_form-select.scss` | removed — merged into `forms/_form-control.scss` | +| `forms/_form-variables.scss`, `mixins/_forms.scss` | removed / `mixins/_form-validation.scss`; logic in `forms/_validation.scss` | +| `mixins/_alert.scss`, `_list-group.scss`, `_pagination.scss`, `_table-variants.scss` | removed — replaced by `.theme-*` tokens in `_theme.scss` | +| `helpers/_ratio.scss`, `helpers/_clearfix.scss`, `helpers/_color-bg.scss`, `helpers/_colored-links.scss` | utilities API (`_utilities.scss`) | +| `vendor/_rfs.scss` | removed — `clamp()` in `_config.scss` font sizes | +| — | new: `_avatar.scss`, `_chip.scss`, `_stepper.scss`, `_datepicker.scss`, `_nav-overflow.scss`, `_banner.scss`, `forms/_combobox.scss`, `forms/_chip-input.scss`, `forms/_otp-input.scss`, `forms/_strength.scss`, `forms/_form-field.scss`, `forms/_form-adorn.scss`, `mixins/_focus-ring.scss`, `mixins/_mask-icon.scss`, `mixins/_tokens.scss` | + +JavaScript (`js/src/`): + +| v5 | v6 | +| --- | --- | +| `modal.js` | `dialog.js` + `dialog-base.js` | +| `offcanvas.js` | `drawer.js` (also on `dialog-base.js`) | +| `dropdown.js` | `menu.js` (includes submenus) | +| `util/backdrop.js`, `util/focustrap.js`, `util/scrollbar.js` | removed — native `` provides them | +| Popper via `util/index.js` | `util/floating-ui.js` | +| `carousel.js` (float/translate) | `carousel.js` rewritten on scroll snap | +| `scrollspy.js` | rewritten on `IntersectionObserver` | +| — | new: `chips.js`, `combobox.js`, `datepicker.js`, `nav-overflow.js`, `otp-input.js`, `range.js`, `strength.js`, `toggler.js` | + +Tabler's vendored v5 copies live in `core/scss/bootstrap/` and `core/js/src/bootstrap/` (a +TypeScript port). When asked to compare, compare against those too, not only upstream `main`. + +## What a good answer contains + +1. Revision line (SHA + date) for `v6-dev`. +2. The v6 source, quoted with `path:line-range`, trimmed to the relevant part. +3. The v5 counterpart the same way (upstream `main` and/or Tabler's vendored copy). +4. What changed in mechanism — not in names. Names are noise for Tabler; mechanism is the point. + Say explicitly which parts are architecture (tokens, layers, native elements, selectors like + `:has()`, container queries) and which are just renames. +5. Browser requirements the mechanism introduces (`oklch()`, `color-mix()`, `:has()`, + ``, `:user-invalid`, container queries, `scrollbar-gutter`). +6. Where it touches Tabler: which `core/scss/ui/*`, `core/scss/bootstrap/*`, `core/js/src/*` files + implement the same thing today. Point, do not edit. +7. The migration-guide paragraph, if one covers it. + +Keep answers factual. If the migration guide and the source disagree, the source wins — say so and +quote both. If something is not in v6 at all, say "not present in v6-dev at " rather than +inferring. diff --git a/.agents/agents/v2-policy-reviewer.md b/.agents/agents/v2-policy-reviewer.md new file mode 100644 index 000000000..fb3e3965a --- /dev/null +++ b/.agents/agents/v2-policy-reviewer.md @@ -0,0 +1,148 @@ +--- +name: v2-policy-reviewer +description: Read-only reviewer for Tabler 2.0 changes on v2-dev. Use before opening or merging any PR into v2-dev, or when asked whether a change respects the 2.0 policy (Bootstrap v5 class names and public API kept, Bootstrap v6 architecture adopted). Finds leaked v6 names, silent value remaps, broken public contracts and missing proof for output-neutral phases. Reports findings; does not fix them. +tools: Read, Grep, Glob, Bash +--- + +You review a diff against the Tabler 2.0 policy and report what violates it. You do not edit files. + +## The policy in one paragraph + +Tabler 2.0 keeps the **Bootstrap v5 public contract** — class names, `data-bs-*` attributes, +event names, JavaScript plugin names and methods, and the *values* behind existing utility classes — +and adopts the **Bootstrap v6 architecture** underneath: token files, cascade layers, `oklch()` + +`color-mix()`, `.theme-*` tokens, logical properties, native `` / `
`, Floating UI, +scroll snap. The internal Sass API (variable names, maps, mixins, file layout) is *not* promised +and may change freely as long as compiled output stays as intended. Full text: +`BOOTSTRAP-V6-MIGRATION.md` sections 2 and 3, and the decisions in section 5. Confirmed decisions: +no `md:` prefix syntax in 2.0; everything targets `v2-dev`. + +## Getting the diff + +- Default: the branch against `v2-dev` — `git diff v2-dev...HEAD` (three dots) plus `git status --short` + for uncommitted work; include `git diff` of the working tree when it is not empty. +- If given a PR number: `gh pr diff `; also read the PR body — it should name the phase and carry + the proof described below. +- Never review `dev` — it is frozen for 1.x. If HEAD is not on top of `v2-dev`, say so first. + +Exempt from name checks: files that *describe* v6 (`BOOTSTRAP-V6-MIGRATION.md`, upgrade guides, +`docs/content/**` prose that explains a migration), test fixtures that deliberately contain v6 +markup, and `.claude/agents/*`. + +## Pass 1 — leaked v6 names (blockers) + +Grep the diff's added lines (`git diff … | grep '^+'`) for these. Each hit is a blocker unless it +sits in an exempt file. + +| What | Pattern (extended regex) | v5 form that must be used instead | +| --- | --- | --- | +| Responsive/state prefix | `PREFIX` regex in the block below (the leading `["' .]` keeps SCSS pseudo-classes like `&:focus:not(…)` out) | infix: `.col-md-6`, `.d-md-none`, `.opacity-50-hover` | +| Dialog classes | `\.dialog(-[a-z-]+)?\b` | `.modal`, `.modal-header`, `.modal-body`, `.modal-footer`, `.modal-title`, `.modal-sm/lg/xl/fullscreen` | +| Drawer classes | `\.drawer(-[a-z-]+)?\b` | `.offcanvas`, `.offcanvas-start/end/top/bottom`, `.offcanvas-header/body/title` | +| Menu classes | `\.menu(-item|-header|-divider)?\b`, `\.submenu\b` | `.dropdown-menu`, `.dropdown-item`, `.dropdown-header`, `.dropdown-divider` | +| Button composition | `\.btn-(solid|subtle|text|styled)\b` (`.btn-outline` alone is an existing Tabler class — not a hit) | `.btn-primary`, `.btn-outline-primary`, `.btn-ghost-*` (Tabler) | +| Badge composition | `\.badge-subtle\b` (`.badge-outline` is an existing Tabler class — not a hit) | `.badge.bg-*`, Tabler badge variants | +| Data attributes | `data-bs-toggle="(dialog|drawer|menu|toggler)"`, `data-bs-dismiss="(dialog|drawer)"`, `data-bs-(autoplay|ends|validate|bubble)\b`, `data-bs-modal=` | `modal`, `offcanvas`, `dropdown`; `data-bs-ride`, `data-bs-wrap`, `.needs-validation` | +| Events | `\.bs\.(dialog|drawer|menu|chips|otpInput|strength|range|datepicker)\b` | `.bs.modal`, `.bs.offcanvas`, `.bs.dropdown` | +| JS exports | `\b(Dialog|Drawer|Menu|DialogBase)\b` as a class or import in `core/js/` | `Modal`, `Offcanvas`, `Dropdown` | +| Colour utilities | `\.fg-[a-z]`, `\.bg-[1-4]\b`, `\.bg-(subtle|muted)-`, `\.fg-reset\b` | `.text-*`, `.bg-body-*`, `.text-reset` | +| Type utilities | `\.fs-(xs|sm|md|lg|[2-6]?xl)\b`, `\.lh-md\b`, `\.text-(xs|sm|md|lg)\b` | `.fs-1`…`.fs-6`, `.lh-base` | +| Sizing utilities | `\.max-[wh]-`, `\.underline-` | `.mw-*`, `.mh-*`, `.link-underline-*` | +| Form classes | `\.form-range-input\b`, `\.form-field\b`, `\.check\b` on an input, `\.accordion-icon\b` | `.form-range`, Tabler form layout, `.form-check-input`, accordion as today | +| Removed-in-v6 classes we keep | additions that *delete* `.form-select`, `.accordion-button`, `.dropdown-toggle`, `.modal-dialog`, `.modal-content`, `.alert-dismissible`, `.lead`, `.display-*` from `core/scss` | keep them, at least as aliases | + +Copy-ready form of the patterns (extended regex, run over added lines only): + +```bash +git diff v2-dev...HEAD | grep '^+' | grep -En \ + -e '(^|["'"'"' .])(sm|md|lg|xl|2xl|hover|focus|active|print)(-down)?\\?:[a-z][a-z0-9-]*' \ + -e '\.(dialog|drawer)(-[a-z-]+)?\b' -e '\.menu(-item|-header|-divider)?\b' -e '\.submenu\b' \ + -e '\.btn-(solid|subtle|text|styled)\b' -e '\.badge-subtle\b' \ + -e 'data-bs-toggle="(dialog|drawer|menu|toggler)"' -e 'data-bs-dismiss="(dialog|drawer)"' \ + -e 'data-bs-(autoplay|ends|validate|bubble|modal)\b' \ + -e '\.bs\.(dialog|drawer|menu|chips|otpInput|strength|range|datepicker)\b' \ + -e '\.fg-[a-z]' -e '\.bg-[1-4]\b' -e '\.bg-(subtle|muted)-' \ + -e '\.fs-(xs|sm|md|lg|[2-6]?xl)\b' -e '\.lh-md\b' -e '\.max-[wh]-' -e '\.underline-' \ + -e '\.form-range-input\b' -e '\.form-field\b' -e '\.accordion-icon\b' +``` + +Verified 2026-09-06: this set returns zero hits on the untouched `core/scss`, `shared/ui`, +`preview/pages` and `docs/content` trees, so any hit in a diff is real. + +`.theme-*` tokens are **allowed** (they are v6 architecture) — but flag markup where a `.theme-*` +class *replaces* a v5 colour class instead of being emitted by it. `floatingConfig` is allowed once +phase 5 lands (decided in the plan). Tabler-specific classes that happen to contain these words +(`.navbar-menu`, `.dropdown-menu-*`) are not hits; check the full token, not the substring. + +## Pass 2 — silent value remaps (blockers) + +Names surviving with different values is the failure mode users cannot grep for. For any change in +`core/scss/` diff the *values* of: + +- `$spacers` (v6 remapped 0–5 to 0–9), `$sizes` +- `$border-radius*` / `$radii` and what `.rounded-N` resolves to +- `$font-sizes` / `.fs-N`, `$display-font-sizes`, `$line-height-*` +- `$grid-breakpoints` / `$breakpoints` (v6: lg 1024, xl 1280, 2xl 1536) and `$container-max-widths` +- `$theme-colors` keys, `$zindex-*` + +Compare against `git show v2-dev:` (or `dev` for the very first phase). A key that keeps its +name but changes its value is a blocker unless the PR says explicitly that the reflow is intended +and section 5 of the plan records the decision. + +## Pass 3 — public contract (blockers) + +For any touched component, confirm these still hold, by reading the code, not the description: + +- Class names emitted for every variant that existed on `dev` (`check-markup-classes` baseline is + the reference; `pnpm run check-markup-classes` if it runs in this environment). +- `data-bs-toggle` / `data-bs-dismiss` / `data-bs-target` values unchanged. +- Event names `show/shown/hide/hidden.bs.` unchanged; `hidePrevented.bs.modal` kept. +- JS: `getInstance`, `getOrCreateInstance`, `show`, `hide`, `toggle`, `dispose` present; the + `window.bootstrap`-style access documented for 1.x still works unless the ESM-only decision + (section 5) has been taken. +- `--tblr-*` custom properties that 1.x documents as public are still defined (may be aliases). +- Both `data-bs-*` and `data-tblr-*` attribute spellings still work in JS. + +## Pass 4 — proof for the claimed phase (warnings) + +Identify the phase from the branch name, PR body or commit messages, then check the required proof +is present or reproducible: + +- Phases 1, 3, 4 (output-neutral): a zero byte-diff of `core/dist/css/tabler.css` and a zero + `html-diff` run. If the PR does not show them, run what is cheap (`pnpm --filter @tabler/core run css` + then `git diff --stat` — only if no dev server is running) and report the result; otherwise + request them. +- Phase 2 (colours): a contrast-gate run and a dark-mode screenshot review listed in the PR. +- Phase 6 (native components): the a11y checklist — focus trap, Escape, backdrop click, focus + return to the trigger, `aria-*` unchanged — and a note that `html-diff` differs by design. +- Any phase: a changeset in `.changeset/` and, when a class was added or moved, updated `classnames` + front matter in `docs/content/**`. + +Missing proof is a warning, not a blocker — but say clearly what is missing. + +## Pass 5 — open questions (notes) + +If the change silently answers one of section 5's open questions (browser baseline, ESM-only, +`.form-select`, `$spacers`, component ownership of `.avatar`/`.chip`/`.stepper`, navbar-as-drawer), +note it: the decision should be recorded in the plan, not implied by code. + +## Report format + +``` +Reviewed: vs v2-dev at , phase () + +BLOCKERS +- path:line — → + +WARNINGS +- ... + +NOTES +- ... + +Contract check: classes ✓/✗ · data-bs ✓/✗ · events ✓/✗ · JS API ✓/✗ · custom props ✓/✗ +Proof: byte-diff · html-diff · a11y · changeset +``` + +Every finding cites `path:line`. Quote the offending line. Do not pad the report with things that +are fine; an empty BLOCKERS section is the goal, and "nothing found" is a valid, complete result. diff --git a/.agents/rules/docs.mdc b/.agents/rules/docs.mdc index 22ea3d57c..1e9103b14 100644 --- a/.agents/rules/docs.mdc +++ b/.agents/rules/docs.mdc @@ -51,6 +51,8 @@ description: Practical description of when and why to use it. No `layout:` key — the route picks the layout. +Quote `summary:` and `description:` values that contain a colon followed by a space (`Cards: use them…`) — unquoted, js-yaml reads the text as a nested map and the page breaks: a 500 on the dev server and a failed docs build on Vercel. Open the page on `:3010` before pushing. + Optional keys: `seoTitle`, `seoDescription`, `icon`, `order`, `related`, `docs-libs`, `css-plugins`, `hide-pagination`, `added-in`. Anything else is rejected. ### Examples diff --git a/.agents/rules/main.mdc b/.agents/rules/main.mdc index 02c9a20e6..04d4ec26b 100644 --- a/.agents/rules/main.mdc +++ b/.agents/rules/main.mdc @@ -7,7 +7,7 @@ alwaysApply: true # Tabler — project rules -Shared instructions for all AI agents (Claude Code, Cursor, etc.). Canonical agent configuration lives in `.agents/` (`rules/` + `skills/` + `agents/`); `.claude/{skills,agents}` and `.cursor/{rules,skills,agents}` are symlinks into it. +Shared instructions for all AI agents (Claude Code, Cursor, etc.). Canonical agent configuration lives in `.agents/` (`rules/` + `skills/` + `agents/`); `.claude/{skills,agents}` and `.cursor/{rules,skills,agents}` are symlinks into it, and the root `CLAUDE.md` only `@`-imports `rules/*.mdc` for Claude Code — edit the files under `.agents/` only. Rules in `rules/*.mdc` (`main`, `docs`, `v2`) always apply. ## Project structure diff --git a/.agents/rules/v2.mdc b/.agents/rules/v2.mdc new file mode 100644 index 000000000..6df6f8d23 --- /dev/null +++ b/.agents/rules/v2.mdc @@ -0,0 +1,52 @@ +--- +description: Tabler 2.0 policy — target branch, what stays from Bootstrap v5, what is adopted from v6, proof required per phase +globs: +alwaysApply: true +--- + +# Tabler 2.0 — branch and compatibility policy + +Applies to every change on `v2-dev`. The plan, phases and open questions live in +`BOOTSTRAP-V6-MIGRATION.md` at the repo root — read sections 2 and 3 before starting 2.0 work. + +## Branches + +- All 2.0 work targets **`v2-dev`**. Cut feature branches from it and open PRs back into it. +- `dev` is frozen for 1.x maintenance. Never merge 2.0 work into `dev`. +- Every 2.0 PR names the phase it belongs to and carries that phase's proof (below). +- Every PR into `v2-dev` goes into the GitHub milestone **2.0**: `gh pr create --base v2-dev --milestone "2.0" …` (or `gh pr edit --milestone "2.0"` afterwards). + +## Kept from Bootstrap v5 — the public contract + +- Class names: `.modal`, `.offcanvas`, `.dropdown-menu`, `.btn-primary`, `.col-md-6`, `.d-md-none`, `.text-*`, `.fs-1`…`.fs-6`, `.rounded-*`, and every class documented for 1.x. +- `data-bs-*` attributes and their values (`data-bs-toggle="modal"`), with the `data-tblr-*` alias still working. +- Event names (`shown.bs.modal`), JavaScript plugin names and methods (`Modal.getInstance`, `show`, `hide`, `dispose`). +- The **values** behind existing utilities: `$spacers`, `.rounded-N`, `.fs-N`, breakpoints and container widths do not change silently. + +## Not adopted from v6 (decided 2026-09-06) + +- The `md:` / `hover:` prefix syntax — infix names (`.col-md-6`) stay. Revisit no earlier than 3.0. +- Renames: `.dialog`, `.drawer`, `.menu`, `.fg-*`, `.bg-1`…`.bg-4`, `.fs-xs`…`.fs-6xl`, `.max-w-*`, `.underline-*`, `data-bs-toggle="dialog|drawer|menu"`, `*.bs.dialog|drawer|menu` events, `Dialog`/`Drawer`/`Menu` exports. +- The v6 remaps of `$spacers` (0–9) and `.rounded-*`. + +## Adopted from v6 — the architecture + +- Token files `_config` / `_colors` / `_theme` / `_root` with the `defaults()` + `tokens()` pattern; cascade `@layer`; custom properties prefixed by PostCSS, never by a Sass `$prefix`. +- `oklch()` colours, `color-mix()` scales, `.theme-*` tokens — **emitted by the v5 classes**, not replacing them in markup (`.btn-primary` sets the theme tokens; markup never needs `.btn-solid .theme-primary`). +- Logical properties in spacing and border utilities (class names unchanged). +- Native `` for modal/offcanvas, `
` for accordion, CSS scroll snap for carousel — under the v5 names, events and data attributes. +- Floating UI instead of Popper; one `focus-ring()` mixin; the numeric `$radii` scale mapped so `.rounded-N` keeps its v5 values. +- The internal Sass API (variable names, maps, mixins, file layout) is **not** promised and may change, as long as compiled output stays as intended. + +## Proof per phase + +- Output-neutral phases (1 Sass split, 3 token scales, 4 logical properties): byte-identical `core/dist/css/tabler.css` and a zero `html-diff` run — see the `html-diff` skill. +- Phase 2 (colours): contrast gate passed, dark mode reviewed by screenshot. +- Phase 6 (native components): the a11y checklist — focus trap, Escape, backdrop click, focus returns to the trigger, `aria-*` unchanged — and a note that `html-diff` differs by design. +- Every phase: a changeset (`generate-changeset` skill), updated `classnames` front matter when a class moved (`class-reference` skill). + +## Agents + +- Before opening a PR into `v2-dev`, run the `v2-policy-reviewer` agent on the diff and fix its blockers. +- To learn how Bootstrap v6 implements something, ask the `bootstrap-v6-reference` agent; it reads the upstream source and reports mechanism, not names. +- The open questions in section 5 of the plan are decided by the maintainer and recorded in the plan — never implied by code. diff --git a/.agents/skills/astro-dev/SKILL.md b/.agents/skills/astro-dev/SKILL.md index 7edec33d1..f16bc7e3f 100644 --- a/.agents/skills/astro-dev/SKILL.md +++ b/.agents/skills/astro-dev/SKILL.md @@ -23,6 +23,8 @@ Never ask the user to check a page manually. Start the server, look at the page, `preview_start` returns a `tabId` — pass it to every later `navigate` / `read_page` / `computer` call so they act on that tab and not on whatever is fronted. The same entries exist in `.claude/launch.json` (`preview`, `docs`, `screenshots`) — start them with `preview_start` so the browser pane opens on the right port, and use `preview-attach` when a server is already running. `pnpm dev` at the repo root starts everything through turbo; only do that when the change spans packages, because the persistent tasks make the output hard to read. +**Port 3000 belongs to the main checkout.** In a git worktree the ports above are taken, and the worktree has no built assets yet. Prepare once with `pnpm turbo run dev:prepare --filter @tabler/preview` (builds `core` and copies the assets into the worktree's `public/`), then start `pnpm --dir preview exec astro dev --port 3001` — the `preview-alt` entry in `.claude/launch.json`. An `html-diff` baseline must be captured from the same server as the comparison, because the toolbar embeds the server path in the HTML. + A `shared/` change shows up in both preview and docs. Verify in the package the user asked about, and open the other one too when the component is used there. ## 2. Full dev vs. astro-only diff --git a/.agents/skills/mr-description/SKILL.md b/.agents/skills/mr-description/SKILL.md index 92512dc88..fa07f87f8 100644 --- a/.agents/skills/mr-description/SKILL.md +++ b/.agents/skills/mr-description/SKILL.md @@ -124,3 +124,5 @@ Write the **title** and **full MR body** in **simple English**, even if the user ## 6. After output Offer to open/create the MR if the user uses **GitLab** (project MCP or UI) or **GitHub** (`gh pr create`), without running destructive git commands unless they ask. + +When the base branch is **`v2-dev`** (Tabler 2.0 work), create the PR with `--milestone "2.0"` — every 2.0 PR belongs to that GitHub milestone. If the PR already exists, add it with `gh pr edit --milestone "2.0"`. diff --git a/BOOTSTRAP-V6-MIGRATION.md b/BOOTSTRAP-V6-MIGRATION.md new file mode 100644 index 000000000..672a7218d --- /dev/null +++ b/BOOTSTRAP-V6-MIGRATION.md @@ -0,0 +1,389 @@ +# Bootstrap v5 → v6: analysis and a phased plan for Tabler 2.0 + +**Status:** analysis only, nothing implemented. Written 2026-09-06. + +**Source of truth:** local Bootstrap checkout at `~/htdocs/bootstrap`, branch `v6-dev` +(`6.0.0-alpha1`, 495 commits ahead of `main`/5.3.8, work from 2025-08-26 to 2026-07-22). +Primary reference: `site/src/content/docs/guides/migration.mdx` (539 lines). +Upstream also ships `skills/bootstrap-v5-v6-migration`, a phase-by-phase migration skill for +coding agents — worth reading as a ready-made checklist. + +Diff size: `scss/` 150 files, +11 585 / −8 889. `js/src/` 36 files, +6 208 / −2 149. + +Tabler's exposure: `core/scss/bootstrap/` holds ~5 000 lines of vendored upstream Sass and +`core/js/src/bootstrap/` ~4 900 lines of a vendored TypeScript port of the v5 plugins. + +--- + +## 1. What actually changed upstream + +### 1.1 Class naming moved from infix to prefix + +Every responsive and state class now uses a Tailwind-style `prefix:class` pattern. + +| v5 | v6 | +| --- | --- | +| `.col-md-6` | `.md:col-6` | +| `.d-md-none` | `.md:d-none` | +| `.navbar-expand-md` | `.md:navbar-expand` | +| `.offset-md-2`, `.g-md-3` | `.md:offset-2`, `.md:g-3` | +| `.container-sm` | `.sm:container` | +| `.table-responsive-md` | `.md:table-responsive` | +| `.list-group-horizontal-md` | `.md:list-group-horizontal` | +| `.sticky-md-top` | `.md:sticky-top` | +| `.opacity-50-hover:hover` | `.hover:opacity-50` | +| `.d-print-none` | `.print:d-none` | +| `.dialog-fullscreen-sm-down` | `.sm-down:dialog-fullscreen` | + +In Sass, `breakpoint-infix()` became `breakpoint-prefix()` and returns `"md\:"`; +`loop-breakpoints-up` / `loop-breakpoints-down` expose `$prefix` instead of `$infix`. + +Breakpoints themselves moved: `lg` 992 → 1024, `xl` 1200 → 1280, `xxl` renamed to `2xl` and +1400 → 1536. Containers: `xl` 1140 → 1200, `2xl` 1320 → 1440. `$grid-breakpoints` → `$breakpoints`. + +### 1.2 Sass architecture + +- `_variables.scss`, `_variables-dark.scss` and `_maps.scss` are gone. New files: `_config.scss` + (all variables), `_colors.scss`, `_theme.scss`, and a rewritten `_root.scss`. +- CSS cascade layers declared in `_root.scss` and applied across every partial. Upstream hit the + same limitation we did: Sass will not allow `@use`/`@forward` inside `@layer`. +- `$prefix` was removed from Sass. Custom properties are authored unprefixed and prefixed at build + time by `postcss-prefix-custom-properties` — the same approach Tabler already shipped in 1.5 + (`.build/build-css.ts`). +- Node Sass support dropped. RFS removed entirely (`scss/vendor/_rfs.scss` deleted); responsive + type now uses `clamp()`. +- New directory grouping with `index.scss` per group: `scss/layout/`, `scss/content/`, + `scss/buttons/`, `scss/forms/`, `scss/mixins/`, `scss/helpers/`. +- All `$*-focus-box-shadow` variables removed in favour of one `focus-ring()` mixin driven by + `--focus-ring*` custom properties. +- `$enable-dark-mode` removed — dark mode is always compiled, switched at runtime via `data-bs-theme`. + +### 1.3 Colour system + +- Every colour variable is `oklch()`; tint/shade scales are generated with `color-mix(in lab, …)` + in the compiled CSS. +- **All `--*-rgb` custom properties and `rgba()` patterns are gone.** This is a hard browser + requirement on `oklch()` and `color-mix()`. +- A `.theme-*` class sets `--theme-bg`, `--theme-fg`, `--theme-border`, `--theme-contrast` and + components only read those tokens. Per-colour component classes are replaced by composition: + - `.btn-primary` → `.btn-solid .theme-primary` + - `.btn-outline-primary` → `.btn-outline .theme-primary` + - `.badge.bg-primary` → `.badge-subtle .theme-primary` + - the same for alerts, tables, cards, accordions and pagination +- New button variants: `.btn-solid`, `.btn-outline`, `.btn-subtle`, `.btn-text`, `.btn-styled`, + `.btn-icon`, plus a `.btn-xs` size. Buttons and inputs share `--btn-input-*` sizing tokens. + +### 1.4 Components rebuilt on native browser APIs + +This is the substantive part of the release, not the renames. + +- **Modal → Dialog** on the native `` element with `showModal()`/`show()`/`close()`. + The `.modal-dialog` / `.modal-content` wrappers and the `.modal-backdrop` element are gone + (`::backdrop` instead), and with them the internal `util/backdrop`, `util/focustrap` and + `util/scrollbar` helpers — the browser supplies the backdrop, the focus trap and the inert top + layer. Scroll lock is `:root.dialog-open` plus `scrollbar-gutter: stable`. +- **Offcanvas → Drawer**, sharing a `DialogBase` class with Dialog, plus swipe-to-dismiss and a + `.drawer-sheet` variant. +- **Responsive navbar uses Drawer, not Collapse.** The toggler targets a ``. + `.navbar-light` / `.navbar-dark` removed. +- **Accordion on `
`/``**, no JavaScript for open/close. Exclusive groups use the + HTML `name` attribute instead of `data-bs-parent`. `.accordion-button` and `.accordion-collapse` + are gone. +- **Carousel on CSS scroll snap.** No more `float` + `translateX` or a custom swipe handler. New + multi-slide, peek, gap and centre modes. `ride` → `autoplay` (boolean, opt-in), `wrap` → + `ends: loop|wrap|stop`. Removed `.carousel-caption`, `.carousel-dark`, `.carousel-control-prev/next` + and the transitional `.carousel-item-*` classes. +- **Dropdown → Menu.** `.dropdown-menu` → `.menu`, `.dropdown-item` → `.menu-item`, + `data-bs-toggle="dropdown"` → `"menu"`, events `*.bs.dropdown` → `*.bs.menu`. The `.dropdown` + wrapper and `.dropdown-toggle` class are gone and markup flattens from `