Skip to content

Commit 0984876

Browse files
added support for css pixels for height and width attributes
1 parent 1a9e5a9 commit 0984876

File tree

3 files changed

+87
-34
lines changed

3 files changed

+87
-34
lines changed

Sources/HTMLKit/HTMLKit.swift

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77

88
import HTMLKitMacros
99

10-
// TODO: fix some `height` & `width` value types (they're CSS pixels, not only integers) | change some to `String` or allow overloads
11-
1210
// MARK: Elements
1311
@freestanding(expression)
1412
public macro html(xmlns: String? = nil, _ innerHTML: [String]) -> String = #externalMacro(module: "HTMLKitMacros", type: "HTMLElement")
@@ -142,8 +140,8 @@ public macro button(
142140
@freestanding(expression)
143141
public macro canvas(
144142
attributes: Set<HTMLElementAttribute> = [],
145-
height: Int? = nil,
146-
width: Int? = nil,
143+
height: HTMLElementAttribute.CSSUnit? = nil,
144+
width: HTMLElementAttribute.CSSUnit? = nil,
147145
_ innerHTML: [String] = []
148146
) -> String = #externalMacro(module: "HTMLKitMacros", type: "HTMLElement")
149147

@@ -226,10 +224,10 @@ public macro em(attributes: Set<HTMLElementAttribute> = [], _ innerHTML: [String
226224
@freestanding(expression)
227225
public macro embed(
228226
attributes: Set<HTMLElementAttribute> = [],
229-
height: Int? = nil,
227+
height: HTMLElementAttribute.CSSUnit? = nil,
230228
src: String? = nil,
231229
type: String? = nil,
232-
width: Int? = nil,
230+
width: HTMLElementAttribute.CSSUnit? = nil,
233231
_ innerHTML: [String] = []
234232
) -> String = #externalMacro(module: "HTMLKitMacros", type: "HTMLElement")
235233

@@ -314,14 +312,14 @@ public macro iframe(
314312
browsingtopics: Bool = false,
315313
credentialless: Bool = false,
316314
csp: String? = nil,
317-
height: Int? = nil,
315+
height: HTMLElementAttribute.CSSUnit? = nil,
318316
loading: HTMLElementAttribute.Loading? = nil,
319317
name: String? = nil,
320318
referrerpolicy: HTMLElementAttribute.ReferrerPolicy? = nil,
321319
sandbox: [HTMLElementAttribute.Iframe.Sandbox] = [],
322320
src: String? = nil,
323321
srcdoc: String? = nil,
324-
width: Int? = nil,
322+
width: HTMLElementAttribute.CSSUnit? = nil,
325323
_ innerHTML: [String] = []
326324
) -> String = #externalMacro(module: "HTMLKitMacros", type: "HTMLElement")
327325

@@ -334,14 +332,14 @@ public macro img(
334332
decoding: HTMLElementAttribute.Decoding? = nil,
335333
elementtiming: String? = nil,
336334
fetchpriority: HTMLElementAttribute.FetchPriority? = nil,
337-
height: Int? = nil,
335+
height: HTMLElementAttribute.CSSUnit? = nil,
338336
ismap: Bool = false,
339337
loading: HTMLElementAttribute.Loading? = nil,
340338
referrerpolicy: HTMLElementAttribute.ReferrerPolicy? = nil,
341339
sizes: [String] = [],
342340
src: String? = nil,
343341
srcset: [String] = [],
344-
width: Int? = nil,
342+
width: HTMLElementAttribute.CSSUnit? = nil,
345343
usemap: String? = nil,
346344
_ innerHTML: [String] = []
347345
) -> String = #externalMacro(module: "HTMLKitMacros", type: "HTMLElement")
@@ -362,7 +360,7 @@ public macro input(
362360
formmethod: HTMLElementAttribute.FormMethod? = nil,
363361
formnovalidate: Bool = false,
364362
formtarget: HTMLElementAttribute.FormTarget? = nil,
365-
height: Int? = nil,
363+
height: HTMLElementAttribute.CSSUnit? = nil,
366364
list: String? = nil,
367365
max: Int? = nil,
368366
maxlength: Int? = nil,
@@ -381,7 +379,7 @@ public macro input(
381379
step: Float? = nil,
382380
type: HTMLElementAttribute.InputMode? = nil,
383381
value: String? = nil,
384-
width: Int? = nil,
382+
width: HTMLElementAttribute.CSSUnit? = nil,
385383
_ innerHTML: [String] = []
386384
) -> String = #externalMacro(module: "HTMLKitMacros", type: "HTMLElement")
387385

@@ -487,10 +485,10 @@ public macro noscript(attributes: Set<HTMLElementAttribute> = [], _ innerHTML: [
487485
public macro object(
488486
attributes: Set<HTMLElementAttribute> = [],
489487
form: String? = nil,
490-
height: Int? = nil,
488+
height: HTMLElementAttribute.CSSUnit? = nil,
491489
name: String? = nil,
492490
type: String? = nil,
493-
width: Int? = nil,
491+
width: HTMLElementAttribute.CSSUnit? = nil,
494492
_ innerHTML: [String] = []
495493
) -> String = #externalMacro(module: "HTMLKitMacros", type: "HTMLElement")
496494

@@ -770,22 +768,21 @@ public macro video(
770768
crossorigin: HTMLElementAttribute.CrossOrigin? = nil,
771769
disablepictureinpicture: Bool = false,
772770
disableremoteplayback: Bool = false,
773-
height: Int? = nil,
771+
height: HTMLElementAttribute.CSSUnit? = nil,
774772
loop: Bool = false,
775773
muted: Bool = false,
776774
playsinline: Bool = true,
777775
poster: String? = nil,
778776
preload: HTMLElementAttribute.Preload? = nil,
779777
src: String? = nil,
780-
width: Int? = nil,
778+
width: HTMLElementAttribute.CSSUnit? = nil,
781779
_ innerHTML: [String] = []
782780
) -> String = #externalMacro(module: "HTMLKitMacros", type: "HTMLElement")
783781

784782
// MARK: W
785783
@freestanding(expression)
786784
public macro wbr(attributes: Set<HTMLElementAttribute> = [], _ innerHTML: [String] = []) -> String = #externalMacro(module: "HTMLKitMacros", type: "HTMLElement")
787785

788-
789786
// MARK: HTMLElementAttribute
790787
public struct HTMLElementAttribute : Hashable {
791788
public let id:String
@@ -795,6 +792,50 @@ public struct HTMLElementAttribute : Hashable {
795792
}
796793
}
797794

795+
// MARK: CSSUnit
796+
public extension HTMLElementAttribute {
797+
struct CSSUnit : CustomStringConvertible {
798+
let string:String
799+
init(_ string: String) {
800+
self.string = string
801+
}
802+
public var description : String { string }
803+
}
804+
}
805+
public extension HTMLElementAttribute.CSSUnit { // https://www.w3schools.com/cssref/css_units.php
806+
// absolute
807+
static func centimeters(_ value: Float) -> Self { Self("\(value)cm") }
808+
static func millimeters(_ value: Float) -> Self { Self("\(value)mm") }
809+
/// 1 inch = 96px = 2.54cm
810+
static func inches(_ value: Float) -> Self { Self("\(value)in") }
811+
/// 1 pixel = 1/96th of 1inch
812+
static func pixels(_ value: Float) -> Self { Self("\(value)px") }
813+
/// 1 point = 1/72 of 1inch
814+
static func points(_ value: Float) -> Self { Self("\(value)pt") }
815+
/// 1 pica = 12 points
816+
static func picas(_ value: Float) -> Self { Self("\(value)pc") }
817+
818+
// relative
819+
/// Relative to the font-size of the element (2em means 2 times the size of the current font)
820+
static func em(_ value: Float) -> Self { Self("\(value)em") }
821+
/// Relative to the x-height of the current font (rarely used)
822+
static func ex(_ value: Float) -> Self { Self("\(value)ex") }
823+
/// Relative to the width of the "0" (zero)
824+
static func ch(_ value: Float) -> Self { Self("\(value)ch") }
825+
/// Relative to font-size of the root element
826+
static func rem(_ value: Float) -> Self { Self("\(value)rem") }
827+
/// Relative to 1% of the width of the viewport
828+
static func viewportWidth(_ value: Float) -> Self { Self("\(value)vw") }
829+
/// Relative to 1% of the height of the viewport
830+
static func viewportHeight(_ value: Float) -> Self { Self("\(value)vh") }
831+
/// Relative to 1% of viewport's smaller dimension
832+
static func viewportMin(_ value: Float) -> Self { Self("\(value)vmin") }
833+
/// Relative to 1% of viewport's larger dimension
834+
static func viewportMax(_ value: Float) -> Self { Self("\(value)vmax") }
835+
/// Relative to the parent element
836+
static func percent(_ value: Float) -> Self { Self("\(value)%") }
837+
}
838+
798839
// MARK: Global Attributes
799840
public extension HTMLElementAttribute {
800841
static func accesskey(_ value: String) -> Self { Self("accesskey") }

Sources/HTMLKitMacros/HTMLElement.swift

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ extension HTMLElement {
3535
if let child:LabeledExprSyntax = element.as(LabeledExprSyntax.self) {
3636
if let key:String = child.label?.text {
3737
switch key {
38-
case "attributes":
39-
attributes = parse_attributes(child: child)
40-
break
41-
default: // extra attribute
42-
if let string:String = parse_extra_attribute(elementType: elementType, child: child) {
43-
attributes.append(string)
44-
}
45-
break
38+
case "attributes":
39+
attributes = parse_attributes(child: child)
40+
break
41+
default: // extra attribute
42+
if let string:String = parse_extra_attribute(elementType: elementType, child: child) {
43+
attributes.append(string)
44+
}
45+
break
4646
}
4747
} else { // inner html
4848
innerHTML = parse_inner_html(child: child)
@@ -174,21 +174,26 @@ private extension HTMLElement {
174174
func yup(_ value: String) -> String {
175175
return key + "=\\\"" + value + "\\\""
176176
}
177+
func member(_ value: String) -> String {
178+
let inner:String
179+
if elementType == .input && key == "type" {
180+
inner = "InputMode"
181+
} else if key == "height" || key == "width" {
182+
inner = "CSSUnit"
183+
} else {
184+
inner = key[key.startIndex].uppercased() + key[key.index(after: key.startIndex)...]
185+
}
186+
return yup("\\(HTMLElementAttribute." + inner + value + ")")
187+
}
177188
let expression:ExprSyntax = child.expression
178189
if let boolean:String = expression.as(BooleanLiteralExprSyntax.self)?.literal.text {
179190
return boolean.elementsEqual("true") ? key : nil
180191
}
181192
if let string:String = expression.as(StringLiteralExprSyntax.self)?.string {
182193
return yup(string)
183194
}
184-
if let member:String = expression.as(MemberAccessExprSyntax.self)?.declName.baseName.text {
185-
let inner:String
186-
if elementType == .input && key == "type" {
187-
inner = "InputMode"
188-
} else {
189-
inner = key[key.startIndex].uppercased() + key[key.index(after: key.startIndex)...]
190-
}
191-
return yup("\\(HTMLElementAttribute." + inner + "." + member + ")")
195+
if let value:String = expression.as(MemberAccessExprSyntax.self)?.declName.baseName.text {
196+
return member("." + value)
192197
}
193198
if let _:NilLiteralExprSyntax = expression.as(NilLiteralExprSyntax.self) {
194199
return nil
@@ -199,6 +204,9 @@ private extension HTMLElement {
199204
if let float:String = expression.as(FloatLiteralExprSyntax.self)?.literal.text {
200205
return yup(float)
201206
}
207+
if let function:FunctionCallExprSyntax = expression.as(FunctionCallExprSyntax.self) {
208+
return member("\(function)")
209+
}
202210
return nil
203211
}
204212
}

Tests/HTMLKitTests/HTMLKitTests.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ extension HTMLKitTests {
1818
XCTAssertEqual(#html([]), "<!DOCTYPE html><html></html>")
1919
XCTAssertEqual(#html(xmlns: "test", []), "<!DOCTYPE html><html xmlns=\"test\"></html>")
2020
}
21+
func test_element_canvas() {
22+
XCTAssertEqual(#canvas(height: .percent(4), width: .em(2.69)), "<canvas height=\"4.0%\" width=\"2.69em\"></canvas>")
23+
}
2124
func test_element_input() {
2225
let string:String = #input(type: .text)
2326
XCTAssertEqual(string, "<input type=\"text\">")
@@ -66,11 +69,12 @@ extension HTMLKitTests {
6669
#div(),
6770
#button(disabled: true),
6871
#video(autoplay: true, controls: false, height: nil, preload: .auto, src: "ezclap", width: 5),
72+
#video(autoplay: true, controls: false, height: nil, preload: .auto, src: "ezclap", width: "1cm"),
6973
]
7074
)
7175
])
7276
])
73-
XCTAssertEqual(test, "<!DOCTYPE html><html><body><div class=\"bing bong\" title=\"just seeing what blow's\" draggable=\"false\" inputmode=\"email\" hidden=\"hidden\">poggies<div></div><a><div><abbr></abbr></div><address></address></a><div></div><button disabled></button><video autoplay preload=\"auto\" src=\"ezclap\" width=\"5\"></video></div></body></html>")
77+
XCTAssertEqual(test, "<!DOCTYPE html><html><body><div class=\"bing bong\" title=\"just seeing what blow's\" draggable=\"false\" inputmode=\"email\" hidden=\"hidden\">poggies<div></div><a><div><abbr></abbr></div><address></address></a><div></div><button disabled></button><video autoplay preload=\"auto\" src=\"ezclap\" width=\"5\"></video><video autoplay preload=\"auto\" src=\"ezclap\" width=\"1cm\"></video></div></body></html>")
7478
}
7579
}
7680

0 commit comments

Comments
 (0)