Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/clear-buttons-focus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sanring/cli': patch
---

Improve the installed Button component's destructive variant contrast for WCAG AA readability.
5 changes: 5 additions & 0 deletions .changeset/tidy-buttons-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sanring/cli': patch
---

Install the Angular CDK dependency required by the shared utilities bundled with registry components.
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ jobs:
- name: Test
run: pnpm --filter @sanring/cli test

- name: Test packaged CLI in a fresh Angular app
run: pnpm test:e2e:cli
timeout-minutes: 15

typecheck:
name: Type check
runs-on: ubuntu-latest
Expand Down Expand Up @@ -119,3 +123,39 @@ jobs:
# 不會被上面那個指令覆蓋到,要另外查。
- name: Type check @sanring/cli schematics
run: pnpm --filter @sanring/cli exec tsc -p tsconfig.schematics.json --noEmit

docs-e2e:
name: Docs E2E + visual regression
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Install Chromium
run: pnpm exec playwright install --with-deps chromium

- name: Run docs E2E
run: pnpm test:e2e:docs

- name: Upload Playwright diagnostics
if: ${{ failure() }}
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: |
playwright-report/
test-results/
if-no-files-found: ignore
retention-days: 7
3 changes: 3 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,16 @@ pnpm start # docs dev server → http://localhost:4200
| `pnpm lint` | ESLint |
| `pnpm --filter @sanring/cli build` | Build CLI(含 `sync-registry` 步驟,見下) |
| `pnpm --filter @sanring/cli test` | 執行 CLI 自己的 Vitest 測試 |
| `pnpm test:e2e:cli` | 打包 CLI,在全新 Angular/npm 專案實際執行 `init`、`add button` 與 production build(需要網路) |

## `@sanring/cli` 的 registry 同步

`packages/cli/registry/` 是 build 產物、不進 git(見 `.gitignore`),每次 `pnpm --filter @sanring/cli build` 都會先跑 `scripts/sync-registry.mjs`,把 repo 根目錄的 `registry/`(正本,有 tracked in git)整個複製過去,再驗證 `registry.json` 列的每個檔案都存在。

**改動 `registry/` 底下的元件檔案後,一定要重新 build 一次 CLI 套件**(或至少跑 `pnpm --filter @sanring/cli sync-registry`),否則發布出去的 CLI 會裝到舊版程式碼——這正是 [.changeset/plenty-pumas-sync.md](.changeset/plenty-pumas-sync.md) 修的問題。

`pnpm test:e2e:cli` 會使用 `packages/cli/e2e/fresh-angular.mjs` 建立獨立暫存專案,成功時自動清除;失敗時保留路徑供除錯。若要保留成功專案,也可使用 `SANRING_E2E_KEEP_TEMP=1 pnpm test:e2e:cli`。這項測試會從 npm 安裝 fresh project dependencies,CI 已在 `Test (@sanring/cli)` job 執行。

## `@sanring/cli` 版本相容性(Changesets)

