Skip to content

Commit e36301b

Browse files
update README reflecting recent changes, and...
- fixed HTMX attribute behaviors that accept a boolean or the value is empty
1 parent 9479398 commit e36301b

File tree

4 files changed

+115
-16
lines changed

4 files changed

+115
-16
lines changed

README.md

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,16 +103,16 @@ Using String Interpolation.
103103
> You will get a compiler warning saying *interpolation may introduce raw HTML*.
104104
>
105105
> Its up to you whether or not to suppress this warning or escape the HTML at runtime using an method described above.
106+
>
107+
> Swift HTMLKit tries to [replace](https://github.com/RandomHashTags/swift-htmlkit/blob/94793984763308ef5275dd9f71ea0b5e83fea417/Sources/HTMLKitMacros/HTMLElement.swift#L423) known interpolation at compile time with a compile time equivalent for the best performance. It is currently limited due to macro expansions being sandboxed and lexical contexts/AST not being available for macro arguments. This means referencing content known at compile time in a html macro won't get replaced by its literal contents. [Read more about this limitation](https://forums.swift.org/t/swift-lexical-lookup-for-referenced-stuff-located-outside-scope-current-file/75776/6).
106108
107109
#### Example
108110
```swift
109-
let string:String = "any string value", integer:Int = -69, float:Float = 3.14159
111+
let string:String = "any string value", integer:Int = -69, float:Float = 3.141592
110112

111-
// ✅ DO
112113
let _:String = #p("\(string); \(integer); \(float)")
113114
let _:String = #p("\(string)", "; ", String(describing: integer), "; ", float.description)
114-
115-
// ❌ DON'T; compiler error: String Interpolation required
115+
// the below also works
116116
let integer_string:String = String(describing: integer), float_string:String = String(describing: float)
117117
let _:String = #p(string, "; ", integer_string, "; ", float_string)
118118

@@ -186,6 +186,46 @@ Use a different html macro. Currently supported types (more to come with new lan
186186

187187
</details>
188188

189+
### HTMX
190+
191+
<details>
192+
193+
<summary>How do I use HTMX?</summary>
194+
195+
Use the `.htmx(<htmx attribute>)` global attribute. All HTMX 2.0 attributes are supported (including web socket).
196+
197+
#### Examples
198+
```swift
199+
200+
// <div hx-boost="true"></div>
201+
var string:StaticString = #div(attributes: [.htmx(.boost(.true))])
202+
203+
// <div hx-get="/test"></div>
204+
string = #div(attributes: [.htmx(.get("/test"))])
205+
206+
// <div hx-on::abort="bruh()"></div>
207+
string = #div(attributes: [.htmx(.on(.abort, "bruh()"))])
208+
209+
// <div hx-on::after-on-load="test()"></div>
210+
string = #div(attributes: [.htmx(.on(.afterOnLoad, "test()"))])
211+
212+
// <div hx-on:click="thing()"></div>
213+
string = #div(attributes: [.htmx(.onevent(.click, "thing()"))])
214+
215+
// <div hx-preserve></div>
216+
string = #div(attributes: [.htmx(.preserve(true))])
217+
218+
// <div ws-connect="/chatroom"></div>
219+
string = #div(attributes: [.htmx(.ws(.connect("/chatroom")))])
220+
221+
// <div hx-ext="ws" ws-send></div>
222+
string = #div(attributes: [.htmx(.ext("ws")), .htmx(.ws(.send(true)))])
223+
224+
```
225+
226+
</details>
227+
228+
189229
## Benchmarks
190230
- Libraries tested
191231
- [BinaryBuilds/swift-html](https://github.com/BinaryBirds/swift-html) v1.7.0 (patched version [here](https://github.com/RandomHashTags/fork-bb-swift-html))

Sources/HTMLKitMacros/HTMLElement.swift

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,18 +186,40 @@ private extension HTMLElement {
186186
if let htmx:HTMLElementAttribute.HTMX = HTMLElementAttribute.HTMX(rawValue: string) {
187187
key = "hx-" + htmx.key
188188
let htmlValue:String = htmx.htmlValue
189-
var delimiter:String = "\\\""
189+
var delimiter:String = "\\\"", isBoolean:Bool = false
190+
func check_boolean(_ boolean: Bool) {
191+
isBoolean = true
192+
if !boolean {
193+
value = ""
194+
}
195+
}
190196
switch htmx {
197+
case .disable(let boolean),
198+
.historyElt(let boolean),
199+
.preserve(let boolean):
200+
check_boolean(boolean)
201+
break
191202
case .request(_, _, _, _), .headers(_, _):
192203
delimiter = "'"
193204
break
194-
case .ws(let value):
195-
key = "ws-" + value.key
205+
case .ws(let ws_value):
206+
key = "ws-" + ws_value.key
207+
switch ws_value {
208+
case .send(let boolean):
209+
check_boolean(boolean)
210+
break
211+
default:
212+
break
213+
}
196214
break
197215
default:
198216
break
199217
}
200-
value = key + (htmlValue.isEmpty ? "" : "=" + delimiter + htmlValue + delimiter)
218+
if isBoolean {
219+
value = value == nil || !value.isEmpty ? key : nil // only allow the value to be added if the boolean value is true
220+
} else {
221+
value = key + "=" + delimiter + htmlValue + delimiter
222+
}
201223
}
202224
} else if let string:String = parse_attribute(context: context, elementType: elementType, key: key, expression: first_expression, lookupFiles: lookupFiles) {
203225
value = string

Sources/HTMLKitUtilities/HTMX.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ public extension HTMLElementAttribute.HTMX {
510510
public extension HTMLElementAttribute.HTMX {
511511
enum WebSocket {
512512
case connect(String)
513-
case send(String)
513+
case send(Bool)
514514

515515
public init?(rawValue: String) {
516516
guard rawValue.last == ")" else { return nil }
@@ -519,9 +519,12 @@ public extension HTMLElementAttribute.HTMX {
519519
func string() -> String {
520520
return String(rawValue[rawValue.index(start, offsetBy: key.count + 2)..<end_minus_one])
521521
}
522+
func boolean() -> Bool {
523+
return rawValue[rawValue.index(start, offsetBy: key.count + 1)..<end] == "true"
524+
}
522525
switch key {
523526
case "connect": self = .connect(string())
524-
case "send": self = .send(string())
527+
case "send": self = .send(boolean())
525528
default: return nil
526529
}
527530
}
@@ -536,7 +539,7 @@ public extension HTMLElementAttribute.HTMX {
536539
public var htmlValue : String {
537540
switch self {
538541
case .connect(let value): return value
539-
case .send(let value): return value
542+
case .send(_): return ""
540543
}
541544
}
542545

Tests/HTMLKitTests/HTMXTests.swift

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Testing
99
import HTMLKit
1010

1111
struct HTMXTests {
12+
// MARK: boost
1213
@Test func boost() {
1314
var string:StaticString = #div(attributes: [.htmx(.boost(.true))])
1415
#expect(string == "<div hx-boost=\"true\"></div>")
@@ -17,10 +18,22 @@ struct HTMXTests {
1718
#expect(string == "<div hx-boost=\"false\"></div>")
1819
}
1920

21+
// MARK: disable
22+
@Test func disable() {
23+
var string:StaticString = #div(attributes: [.htmx(.disable(true))])
24+
#expect(string == "<div hx-disable></div>")
25+
26+
string = #div(attributes: [.htmx(.disable(false))])
27+
#expect(string == "<div></div>")
28+
}
29+
2030
// MARK: get
2131
@Test func get() {
22-
let string:StaticString = #div(attributes: [.htmx(.get("/test"))])
32+
var string:StaticString = #div(attributes: [.htmx(.get("/test"))])
2333
#expect(string == "<div hx-get=\"/test\"></div>")
34+
35+
string = #div(attributes: [.htmx(.get(""))])
36+
#expect(string == "<div hx-get=\"\"></div>")
2437
}
2538

2639
// MARK: headers
@@ -66,6 +79,15 @@ struct HTMXTests {
6679
return set
6780
}
6881

82+
// MARK: history-elt
83+
@Test func historyElt() {
84+
var string:StaticString = #div(attributes: [.htmx(.historyElt(true))])
85+
#expect(string == "<div hx-history-elt></div>")
86+
87+
string = #div(attributes: [.htmx(.historyElt(false))])
88+
#expect(string == "<div></div>")
89+
}
90+
6991
// MARK: on
7092
@Test func on() {
7193
var string:StaticString = #div(attributes: [.htmx(.on(.abort, "bruh"))])
@@ -90,6 +112,15 @@ struct HTMXTests {
90112
#expect(string == "<div hx-post=\"https://github.com/RandomHashTags\"></div>")
91113
}
92114

115+
// MARK: preserve
116+
@Test func preserve() {
117+
var string:StaticString = #div(attributes: [.htmx(.preserve(true))])
118+
#expect(string == "<div hx-preserve></div>")
119+
120+
string = #div(attributes: [.htmx(.preserve(false))])
121+
#expect(string == "<div></div>")
122+
}
123+
93124
// MARK: replaceURL
94125
@Test func replaceURL() {
95126
var string:StaticString = #div(attributes: [.htmx(.replaceURL(.true))])
@@ -125,10 +156,13 @@ struct HTMXTests {
125156

126157
// MARK: ws
127158
@Test func ws() {
128-
var string:StaticString = #div(attributes: [.htmx(.ws(.connect("https://paradigm-app.com")))])
129-
#expect(string == "<div ws-connect=\"https://paradigm-app.com\"></div>")
159+
var string:StaticString = #div(attributes: [.htmx(.ws(.connect("/chatroom")))])
160+
#expect(string == "<div ws-connect=\"/chatroom\"></div>")
161+
162+
string = #div(attributes: [.htmx(.ext("ws")), .htmx(.ws(.send(true)))])
163+
#expect(string == "<div hx-ext=\"ws\" ws-send></div>")
130164

131-
string = #div(attributes: [.htmx(.ext("ws")), .htmx(.ws(.send("https://linktr.ee/anderson_evan")))])
132-
#expect(string == "<div hx-ext=\"ws\" ws-send=\"https://linktr.ee/anderson_evan\"></div>")
165+
string = #div(attributes: [.htmx(.ext("ws")), .htmx(.ws(.send(false)))])
166+
#expect(string == "<div hx-ext=\"ws\"></div>")
133167
}
134168
}

0 commit comments

Comments
 (0)