Feat: Align the data-flow wrappers with SwiftUI (DynamicProperty, Binding, Bindable, AppStorage)#69
Merged
Merged
Conversation
- Add the public DynamicProperty protocol with a default update() and conform State, Binding, Environment, and AppStorage - Hydrate user-defined dynamic properties recursively: nested framework wrappers bind depth-first with stable declaration-ordered property indices, and update() runs once per hydration before body evaluation - Cover conformances, nested-state persistence, and the update cycle with tests
- Add @dynamicMemberLookup with writable key-path child bindings - Add init(projectedValue:), optional promotion and unwrapping initializers, and the AnyHashable projection - Add conditional Identifiable, Sequence, Collection, Bidirectional-, and RandomAccessCollection conformances with writable element bindings - Mark Binding @unchecked Sendable when its value is Sendable - Cover writeback semantics for member, optional, and element bindings
- Add SwiftUI's init(initialValue:) spelling and the empty initializer for nil-expressible state values
- Drop the struct-level Codable constraint; persistence runs through family-specific read/write steps on the storage box - Add SwiftUI's typed families (Bool, Int, Double, String, URL, Data, Date, RawRepresentable with String or Int raw values) plus their optional variants, where nil assignment removes the stored value - Rename the backend parameter to SwiftUI's store label; it accepts a StorageBackend as the documented terminal adaptation of UserDefaults - Keep arbitrary Codable values as a documented additive convenience
- Add SwiftUI's Bindable property wrapper with dynamic member lookup producing writable bindings into @observable models - Provide the wrappedValue, unlabeled, and projectedValue initializer spellings plus conditional Identifiable and DynamicProperty conformances
- The synthesized internal init(wrappedValue:) violated the property-wrapper accessibility requirement; a private designated initializer now backs the public Observable-constrained spellings
- Add Bindable and custom dynamic property sections to the state management article and describe the typed AppStorage families - Extend the data-flow compile fixture with wrapper families, dynamic member bindings, and a custom dynamic property
- Binding is now Sendable for Sendable values per the SwiftUI reference, so the positive fixture asserts it and the negative fixture rejects bindings to non-Sendable values instead
- The 'is' checks tripped the warning-fatal gate ("'is' test is always
true"); generic requirement calls prove the conformances at compile
time instead
…rface - Drop the two stale overrides from the reshaped AppStorage wrapper - Add overrides for the new surface: DynamicProperty, Bindable, the Binding projection initializers and conditional conformances, the State initializers, and the typed AppStorage families - Regenerate the manifest with TUIkitAPICheck against fresh 6.0.3 macOS and Linux snapshots
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 #18.
Summary
update(); the renderer hydrates user-defined dynamic properties recursively (nested framework wrappers bind depth-first with stable declaration-ordered indices) and runsupdate()once per hydration beforebody@dynamicMemberLookupchild bindings with writeback,init(projectedValue:), optional promotion/unwrapping, AnyHashable projection, conditionalIdentifiable+Sequence/Collection/BidirectionalCollection/RandomAccessCollection(writable element bindings), and@unchecked Sendable where Value: Sendableinit(initialValue:)and the empty initializer for nil-expressible valuesCodablebound removed; SwiftUI's typed initializer families (Bool, Int, Double, String, URL, Data, Date, RawRepresentable String/Int + optional variants with remove-on-nil) delegate to family-specific read/write steps on the injected, ordered backend from [P0-10] Serialize AppStorage persistence and inject its backend per app #15; the backend parameter now uses SwiftUI'sstorelabel and accepts aStorageBackendas the documented terminal adaptation ofUserDefaults; arbitraryCodablevalues stay as a documented additive convenience@Observablemodels, all three initializer spellings, conditionalIdentifiableDeviations from the issue text (documented)
Transactionvalue contract per the tracker's conflict rules@Observable+@Environment(Type.self), which already existed, plus the newBindable) covers the terminal-useful semantics. SceneStorage belongs to scene-session work ([P1-14] Add composable Scene modifiers and Scene environment propagation #19/[P2-28] Add terminal accessibility, search, refresh, and application actions #33 sphere). Their manifest classification stays with the roadmap@Statemacro layer remains a separate compiler-floor decision per the issue textTest plan
./scripts/test-linux.sh, warning-fatalverify-compatibility-manifest.shpasses against the regenerated manifest