Fix: Align View, ViewBuilder, ViewModifier, and ModifiedContent with SwiftUI - #67
Merged
Conversation
- Add buildBlock() -> EmptyView for empty builder blocks - Reshape TupleView to SwiftUI's tuple-generic TupleView<T> with a public value property; the builder captures children on a fast path and the public initializer resolves them by reflection - Give TupleView an unconditional best-effort Equatable so .equatable() keeps working on multi-child containers (Swift 6.0 cannot constrain tuple elements); non-comparable children safely degrade to cache misses - Rename ConditionalView to SwiftUI's _ConditionalContent spelling and rename buildOptional to buildIf - Erase limited-availability content to AnyView and add AnyView's labeled init(erasing:) - Drop the optional-expression overload SwiftUI does not expose
- Replace the buffer-level public ViewModifier protocol with SwiftUI's body(content:) contract, including the _ViewModifier_Content placeholder that resolves to the wrapped view at its body position - Add the public ModifiedContent value type (unconstrained pair, conditional View and Equatable conformances) and return it from View.modifier(_:) - Move procedural buffer transformations behind the package-internal BufferViewModifier layer with BufferModifiedView; PaddingModifier and BackgroundModifier become internal and .padding()/.background() route through the internal wrapper - Cover the new contract with rendering, environment-propagation, nesting, and value-semantics tests plus a padding regression test
- Add _ViewModifier_Content to the type_name exclusion list
- Add @preconcurrency to the View and ViewModifier protocols per the pinned SwiftUI reference surface - Document why ViewBuilder stays @mainactor as a compiler-floor exception: Swift 6.0 infers main-actor isolation onto conforming types' initializers, which the builder must call - Extend the issue-17 compile fixture with custom views, conditional and availability builder forms, generic content, a custom modifier, and nested modified content
- Rewrite the modifier sections in CustomViews, Architecture, and RenderCycle for body(content:), ModifiedContent, and the internal buffer layer - Replace links to removed or underscored symbols (ModifiedView, modify(buffer:context:), _ConditionalContent) that DocC can no longer resolve
- Drop overrides for removed symbols: the buffer-level ViewModifier requirements, ModifiedView, ConditionalView, the pack-generic TupleView members, buildOptional, and the internalized padding and background modifiers - Add overrides for the new surface: ModifiedContent, the body(content:) contract, tuple-typed TupleView members, buildIf, buildBlock(), AnyView(erasing:), and the AnyView-erasing buildLimitedAvailability - Regenerate the manifest with TUIkitAPICheck against fresh 6.0.3 macOS and Linux snapshots
wadetregaskis
added a commit
to wadetregaskis/TUIkit
that referenced
this pull request
Sep 2, 2026
The tail — storage, view contracts, data flow, scenes — judged at branch granularity, since by this point each branch's character was clear from its first commit and per-commit detail would not have changed a verdict. PR phranck#65's serialised writes are already ours (NSLock plus a serial save queue). Its error reporting is not: we drop persistence failures on the floor, so a read-only config directory looks like a successful save. Deferred — real, small, unforced. PRs phranck#67, phranck#69 and phranck#70 are deferred as a batch and explicitly NOT as upstream-review work. They are all one thing — align the framework's shape with SwiftUI's — and CLAUDE.md requires that to be answered against the real SDK, which is how SwiftUI-compatibility.md was built. Reading what upstream happened to write is the wrong instrument. Some of it is already shipped here; DynamicProperty as a public protocol is not. The next step is an audit pass over the data-flow and view-modifier surfaces with these branches as one input among several, which is a piece of work rather than triage. Also fixes the ledger's row order: recording 8a73ec3 out of sequence made `verify` report a gap, which is the check doing its job. Final spread across 205 commits: 56 n-a, 37 noise, 35 have, 35 defer, 17 adapt, 16 reject, 5 queued, 4 inspired. Co-Authored-By: Claude <[email protected]>
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.
Closes #17.
Summary
buildBlock() -> EmptyView, tuple-typedTupleView<(repeat each Content)>,buildIf(wasbuildOptional),buildEither -> _ConditionalContent(renamed fromConditionalView),buildLimitedAvailability -> AnyView, and the optional-expression overload SwiftUI does not expose is gone;buildArray/ViewArraystays as a documented additive convenienceTupleView<T>withpublic var value: T): the builder captures children on a reflection-free fast path, the public initializer resolves them via Mirror, and an unconditional best-effortEquatablekeeps.equatable()working on multi-child containers (Swift 6.0 cannot constrain tuple elements; non-comparable children safely degrade to cache misses)body(content:)with the_ViewModifier_Contentplaceholder;.modifier(_:)returns the new publicModifiedContentvalue (conditional View/Equatable conformances). Procedural buffer transformations moved behind the package-internalBufferViewModifier/BufferModifiedViewlayer;PaddingModifier/BackgroundModifierare internal now@preconcurrency @MainActoronViewandViewModifierper the pinned SwiftUI reference;ViewBuilderstays@MainActoras a documented compiler-floor exception (Swift 6.0 infers main-actor isolation onto conforming types' initializers)init(erasing:)Deviations from the issue text
ContentBuilder: the pinned SwiftUI reference snapshots (Xcode 26.6, SwiftUI + SwiftUICore, all platforms) contain no such symbol; the alias appears to be a spec artifact. Not added.Test plan
./scripts/test-linux.shViewBuilderAlignmentTests(builder surface, tuple typing, runtime equality, availability erasure),ViewModifierContentTests(contract, environment propagation, nesting, value semantics, padding regression)verify-compatibility-manifest.shpasses against the regenerated manifest