Skip to content

feat(configurator): redesign visual editor panels + mobile ergonomics + control UX - #402

Merged
jackgranatowski merged 12 commits into
mainfrom
claude/pr401-errors-reviews-np5mqg
Jun 25, 2026
Merged

feat(configurator): redesign visual editor panels + mobile ergonomics + control UX#402
jackgranatowski merged 12 commits into
mainfrom
claude/pr401-errors-reviews-np5mqg

Conversation

@jackgranatowski

@jackgranatowski jackgranatowski commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Supersedes #401 (closed without merge). Carries the full studio redesign forward with all CI failures resolved, CodeRabbit review threads addressed, and three additional production-readiness items completed.

What's included

Studio redesign (from #401)

  • New reusable components: CategoryHeader, ControlSection, ControlPreview, FriendlyControl, StudioFrame, StudioWorkflow
  • Studio editors for all 8 domains: Typography, Color, Spacing, Layout, Shape (Borders), Shadow, Motion, Effects — each with a live specimen, workflow nav, and curated controls
  • controlSchema.js — heuristic token→control-type mapper (color, font, length, radius, shadow, motion, wrap, …)
  • DomainPanel refactored to embed studio views; Header compacted and hardened

CI fixes & review comments (vs #401)

  • Fixed 20 e2e test failures caused by usesVisualStudio guard hiding ScaleGenerators and brand-color cards
  • Added missing .panel__title class to CategoryHeader; reused ContainerBars in LayoutStudio for .cbars__bar assertion
  • Fixed a11y.spec.js — expand allvars before querying row info button
  • Converted mixed Polish/English descriptions to English across all Studio components
  • Added prefers-reduced-motion overrides in MotionStudio and EffectsStudio
  • Fixed Header.svelte memory leak (onDestroy for share timer)
  • controlSchema.js: fixed gradient direction select options; added font-weight guard before generic font rule
  • DomainPanel: consolidated redesignedDomains set + if/else chain into single STUDIO_BY_DOMAIN map + <svelte:component>
  • StudioWorkflow / StudioFrame: converted <span>/<div> workflow steps to <ol>/<li> for proper list semantics
  • FriendlyControl: added fallback <option> when activeValue not in meta.options
  • Header: use modifiedCountsByDomain() instead of raw Object.keys(overrides).length
  • ColorStudio: replaced navigating <a href="/"> with inert <span role="link">
  • TypographyStudio: removed unused strong CSS selector (cleared CI warning)

Item 6 — Screenshot QA

  • tests-e2e/screenshots.spec.js: 9 domains × 3 viewports (1280 / 768 / 390 px) — 27 PNGs captured via --project=screenshots
  • Added screenshots project to playwright.config.js

Item 7 — Mobile ergonomics

  • app.css: WCAG 2.5.5 touch targets — 44 px min-height for .cfg-btn / .cfg-input / .cfg-select at ≤980 px
  • StudioFrame: description hidden + h3 shrinks at ≤820 px (left column no longer towers above controls on mobile)
  • StudioWorkflow + LayoutStudio: horizontal scroll fallback at ≤480 px for the 4-step workflow nav
  • ControlSection: starts collapsed on mobile (window.innerWidth < 768) to avoid 4000+ px page walls

Item 8 — "What does this control do"

  • FriendlyControl: "drives N" badge via dependentsCount(); accent colour when ≥10 dependents (master token)
  • ControlPreview: short caption below every preview (colour / typeface / corner / elevation / timing / …)
  • SmartSettings: aggregate drives count in section summary; token count in reset button label

Test plan

  • npm run build — clean, no Svelte warnings
  • npm run test:unit — 525 unit tests pass
  • npx playwright test --project=chromium — all e2e tests pass
  • npx playwright test --project=screenshots — 27 PNGs in test-results/screenshots/
  • Visual review of screenshots at 390 px — workflow nav scrolls horizontally, StudioFrame header is compact, ControlSections collapsed by default
  • Spot-check a master token (e.g. --sf-space-scale) — should show "drives 45" badge in FriendlyControl

jackgranatowski and others added 10 commits June 24, 2026 23:12
…comments on PR #401

CI fixes:
- CategoryHeader: add panel__title class to h2 so shell/undo-redo e2e tests
  that cycle domains via keyboard still find the heading (9 tests × 3 browsers)
- DomainPanel: restore ScaleGenerator for visual-studio domains (typography,
  spacing) — removes the !usesVisualStudio guard so generator.spec.js and the
  undo-redo spec can locate .gen elements
- ColorStudio: add panel__card + cfg-card classes and rename "Main colors"
  disclosure to "Core brand colors" to satisfy shell.spec.js panel__card check
- LayoutStudio: replace custom .container-rails/.rail markup with ContainerBars
  component so domain-preview.spec.js .cbars__bar assertions pass; convert
  workflow nav to semantic <ol><li>; fix Polish description
- a11y.spec.js: expand allvars disclosure before querying .row__info-btn —
  Layout Settings now use FriendlyControl, raw TokenRows live in allvars

CodeRabbit review fixes:
- Header: import onDestroy and clearTimeout(_shareTimer) on component teardown
- EffectsStudio / SpacingStudio / ColorStudio / TypographyStudio: replace
  mixed-Polish descriptions with full English copy
- TypographyStudio: drive specimen content from the active tab (Headings shows
  heading stack, Body shows paragraph, Code shows mono sample, Overview all)
- controlSchema: add options array when heuristic selects gradient-direction
  as a select control; check font-weight before the generic /font/ branch to
  give weight tokens a number control instead of a font-family picker
- MotionStudio: add prefers-reduced-motion media query to disable infinite
  animations for users who have requested reduced motion

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2b6qg3hbi9QsBZmaFwjUd
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2b6qg3hbi9QsBZmaFwjUd
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jackgranatowski, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 7 minutes and 15 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 554a46b4-5e40-4fb5-98a7-8fca412fda24

📥 Commits

Reviewing files that changed from the base of the PR and between 0a3cc02 and 7281e36.

📒 Files selected for processing (12)
  • configurator/src/components/DomainPanel.svelte
  • configurator/src/components/FriendlyControl.svelte
  • configurator/src/components/Header.svelte
  • configurator/src/components/editors/ColorStudio.svelte
  • configurator/src/components/editors/EffectsStudio.svelte
  • configurator/src/components/editors/MotionStudio.svelte
  • configurator/src/components/editors/ShadowStudio.svelte
  • configurator/src/components/editors/ShapeStudio.svelte
  • configurator/src/components/editors/StudioFrame.svelte
  • configurator/src/components/editors/StudioWorkflow.svelte
  • configurator/src/components/editors/TypographyStudio.svelte
  • configurator/tests-e2e/a11y.spec.js
📝 Walkthrough

Walkthrough

The PR adds studio-based configurator controls, shared token-editing components, new studio screens for multiple domains, and updated DomainPanel and Header rendering. It also adjusts focus behavior in tablist editors and adds schema and component tests.

Changes

Configurator studio redesign

Layer / File(s) Summary
Token schema and studio group contracts
configurator/src/lib/controlSchema.js, configurator/src/lib/studioSchema.js, configurator/tests/studio-schema.test.js
controlForToken infers control metadata from token names and values, TYPOGRAPHY_PANELS and STUDIO_GROUPS define studio metadata, and tests validate token references and pruning.
Reusable control cards
configurator/src/components/CategoryHeader.svelte, configurator/src/components/ControlPreview.svelte, configurator/src/components/ControlSection.svelte, configurator/src/components/FriendlyControl.svelte
Adds the category header, type-specific control preview, collapsible section shell, and friendly token editor wrapper with preview, select, and reset behavior.
Studio shell and token wiring
configurator/src/components/editors/StudioFrame.svelte, configurator/src/components/editors/StudioWorkflow.svelte, configurator/src/components/editors/StudioControls.svelte, configurator/src/components/SmartSettings.svelte
Adds the shared studio frame and workflow nav, renders groups through ControlSection and FriendlyControl, and routes SmartSettings motion and fallback controls through FriendlyControl.
Domain studio screens
configurator/src/components/editors/TypographyStudio.svelte, configurator/src/components/editors/ColorStudio.svelte, configurator/src/components/editors/SpacingStudio.svelte, configurator/src/components/editors/LayoutStudio.svelte, configurator/src/components/editors/ShapeStudio.svelte, configurator/src/components/editors/ShadowStudio.svelte, configurator/src/components/editors/MotionStudio.svelte, configurator/src/components/editors/EffectsStudio.svelte, configurator/tests-components/studios.test.js
Defines the typography, color, spacing, layout, shape, shadow, motion, and effects studio screens and validates them with mount and interaction tests.
DomainPanel studio routing
configurator/src/components/DomainPanel.svelte
Reworks DomainPanel to render the new studio components, add category headers, and replace curated brand-color details with ControlSection and FriendlyControl groups.
Header and tablist accessibility
configurator/src/components/Header.svelte, configurator/src/components/HeadingEditor.svelte, configurator/src/components/RadiusEditor.svelte, configurator/tests-e2e/a11y.spec.js
Updates the header layout and status handling, and makes heading and radius tablists focusable while adjusting the e2e row selector.

Sequence Diagram(s)

No additional diagrams.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

codex

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: a broad redesign of configurator visual editor panels.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/pr401-errors-reviews-np5mqg

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Redesign configurator domains with Studio editors and Friendly controls
✨ Enhancement 🧪 Tests 🐞 Bug fix 🕐 40+ Minutes

Grey Divider

Description

• Introduce Studio-style editors for core visual domains with richer previews and workflows.
• Replace raw TokenRow surfaces with schema-driven FriendlyControl cards and previews.
• Add studio schema + component tests, and fix e2e/a11y regressions from the redesign.
Diagram

graph TD
  DP["DomainPanel"] --> CH["CategoryHeader"] --> VS["Studio editors"]
  DP --> FC["FriendlyControl"] --> CP["ControlPreview"] --> ST[("Store + preview")]
  VS --> ST
  FC --> SC["controlSchema + studioSchema"]
  VS --> SC
  TS["Studio tests"] --> VS
  TS --> FC
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Fully data-driven studios (single generic Studio renderer)
  • ➕ Less bespoke Svelte markup per domain
  • ➕ Easier to add/adjust workflows and previews via config only
  • ➕ More consistent rendering and accessibility patterns
  • ➖ Harder to achieve domain-specific preview richness (e.g., Color role map, Layout composition) without escape hatches
  • ➖ More up-front abstraction work and potential for lowest-common-denominator UX
2. Incremental rollout behind a feature flag per domain
  • ➕ Reduces risk of e2e selector regressions and CI churn
  • ➕ Enables A/B comparison and faster rollback if needed
  • ➖ Temporary duplication of UI paths and styling
  • ➖ Adds branching complexity to DomainPanel and tests during migration
3. Keep TokenRow as the base editor and layer preview/cards on top
  • ➕ Smaller diff and fewer new components
  • ➕ Preserves existing test selectors and raw-info UX
  • ➖ TokenRow becomes overloaded with multiple presentation modes
  • ➖ Harder to standardize studio layouts around a consistent ‘friendly’ surface

Recommendation: The chosen approach (domain-specific Studio editors + shared StudioFrame/StudioControls + schema-driven FriendlyControl) is appropriate for the goal of richer, domain-tailored previews while still centralizing token/control metadata. If churn continues from selector-based e2e assertions, consider temporarily feature-flagging remaining domains during rollout, but avoid forcing all studios into a single generic renderer too early—these previews are intentionally bespoke.

Files changed (27) +1269 / -529

Enhancement (20) +1141 / -524
CategoryHeader.svelteAdd domain hero header with counts and reset action +33/-0

Add domain hero header with counts and reset action

• Introduces a new panel header component showing domain icon/label/blurb, override/token counts, and an optional reset button. Adds styling and preserves '.panel__title' on the heading for existing e2e selectors.

configurator/src/components/CategoryHeader.svelte

ControlPreview.svelteAdd inline visual preview surface for token controls +63/-0

Add inline visual preview surface for token controls

• Adds a preview component that renders type-specific samples (color, font, radius, shadow, motion, line-height, etc.). Styles preview using 'buildPreviewDeclarations()' so previews reflect the active preview theme and overrides.

configurator/src/components/ControlPreview.svelte

ControlSection.svelteAdd collapsible control section with modified count +26/-0

Add collapsible control section with modified count

• Creates a reusable '<details>' wrapper for grouped controls, including hint text and a 'changed' badge. Replaces ad-hoc expand summary snippets previously embedded in DomainPanel.

configurator/src/components/ControlSection.svelte

DomainPanel.svelteRoute redesigned domains into Studio editors and Friendly controls +45/-289

Route redesigned domains into Studio editors and Friendly controls

• Replaces the legacy per-domain header and several domain-specific bespoke blocks with a 'CategoryHeader' and dedicated Studio editors for colors/typography/spacing/layout/borders/shadows/motion/effects. Updates curated groups/essentials to render 'FriendlyControl' inside 'ControlSection', and adjusts generator/knob rendering to keep tests and workflows working across redesigned domains.

configurator/src/components/DomainPanel.svelte

FriendlyControl.svelteIntroduce schema-driven control row with preview and reset +60/-0

Introduce schema-driven control row with preview and reset

• Adds a new control surface that derives control type/options from 'controlSchema', writes overrides via the store, shows modified state, and embeds 'ControlPreview'. Supports a select-based editor for enumerated tokens plus show-token/reset actions.

configurator/src/components/FriendlyControl.svelte

Header.svelteRedesign top bar into search + status + grouped actions +59/-233

Redesign top bar into search + status + grouped actions

• Refactors the header UI into a command area (search + domain/override/token status) and a semantic nav of grouped actions (history/session/workspace). Adds active-domain label resolution, export button affordance, and ensures timers are cleaned up on destroy.

configurator/src/components/Header.svelte

SmartSettings.svelteSwitch SmartSettings rows to FriendlyControl +3/-2

Switch SmartSettings rows to FriendlyControl

• Replaces 'TokenRow' usage with 'FriendlyControl' for timing/easing and other smart sections. Keeps the same token set but standardizes the editing surface and removes raw-info specific wiring from this view.

configurator/src/components/SmartSettings.svelte

ColorStudio.svelteAdd Color Studio workflow with palette/role previews +105/-0

Add Color Studio workflow with palette/role previews

• Introduces a Studio editor for colors, including workflow steps, usage previews, palette swatches, role-map visualization, and collapsible sections for brand/status/tuning/assignments/shade ramp. Integrates existing color components (BrandColorRow, ColorAssignments, ShadeRamp) with the new Studio frame.

configurator/src/components/editors/ColorStudio.svelte

EffectsStudio.svelteAdd Effects Studio with blur/opacity/scrim/mask previews +69/-0

Add Effects Studio with blur/opacity/scrim/mask previews

• Adds an effects-focused Studio with workflow navigation, preview labs for glass/blur, state opacity, scrim overlays, and mask fades. Renders curated controls via 'StudioControls' backed by 'STUDIO_GROUPS.effects'.

configurator/src/components/editors/EffectsStudio.svelte

LayoutStudio.svelteAdd Layout Studio with container/grid/measure previews +91/-0

Add Layout Studio with container/grid/measure previews

• Adds a layout Studio featuring a semantic workflow list, container width comparison using 'ContainerBars', and composition/measure/anchor previews. Wires curated token groups through 'StudioControls' for layout-related tokens.

configurator/src/components/editors/LayoutStudio.svelte

MotionStudio.svelteAdd Motion Studio with duration/easing/preset previews +90/-0

Add Motion Studio with duration/easing/preset previews

• Introduces a motion Studio with workflow steps and preview labs for duration rails, easing curves, animation presets, and reduced-motion behavior. Uses 'StudioControls' with motion groups and includes prefers-reduced-motion fallbacks for animations.

configurator/src/components/editors/MotionStudio.svelte

ShadowStudio.svelteAdd Shadow Studio with elevation and surface context previews +63/-0

Add Shadow Studio with elevation and surface context previews

• Adds a shadow Studio showing an elevation stack, surface/popup/dialog context, and media/text shadow previews. Curated controls are rendered via 'StudioControls' and 'STUDIO_GROUPS.shadows'.

configurator/src/components/editors/ShadowStudio.svelte

ShapeStudio.svelteAdd Shape Studio for radius/border/divider/focus system +73/-0

Add Shape Studio for radius/border/divider/focus system

• Introduces a shape Studio with radius scale previews, component shape previews, and border/divider/focus ring demonstrations. Uses 'StudioControls' for the borders domain token groups.

configurator/src/components/editors/ShapeStudio.svelte

SpacingStudio.svelteAdd Spacing Studio with scale ruler and rhythm previews +84/-0

Add Spacing Studio with scale ruler and rhythm previews

• Adds a spacing Studio including workflow steps, a scale ruler driven by '--sf-space-scale', and previews for section padding, content rhythm, and component spacing. Hooks curated spacing groups into 'StudioControls'.

configurator/src/components/editors/SpacingStudio.svelte

StudioControls.svelteAdd reusable curated control renderer for studios +24/-0

Add reusable curated control renderer for studios

• Provides a shared renderer that maps resolved studio token groups into collapsible 'ControlSection's. Each token is edited with 'FriendlyControl', and modified counts are derived from the overrides store.

configurator/src/components/editors/StudioControls.svelte

StudioFrame.svelteAdd shared Studio frame with staged preview styling +30/-0

Add shared Studio frame with staged preview styling

• Creates a common Studio layout with sticky left rail copy and a right preview/control surface. Applies 'buildPreviewDeclarations()' to ensure each studio preview uses the configured preview theme and current overrides.

configurator/src/components/editors/StudioFrame.svelte

StudioWorkflow.svelteAdd reusable workflow step navigation for studios +16/-0

Add reusable workflow step navigation for studios

• Adds a small component to render numbered workflow steps with consistent styling and responsive layout. Used by multiple studios to standardize step presentation.

configurator/src/components/editors/StudioWorkflow.svelte

TypographyStudio.svelteAdd Typography Studio with scope tabs and specimen preview +75/-0

Add Typography Studio with scope tabs and specimen preview

• Introduces a typography Studio with tabbed scopes (panels), a live specimen preview, and curated controls tied to the active panel. Uses 'TYPOGRAPHY_PANELS' + 'resolveStudioGroups()' to keep token lists centralized and testable.

configurator/src/components/editors/TypographyStudio.svelte

controlSchema.jsAdd control schema heuristics for FriendlyControl +56/-0

Add control schema heuristics for FriendlyControl

• Defines explicit token control metadata plus heuristic inference (select/color/font/length/number) based on token name and value patterns. Exposes 'controlForToken()' to unify labeling, descriptions, control types, and preview types across studios.

configurator/src/lib/controlSchema.js

studioSchema.jsAdd curated studio token panels/groups and resolver +76/-0

Add curated studio token panels/groups and resolver

• Introduces 'TYPOGRAPHY_PANELS' and domain 'STUDIO_GROUPS' as curated token collections with titles/hints. Adds 'resolveStudioGroups()' to map token names to real token objects and drop stale references safely.

configurator/src/lib/studioSchema.js

Bug fix (3) +4 / -3
HeadingEditor.svelteFix tablist keyboard focusability +1/-1

Fix tablist keyboard focusability

• Adds 'tabindex="0"' to the heading level tablist container so keyboard events are reliably reachable/focusable for navigation.

configurator/src/components/HeadingEditor.svelte

RadiusEditor.svelteFix tablist keyboard focusability +1/-1

Fix tablist keyboard focusability

• Adds 'tabindex="0"' to the radius level tablist container to improve keyboard navigation reliability.

configurator/src/components/RadiusEditor.svelte

a11y.spec.jsFix a11y e2e to expand All Variables before querying rows +2/-1

Fix a11y e2e to expand All Variables before querying rows

• Updates the selector path for the 'Reading width' row by expanding the All Variables disclosure first, then querying within '.allvars__body'. Aligns the test with the redesigned progressive disclosure behavior.

configurator/tests-e2e/a11y.spec.js

Tests (2) +122 / -0
studios.test.jsAdd smoke tests for studios and FriendlyControl override writes +65/-0

Add smoke tests for studios and FriendlyControl override writes

• Adds vitest/jsdom structural tests ensuring each Studio mounts, renders core preview surfaces, and includes expected workflow/preview text. Includes targeted tests for typography scope switching and schema-driven select controls writing to overrides.

configurator/tests-components/studios.test.js

studio-schema.test.jsAdd schema contract tests for studio token lists +57/-0

Add schema contract tests for studio token lists

• Adds node:test assertions that every curated panel/group has required metadata and references tokens present in the generated API index. Also verifies 'resolveStudioGroups()' filters dead tokens without mutating labels.

configurator/tests/studio-schema.test.js

Other (2) +2 / -2
badge-essential.jsonUpdate essential bundle size badge +1/-1

Update essential bundle size badge

• Updates the reported gzip size message for the essential build badge to reflect the new output size after the redesign.

dist/badge-essential.json

badge-optimal.jsonUpdate optimal bundle size badge +1/-1

Update optimal bundle size badge

• Updates the reported gzip size message for the optimal build badge to reflect the new output size after the redesign.

dist/badge-optimal.json

@qodo-code-review

qodo-code-review Bot commented Jun 25, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 5 rules

Grey Divider


Action required

1. Preview link navigates away ✓ Resolved 🐞 Bug ☼ Reliability
Description
ColorStudio includes a real anchor href="/" in the preview surface; clicking it will
navigate/reload and can reset the configurator session state.
Code

configurator/src/components/editors/ColorStudio.svelte[R31-34]

+    <section class="usage" aria-label="Usage preview">
+      <button>Primary button</button>
+      <div><strong>Surface card</strong><p>Text, link, border and subtle background preview.</p><a href="/">Example link</a></div>
+      <mark>Status message</mark>
Relevance

⭐⭐ Medium

No prior review evidence about preventing navigation from preview/demo anchors; preview UX fixes
exist but not this pattern.

PR-#312
PR-#328

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The studio markup contains a literal link to /. Since the app is configured as a static SPA,
clicking the link can trigger a full reload/navigation rather than an inert preview interaction.

configurator/src/components/editors/ColorStudio.svelte[31-35]
configurator/vite.config.js[29-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Color Studio preview contains `<a href="/">…</a>`, which performs a hard navigation when clicked.

## Issue Context
This project is built as a static SPA (`base: './'`). A hard navigation can reload the app and disrupt/lose the current editing session.

## Fix Focus Areas
- configurator/src/components/editors/ColorStudio.svelte[31-35]
- configurator/vite.config.js[29-34]

## Suggested fix
Make the preview link inert:
- Use `href="#"` and `onclick={(e) => e.preventDefault()}` (or `on:click|preventDefault` if using directive syntax),
- or replace it with a `<span role="link" tabindex="0">` purely for visual preview,
- or keep `href` but add an explicit click handler that prevents navigation.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Preview style recomputed per row 🐞 Bug ➹ Performance
Description
ControlPreview computes stageStyle via buildPreviewDeclarations(overrides, ui.previewTheme)
inside each instance, so rendering many FriendlyControls multiplies work and repeats large inline
style strings across the DOM.
Code

configurator/src/components/ControlPreview.svelte[R2-9]

+  import { overrides, ui } from '../lib/store.svelte.js';
+  import { buildPreviewDeclarations } from '../lib/preview.js';
+  let { token, value = '', type = 'text', label = '' } = $props();
+  const active = $derived(value || overrides[token?.name] || token?.value || '');
+  const stageStyle = $derived(buildPreviewDeclarations(overrides, ui.previewTheme));
+</script>
+
+<div class="ctrl-preview" style={stageStyle} title={token?.name || label}>
Relevance

⭐⭐⭐ High

Team accepted removing redundant per-row work in UI ($effect per row) for perf in PR #398.

PR-#398

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
ControlPreview computes stageStyle locally, and buildPreviewDeclarations iterates the entire
token catalogue plus all overrides on every call, so duplicating this per preview row adds avoidable
repeated work.

configurator/src/components/ControlPreview.svelte[2-10]
configurator/src/lib/preview.js[28-46]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ControlPreview` calls `buildPreviewDeclarations(...)` per component instance. Since `buildPreviewDeclarations` loops through `allTokens` and `Object.entries(overrides)`, doing this per-row can scale poorly when many controls are visible.

## Issue Context
`FriendlyControl` is used for studio control rows and always includes `ControlPreview`, so the computation is repeated N times (N = number of visible control rows) whenever overrides or preview theme changes.

## Fix Focus Areas
- configurator/src/components/ControlPreview.svelte[1-10]
- configurator/src/lib/preview.js[28-46]

## Suggested fix
Prefer one of:
1. Create a module-level shared derived value in a `.svelte.js` module (e.g. `src/lib/previewStage.svelte.js`) that exports a single reactive `previewDeclarations` string computed once from `{overrides, ui.previewTheme}` and reuse it in all previews.
2. Or pass `stageStyle` down from a parent wrapper that already computes it once (e.g. StudioFrame / the studio root), so ControlPreview doesn’t recompute.

Also consider avoiding repeating the full declarations string as an inline style on every preview node (e.g. apply it to a single wrapper element around the previews).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Consume tokens bypass guardrails 🐞 Bug ≡ Correctness
Description
FriendlyControl renders editable controls for all tokens without checking `token.role ===
'consumption'`, bypassing TokenRow’s readonly behavior and making derived tokens (e.g.
--sf-animation-fade-in) directly editable in studios.
Code

configurator/src/components/FriendlyControl.svelte[R28-39]

+  <div class="friendly__editor">
+    {#if meta.control === 'select' && meta.options?.length}
+      <select class="cfg-select friendly__select" value={activeValue} onchange={onSelect} aria-label={token.name}>
+        {#each meta.options as option (option)}
+          <option value={option}>{option}</option>
+        {/each}
+      </select>
+    {:else}
+      <TokenEditor {token} />
+    {/if}
+  </div>
+  <ControlPreview {token} type={meta.preview} />
Relevance

⭐⭐⭐ High

Repo explicitly made consumption tokens read-only (PR #325) and reinforced special handling (PR
#395).

PR-#325
PR-#395

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
TokenRow implements explicit readonly handling for consumption tokens, while FriendlyControl always
renders an editor. The studio schema includes tokens like --sf-animation-fade-in, which the
api-index marks as role: consumption, meaning the new studio UI will expose an editor for a token
previously considered derived/readonly by default.

configurator/src/components/FriendlyControl.svelte[19-43]
configurator/src/components/TokenRow.svelte[66-74]
configurator/src/components/TokenRow.svelte[168-193]
configurator/src/lib/studioSchema.js[57-61]
configurator/src/data/api-index.generated.json[246-256]
PR-#395

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`FriendlyControl` does not respect consumption/derived tokens. Unlike `TokenRow`, it never checks `isConsumptionToken(token)` and therefore always renders an editor (select or `TokenEditor`) for tokens that the app previously treated as readonly unless explicitly forced editable.

## Issue Context
The codebase already has a clear policy in `TokenRow`: consumption tokens are readonly by default and only become editable when `forceEditable` is explicitly set. The new studio surfaces include tokens whose api-index `role` is `consumption`.

## Fix Focus Areas
- configurator/src/components/FriendlyControl.svelte[1-44]
- configurator/src/components/TokenRow.svelte[66-74]
- configurator/src/components/TokenRow.svelte[168-193]
- configurator/src/lib/studioSchema.js[57-61]

## Suggested fix
1. Add a `forceEditable = false` prop to `FriendlyControl`.
2. Import and use `isConsumptionToken` (from `src/lib/model.js`) to compute `isConsume`.
3. If `isConsume && !forceEditable`, render a readonly effective value plus a reset affordance (mirroring `TokenRow`’s consumption branch).
4. Update call sites that intentionally want to allow editing consumption tokens (if any) to pass `forceEditable` explicitly, rather than making *all* consumption tokens editable by default.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

4. Tablist becomes tabbable 🐞 Bug ☼ Reliability
Description
Adding tabindex="0" to the tablist wrapper makes it an extra tab stop in addition to the active
tab button, which can degrade keyboard navigation.
Code

configurator/src/components/HeadingEditor.svelte[83]

+  <div class="hed__tabs" role="tablist" tabindex="0" aria-label="Heading level" onkeydown={navigateTabs}>
Relevance

⭐⭐ Medium

No historical suggestions found about tablist wrapper tabindex creating extra tab stop; a11y-related
changes mixed outcomes.

PR-#382

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Both editors set tabindex="0" on the tablist wrapper while tabs already manage focus via
tabindex={active ? 0 : -1}, making the wrapper an additional keyboard focus target.

configurator/src/components/HeadingEditor.svelte[82-92]
configurator/src/components/RadiusEditor.svelte[54-64]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The tablist wrapper now has `tabindex="0"`, which makes the container tabbable even though the tabs already implement roving tabindex.

## Issue Context
This introduces an extra focus stop that may not provide meaningful interaction (focus lands on the container rather than the selected tab).

## Fix Focus Areas
- configurator/src/components/HeadingEditor.svelte[82-92]
- configurator/src/components/RadiusEditor.svelte[54-64]

## Suggested fix
Remove `tabindex="0"` from the tablist wrappers (or set to `-1` if there is a specific programmatic focus need), relying on the tab buttons’ existing roving tabindex implementation.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread configurator/src/components/editors/ColorStudio.svelte
@jackgranatowski

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot added the codex label Jun 25, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (3)
configurator/src/components/editors/StudioWorkflow.svelte (1)

5-8: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use ordered-list semantics for the step sequence.

Line 5–8 renders ordered steps with <span> nodes; using <ol>/<li> gives better accessibility semantics for this numbered workflow.

Suggested change
-<nav class="studio-workflow" aria-label={ariaLabel}>
-  {`#each` steps as step, index (step)}
-    <span><b>{index + 1}</b>{step}</span>
-  {/each}
-</nav>
+<nav aria-label={ariaLabel}>
+  <ol class="studio-workflow">
+    {`#each` steps as step, index (step)}
+      <li><b>{index + 1}</b>{step}</li>
+    {/each}
+  </ol>
+</nav>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@configurator/src/components/editors/StudioWorkflow.svelte` around lines 5 -
8, The step sequence in StudioWorkflow.svelte is rendered as generic spans
inside the nav, but it should use ordered-list semantics for accessibility.
Update the markup around the steps loop in the StudioWorkflow component so the
numbered workflow is represented with an ol containing li items instead of span
elements, while preserving the existing aria-label and step rendering logic.
configurator/src/components/DomainPanel.svelte (1)

89-90: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Duplicated domain→studio source of truth.

redesignedDomains (Line 89) and the studio {#if}/{:else if} chain (Lines 190-206) independently enumerate the same eight domain ids. They're in sync now, but adding/removing a studio requires editing both places, and a mismatch would silently render neither the studio nor the friendly-controls fallback. Consider driving both from one map (id → component).

♻️ Sketch
-  const redesignedDomains = new Set(['colors', 'typography', 'spacing', 'layout', 'borders', 'shadows', 'motion', 'effects']);
-  const usesVisualStudio = $derived(redesignedDomains.has(domain.id));
+  const STUDIO_BY_DOMAIN = {
+    typography: TypographyStudio, colors: ColorStudio, spacing: SpacingStudio,
+    layout: LayoutStudio, borders: ShapeStudio, shadows: ShadowStudio,
+    motion: MotionStudio, effects: EffectsStudio,
+  };
+  const Studio = $derived(STUDIO_BY_DOMAIN[domain.id] ?? null);
+  const usesVisualStudio = $derived(Studio != null);

Then render {#if Studio}<svelte:component this={Studio} />{/if} in place of the if/else chain.

Also applies to: 190-206

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@configurator/src/components/DomainPanel.svelte` around lines 89 - 90, The
DomainPanel.svelte logic duplicates the same domain-to-studio mapping in both
redesignedDomains/usesVisualStudio and the Studio if/else chain, so consolidate
them into one source of truth. Update the DomainPanel component to derive the
active studio from a single map or lookup keyed by domain.id, and then render
that resolved component directly instead of maintaining separate enumerations
for the same eight ids. Ensure the friendly-controls fallback still handles
unknown domains when no studio is found.
configurator/src/components/editors/StudioFrame.svelte (1)

13-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

aria-label on a generic <div> is not reliably exposed.

aria-label on an element without a semantic/landmark role is ignored by many AT combinations. If these workflow steps are decorative, drop the label; if they convey state, use a list (<ol>/<li>) or add an appropriate role so the label is announced.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@configurator/src/components/editors/StudioFrame.svelte` around lines 13 - 15,
The workflow container in StudioFrame’s studio__steps block uses aria-label on a
generic div, which may not be exposed to assistive tech. Either remove the label
if the preview/tune/verify text is purely decorative, or change the structure to
a semantic list or add an appropriate role so the label is actually announced;
keep the existing step content but adjust the wrapper markup in
StudioFrame.svelte accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@configurator/src/components/editors/EffectsStudio.svelte`:
- Line 58: The `.pending` shimmer animation in `EffectsStudio.svelte` ignores
reduced-motion preferences. Add a `prefers-reduced-motion: reduce` override in
the same component’s styles to disable or minimize the `shimmer` animation for
`.pending`, and make sure the `@keyframes shimmer` usage is only active when
motion is allowed.

In `@configurator/src/components/editors/MotionStudio.svelte`:
- Line 13: The MotionStudio description copy is mixing locales, so update the
StudioFrame description to use one consistent language only. Edit the
MotionStudio.svelte string on the StudioFrame component so the title/description
text stays fully in a single locale, keeping the surrounding copy style
consistent.

In `@configurator/src/components/editors/ShadowStudio.svelte`:
- Line 12: The StudioFrame description in ShadowStudio.svelte mixes Polish and
English, so update the description text to use a single locale consistently.
Adjust the Shadow Studio copy in the StudioFrame title/description block so the
full sentence is entirely in English (or entirely in Polish), keeping the
message aligned with the surrounding UI language.

In `@configurator/src/components/editors/ShapeStudio.svelte`:
- Line 13: The ShapeStudio description string is mixing English and Polish, so
update the StudioFrame copy to use one consistent locale only. Locate the
ShapeStudio.svelte component and replace the mixed-language description with
fully English text, or move it into the existing i18n/localization flow if that
is how other studio copy is handled, so the displayed UX text is consistent.

In `@configurator/src/components/editors/TypographyStudio.svelte`:
- Line 68: The TypographyStudio.svelte styles include an unused strong selector
that triggers the CI warning; update the component’s scoped CSS to remove strong
from the combined strong, code rule and keep only the code selector, since the
.specimen markup renders code but not strong.

In `@configurator/src/components/FriendlyControl.svelte`:
- Around line 29-34: The select in FriendlyControl.svelte can show the wrong
option when activeValue is not included in meta.options, causing the UI to
misrepresent the stored override/token value. Update the select rendering so the
current activeValue is preserved visibly when it’s out of range, such as by
adding a fallback option or normalizing the value before binding; use the
existing meta.control, meta.options, activeValue, and onSelect logic to keep the
displayed selection aligned with the store.

In `@configurator/src/components/Header.svelte`:
- Line 9: The header’s override count is using raw object key count, which can
include stale or unknown entries and drift from the canonical token count.
Update Header.svelte’s modCount derived value to count only token-aware valid
overrides from the same source used for sharing/status, so the header reflects
the canonical override state and does not enable sharing on stale keys.

In `@configurator/tests-e2e/a11y.spec.js`:
- Around line 66-67: The accessibility test is toggling the allvars details
panel unconditionally before locating the row, which can close an already-open
`details.allvars` and cause the row lookup to fail. Update `a11y.spec.js` so the
`page.locator('details.allvars summary').click()` step only opens the panel when
it is closed, or otherwise avoid re-clicking an already open `details.allvars`
before querying the `.allvars__body .row` for “Reading width”. Use the existing
`details.allvars` and row locator logic to keep the panel state stable before
asserting on the row info button.

---

Nitpick comments:
In `@configurator/src/components/DomainPanel.svelte`:
- Around line 89-90: The DomainPanel.svelte logic duplicates the same
domain-to-studio mapping in both redesignedDomains/usesVisualStudio and the
Studio if/else chain, so consolidate them into one source of truth. Update the
DomainPanel component to derive the active studio from a single map or lookup
keyed by domain.id, and then render that resolved component directly instead of
maintaining separate enumerations for the same eight ids. Ensure the
friendly-controls fallback still handles unknown domains when no studio is
found.

In `@configurator/src/components/editors/StudioFrame.svelte`:
- Around line 13-15: The workflow container in StudioFrame’s studio__steps block
uses aria-label on a generic div, which may not be exposed to assistive tech.
Either remove the label if the preview/tune/verify text is purely decorative, or
change the structure to a semantic list or add an appropriate role so the label
is actually announced; keep the existing step content but adjust the wrapper
markup in StudioFrame.svelte accordingly.

In `@configurator/src/components/editors/StudioWorkflow.svelte`:
- Around line 5-8: The step sequence in StudioWorkflow.svelte is rendered as
generic spans inside the nav, but it should use ordered-list semantics for
accessibility. Update the markup around the steps loop in the StudioWorkflow
component so the numbered workflow is represented with an ol containing li items
instead of span elements, while preserving the existing aria-label and step
rendering logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 20c96cf5-6365-4e5b-8751-1e379209c1e7

📥 Commits

Reviewing files that changed from the base of the PR and between 7cef166 and 0a3cc02.

⛔ Files ignored due to path filters (2)
  • dist/badge-essential.json is excluded by !**/dist/**
  • dist/badge-optimal.json is excluded by !**/dist/**
📒 Files selected for processing (25)
  • configurator/src/components/CategoryHeader.svelte
  • configurator/src/components/ControlPreview.svelte
  • configurator/src/components/ControlSection.svelte
  • configurator/src/components/DomainPanel.svelte
  • configurator/src/components/FriendlyControl.svelte
  • configurator/src/components/Header.svelte
  • configurator/src/components/HeadingEditor.svelte
  • configurator/src/components/RadiusEditor.svelte
  • configurator/src/components/SmartSettings.svelte
  • configurator/src/components/editors/ColorStudio.svelte
  • configurator/src/components/editors/EffectsStudio.svelte
  • configurator/src/components/editors/LayoutStudio.svelte
  • configurator/src/components/editors/MotionStudio.svelte
  • configurator/src/components/editors/ShadowStudio.svelte
  • configurator/src/components/editors/ShapeStudio.svelte
  • configurator/src/components/editors/SpacingStudio.svelte
  • configurator/src/components/editors/StudioControls.svelte
  • configurator/src/components/editors/StudioFrame.svelte
  • configurator/src/components/editors/StudioWorkflow.svelte
  • configurator/src/components/editors/TypographyStudio.svelte
  • configurator/src/lib/controlSchema.js
  • configurator/src/lib/studioSchema.js
  • configurator/tests-components/studios.test.js
  • configurator/tests-e2e/a11y.spec.js
  • configurator/tests/studio-schema.test.js

Comment thread configurator/src/components/editors/EffectsStudio.svelte
Comment thread configurator/src/components/editors/MotionStudio.svelte Outdated
Comment thread configurator/src/components/editors/ShadowStudio.svelte Outdated
Comment thread configurator/src/components/editors/ShapeStudio.svelte Outdated
Comment thread configurator/src/components/editors/TypographyStudio.svelte Outdated
Comment thread configurator/src/components/FriendlyControl.svelte
Comment thread configurator/src/components/Header.svelte Outdated
Comment thread configurator/tests-e2e/a11y.spec.js Outdated
claude added 2 commits June 25, 2026 06:51
…_info-btn

The info button (showRawInfo) is only rendered in SmartSettings gradient
sections, not in allvars raw rows. Update the aria-expanded test to click
into the Gradients panel where Raw gradient rows expose .row__info-btn.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2b6qg3hbi9QsBZmaFwjUd
- ColorStudio: replace navigating <a href="/"> with inert <span role="link">
- EffectsStudio: add prefers-reduced-motion override for .pending shimmer
- MotionStudio, ShadowStudio, ShapeStudio: fix mixed Polish/English descriptions
- TypographyStudio: remove unused `strong` CSS selector (clears CI warning)
- FriendlyControl: add fallback <option> when activeValue not in meta.options
- Header: use modifiedCountsByDomain() instead of raw Object.keys count
- StudioWorkflow: convert <span> items to <ol>/<li> for proper list semantics
- StudioFrame: convert studio__steps div to <ol> so aria-label is reliably exposed
- DomainPanel: consolidate redesignedDomains + if/else chain into STUDIO_BY_DOMAIN map

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants