Skip to content

feat(configurator): discoverable global search + deep-link to control (UX redesign, phase 6) - #696

Merged
jackgranatowski merged 5 commits into
mainfrom
ux/configurator-search-deeplink
Aug 20, 2026
Merged

jackgranatowski merged 5 commits into
mainfrom
ux/configurator-search-deeplink

Conversation

@jackgranatowski

Copy link
Copy Markdown
Contributor

Phase 6 of the configurator UX redesign — search that lands on the control

Stacked on #691#692#693#694#695. Merge those first; this branch includes their commits.

The command palette was hidden behind ⌘K and only jumped to a domain — the user then had to re-find the token by hand. This turns search into a first-class, visible tool that lands you exactly on the control.

What changed

  • Discoverable: a visible Search… ⌘K button in the header opens the palette (the shortcut still works).
  • A real command palette: a Go to section lists every panel/tool (useful before you type), plus token results below. Uses the new phase-4 names (Shape / Accessibility / Presets / Install & export / Reference).
  • Deep-link to the control: selecting a token result navigates to its domain, opens the All-tokens list, pre-fills the search with the token, scrolls to it and highlights the row with a ring for ~2.6s — so you land on the actual editor (now the phase-5 Inherit/Value/Expression ValueField).

How the deep-link is wired

A one-shot focusRequest {token, nonce} is threaded App → DomainPanel → AllTokensTab. The nonce lets the same token be re-focused (a second search still scrolls/highlights). A single guarded effect in DomainPanel decides Controls-vs-tokens, so a simultaneous domain change and focus request can't race.

Verification

  • npm run check: 0 errors · npm run lint: clean · build OK
  • npm run test: 272/272 · shell e2e green
  • Screenshot-verified: the palette (Go-to list) and the full deep-link (search radius-l → Shape → All tokens, filtered, row highlighted).

Scope / follow-ups

Lands discoverable search + control-level deep-link. Preview-only vs persistent-control separation (Components) and contextual tool previews (Accessibility / Presets / Install & export show the Color gallery today) remain focused follow-ups.

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Warning

Review limit reached

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

Next review available in: 59 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 65f8d63b-d607-4395-9a02-6796cccd2b11

📥 Commits

Reviewing files that changed from the base of the PR and between d89b7e6 and 3c1caa2.

📒 Files selected for processing (15)
  • configurator/src/App.svelte
  • configurator/src/components/CommandPalette.svelte
  • configurator/src/components/DomainPanel.svelte
  • configurator/src/components/inputs/TokenRow.svelte
  • configurator/src/components/inputs/ValueField.svelte
  • configurator/src/components/panels/AllTokensTab.svelte
  • configurator/src/components/panels/HomePanel.svelte
  • configurator/src/components/shell/SidebarNav.svelte
  • configurator/src/components/shell/StudioHeader.svelte
  • configurator/src/lib/history.ts
  • configurator/src/lib/valueField.ts
  • configurator/tests-components/token-editing.test.js
  • configurator/tests-e2e/shell.spec.js
  • configurator/tests/history.test.ts
  • configurator/tests/valueField.test.ts

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.

@greptile-apps

greptile-apps Bot commented Aug 19, 2026

Copy link
Copy Markdown

Greptile Summary

The PR redesigns configurator navigation and token search, adds control-level deep-linking, and introduces richer token editing and change inspection.

  • Adds a visible command palette with panel navigation and token-row focus/highlighting.
  • Replaces substring domain routing with a shared namespace-based classifier.
  • Adds unified Value/Expression editing, token relationship metadata, a Changes panel, and undo coalescing.
  • Expands unit and shell coverage for the new models and navigation.

Confidence Score: 3/5

The PR should not merge until undo grouping preserves distinct edits and Escape reliably cancels uncommitted token values.

Time-only history grouping can collapse separate edits into one undo step, while the new value editor routes Escape through its commit-on-blur handler; its retained manual mode also creates a non-blocking stale-state issue.

