|
1 | 1 | Write HTML using Swift Macros.
|
| 2 | +- [Why?](#why) |
| 3 | +- [Examples](#examples) |
| 4 | + - [Basic](#basic) |
| 5 | + - [Advanced](#advanced) |
| 6 | +- [Benchmarks](#benchmarks) |
2 | 7 |
|
3 | 8 | ## Why?
|
4 | 9 | - Swift Macros are powerful and offer performance benefits
|
5 | 10 | - Alternative libraries may not fit all situations and may restrict how the html is generated/manipulated, prone to human error, or cost a constant performance overhead (middleware, rendering, result builders, etc)
|
6 | 11 | - HTML macros enforce safety, can be used anywhere, and compile directly to strings which are easily manipulated
|
7 | 12 | - The output is minified at no performance cost
|
8 | 13 | ## Examples
|
| 14 | +<style> |
| 15 | + details { padding-left:20px } |
| 16 | + summary { margin-left:-20px } |
| 17 | +</style> |
| 18 | +### Basic |
| 19 | +<details> |
| 20 | +<summary>How do I use this library?</summary> |
| 21 | + |
| 22 | +Syntax: `#<html element>(attributes: [], <element specific attributes>: V?, _ innerHTML: [ExpressibleByStringLiteral])` |
| 23 | +#### Examples |
| 24 | + |
9 | 25 | ```swift
|
| 26 | +// <div class="dark"><p>Macros are beautiful</p></div> |
| 27 | +#div(attributes: [.class(["dark"])], [ |
| 28 | + #p(["Macros are beautiful"]) |
| 29 | +]) |
| 30 | + |
| 31 | +// <a href="https://github.com/RandomHashTags/litleagues" target="_blank"></a> |
| 32 | +#a(href: "https://github.com/RandomHashTags/litleagues", target: ._blank) |
| 33 | + |
| 34 | +// <input id="funny-number" max="420" min="69" name="funny_number" step="1" type="number" value="69"> |
| 35 | +#input( |
| 36 | + attributes: [.id("funny-number")], |
| 37 | + max: 420, |
| 38 | + min: 69, |
| 39 | + name: "funny_number", |
| 40 | + step: 1, |
| 41 | + type: .number, |
| 42 | + value: "69" |
| 43 | +) |
| 44 | + |
| 45 | +// html example |
10 | 46 | let test:String = #html([
|
11 | 47 | #body([
|
12 | 48 | #div(
|
@@ -34,19 +70,83 @@ let test:String = #html([
|
34 | 70 | ])
|
35 | 71 | ])
|
36 | 72 | ```
|
| 73 | +</details> |
| 74 | + |
| 75 | +<details> |
| 76 | +<summary>How do I encode variables?</summary> |
| 77 | +Using String Interpolation. |
| 78 | + |
| 79 | +#### Example |
| 80 | +```swift |
| 81 | +let string:String = "any string value", integer:Int = -69, float:Float = 3.14159 |
| 82 | + |
| 83 | +// ✅ DO |
| 84 | +let _:String = #p(["\(string) \(integer); \(float)"]) |
| 85 | + |
| 86 | +// ❌ DON'T |
| 87 | +let _:String = #p([string, "; ", String(describing: integer), "; ", float.description]) |
| 88 | +``` |
| 89 | + |
| 90 | +</details> |
| 91 | + |
| 92 | +### Advanced |
| 93 | +<details> |
| 94 | +<summary>I need a custom element!</summary> |
| 95 | + |
| 96 | +Use the `#custom(tag:isVoid:attributes:innerHTML:)` macro. |
| 97 | +#### Example |
| 98 | +We want to show the [Apple Pay button](https://developer.apple.com/documentation/apple_pay_on_the_web/displaying_apple_pay_buttons_using_javascript#3783424): |
| 99 | +```swift |
| 100 | +#custom(tag: "apple-pay-button", isVoid: false, attributes: [.custom("buttonstyle", "black"), .custom("type", "buy"), .custom("locale", "el-GR")]) |
| 101 | +``` |
| 102 | +becomes |
| 103 | +```html |
| 104 | +<apple-pay-button buttonstyle="black" type="buy" locale="el-GR"></apple-pay-button> |
| 105 | +``` |
| 106 | + |
| 107 | +</details> |
| 108 | + |
| 109 | +<details> |
| 110 | +<summary>I need a custom attribute!</summary> |
| 111 | + |
| 112 | +Use `HTMLElementAttribute.custom(id:value:)` |
| 113 | +#### Example |
| 114 | +We want to show the [Apple Pay button](https://developer.apple.com/documentation/apple_pay_on_the_web/displaying_apple_pay_buttons_using_javascript#3783424): |
37 | 115 | ```swift
|
38 |
| -func testExample2() { |
39 |
| - var test:TestStruct = TestStruct(name: "one", array: ["1", "2", "3"]) |
40 |
| - XCTAssertEqual(test.html, "<p>one123</p>") |
41 |
| - |
42 |
| - test.name = "two" |
43 |
| - test.array = [4, 5, 6, 7, 8] |
44 |
| - XCTAssertEqual(test.html, "<p>two45678</p>") |
45 |
| -} |
46 |
| -struct TestStruct { |
47 |
| - var name:String |
48 |
| - var array:[CustomStringConvertible] |
49 |
| - |
50 |
| - var html : String { #p(["\(name)", "\(array.map({ "\($0)" }).joined())"]) } |
51 |
| -} |
| 116 | +#custom(tag: "apple-pay-button", isVoid: false, attributes: [.custom("buttonstyle", "black"), .custom("type", "buy"), .custom("locale", "el-GR")]) |
52 | 117 | ```
|
| 118 | +becomes |
| 119 | +```html |
| 120 | +<apple-pay-button buttonstyle="black" type="buy" locale="el-GR"></apple-pay-button> |
| 121 | +``` |
| 122 | + |
| 123 | +</details> |
| 124 | + |
| 125 | +<details> |
| 126 | +<summary>I need to listen for events!</summary> |
| 127 | + |
| 128 | +> <strong>WARNING</strong> |
| 129 | +> |
| 130 | +> Inline event handlers are an outdated way to handle events. |
| 131 | +> |
| 132 | +> General consensus considers this \"bad practice\" and you shouldn't mix your HTML and JavaScript. |
| 133 | +> |
| 134 | +> This remains deprecated to encourage use of other techniques. |
| 135 | +> |
| 136 | +> Learn more at https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#inline_event_handlers_—_dont_use_these. |
| 137 | +
|
| 138 | +Use the `HTMLElementAttribute.event(<type>, "<value>")`. |
| 139 | +#### Example |
| 140 | +```swift |
| 141 | +#div(attributes: [.event(.click, "doThing()"), .event(.change, "doAnotherThing()")]) |
| 142 | +``` |
| 143 | +</details> |
| 144 | + |
| 145 | +## Benchmarks |
| 146 | +<details> |
| 147 | +<summary>Methodology</summary> |
| 148 | +Coming soon |
| 149 | +</details> |
| 150 | + |
| 151 | +## Contributing |
| 152 | +Create a PR. |
0 commit comments