Skip to content

Commit 53a406d

Browse files
committed
feat(components): initial Image implementation
1 parent 3a7e15b commit 53a406d

File tree

8 files changed

+116
-2
lines changed

8 files changed

+116
-2
lines changed

example/src/views/FullFormExample.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const FullFormExample: FunctionComponent = () => {
88
<SwiftUI style={{flex: 1}}>
99
<SwiftUI.Text text="FullFormExample" />
1010
<SwiftUI.Form>
11+
<ImageSection />
1112
<RectangleSection />
1213
<TextFieldSection />
1314
<PickerSection />
@@ -163,3 +164,23 @@ const RectangleSection: FunctionComponent = () => {
163164
</SwiftUI.Section>
164165
);
165166
};
167+
168+
const ImageSection: FunctionComponent = () => {
169+
const [color, setColor] = useState('blue');
170+
171+
return (
172+
<SwiftUI.Section header="Rectangle Example">
173+
<SwiftUI.Image
174+
name="star.fill"
175+
isSystemImage={true}
176+
tintColor="#FF0000"
177+
style={{width: 50, height: 50}}
178+
/>
179+
180+
<SwiftUI.Button
181+
title={`Change flag to ${color === 'blue' ? 'Italy' : 'France'}`}
182+
onPress={() => setColor(color === 'blue' ? 'green' : 'blue')}
183+
/>
184+
</SwiftUI.Section>
185+
);
186+
};

ios/SwiftUINode.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,14 @@ private struct NodeWrapper: Decodable {
8888
node = try GenericNode<RectangleProps>(from: decoder)
8989
case "Spacer":
9090
node = try GenericNode<SpacerProps>(from: decoder)
91+
case "Image":
92+
node = try GenericNode<ImageProps>(from: decoder)
9193
default:
9294
throw DecodingError.typeMismatch(
9395
(any SwiftUINode).self,
9496
DecodingError.Context(
9597
codingPath: container.codingPath,
96-
debugDescription: "Unknown type: \(type)"
98+
debugDescription: "Unknown node type: \(type)"
9799
)
98100
)
99101
}

ios/SwiftUIRootView.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ public class SwiftUIRootView: SwiftUIContainerView {
186186
AnyView(RectangleView(props: rectangle.props))
187187
case let spacer as GenericNode<SpacerProps>:
188188
AnyView(SpacerView(props: spacer.props))
189+
case let image as GenericNode<ImageProps>:
190+
AnyView(ImageView(props: image.props))
189191
default:
190192
AnyView(EmptyView())
191193
}
@@ -260,11 +262,15 @@ public class SwiftUIRootView: SwiftUIContainerView {
260262
case let sheet as GenericNode<SheetProps>:
261263
let updatedProps = try decoder.decode(SheetProps.self, from: updatedPropsData)
262264
sheet.props.merge(from: updatedProps)
263-
265+
264266
case let rectangle as GenericNode<RectangleProps>:
265267
let updatedProps = try decoder.decode(RectangleProps.self, from: updatedPropsData)
266268
rectangle.props.merge(from: updatedProps)
267269

270+
case let image as GenericNode<ImageProps>:
271+
let updatedProps = try decoder.decode(ImageProps.self, from: updatedPropsData)
272+
image.props.merge(from: updatedProps)
273+
268274
default:
269275
print("Unsupported node type for updateChildProps: \(type(of: node))")
270276
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import SwiftUI
2+
3+
public final class ImageProps: ObservableObject, Decodable {
4+
@Published var name: String = ""
5+
@Published var isSystemImage: Bool = false
6+
@Published var resizeMode: ImageResizeMode
7+
@Published var tintColor: String?
8+
@Published var style: StyleProps?
9+
10+
enum ImageResizeMode: String, CaseIterable {
11+
case `default`
12+
case cover
13+
case contain
14+
case stretch
15+
case center
16+
17+
@ViewBuilder
18+
func applyResizeMode(_ image: Image) -> some View {
19+
switch self {
20+
case .cover:
21+
image.resizable().scaledToFill()
22+
case .contain:
23+
image.resizable().scaledToFit()
24+
case .stretch:
25+
image.resizable()
26+
case .center:
27+
image
28+
case .default:
29+
image
30+
}
31+
}
32+
}
33+
34+
enum CodingKeys: String, CodingKey {
35+
case name, isSystemImage, resizeMode, tintColor, style
36+
}
37+
38+
public required init(from decoder: Decoder) throws {
39+
let container = try decoder.container(keyedBy: CodingKeys.self)
40+
name = try container.decode(String.self, forKey: .name)
41+
isSystemImage = try container.decodeIfPresent(Bool.self, forKey: .isSystemImage) ?? false
42+
resizeMode = try ImageResizeMode(rawValue: container.decodeIfPresent(String.self, forKey: .resizeMode) ?? "") ?? .default
43+
tintColor = try container.decodeIfPresent(String.self, forKey: .tintColor)
44+
style = try container.decodeIfPresent(StyleProps.self, forKey: .style)
45+
}
46+
47+
public func merge(from other: ImageProps) {
48+
name = other.name
49+
isSystemImage = other.isSystemImage
50+
resizeMode = other.resizeMode
51+
tintColor = other.tintColor
52+
style = other.style
53+
}
54+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import SwiftUI
2+
3+
public struct ImageView: View {
4+
@ObservedObject public var props: ImageProps
5+
6+
public var body: some View {
7+
let baseImage = props.isSystemImage ? Image(systemName: props.name) : Image(props.name)
8+
// let tintedImage = props.tintColor != nil ? image.foregroundColor(Color(hex: props.tintColor!)) : image
9+
return props.resizeMode.applyResizeMode(baseImage).foregroundStyle(Color.red).applyStyles(props.style)
10+
}
11+
}

src/SwiftUI.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
Form,
77
Group,
88
HStack,
9+
Image,
910
Picker,
1011
Rectangle,
1112
Section,
@@ -95,3 +96,4 @@ SwiftUI.ZStack = ZStack;
9596
SwiftUI.Sheet = Sheet;
9697
SwiftUI.Rectangle = Rectangle;
9798
SwiftUI.Spacer = Spacer;
99+
SwiftUI.Image = Image;

src/components/Image.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { useSwiftUINode } from "../hooks";
2+
import type { FunctionComponentWithId, NativeViewStyle } from "../types";
3+
4+
export type NativeImageProps = {
5+
name: string;
6+
isSystemImage?: boolean;
7+
resizeMode?: "cover" | "contain" | "stretch" | "center";
8+
tintColor?: string;
9+
style?: NativeViewStyle;
10+
};
11+
12+
export const Image: FunctionComponentWithId<NativeImageProps> = ({ ...props }) => {
13+
useSwiftUINode("Image", props);
14+
return null;
15+
};
16+
17+
Image.displayName = "Image";

src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export * from "./DatePicker";
33
export * from "./Form";
44
export * from "./Group";
55
export * from "./HStack";
6+
export * from "./Image";
67
export * from "./Picker";
78
export * from "./Rectangle";
89
export * from "./Section";

0 commit comments

Comments
 (0)