Files Needing Attention: configurator/src/App.svelte, configurator/src/components/inputs/ValueField.svelte

Important Files Changed

Filename Overview
configurator/src/App.svelte Wires global search and deep-link state, but time-only history coalescing merges distinct same-token edits.
configurator/src/components/inputs/ValueField.svelte Introduces the unified editor; Escape can commit a canceled draft and manual mode can remain stale.
configurator/src/components/CommandPalette.svelte Adds panel destinations and token-level navigation with no accepted correctness issue.
configurator/src/components/panels/AllTokensTab.svelte Implements canonical domain filtering and nonce-driven token filtering, scrolling, and highlighting.
configurator/src/lib/domains.ts Centralizes token routing around generated namespace metadata and explicit exceptions.
configurator/src/lib/tokenModel.ts Adds token roles, dependency analysis, scale-shadow detection, validation, and change summaries.

Sequence Diagram

sequenceDiagram
  actor User
  participant Palette as CommandPalette
  participant App
  participant Domain as DomainPanel
  participant Tokens as AllTokensTab
  User->>Palette: Search and select token
  Palette->>App: onNavigate(domain, token)
  App->>Domain: domain + focusToken + nonce
  Domain->>Tokens: Open All tokens with focus request
  Tokens->>Tokens: Filter, scroll, and highlight row
  Tokens-->>User: Focused ValueField
Loading

Reviews (1): Last reviewed commit: "feat(configurator): discoverable global ..." | Re-trigger Greptile

Comment thread configurator/src/App.svelte Outdated
Comment on lines +119 to +122
if (!shouldCoalesce(coalesce, keys, now)) {
past = [...past.slice(-49), prev];
}
coalesce = { key: keys.length === 1 ? keys[0] : null, time: now };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Undo merges separate edits

When two distinct edits to the same token are committed within 600ms, shouldCoalesce treats the second as part of the first because no blur, pointer-up, or other gesture boundary resets the state. A single Undo therefore removes both edits instead of restoring the intermediate value.

onblur={(e) => { editing = false; commit((e.target as HTMLInputElement).value); }}
onkeydown={(e) => {
if (e.key === "Enter") (e.currentTarget as HTMLInputElement).blur();
if (e.key === "Escape") { editing = false; draft = overrideValue ?? token.value ?? ""; (e.currentTarget as HTMLInputElement).blur(); }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Escape commits canceled drafts

When a user edits the field and presses Escape, this handler blurs the input, and the blur handler immediately commits the input element's current value. The attempted cancellation therefore saves the draft as an override.

Comment on lines +19 to +20
let manualMode = $state<ValueMode | null>(null);
let mode = $derived<ValueMode>(manualMode ?? detectMode(overrideValue));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Manual mode remains stale

manualMode is cleared only when Inherit is selected, so undo, reset, preset application, or another external override change can leave an expression or inherited value displayed under the Value tab. Reset the manual selection when overrideValue changes so the editor continues to describe the current value accurately.

…tion/Quality/Project)

Replace the flat, unlabelled icon rail with a grouped, always-labelled
navigation so users reason about areas of the design system instead of decoding
icons. The rail is now organised into four named groups:

- Foundations: Colors, Typography, Spacing, Shape, Motion
- Composition: Layout, Shadows, Effects, Macros, Components, Misc
- Quality:     Changes, Accessibility
- Project:     Presets, Install & export, Reference

Renames per the plan: Borders→Shape (it already holds radius), WCAG→
Accessibility, Themes→Presets, Install→"Install & export", Classes→Reference.
Labels update in App's panel-heading map and HomePanel too, so the sidebar, the
panel header and the Home overview all tell the same story (same order, names,
descriptions and counts).

Responsive: desktop shows the labelled column (w-52) with group headers and a
trailing count pill; mobile keeps the compact icon rail (w-14) with corner-dot
counts and tooltips — no change to the mobile fold behaviour.

Scope: this is the information-architecture + naming half of the redesign's
phase 4. Domain/panel ids, token classification and preview mapping are
unchanged, so it's non-disruptive. Content-level panel merges (a single Depth
panel combining Shadows+Effects, the Misc split, and moving focus-ring/touch
into an expanded Accessibility panel) are deliberately deferred to their own
focused follow-ups.

