Skip to content
Open
Show file tree
Hide file tree
Changes from 117 commits
Commits
Show all changes
192 commits
Select commit Hold shift + click to select a range
a76799a
GEMINI: feat: Initial Swift package structure for A2UI renderer
sunnypurewal Feb 23, 2026
bceef4d
GEMINI: feat: Define core A2UI data models in Swift
sunnypurewal Feb 23, 2026
8aa224d
GEMINI: feat: Implement A2UI message parsing logic
sunnypurewal Feb 23, 2026
6b62130
GEMINI: feat: Create data store for managing surface and component state
sunnypurewal Feb 23, 2026
6665a8d
GEMINI: feat: Develop the main surface view and component renderer
sunnypurewal Feb 23, 2026
c9e52f7
GEMINI: feat: Implement rendering for individual A2UI components
sunnypurewal Feb 23, 2026
214cdb5
GEMINI: feat: Add comprehensive unit tests for core logic and extensi…
sunnypurewal Feb 23, 2026
7a2f2ae
GEMINI: feat: Add sample application to demonstrate renderer usage
sunnypurewal Feb 23, 2026
e943e8e
GEMINI: fix(swift): Refine .gitignore for Xcode best practices
sunnypurewal Feb 23, 2026
2fd3168
GEMINI: feat(sample): Add Xcode project for sample app
sunnypurewal Feb 23, 2026
45df65e
GEMINI: feat(swift): Copy .gitignore to samples/swift
sunnypurewal Feb 23, 2026
28b9337
GEMINI: fix(sample): Remove String:Identifiable and refactor sheet
sunnypurewal Feb 23, 2026
aaffe38
manually fix project ref
sunnypurewal Feb 23, 2026
0ba8798
GEMINI: docs(swift): Add READMEs for renderer and sample app
sunnypurewal Feb 23, 2026
a606602
GEMINI: fix(swift): Update tests to match v0.10 data models
sunnypurewal Feb 23, 2026
6205db9
GEMINI: Fix Swift renderer data handling and parser
sunnypurewal Feb 23, 2026
120b092
Merge branch 'google:main' into main
sunnypurewal Feb 23, 2026
01339b7
CLAUDE: Remove invalid description parameter from video component test
sunnypurewal Feb 23, 2026
7d484e0
update more v0.10
sunnypurewal Feb 24, 2026
81c5c0f
CLAUDE: Fix component decoding to support both JSON formats and updat…
sunnypurewal Feb 24, 2026
5fdaa4f
Merge branch 'google:main' into main
sunnypurewal Feb 24, 2026
c86d241
Update custom Action to match schema spec
sunnypurewal Feb 25, 2026
28a52bf
Fix build warnings in input views
sunnypurewal Feb 25, 2026
5a35ff1
Merge branch 'google:main' into main
sunnypurewal Feb 25, 2026
d212735
Merge branch 'main' of github.com:sunnypurewal/A2UI
sunnypurewal Feb 25, 2026
2985345
begin refactor of gallery to use user-editable data model
sunnypurewal Feb 25, 2026
2c0c746
refactor: parse children oneof as enum
sunnypurewal Feb 25, 2026
797122f
implement enum for justify and align
sunnypurewal Feb 25, 2026
41ba490
begin user editable gallery
sunnypurewal Feb 25, 2026
83b89b5
refactoring app to detail views
sunnypurewal Feb 25, 2026
6447120
GEMINI: simplify ContentView to category list
sunnypurewal Feb 25, 2026
3c8d5d2
more navigation improvements
sunnypurewal Feb 25, 2026
c61e59d
GEMINI: add GalleryComponent initializer for Row/Column templates
sunnypurewal Feb 25, 2026
9a36fbd
continue implementing navigation
sunnypurewal Feb 25, 2026
dd7fe5c
GEMINI: fix bindings in ComponentView
sunnypurewal Feb 25, 2026
4412a8b
show json button
sunnypurewal Feb 25, 2026
1aafd0c
GEMINI: pretty print component JSON
sunnypurewal Feb 25, 2026
2a3340a
full Row and Column rendering with property editing works
sunnypurewal Feb 25, 2026
b15c876
ready to use datamodel in gallery
sunnypurewal Feb 25, 2026
2ece30b
GEMINI: add DataModelField for gallery data model updates
sunnypurewal Feb 25, 2026
2258e45
GEMINI: add data model editors for gallery surfaces
sunnypurewal Feb 25, 2026
0f04342
editing data model
sunnypurewal Feb 25, 2026
79b6d53
GEMINI: show data model JSON in ComponentView
sunnypurewal Feb 25, 2026
19bfd9e
GEMINI: restore JSON-safe data model updates
sunnypurewal Feb 25, 2026
52844a7
fix preview
sunnypurewal Feb 25, 2026
b0fc8ca
allowing list data model editing
sunnypurewal Feb 25, 2026
cbe0530
GEMINI: add list value support to data model fields
sunnypurewal Feb 25, 2026
fd5a33d
GEMINI: store list fields as JSON object arrays
sunnypurewal Feb 25, 2026
4edf50d
GEMINI: store list objects as array of dictionaries
sunnypurewal Feb 25, 2026
fa9b00f
add list to gallery
sunnypurewal Feb 25, 2026
2d98462
build bkore
sunnypurewal Feb 25, 2026
445c8ab
add text gallery
sunnypurewal Feb 25, 2026
210f2f0
add text variant
sunnypurewal Feb 25, 2026
69b6208
add image to gallery with avatar variant
sunnypurewal Feb 25, 2026
89ad65a
GEMINI: Add A2UIIconName enum and IconMapper for SF Symbols mapping
sunnypurewal Feb 25, 2026
2857b00
clean up refactor
sunnypurewal Feb 25, 2026
70efc79
GEMINI: Support .choice in DataModelField for enum-like selection
sunnypurewal Feb 25, 2026
c9ce6d9
add icon to gallery
sunnypurewal Feb 25, 2026
54b8c40
GEMINI: Add volume slider to A2UIAudioPlayerView
sunnypurewal Feb 26, 2026
0622ff7
GEMINI: Add progress scrubber to A2UIAudioPlayerView
sunnypurewal Feb 26, 2026
e7e017d
GEMINI: Reload AVPlayer on URL change and improve A2UIAudioPlayerView
sunnypurewal Feb 26, 2026
e7dd86d
add audio and video to gallery
sunnypurewal Feb 26, 2026
f82b8df
manual updates to schema
sunnypurewal Feb 26, 2026
b1c9640
GEMINI: Refactor Swift A2UI components into modular directory structure
sunnypurewal Feb 26, 2026
00d2962
GEMINI: Fix build failures in Swift tests by updating string literals…
sunnypurewal Feb 26, 2026
7f34479
GEMINI: Split A2UIModels.swift into modular files in Models directory
sunnypurewal Feb 26, 2026
29f4f21
GEMINI: Refactor A2UI Swift renderer into modular subdirectories
sunnypurewal Feb 26, 2026
273d119
GEMINI: Fix syntax error in A2UIDataStore.swift flush() method
sunnypurewal Feb 26, 2026
9999b57
GEMINI: Refactor GalleryComponent.swift into modular files and add mi…
sunnypurewal Feb 26, 2026
7bfc9b3
add video fullscreen option
sunnypurewal Feb 26, 2026
e61db8a
GEMINI: Fix audio and video player persistence by pausing in onDisappear
sunnypurewal Feb 26, 2026
429a27d
GEMINI: Release AVPlayer memory by setting player to nil in onDisappear
sunnypurewal Feb 26, 2026
6ff66c4
GEMINI: Fix TextField data binding by handling .dataUpdate locally in…
sunnypurewal Feb 26, 2026
1cb46c9
Add Checkbox to gallery
sunnypurewal Feb 26, 2026
01f355a
add picker to gallery
sunnypurewal Feb 26, 2026
58bf498
GEMINI: Improve A2UIChoicePicker multipleSelection variant with nativ…
sunnypurewal Feb 26, 2026
23dc659
GEMINI: Add SwiftUI previews for all A2UI components
sunnypurewal Feb 26, 2026
6047888
update choice picker gallery
sunnypurewal Feb 26, 2026
3a18325
add slider to preview
sunnypurewal Feb 26, 2026
90482c6
GEMINI: update PropertyDefinition to support numeric values
sunnypurewal Feb 26, 2026
f668521
add datetimepicker to gallery
sunnypurewal Feb 26, 2026
bb563ee
GEMINI: add Boolean and Date support to PropertyDefinition
sunnypurewal Feb 26, 2026
62413bc
update datetime picker options
sunnypurewal Feb 26, 2026
23224d1
add button to gallery but still need functions
sunnypurewal Feb 26, 2026
400c478
add modal to gallery
sunnypurewal Feb 26, 2026
d1ef284
add tabs to gallery
sunnypurewal Feb 26, 2026
5fd438e
add divider to gallery
sunnypurewal Feb 26, 2026
89dbe43
GEMINI: Update BoundValue and FunctionCall models to support catalog …
sunnypurewal Feb 26, 2026
e002bcb
GEMINI: Implement A2UIFunctionEvaluator and integrate into SurfaceState
sunnypurewal Feb 26, 2026
2fb74d1
GEMINI: Add unit tests for A2UI catalog functions
sunnypurewal Feb 26, 2026
62fa221
GEMINI: Fix build errors and test failures for macOS support and cata…
sunnypurewal Feb 26, 2026
717af0d
GEMINI: Implement Checkable support for input components and display …
sunnypurewal Feb 26, 2026
245dd37
GEMINI: Complete Checkable implementation with unit tests and TextFie…
sunnypurewal Feb 26, 2026
ca35a3a
GEMINI: Add validation error view and logging to track check evaluation
sunnypurewal Feb 26, 2026
1d2b0ac
GEMINI: Refactor Checkable implementation to align with v0.10 spec st…
sunnypurewal Feb 26, 2026
7ef4b1d
GEMINI: Revert BoundValue to strictly follow A2UI spec
sunnypurewal Feb 26, 2026
32e4218
fix textfield validation gallery
sunnypurewal Feb 26, 2026
6d91dee
GEMINI: Add StandardCheckFunction enum and allow configuring checks i…
sunnypurewal Feb 26, 2026
922bc29
GEMINI: Fix TextField gallery template by making it a single line string
sunnypurewal Feb 26, 2026
05efe93
implementing textfield checks
sunnypurewal Feb 26, 2026
55ffd58
GEMINI: Allow nil values in PropertyDefinition and add mapValue for c…
sunnypurewal Feb 26, 2026
1ff3fca
update textfield gallery to have checks
sunnypurewal Feb 26, 2026
8fabaaa
GEMINI: Add Functions category to gallery with A2UI-based demos
sunnypurewal Feb 26, 2026
6e2dffb
GEMINI: Hide data model fields in function gallery editors
sunnypurewal Feb 26, 2026
03f582f
GEMINI: Split FunctionDemos.swift into individual files per component
sunnypurewal Feb 26, 2026
e558099
GEMINI: Refactor A2UIFunctionEvaluator into smaller, categorized files
sunnypurewal Feb 26, 2026
857f09a
GEMINI: Refactor function signatures to use typed arguments
sunnypurewal Feb 26, 2026
9af698f
GEMINI: Refactor functions to use non-optional parameters and move ar…
sunnypurewal Feb 26, 2026
c85baef
remove plan
sunnypurewal Feb 26, 2026
9fcd3d1
GEMINI: Update function evaluator and pluralize to strictly follow A2…
sunnypurewal Feb 26, 2026
4cfa0f3
GEMINI: Decouple validation UI and implement virtual validation paths…
sunnypurewal Feb 26, 2026
367cc4b
GEMINI: Update Swift gallery to show validation status via virtual pa…
sunnypurewal Feb 26, 2026
b1fed9d
GEMINI: Inject virtual validation paths into Data Model JSON display …
sunnypurewal Feb 26, 2026
c7c4ba6
Merge branch 'google:main' into main
sunnypurewal Feb 26, 2026
18583a1
unedit files
sunnypurewal Feb 26, 2026
78e1363
Merge branch 'main' of github.com:sunnypurewal/A2UI
sunnypurewal Feb 26, 2026
2ba865a
update swift gitignores
sunnypurewal Feb 26, 2026
47ae104
Update READMEs
sunnypurewal Feb 26, 2026
eab94b0
Fix warnings in function evaluator
sunnypurewal Feb 26, 2026
3de36a5
GEMINI: Add ViewInspector support and improve initial renderer tests
sunnypurewal Feb 26, 2026
7c19652
GEMINI: Migrate all test suites to Swift Testing framework
sunnypurewal Feb 26, 2026
a13e38d
GEMINI: Refactor input components to use direct Binding instead of @S…
sunnypurewal Feb 26, 2026
e68418c
Update function tests to use new pattern
sunnypurewal Feb 26, 2026
cf5a470
GEMINI: Refactor test files to use variable reuse and custom init hel…
sunnypurewal Feb 26, 2026
cdc7d8c
fix force unwrap icon
sunnypurewal Feb 26, 2026
43b3e31
fix capture cycle
sunnypurewal Feb 26, 2026
a5eb258
improve JSONL parsing
sunnypurewal Feb 26, 2026
d16fe12
Better Double->Int conversion
sunnypurewal Feb 26, 2026
2773247
remove video autoplay
sunnypurewal Feb 26, 2026
3e4436a
Update unknown message handling
sunnypurewal Feb 26, 2026
9d833b2
continue adding test coverage
sunnypurewal Feb 26, 2026
dab7cc4
GEMINI: Increase code coverage to 90%+ for core files and UI components.
sunnypurewal Feb 26, 2026
964a300
GEMINI: Achieve 90%+ test coverage across all targeted files.
sunnypurewal Feb 26, 2026
065c6e9
GEMINI: Finalize 90%+ coverage for all targeted files.
sunnypurewal Feb 26, 2026
e9fc194
GEMINI: Refactor tests to match source structure
sunnypurewal Feb 27, 2026
4f71031
CLAUDE: Remove virtual validation paths, display errors inline in inp…
sunnypurewal Feb 27, 2026
a92f0bd
CLAUDE: Remove inline validation error display from input components
sunnypurewal Feb 27, 2026
9f05086
GEMINI: Add ResourcesView for app information and settings
sunnypurewal Feb 27, 2026
1dd1eca
GEMINI: Update home screen with Gallery and App sections
sunnypurewal Feb 27, 2026
fbad8bf
GEMINI: Fix data binding resolution in templates by passing contextua…
sunnypurewal Feb 27, 2026
b5b3a23
GEMINI: Show validation error messages in Swift input components
sunnypurewal Feb 27, 2026
c0b2cf6
GEMINI: move Button from Navigation to Input section in Swift sample app
sunnypurewal Feb 27, 2026
ad9e5a8
update sample app readme
sunnypurewal Feb 27, 2026
9ea0b98
add Resources section to sample app
sunnypurewal Feb 27, 2026
c224d3e
GEMINI: Improve test coverage for A2UI components and data store to 90%+
sunnypurewal Feb 27, 2026
cc57da7
GEMINI: Refactor debug borders to use environment variables and remov…
sunnypurewal Feb 27, 2026
347866c
GEMINI: Convert all renderer tests to Swift Testing framework
sunnypurewal Feb 27, 2026
452b47b
GEMINI: Remove ViewInspector dependency and all dependent tests
sunnypurewal Feb 27, 2026
ebfb2e4
rename functions
sunnypurewal Feb 27, 2026
0d37d10
updating openURL arch
sunnypurewal Feb 27, 2026
cec48b2
wip open url tests
sunnypurewal Feb 27, 2026
3b06ea8
update OpenURL tests
sunnypurewal Feb 27, 2026
be9faa5
add format string tests
sunnypurewal Feb 27, 2026
4d31c6d
GEMINI: add tests for A2UIDataStore.flush()
sunnypurewal Feb 27, 2026
d4f25a6
update parser and data store tests
sunnypurewal Feb 27, 2026
31b416a
update formatting tests
sunnypurewal Feb 27, 2026
8a1cfb8
GEMINI: improve coverage for ComponentType and fix timezone issues in…
sunnypurewal Feb 27, 2026
3bff72d
improve date string parsing
sunnypurewal Feb 27, 2026
5b37252
code coverage for all functions
sunnypurewal Feb 27, 2026
1b9f961
more test coverage
sunnypurewal Feb 27, 2026
d9c0797
GEMINI: Restore CaseIterable and Identifiable conformances to enums
sunnypurewal Feb 27, 2026
23e9e8a
GEMINI: Migrate all remaining test files from XCTest to Swift Testing
sunnypurewal Feb 27, 2026
5f5b2d8
Merge branch 'google:main' into main
sunnypurewal Feb 27, 2026
1c93593
GEMINI: update Swift sample app to display UserActions in a log
sunnypurewal Feb 27, 2026
d834189
GEMINI: improve button sample with status label and round-trip event …
sunnypurewal Feb 27, 2026
6fc5946
GEMINI: migrate Swift renderer and tests to A2UI v0.10 schema
sunnypurewal Feb 27, 2026
5688f6e
Merge branch 'main' of github.com:sunnypurewal/A2UI
sunnypurewal Feb 27, 2026
a00a40b
Merge branch 'google:main' into main
sunnypurewal Feb 27, 2026
b1ad267
GEMINI: Replace OSLog and print with conditional A2UILogger
sunnypurewal Feb 27, 2026
4724501
GEMINI: Remove redundant internal keywords
sunnypurewal Feb 27, 2026
7626d61
GEMINI: Add CHANGELOG.md for Swift implementation
sunnypurewal Feb 27, 2026
595264d
GEMINI: update A2UI version from 0.10 to 0.9 in Swift code
sunnypurewal Feb 27, 2026
2948c4b
GEMINI: Fix property resolution in GalleryComponent and update valida…
sunnypurewal Feb 28, 2026
3d670d8
update format date
sunnypurewal Feb 28, 2026
d69a4c3
GEMINI: Add SF Symbols to ComponentCategory in Gallery
sunnypurewal Feb 28, 2026
832642f
GEMINI: Add SF Symbols to ComponentType and update Gallery list labels
sunnypurewal Feb 28, 2026
9c7bc5e
Fix formatting and improve section headers in README
sunnypurewal Feb 28, 2026
109dc0d
Update README to reflect SwiftUI renderer
sunnypurewal Feb 28, 2026
f985dfd
sample app improvements
sunnypurewal Feb 28, 2026
08c9d03
Merge branch 'main' of github.com:sunnypurewal/A2UI
sunnypurewal Feb 28, 2026
c279d0a
fix 2 tests
sunnypurewal Feb 28, 2026
6fa8fde
add support for custom functions
sunnypurewal Feb 28, 2026
eb932c5
Merge branch 'google:main' into main
sunnypurewal Mar 2, 2026
a92c922
Document data store resolution and small sample app fix
sunnypurewal Mar 3, 2026
5892326
Merge branch 'main' of github.com:sunnypurewal/A2UI
sunnypurewal Mar 3, 2026
f3d430b
Merge branch 'google:main' into main
sunnypurewal Mar 3, 2026
a76332d
Merge branch 'main' of github.com:sunnypurewal/A2UI
sunnypurewal Mar 3, 2026
feb7c3f
Merge branch 'google:main' into main
sunnypurewal Mar 3, 2026
de4b8c6
Merge branch 'main' into main
sunnypurewal Mar 4, 2026
9b8b89a
Merge branch 'google:main' into main
sunnypurewal Mar 5, 2026
8337c3d
Merge branch 'main' into main
sunnypurewal Mar 6, 2026
68b7daf
Merge branch 'google:main' into main
sunnypurewal Mar 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions renderers/swift/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Build artifacts
.build/