`@sanring/cli` 用 [Changesets](https://github.com/changesets/changesets) 管理版本與 CHANGELOG:改到 `packages/cli` 的 PR 跑 `pnpm changeset`,選版本、寫說明——這段說明會直接進 `packages/cli/CHANGELOG.md`,不需要另外維護一份相容性文件。
Expand Down
52 changes: 52 additions & 0 deletions DEVLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,20 @@ P9 golden fixture 掃完 53 元件後發現一批長期存在的 registry 宣告

**範圍限制**:Component Docs 全面掃描效率與工程證據尚未完成,所以本輪只用 `/components/button` 作為 representative component page;其餘 component docs 完成後,應用同一套驗證重新覆蓋。

## P29 Phase 4 — Component Docs 掃描效率與工程證據收斂(2026-08-22)

**已完成**:本輪將先前已建立的 metadata/evidence 資料層收斂成一套明確的 component reference surface,改動全部落在共用 `component-page-*` primitives,因此一次覆蓋 52 個 component pages:

- Header 把 install command 與 package path 提升成主要 manifest panel;registry name、shipped status、shared deps、SSR/browser boundary、a11y、keyboard、state model 與 latest version 收斂成第二層 evidence chips,並新增 Installation/API/Recent changes 快速 anchor。Radio 因 API 拆成 group/item 兩張表,專用 anchor 指到 `#api-group`。
- Previewer 採 `01 Preview` / `02 Source` 兩區清楚標頭與 rendered/copy-ready 狀態,並把預覽高度壓到 desktop 320px、mobile 280px。沒有重新引入 Preview/Code tabs:先前使用者已要求撤回會隱藏 code 的 tabs,所以這次保留 demo/source 同時可見,用層級而非隱藏來提升掃描效率。
- API reference 新增 row count/reference header、編號、type code pill 與更緊湊的 desktop columns;mobile 維持 cards,但將 type/default 改成雙欄、description 獨立收尾,長型別與預設值仍可斷行。
- Recent changes 從一般頁尾面板改成最多 3 筆的 compact release strip,保留 version/date/type/breaking/text 與完整 changelog 入口。
- 安裝指令在手機版改用 surface 內橫向捲動,避免 CLI token 在單字中間斷行;頁面本身仍維持零水平 overflow。

**視覺觀察**:Button 作為簡單基準時,manifest 與 Preview/Source 層級可在第一屏辨識;Dialog 的 keyboard/a11y/state evidence 可正常換行;Table 的寬 demo 與高密度 API 沒有撐破 content rail。Light/dark 的 command surface 均保持深色 code 語彙,mint 只用在 status/index/active signal。Mobile header 會把 command/path 疊成單欄,evidence chips 與 jump links 自然換行;API cards 在 360px/390px 仍可掃描。

**驗證**:`pnpm exec tsc --noEmit`、scoped ESLint、`git diff --check` 通過;Angular development bundle 冷啟動成功。Playwright 更新 component-page assertions 來覆蓋 install command、Installation/API anchors、Preview/Source 同時可見、API reference surface、recent changes 與 Radio 的 `#api-group`;Phase 4 視覺矩陣擴充為 Button/Dialog/Table 的 desktop light、desktop dark、360px、390px,並對 header/previewer/API/release strip 另拍局部截圖。Desktop Chromium **11 passed**、mobile Chromium **11 passed**。

---

## P30 — `checkbox` Enter 鍵「無法切換」查證後確認不是缺口
Expand Down Expand Up @@ -901,3 +915,41 @@ P30 先前已收完 15 個必修缺口;這輪把剩下 15 組建議項目逐
**額外的流程修正(跟這兩個 CI bug 無關,是同一輪順手發現並修正的操作失誤)**:原本手動跑了 `pnpm changeset version` 把兩份 changeset 直接消耗掉、產生 0.24.0 並連同版號改動一起開 PR,結果讓 `.github/workflows/require-changeset.yml` 判定「這個 PR 沒有待處理的 changeset」而失敗。查 `gh pr list` 撈出的完整歷史(#1–#26)後確認:這個 repo 27 次版本紀錄裡有 26 次都是 `changesets/action` bot 自動開的 `chore: version packages` PR(分支 `changeset-release/main`)在做真正的 bump,只有一次(0.23.2→0.23.3)是例外手動直接推到 `main`(沒經過 PR,所以沒撞到這個檢查)。修正方式是把 `packages/cli/package.json`/`CHANGELOG.md` 改回 0.23.3、把兩份 changeset 檔案原樣留著(不消耗),讓 bot 在這個 PR 合併進 `main` 後自己開版號 PR。**教訓**:`packages/cli`/`registry` 的版本發布一律讓 changeset 檔案跟著功能改動落地就好,不要手動跑 `changeset version`——那是 bot 的工作,手動搶著做只會跟 `require-changeset.yml` 打架。

**驗證**:Docker 重現(`node:24-bookworm`、`CI=true`、`GITHUB_ACTIONS=true`、`--frozen-lockfile`、`sync-registry`、`vitest run`)240/240 通過;`pnpm changeset status --since=origin/main` 通過;PR #27 的六個 GitHub Actions check(Lint、Test (@sanring/cli)、Test (@sanring/ui)、Type check、Registry Sync Check、Require Changeset)全綠。

---

## P11 — Docs component page light/dark accessibility smoke test(2026-08-22)

**已完成**:新增 `apps/docs/e2e/component-page-accessibility.spec.ts`,以 Button component page 作為代表 reference surface,在 desktop/mobile Chromium 各跑 light/dark 兩種主題。每輪會用既有 `axe-core` 對完整 `main article` 執行 WCAG 2 A/AA 掃描,並另外明確驗證 page title、description、installation、preview source、Command/Manual tabs、兩處 copy-code control 與 header install-copy control。Keyboard assertions 會實際用 ArrowRight/ArrowLeft 切換 installation tabs,並以 Shift+Tab/Tab 回到目標 control,確認 active element、`:focus-visible` 以及 outline/box-shadow focus indicator 同時存在,不是只檢查 DOM 上有 class。

**測試抓到並修正的真實問題**:

- Mobile code blocks 的 `overflow-auto` region 原本沒有 tab stop,鍵盤使用者無法進入後用方向鍵水平捲動。共享 `ComponentPageCodeBlock` 的 scroll surface 補 `tabindex="0"` 與 inset focus ring,一次修正 component docs 與 long-form pages 的同一種 code surface。
- Light theme 的 `--docs-accent-strong` 使用 `primary-70`,在 eyebrow 與 latest-version 小字上低於 axe 的 AA 門檻;改用 `primary-80`。Installation 的非作用中 package manager 與 code line number 原本把一般頁面的 `--docs-muted` 放在固定深色 code surface 上,改用專屬 `--docs-code-muted`/`--docs-code-fg`。
- Button `destructive` variant 原本是 `error-50` 白字,light/dark 都無法達到一般文字 4.5:1。`packages/ui` 與可安裝的 `registry` source 同步改為 `error-70` 白字、`error-80` hover、`error-60` focus ring,保留 destructive 語意但提高對比。

**驗證**:新增 accessibility smoke desktop/mobile × light/dark **4/4 passed**;連同既有 component-page 與 Phase 4 matrix 共 **26/26 passed**。`pnpm exec tsc --noEmit`、repo 全域 `pnpm lint`、`git diff --check` 通過;Button directive targeted unit tests **8/8 passed**;registry sync(52/52)與 registry parity(52 directories)皆通過。

---

## P11 — Docs 自動化視覺回歸 baseline + CI quality gate(2026-08-22)

**已完成**:新增 `apps/docs/e2e/visual-regression.spec.ts` 與 6 張核准 baseline,固定以 `1440x900` desktop Chromium 覆蓋 home、Button component page、CLI overview 的 light/dark 畫面。Home/CLI 比對第一個 viewport,Button 則直接比對完整 Basic section,確保真正的 preview 與 source code 都進入 baseline。這三個 surface 分別代表品牌首頁、共用 component docs layout/preview 與 long-form docs/深色 workflow panel;mobile/breakpoint 正確性仍由既有 structural E2E matrix 負責,避免把大量高度不一的 full-page PNG 當成難維護的測試資產。

**穩定性設計**:`visual-chromium` 是獨立 Playwright project,不會在 desktop/mobile structural projects 重複執行;固定 viewport、locale、timezone、reduced motion,每個案例在 screenshot 前鎖定 `sanring-docs-theme`、等待 route landmark/network idle/`document.fonts.ready`,並停用 animation、transition、caret 與 smooth scroll。pixel comparison 保留 3% diff-ratio 與 0.3 color threshold,容忍 macOS/Linux Chromium 的字型 anti-aliasing 差異,但版面位移、surface/token 色彩與元件外觀變化仍會超過門檻。baseline 路徑不含 host OS,讓本機與 GitHub Actions 共用同一組 approved PNG。

**CI 與維護流程**:`ci.yml` 新增 `Docs E2E + visual regression` job,乾淨 checkout 會安裝 Chromium、執行完整 `pnpm test:e2e:docs`;失敗時上傳 7 天保存的 Playwright HTML report、actual/expected/diff 圖。`DOCS_VISUAL_SYSTEM.md` 已改寫 automation 邊界,並記錄視覺 subset 與 `--update-snapshots` 指令;只有人工檢查 actual/diff、確認是刻意改版後才能更新 baseline。`ROADMAP.md` 同步把 accessibility 與 visual regression 從未完成 quality infrastructure 移到 Recently shipped,TODOLIST 的 P11 現在只剩真正 CLI e2e。

**驗證**:Home/CLI 4 張 viewport baseline 均人工抽查完成載入且尺寸為 `1440x900`;審圖時發現 Button 第一屏只露出 preview 外框,隨即把另 2 張改成直接擷取完整 Basic section,確保實際 variants 受保護。baseline 產生後以無 `--update-snapshots` 模式重跑 visual diff **6/6 passed**;完整 `pnpm test:e2e:docs` **46/46 passed**。Playwright `--list` 確認 suite 為 structural/a11y desktop+mobile 40 個案例加 visual-only 6 個案例,沒有重複執行 screenshot spec;repo 全域 lint、`tsc --noEmit`、`git diff --check` 皆通過。

---

## P11 — Packaged CLI × fresh Angular 真正 E2E quality gate(2026-08-23)

**已完成**:新增 `packages/cli/e2e/fresh-angular.mjs` 與 root/package-level `test:e2e:cli`/`test:e2e` scripts。測試每次都在 OS temp 建立隔離環境:先執行 CLI production build 與 `pnpm pack`,再透過隔離的 Angular CLI 22.0.1 scaffold 一個全新 npm application、安裝該本地 tarball、實際執行 `sanring init --yes` 與 `sanring add button --yes`。測試會斷言 config/theme/Button/shared source 都存在、installed version 已記錄、CDK dependency 真的寫入新專案。最後把 registry 安裝出的 `ButtonDirective` 匯入 root `App` 並在 template 使用後跑 production `ng build`;不是只確認檔案複製成功,也不會因為未引用的 source 沒被 Angular compiler 納入而假綠。成功時清除 temp,失敗時保留完整專案路徑;可用 `SANRING_E2E_KEEP_TEMP=1` 主動保留。CI 的 `Test (@sanring/cli)` job 已加同一條流程與 15 分鐘 timeout。

**package-manager 決策**:最初用 pnpm 建 fresh app,但 pnpm 10 在全新、沒有 `onlyBuiltDependencies` 核准清單的專案會因 Angular build toolchain 的 `esbuild`/`lmdb`/`@parcel/watcher` install scripts 回報 `ERR_PNPM_IGNORED_BUILDS`;這是在 Sanring 執行前就發生的 package-manager policy,不是產品缺陷。最終改用 Angular CLI 預設 npm,同時讓 E2E 覆蓋 CLI 內 `detectPackageManager → npm install` 的真實依賴安裝路徑。

**測試抓到並修正的真實發布缺陷**:第一次走到 production build 時,乾淨專案無法 resolve `@angular/cdk/a11y`。根因是所有使用 `shared/utils.ts` 的元件都會間接需要 CDK(`uniqueId()` 使用 `_IdGenerator`),但 `registry.json` 的 `utils.peerDependencies` 只列 `clsx`/`tailwind-merge`;repo 與既有 mock tests 本身早已有 CDK,所以缺口一直被遮住。已補 `@angular/cdk: ^22.0.0`,因此 `sanring add button` 現在會自動安裝它。進一步把 `build.test.ts` golden fixture 從只比較 52 個 component metadata 擴大到所有 shared entries 後,又抓出 `collection-controller.ts` 同樣直接 import CDK 卻沒宣告,一併校正;新的 shared peer-dependency comparison 會阻止這一類 drift 再發生。CLI patch changeset 已加入。

**驗證**:本機 fresh run 實際安裝 Angular 22.1.3/CLI 22.1.5,完整 `packed CLI → npm install → sanring init → sanring add button → import installed source → production ng build` 連續通過,production bundle 142.33 kB。`build.test.ts` targeted golden fixture **11/11 passed**,shared/component metadata 零已知落差;完整 CLI suite **19 files / 240 tests passed**。repo 全域 lint、CLI main/schematics TypeScript、registry sync/parity、Changesets status、CI YAML 與 `git diff --check` 皆通過。
17 changes: 6 additions & 11 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,14 @@ This is a snapshot, not a commitment or a timeline. Items move, get reprioritize
- **GitHub registries** — point the CLI at `github:<owner>/<repo>` directly, without hosting a raw `registry.json` yourself.
- **Private registry authentication** — Bearer-token support for company-internal or private-repo registries.

## Quality infrastructure (ongoing, lower urgency)

- Automated accessibility regression testing (axe-core or similar)
- Visual regression testing for CSS changes (screenshot diffing against an approved baseline) — the
docs site now has Playwright e2e smoke coverage (see Recently shipped), which is the runner this
would build on, but there's no baseline/diffing set up yet
- Real end-to-end CLI tests against a freshly scaffolded Angular project

## Recently shipped

- Docs site Playwright e2e coverage — structural smoke tests (renders, no console errors, no
horizontal overflow, mobile nav, theme switching) across home, a component page, and a long-form
page; `pnpm test:e2e:docs` to run
- Packaged CLI end-to-end quality gate — CI installs the local tarball into a freshly scaffolded
Angular app, runs `sanring init` and `sanring add button`, imports the installed source, and
requires a successful production build
- Docs site Playwright quality gate — structural smoke tests, axe-core accessibility coverage, and
approved visual baselines for representative home/component/CLI surfaces in both themes; CI runs
the full suite through `pnpm test:e2e:docs`
- Docs site visual system pass — consistent `--docs-*` tokens, WCAG-verified color contrast in both
themes, and a documented type scale/spacing contract (`apps/docs/DOCS_VISUAL_SYSTEM.md`)
- `sanring build` — auto-generate a third-party registry's `registry.json` (component deps, shared deps, peer dependencies) from a source directory, instead of hand-writing it against the schema
Expand Down
Loading
Loading