feat(tokens)!: adopt espresso v2 tokens + codemod migration#727
Merged
Conversation
84b44f7 to
280a01a
Compare
3 tasks
56a53c7 to
002efa1
Compare
002efa1 to
5b34eef
Compare
…ndations docs
Generator
- tailwind/figma-tokens-to-theme.js reads the W3C DTCG token JSON
exported from Figma (espresso-v2-design-tokens/) and emits
tailwind/generated/{colors,radius,typography}.json
- Run with `yarn sync-tokens`
- Preserves legacy semantic names (surface-cards, surface-white,
ink-gray-9, outline-gray-modals, …) via alias + legacy-entry maps
so existing src/ and docs/ usage keeps working through the rename
Tailwind
- tailwind/colors.json refreshed from Figma; adds *.950 shades,
gray-alpha and red-alpha ramps, surface/ink/outline updates
- tailwind/plugin.js now consumes radius.json + typography.json
instead of hardcoded scales; exposes new sizes (tiny, 4xl..15xl)
and the full numeric radius scale (rounded-0..9) alongside the
named aliases
Docs
- New /docs/foundations/* pages replacing /docs/design-system/*:
Colours — Base, Colours — Semantic, Typography, Corner Radius,
Drop Shadow
- Components in docs/components/foundations/ read directly from
the generated JSON; light/dark TabButtons toggle; click-to-copy
- Layout.vue respects `outline: false` frontmatter (custom
OnThisPage was previously unconditional)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
transformerStyleToClass only flushes its CSS at buildEnd, so in dev the generated shiki.css stays empty and code blocks lose their syntax highlighting. Skip the transformer in dev and let shiki emit inline --shiki-light/dark styles directly. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add text-{size}-medium utilities (ADR-0004) for Figma's named
typography styles; Button md/lg adopt them for exact tracking parity
- Switch Button focus ring to ring-2 to match Figma's 2px shadow (ADR-0005)
- Adopt numbered radius tokens as canonical (ADR-0006); Button migrates
from named aliases; named aliases flagged for migration
- Add spec/foundations.md covering typography, focus, radius, themes,
code-only extensions, and the Figma verification process
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Delete Variants/Themes/Sizes/Icons stories; the API table already covers prop variations - Add 6 contextual stories matching the Button Figma file: section controls, section action, selection toolbar, inline actions, stacked actions, and a live-class card - Add a Playground builder (TabButtons + Switch knobs) with live preview and dynamically generated Vue snippet; registered globally as <ButtonBuilder> in the VitePress theme Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Wire the Figma token pipeline to emit elevation/focus effects, expose them as CSS variables, and register `shadow-*` / `ring-*` utilities that resolve to the new variables. Replace the standalone drop-shadow docs page with a broader elevation page that previews both stacks. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Consolidates the lucide / feather / emoji / Vue-component icon-rendering pattern that's currently duplicated across Button, Dropdown, Dialog, and OptionIcon into one small component, so new call sites have one obvious choice. Falsy values render nothing; fallthrough attrs go to the rendered root. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
A compact tab item used by TabButtons (and reusable on its own). The `icon` prop renders an icon-only pill — any `label` is exposed only to assistive tech. `iconLeft` / `iconRight` are accent icons rendered next to a visible label, matching Button's semantics. Variants cover the segmented, outline, underline, and browser-tab looks. Icon rendering goes through the shared `<Icon>` component. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…wrap TabButtons no longer wraps `<Button>` internally — each tab is now a native `<button>`, `<a href>`, or `<RouterLink>` rendering a `<Pill>` for its visual treatment. BREAKING CHANGE: per-option `theme`, `variant`, `size`, `loading`, `hideLabel` and `tooltip`-as-popover are no longer honored. Use the shared `<Button>` directly if any of these matter, or supply richer content via the `prefix` / `suffix` slots. Migration notes added to `TabButtons.md`. New: `route` and `href` per option render the tab as a RouterLink or anchor respectively. The internal v-model fallback chain (`value ?? label ?? index`) is preserved for back-compat with consumers that bound to a label string. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Picks up the new Pill and Icon components in the auto-resolved declaration file, drops stale Rating story entries, and absorbs incidental type-union reordering in Divider/Popover/Tooltip api docs. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the four duplicated *Builder.vue files (~180 lines each, 90% identical chrome) with a shared ComponentPlayground that takes a knob schema + #preview slot + code(values) fn. Each per-component builder shrinks to ~30-80 lines of pure config. Code preview matches story preview visuals exactly: runtime shiki highlighting with the same tokyo-night/github-light themes, .shiki sizing and bg, and the global .copy button style. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Previously the active indicator was a 3px rounded bar floating 3px outboard of the rail, with full pill height. Read as a text caret next to the label rather than a tab marker. Now: 1px-wide square segment positioned at right:-2px (overlapping the column rail), label-height via inset-y-1.5. Active label gets font-medium on underline variant so the label itself signals selection. Adds pr-2 to vertical underline pills so short labels don't sit flush against the indicator. Also cleans up a stray </content> tag at the end of Pill.vue and TabButtons.vue (left over from prior commits, broke SFC parsing). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Swap the per-site focus-visible:ring-* + ring-outline-gray-* patterns
for the new focus-ring / focus-ring-{theme} utilities backed by the
--focus-* design tokens. Button maps theme → themed focus-ring
(blue/green/red); other components use the default gray focus-ring.
Triggers in Select / shared selection / MultiSelect TagsTrigger also
adopt focus-ring on data-[state=open] so the open ring matches the
focus ring exactly. Intentional suppression sites (Sidebar item, ghost
input variants) left unchanged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace generic Tab/Tab placeholder options with Home/Task/Contact/Others nav and an icon-only ghost sidebar, inspired by the Figma showcase. Use distinct iconLeft icons per option and switch the Sizes / PrefixSuffix demos to view-switcher and Inbox/Comments patterns. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The docs render the stories/ snippets directly; this orphan Histoire-style file isn't referenced anywhere. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Sidebar/page renames: "Colours — Base" → "Base Colors", "Colours — Semantic" → "Semantic Colors", "Corner Radius" → "Radius" (file renamed to foundations/radius.md, URL paths for colours unchanged). - SemanticPage rewritten as a flat row list per token: swatch, name, → reference, and resolved value — no surrounding box, no hover. - PalettePage: drop the per-swatch inset 1px ring and the p-2 wrappers around the overlay sections; each overlay swatch now layers its translucent color over its own bg-ink-gray-9 / bg-surface-white backdrop via a linear-gradient. - New docs/composables/useTheme.ts watches the <html data-theme> attribute (set by Navbar.vue) so the local Light/Dark switchers on both foundations pages follow global theme toggles in real time. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Espresso 2.0's Figma dark-mode page applies elevation/light/* shadows
universally — never the elevation/dark/* set. Match that: emit
--elevation-{sm..2xl} from :root only, so shadow-* resolves to the same
value in both themes. The Figma dark set is still exposed as
--dark-elevation-* / shadow-dark-* for opt-in heavier shadows.
Pill: raised active state now uses bg-surface-gray-2-contrast shadow-base
+ text-ink-gray-8, matching the Figma dark-mode active pill (lighter
surface over container, subtle light shadow with inner highlight, less
glaring label).
TabButtons: clip the container so the active pill's shadow doesn't
overflow the rounded corners.
Docs: elevation page copy reflects the single-shadow-set model;
ElevationPreview switcher uses TabButtons and syncs with the global
theme toggle (same pattern as Palette/Semantic pages).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pass defaultColor: false to Shiki's codeToHtml so both themes are emitted as CSS variables (--shiki-light / --shiki-dark) instead of inline color on the light theme. The [data-theme="dark"] .shiki span rule in docs/css/style.css can then flip tokens at runtime — previously the light theme's inline color won by specificity and snippets stayed light even in dark mode. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Radius: collapse the numeric and named-alias sections into one divided list (one row per scale step). Each row shows the rounded-N class + --radius-N CSS variable, with aliases like `rounded`, `rounded-sm` rendered as inline chips on the numeric row they map to. Swatches enlarged so adjacent steps (e.g. 2 → 3 = 5px → 6px) are distinguishable. Plumb --radius-* CSS variables through tailwind/plugin.js so the docs aren't lying: borderRadius now resolves via var(--radius-N), with `DEFAULT` reusing the numeric var that shares its value. Values unchanged. Typography: display line-height as a unitless ratio (lh / size) instead of the raw px value from Figma — closer to how designers reason about leading.
…values PR #720 on main extracted borderRadius/boxShadow/fontSize into tokens.js as a public sub-path export. Our branch already replaced those values with Figma-generated tokens in plugin.js. After the rebase, tokens.js still exported the legacy hardcoded values, drifting from what the plugin actually emits. Source from ./generated/* so external consumers match the plugin output. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Extend the ComponentPlayground pattern (Button/Badge/Pill/TabButtons) to the remaining atoms: Alert, Avatar, Breadcrumbs, Checkbox, Combobox, Dialog, Divider, Dropdown, ErrorMessage, FormControl, MultiSelect, Password, Progress, Rating, Select, Slider, Switch, Tabs, TextInput, Textarea, Tooltip. Each gets a Builder component registered in the vitepress theme and a Playground section in its docs page. Widen knob labels so longer prop names don't wrap. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend the masking pseudo 3px past the rail line (instead of 1px) and darken the tab border one step so the active tab reads as a raised shape continuing into the panel, not a closed bottom corner. No drop shadow — it would repaint below the rail and re-close the edge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Also refresh auto-generated components.d.ts (picks up KeyboardShortcutsModal, drops removed TabButtons.story). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the token JSONs with the final design export: - Full 1-10 ramps for every color family in surface/ink/outline (the renumbered scheme from the v2 migration mapping) - New semantic tokens: base, sidebar, elevation-1/2/3, alert-button-* - Final primitive value pass (light blue/green/amber/violet refinements, dark ramps overhauled, radius-9 999px) - red-alpha ramps dropped (surface-alpha/outline-alpha red removed) - Primitives file renamed without the 🔵 prefix to match the export Generator updates that rode along in the working tree: emit neutral.transparent, pin menu-bar/gray-2-contrast/gray-modals as legacy entries, auto-copy colors.json out of generated/, and check in the token drift audit tool (audit-token-drift.cjs). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mechanical rename of all old semantic token names to their espresso v2 equivalents via the new codemod (tailwind/migrate-tokens-v2.js), applied to src/, docs/, frappe/, skills/, icons/, spec/, v1-release/ and tailwind/plugin.js — 372 replacements. Highlights of the mapping (see the codemod for the full table): - surface: white→base, menu-bar→sidebar, card(s)→elevation-1, modal→elevation-2, selected→elevation-3, gray-2-contrast→elevation-3, gray-5/6/7→8/9/10, accent 5/6/7→7/8/9 - ink: white→base, accent 2/3/4→5/6/8 - outline: white→base, gray-5→gray-7, gray-modal(s)→elevation-2, accent 2/3/4→3/4/5 The codemod is single-pass (chained renames like outline red-2→3→4→5 must not cascade) and ships in the package so consuming apps can run: node node_modules/frappe-ui/tailwind/migrate-tokens-v2.js src BREAKING CHANGE: old espresso token names are retired; run the codemod on app code when upgrading. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the LEGACY_ENTRIES/ALIASES machinery from the generator. Every pinned name is either retired by the v2 migration (surface-white, surface-modal, surface-menu-bar, surface-cards, surface-selected, surface-gray-2-contrast, ink-white, outline-gray-modals) or now defined natively by the Figma export's full 1-10 ramps (surface-cyan-1, ink-gray-9, outline-orange-1, ...). Retired names no longer produce CSS variables or utility classes, so any straggler usage fails visibly instead of silently keeping old styles. BREAKING CHANGE: var(--surface-white) and friends are gone; run tailwind/migrate-tokens-v2.js on app code. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Progress built the expected token class via string interpolation
(bg-surface-gray-${7|2}) so the v2 token codemod couldn't rewrite it;
update to the migrated gray-10. Select still asserted the old
focus-visible:ring-2 class from before the focus-ring refactor.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…utline
The default keyboard focus indicator now comes from one base-layer rule:
:focus-visible { outline: var(--focus-outline-default); outline-offset: 0 }
backed by new --focus-outline-* vars (2px light / 3px dark, theme-flipped)
derived from the same Figma focus tokens as the --focus-* shadows.
focus-ring utilities switch from box-shadow to outline, which removes a
whole conflict class: box-shadow rings fought shadow-*/focus:shadow-sm on
the same element (TextInput had this), outlines cannot. Outlines also
follow border-radius and survive forced-colors mode.
Components drop their per-element 'outline-none focus-visible:focus-ring'
boilerplate (Button, Breadcrumbs, Checkbox, Rating, Select, Switch,
Textarea, TextInput, Toast, selection triggers) — the global rule covers
them. Kept: themed overrides (focus-ring-red/green/blue on Button),
state rings (data-[state=open]:focus-ring), wrapper focus-within rings,
and deliberate suppressions (Dialog panel, ghost inputs, menu panels).
BREAKING CHANGE: outline-none on a focusable element now suppresses the
design-system focus ring, not just the UA one. ADR-0005 amended.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Post-rebase pass: code that landed on main since the branch point still used old token names. Ran the codemod on the 275 main-only files (21 changed — mostly src/molecules/editor/) and a provenance-guarded line-level pass on the 36 files both sides touched (1 line). Also drop the xl/2xl size knobs from ButtonBuilder — main's Button rewrite removed those sizes (xs/sm/md/lg now). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Make text.styles.tokens.json the source of truth for the type scale and
add weight-aware text styles.
- Add 15px (lg) and 17px (2xl) text stops; the scale shifts up two names
from the old lg (text-lg=16px → text-xl, etc.), in both text and
paragraph groups.
- Derive the scale from text.styles.tokens.json — exact per-size
size/line-height/letter-spacing, plus tiny's uppercase — instead of the
variable export (Typography.Desktop), which rounds line-heights and
drops per-size tracking. Weights stay name-mapped via FONT_WEIGHT_MAP
(regular 420, medium 500, semibold 600, bold 700, black 800) because the
Figma exporter corrupts the weight column (Regular's wght-420 override on
the Thin instance exports as 100/400; Black exports as 700 not 800).
- Correct text.styles in place to match Figma: every regular→420, every
black→800, and the paragraph/5xl 0.5px→0.5% unit typo. Build output is
unchanged by this (weights are name-mapped), but the file is now truthful.
- Add text-{size}-{weight} and text-p-{size}-{weight} component classes
carrying each weight's letter-spacing (values honored as-is from
text.styles). Drop the hand-maintained FONT_SIZE_AUGMENT /
PARAGRAPH_LINE_HEIGHT / FONT_SIZE_MEDIUM_TRACKING maps in plugin.js and
the stale parallel copy in tokens.js.
- migrate-tokens-v2.js: add the text-size renames, merge co-located
text-{size} + font-{weight} into text-{size}-{weight} (static class
attrs only, non-adjacent and color-safe), and refuse to run on an
already-migrated repo (--force / --dry-run to override).
- Apply to frappe-ui's own components: the size shift and 72 weight-class
merges across the library.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Rename colours/ route to colors/ - Add a standalone Focus Ring page; fix colored focus-ring variants (literal class strings so the JIT emits them) and demo with real tabbable components - Typography: page-wide weight switcher driving real text-<size>-<weight> token classes (safelisted), paragraph variants, even vertical rhythm - Square color swatches; fix invisible white-overlay; same-size neutrals - Ground elevation surface pairings in actual component usage and use surface-elevation-* tokens; flush, theme-driven preview - In-page Light/Dark switchers now drive the global theme - Consistent prose-v3 descriptions; trim verbose copy and em-dashes Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Post-rebase pass for main's beta.4 changes (editor starter-kit rewrite
+ FrappeUI plugin). Ran the codemod on the 52 main-only files (4 changed)
and the 3 conflict-resolved editor files taken from main's version
(MediaToolbar, ImageGroupGridCell, ImageGroupNodeView): ink-white→base,
surface-gray-7→10, and text-{xs,sm} font-medium merged to the combined
style utilities — 18 renames + 2 weight merges across 7 files.
Skipped IframeNodeView's `text-xl` (L206): the auto-merge kept this
branch's already-migrated value (main's text-lg → v2 text-xl), so the
codemod's text-xl→text-3xl would double-shift it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bb07878 to
bc9114c
Compare
Each tab used `<component :is="tabElement(button)">` where `tabElement`
returned the bare string 'button'/'a'. At runtime Vue's
`resolveDynamicComponent` runs the name through the asset resolver, which
capitalizes it and matches a globally registered component — so in apps
that do `app.component('Button', ...)` (e.g. Gameplan) every tab rendered
as the frappe-ui Button component (nested truncate wrapper + Button
classes) instead of a native <button>, breaking the tab styling.
Render native tags through tiny functional-component wrappers so `:is` is
always bound to a component value, bypassing the resolver. `inheritAttrs`
is false so the merged Reka/data/class/@click attrs apply exactly once.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DialogContent is nested inside the scrollable DialogOverlay, and the overlay carries a pointerdown handler bound with Vue's `.prevent` modifier. A pointerdown on a dialog input bubbles up to the overlay and is preventDefault'd, which suppresses the compatibility mousedown — and mousedown's default action is what focuses the input. Result: text fields could not be focused/clicked with the mouse (keyboard and click-based buttons still worked). Stop content pointerdowns from reaching the overlay's prevent handler. Outside-click dismissal is unaffected: Reka detects it in the capture phase, which a bubble-phase `.stop` cannot intercept. This is a workaround; the stray overlay pointerdown.prevent should be removed at its source. Refs #766. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EditorContent mounts the editor directly onto its own root div, so that element's `class` attribute has two writers: ProseMirror (adds `ProseMirror`/ `tiptap`/`ProseMirror-focused`) and Vue's `:class` binding. Vue's binding is a wholesale replace, so any re-render dropped ProseMirror's classes until the next state update re-added them. With `ProseMirror` gone, every `.ProseMirror`-scoped content style silently no-ops — most visibly, table cells lose their borders in editable mode (read-only never re-renders, so it was unaffected). Manage only our own tokens via `classList.add/remove` instead of `:class`, mirroring how prosemirror-view's `patchAttributes` surgically maintains its own tokens. Both owners now coexist on the shared attribute. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The contextual table toolbar is teleported to body with fixed positioning and anchored to the table's top. Following the table on scroll floated it out of the editor's scroll container and over the page header. Hide it on scroll instead; it reappears the next time the caret lands in a table. Resize still repositions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…toggled editors Stock @tiptap gates columnResizing behind `resizable && editor.isEditable`, evaluated once at editor creation. That plugin also installs the TableView `.tableWrapper` scroll container, so read-only editors (and editors toggled into edit mode via setEditable, which never reconfigures plugins) got a bare table that overflows its bounds, no table-only scroll, and no column resize handles after reopening saved content. Install columnResizing whenever `resizable` is set, dropping the isEditable gate. prosemirror-tables already no-ops its own pointer handlers when `!view.editable`, so handles only show/drag when editable and setEditable flips view.editable live. Add `.tableWrapper { max-width: 100%; overflow-x: auto }` so a too-wide table scrolls within its own bounds. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… table A wide table scrolls inside its `.tableWrapper` (overflow-x: auto), so the table's own horizontal center can be scrolled out of view and the toolbar — anchored with floating-ui `placement: 'top'` on the <table> — floated over the clipped region. Anchor instead to the horizontal intersection of the table and the wrapper viewport: it collapses to the table for a narrow, fully-visible table and to the visible window for a wide, scrolled one, keeping the toolbar centered over what the user can see. Vertical anchor stays at the table top. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The default upload function created public File records (is_private=0), served from the unauthenticated /files/ path, leaking editor images and attachments to anyone with the URL. Default uploads to private; callers can still override via uploadArgs (e.g. private: false) for intentionally public files. Ref: frappe/security#206 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump @tiptap/* to ^3.26.0 and the prosemirror-* resolutions. Add a jsdom elementFromPoint polyfill since prosemirror-view ≥1.41 calls it during cursor handling. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Keyboard: arrows exit the table at top/bottom edge, Tab on the last cell appends a row, Mod+A escalates cell → table → doc. - Drag-select auto-scrolls past the wrapper edge; pointer capture ends drags released off-window. - Touch: long-press opens the table context menu. - Insert via a size-picker grid (toolbar button and /table slash command). - Context menu gets keyboard focus, checked toggle state, and merge/split labels; floating toolbar follows the table on scroll and pins in view. - Selection overlay re-measures on resize; IME and paste land in the anchor cell. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
What this does
Adopts the final espresso v2 design tokens from Figma and migrates the whole codebase onto the new token names.
The v2 palette renumbers and renames the semantic tokens — e.g. every colour family now has a full
1..10ramp, and names likesurface-white/surface-modal/ink-whiteare replaced bysurface-base/surface-elevation-2/ink-base.Changes
yarn sync-tokens. Full 1–10 colour ramps, plus new semantic names:base,sidebar,elevation-1/2/3.tailwind/migrate-tokens-v2.jsrenames every old token to its v2 name (utility classes and CSS vars), shifts typography utilities to the new scale, and merges statictext-{size} font-*pairs into named text-style utilities. Run once on the whole repo. Downstream apps can run the same script to upgrade.:focus-visibleoutline rule applied globally, instead of per-component classes. Retheme withfocus-visible:focus-ring-red, suppress withfocus-visible:outline-none./docs/foundations/*pages (Colours — Base/Semantic, Typography, Corner Radius, Drop Shadow) read directly from the generated tokens, plus interactive playgrounds added to 21 component pages.Follow-up fixes
surface-alpha-*andoutline-alpha-*semantic tokens that were missing from the Tailwind output.surface-elevation-*tokens.EditorContent, kept table resizing/scroll wrappers in read-only and toggled editors, hid the table toolbar on scroll, centered it over the visible table area, and added drag-scroll, selection overlay, table-size picker, and context-menu polish.Progresspackage export, fixed stale Progress/Select Cypress assertions, restored Shiki colors in docs dev, and synced playground code snippets with dark mode.Upgrading an app
Run it once — re-running double-shifts chained renames.
Test plan
yarn buildpassesyarn testpasses (167/167) andyarn test:cypresspasses (42 specs)/docs/foundations/colours/semantic— surface/ink/outline render, light/dark toggle worksFull token mapping (old → v2)
surfacesurface-whitesurface-basesurface-menu-barsurface-sidebarsurface-cardsurface-elevation-1surface-cardssurface-elevation-1surface-modalsurface-elevation-2surface-selectedsurface-elevation-3surface-gray-2-contrastsurface-elevation-3surface-gray-5surface-gray-8surface-gray-6surface-gray-9surface-gray-7surface-gray-10surface-red-5surface-red-7surface-red-6surface-red-8surface-red-7surface-red-9surface-blue-5surface-blue-7surface-blue-6surface-blue-8surface-blue-7surface-blue-9surface-green-5surface-green-7surface-green-6surface-green-8surface-green-7surface-green-9surface-amber-5surface-amber-7surface-amber-6surface-amber-8surface-amber-7surface-amber-9surface-violet-5surface-violet-7surface-violet-6surface-violet-8surface-violet-7surface-violet-9inkink-whiteink-baseink-red-2ink-red-5ink-red-3ink-red-6ink-red-4ink-red-8ink-blue-2ink-blue-5ink-blue-3ink-blue-6ink-blue-4ink-blue-8ink-green-2ink-green-5ink-green-3ink-green-6ink-green-4ink-green-8ink-amber-2ink-amber-5ink-amber-3ink-amber-6ink-amber-4ink-amber-8ink-violet-2ink-violet-5ink-violet-3ink-violet-6ink-violet-4ink-violet-8outlineoutline-whiteoutline-baseoutline-gray-modaloutline-elevation-2outline-gray-modalsoutline-elevation-2outline-gray-5outline-gray-7outline-red-2outline-red-3outline-red-3outline-red-4outline-red-4outline-red-5outline-blue-2outline-blue-3outline-blue-3outline-blue-4outline-blue-4outline-blue-5outline-green-2outline-green-3outline-green-3outline-green-4outline-green-4outline-green-5outline-amber-2outline-amber-3outline-amber-3outline-amber-4outline-amber-4outline-amber-5outline-violet-2outline-violet-3outline-violet-3outline-violet-4outline-violet-4outline-violet-5textThe espresso text scale adds 15px (
lg) and 17px (2xl) stops, so oldlgand larger utility names shift upward to preserve the rendered size. The same mapping applies totext-*,text-p-*, andtext-*-medium.text-lg/text-p-lg/text-lg-mediumtext-xl/text-p-xl/text-xl-mediumtext-xl/text-p-xl/text-xl-mediumtext-3xl/text-p-3xl/text-3xl-mediumtext-2xl/text-p-2xl/text-2xl-mediumtext-4xl/text-p-4xl/text-4xl-mediumtext-3xl/text-p-3xl/text-3xl-mediumtext-5xl/text-p-5xl/text-5xl-mediumtext-4xl/text-p-4xl/text-4xl-mediumtext-6xl/text-p-6xl/text-6xl-mediumtext-5xl/text-p-5xl/text-5xl-mediumtext-7xl/text-p-7xl/text-7xl-mediumtext-6xl/text-p-6xl/text-6xl-mediumtext-8xl/text-p-8xl/text-8xl-mediumtext-7xl/text-p-7xl/text-7xl-mediumtext-9xl/text-p-9xl/text-9xl-mediumtext-8xl/text-p-8xl/text-8xl-mediumtext-10xl/text-p-10xl/text-10xl-mediumtext-9xl/text-p-9xl/text-9xl-mediumtext-11xl/text-p-11xl/text-11xl-mediumtext-10xl/text-p-10xl/text-10xl-mediumtext-12xl/text-p-12xl/text-12xl-mediumtext-11xl/text-p-11xl/text-11xl-mediumtext-13xl/text-p-13xl/text-13xl-mediumtext-12xl/text-p-12xl/text-12xl-mediumtext-14xl/text-p-14xl/text-14xl-mediumtext-13xl/text-p-13xl/text-13xl-mediumtext-15xl/text-p-15xl/text-15xl-mediumtext-14xl/text-p-14xl/text-14xl-mediumtext-16xl/text-p-16xl/text-16xl-mediumtext-15xl/text-p-15xl/text-15xl-mediumtext-17xl/text-p-17xl/text-17xl-mediumStatic class lists also merge one text size with one font weight after the size shift:
text-{size} font-normaltext-{size}text-{size} font-mediumtext-{size}-mediumtext-{size} font-semiboldtext-{size}-semiboldtext-{size} font-boldtext-{size}-boldtext-{size} font-extraboldtext-{size}-blackExample:
text-lg font-mediumbecomestext-xl-medium.surface-alphasurface-alpha-whitesurface-alpha-basesurface-alpha-menu-barsurface-alpha-sidebarsurface-alpha-cardsurface-alpha-elevation-1surface-alpha-cardssurface-alpha-elevation-1surface-alpha-modalsurface-alpha-elevation-2surface-alpha-selectedsurface-alpha-elevation-3surface-alpha-gray-5surface-alpha-gray-8surface-alpha-gray-6surface-alpha-gray-9surface-alpha-gray-7surface-alpha-gray-10surface-alpha-red-1surface-alpha-red-2surface-alpha-red-3surface-alpha-red-4surface-alpha-red-5surface-alpha-red-6surface-alpha-red-7outline-alphaoutline-alpha-whiteoutline-alpha-baseoutline-alpha-gray-modaloutline-alpha-elevation-2outline-alpha-gray-modalsoutline-alpha-elevation-2outline-alpha-gray-5outline-alpha-gray-7outline-alpha-red-2outline-alpha-red-3outline-alpha-red-4Docs preview: https://ui.frappe.io/pr-preview/pr-727/
Coverage: 56.48% (-0.41% vs
main)