# Swift Package Manager
.swiftpm/

# Xcode
.DS_Store
*.playground/
DerivedData/

# User-specific workspace/project files
**/*.xcodeproj/project.xcworkspace/
**/*.xcodeproj/xcuserdata/
**/*.xcworkspace/xcuserdata/
23 changes: 23 additions & 0 deletions renderers/swift/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// swift-tools-version: 6.0
import PackageDescription

let package = Package(
name: "A2UI",
platforms: [
.iOS(.v18),
.macOS(.v15)
],
products: [
.library(
name: "A2UI",
targets: ["A2UI"]),
],
targets: [
.target(
name: "A2UI",
dependencies: []),
.testTarget(
name: "A2UITests",
dependencies: ["A2UI"]),
]
)
41 changes: 41 additions & 0 deletions renderers/swift/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# A2UI Swift Renderer

This directory contains the source code for the A2UI Swift Renderer.

It is a native Swift package that provides the necessary components to parse and render A2UI protocol messages within a SwiftUI application.

## Key Components:

- **A2UIParser**: Deserializes A2UI JSON messages into Swift data models.
- **A2UIDataStore**: Manages the state of the UI surface and its components.
- **A2UISurfaceView**: A SwiftUI view that orchestrates the rendering of the entire A2UI surface.
- **A2UIComponentRenderer**: A view responsible for dynamically rendering individual A2UI components (e.g., Text, Button, Card) as native SwiftUI views.

For an example of how to use this renderer, please see the sample application in `samples/client/swift`.

## Usage

To use this package in your Xcode project:

1. Go to **File > Add Packages...**
2. In the "Add Package" dialog, click **Add Local...**
3. Navigate to this directory (`renderers/swift`) and click **Add Package**.
4. Select the `A2UI` library to be added to your application target.

## Running Tests

You can run the included unit tests using either Xcode or the command line.

### Xcode

1. Open the `Package.swift` file in this directory with Xcode.
2. Go to the **Test Navigator** (Cmd+6).
3. Click the play button to run all tests.

### Command Line

Navigate to this directory in your terminal and run:

```bash
swift test
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import SwiftUI
import AVKit

struct A2UIAudioPlayerView: View {
let properties: AudioPlayerProperties
@Environment(SurfaceState.self) var surface
@State private var player: AVPlayer?
@State private var isPlaying: Bool = false
@State private var volume: Double = 1.0
@State private var currentTime: Double = 0
@State private var duration: Double = 0
@State private var isEditing: Bool = false
@State private var timeObserverToken: Any?

var body: some View {
VStack(alignment: .leading, spacing: 8) {
HStack {
Button(action: {
togglePlay()
}) {
Image(systemName: isPlaying ? "pause.fill" : "play.fill")
.font(.title)
}

VStack(alignment: .leading) {
Text(surface.resolve(properties.description) ?? "Audio Player")
.font(.caption)

Slider(value: $currentTime, in: 0...max(duration, 0.01)) { editing in
isEditing = editing
if !editing {
player?.seek(to: CMTime(seconds: currentTime, preferredTimescale: 600))
}
}

HStack {
Text(formatTime(currentTime))
Spacer()
Text(formatTime(duration))
}
.font(.system(size: 10, design: .monospaced))
.foregroundColor(.secondary)
}
}

HStack {
Image(systemName: "speaker.fill")
.foregroundColor(.secondary)
Slider(value: $volume, in: 0...1)
.onChange(of: volume) { _, newValue in
player?.volume = Float(newValue)
}
Image(systemName: "speaker.wave.3.fill")
.foregroundColor(.secondary)
}
}
.padding()
.background(Color.secondary.opacity(0.1))
.cornerRadius(8)
.onAppear {
setupPlayer()
}
.onDisappear {
if let token = timeObserverToken {
player?.removeTimeObserver(token)
timeObserverToken = nil
}
player?.pause()
player = nil
}
}

private func setupPlayer() {
if let urlString = surface.resolve(properties.url), let url = URL(string: urlString) {
let avPlayer = AVPlayer(url: url)
player = avPlayer
volume = Double(avPlayer.volume)
isPlaying = false
currentTime = 0
duration = 0

// Observe time
timeObserverToken = avPlayer.addPeriodicTimeObserver(forInterval: CMTime(seconds: 0.5, preferredTimescale: 600), queue: .main) { time in
Task { @MainActor in
if !isEditing {
currentTime = time.seconds
}
}
}

// Observe duration
Task {
if let duration = try? await avPlayer.currentItem?.asset.load(.duration) {
self.duration = duration.seconds
}
}
}
}

private func togglePlay() {
if isPlaying {
player?.pause()
} else {
player?.play()
}
isPlaying.toggle()
}

private func formatTime(_ seconds: Double) -> String {
let minutes = Int(seconds) / 60
let seconds = Int(seconds) % 60
return String(format: "%d:%02d", minutes, seconds)
}
}

#Preview {
let surface = SurfaceState(id: "test")
let dataStore = A2UIDataStore()

A2UIAudioPlayerView(properties: AudioPlayerProperties(
url: .init(literal: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3"),
description: .init(literal: "Sample Audio")
))
.padding()
.environment(surface)
.environment(dataStore)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Foundation

public struct AudioPlayerProperties: Codable, Sendable {
public let url: BoundValue<String>
public let description: BoundValue<String>?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import SwiftUI

struct A2UIButtonView: View {
@Environment(SurfaceState.self) var surface
let id: String
let properties: ButtonProperties
let checks: [CheckRule]?

init(id: String, properties: ButtonProperties, checks: [CheckRule]? = nil) {
self.id = id
self.properties = properties
self.checks = checks
}

var body: some View {
let variant = properties.variant ?? .primary
let isDisabled = if let checks = checks {
errorMessage(surface: surface, checks: checks) != nil
} else {
false
}

Button(action: {
performAction()
}) {
A2UIComponentRenderer(componentId: properties.child)
.padding(.horizontal, 8)
.padding(.vertical, 4)
}
.disabled(isDisabled)
.applyButtonStyle(variant: variant)
#if os(iOS)
.tint(variant == .primary ? .blue : .gray)
#endif
}

private func performAction() {
surface.trigger(action: properties.action)
}
}

extension View {
@ViewBuilder
func applyButtonStyle(variant: ButtonVariant) -> some View {
if variant == .borderless {
self.buttonStyle(.borderless)
} else {
self.buttonStyle(.bordered)
}
}
}

#Preview {
let surface = SurfaceState(id: "test")
let dataStore = A2UIDataStore()

// Add a text component for the button child
surface.components["t1"] = ComponentInstance(id: "t1", component: .text(TextProperties(text: .init(literal: "Click Me"), variant: nil)))

return VStack(spacing: 20) {
A2UIButtonView(id: "b1", properties: ButtonProperties(
child: "t1",
action: .custom(name: "primary_action", context: nil),
variant: .primary
))

A2UIButtonView(id: "b2", properties: ButtonProperties(
child: "t1",
action: .custom(name: "borderless_action", context: nil),
variant: .borderless
))
}
.padding()
.environment(surface)
.environment(dataStore)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Foundation

public struct ButtonProperties: Codable, Sendable {
public let child: String
public let action: Action
public let variant: ButtonVariant?

public init(child: String, action: Action, variant: ButtonVariant? = nil) {
self.child = child
self.action = action
self.variant = variant
}
}

public enum ButtonVariant: String, Codable, Sendable, CaseIterable, Identifiable {
public var id: String { self.rawValue }
case primary
case borderless
}
27 changes: 27 additions & 0 deletions renderers/swift/Sources/A2UI/Components/Card/A2UICardView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import SwiftUI

struct A2UICardView: View {
let properties: CardProperties

var body: some View {
A2UIComponentRenderer(componentId: properties.child)
.padding()
.background(
RoundedRectangle(cornerRadius: 12)
.fill(Color(white: 0.95))
)
.shadow(color: Color.black.opacity(0.1), radius: 4, x: 0, y: 2)
}
}

#Preview {
let surface = SurfaceState(id: "test")
let dataStore = A2UIDataStore()

surface.components["t1"] = ComponentInstance(id: "t1", component: .text(TextProperties(text: .init(literal: "Card Content"), variant: .h3)))

return A2UICardView(properties: CardProperties(child: "t1"))
.padding()
.environment(surface)
.environment(dataStore)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Foundation

public struct CardProperties: Codable, Sendable {
public let child: String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import SwiftUI

struct A2UICheckBoxView: View {
let id: String
let properties: CheckBoxProperties
@Environment(SurfaceState.self) var surface
@State private var isOn: Bool = false

init(id: String, properties: CheckBoxProperties) {
self.id = id
self.properties = properties
}

var body: some View {
Toggle(isOn: $isOn) {
Text(resolveValue(surface, binding: properties.label) ?? "")
}
.onChange(of: isOn) { _, newValue in
updateBinding(surface: surface, binding: properties.value, newValue: newValue)
surface.runChecks(for: id)
}
.onAppear {
isOn = resolveValue(surface, binding: properties.value) ?? false
surface.runChecks(for: id)
}
}
}

#Preview {
let surface = SurfaceState(id: "test")
let dataStore = A2UIDataStore()

A2UICheckBoxView(id: "cb1", properties: CheckBoxProperties(
label: .init(literal: "Check this box"),
value: .init(literal: true)
))
.padding()
.environment(surface)
.environment(dataStore)
}
Loading