Updated tests-e2e/shell.spec.js NAV_LABELS to the new names. check, lint, all
257 unit tests and the shell e2e suite pass; desktop + mobile screenshot-verified.
… grouped undo

Two universal control fixes from the audit.

1) Grouped undo (src/lib/history.ts). A slider drag fires `input` on every
   tick, so a single gesture used to push dozens of near-identical snapshots and
   one Ctrl+Z rewound a single pixel. setOverrides now coalesces a run of
   consecutive edits to the *same* token within a short window into one history
   entry; a different edit or a pause starts a fresh group; undo/redo end the
   open group. Pure helpers (changedKeys, shouldCoalesce) are unit-tested.

2) Unified value editor (ValueField.svelte + src/lib/valueField.ts). An explicit
   three-mode control — Inherit / Value / Expression — replaces TokenRow's
   ad-hoc scale-picker/expand/button editor. An expression override (var()/
   calc()/clamp()/…) always resolves to Expression mode and is shown verbatim,
   never parsed down to a fallback number, so the next edit can't silently
   overwrite it; switching to a fixed Value is a deliberate tab click. Inherit
   shows the framework default and offers a "relink to a scale step" dropdown
   (folding in the old sibling-scale picker). detectMode/isExpression/
   splitValueUnit are unit-tested.

TokenRow keeps all its phase-1 context (role badge, inherits, used-by, Detached/
Invalid warnings) and now edits through ValueField — so All tokens and the
Changes panel both gain the unified editor. check + lint clean; 272 unit tests
(history 8, valueField 7) and the shell e2e suite pass; screenshot-verified that
a calc() override renders in Expression mode verbatim.

Scope note: this lands the unified generic editor and grouped undo. Migrating
the specialised SliderRow-based panels onto the same three-mode model, and the
shared scale control with detach diagnostics for radius/border/motion, are
tracked as follow-ups (the detach diagnostics already exist in the Changes panel
and tokenModel.scaleShadows).
…token's control

The command palette was hidden behind Cmd/Ctrl+K and only jumped to a domain,
forcing users to re-find the token. This makes search a first-class, visible
tool that lands you exactly on the control.

- StudioHeader: a visible "Search… ⌘K" button opens the palette (still Cmd/Ctrl+K).
- CommandPalette: now a real command palette — a "Go to" section lists every
  panel/tool (so it's useful before typing), plus token results. Uses the new
  panel names (Shape/Accessibility/Presets/Install & export/Reference).
- Deep-link: selecting a token result navigates to its domain, opens the
  All-tokens list, pre-fills the search with the token, scrolls to it and
  highlights the row with a ring for ~2.6s. Implemented as a one-shot
  focusRequest {token, nonce} threaded App → DomainPanel → AllTokensTab; the
  nonce lets the same token be re-focused. A single guarded effect in
  DomainPanel decides Controls-vs-tokens so a domain change and a focus request
  can't race.

check + lint clean; 272 unit tests and the shell e2e suite pass; palette +
deep-link screenshot-verified in Chromium.

Scope: lands discoverable search + control-level deep-link. Preview-only vs
persistent-control separation (Components) and contextual tool previews
(Accessibility/Presets/Install & export) remain follow-ups.
@jackgranatowski
jackgranatowski force-pushed the ux/configurator-search-deeplink branch from c279609 to 3c1caa2 Compare August 20, 2026 11:59
@jackgranatowski
jackgranatowski merged commit e36d416 into main Aug 20, 2026
13 checks passed
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.

2 participants