Skip to content

feat(ui): add core primitives and state panels#1031

Open
EhabY wants to merge 7 commits into
feat/devex-624-ui-scaffoldfrom
feat/devex-618-ui-state-panels
Open

feat(ui): add core primitives and state panels#1031
EhabY wants to merge 7 commits into
feat/devex-624-ui-scaffoldfrom
feat/devex-618-ui-state-panels

Conversation

@EhabY

@EhabY EhabY commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Story

PR #1030 establishes the @repo/ui scaffold and semantic theme boundary. This stacked PR turns that scaffold into the small set of reusable primitives needed for upcoming Workspaces states without pulling workspace, task, or extension models into the package.

It adds:

  • Icon and IconButton
  • Spinner and ProgressBar
  • SearchInput
  • StatusPill with generic neutral | info | success | warning | danger tones
  • EmptyState and ErrorState

WelcomePanel is intentionally omitted because the extension already uses native VS Code viewsWelcome. Skeleton is deferred until the Workspaces first-load layout provides concrete placeholder geometry.

VS Code fidelity

Components are native HTML elements styled to match VS Code's own controls, using the VS Code Elements implementation as a design reference without importing it:

  • 22px toolbar icon buttons with toolbar hover/active/focus variables
  • 26px input geometry for search
  • 28px progress ring and 2px progress bar
  • Compact 18px status pills
  • Native primary-button retry styling
  • VS Code's 0.4 disabled opacity, plus high-contrast, forced-colors, and reduced-motion handling
  • Icons inherit contextual color

