Add design token extraction for button components#351
Open
bartveneman wants to merge 9 commits into
Open
Conversation
New, additive /api/design-tokens endpoint: scrapes a URL's HTML+CSS, finds button/.button/.btn/[role=button] elements via linkedom, matches CSS rules against them with element.matches(), and resolves the CSS cascade (specificity, !important, source order) to surface only design-token-relevant declarations (background/color/border/shadow/ font, not spacing) per element and per interaction state (hover/focus/active/disabled). Results are grouped into suggested token combinations. No existing files were modified.
New (public)/component-tokens page reuses the existing CSS-form URL submit flow (same pattern as lint-css), fetches the design-tokens API for the submitted URL, and renders the raw JSON in a <pre> so the extracted token combinations can be eyeballed. File/raw-CSS tabs of the form are present but unused. No existing files were modified.
✅ Deploy Preview for projectwallace ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
/api/design-tokens no longer takes a ?component= selector; it now runs the extraction pipeline once per known preset (button, heading) and returns a report keyed by component name. Also adds the heading (h1/.h1/.heading-1) preset, and switches to the non-deprecated compareSpecificity export from @projectwallace/css-analyzer/selectors (the main-index one is documented as its inverse, which is why the cascade sort previously needed flipped arguments).
get_design_tokens fetched the raw, unresolved url string directly for the page's HTML, unlike get_css which normalizes it through resolve_url() first. Any protocol-less input (e.g. "example.com" - literally the form's own placeholder text) made the native fetch() throw "Invalid URL" inside the Promise.all, which propagated past the try/catch in +server.ts as a generic 500 that the page always reported as "Something went wrong." Now the url is validated/normalized via resolve_url() up front (same as get_css), and the HTML fetch failure is caught and turned into a proper structured error instead of an uncaught rejection.
padding is part of a component's visual shape, not just layout noise like margin/width/gap - add it to the design-token property allowlist alongside the already-present outline.
Drop the bare "button" tag selector in favor of more specific matches: button[type="submit"], input[type="button"], .button/.btn classes, [role="button"], and suffix classes like [class*="-button"] and [class*="-btn"].
Wrap the button preset's selectors in :is(...):not([class*="-link"]) so fuzzy matchers like [class*="-button"] don't pick up elements whose class also identifies them as a link (e.g. "nav-link"). Component presets are now single compound selector strings instead of arrays joined with a comma.
[class*="-link"] only caught hyphen-delimited class names (e.g. "nav-link"). Add a second :not([class*=":link"]) clause so colon-delimited variants (e.g. "pd:link") are excluded too.
New independent module (src/lib/resolve-css-variables.ts) that: - extracts the winning value of every custom property declared unconditionally on :root or html (same cascade rules as elsewhere - specificity, !important, source order - explicitly skipping anything nested inside a conditional at-rule like @media, since that can't be known without evaluating the condition) - substitutes var(--name[, fallback]) references in an arbitrary value string against that map, recursively resolving chained references and falling back gracefully on unknown/circular references Framework-agnostic and reusable outside this feature. Wired into /api/design-tokens (now returns root_custom_properties alongside the existing per-component report) and into the component-tokens debug page as a checkbox that resolves variables client-side, instantly, using data already in the initial response.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds a new feature to extract and analyze design tokens from button-like components on any website. It includes a complete pipeline for parsing CSS, matching selectors to DOM elements, resolving the CSS cascade, and suggesting common token combinations.
Key Changes
/api/design-tokens) that accepts a URL and optional component type, returning extracted design tokens and suggested combinationsextract-tokens.ts) that:button,.button,.btn,[role="button"])/component-tokens) for interactively analyzing any website's button design tokensImplementation Details
@projectwallace/css-parserfor CSS parsing and@projectwallace/css-analyzerfor specificity calculationlinkedomfor server-side DOM parsing and selector matchinghttps://claude.ai/code/session_01WbLSKV7rJBokuRvBRNeWRf