From 4295f5cd1a2d95b74518f5c5c15cf993aa5992dc Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Mon, 6 Jul 2026 21:27:46 +0200 Subject: [PATCH 1/5] Revise the download attribute --- .../Attributes/ContentAttributes.swift | 54 +++++++++++++++++-- .../Abstraction/Elements/BodyElements.swift | 22 +++++++- .../Abstraction/Elements/MapElements.swift | 22 +++++++- Tests/HTMLKitTests/AttributesTests.swift | 30 +++++++++-- 4 files changed, 117 insertions(+), 11 deletions(-) diff --git a/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift b/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift index b7bb6c79..ae2c8849 100644 --- a/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift +++ b/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift @@ -982,16 +982,62 @@ extension DisabledAttribute where Self: EmptyNode { public protocol DownloadAttribute: Attribute { /// Mark the target as downloadable. - /// + /// /// ```swift /// Anchor { /// "Lorem ipsum..." /// } - /// .download() + /// .download(true) /// ``` - /// + /// + /// - Parameter condition: Whether the target is downloadable. + /// + /// - Returns: The element + func download(_ condition: Bool) -> Self + + /// Mark the target as downloadable. + /// + /// ```swift + /// Anchor { + /// "Lorem ipsum..." + /// } + /// .download("filename") + /// ``` + /// + /// - Parameter value: The name to label the download. + /// + /// - Returns: The element + func download(_ name: String) -> Self + + /// Mark the target as downloadable. + /// + /// ```swift + /// Anchor { + /// "Lorem ipsum..." + /// } + /// .download("filename") + /// ``` + /// + /// - Parameters: + /// - localizedKey: The string key to be translated. + /// - tableName: The translation table to look in. + /// + /// - Returns: The element + func download(_ localizedKey: LocalizedStringKey, tableName: String?) -> Self + + /// Mark the target as downloadable. + /// + /// ```swift + /// Anchor { + /// "Lorem ipsum..." + /// } + /// .download("filename") + /// ``` + /// + /// - Parameter value: The name to label the download. + /// /// - Returns: The element - func download() -> Self + func download(verbatim name: String) -> Self } extension DownloadAttribute where Self: ContentNode { diff --git a/Sources/HTMLKit/Abstraction/Elements/BodyElements.swift b/Sources/HTMLKit/Abstraction/Elements/BodyElements.swift index 10104f52..569bda4c 100644 --- a/Sources/HTMLKit/Abstraction/Elements/BodyElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/BodyElements.swift @@ -12574,8 +12574,26 @@ extension Anchor: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } - public func download() -> Anchor { - return mutate(download: .init("download", context: .trusted)) + public func download(_ condition: Bool = true) -> Anchor { + + if condition { + return mutate(download: .init("download", context: .trusted)) + } + + return self + } + + @_disfavoredOverload + public func download(_ name: String) -> Anchor { + return mutate(download: .init(name, context: .tainted(.html))) + } + + public func download(_ localizedKey: LocalizedStringKey, tableName: String?) -> Anchor { + return mutate(download: .init(LocalizedString(key: localizedKey, table: tableName), context: .tainted(.html))) + } + + public func download(verbatim name: String) -> Anchor { + return mutate(download: .init(name, context: .tainted(.html))) } public func reference(_ value: String) -> Anchor { diff --git a/Sources/HTMLKit/Abstraction/Elements/MapElements.swift b/Sources/HTMLKit/Abstraction/Elements/MapElements.swift index 35056de5..60590fda 100644 --- a/Sources/HTMLKit/Abstraction/Elements/MapElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/MapElements.swift @@ -291,8 +291,26 @@ extension Area: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return mutate(target: .init(value.rawValue, context: .trusted)) } - public func download() -> Area { - return mutate(download: .init("download", context: .trusted)) + public func download(_ condition: Bool = true) -> Area { + + if condition { + return mutate(download: .init("download", context: .trusted)) + } + + return self + } + + @_disfavoredOverload + public func download(_ name: String) -> Area { + return mutate(download: .init(name, context: .tainted(.html))) + } + + public func download(_ localizedKey: LocalizedStringKey, tableName: String?) -> Area { + return mutate(download: .init(LocalizedString(key: localizedKey, table: tableName), context: .tainted(.html))) + } + + public func download(verbatim name: String) -> Area { + return mutate(download: .init(name, context: .tainted(.html))) } public func ping(_ value: String) -> Area { diff --git a/Tests/HTMLKitTests/AttributesTests.swift b/Tests/HTMLKitTests/AttributesTests.swift index aafc46bf..57c97d95 100644 --- a/Tests/HTMLKitTests/AttributesTests.swift +++ b/Tests/HTMLKitTests/AttributesTests.swift @@ -319,8 +319,26 @@ final class AttributesTests: XCTestCase { return self } - func download() -> Tag { - return self.mutate(download: .init("download", context: .trusted)) + func download(_ condition: Bool = true) -> Tag { + + if condition { + return self.mutate(download: .init("download", context: .trusted)) + } + + return self + } + + @_disfavoredOverload + func download(_ name: String) -> Tag { + return self.mutate(download: .init(name, context: .tainted(.html))) + } + + func download(_ localizedKey: LocalizedStringKey, tableName: String?) -> Tag { + return self.mutate(download: .init(LocalizedString(key: localizedKey, table: tableName), context: .tainted(.html))) + } + + func download(verbatim name: String) -> Tag { + return self.mutate(download: .init(name, context: .tainted(.html))) } func encoding(_ value: Values.Encoding) -> Tag { @@ -1722,11 +1740,17 @@ final class AttributesTests: XCTestCase { let view = TestView { Tag {}.download() + Tag {}.download(false) + Tag {}.download(true) + Tag {}.download("filename") } XCTAssertEqual(try renderer.render(view: view), """ - + \ + \ + \ + """ ) } From 3ae603c0911802aa4757781730c9954c30afde7a Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Wed, 8 Jul 2026 22:31:45 +0200 Subject: [PATCH 2/5] Revise the hidden attribute --- .../Attributes/ContentAttributes.swift | 14 + .../Abstraction/Elements/BasicElements.swift | 4 + .../Abstraction/Elements/BodyElements.swift | 306 +++++++++++++++++- .../Elements/DefinitionElements.swift | 8 + .../Abstraction/Elements/FigureElements.swift | 4 + .../Abstraction/Elements/FormElements.swift | 24 ++ .../Abstraction/Elements/HeadElements.swift | 20 ++ .../Abstraction/Elements/HtmlElements.swift | 8 + .../Abstraction/Elements/InputElements.swift | 16 + .../Abstraction/Elements/ListElements.swift | 4 + .../Abstraction/Elements/MapElements.swift | 4 + .../Abstraction/Elements/MediaElements.swift | 8 + .../Abstraction/Elements/RubyElements.swift | 8 + .../Abstraction/Elements/TableElements.swift | 36 +++ .../Abstraction/Tokens/ValueTokens.swift | 13 + Tests/HTMLKitTests/AttributesTests.swift | 11 +- 16 files changed, 483 insertions(+), 5 deletions(-) diff --git a/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift b/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift index ae2c8849..967f4660 100644 --- a/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift +++ b/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift @@ -1380,6 +1380,20 @@ public protocol HiddenAttribute: Attribute { /// /// - Returns: The element func hidden(_ condition: Bool) -> Self + + /// Hide an element. + /// + /// ```swift + /// Paragraph { + /// "Lorem ipsum..." + /// } + /// .hidden(.untilFound) + /// ``` + /// + /// - Parameter value: The condition under which to hide the element. + /// + /// - Returns: The element + func hidden(_ value: Values.Condition) -> Self } extension HiddenAttribute where Self: ContentNode { diff --git a/Sources/HTMLKit/Abstraction/Elements/BasicElements.swift b/Sources/HTMLKit/Abstraction/Elements/BasicElements.swift index d3470bf9..08d5ebf7 100644 --- a/Sources/HTMLKit/Abstraction/Elements/BasicElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/BasicElements.swift @@ -195,6 +195,10 @@ extension Html: GlobalContentAttributes, GlobalEventAttributes { return self } + public func hidden(_ value: Values.Condition) -> Html { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Html { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } diff --git a/Sources/HTMLKit/Abstraction/Elements/BodyElements.swift b/Sources/HTMLKit/Abstraction/Elements/BodyElements.swift index 569bda4c..308dc85d 100644 --- a/Sources/HTMLKit/Abstraction/Elements/BodyElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/BodyElements.swift @@ -281,6 +281,10 @@ extension Article: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessi return self } + public func hidden(_ value: Values.Condition) -> Article { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Article { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -819,6 +823,10 @@ extension Section: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessi return self } + public func hidden(_ value: Values.Condition) -> Section { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Section { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -1359,6 +1367,10 @@ extension Navigation: GlobalContentAttributes, GlobalEventAttributes, GlobalAcce return self } + public func hidden(_ value: Values.Condition) -> Navigation { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Navigation { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -1894,6 +1906,10 @@ extension Aside: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibi return self } + + public func hidden(_ value: Values.Condition) -> Aside { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Aside { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -2428,6 +2444,10 @@ extension Heading1: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> Heading1 { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Heading1 { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -2969,6 +2989,10 @@ extension Heading2: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> Heading2 { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Heading2 { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -3511,6 +3535,10 @@ extension Heading3: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> Heading3 { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Heading3 { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -4053,6 +4081,10 @@ extension Heading4: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> Heading4 { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Heading4 { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -4595,6 +4627,10 @@ extension Heading5: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> Heading5 { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Heading5 { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -5137,6 +5173,10 @@ extension Heading6: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> Heading6 { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Heading6 { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -5683,6 +5723,10 @@ extension HeadingGroup: GlobalContentAttributes, GlobalEventAttributes, GlobalAc return self } + + public func hidden(_ value: Values.Condition) -> HeadingGroup { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> HeadingGroup { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -6218,6 +6262,10 @@ extension Header: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + public func hidden(_ value: Values.Condition) -> Header { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Header { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -6750,6 +6798,10 @@ extension Footer: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + public func hidden(_ value: Values.Condition) -> Footer { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Footer { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -7289,6 +7341,10 @@ extension Address: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessi return self } + public func hidden(_ value: Values.Condition) -> Address { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Address { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -7822,6 +7878,10 @@ extension Paragraph: GlobalContentAttributes, GlobalEventAttributes, GlobalAcces return self } + public func hidden(_ value: Values.Condition) -> Paragraph { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Paragraph { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -8359,6 +8419,10 @@ extension HorizontalRule: GlobalContentAttributes, GlobalEventAttributes, Global return self } + public func hidden(_ value: Values.Condition) -> HorizontalRule { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> HorizontalRule { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -8898,6 +8962,10 @@ extension PreformattedText: GlobalContentAttributes, GlobalEventAttributes, Glob return self } + public func hidden(_ value: Values.Condition) -> PreformattedText { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> PreformattedText { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -9430,6 +9498,10 @@ extension Blockquote: GlobalContentAttributes, GlobalEventAttributes, GlobalAcce return self } + + public func hidden(_ value: Values.Condition) -> Blockquote { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Blockquote { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -9982,6 +10054,10 @@ extension OrderedList: GlobalContentAttributes, GlobalEventAttributes, GlobalAcc return self } + public func hidden(_ value: Values.Condition) -> OrderedList { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> OrderedList { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -10535,6 +10611,10 @@ extension UnorderedList: GlobalContentAttributes, GlobalEventAttributes, GlobalA return self } + public func hidden(_ value: Values.Condition) -> UnorderedList { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> UnorderedList { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -11086,6 +11166,10 @@ extension Menu: GlobalContentAttributes { return self } + public func hidden(_ value: Values.Condition) -> Menu { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Menu { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -11376,6 +11460,10 @@ extension DescriptionList: GlobalContentAttributes, GlobalEventAttributes, Globa return self } + public func hidden(_ value: Values.Condition) -> DescriptionList { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> DescriptionList { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -11914,6 +12002,10 @@ extension Figure: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + public func hidden(_ value: Values.Condition) -> Figure { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Figure { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -12449,6 +12541,10 @@ extension Anchor: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + public func hidden(_ value: Values.Condition) -> Anchor { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Anchor { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -13054,6 +13150,10 @@ extension Emphasize: GlobalContentAttributes, GlobalEventAttributes, GlobalAcces return self } + + public func hidden(_ value: Values.Condition) -> Emphasize { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Emphasize { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -13589,6 +13689,10 @@ extension Strong: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + + public func hidden(_ value: Values.Condition) -> Strong { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Strong { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -14125,6 +14229,10 @@ extension Small: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibi return self } + public func hidden(_ value: Values.Condition) -> Small { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Small { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -14669,6 +14777,10 @@ extension StrikeThrough: GlobalContentAttributes, GlobalEventAttributes { return self } + public func hidden(_ value: Values.Condition) -> StrikeThrough { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> StrikeThrough { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -14990,6 +15102,10 @@ extension Main: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return self } + + public func hidden(_ value: Values.Condition) -> Main { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Main { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -15531,6 +15647,10 @@ extension Search: GlobalContentAttributes { return self } + public func hidden(_ value: Values.Condition) -> Search { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Search { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -15814,6 +15934,10 @@ extension Division: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> Division { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Division { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -16477,6 +16601,10 @@ extension Definition: GlobalContentAttributes, GlobalEventAttributes, GlobalAcce return self } + public func hidden(_ value: Values.Condition) -> Definition { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Definition { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -17013,6 +17141,10 @@ extension Cite: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return self } + public func hidden(_ value: Values.Condition) -> Cite { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Cite { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -17548,6 +17680,10 @@ extension ShortQuote: GlobalContentAttributes, GlobalEventAttributes, GlobalAcce return self } + public func hidden(_ value: Values.Condition) -> ShortQuote { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> ShortQuote { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -18088,6 +18224,10 @@ extension Abbreviation: GlobalContentAttributes, GlobalEventAttributes, GlobalAc return self } + public func hidden(_ value: Values.Condition) -> Abbreviation { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Abbreviation { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -18624,6 +18764,10 @@ extension Ruby: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return self } + public func hidden(_ value: Values.Condition) -> Ruby { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Ruby { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -19162,6 +19306,10 @@ extension Data: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return self } + public func hidden(_ value: Values.Condition) -> Data { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Data { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -19712,6 +19860,10 @@ extension Time: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return self } + public func hidden(_ value: Values.Condition) -> Time { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Time { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -20252,6 +20404,10 @@ extension Code: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return self } + + public func hidden(_ value: Values.Condition) -> Code { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Code { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -20790,6 +20946,10 @@ extension Variable: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> Variable { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Variable { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -21322,6 +21482,10 @@ extension SampleOutput: GlobalContentAttributes, GlobalEventAttributes, GlobalAc return self } + + public func hidden(_ value: Values.Condition) -> SampleOutput { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> SampleOutput { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -21860,6 +22024,10 @@ extension KeyboardInput: GlobalContentAttributes, GlobalEventAttributes, GlobalA return self } + public func hidden(_ value: Values.Condition) -> KeyboardInput { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> KeyboardInput { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -22397,6 +22565,10 @@ extension Subscript: GlobalContentAttributes, GlobalEventAttributes, GlobalAcces return self } + public func hidden(_ value: Values.Condition) -> Subscript { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Subscript { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -22933,6 +23105,10 @@ extension Superscript: GlobalContentAttributes, GlobalEventAttributes, GlobalAcc return self } + public func hidden(_ value: Values.Condition) -> Superscript { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Superscript { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -23469,6 +23645,10 @@ extension Italic: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + + public func hidden(_ value: Values.Condition) -> Italic { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Italic { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -24016,6 +24196,10 @@ extension Bold: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return self } + public func hidden(_ value: Values.Condition) -> Bold { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Bold { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -24562,6 +24746,10 @@ extension Underline: GlobalContentAttributes, GlobalEventAttributes, GlobalAcces return self } + public func hidden(_ value: Values.Condition) -> Underline { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Underline { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -25108,6 +25296,10 @@ extension Mark: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return self } + public func hidden(_ value: Values.Condition) -> Mark { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Mark { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -25645,6 +25837,10 @@ extension Bdi: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibili return self } + public func hidden(_ value: Values.Condition) -> Bdi { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Bdi { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -26170,6 +26366,10 @@ extension Bdo: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibili return self } + public func hidden(_ value: Values.Condition) -> Bdo { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Bdo { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -26703,6 +26903,10 @@ extension Span: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return self } + public func hidden(_ value: Values.Condition) -> Span { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Span { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -27233,6 +27437,10 @@ extension LineBreak: GlobalContentAttributes, GlobalEventAttributes, GlobalAcces return self } + public func hidden(_ value: Values.Condition) -> LineBreak { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> LineBreak { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -27754,6 +27962,10 @@ extension WordBreak: GlobalContentAttributes, GlobalEventAttributes, GlobalAcces return self } + + public func hidden(_ value: Values.Condition) -> WordBreak { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> WordBreak { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -28287,6 +28499,10 @@ extension InsertedText: GlobalContentAttributes, GlobalEventAttributes, GlobalAc return self } + + public func hidden(_ value: Values.Condition) -> InsertedText { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> InsertedText { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -28829,6 +29045,10 @@ extension DeletedText: GlobalContentAttributes, GlobalEventAttributes, GlobalAcc return self } + public func hidden(_ value: Values.Condition) -> DeletedText { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> DeletedText { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -29375,6 +29595,10 @@ extension Picture: GlobalContentAttributes, GlobalEventAttributes { return self } + public func hidden(_ value: Values.Condition) -> Picture { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Picture { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -29669,6 +29893,10 @@ extension Image: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibi return self } + + public func hidden(_ value: Values.Condition) -> Image { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Image { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -30278,6 +30506,10 @@ extension InlineFrame: GlobalContentAttributes, GlobalEventAttributes, GlobalAcc return self } + public func hidden(_ value: Values.Condition) -> InlineFrame { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> InlineFrame { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -30842,6 +31074,10 @@ extension Embed: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibi return self } + public func hidden(_ value: Values.Condition) -> Embed { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Embed { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -31396,6 +31632,10 @@ extension Object: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + public func hidden(_ value: Values.Condition) -> Object { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Object { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -31955,6 +32195,10 @@ extension Video: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibi return self } + public func hidden(_ value: Values.Condition) -> Video { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Video { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -32557,6 +32801,10 @@ extension Audio: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibi return self } + public func hidden(_ value: Values.Condition) -> Audio { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Audio { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -33139,6 +33387,10 @@ extension Map: GlobalContentAttributes, GlobalEventAttributes, NameAttribute { return self } + public func hidden(_ value: Values.Condition) -> Map { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Map { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -33452,6 +33704,10 @@ extension Form: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return self } + public func hidden(_ value: Values.Condition) -> Form { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Form { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -34032,6 +34288,10 @@ extension DataList: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + + public func hidden(_ value: Values.Condition) -> DataList { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> DataList { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -34568,6 +34828,10 @@ extension Output: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + public func hidden(_ value: Values.Condition) -> Output { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Output { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -35114,6 +35378,10 @@ extension Progress: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + + public func hidden(_ value: Values.Condition) -> Progress { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Progress { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -35668,6 +35936,10 @@ extension Meter: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibi return self } + + public func hidden(_ value: Values.Condition) -> Meter { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Meter { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -36239,7 +36511,11 @@ extension Details: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessi return self } - + + public func hidden(_ value: Values.Condition) -> Details { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Details { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -36801,6 +37077,10 @@ extension Dialog: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + public func hidden(_ value: Values.Condition) -> Dialog { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Dialog { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -37361,6 +37641,10 @@ extension Script: GlobalContentAttributes, GlobalEventAttributes, Asynchronously return self } + public func hidden(_ value: Values.Condition) -> Script { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Script { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -37701,6 +37985,10 @@ extension NoScript: GlobalContentAttributes, GlobalEventAttributes { return self } + + public func hidden(_ value: Values.Condition) -> NoScript { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> NoScript { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -38012,6 +38300,10 @@ extension Template: GlobalContentAttributes, GlobalEventAttributes, ShadowRootMo return self } + public func hidden(_ value: Values.Condition) -> Template { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Template { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -38314,6 +38606,10 @@ extension Canvas: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + + public func hidden(_ value: Values.Condition) -> Canvas { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Canvas { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -38862,6 +39158,10 @@ extension Table: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibi return self } + + public func hidden(_ value: Values.Condition) -> Table { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Table { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -39774,6 +40074,10 @@ extension Slot: GlobalContentAttributes, NameAttribute { return self } + public func hidden(_ value: Values.Condition) -> Slot { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Slot { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } diff --git a/Sources/HTMLKit/Abstraction/Elements/DefinitionElements.swift b/Sources/HTMLKit/Abstraction/Elements/DefinitionElements.swift index 71b4b362..9ec8f71b 100644 --- a/Sources/HTMLKit/Abstraction/Elements/DefinitionElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/DefinitionElements.swift @@ -143,6 +143,10 @@ extension TermName: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> TermName { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> TermName { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -681,6 +685,10 @@ extension TermDefinition: GlobalContentAttributes, GlobalEventAttributes, Global return self } + public func hidden(_ value: Values.Condition) -> TermDefinition { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> TermDefinition { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } diff --git a/Sources/HTMLKit/Abstraction/Elements/FigureElements.swift b/Sources/HTMLKit/Abstraction/Elements/FigureElements.swift index d249b31e..fff3e1d7 100644 --- a/Sources/HTMLKit/Abstraction/Elements/FigureElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/FigureElements.swift @@ -139,6 +139,10 @@ extension FigureCaption: GlobalContentAttributes, GlobalEventAttributes, GlobalA return self } + public func hidden(_ value: Values.Condition) -> FigureCaption { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> FigureCaption { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } diff --git a/Sources/HTMLKit/Abstraction/Elements/FormElements.swift b/Sources/HTMLKit/Abstraction/Elements/FormElements.swift index 7ef9ed73..78eb11c3 100644 --- a/Sources/HTMLKit/Abstraction/Elements/FormElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/FormElements.swift @@ -121,6 +121,10 @@ extension Input: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibi return self } + public func hidden(_ value: Values.Condition) -> Input { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Input { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -780,6 +784,10 @@ extension Label: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibi return self } + public func hidden(_ value: Values.Condition) -> Label { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Label { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -1335,6 +1343,10 @@ extension Select: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + public func hidden(_ value: Values.Condition) -> Select { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Select { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -1823,6 +1835,10 @@ extension TextArea: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> TextArea { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> TextArea { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -2444,6 +2460,10 @@ extension Button: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + public func hidden(_ value: Values.Condition) -> Button { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Button { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -3063,6 +3083,10 @@ extension Fieldset: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> Fieldset { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Fieldset { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } diff --git a/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift b/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift index f87bb8cf..865c6da8 100644 --- a/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift @@ -132,6 +132,10 @@ extension Title: GlobalContentAttributes, GlobalEventAttributes { return self } + public func hidden(_ value: Values.Condition) -> Title { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Title { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -433,6 +437,10 @@ extension Base: GlobalContentAttributes, GlobalEventAttributes, ReferenceAttribu return self } + public func hidden(_ value: Values.Condition) -> Base { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Base { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -732,6 +740,10 @@ extension Meta: GlobalContentAttributes, GlobalEventAttributes, ContentAttribute return self } + public func hidden(_ value: Values.Condition) -> Meta { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Meta { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -1074,6 +1086,10 @@ extension Style: GlobalContentAttributes, GlobalEventAttributes, TypeAttribute, return self } + public func hidden(_ value: Values.Condition) -> Style { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Style { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -1392,6 +1408,10 @@ extension Link: GlobalContentAttributes, GlobalEventAttributes, ReferenceAttribu return self } + public func hidden(_ value: Values.Condition) -> Link { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Link { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } diff --git a/Sources/HTMLKit/Abstraction/Elements/HtmlElements.swift b/Sources/HTMLKit/Abstraction/Elements/HtmlElements.swift index 3b658737..02fb8d55 100644 --- a/Sources/HTMLKit/Abstraction/Elements/HtmlElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/HtmlElements.swift @@ -130,6 +130,10 @@ extension Head: GlobalContentAttributes, GlobalEventAttributes { return self } + public func hidden(_ value: Values.Condition) -> Head { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Head { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -438,6 +442,10 @@ extension Body: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return self } + public func hidden(_ value: Values.Condition) -> Body { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Body { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } diff --git a/Sources/HTMLKit/Abstraction/Elements/InputElements.swift b/Sources/HTMLKit/Abstraction/Elements/InputElements.swift index 05a78b87..85f750fb 100644 --- a/Sources/HTMLKit/Abstraction/Elements/InputElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/InputElements.swift @@ -145,6 +145,10 @@ extension OptionGroup: GlobalContentAttributes, GlobalEventAttributes, GlobalAcc return self } + public func hidden(_ value: Values.Condition) -> OptionGroup { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> OptionGroup { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -703,6 +707,10 @@ extension Option: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + public func hidden(_ value: Values.Condition) -> Option { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Option { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -1293,6 +1301,10 @@ extension Legend: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return self } + public func hidden(_ value: Values.Condition) -> Legend { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Legend { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -1831,6 +1843,10 @@ extension Summary: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessi return self } + public func hidden(_ value: Values.Condition) -> Summary { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Summary { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } diff --git a/Sources/HTMLKit/Abstraction/Elements/ListElements.swift b/Sources/HTMLKit/Abstraction/Elements/ListElements.swift index c6e7d7b3..151fa58a 100644 --- a/Sources/HTMLKit/Abstraction/Elements/ListElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/ListElements.swift @@ -139,6 +139,10 @@ extension ListItem: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> ListItem { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> ListItem { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } diff --git a/Sources/HTMLKit/Abstraction/Elements/MapElements.swift b/Sources/HTMLKit/Abstraction/Elements/MapElements.swift index 60590fda..52de61ac 100644 --- a/Sources/HTMLKit/Abstraction/Elements/MapElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/MapElements.swift @@ -126,6 +126,10 @@ extension Area: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return self } + + public func hidden(_ value: Values.Condition) -> Area { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Area { return mutate(inputmode: .init(value.rawValue, context: .trusted)) diff --git a/Sources/HTMLKit/Abstraction/Elements/MediaElements.swift b/Sources/HTMLKit/Abstraction/Elements/MediaElements.swift index e5b6e464..65cec284 100644 --- a/Sources/HTMLKit/Abstraction/Elements/MediaElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/MediaElements.swift @@ -120,6 +120,10 @@ extension Source: GlobalContentAttributes, GlobalEventAttributes, TypeAttribute, return self } + public func hidden(_ value: Values.Condition) -> Source { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Source { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -469,6 +473,10 @@ extension Track: GlobalContentAttributes, GlobalEventAttributes, KindAttribute, return self } + public func hidden(_ value: Values.Condition) -> Track { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Track { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } diff --git a/Sources/HTMLKit/Abstraction/Elements/RubyElements.swift b/Sources/HTMLKit/Abstraction/Elements/RubyElements.swift index 2efa389b..4c2d4b9a 100644 --- a/Sources/HTMLKit/Abstraction/Elements/RubyElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/RubyElements.swift @@ -141,6 +141,10 @@ extension RubyText: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> RubyText { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> RubyText { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -682,6 +686,10 @@ extension RubyPronunciation: GlobalContentAttributes, GlobalEventAttributes, Glo return self } + + public func hidden(_ value: Values.Condition) -> RubyPronunciation { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> RubyPronunciation { return mutate(inputmode: .init(value.rawValue, context: .trusted)) diff --git a/Sources/HTMLKit/Abstraction/Elements/TableElements.swift b/Sources/HTMLKit/Abstraction/Elements/TableElements.swift index 896dee2e..0ed92911 100644 --- a/Sources/HTMLKit/Abstraction/Elements/TableElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/TableElements.swift @@ -164,6 +164,10 @@ extension Caption: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessi return self } + public func hidden(_ value: Values.Condition) -> Caption { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> Caption { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -701,6 +705,10 @@ extension ColumnGroup: GlobalContentAttributes, GlobalEventAttributes, SpanAttri return self } + public func hidden(_ value: Values.Condition) -> ColumnGroup { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> ColumnGroup { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -1002,6 +1010,10 @@ extension Column: GlobalContentAttributes, GlobalEventAttributes, SpanAttribute return self } + + public func hidden(_ value: Values.Condition) -> Column { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } public func inputMode(_ value: Values.Mode) -> Column { return mutate(inputmode: .init(value.rawValue, context: .trusted)) @@ -1315,6 +1327,10 @@ extension TableBody: GlobalContentAttributes, GlobalEventAttributes, GlobalAcces return self } + public func hidden(_ value: Values.Condition) -> TableBody { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> TableBody { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -1869,6 +1885,10 @@ extension TableHead: GlobalContentAttributes, GlobalEventAttributes, GlobalAcces return self } + public func hidden(_ value: Values.Condition) -> TableHead { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> TableHead { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -2423,6 +2443,10 @@ extension TableFoot: GlobalContentAttributes, GlobalEventAttributes, GlobalAcces return self } + public func hidden(_ value: Values.Condition) -> TableFoot { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> TableFoot { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -2963,6 +2987,10 @@ extension TableRow: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> TableRow { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> TableRow { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -3516,6 +3544,10 @@ extension DataCell: GlobalContentAttributes, GlobalEventAttributes, GlobalAccess return self } + public func hidden(_ value: Values.Condition) -> DataCell { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> DataCell { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } @@ -4078,6 +4110,10 @@ extension HeaderCell: GlobalContentAttributes, GlobalEventAttributes, GlobalAcce return self } + public func hidden(_ value: Values.Condition) -> HeaderCell { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } + public func inputMode(_ value: Values.Mode) -> HeaderCell { return mutate(inputmode: .init(value.rawValue, context: .trusted)) } diff --git a/Sources/HTMLKit/Abstraction/Tokens/ValueTokens.swift b/Sources/HTMLKit/Abstraction/Tokens/ValueTokens.swift index d25131ce..2b3b0a0e 100644 --- a/Sources/HTMLKit/Abstraction/Tokens/ValueTokens.swift +++ b/Sources/HTMLKit/Abstraction/Tokens/ValueTokens.swift @@ -2166,4 +2166,17 @@ public enum Values { /// Indicates the script contains json data. case data = "application/json" } + + /// An enumeration of hide condition. + /// + /// ```swift + /// Paragraph { + /// "Lorem ipsum..." + /// } + /// .hidden(.untilFound) + /// ``` + public enum Condition: String { + + case untilFound = "until-found" + } } diff --git a/Tests/HTMLKitTests/AttributesTests.swift b/Tests/HTMLKitTests/AttributesTests.swift index 57c97d95..d5f30549 100644 --- a/Tests/HTMLKitTests/AttributesTests.swift +++ b/Tests/HTMLKitTests/AttributesTests.swift @@ -83,6 +83,10 @@ final class AttributesTests: XCTestCase { return self } + + func hidden(_ value: Values.Condition) -> Tag { + return mutate(hidden: .init(value.rawValue, context: .trusted)) + } func id(_ value: String) -> Tag { return self.mutate(id: .init(value, context: .tainted(.html))) @@ -1321,19 +1325,18 @@ final class AttributesTests: XCTestCase { func testHiddenAttribute() throws { let view = TestView { - // unconditionally Tag {}.hidden() - // with a false condition Tag {}.hidden(false) - // with a true condition Tag {}.hidden(true) + Tag {}.hidden(.untilFound) } XCTAssertEqual(try renderer.render(view: view), """ \ \ - + \ + """ ) } From 544fa72cb77a9c16bed8d2e2e2f8504591dcedb9 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Fri, 10 Jul 2026 08:14:35 +0200 Subject: [PATCH 3/5] Revise the relationship attribute --- .../Attributes/ContentAttributes.swift | 21 ++++++++++++++++--- .../Abstraction/Elements/BodyElements.swift | 16 ++++++++++---- .../Abstraction/Elements/HeadElements.swift | 8 +++++-- .../Abstraction/Elements/MapElements.swift | 8 +++++-- .../Abstraction/Tokens/ValueTokens.swift | 21 +++++++++++++------ .../Framework/Rendering/EnumeratedList.swift | 6 ++++++ Tests/HTMLKitTests/AttributesTests.swift | 14 ++++++++++--- 7 files changed, 74 insertions(+), 20 deletions(-) diff --git a/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift b/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift index 967f4660..2d3697ad 100644 --- a/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift +++ b/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift @@ -2786,13 +2786,28 @@ public protocol RelationshipAttribute: Attribute { /// "Lorem ipsum..." /// } /// .reference("https://...") - /// .relationship(.author) + /// .relationship(.author, .external) /// ``` /// - /// - Parameter value: The relationship type to associate with. + /// - Parameter values: The relationship types to associate with. /// /// - Returns: The element - func relationship(_ value: Values.Relation) -> Self + func relationship(_ values: Values.Relation...) -> Self + + /// Indicate the relationship between documents. + /// + /// ```swift + /// Anchor { + /// "Lorem ipsum..." + /// } + /// .reference("https://...") + /// .relationship([.author, .external]) + /// ``` + /// + /// - Parameter values: The relationship types to associate with. + /// + /// - Returns: The element + func relationship(_ values: [Values.Relation]) -> Self } extension RelationshipAttribute where Self: ContentNode { diff --git a/Sources/HTMLKit/Abstraction/Elements/BodyElements.swift b/Sources/HTMLKit/Abstraction/Elements/BodyElements.swift index 308dc85d..3428e23a 100644 --- a/Sources/HTMLKit/Abstraction/Elements/BodyElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/BodyElements.swift @@ -12720,8 +12720,12 @@ extension Anchor: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessib return mutate(referrerpolicy: .init(value.rawValue, context: .trusted)) } - public func relationship(_ value: Values.Relation) -> Anchor { - return mutate(rel: .init(value.rawValue, context: .trusted)) + public func relationship(_ values: Values.Relation...) -> Anchor { + return mutate(rel: .init(EnumeratedList(values: values, separator: " "), context: .trusted)) + } + + public func relationship(_ values: [Values.Relation]) -> Anchor { + return mutate(rel: .init(EnumeratedList(values: values, separator: " "), context: .trusted)) } public func target(_ value: Values.Target) -> Anchor { @@ -33870,8 +33874,12 @@ extension Form: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return mutate(target: .init(value.rawValue, context: .trusted)) } - public func relationship(_ value: Values.Relation) -> Form { - return mutate(rel: .init(value.rawValue, context: .trusted)) + public func relationship(_ values: Values.Relation...) -> Form { + return mutate(rel: .init(EnumeratedList(values: values, separator: " "), context: .trusted)) + } + + public func relationship(_ values: [Values.Relation]) -> Form { + return mutate(rel: .init(EnumeratedList(values: values, separator: " "), context: .trusted)) } public func popover(_ value: Values.Popover.State) -> Form { diff --git a/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift b/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift index 865c6da8..580cf4c3 100644 --- a/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift @@ -1569,8 +1569,12 @@ extension Link: GlobalContentAttributes, GlobalEventAttributes, ReferenceAttribu return mutate(referrerpolicy: .init(value.rawValue, context: .trusted)) } - public func relationship(_ value: Values.Relation) -> Link { - return mutate(rel: .init(value.rawValue, context: .trusted)) + public func relationship(_ values: Values.Relation...) -> Link { + return mutate(rel: .init(EnumeratedList(values: values, separator: " "), context: .trusted)) + } + + public func relationship(_ values: [Values.Relation]) -> Link { + return mutate(rel: .init(EnumeratedList(values: values, separator: " "), context: .trusted)) } public func sizes(_ candidates: [String]) -> Link { diff --git a/Sources/HTMLKit/Abstraction/Elements/MapElements.swift b/Sources/HTMLKit/Abstraction/Elements/MapElements.swift index 52de61ac..4ef40a66 100644 --- a/Sources/HTMLKit/Abstraction/Elements/MapElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/MapElements.swift @@ -321,8 +321,12 @@ extension Area: GlobalContentAttributes, GlobalEventAttributes, GlobalAccessibil return mutate(ping: .init(value, context: .tainted(.html))) } - public func relationship(_ value: Values.Relation) -> Area { - return mutate(rel: .init(value.rawValue, context: .trusted)) + public func relationship(_ values: Values.Relation...) -> Area { + return mutate(rel: .init(EnumeratedList(values: values, separator: " "), context: .trusted)) + } + + public func relationship(_ values: [Values.Relation]) -> Area { + return mutate(rel: .init(EnumeratedList(values: values, separator: " "), context: .trusted)) } public func referrerPolicy(_ value: Values.Policy) -> Area { diff --git a/Sources/HTMLKit/Abstraction/Tokens/ValueTokens.swift b/Sources/HTMLKit/Abstraction/Tokens/ValueTokens.swift index 2b3b0a0e..a3fd0536 100644 --- a/Sources/HTMLKit/Abstraction/Tokens/ValueTokens.swift +++ b/Sources/HTMLKit/Abstraction/Tokens/ValueTokens.swift @@ -803,18 +803,21 @@ public enum Values { /// Indicates an alternate presentation. case alternate - /// Indicates the preferred url. - case canonical - /// Indicates an author page. case author /// Indicates a perma link. case bookmark + /// Indicates the preferred url. + case canonical + /// Indicates a dns prefetch. case dnsPrefetch = "dns-prefetch" + /// Hints to block rendering until fully parsed. + case expect + /// Indicates a external resource. case external @@ -824,15 +827,15 @@ public enum Values { /// Indicates a document icon. case icon + /// Indicates a licence information. + case licence + /// Indicates a app manifest. case manifest /// Indicates a module preload. case modulePreload = "modulepreload" - /// Indicates a licence information. - case licence - /// Indicates a page pagination. case next @@ -863,6 +866,9 @@ public enum Values { /// Indicates a page pagination. case prev + /// Indicates about data collection and usage practices. + case privacyPolicy = "privacy-policy" + /// Indicates a search content. case search @@ -872,6 +878,9 @@ public enum Values { /// Indicates a content tag. case tag + /// Indicates about agreements. + case terms = "terms-of-service" + /// Indicates a touch icon. case appleTouchIcon = "apple-touch-icon" diff --git a/Sources/HTMLKit/Framework/Rendering/EnumeratedList.swift b/Sources/HTMLKit/Framework/Rendering/EnumeratedList.swift index 88e61a85..a3207892 100644 --- a/Sources/HTMLKit/Framework/Rendering/EnumeratedList.swift +++ b/Sources/HTMLKit/Framework/Rendering/EnumeratedList.swift @@ -90,6 +90,12 @@ extension EnumeratedList { self.values = values.map(\.rawValue) self.separator = separator } + + internal init(values: [Values.Relation], separator: String) { + + self.values = values.map(\.rawValue) + self.separator = separator + } } extension EnumeratedList: Equatable { diff --git a/Tests/HTMLKitTests/AttributesTests.swift b/Tests/HTMLKitTests/AttributesTests.swift index d5f30549..cab56c44 100644 --- a/Tests/HTMLKitTests/AttributesTests.swift +++ b/Tests/HTMLKitTests/AttributesTests.swift @@ -543,8 +543,12 @@ final class AttributesTests: XCTestCase { return self.mutate(referrerpolicy: .init(value.rawValue, context: .trusted)) } - func relationship(_ value: Values.Relation) -> Tag { - return self.mutate(rel: .init(value.rawValue, context: .trusted)) + public func relationship(_ values: Values.Relation...) -> Tag { + return mutate(rel: .init(EnumeratedList(values: values, separator: " "), context: .trusted)) + } + + public func relationship(_ values: [Values.Relation]) -> Tag { + return mutate(rel: .init(EnumeratedList(values: values, separator: " "), context: .trusted)) } func required(_ condition: Bool = true) -> Tag { @@ -2301,11 +2305,15 @@ final class AttributesTests: XCTestCase { let view = TestView { Tag {}.relationship(.author) + Tag {}.relationship(.author, .external) + Tag {}.relationship([.author, .external]) } XCTAssertEqual(try renderer.render(view: view), """ - + \ + \ + """ ) } From 060deebb0ebbb1f8b1bc99af05435cc5212dd400 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Fri, 10 Jul 2026 13:38:54 +0200 Subject: [PATCH 4/5] Introduce the imagesources attribute --- .../Attributes/ContentAttributes.swift | 47 +++++++++++++++++++ .../Abstraction/Elements/HeadElements.swift | 10 +++- Tests/HTMLKitTests/AttributesTests.swift | 31 +++++++++++- 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift b/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift index 2d3697ad..697cf56b 100644 --- a/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift +++ b/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift @@ -4320,3 +4320,50 @@ extension AbbreviatedAttribute where Self: EmptyNode { return self.mutate(key: "abbr", value: value) } } + +/// A type that provides the `imageSources` modifier. +@_documentation(visibility: internal) +public protocol ImageSourcesAttribute: Attribute { + + /// Preload a set of sources. + /// + /// ```swift + /// Link() + /// .relationship(.preload) + /// .as(.image) + /// .imageSources([SourceCandidate("...webp", width: 1024), SourceCandidate("...webp", width: 1680)]) + /// ``` + /// + /// - Parameter candidates: The candidates to load in advance. + /// + /// - Returns: The element. + func imageSources(_ candidates: [SourceCandidate]) -> Self + + /// Preload a set of sources. + /// + /// ```swift + /// Link() + /// .relationship(.preload) + /// .as(.image) + /// .imageSources(SourceCandidate("...webp", width: 1024), SourceCandidate("...webp", width: 1680)) + /// ``` + /// + /// - Parameter candidates: The candidates to load in advance. + /// + /// - Returns: The element. + func imageSources(_ candidates: SourceCandidate...) -> Self +} + +extension ImageSourcesAttribute where Self: ContentNode { + + internal func mutate(imagesrcset value: AttributeData) -> Self { + return self.mutate(key: "imagesrcset", value: value) + } +} + +extension ImageSourcesAttribute where Self: EmptyNode { + + internal func mutate(imagesrcset value: AttributeData) -> Self { + return self.mutate(key: "imagesrcset", value: value) + } +} diff --git a/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift b/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift index 580cf4c3..c8ffc295 100644 --- a/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift @@ -1338,7 +1338,7 @@ public struct Link: EmptyNode, HeadElement, BodyElement { } } -extension Link: GlobalContentAttributes, GlobalEventAttributes, ReferenceAttribute, ReferenceLanguageAttribute, MediaAttribute, ReferrerPolicyAttribute, RelationshipAttribute, SizesAttribute, TypeAttribute, FetchPriorityAttribute, BlockingAttribute, FormEventAttribute, IntegrityAttribute, AsAttribute, CrossOriginAttribute { +extension Link: GlobalContentAttributes, GlobalEventAttributes, ReferenceAttribute, ReferenceLanguageAttribute, MediaAttribute, ReferrerPolicyAttribute, RelationshipAttribute, SizesAttribute, TypeAttribute, FetchPriorityAttribute, BlockingAttribute, FormEventAttribute, IntegrityAttribute, AsAttribute, CrossOriginAttribute, ImageSourcesAttribute { public func accessKey(_ value: Character) -> Link { return mutate(accesskey: .init("\(value)", context: .trusted)) @@ -1601,6 +1601,14 @@ extension Link: GlobalContentAttributes, GlobalEventAttributes, ReferenceAttribu return mutate(popover: .init(value.rawValue, context: .trusted)) } + public func imageSources(_ candidates: [SourceCandidate]) -> Link { + return mutate(imagesrcset: .init(EnumeratedList(values: candidates, separator: ", "), context: .tainted(.html))) + } + + public func imageSources(_ candidates: SourceCandidate...) -> Link { + return mutate(imagesrcset: .init(EnumeratedList(values: candidates, separator: ", "), context: .tainted(.html))) + } + public func custom(key: String, value: String, context: EscapeContext = .tainted(.html)) -> Link { return mutate(key: key, value: .init(value, context: context)) } diff --git a/Tests/HTMLKitTests/AttributesTests.swift b/Tests/HTMLKitTests/AttributesTests.swift index cab56c44..48d3dfcd 100644 --- a/Tests/HTMLKitTests/AttributesTests.swift +++ b/Tests/HTMLKitTests/AttributesTests.swift @@ -10,7 +10,7 @@ final class AttributesTests: XCTestCase { @ContentBuilder var body: Content } - typealias AllAttributes = AccessKeyAttribute & AcceptAttribute & ActionAttribute & AlternateAttribute & AsynchronouslyAttribute & AutocapitalizeAttribute & AutocompleteAttribute & AutofocusAttribute & AutoplayAttribute & CharsetAttribute & CheckedAttribute & CiteAttribute & ClassAttribute & ColumnsAttribute & ColumnSpanAttribute & ContentAttribute & EditAttribute & ControlsAttribute & DataAttribute & DateTimeAttribute & DefaultAttribute & DeferAttribute & DirectionAttribute & DisabledAttribute & DownloadAttribute & DragAttribute & EncodingAttribute & EnterKeyAttribute & ForAttribute & FormAttribute & FormActionAttribute & EquivalentAttribute & HeadersAttribute & HeightAttribute & HiddenAttribute & HighAttribute & ReferenceAttribute & ReferenceLanguageAttribute & IdentifierAttribute & IsMapAttribute & InputModeAttribute & IsAttribute & ItemAttribute & ItemPropertyAttribute & KindAttribute & LabelAttribute & LanguageAttribute & ListAttribute & LoopAttribute & LowAttribute & MaximumValueAttribute & MaximumLengthAttribute & MediaAttribute & MethodAttribute & MinimumValueAttribute & MinimumLengthAttribute & MultipleAttribute & MutedAttribute & NameAttribute & NonceAttribute & NoValidateAttribute & OpenAttribute & OptimumAttribute & PatternAttribute & PartAttribute & PingAttribute & PlaceholderAttribute & PosterAttribute & PreloadAttribute & ReadOnlyAttribute & ReferrerPolicyAttribute & RelationshipAttribute & RequiredAttribute & ReversedAttribute & RoleAttribute & RowsAttribute & RowSpanAttribute & SandboxAttribute & ScopeAttribute & ShapeAttribute & SizeAttribute & SizesAttribute & SlotAttribute & SpanAttribute & SpellCheckAttribute & SourceAttribute & StartAttribute & StepAttribute & StyleAttribute & TabulatorAttribute & TargetAttribute & TitleAttribute & TranslateAttribute & TypeAttribute & ValueAttribute & WidthAttribute & WrapAttribute & PropertyAttribute & SelectedAttribute & WindowEventAttribute & FocusEventAttribute & PointerEventAttribute & MouseEventAttribute & WheelEventAttribute & InputEventAttribute & KeyboardEventAttribute & DragEventAttribute & ClipboardEventAttribute & SelectionEventAttribute & MediaEventAttribute & FormEventAttribute & DetailEventAttribute & AtomicAccessibilityAttribute & BusyAccessibilityAttribute & ControlsAccessibilityAttribute & CurrentAccessibilityAttribute & DescriptionsAccessibilityAttribute & DetailAccessibilityAttribute & DisabledAccessibilityAttribute & FlowAccessibilityAttribute & PopupAccessibilityAttribute & HiddenAccessibilityAttribute & InvalidAccessibilityAttribute & ShortcutsAccessibilityAttribute & LabelAccessibilityAttribute & LabelsAccessibilityAttribute & LiveAccessibilityAttribute & OwnsAccessibilityAttribute & MultilineAccessibilityAttribute & RowIndexAccessibilityAttribute & RelevantAccessibilityAttribute & RoleDescriptionAccessibilityAttribute & SortAccessibilityAttribute & OrientationAccessibilityAttribute & RequiredAccessibilityAttribute & ReadOnlyAccessibilityAttribute & ModalAccessibilityAttribute & LevelAccessibilityAttribute & HintAccessibilityAttribute & PositionAccessibilityAttribute & MultiselectAccessibilityAttribute & RowCountAccessibilityAttribute & ColumnIndexAccessibilityAttribute & ColumnCountAccessibilityAttribute & RowSpanAccessibilityAttribute & ColumnSpanAccessibilityAttribute & MaximumValueAccessibilityAttribute & MinimumValueAccessibilityAttribute & ValueAccessibilityAttribute & PressedAccessibilityAttribute & SelectedAccessibilityAttribute & CheckedAccessibilityAttribute & ExpandedAccessibilityAttribute & FocusedAccessibilityAttribute & CompletionAccessibilityAttribute & DrawAttribute & FillAttribute & StrokeAttribute & RadiusAttribute & PositionPointAttribute & RadiusPointAttribute & CenterPointAttribute & ViewBoxAttribute & NamespaceAttribute & PointsAttribute & ShadowRootModeAttribute & InertAttribute & FetchPriorityAttribute & LoadingAttribute & SourceSetAttribute & DecodingAttribute & BlockingAttribute & PopoverAttribute & PopoverTargetAttribute & UseMapAttribute & PlaysInlineAttribute & IntegrityAttribute & AsAttribute & CrossOriginAttribute & SourceLanguageAttribute & SourceDocumentAttribute & AbbreviatedAttribute + typealias AllAttributes = AccessKeyAttribute & AcceptAttribute & ActionAttribute & AlternateAttribute & AsynchronouslyAttribute & AutocapitalizeAttribute & AutocompleteAttribute & AutofocusAttribute & AutoplayAttribute & CharsetAttribute & CheckedAttribute & CiteAttribute & ClassAttribute & ColumnsAttribute & ColumnSpanAttribute & ContentAttribute & EditAttribute & ControlsAttribute & DataAttribute & DateTimeAttribute & DefaultAttribute & DeferAttribute & DirectionAttribute & DisabledAttribute & DownloadAttribute & DragAttribute & EncodingAttribute & EnterKeyAttribute & ForAttribute & FormAttribute & FormActionAttribute & EquivalentAttribute & HeadersAttribute & HeightAttribute & HiddenAttribute & HighAttribute & ReferenceAttribute & ReferenceLanguageAttribute & IdentifierAttribute & IsMapAttribute & InputModeAttribute & IsAttribute & ItemAttribute & ItemPropertyAttribute & KindAttribute & LabelAttribute & LanguageAttribute & ListAttribute & LoopAttribute & LowAttribute & MaximumValueAttribute & MaximumLengthAttribute & MediaAttribute & MethodAttribute & MinimumValueAttribute & MinimumLengthAttribute & MultipleAttribute & MutedAttribute & NameAttribute & NonceAttribute & NoValidateAttribute & OpenAttribute & OptimumAttribute & PatternAttribute & PartAttribute & PingAttribute & PlaceholderAttribute & PosterAttribute & PreloadAttribute & ReadOnlyAttribute & ReferrerPolicyAttribute & RelationshipAttribute & RequiredAttribute & ReversedAttribute & RoleAttribute & RowsAttribute & RowSpanAttribute & SandboxAttribute & ScopeAttribute & ShapeAttribute & SizeAttribute & SizesAttribute & SlotAttribute & SpanAttribute & SpellCheckAttribute & SourceAttribute & StartAttribute & StepAttribute & StyleAttribute & TabulatorAttribute & TargetAttribute & TitleAttribute & TranslateAttribute & TypeAttribute & ValueAttribute & WidthAttribute & WrapAttribute & PropertyAttribute & SelectedAttribute & WindowEventAttribute & FocusEventAttribute & PointerEventAttribute & MouseEventAttribute & WheelEventAttribute & InputEventAttribute & KeyboardEventAttribute & DragEventAttribute & ClipboardEventAttribute & SelectionEventAttribute & MediaEventAttribute & FormEventAttribute & DetailEventAttribute & AtomicAccessibilityAttribute & BusyAccessibilityAttribute & ControlsAccessibilityAttribute & CurrentAccessibilityAttribute & DescriptionsAccessibilityAttribute & DetailAccessibilityAttribute & DisabledAccessibilityAttribute & FlowAccessibilityAttribute & PopupAccessibilityAttribute & HiddenAccessibilityAttribute & InvalidAccessibilityAttribute & ShortcutsAccessibilityAttribute & LabelAccessibilityAttribute & LabelsAccessibilityAttribute & LiveAccessibilityAttribute & OwnsAccessibilityAttribute & MultilineAccessibilityAttribute & RowIndexAccessibilityAttribute & RelevantAccessibilityAttribute & RoleDescriptionAccessibilityAttribute & SortAccessibilityAttribute & OrientationAccessibilityAttribute & RequiredAccessibilityAttribute & ReadOnlyAccessibilityAttribute & ModalAccessibilityAttribute & LevelAccessibilityAttribute & HintAccessibilityAttribute & PositionAccessibilityAttribute & MultiselectAccessibilityAttribute & RowCountAccessibilityAttribute & ColumnIndexAccessibilityAttribute & ColumnCountAccessibilityAttribute & RowSpanAccessibilityAttribute & ColumnSpanAccessibilityAttribute & MaximumValueAccessibilityAttribute & MinimumValueAccessibilityAttribute & ValueAccessibilityAttribute & PressedAccessibilityAttribute & SelectedAccessibilityAttribute & CheckedAccessibilityAttribute & ExpandedAccessibilityAttribute & FocusedAccessibilityAttribute & CompletionAccessibilityAttribute & DrawAttribute & FillAttribute & StrokeAttribute & RadiusAttribute & PositionPointAttribute & RadiusPointAttribute & CenterPointAttribute & ViewBoxAttribute & NamespaceAttribute & PointsAttribute & ShadowRootModeAttribute & InertAttribute & FetchPriorityAttribute & LoadingAttribute & SourceSetAttribute & DecodingAttribute & BlockingAttribute & PopoverAttribute & PopoverTargetAttribute & UseMapAttribute & PlaysInlineAttribute & IntegrityAttribute & AsAttribute & CrossOriginAttribute & SourceLanguageAttribute & SourceDocumentAttribute & AbbreviatedAttribute & ImageSourcesAttribute struct Tag: ContentNode, GlobalElement, AllAttributes { @@ -1210,6 +1210,14 @@ final class AttributesTests: XCTestCase { func abbreviated(verbatim value: String) -> Tag { return self.mutate(abbr: .init(value, context: .tainted(.html))) } + + func imageSources(_ candidates: [HTMLKit.SourceCandidate]) -> Tag { + return mutate(imagesrcset: .init(EnumeratedList(values: candidates, separator: ", "), context: .tainted(.html))) + } + + func imageSources(_ candidates: HTMLKit.SourceCandidate...) -> Tag { + return mutate(imagesrcset: .init(EnumeratedList(values: candidates, separator: ", "), context: .tainted(.html))) + } } var renderer = Renderer() @@ -3875,4 +3883,25 @@ final class AttributesTests: XCTestCase { """ ) } + + func testImageSourcesAttribute() throws { + + let view = TestView { + Tag {}.imageSources(SourceCandidate("img.webp")) + Tag {}.imageSources(SourceCandidate("img.png", density: 4)) + Tag {}.imageSources(SourceCandidate("img.png", density: .ultra)) + Tag {}.imageSources(SourceCandidate("img.png", width: 1024)) + Tag {}.imageSources(SourceCandidate("img.png", width: 1024), SourceCandidate("img.png", density: .ultra)) + } + + XCTAssertEqual(try renderer.render(view: view), + """ + \ + \ + \ + \ + + """ + ) + } } From adfabcfdd2812407d6954b64631a6dc68ad90eae Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Fri, 10 Jul 2026 13:45:35 +0200 Subject: [PATCH 5/5] Introduce the imagesizes attribute --- .../Attributes/ContentAttributes.swift | 47 +++++++++++++++++++ .../Abstraction/Elements/HeadElements.swift | 10 +++- Tests/HTMLKitTests/AttributesTests.swift | 37 ++++++++++++++- 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift b/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift index 697cf56b..d624262f 100644 --- a/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift +++ b/Sources/HTMLKit/Abstraction/Attributes/ContentAttributes.swift @@ -4367,3 +4367,50 @@ extension ImageSourcesAttribute where Self: EmptyNode { return self.mutate(key: "imagesrcset", value: value) } } + +/// A type that provides the `imageSizes` modifier. +@_documentation(visibility: internal) +public protocol ImageSizesAttribute: Attribute { + + /// Preload the right source size. + /// + /// ```swift + /// Link() + /// .relationship(.preload) + /// .as(.image) + /// .imageSizes(SizeCandidate("100vw", conditions: .maxWidth("1680px")), SizeCandidate("80vw")) + /// ``` + /// + /// - Parameter candidates: The candidates to choose from. + /// + /// - Returns: The element. + func imageSizes(_ candidates: [SizeCandidate]) -> Self + + /// Preload the right source size. + /// + /// ```swift + /// Link() + /// .relationship(.preload) + /// .as(.image) + /// .imageSizes(SizeCandidate("100vw", conditions: .maxWidth("1680px")), SizeCandidate("80vw")) + /// ``` + /// + /// - Parameter candidates: The candidates to choose from. + /// + /// - Returns: The element. + func imageSizes(_ candidates: SizeCandidate...) -> Self +} + +extension ImageSizesAttribute where Self: ContentNode { + + internal func mutate(imagesizes value: AttributeData) -> Self { + return self.mutate(key: "imagesizes", value: value) + } +} + +extension ImageSizesAttribute where Self: EmptyNode { + + internal func mutate(imagesizes value: AttributeData) -> Self { + return self.mutate(key: "imagesizes", value: value) + } +} diff --git a/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift b/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift index c8ffc295..51cdb886 100644 --- a/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift +++ b/Sources/HTMLKit/Abstraction/Elements/HeadElements.swift @@ -1338,7 +1338,7 @@ public struct Link: EmptyNode, HeadElement, BodyElement { } } -extension Link: GlobalContentAttributes, GlobalEventAttributes, ReferenceAttribute, ReferenceLanguageAttribute, MediaAttribute, ReferrerPolicyAttribute, RelationshipAttribute, SizesAttribute, TypeAttribute, FetchPriorityAttribute, BlockingAttribute, FormEventAttribute, IntegrityAttribute, AsAttribute, CrossOriginAttribute, ImageSourcesAttribute { +extension Link: GlobalContentAttributes, GlobalEventAttributes, ReferenceAttribute, ReferenceLanguageAttribute, MediaAttribute, ReferrerPolicyAttribute, RelationshipAttribute, SizesAttribute, TypeAttribute, FetchPriorityAttribute, BlockingAttribute, FormEventAttribute, IntegrityAttribute, AsAttribute, CrossOriginAttribute, ImageSourcesAttribute, ImageSizesAttribute { public func accessKey(_ value: Character) -> Link { return mutate(accesskey: .init("\(value)", context: .trusted)) @@ -1609,6 +1609,14 @@ extension Link: GlobalContentAttributes, GlobalEventAttributes, ReferenceAttribu return mutate(imagesrcset: .init(EnumeratedList(values: candidates, separator: ", "), context: .tainted(.html))) } + public func imageSizes(_ candidates: [SizeCandidate]) -> Link { + return mutate(imagesizes: .init(EnumeratedList(values: candidates, separator: ", "), context: .tainted(.html))) + } + + public func imageSizes(_ candidates: SizeCandidate...) -> Link { + return mutate(imagesizes: .init(EnumeratedList(values: candidates, separator: ", "), context: .tainted(.html))) + } + public func custom(key: String, value: String, context: EscapeContext = .tainted(.html)) -> Link { return mutate(key: key, value: .init(value, context: context)) } diff --git a/Tests/HTMLKitTests/AttributesTests.swift b/Tests/HTMLKitTests/AttributesTests.swift index 48d3dfcd..1f24e1a0 100644 --- a/Tests/HTMLKitTests/AttributesTests.swift +++ b/Tests/HTMLKitTests/AttributesTests.swift @@ -10,7 +10,7 @@ final class AttributesTests: XCTestCase { @ContentBuilder var body: Content } - typealias AllAttributes = AccessKeyAttribute & AcceptAttribute & ActionAttribute & AlternateAttribute & AsynchronouslyAttribute & AutocapitalizeAttribute & AutocompleteAttribute & AutofocusAttribute & AutoplayAttribute & CharsetAttribute & CheckedAttribute & CiteAttribute & ClassAttribute & ColumnsAttribute & ColumnSpanAttribute & ContentAttribute & EditAttribute & ControlsAttribute & DataAttribute & DateTimeAttribute & DefaultAttribute & DeferAttribute & DirectionAttribute & DisabledAttribute & DownloadAttribute & DragAttribute & EncodingAttribute & EnterKeyAttribute & ForAttribute & FormAttribute & FormActionAttribute & EquivalentAttribute & HeadersAttribute & HeightAttribute & HiddenAttribute & HighAttribute & ReferenceAttribute & ReferenceLanguageAttribute & IdentifierAttribute & IsMapAttribute & InputModeAttribute & IsAttribute & ItemAttribute & ItemPropertyAttribute & KindAttribute & LabelAttribute & LanguageAttribute & ListAttribute & LoopAttribute & LowAttribute & MaximumValueAttribute & MaximumLengthAttribute & MediaAttribute & MethodAttribute & MinimumValueAttribute & MinimumLengthAttribute & MultipleAttribute & MutedAttribute & NameAttribute & NonceAttribute & NoValidateAttribute & OpenAttribute & OptimumAttribute & PatternAttribute & PartAttribute & PingAttribute & PlaceholderAttribute & PosterAttribute & PreloadAttribute & ReadOnlyAttribute & ReferrerPolicyAttribute & RelationshipAttribute & RequiredAttribute & ReversedAttribute & RoleAttribute & RowsAttribute & RowSpanAttribute & SandboxAttribute & ScopeAttribute & ShapeAttribute & SizeAttribute & SizesAttribute & SlotAttribute & SpanAttribute & SpellCheckAttribute & SourceAttribute & StartAttribute & StepAttribute & StyleAttribute & TabulatorAttribute & TargetAttribute & TitleAttribute & TranslateAttribute & TypeAttribute & ValueAttribute & WidthAttribute & WrapAttribute & PropertyAttribute & SelectedAttribute & WindowEventAttribute & FocusEventAttribute & PointerEventAttribute & MouseEventAttribute & WheelEventAttribute & InputEventAttribute & KeyboardEventAttribute & DragEventAttribute & ClipboardEventAttribute & SelectionEventAttribute & MediaEventAttribute & FormEventAttribute & DetailEventAttribute & AtomicAccessibilityAttribute & BusyAccessibilityAttribute & ControlsAccessibilityAttribute & CurrentAccessibilityAttribute & DescriptionsAccessibilityAttribute & DetailAccessibilityAttribute & DisabledAccessibilityAttribute & FlowAccessibilityAttribute & PopupAccessibilityAttribute & HiddenAccessibilityAttribute & InvalidAccessibilityAttribute & ShortcutsAccessibilityAttribute & LabelAccessibilityAttribute & LabelsAccessibilityAttribute & LiveAccessibilityAttribute & OwnsAccessibilityAttribute & MultilineAccessibilityAttribute & RowIndexAccessibilityAttribute & RelevantAccessibilityAttribute & RoleDescriptionAccessibilityAttribute & SortAccessibilityAttribute & OrientationAccessibilityAttribute & RequiredAccessibilityAttribute & ReadOnlyAccessibilityAttribute & ModalAccessibilityAttribute & LevelAccessibilityAttribute & HintAccessibilityAttribute & PositionAccessibilityAttribute & MultiselectAccessibilityAttribute & RowCountAccessibilityAttribute & ColumnIndexAccessibilityAttribute & ColumnCountAccessibilityAttribute & RowSpanAccessibilityAttribute & ColumnSpanAccessibilityAttribute & MaximumValueAccessibilityAttribute & MinimumValueAccessibilityAttribute & ValueAccessibilityAttribute & PressedAccessibilityAttribute & SelectedAccessibilityAttribute & CheckedAccessibilityAttribute & ExpandedAccessibilityAttribute & FocusedAccessibilityAttribute & CompletionAccessibilityAttribute & DrawAttribute & FillAttribute & StrokeAttribute & RadiusAttribute & PositionPointAttribute & RadiusPointAttribute & CenterPointAttribute & ViewBoxAttribute & NamespaceAttribute & PointsAttribute & ShadowRootModeAttribute & InertAttribute & FetchPriorityAttribute & LoadingAttribute & SourceSetAttribute & DecodingAttribute & BlockingAttribute & PopoverAttribute & PopoverTargetAttribute & UseMapAttribute & PlaysInlineAttribute & IntegrityAttribute & AsAttribute & CrossOriginAttribute & SourceLanguageAttribute & SourceDocumentAttribute & AbbreviatedAttribute & ImageSourcesAttribute + typealias AllAttributes = AccessKeyAttribute & AcceptAttribute & ActionAttribute & AlternateAttribute & AsynchronouslyAttribute & AutocapitalizeAttribute & AutocompleteAttribute & AutofocusAttribute & AutoplayAttribute & CharsetAttribute & CheckedAttribute & CiteAttribute & ClassAttribute & ColumnsAttribute & ColumnSpanAttribute & ContentAttribute & EditAttribute & ControlsAttribute & DataAttribute & DateTimeAttribute & DefaultAttribute & DeferAttribute & DirectionAttribute & DisabledAttribute & DownloadAttribute & DragAttribute & EncodingAttribute & EnterKeyAttribute & ForAttribute & FormAttribute & FormActionAttribute & EquivalentAttribute & HeadersAttribute & HeightAttribute & HiddenAttribute & HighAttribute & ReferenceAttribute & ReferenceLanguageAttribute & IdentifierAttribute & IsMapAttribute & InputModeAttribute & IsAttribute & ItemAttribute & ItemPropertyAttribute & KindAttribute & LabelAttribute & LanguageAttribute & ListAttribute & LoopAttribute & LowAttribute & MaximumValueAttribute & MaximumLengthAttribute & MediaAttribute & MethodAttribute & MinimumValueAttribute & MinimumLengthAttribute & MultipleAttribute & MutedAttribute & NameAttribute & NonceAttribute & NoValidateAttribute & OpenAttribute & OptimumAttribute & PatternAttribute & PartAttribute & PingAttribute & PlaceholderAttribute & PosterAttribute & PreloadAttribute & ReadOnlyAttribute & ReferrerPolicyAttribute & RelationshipAttribute & RequiredAttribute & ReversedAttribute & RoleAttribute & RowsAttribute & RowSpanAttribute & SandboxAttribute & ScopeAttribute & ShapeAttribute & SizeAttribute & SizesAttribute & SlotAttribute & SpanAttribute & SpellCheckAttribute & SourceAttribute & StartAttribute & StepAttribute & StyleAttribute & TabulatorAttribute & TargetAttribute & TitleAttribute & TranslateAttribute & TypeAttribute & ValueAttribute & WidthAttribute & WrapAttribute & PropertyAttribute & SelectedAttribute & WindowEventAttribute & FocusEventAttribute & PointerEventAttribute & MouseEventAttribute & WheelEventAttribute & InputEventAttribute & KeyboardEventAttribute & DragEventAttribute & ClipboardEventAttribute & SelectionEventAttribute & MediaEventAttribute & FormEventAttribute & DetailEventAttribute & AtomicAccessibilityAttribute & BusyAccessibilityAttribute & ControlsAccessibilityAttribute & CurrentAccessibilityAttribute & DescriptionsAccessibilityAttribute & DetailAccessibilityAttribute & DisabledAccessibilityAttribute & FlowAccessibilityAttribute & PopupAccessibilityAttribute & HiddenAccessibilityAttribute & InvalidAccessibilityAttribute & ShortcutsAccessibilityAttribute & LabelAccessibilityAttribute & LabelsAccessibilityAttribute & LiveAccessibilityAttribute & OwnsAccessibilityAttribute & MultilineAccessibilityAttribute & RowIndexAccessibilityAttribute & RelevantAccessibilityAttribute & RoleDescriptionAccessibilityAttribute & SortAccessibilityAttribute & OrientationAccessibilityAttribute & RequiredAccessibilityAttribute & ReadOnlyAccessibilityAttribute & ModalAccessibilityAttribute & LevelAccessibilityAttribute & HintAccessibilityAttribute & PositionAccessibilityAttribute & MultiselectAccessibilityAttribute & RowCountAccessibilityAttribute & ColumnIndexAccessibilityAttribute & ColumnCountAccessibilityAttribute & RowSpanAccessibilityAttribute & ColumnSpanAccessibilityAttribute & MaximumValueAccessibilityAttribute & MinimumValueAccessibilityAttribute & ValueAccessibilityAttribute & PressedAccessibilityAttribute & SelectedAccessibilityAttribute & CheckedAccessibilityAttribute & ExpandedAccessibilityAttribute & FocusedAccessibilityAttribute & CompletionAccessibilityAttribute & DrawAttribute & FillAttribute & StrokeAttribute & RadiusAttribute & PositionPointAttribute & RadiusPointAttribute & CenterPointAttribute & ViewBoxAttribute & NamespaceAttribute & PointsAttribute & ShadowRootModeAttribute & InertAttribute & FetchPriorityAttribute & LoadingAttribute & SourceSetAttribute & DecodingAttribute & BlockingAttribute & PopoverAttribute & PopoverTargetAttribute & UseMapAttribute & PlaysInlineAttribute & IntegrityAttribute & AsAttribute & CrossOriginAttribute & SourceLanguageAttribute & SourceDocumentAttribute & AbbreviatedAttribute & ImageSourcesAttribute & ImageSizesAttribute struct Tag: ContentNode, GlobalElement, AllAttributes { @@ -1218,6 +1218,14 @@ final class AttributesTests: XCTestCase { func imageSources(_ candidates: HTMLKit.SourceCandidate...) -> Tag { return mutate(imagesrcset: .init(EnumeratedList(values: candidates, separator: ", "), context: .tainted(.html))) } + + func imageSizes(_ candidates: [HTMLKit.SizeCandidate]) -> Tag { + return mutate(imagesizes: .init(EnumeratedList(values: candidates, separator: ", "), context: .tainted(.html))) + } + + func imageSizes(_ candidates: HTMLKit.SizeCandidate...) -> Tag { + return mutate(imagesizes: .init(EnumeratedList(values: candidates, separator: ", "), context: .tainted(.html))) + } } var renderer = Renderer() @@ -3904,4 +3912,31 @@ final class AttributesTests: XCTestCase { """ ) } + + func testImageSizesAttribute() throws { + + let view = TestView { + Tag {}.imageSizes(SizeCandidate("auto")) + Tag {}.imageSizes(SizeCandidate("100vw", conditions: .orientation(.landscape))) + Tag {}.imageSizes(SizeCandidate("100vw", conditions: .orientation(.portrait))) + Tag {}.imageSizes(SizeCandidate("100vw", conditions: .orientation(.landscape), .width("50em"))) + Tag {}.imageSizes(SizeCandidate("calc(100vw - 100px)", conditions: .minWidth("50em"))) + Tag {}.imageSizes(SizeCandidate("100vw", conditions: .maxWidth("50em"))) + Tag {}.imageSizes([SizeCandidate("100vw"), SizeCandidate("100vw", conditions: .maxWidth("50em"))]) + Tag {}.imageSizes(SizeCandidate("100vw"), SizeCandidate("100vw", conditions: .maxWidth("50em"))) + } + + XCTAssertEqual(try renderer.render(view: view), + """ + \ + \ + \ + \ + \ + \ + \ + + """ + ) + } }