Layout widgets + theme tokens, engine perf, and a 3-layer test suite#1
Merged
Conversation
These files predate the Go 1.19+ gofmt doc-comment reformatting and were flagged by `gofmt -l`. Whitespace/comment-format only, no logic changes — so the new CI gofmt gate starts green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…d type Reduce work crossing the syscall/js boundary — the real cost in a WASM-DOM framework, where naive per-update churn makes it slower than React rather than faster. - SetState is now microtask-batched: scheduleRebuild enqueues the element and a single queueMicrotask flush drains the queue, deduping repeated SetStates on one element and coalescing across siblings into one rebuild pass. A mounted flag skips elements unmounted before the flush. DOM updates on the next microtask (before paint), no longer synchronously. - Event listeners are persistent per event NAME: syncEvents registers one js.Func per name that dispatches to the live e.host.Events[name] at fire time, so a rebuild swapping the handler closure does zero DOM work. Only added or removed names touch addEventListener/removeEventListener — eliminating the release-all/recreate-all churn on every reconcile. - fillEvent reads only the raw-event fields relevant to the event name (coords for pointer/mouse, key for keyboard, value for form/typing) instead of probing all six on every fire. - canUpdate compares a reflect.Type cached on the element instead of reflecting on the old widget each reconcile. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Let apps express richer layouts and reference theme colors by role instead of hand-writing CSS or hard-coding hex. - New layout primitives (widgets/layout_ext.go): Expanded, Flexible, Spacer, Stack+Positioned, Grid (incl. MinColumnWidth for media-query-free responsive reflow), Wrap, Align (nine presets), AspectRatio, ConstrainedBox. - Color tokens (widgets/color.go): ColorPrimary, ColorInk, ... "theme:*" sentinel strings resolved against the active theme; raw CSS colors pass through unchanged, so fields stay backward-compatible. - Container is now a theme-aware StatelessWidget (so it can read ctx.Theme): resolves Color/BorderColor tokens and gains Shadow, Overflow, Position+inset, Gap, Min/Max sizing, Opacity, Cursor, Transition, Flex/AlignSelf. - Heading/Body/Caption/Link resolve color tokens too. - Showcase: new "Layout & color tokens" section demoing all of the above. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Guard framework quality so changes can't silently break products built on Gutter. - Layer 1 (host go test): every widget's rendered *gutter.Host, color-token resolution, typography, Notifier, AssetURL, options, and the SetState-batching contract. Core 97.7% / themes 100% coverage. - Layer 2 (element_wasm_test.go via wasmbrowsertest): the reconciler against a real DOM — mount/update/unmount, attr/style diffing, keyed + positional reconcileChildren (asserting DOM node identity survives reorder), event payload, persistent-listener handler swap, batched-SetState coalescing, dispose lifecycle. - Layer 3 (e2e/): a deterministic testapp driven by Playwright — render, batched counter, controlled-input caret, keyed reorder value retention, conditional mount/unmount. - CI (.github/workflows/test.yml) runs all three on every push/PR. - TESTING.md documents the layers and the wasmbrowsertest setup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Update CLAUDE.md for the layout widgets, color tokens, theme-aware Container, persistent event dispatch + batched SetState, and the three-layer test suite. Note the Heading-renders-span accessibility gap surfaced by the e2e suite. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The wasm job's Chrome crashed in ZygoteHostImpl::Init — ubuntu-24.04 runners block unprivileged user namespaces via AppArmor, and wasmbrowsertest runs Chrome with the sandbox enabled (chromedp's defaults don't pass --no-sandbox, and it exposes no flag to add it). Re-enable unprivileged userns via sysctl. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Silence the Node 20 deprecation warnings by moving to current majors: checkout v6, setup-go v6, setup-node v6, upload-artifact v7, setup-chrome v2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <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.
Addresses two concerns — layout/CSS expressiveness and DOM-render performance — and adds a comprehensive test suite so future changes can't silently break products built on Gutter.
1. Layout & color tokens (less hand-written CSS)
widgets/layout_ext.go):Expanded,Flexible,Spacer,Stack+Positioned,Grid(incl.MinColumnWidthfor media-query-free responsive reflow),Wrap,Align(nine presets),AspectRatio,ConstrainedBox.widgets/color.go):ColorPrimary,ColorInk, …"theme:*"sentinels resolved against the active theme. Raw CSS colors pass through unchanged → fully backward-compatible.Containeris now theme-aware (StatelessWidget, so it can readctx.Theme): resolvesColor/BorderColortokens and gainsShadow,Overflow,Position+inset,Gap, min/max sizing,Opacity,Cursor,Transition,Flex/AlignSelf.Heading/Body/Caption/Linkresolve tokens too.2. Engine performance (minimize JS-boundary crossings)
SetState:queueMicrotaskflush coalesces repeated/sibling SetStates into one rebuild pass; amountedguard skips unmounted elements. DOM now updates on the next microtask (before paint), not synchronously.js.Funcper event name dispatches to the live handler, so a rebuild that swaps the closure does zero DOM work. Replaces the release-all/recreate-all churn on every reconcile.canUpdate.3. Three-layer test suite + CI
go test ./...): every widget's rendered*gutter.Host, token resolution, typography,Notifier,AssetURL, options, SetState-batching contract. Core 97.7% / themes 100% coverage.element_wasm_test.goviawasmbrowsertest): the reconciler against a real DOM — mount/update/unmount, attr/style diffing, keyed reorder preserving node identity, event payload, persistent-listener handler swap, batched-SetState coalescing, dispose.e2e/): a deterministic testapp driven by Playwright — render, batched counter, controlled-input caret, keyed reorder value retention, conditional mount/unmount..github/workflows/test.yml) runs all three on every push/PR. Setup documented inTESTING.md.Behavioral note
SetStateis no longer synchronous — the DOM updates on the next microtask (before paint). Verified safe for controlled inputs (caret preserved), 60Hz animations, and drag-drop. Documented in CLAUDE.md.Heads-up surfaced by the e2e suite
Heading/typography widgets render a styled<span>, not semantic<h1>–<h6>(no ARIA roles). Noted in CLAUDE.md known limitations; not changed here.🤖 Generated with Claude Code