Skip to content

[WIP][prototype] density system#48749

Draft
siriwatknp wants to merge 187 commits into
mui:masterfrom
siriwatknp:exp/density-button-prototype
Draft

[WIP][prototype] density system#48749
siriwatknp wants to merge 187 commits into
mui:masterfrom
siriwatknp:exp/density-button-prototype

Conversation

@siriwatknp

@siriwatknp siriwatknp commented Jul 1, 2026

Copy link
Copy Markdown
Member

Playground: https://deploy-preview-48749--material-ui.netlify.app/experiments/density-playground/

Part of #48746 (density RFC). Prototype / experiment — draft, not for merge. The combined, end-to-end preview of the proposed density feature — 10 component families verified and surfaced in the playground so far, more staged in the presets.

What this demonstrates

A holistic, opt-in density layer for @mui/material built entirely on emitted theme styleOverrides — no new density prop, no component-source changes, zero cost when unused.

  • Three public presets — enhanceCompactDensity / enhanceNormalDensity / enhanceComfortDensity (packages/mui-material/src/styles/). Each ships a --mui-density-* step scale on the theme's own CSS-variables channel (materialized by ThemeProvider at the theme's rootSelector — no CssBaseline requirement) and emits every covered component's density values as styleOverrides against the selectors the component already ships (size/dense variants, slots). Mirrors enhanceHighContrast; createTheme stays untouched.
  • Zero component-source changes. The per-component mapping is authored inline in the presets. Calc-coupled geometry (outlined/filled/standard input label bridge, Tooltip arrow, Chip height) is handled by private --_* vars emitted inside the overrides — coupled sub-elements derive from one value via calc, so alignment holds at any density; decided per component.
  • Slot-aware emission — overrides land on root by default, on the portal slot where the styled element renders through a portal (Autocomplete listbox, Tooltip tooltip).
  • Cross-package: MUI X Data Grid — row/header heights are JS-gated (the virtualizer computes row positions from the rowHeight prop), so the presets attach theme defaultProps: rowHeight 28/40/60 with columnHeaderHeight on the same bases (app defaults win); the grid's own density prop stays unset — its fixed ×0.7/×1.3 stops can't express a 1.5× comfort ratio, and the toolbar density selector stays a relative multiplier on top. Insets, toolbar/footer, filter/columns panels, column menu, quick filter (expanded-state via a variants matcher), overlays, and Pro/Premium chrome (header filters, grouping indent, pivot/AI/charts panels, sidebar) ride emitted styleOverrides; grid chrome built from Material components reflows via the Material emissions for free.
  • Cross-package: MUI X Tree View + Date/Time Pickers — Tree View: item indentation via defaultProps.itemChildrenIndentation carrying a density-var string (the component sets the indentation var as an inline style on the tree root, so styleOverrides can't reach it; 'var(--mui-density-md)' passes through verbatim — a second flavor of the JS-gated exception where the prop value stays CSS), row height through the component's own --TreeView-itemHeight hook (unset upstream → the no-preset state stays pixel-identical), content paddings/gap via steps with the depth-indent calc re-emitted on a step base. Pickers: one private --_daySize var on the day-calendar root re-points --PickerDay-size and drives the weekday/week-number boxes plus both 6-week container minHeight calcs (master values are JS constants baked in at build time); calendar root box, year/month buttons, and clock-section widths as raw per-preset px; header/toolbar/clock-item spacing via steps (toolbar scoped to portrait; clock-item margins frozen where scroll-positioning JS reuses them). Both families' Material-built internals (checkboxes, MenuItem clock items, text fields, action bars) reflow via the Material emissions for free.
  • Coverage — 32 Material families verified & surfaced in the playground: Button (incl. IconButton), ButtonGroup, Menu (MenuItem, List), Tooltip, TextField (Outlined/Filled/standard Input, InputBase, InputLabel, InputAdornment), Select, Autocomplete, Tabs, Accordion, Checkbox, Radio, Switch (calc-coupled thumb/track), SvgIcon, Chip, Alert, Card, Avatar, Badge, ToggleButton, Breadcrumbs, Stepper, LinearProgress, Table (TableCell, TableSortLabel, TablePagination), Slider, Divider, Toolbar (responsive regular/dense heights), Dialog (title/content/actions + paper margin with viewport-calc coupling), Fab, Pagination, ListItemButton, SnackbarContent, BottomNavigation. Cross-package: Data Grid (MUI X) with community + Pro/Premium demos (grouping, header filters, pivot sidebar, panels rendered inline), Tree View (pre-expanded nesting + checkbox selection), and Date/Time Pickers (day/year/month calendars incl. week numbers and loading state, digital clocks, static date-time with toolbar). Remaining candidates (no emissions yet): Rating, the List content family, form wrappers, AvatarGroup, ToggleButtonGroup, SpeedDial, MobileStepper — plus prop-driven sizing (CircularProgress size, ImageList gap) now expressible via the defaultProps channel.
  • Playground /experiments/density-playground — flip unset/compact/normal/comfort; per-family demo matrices; every emitted value inspectable and overridable live (density-step keys or raw CSS); scale-step, typography, and spacing knobs; visual-debug overlays (bounding box, text box, outline, measure); export or copy a self-contained density.ts to try the feature in any sandbox without upgrading @mui/material.
  • Codegen + parity guardpnpm density:codegen snapshots the three presets into a generated emission table; density.test.ts diffs table ↔ preset readback so the playground and the presets can't drift.
  • Local regression harnessscripts/density-screenshots/ (pnpm density:shot) asserts the unconfigured default render is pixel-identical to a master baseline at maxDiffPixels: 0, plus compact/comfort reflow captures.

Verification

  • Zero-diff gate: unconfigured render pixel-identical to master (maxDiffPixels: 0); no preset → no --mui-density-* vars emitted.
  • Computed-style: compact/normal/comfort reflow every (variant, size) cell; element-level sx wins over the preset styleOverrides.
  • @mui/material + docs typecheck, eslint, and the density parity tests all green.

Scope

  • Production density scale values are settled internally (out of RFC scope) — the values here are the working proposal.
  • pkg.pr.new install link and upstream Argos run are follow-ups tracked on the RFC.

🤖 Generated with Claude Code

siriwatknp added 30 commits June 5, 2026 12:41
Expose Button padding as overridable CSS vars resolved inline from a
(variant,size) lookup; add enhanceDensity to wire tokens to a --mui-density-*
scale. Literal-px fallbacks keep the default pixel-identical. Design in
CONTEXT.md + docs/adr/0001; demo at /experiments/density-tokens.
… + --Button-pad seam

- Root consumes var(--Button-pad, var(--_pad)); --_pad universal default on root
- (variant,size) literals + built-in-size routing live in variants (deduped CSS)
- Inline bridge only for custom sizes (keeps custom sizes tunable, zero inline for built-ins)
- Two-var rationale + accepted trade-offs documented in ADR-0001 + CONTEXT
- enhanceDensity maps sized tokens (--Button-<size>-pad) to density scale
…seam

- OutlinedInput: block-only density (--OutlinedInput-<size>-padBlock); root routes, input inherits; drop redundant size/multiline variants
- InputLabel: generic --InputLabel-y seam; OutlinedInput bridges sibling label via :has(~ &)
- Docs: ADR-0001 OutlinedInput + label :has bridge, CONTEXT, density-adapter-rollout guide, experiment demo
- density-fixture.tsx: per-component matrix scoped by ?c=&level (default pixel-identical)
- scripts/density-screenshots: config + spec + README (maxDiffPixels 0)
- density:shot / density:shot:update scripts; gitignore harness outputs
- Tokenize the 14px inline gutter as --OutlinedInput-padInline (size-invariant base token)
- Uniform consume shape var(--seam, var(--_internal)) across both axes: block sized (routed), inline base; --_padInline internal default
- Docs: base-token shape in ADR/CONTEXT; rollout gotchas — split-only-if-forced, uniform consume shape, inline gutter != adornment gap
Revert the lift of block padding to the root + inheritance; tokenize each
literal where master has it (input owns inline/non-multiline, root owns
multiline/adornment gutters) for the smallest diff.

Promote padInline from a base token to a sized axis: default 14px both sizes,
but expose --OutlinedInput-<size>-padInline so a design system can tune inline
density per size. Both axes now routed per size in place; label :has derives
--InputLabel-y straight from the public sized token.

Docs: base token reserved for axes where per-size override is meaningless; a
size-invariant default alone no longer justifies it.
Apply the density adapter (docs/adr/0001) to the @mui/material components used
by the dashboard template: Chip, IconButton, MenuItem, ListItem, ListItemButton,
ListItemIcon, ListItemText, ListSubheader, Toolbar, Tab, Tabs, TablePagination,
CardContent, Select, Breadcrumbs, InputAdornment, Badge. Each exposes its real
spacing axes as public sized tokens over literal-px internal defaults; the
default render stays pixel-identical to master (density screenshot harness,
maxDiffPixels:0). Checkbox/FormControl skipped - no density axis.

enhanceDensity wires every component's sized tokens (incl. OutlinedInput) to the
density scale. The verification fixture gains a matrix + dense/loose scope per
component.

Boolean `dense` components (MenuItem, ListItem, ListItemButton, ListItemText)
expose the default state via the plain seam --Component-<key> and only the dense
override as --Component-dense-<key>. Toolbar keeps theme.mixins.toolbar for its
regular height (only dense + gutters tokenized).
Boolean compactness toggles (dense) use a state token: default state is the
plain seam --Component-<key> (base-token-shaped, no base routing), only the on
state is qualified --Component-dense-<key>. No --Component-normal/regular/default-
qualifier - a boolean has no name for off. Added to CONTEXT language, ADR 0001
resolution, and the rollout recipe + naming.
SwitchBase (shared agnostic base) consumes one seam: padding var(--SwitchBase-pad,
var(--_pad)), --_pad 9px. Checkbox/Radio (styled(SwitchBase)) route per-size
public tokens --Checkbox/Radio-<size>-pad into the seam; default 9px both sizes
(pixel-identical). Switch routes its thumb (SwitchBase) padding via --Switch-<size>-pad
(9/4); box geometry stays literal (size-coupled). enhanceDensity + fixture wired.
SwitchBase owns the agnostic seam consumed once; Checkbox/Radio/Switch route
per-component sized tokens into it. Covers the two reader topologies (consumer is
the base vs wraps it as a descendant), delivery via custom-property inheritance
(no descendant selector), and the --_<key>-shadowing caveat. Added to CONTEXT
relationships, ADR 0001 specifics, rollout Recipe C + Done list.
Tokenize Switch's four real dims per size (--Switch-<size>-width/height/thumbSize/
touchSize). Derive SwitchBase pad = (touchSize-thumbSize)/2, button top =
(height-touchSize)/2, checked travel = width-touchSize, thumb size = thumbSize, so
the thumb stays centered on the track (absolute + transform). Replaces the
pad-only token that drifted the thumb. Switch dropped from enhanceDensity (geometry
isn't spacing-scale-derived). Default pixel-identical.
…lues

Switch tokenizes width/height/thumbSize/touchSize per size and derives pad/top/
travel via calc (thumb stays centered); not the pad-only approach. Corrects the
shared-base sections in ADR 0001 + rollout Recipe C.
The root padding (12/7, track inset) is its own axis -> tokenize as
--Switch-<size>-pad over --_pad, consumed padding: var(--Switch-pad, var(--_pad)).
Distinct from the derived thumb SwitchBase pad. Fixture scope + docs updated.
borderRadius = (height - 2*pad)/2 (full-pill track thickness) instead of literal
14/2, so the track stays rounded when the dims are tuned. Pixel-identical (medium
7px; small clamps to a pill).
Add an xxl density step (4x spacing unit). Wire MuiSwitch: map per-size
width/height/touchSize/thumbSize/pad to scale steps (xxl for the wider track);
pad/top/travel/radius re-derive so the geometry stays valid. Docs updated.
Switch dims were mapped to single scale steps, shrinking it. Compose from steps so
defaults land on today's px (medium 58/38/20/38/12, small 40/24/16/24/7) and still
scale with density: width calc(xxl*2-6), height/touch calc(xxl+xs), thumb
calc(lg+xxs), etc. touchSize == height keeps the thumb centered.
…Tabs minHeight

- enhanceDensity: derive OutlinedInput --InputLabel-y from density step (sibling label can't read the input's padBlock token); per-size via variants
- MenuItem: consume --ListItemIcon-minWidth (was hardcoded 36) so density reaches the icon
- Tabs: add --Tabs-minHeight base seam (parent can't read child --Tab-minHeight) + wire MuiTabs
- New /experiments/density-showcase: preset switcher (compact/normal/comfort), live scale readout + per-component token accordion, masonry gallery
- Extract shared demos to densityDemos.tsx; fixture imports it
- Fixture: --Tabs-minHeight scope, center row Stacks
calc(var(--Chip-height) - inset) per size so they track density; insets reproduce today's medium/small sizes (pixel-identical default)
Signed-off-by: Siriwat K <siriwatkunaporn@gmail.com>
Prefix density tokens, tracking the css-var feature: --mui-Button-pad with
cssVariables, bare --Button-pad without. One cached getButtonVars(theme) resolver
shared by component + consumer so emitted/targeted names can't drift; as-const key
map is the typed handle. Button + OutlinedInput + InputLabel converted;
enhanceDensity blocks guarded to match. No theme.vars, no getCssVar, no forced
prefix; custom-size inline routing dropped. Default render unchanged (Argos
zero-diff). Demo: /experiments/density-var-prefix.
Rename the agnostic seam off the component name and prefix: --Button-pad ->
literal --comp-pad, --OutlinedInput-pad{Block,Inline} -> --comp-pad{Block,Inline},
--InputLabel-y -> --comp-labelY. The seam is the bare root's consumption point, not
a design knob, so it stays literal/unprefixed and out of buttonVars. buttonVars now
holds only the Material UI layer's public sized tokens (which track the prefix).
Document the per-layer naming in ADR-0003.
…e granularity

Custom (theme-added) sizes are excluded from density (no inline routing) — the
seam is only set for built-in sizes, so the generic-seam inheritance case is a
documented non-goal, and we avoid prefixing turning the free inline custom-size
string into a theme-dependent read. Record that as a concrete cost of prefixing.
…al-mode

Export enhance baked density to raw px + dropped the mechanism. Rewrite to
match enhance*Density:
- port applyDensity (theme.density + CSS-vars channel: vars.density, wrapped
  generateThemeVars/generateStyleSheets); no CssBaseline
- enhance mutates+returns like the preset (no createTheme re-run -> no
  dropped cssVars mode); overrides keep var(--mui-density-*) refs
- static themes resolve refs -> px at runtime; cssVars keep refs
- generated file imports only `type Theme`
- exportPayload: drop export-time ref resolution; scale stays bare-key px
- Spacing tab (var-backed theme.spacing, per-preset default compact=6);
  Stack/Grid/Container demos with subtle dashed tiles; Padding toggle
  greens Stack/Grid gaps; export bakes spacing (applySpacing, dual-mode)
- all canvas demo row Stacks -> spacing 10
- tooltip height-measure targets .MuiTooltip-tooltip, not trigger buttons
- how-to dialog: @mui/lab Timeline -> MUI List
- enhanceCompactDensity: MenuItem height em + typography lineHeight tune;
  regenerated emit table / labels / fields
…ug (padding+margin)

- select minHeight:auto across all 3 presets; hidden from sidebar (preset-driven, not tunable)
- InputBase surfaces under both TextField and Select; Select input slot hidden via per-family denylist
- Padding toggle renamed to Bounding box; adds a margin overlay alongside padding
- margin overlay is JS-driven (reads live getComputedStyle, not a hardcoded density var) so it
  tracks sidebar overrides and shows every non-zero side, not just one
- wired: InputAdornment, AccordionSummary, Tooltip offset, Checkbox/Radio label-pull margin
…how-to-use copy

- add icon button next to Export to copy density.ts to clipboard
- MenuItem demo: trailing keyboard-shortcut-style text (sx color text.secondary)
- update How-to-use walkthrough: measure overlay, Spacing tab, copy button
…ug overlays (message/action/icon), show family in selector
…tering margins; show family, ChipMatrix row Stack + small avatar/icon demos, margin markers
…eholder/helper roundtrip; drop token-count validation, trust input fragments
…ons), 3 composition demos (full, content-only last-child, action-area grid), child-gap + last-child labels, margin markers
…ine (was padding shorthand); group-level ToggleButton height measure; per-size demo icons; Avatar debug-text; Badge bubble measure; positioned-ring-slots exception (bounding-box kept Badge bubble anchored)
…mal = master dims); size-scoped var knobs; clamped left re-anchor; FormControlLabel in family; gutter-synced label pull via linked writes; SwitchMatrix demo
…e + endAdornment exclusion; tag + separator margin markers; option label polish
… + linked alternativeLabel connector-right; compact 9.5px vertical/alternativeLabel tuning (connector insets/top, StepContent per-layout variants, StepLabel label gap d.md); 2-row demos incl vertical alternativeLabel; ButtonGroup group measure + per-size demos; Button/SvgIcon cross-family sidebar
…el (master zeroes vertical); tokenize vertical-alternativeLabel iconContainer paddingLeft (all presets); collapse both gap rows into 'row label spacing' virtual knob
…hidden/hiddenIn/note self-declared, hiddenFieldIds derived; codegen preserves values + remaps ids); surface Progress family — LinearProgress height raw px 3/4/5, linear demos + measure slot, pinned last in selector (minor single-knob rule)
…ultProps, first-class defaultProp target field in codegen, buildOverrides/export routing with app defaults winning) + MuiDataGrid emissions: rowHeight 40/52/64 + columnHeaderHeight 44/56/68 raw px (grid density prop stays unset; selector = relative override), cell/header/edit insets + title gap + toolbar minHeight/padding/gap + footer minHeight + count gutters + actions gap as steps; playground DataGrid family (core/toolbar/forced-edit demos, debug registries, defaultProps knobs); finalize densityFields registry merge (densityExtraFields removed) + densityRender test
…l slot: upstream key collision with popup shell; menuList under menu: internal slot + body portal; columnsManagement paddings + FormControlLabel row-label gap), filter-form gap/field widths, quick-filter expanded width via variants matcher (ownerState-only state, collapsed keeps --trigger-width), overlay gap, drag/rowspan insets (nested to match upstream specificity), pro header-filter paddings/input margins, grouping indent multiplier var + toggle gutters, premium chrome sizing (sidebar/pivot/AI widths + 44/52/60 header trio + field rows + drop zones; charts mirrors pivot); inline-axis longhand refactor (paddingInline/marginInline where block side is 0); playground: DataGridPremium demos (inline filter/columns panels via basePopper.material.disablePortal, header filters, pre-expanded grouping, no-columns overlay, pivot sidebar) + debug registries + knob notes
…— pulls the row off the sidebar edge so the absolutely-pinned hover drag handle gets space (charts mirrors pivot); knob notes + export baseline
…ops (rowHeight + columnHeaderHeight follow same bases; the grid's fixed x0.7/x1.3 stops can't express the 1.5x comfort ratio — exact bases, density prop unset); tests + export baseline + demo blurbs updated
… ListItemButton, SnackbarContent, BottomNavigation) + close their seam gaps — Toolbar regular responsive minHeight via styleOverrides (mixins untouched; landscape media emitted flat, up(xs) is a no-op wrapper the readback can't resolve); Dialog paper --_dialogMargin var driving margin + all 100%-minus-margin viewport calcs (media guards stay at master boundaries, fullScreen state re-asserted) + DialogActions button gap; PaginationItem paddingInline/marginInline steps + --_height var deriving height and pill radius (h/2); SnackbarContent message paddingBlock + action paddingLeft; BottomNavigationAction width clamps + icon-only centering paddingTop (no-label zero re-asserted); demos: real inline Dialog (fullWidth), ellipsis pagination, icon-only bottom nav, extended Fab control; registries + knob meta (derived rows hidden)
… + frozen re-assert — DialogContent padding into dividers:false (master dividers 16/24 untouched, knob edits can't leak into the state), Dialog paper margin/viewport calcs all scoped fullScreen:false (drops the 4 re-assert rows), BottomNavigationAction paddingTop on the net icon-only-with-label condition (drops the no-label zero re-assert); knob meta rebuilt for the new ids
…t into view — extract slotHighlightSelector from slotHighlightSx, scroll effect on toggle-on/switch (canvas scrolls independently, a big component's slot can sit off-screen exactly while its knobs are edited)
…st one demo (16 recovered) — filter panel goes Premium with a 2-item model (community forbade multi-filtering: gated BOTH logicOperatorInput and panelFooter), core demo preselects 2 rows via rowSelectionModel (initialState.rowSelection is dead config), pivot Columns zone left empty for the placeholder, new tree-data demo (toggle + non-paginated Premium footer = rowCount), new row-spanning multiSelect demo (aria-rowspan=2 exercises the rowspan emission), toolbar gains label prop + prefilled quickFilterValues (control does not mount while collapsed; primitive auto-expands on non-empty value), empty columns panel via getTogglableColumns [] (emptyText), AI panel via preferencePanel initialState + explicit slot (ships null by default), charts panel via GridChartsRendererProxy with a null renderer (proxy ships in the grid package — x-charts-premium only paints; Fields tab flipped by one-shot effect, tab state is internal), preference panels pinned open via slotProps.panel.onClose no-op (GridPanel routes clickaway+Escape through it); SLOT_HIGHLIGHT entries for 2 slots whose utility classes upstream never emits (emotion label class only), padding/margin/measure registries for the newly visible slots incl. pre-existing pivotPanelField margin miss
…wspan multiSelect paddingTop now have live demos
… itemChildrenIndentation via defaultProps string 'var(--mui-density-md)' on Rich+SimpleTreeView (the var is INLINE STYLE on the tree root, styleOverrides can't reach it; a string prop passes verbatim so step semantics survive; knob-typed keys resolve the same way), row height rides upstream's own --TreeView-itemHeight unset-fallback hook (28/32/40), content longhand paddings + gap steps with the paddingLeft depth calc re-emitted on a step base (a shorthand would clobber it); Pickers: one --_daySize private var on the DayCalendar root (NOT DateCalendar — an ancestor copy would be shadowed by the descendant's and kill the knob) re-points PickerDay's --PickerDay-size and drives weekday/week-number boxes + both 6-week container minHeight calcs ((size+4)*6), DateCalendar root box raw per-preset trios (286x278/336x320/406x376 — day-var can't reach an ancestor), header spacing steps with min+maxHeight pinned together (Safari-jump comment upstream) and the toolbar padding scoped to pickerOrientation=portrait (landscape master 16 untouched), year/month buttons + multi-section clock root/item width trios, clock item padding steps with the 2px 4px margin frozen (JS scroll math subtracts the first item's 4px); demos: pre-expanded 3-level RichTreeView + checkbox variant, DateCalendar with week numbers, loading calendar (loadingContainer shares the calc), year+month grids, both digital clocks (DigitalClock width-boxed — items stretch unconstrained), StaticDateTimePicker for the toolbar, fixed dayjs date + weekOfYear plugin (displayWeekNumber calls value.week(), adapter doesn't install it — was an SSR 500); registries: rings/markers/measure entries, SLOT_HIGHLIGHT for the two defaultProps rows; derived var-consumer rows hidden (day var row is the knob, Chip/Dialog precedent). Verified: material+docs types, 57 tests (export snapshot regen reviewed = exactly the new emissions), codegen md5-stable x2 incl. post-prettier, eslint, prettier, browser presence audit both families (compact values live: item 28, day 30, containers 204, buttons 64x32, clock items 32) + locator pulse/scroll end-to-end
…aultProp now emits d.md instead of a hardcoded 'var(--mui-density-md)' string (dual-mode: prefix-aware var ref under cssVariables, raw px on static themes — the hardcoded form broke both; zero table diff in vars mode), DateCalendar maxHeight pinned to the height trio (the PickerViewRoot base clamps maxHeight at 336 — comfort's 406 was silently clipped, scrollHeight now equals clientHeight), missed Year/Month grid spacing knobs: rowGap (12->md / 16->lg) + block padding (6->xs / 8->sm) + 3-per-row columnGap (24->xl) with Year's paddingBlock + both columnGaps scoped to the default 3-per-row variant (the 4-per-row variant redefines padding '0 2px' / columnGap 0 — an unconditional emission would clobber it, negated-variant rule) + Year buttonFiller mirroring the button box (last-row spacer, was left at master 72x36); verified: types, 57 tests (snapshot regen = exactly the additions), codegen md5-stable x2, eslint, prettier, comfort probe 376x406 unclipped + year/month buttons 84x44
…l usage rank — X-inline positions (DataGrid 21 / TreeView 27 / DatePicker 31) replaced by a bottom MUI X group (DataGrid, DatePicker, TreeView, matching the yml's group listing); the 7 non-Weave-ranked families (Toolbar..BottomNavigation) made explicit after the ranked core instead of implicit Infinity-rank, Progress stays pinned after them
…ow — the block padding is the seam (master su(1) 0), an inline knob on the list wrapper had no master value to remap
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

RFC Request For Comments.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant