Repository navigation
expand supported SwiftUI views - #23
Conversation
0xWDG
commented
Aug 20, 2026
- added 15 new JSON-backed SwiftUI components
- log and skip unsupported view types without failing rendering ignore metadata objects without a type
- added more previews, documentation, tests, and playground examples
added 15 new JSON-backed SwiftUI components log and skip unsupported view types without failing rendering ignore metadata objects without a type added more previews, documentation, tests, and playground examples
There was a problem hiding this comment.
Pull request overview
Expands DynamicUI’s JSON-to-SwiftUI renderer by adding many new supported view types, improving decoding resilience (ignoring metadata-only entries), and documenting/previewing the new components across DocC, previews, tests, and the playground.
Changes:
- Adds new JSON-backed SwiftUI components (e.g., AsyncImage, Link/ShareLink, Menu, NavigationStack/NavigationLink, Grid/GridRow, Lazy stacks/grids, Stepper, DatePicker, ColorPicker).
- Updates decoding/rendering to ignore objects without a string
typeand to log-and-skip unsupportedtypes instead of failing the full render. - Extends tests, DocC, previews, README, and playground demos to cover the expanded component set.
Reviewed changes
Copilot reviewed 57 out of 57 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| Tests/DynamicUITests/DynamicUITests.swift | Adds coverage for supported-type registry and metadata-ignoring decode behavior. |
| Sources/DynamicUI/Views/DynamicZStack.swift | Adds Debug preview fixture for ZStack. |
| Sources/DynamicUI/Views/DynamicVStack.swift | Adds Debug preview fixture for VStack. |
| Sources/DynamicUI/Views/DynamicVSplitView.swift | Adds Debug preview fixture for VSplitView. |
| Sources/DynamicUI/Views/DynamicToggle.swift | Switches to compatibility dynamicUIOnChange wrapper. |
| Sources/DynamicUI/Views/DynamicTextField.swift | Switches to compatibility dynamicUIOnChange + adds preview. |
| Sources/DynamicUI/Views/DynamicTextEditor.swift | Switches to compatibility dynamicUIOnChange + adds preview. |
| Sources/DynamicUI/Views/DynamicTEMPLATE.swift | Adds template preview (debug-only). |
| Sources/DynamicUI/Views/DynamicTabView.swift | Adds TabView preview fixture. |
| Sources/DynamicUI/Views/DynamicStepper.swift | Introduces Stepper component with platform fallbacks + preview. |
| Sources/DynamicUI/Views/DynamicSlider.swift | Switches to compatibility dynamicUIOnChange wrapper. |
| Sources/DynamicUI/Views/DynamicShareLink.swift | Introduces ShareLink component with fallbacks + preview. |
| Sources/DynamicUI/Views/DynamicSecureTextField.swift | Switches to compatibility dynamicUIOnChange + adds preview. |
| Sources/DynamicUI/Views/DynamicScrollView.swift | Adds ScrollView preview fixture. |
| Sources/DynamicUI/Views/DynamicPicker.swift | Switches to compatibility dynamicUIOnChange + adds preview. |
| Sources/DynamicUI/Views/DynamicNavigationView.swift | Adds NavigationView preview fixture. |
| Sources/DynamicUI/Views/DynamicNavigationStack.swift | Introduces NavigationStack component with fallback + preview. |
| Sources/DynamicUI/Views/DynamicNavigationSplitView.swift | Adds NavigationSplitView preview fixture. |
| Sources/DynamicUI/Views/DynamicNavigationLink.swift | Introduces NavigationLink component + preview. |
| Sources/DynamicUI/Views/DynamicMenu.swift | Introduces Menu component with platform fallbacks + preview. |
| Sources/DynamicUI/Views/DynamicLink.swift | Introduces Link component + preview. |
| Sources/DynamicUI/Views/DynamicLazyVStack.swift | Introduces LazyVStack component + preview. |
| Sources/DynamicUI/Views/DynamicLazyVGrid.swift | Introduces LazyVGrid component. |
| Sources/DynamicUI/Views/DynamicLazyHStack.swift | Introduces LazyHStack component + preview. |
| Sources/DynamicUI/Views/DynamicLazyHGrid.swift | Introduces LazyHGrid component and shared grid configuration. |
| Sources/DynamicUI/Views/DynamicLabel.swift | Adds Label preview fixture. |
| Sources/DynamicUI/Views/DynamicInvalidTest.swift | Adds debug-only “invalid JSON” preview fixture. |
| Sources/DynamicUI/Views/DynamicImage.swift | Adds Image preview fixture. |
| Sources/DynamicUI/Views/DynamicGridRow.swift | Introduces GridRow component with fallback + preview. |
| Sources/DynamicUI/Views/DynamicGrid.swift | Introduces Grid component with fallback + preview. |
| Sources/DynamicUI/Views/DynamicDatePicker.swift | Introduces DatePicker component with platform fallbacks + ISO8601 handling + preview. |
| Sources/DynamicUI/Views/DynamicColorPicker.swift | Introduces ColorPicker component + color serialization + preview. |
| Sources/DynamicUI/Views/DynamicAsyncImage.swift | Introduces AsyncImage component with loading/failure states + preview. |
| Sources/DynamicUI/Helpers/PreviewFixtures.swift | Adds shared preview fixture helpers (debug-only). |
| Sources/DynamicUI/Helpers/DynamicUIHelper.swift | Adds hex color parsing + Color→hex serialization. |
| Sources/DynamicUI/Extensions/View.modifiers.swift | Adds dynamicUIOnChange wrapper for new/old SwiftUI onChange APIs. |
| Sources/DynamicUI/DynamicUIViewType.swift | Adds centralized registry of supported view types. |
| Sources/DynamicUI/DynamicUIComponent.swift | Adds metadata-tolerant decode entry wrapper + layout decoder helper. |
| Sources/DynamicUI/DynamicUI.swift | Switches to registry-based view dispatch and logs unsupported types; uses layout decoder. |
| Sources/DynamicUI/DynamicUI.docc/Views/Stepper.md | Adds Stepper documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/ShareLink.md | Adds ShareLink documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/NavigationStack.md | Adds NavigationStack documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/NavigationLink.md | Adds NavigationLink documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/Menu.md | Adds Menu documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/Link.md | Adds Link documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/LazyVStack.md | Adds LazyVStack documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/LazyVGrid.md | Adds LazyVGrid documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/LazyHStack.md | Adds LazyHStack documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/LazyHGrid.md | Adds LazyHGrid documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/GridRow.md | Adds GridRow documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/Grid.md | Adds Grid documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/DatePicker.md | Adds DatePicker documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/ColorPicker.md | Adds ColorPicker documentation. |
| Sources/DynamicUI/DynamicUI.docc/Views/AsyncImage.md | Adds AsyncImage documentation. |
| Sources/DynamicUI/DynamicUI.docc/DynamicUI.md | Updates schema/behavior docs and adds links for new components. |
| README.md | Updates high-level behavior notes (logging/skipping unknown types; ignore metadata entries). |
| Playground/DynamicUI Playground/ContentView.swift | Adds “Custom” demo and expands sample JSON to include new views; improves editor/preview layout. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| public struct DynamicUIComponent: Codable, Hashable { | ||
| private enum CodingKeys: String, CodingKey { | ||
| case type | ||
| case title | ||
| case text |
| let count = min(max(component.parameters?[countKey]?.toInt() ?? 1, 1), 50) | ||
| let minimum = max(component.parameters?["minimum"]?.toDouble() ?? 10, 0) | ||
| let maximum = max(component.parameters?["maximum"]?.toDouble() ?? .infinity, minimum) | ||
| let spacing = spacing(for: component) | ||
| let item = GridItem( | ||
| .flexible(minimum: minimum, maximum: maximum), | ||
| spacing: spacing | ||
| ) |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 57 out of 57 changed files in this pull request and generated no new comments.
Suppressed comments (3)
Sources/DynamicUI/DynamicUI.docc/DynamicUI.md:130
- The “Controls” DocC links are missing the
Views/prefix, so they won’t match the article paths underDynamicUI.docc/Views/.
- <doc:Button>
- <doc:Toggle>
- <doc:TextField>
- <doc:SecureField>
- <doc:TextEditor>
Sources/DynamicUI/DynamicUI.docc/DynamicUI.md:147
- The “Containers” DocC links are also missing the
Views/prefix; update them to match the article locations underDynamicUI.docc/Views/so the links resolve.
- <doc:VStack>
- <doc:HStack>
- <doc:ZStack>
- <doc:LazyVStack>
- <doc:LazyHStack>
Sources/DynamicUI/DynamicUI.docc/DynamicUI.md:122
- The DocC links under “Supported Views” point to
<doc:Text>etc, but the articles live underDynamicUI.docc/Views/(e.g.Views/Text.md). These links will likely be unresolved; include theViews/path in the identifiers.
This issue also appears in the following locations of the same file:
- line 126
- line 143
- <doc:Text>
- <doc:Label>
- <doc:Image>
- <doc:AsyncImage>
- <doc:Divider>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 58 out of 58 changed files in this pull request and generated no new comments.
Suppressed comments (6)
Sources/DynamicUI/DynamicUI.swift:170
- Filtering components and then using
visibleComponents.indicesas theForEachidentity can cause unstable view identity when conditions toggle (indexes shift when an item is hidden/shown), which can lead to SwiftUI reusing the wrong subview/state for a different component.
/// - Returns: A SwiftUI View
func buildView(for components: [DynamicUIComponent]) -> some View {
// swiftlint:disable:previous cyclomatic_complexity function_body_length
Sources/DynamicUI/DynamicUI.swift:313
unsupportedView(for:)logs from inside the view-building path. BecausebuildViewmay be evaluated frequently by SwiftUI, this can generate repeated error logs for the same unsupported type and spam unified logging in production.
}
}
Sources/DynamicUI/Views/DynamicStepper.swift:32
- Using
.leastNonzeroMagnitudeas the minimum step means a JSONstepof0(or negative) will become an extremely tiny increment, which can make the Stepper practically unusable and generate huge numbers of intermediate values.
Sources/DynamicUI/Views/DynamicLink.swift:23 DynamicLinkaccepts any URL scheme. If JSON comes from an untrusted source, this can enable links to non-web schemes (e.g.tel:, custom deep links, or other handlers). Consider restricting to an allow-list (similar toDynamicAsyncImageonly allowing http/https), or making allowed schemes configurable.
Sources/DynamicUI/Views/DynamicShareLink.swift:23DynamicShareLinkaccepts any URL scheme. If layouts are driven by remote/untrusted JSON, consider validating schemes (e.g. http/https allow-list) before constructing aShareLink/fallbackLink, to avoid sharing or opening unintended URL types.
Tests/DynamicUITests/DynamicUITests.swift:5- This test name says it verifies "documented" views, but the expected set is hard-coded rather than derived from the documentation source. Renaming the test would make its intent accurate and reduce confusion.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 58 out of 58 changed files in this pull request and generated no new comments.
Suppressed comments (2)
Sources/DynamicUI/DynamicUI.swift:317
unsupportedView(for:)logs an OSLog.errormessage withprivacy: .publicfor a value coming from external JSON. This can unnecessarily surface untrusted input in customer logs and elevate it to error severity; consider logging atwarning(or lower) and relying on the default private redaction for interpolated values.
private func unsupportedView(for type: String) -> EmptyView {
Self.logger.error("Unsupported DynamicUI view type: \(type, privacy: .public)")
return EmptyView()
Tests/DynamicUITests/DynamicUITests.swift:61
- New hex color support in
DynamicUIHelper.translateColor/translateHexColoris not currently covered by tests. Adding a small unit test for valid/invalid hex strings will help prevent regressions in ColorPicker defaults and modifier parsing.