Skip to content

Commit 336f136

Browse files
committed
Draft: Handle relative size
1 parent b55dd5b commit 336f136

File tree

3 files changed

+88
-35
lines changed

3 files changed

+88
-35
lines changed

Examples/Demo/Demo/ImagesView.swift

+12-5
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,21 @@ struct ImagesView: View {
55
private let content = """
66
You can display an image by adding `!` and wrapping the alt text in `[ ]`.
77
Then wrap the link for the image in parentheses `()`.
8-
8+
99
```
10-
![This is an image](https://picsum.photos/id/91/400/300){width=50px}
10+
![This is a 50 px image](https://picsum.photos/id/91/400/300){width=50px}
1111
```
12-
13-
![This is an image](https://picsum.photos/id/91/400/300){width=50px}
14-
12+
13+
![This is a 50px image](https://picsum.photos/id/91/400/300){width=50px}
14+
1515
― Photo by Jennifer Trovato
16+
17+
```
18+
![This is a 50% image](https://i.natgeofe.com/n/548467d8-c5f1-4551-9f58-6817a8d2c45e/NationalGeographic_2572187_3x2.jpg){width=50%}
19+
```
20+
21+
![This is a 50% image](https://i.natgeofe.com/n/548467d8-c5f1-4551-9f58-6817a8d2c45e/NationalGeographic_2572187_3x2.jpg){width=50%}
22+
1623
"""
1724

1825
private let inlineImageContent = """

Sources/MarkdownUI/Utility/InlineNode+RawImageData.swift

+60-29
Original file line numberDiff line numberDiff line change
@@ -25,49 +25,80 @@ extension InlineNode {
2525
var size: MarkdownImageSize? {
2626
switch self {
2727
case .text(let input):
28-
let pattern = "\\{(?:width\\s*=\\s*(\\d+)px\\s*)?(?:height\\s*=\\s*(\\d+)px\\s*)?(?:width\\s*=\\s*(\\d+)px\\s*)?(?:height\\s*=\\s*(\\d+)px\\s*)?\\}"
28+
// Trying first to found a fixed pattern match
29+
let fixedPattern = "\\{(?:width\\s*=\\s*(\\d+)px\\s*)?(?:height\\s*=\\s*(\\d+)px\\s*)?(?:width\\s*=\\s*(\\d+)px\\s*)?(?:height\\s*=\\s*(\\d+)px\\s*)?\\}"
2930

30-
guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else {
31-
return nil
31+
if let (width, height) = extract(regexPattern: fixedPattern, from: input) {
32+
return MarkdownImageSize(value: .fixed(width, height))
3233
}
3334

34-
let range = NSRange(input.startIndex..<input.endIndex, in: input)
35-
guard let match = regex.firstMatch(in: input, options: [], range: range) else {
36-
return nil
37-
}
38-
39-
var width: CGFloat?
40-
var height: CGFloat?
35+
// Trying then to found a relative pattern match
36+
let relativePattern = "\\{(?:width\\s*=\\s*(\\d+)%\\s*)?(?:height\\s*=\\s*(\\d+)%\\s*)?(?:width\\s*=\\s*(\\d+)%\\s*)?(?:height\\s*=\\s*(\\d+)%\\s*)?\\}"
4137

42-
if let widthRange = Range(match.range(at: 1), in: input), let widthValue = Int(input[widthRange]) {
43-
width = CGFloat(widthValue)
44-
} else if let widthRange = Range(match.range(at: 3), in: input), let widthValue = Int(input[widthRange]) {
45-
width = CGFloat(widthValue)
38+
if let (wRatio, hRatio) = extract(regexPattern: relativePattern, from: input) {
39+
return MarkdownImageSize(value: .relative((wRatio ?? 100)/100, (hRatio ?? 100)/100))
4640
}
4741

48-
if let heightRange = Range(match.range(at: 2), in: input), let heightValue = Int(input[heightRange]) {
49-
height = CGFloat(heightValue)
50-
} else if let heightRange = Range(match.range(at: 4), in: input), let heightValue = Int(input[heightRange]) {
51-
height = CGFloat(heightValue)
52-
}
53-
54-
return MarkdownImageSize(width: width, height: height)
42+
return nil
5543
default:
5644
return nil
5745
}
5846
}
47+
48+
private func extract(
49+
regexPattern pattern: String,
50+
from input: String
51+
) -> (width: CGFloat?, height: CGFloat?)? {
52+
guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else {
53+
return nil
54+
}
55+
56+
let range = NSRange(input.startIndex..<input.endIndex, in: input)
57+
guard let match = regex.firstMatch(in: input, options: [], range: range) else {
58+
return nil
59+
}
60+
61+
var width: CGFloat?
62+
var height: CGFloat?
63+
64+
if let widthRange = Range(match.range(at: 1), in: input), let widthValue = Int(input[widthRange]) {
65+
width = CGFloat(widthValue)
66+
} else if let widthRange = Range(match.range(at: 3), in: input), let widthValue = Int(input[widthRange]) {
67+
width = CGFloat(widthValue)
68+
}
69+
70+
if let heightRange = Range(match.range(at: 2), in: input), let heightValue = Int(input[heightRange]) {
71+
height = CGFloat(heightValue)
72+
} else if let heightRange = Range(match.range(at: 4), in: input), let heightValue = Int(input[heightRange]) {
73+
height = CGFloat(heightValue)
74+
}
75+
76+
return (width, height)
77+
}
5978
}
6079

6180
/// A value type representating an image size suffix.
6281
///
63-
/// Example: `![This is an image](https://foo/bar.png){width=50px}`
82+
/// Example:
83+
/// - `![This is an image](https://foo/bar.png){width=50px}`
84+
/// - `![This is an image](https://foo/bar.png){width=50%}`
6485
///
65-
/// Suffix can be either
66-
/// - {width=50px}
67-
/// - {height=50px}
68-
/// - {width=50px height=100px}
69-
/// - {height=50px width=100px}
86+
/// Suffix can either be:
87+
/// - `{width=50px}`
88+
/// - `{height=50px}`
89+
/// - `{width=50px height=100px}`
90+
/// - `{height=50px width=100px}`
91+
/// - `{width=50%}`
92+
/// - `{height=50%}`
93+
/// - `{width=50% height=100%}`
94+
/// - `{height=50% width=100%}`
7095
struct MarkdownImageSize {
71-
let width: CGFloat?
72-
let height: CGFloat?
96+
let value: Value
97+
98+
enum Value {
99+
/// Represents a fixed value size:`.fixed(width, height)`
100+
case fixed(CGFloat?, CGFloat?)
101+
/// Represents a relative value size: `.relative(proportionalWidth, proportionalHeight)`
102+
case relative(CGFloat, CGFloat)
103+
}
73104
}

Sources/MarkdownUI/Views/Inlines/ImageView.swift

+16-1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,21 @@ private struct ImageViewFrameModifier: ViewModifier {
106106
let size: MarkdownImageSize?
107107

108108
func body(content: Content) -> some View {
109-
content.frame(width: size?.width, height: size?.height)
109+
if let size {
110+
switch size.value {
111+
case .fixed(let width, let height):
112+
content.frame(width: width, height: height)
113+
case .relative(let wRatio, _):
114+
if #available(iOS 17.0, *) {
115+
content
116+
// .containerRelativeFrame(.vertical) { height, _ in height * hRatio }
117+
.containerRelativeFrame(.horizontal) { width, _ in width * wRatio }
118+
} else {
119+
content
120+
}
121+
}
122+
} else {
123+
content
124+
}
110125
}
111126
}

0 commit comments

Comments
 (0)