Library boundary (NPM-ready)

  • CodiconName is derived at type-check time from @vscode/codicons/dist/metadata.json; no generated source, no runtime icon list.
  • ESLint rejects @repo/* and relative cross-package imports from packages/ui.
  • React stays a peer dependency; codicons remains the only runtime dependency.
  • Shared internals (#cx, #codicons, #storybook) are reached through package.json subpath imports, which resolve only inside this package and ship with it on a standalone split.
  • Component CSS consumes semantic --ui-* tokens only; tokens.css is the single VS Code mapping layer.
  • README documents how a compiled dist can be added later without changing public APIs.

Storybook fidelity

  • Theme variables and the default webview stylesheet are dumped from a real VS Code instance via pnpm sync:vscode-themes, replacing the hand-maintained webview-playground approximations. This includes the genuine --vscode-font-family and the real per-theme variable sets (e.g. HC-only toolbar-hoverOutline).
  • The sync machinery lives in .storybook/themes/ next to its generated output: a thin sync.mjs launcher, the in-extension-host suite.cjs, and a checked-in fixture manifest (no temp-dir codegen).
  • The captured VS Code is pinned (VSCODE_VERSION, currently 1.128.0) so dumps are reproducible; capture is deterministic — the startup theme is dumped last so every dump follows a real theme-change event, and a theme that fails to activate rejects loudly instead of silently dumping the wrong theme.
  • sync.mjs formats the generated stylesheet itself, so a resync never leaves a diff for format:check to reject.

Regression guards

  • UI/VSCodeParity renders every control next to its @vscode-elements counterpart under identical variables, snapshotted by Chromatic in all four themes, so drift from VS Code styling shows up as a visual diff (@vscode-elements/react-elements is a devDependency only).
  • Controls share one flex-centering geometry base (components/control.css); component CSS is inherit-first and never uses line-height/vertical-padding math.

Coverage

  • One <Component>.stories.tsx per public component with a combined matrix story (10 stories total, including Foundations and a snapshot-disabled icon gallery), each snapshotted in Light, Dark, High Contrast, and High Contrast Light.
  • Focused component tests cover accessibility and behavior; the UI package suite passes 20 tests.
  • Validated with type checking, linting, formatting, UI tests, Storybook CI build, production build, and git diff --check.

Closes DEVEX-618.

Generated by Coder Agents on behalf of @EhabY.

Implementation plan

DEVEX-618: UI core primitives and state panels

Goal

Create a stacked PR on feat/devex-624-ui-scaffold that adds concise, generic components to @repo/ui with Storybook, visual-regression, accessibility, and focused behavioral coverage, while preserving a clean future standalone-library boundary.

Scope

Implement Icon, IconButton, Spinner, ProgressBar, SearchInput, StatusPill, EmptyState, and ErrorState.

Do not implement WelcomePanel (native viewsWelcome remains) or Skeleton (no concrete first-load geometry yet).

Styling strategy

Match VS Code exactly with native elements rather than a custom design system or a runtime dependency on @vscode-elements:

  • Learn dimensions, variables, and interaction patterns from the installed VS Code Elements package.
  • Keep the toolbar-button, input, button, badge, and progress geometry consistent with VS Code defaults.
  • Map themes once in tokens.css; component CSS uses semantic --ui-* tokens only.
  • Support high contrast through VS Code contrast variables, plus forced-colors and prefers-reduced-motion media handling.

Minimal tooling

  • Derive CodiconName as a TypeScript type from codicon metadata (resolveJsonModule); commit no generated output and expose no runtime icon array.
  • Enforce package isolation with ESLint (@repo/* bans and import-x/no-relative-packages) instead of a custom script.

Storybook

One combined matrix story per component under UI/<Component>, four-theme Chromatic modes on each matrix, interaction assertions via play functions, and a snapshot-disabled curated icon gallery. Detailed behavior stays in Vitest.

Behavioral tests

Focused Testing Library/Vitest tests in test/webview/ui/ covering icon semantics, button accessibility, spinner status, progress ARIA/clamping, controlled search and clear-focus behavior, status pill tones, and state panel slots/retry.

Validation

pnpm format:check, pnpm typecheck, pnpm lint, pnpm test:webview ./test/webview/ui, pnpm storybook:ci, pnpm build, and git diff --check, plus manual Storybook review across all four themes.

Git and PR

  • Working branch feat/devex-618-ui-state-panels, stacked on feat/devex-624-ui-scaffold.
  • Conventional Commits.
  • PR discloses Coder Agents generation, links DEVEX-618, and explains omissions.

@linear-code

linear-code Bot commented Jul 13, 2026

Copy link
Copy Markdown

DEVEX-618

@EhabY EhabY self-assigned this Jul 13, 2026
@EhabY EhabY force-pushed the feat/devex-618-ui-state-panels branch 2 times, most recently from 1df5daf to 02a0ff1 Compare July 14, 2026 09:53
@EhabY EhabY force-pushed the feat/devex-618-ui-state-panels branch from 02a0ff1 to e1122d6 Compare July 14, 2026 10:07
@EhabY EhabY force-pushed the feat/devex-618-ui-state-panels branch from e1122d6 to 839acc7 Compare July 14, 2026 10:08
EhabY and others added 5 commits July 14, 2026 10:34
…joining

- Move the theme sync machinery into .storybook/themes/ next to its
  generated output: the extension-test suite becomes a real suite.cjs
  file instead of an escaped template string, and the fixture manifest
  is checked in instead of written to a temp dir at runtime (VS Code
  loads a manifest-only fixture; the empty extension.js shim is gone).
- Pin the captured VS Code to 1.128.0 so dumps are reproducible; bump
  VSCODE_VERSION in sync.mjs to resync against a newer release.
- Capture the startup theme (dark) last so every dump follows a real
  theme-change event; capturing it immediately at startup can read
  partially-loaded theme data. Failed activation rejects loudly instead
  of silently dumping the wrong theme.
- Format the generated stylesheet from sync.mjs so a resync never
  leaves an unformatted diff for format:check.
- Add a tiny cx() helper used by all components instead of the repeated
  filter/join expression, and reach shared internals (#cx, #codicons,
  #storybook) through package.json subpath imports instead of ../../
  paths; the aliases are scoped to packages/ui and ship with it.
- JSDoc for top-level declarations, readonly types on const
  collections, and list sync:vscode-themes in the AGENTS.md command
  table.
Typography, text color, and body margin now come from the dumped VS Code
default stylesheet; keep only the sidebar background, viewport sizing,
and the deliberate body-padding override.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant