diff --git a/Sources/HTMLKit/External/Attributes/VectorAttributes.swift b/Sources/HTMLKit/External/Attributes/VectorAttributes.swift
new file mode 100644
index 00000000..ee28a01e
--- /dev/null
+++ b/Sources/HTMLKit/External/Attributes/VectorAttributes.swift
@@ -0,0 +1,398 @@
+/// ## Description
+/// The file contains the basic attribute handlers.
+///
+/// ## Note
+/// If you about to add something to the file, stick to the official documentation to keep the code consistent.
+///
+/// ## Authors
+/// Mats Moll: https://github.com/matsmoll
+/// Mattes Mohr: https://github.com/mattesmohr
+
+import OrderedCollections
+
+/// ## Description
+/// The alias combines the global attributes.
+///
+/// ## References
+public typealias GlobalVectorAttributes = IdentifierAttribute & TabulatorAttribute & ClassAttribute & StyleAttribute & FillAttribute & FillOpacityAttribute & StrokeAttribute & StrokeWidthAttribute & StrokeOpacityAttribute & StrokeLineCapAttribute & StrokeLineJoinAttribute
+
+/// ## Description
+/// The protocol provides the element with the fill handler.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#attr-option-selected
+///
+public protocol FillAttribute: AnyAttribute {
+
+ /// The func adds
+ ///
+ ///
+ func fill(_ value: String) -> Self
+}
+
+extension FillAttribute {
+
+ internal var key: String { "fill" }
+}
+
+extension FillAttribute where Self: ContentNode {
+
+ internal func mutate(fill value: String) -> Self {
+
+ guard var attributes = self.attributes else {
+ return .init(attributes: set(key: key, value: value), content: content)
+ }
+
+ return .init(attributes: update(key: key, value: value, on: &attributes), content: content)
+ }
+}
+
+/// ## Description
+/// The protocol provides the element with the fill-opacity handler.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#attr-option-selected
+///
+public protocol FillOpacityAttribute: AnyAttribute {
+
+ /// The func adds
+ ///
+ ///
+ func fillOpacity(_ value: Double) -> Self
+}
+
+extension FillOpacityAttribute {
+
+ internal var key: String { "fill-opacity" }
+}
+
+extension FillOpacityAttribute where Self: ContentNode {
+
+ internal func mutate(fillopacity value: Double) -> Self {
+
+ guard var attributes = self.attributes else {
+ return .init(attributes: set(key: key, value: value), content: content)
+ }
+
+ return .init(attributes: update(key: key, value: value, on: &attributes), content: content)
+ }
+}
+
+/// ## Description
+/// The protocol provides the element with the stroke handler.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#attr-option-selected
+///
+public protocol StrokeAttribute: AnyAttribute {
+
+ /// The func adds
+ ///
+ ///
+ func stroke(_ value: String) -> Self
+}
+
+extension StrokeAttribute {
+
+ internal var key: String { "stroke" }
+}
+
+extension StrokeAttribute where Self: ContentNode {
+
+ internal func mutate(stroke value: String) -> Self {
+
+ guard var attributes = self.attributes else {
+ return .init(attributes: set(key: key, value: value), content: content)
+ }
+
+ return .init(attributes: update(key: key, value: value, on: &attributes), content: content)
+ }
+}
+
+/// ## Description
+/// The protocol provides the element with the stroke-width handler.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#attr-option-selected
+///
+public protocol StrokeWidthAttribute: AnyAttribute {
+
+ /// The func adds
+ ///
+ ///
+ func strokeWidth(_ size: Int) -> Self
+}
+
+extension StrokeWidthAttribute {
+
+ internal var key: String { "stroke-width" }
+}
+
+extension StrokeWidthAttribute where Self: ContentNode {
+
+ internal func mutate(strokewidth value: Int) -> Self {
+
+ guard var attributes = self.attributes else {
+ return .init(attributes: set(key: key, value: value), content: content)
+ }
+
+ return .init(attributes: update(key: key, value: value, on: &attributes), content: content)
+ }
+}
+
+/// ## Description
+/// The protocol provides the element with the stroke-opacity handler.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#attr-option-selected
+///
+public protocol StrokeOpacityAttribute: AnyAttribute {
+
+ /// The func adds
+ ///
+ ///
+ func strokeOpacity(_ value: Double) -> Self
+}
+
+extension StrokeOpacityAttribute {
+
+ internal var key: String { "stroke-opacity" }
+}
+
+extension StrokeOpacityAttribute where Self: ContentNode {
+
+ internal func mutate(strokeopacity value: Double) -> Self {
+
+ guard var attributes = self.attributes else {
+ return .init(attributes: set(key: key, value: value), content: content)
+ }
+
+ return .init(attributes: update(key: key, value: value, on: &attributes), content: content)
+ }
+}
+
+/// ## Description
+/// The protocol provides the element with the stroke-linecap handler.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#attr-option-selected
+///
+public protocol StrokeLineCapAttribute: AnyAttribute {
+
+ /// The func adds
+ ///
+ ///
+ func strokeLineCap(_ type: Linecap) -> Self
+}
+
+extension StrokeLineCapAttribute {
+
+ internal var key: String { "stroke-linecap" }
+}
+
+extension StrokeLineCapAttribute where Self: ContentNode {
+
+ internal func mutate(strokelinecap value: String) -> Self {
+
+ guard var attributes = self.attributes else {
+ return .init(attributes: set(key: key, value: value), content: content)
+ }
+
+ return .init(attributes: update(key: key, value: value, on: &attributes), content: content)
+ }
+}
+
+/// ## Description
+/// The protocol provides the element with the stroke-linejoin handler.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#attr-option-selected
+///
+public protocol StrokeLineJoinAttribute: AnyAttribute {
+
+ /// The func adds
+ ///
+ ///
+ func strokeLineJoin(_ type: Linejoin) -> Self
+}
+
+extension StrokeLineJoinAttribute {
+
+ internal var key: String { "stroke-linejoin" }
+}
+
+extension StrokeLineJoinAttribute where Self: ContentNode {
+
+ internal func mutate(strokelinejoin value: String) -> Self {
+
+ guard var attributes = self.attributes else {
+ return .init(attributes: set(key: key, value: value), content: content)
+ }
+
+ return .init(attributes: update(key: key, value: value, on: &attributes), content: content)
+ }
+}
+
+/// ## Description
+/// The protocol provides the element with the radius handler.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#attr-option-selected
+///
+public protocol RadiusAttribute: AnyAttribute {
+
+ /// The func adds
+ ///
+ ///
+ func radius(_ size: Int) -> Self
+}
+
+extension RadiusAttribute {
+
+ internal var key: String { "r" }
+}
+
+extension RadiusAttribute where Self: ContentNode {
+
+ internal func mutate(radius value: Int) -> Self {
+
+ guard var attributes = self.attributes else {
+ return .init(attributes: set(key: key, value: value), content: content)
+ }
+
+ return .init(attributes: update(key: key, value: value, on: &attributes), content: content)
+ }
+}
+
+/// ## Description
+/// The protocol provides the element with the radius handler.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#attr-option-selected
+///
+public protocol PositionPointAttribute: AnyAttribute {
+
+ /// The func adds
+ ///
+ ///
+ func positionPoint(_ point: Point) -> Self
+}
+
+extension PositionPointAttribute where Self: ContentNode {
+
+ internal func mutate(radius: Point) -> Self {
+
+ guard var attributes = self.attributes else {
+
+ var attributes = OrderedDictionary()
+ attributes["x"] = radius.x
+ attributes["y"] = radius.y
+
+ return .init(attributes: attributes, content: content)
+ }
+
+ attributes["x"] = radius.x
+ attributes["y"] = radius.y
+
+ return .init(attributes: attributes, content: content)
+ }
+}
+
+/// ## Description
+/// The protocol provides the element with the radius handler.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#attr-option-selected
+///
+public protocol RadiusPointAttribute: AnyAttribute {
+
+ /// The func adds
+ ///
+ ///
+ func radiusPoint(_ point: Point) -> Self
+}
+
+extension RadiusPointAttribute where Self: ContentNode {
+
+ internal func mutate(radius: Point) -> Self {
+
+ guard var attributes = self.attributes else {
+
+ var attributes = OrderedDictionary()
+ attributes["rx"] = radius.x
+ attributes["ry"] = radius.y
+
+ return .init(attributes: attributes, content: content)
+ }
+
+ attributes["rx"] = radius.x
+ attributes["ry"] = radius.y
+
+ return .init(attributes: attributes, content: content)
+ }
+}
+
+/// ## Description
+/// The protocol provides the element with the radius handler.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#attr-option-selected
+///
+public protocol CenterPointAttribute: AnyAttribute {
+
+ /// The func adds
+ ///
+ ///
+ func centerPoint(_ point: Point) -> Self
+}
+
+extension CenterPointAttribute where Self: ContentNode {
+
+ internal func mutate(centerpoint: Point) -> Self {
+
+ guard var attributes = self.attributes else {
+
+ var attributes = OrderedDictionary()
+ attributes["cx"] = centerpoint.x
+ attributes["cy"] = centerpoint.y
+
+ return .init(attributes: attributes, content: content)
+ }
+
+ attributes["cx"] = centerpoint.x
+ attributes["cy"] = centerpoint.y
+
+ return .init(attributes: attributes, content: content)
+ }
+}
+
+/// ## Description
+/// The protocol provides the element with the viewbox handler.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#attr-option-selected
+///
+public protocol ViewBoxAttribute: AnyAttribute {
+
+ /// The func adds
+ ///
+ ///
+ func viewBox(_ value: String) -> Self
+}
+
+extension ViewBoxAttribute {
+
+ internal var key: String { "viewbox" }
+}
+
+extension ViewBoxAttribute where Self: ContentNode {
+
+ internal func mutate(viewbox value: String) -> Self {
+
+ guard var attributes = self.attributes else {
+ return .init(attributes: set(key: key, value: value), content: content)
+ }
+
+ return .init(attributes: update(key: key, value: value, on: &attributes), content: content)
+ }
+}
diff --git a/Sources/HTMLKit/External/Elements/BodyElements.swift b/Sources/HTMLKit/External/Elements/BodyElements.swift
index 4a8861a3..ee8a84fe 100644
--- a/Sources/HTMLKit/External/Elements/BodyElements.swift
+++ b/Sources/HTMLKit/External/Elements/BodyElements.swift
@@ -191,6 +191,11 @@ public typealias Iframe = InlineFrame
///
public typealias Param = Parameter
+/// ## Description
+/// The alias points to Parameter.
+///
+public typealias Svg = Vector
+
/// ## Description
/// The element represents a self-contained content.
///
@@ -14357,3 +14362,101 @@ extension Table: Modifiable {
}
}
}
+
+/// ## Description
+/// The element represents a vector.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#the-table-element
+///
+public struct Vector: ContentNode, HtmlElement, BodyElement, FormElement, FigureElement, ObjectElement {
+
+ internal var name: String { "svg" }
+
+ internal var attributes: OrderedDictionary?
+
+ internal var content: [VectorElement]
+
+ public init(@ContentBuilder content: () -> [VectorElement]) {
+ self.content = content()
+ }
+
+ internal init(attributes: OrderedDictionary?, content: [VectorElement]) {
+ self.attributes = attributes
+ self.content = content
+ }
+}
+
+extension Vector: AnyContent {
+
+ public func prerender(_ formula: Renderer.Formula) throws {
+ try self.build(formula)
+ }
+
+ public func render(with manager: Renderer.ContextManager) throws -> String {
+ return try self.build(with: manager)
+ }
+}
+
+extension Vector: GlobalVectorAttributes, WidthAttribute, HeightAttribute, ViewBoxAttribute {
+
+ public func id(_ value: String) -> Vector {
+ return self.mutate(id: value)
+ }
+
+ public func id(_ value: TemplateValue) -> Vector {
+ return self.mutate(id: value.rawValue)
+ }
+
+ public func tabIndex(_ value: String) -> Vector {
+ return self.mutate(tabindex: value)
+ }
+
+ public func width(_ size: Int) -> Vector {
+ return self.mutate(width: size)
+ }
+
+ public func height(_ size: Int) -> Vector {
+ return self.mutate(height: size)
+ }
+
+ public func `class`(_ value: String) -> Vector {
+ return self.mutate(class: value)
+ }
+
+ public func style(_ value: String) -> Vector {
+ return self.mutate(style: value)
+ }
+
+ public func viewBox(_ value: String) -> Vector {
+ return self.mutate(viewbox: value)
+ }
+
+ public func fill(_ value: String) -> Vector {
+ return self.mutate(fill: value)
+ }
+
+ public func stroke(_ value: String) -> Vector {
+ return self.mutate(stroke: value)
+ }
+
+ public func strokeWidth(_ size: Int) -> Vector {
+ return self.mutate(strokewidth: size)
+ }
+
+ public func fillOpacity(_ value: Double) -> Vector {
+ return self.mutate(fillopacity: value)
+ }
+
+ public func strokeOpacity(_ value: Double) -> Vector {
+ return self.mutate(strokeopacity: value)
+ }
+
+ public func strokeLineCap(_ type: Linecap) -> Vector {
+ return self.mutate(strokelinecap: type.rawValue)
+ }
+
+ public func strokeLineJoin(_ type: Linejoin) -> Vector {
+ return self.mutate(strokelinejoin: type.rawValue)
+ }
+}
diff --git a/Sources/HTMLKit/External/Elements/VectorElements.swift b/Sources/HTMLKit/External/Elements/VectorElements.swift
new file mode 100644
index 00000000..a72a8e0b
--- /dev/null
+++ b/Sources/HTMLKit/External/Elements/VectorElements.swift
@@ -0,0 +1,738 @@
+import OrderedCollections
+
+/// ## Description
+/// The alias points to Rectangle.
+///
+public typealias Rect = Rectangle
+
+/// ## Description
+/// The element represents ...
+///
+/// ## References
+/// https://html.spec.whatwg.org/#the-table-element
+///
+public struct Circle: ContentNode, VectorElement {
+
+ internal var name: String { "circle" }
+
+ internal var attributes: OrderedDictionary?
+
+ internal var content: [AnyContent]
+
+ public init(@ContentBuilder content: () -> [AnyContent]) {
+ self.content = content()
+ }
+
+ internal init(attributes: OrderedDictionary?, content: [AnyContent]) {
+ self.attributes = attributes
+ self.content = content
+ }
+}
+
+extension Circle: GlobalVectorAttributes, CenterPointAttribute, RadiusAttribute {
+
+ public func id(_ value: String) -> Circle {
+ return self.mutate(id: value)
+ }
+
+ public func id(_ value: TemplateValue) -> Circle {
+ return self.mutate(id: value.rawValue)
+ }
+
+ public func tabIndex(_ value: String) -> Circle {
+ return self.mutate(tabindex: value)
+ }
+
+ public func `class`(_ value: String) -> Circle {
+ return self.mutate(class: value)
+ }
+
+ public func style(_ value: String) -> Circle {
+ return self.mutate(style: value)
+ }
+
+ public func fill(_ value: String) -> Circle {
+ return self.mutate(fill: value)
+ }
+
+ public func stroke(_ value: String) -> Circle {
+ return self.mutate(stroke: value)
+ }
+
+ public func strokeWidth(_ size: Int) -> Circle {
+ return self.mutate(strokewidth: size)
+ }
+
+ public func centerPoint(_ point: Point) -> Circle {
+ return self.mutate(centerpoint: point)
+ }
+
+ public func radius(_ size: Int) -> Circle {
+ return self.mutate(radius: size)
+ }
+
+ public func fillOpacity(_ value: Double) -> Circle {
+ return self.mutate(fillopacity: value)
+ }
+
+ public func strokeOpacity(_ value: Double) -> Circle {
+ return self.mutate(strokeopacity: value)
+ }
+
+ public func strokeLineCap(_ type: Linecap) -> Circle {
+ return self.mutate(strokelinecap: type.rawValue)
+ }
+
+ public func strokeLineJoin(_ type: Linejoin) -> Circle {
+ return self.mutate(strokelinejoin: type.rawValue)
+ }
+}
+
+extension Circle: AnyContent {
+
+ public func prerender(_ formula: Renderer.Formula) throws {
+ try self.build(formula)
+ }
+
+ public func render(with manager: Renderer.ContextManager) throws -> String {
+ try self.build(with: manager)
+ }
+}
+
+/// ## Description
+/// The element represents ...
+///
+/// ## References
+/// https://html.spec.whatwg.org/#the-table-element
+///
+public struct Rectangle: ContentNode, VectorElement {
+
+ internal var name: String { "rect" }
+
+ internal var attributes: OrderedDictionary?
+
+ internal var content: [AnyContent]
+
+ public init(@ContentBuilder content: () -> [AnyContent]) {
+ self.content = content()
+ }
+
+ internal init(attributes: OrderedDictionary?, content: [AnyContent]) {
+ self.attributes = attributes
+ self.content = content
+ }
+}
+
+extension Rectangle: GlobalVectorAttributes, WidthAttribute, HeightAttribute, RadiusPointAttribute {
+
+ public func id(_ value: String) -> Rectangle {
+ return self.mutate(id: value)
+ }
+
+ public func id(_ value: TemplateValue) -> Rectangle {
+ return self.mutate(id: value.rawValue)
+ }
+
+ public func tabIndex(_ value: String) -> Rectangle {
+ return self.mutate(tabindex: value)
+ }
+
+ public func `class`(_ value: String) -> Rectangle {
+ return self.mutate(class: value)
+ }
+
+ public func style(_ value: String) -> Rectangle {
+ return self.mutate(style: value)
+ }
+
+ public func fill(_ value: String) -> Rectangle {
+ return self.mutate(fill: value)
+ }
+
+ public func stroke(_ value: String) -> Rectangle {
+ return self.mutate(stroke: value)
+ }
+
+ public func strokeWidth(_ size: Int) -> Rectangle {
+ return self.mutate(strokewidth: size)
+ }
+
+ public func radiusPoint(_ point: Point) -> Rectangle {
+ return self.mutate(radius: point)
+ }
+
+ public func width(_ size: Int) -> Rectangle {
+ return self.mutate(width: size)
+ }
+
+ public func height(_ size: Int) -> Rectangle {
+ return self.mutate(height: size)
+ }
+
+ public func fillOpacity(_ value: Double) -> Rectangle {
+ return self.mutate(fillopacity: value)
+ }
+
+ public func strokeOpacity(_ value: Double) -> Rectangle {
+ return self.mutate(strokeopacity: value)
+ }
+
+ public func strokeLineCap(_ type: Linecap) -> Rectangle {
+ return self.mutate(strokelinecap: type.rawValue)
+ }
+
+ public func strokeLineJoin(_ type: Linejoin) -> Rectangle {
+ return self.mutate(strokelinejoin: type.rawValue)
+ }
+}
+
+extension Rectangle: AnyContent {
+
+ public func prerender(_ formula: Renderer.Formula) throws {
+ try self.build(formula)
+ }
+
+ public func render(with manager: Renderer.ContextManager) throws -> String {
+ try self.build(with: manager)
+ }
+}
+
+/// ## Description
+/// The element represents a comment output.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#the-table-element
+///
+public struct Ellipse: ContentNode, VectorElement {
+
+ internal var name: String { "ellipse" }
+
+ internal var attributes: OrderedDictionary?
+
+ internal var content: [AnyContent]
+
+ public init(@ContentBuilder content: () -> [AnyContent]) {
+ self.content = content()
+ }
+
+ internal init(attributes: OrderedDictionary?, content: [AnyContent]) {
+ self.attributes = attributes
+ self.content = content
+ }
+}
+
+extension Ellipse: GlobalVectorAttributes, CenterPointAttribute, RadiusPointAttribute {
+
+ public func id(_ value: String) -> Ellipse {
+ return self.mutate(id: value)
+ }
+
+ public func id(_ value: TemplateValue) -> Ellipse {
+ return self.mutate(id: value.rawValue)
+ }
+
+ public func tabIndex(_ value: String) -> Ellipse {
+ return self.mutate(tabindex: value)
+ }
+
+ public func `class`(_ value: String) -> Ellipse {
+ return self.mutate(class: value)
+ }
+
+ public func style(_ value: String) -> Ellipse {
+ return self.mutate(style: value)
+ }
+
+ public func fill(_ value: String) -> Ellipse {
+ return self.mutate(fill: value)
+ }
+
+ public func stroke(_ value: String) -> Ellipse {
+ return self.mutate(stroke: value)
+ }
+
+ public func strokeWidth(_ size: Int) -> Ellipse {
+ return self.mutate(strokewidth: size)
+ }
+
+ public func centerPoint(_ point: Point) -> Ellipse {
+ return self.mutate(centerpoint: point)
+ }
+
+ public func radiusPoint(_ point: Point) -> Ellipse {
+ return self.mutate(radius: point)
+ }
+
+ public func fillOpacity(_ value: Double) -> Ellipse {
+ return self.mutate(fillopacity: value)
+ }
+
+ public func strokeOpacity(_ value: Double) -> Ellipse {
+ return self.mutate(strokeopacity: value)
+ }
+
+ public func strokeLineCap(_ type: Linecap) -> Ellipse {
+ return self.mutate(strokelinecap: type.rawValue)
+ }
+
+ public func strokeLineJoin(_ type: Linejoin) -> Ellipse {
+ return self.mutate(strokelinejoin: type.rawValue)
+ }
+}
+
+extension Ellipse: AnyContent {
+
+ public func prerender(_ formula: Renderer.Formula) throws {
+ try self.build(formula)
+ }
+
+ public func render(with manager: Renderer.ContextManager) throws -> String {
+ try self.build(with: manager)
+ }
+}
+
+/// ## Description
+/// The element represents ...
+///
+/// ## References
+/// https://html.spec.whatwg.org/#the-table-element
+///
+public struct Line: ContentNode, VectorElement {
+
+ internal var name: String { "line" }
+
+ internal var attributes: OrderedDictionary?
+
+ internal var content: [AnyContent]
+
+ public init(@ContentBuilder content: () -> [AnyContent]) {
+ self.content = content()
+ }
+
+ internal init(attributes: OrderedDictionary?, content: [AnyContent]) {
+ self.attributes = attributes
+ self.content = content
+ }
+}
+
+extension Line: GlobalVectorAttributes {
+
+ public func id(_ value: String) -> Line {
+ return self.mutate(id: value)
+ }
+
+ public func id(_ value: TemplateValue) -> Line {
+ return self.mutate(id: value.rawValue)
+ }
+
+ public func tabIndex(_ value: String) -> Line {
+ return self.mutate(tabindex: value)
+ }
+
+ public func `class`(_ value: String) -> Line {
+ return self.mutate(class: value)
+ }
+
+ public func style(_ value: String) -> Line {
+ return self.mutate(style: value)
+ }
+
+ public func fill(_ value: String) -> Line {
+ return self.mutate(fill: value)
+ }
+
+ public func stroke(_ value: String) -> Line {
+ return self.mutate(stroke: value)
+ }
+
+ public func strokeWidth(_ size: Int) -> Line {
+ return self.mutate(strokewidth: size)
+ }
+
+ public func fillOpacity(_ value: Double) -> Line {
+ return self.mutate(fillopacity: value)
+ }
+
+ public func strokeOpacity(_ value: Double) -> Line {
+ return self.mutate(strokeopacity: value)
+ }
+
+ public func strokeLineCap(_ type: Linecap) -> Line {
+ return self.mutate(strokelinecap: type.rawValue)
+ }
+
+ public func strokeLineJoin(_ type: Linejoin) -> Line {
+ return self.mutate(strokelinejoin: type.rawValue)
+ }
+}
+
+extension Line: AnyContent {
+
+ public func prerender(_ formula: Renderer.Formula) throws {
+ try self.build(formula)
+ }
+
+ public func render(with manager: Renderer.ContextManager) throws -> String {
+ try self.build(with: manager)
+ }
+}
+
+/// ## Description
+/// The element represents a comment output.
+///
+/// ## References
+/// https://html.spec.whatwg.org/#the-table-element
+///
+public struct Polygon: ContentNode, VectorElement {
+
+ internal var name: String { "polygon" }
+
+ internal var attributes: OrderedDictionary?
+
+ internal var content: [AnyContent]
+
+ public init(@ContentBuilder content: () -> [AnyContent]) {
+ self.content = content()
+ }
+
+ internal init(attributes: OrderedDictionary?, content: [AnyContent]) {
+ self.attributes = attributes
+ self.content = content
+ }
+}
+
+extension Polygon: GlobalVectorAttributes {
+
+ public func id(_ value: String) -> Polygon {
+ return self.mutate(id: value)
+ }
+
+ public func id(_ value: TemplateValue) -> Polygon {
+ return self.mutate(id: value.rawValue)
+ }
+
+ public func tabIndex(_ value: String) -> Polygon {
+ return self.mutate(tabindex: value)
+ }
+
+ public func `class`(_ value: String) -> Polygon {
+ return self.mutate(class: value)
+ }
+
+ public func style(_ value: String) -> Polygon {
+ return self.mutate(style: value)
+ }
+
+ public func fill(_ value: String) -> Polygon {
+ return self.mutate(fill: value)
+ }
+
+ public func stroke(_ value: String) -> Polygon {
+ return self.mutate(stroke: value)
+ }
+
+ public func strokeWidth(_ size: Int) -> Polygon {
+ return self.mutate(strokewidth: size)
+ }
+
+ public func fillOpacity(_ value: Double) -> Polygon {
+ return self.mutate(fillopacity: value)
+ }
+
+ public func strokeOpacity(_ value: Double) -> Polygon {
+ return self.mutate(strokeopacity: value)
+ }
+
+ public func strokeLineCap(_ type: Linecap) -> Polygon {
+ return self.mutate(strokelinecap: type.rawValue)
+ }
+
+ public func strokeLineJoin(_ type: Linejoin) -> Polygon {
+ return self.mutate(strokelinejoin: type.rawValue)
+ }
+}
+
+extension Polygon: AnyContent {
+
+ public func prerender(_ formula: Renderer.Formula) throws {
+ try self.build(formula)
+ }
+
+ public func render(with manager: Renderer.ContextManager) throws -> String {
+ try self.build(with: manager)
+ }
+}
+
+/// ## Description
+/// The element represents ...
+///
+/// ## References
+/// https://html.spec.whatwg.org/#the-table-element
+///
+public struct Polyline: ContentNode, VectorElement {
+
+ internal var name: String { "polyline" }
+
+ internal var attributes: OrderedDictionary?
+
+ internal var content: [AnyContent]
+
+ public init(@ContentBuilder content: () -> [AnyContent]) {
+ self.content = content()
+ }
+
+ internal init(attributes: OrderedDictionary?, content: [AnyContent]) {
+ self.attributes = attributes
+ self.content = content
+ }
+}
+
+extension Polyline: GlobalVectorAttributes {
+
+ public func id(_ value: String) -> Polyline {
+ return self.mutate(id: value)
+ }
+
+ public func id(_ value: TemplateValue) -> Polyline {
+ return self.mutate(id: value.rawValue)
+ }
+
+ public func tabIndex(_ value: String) -> Polyline {
+ return self.mutate(tabindex: value)
+ }
+
+ public func `class`(_ value: String) -> Polyline {
+ return self.mutate(class: value)
+ }
+
+ public func style(_ value: String) -> Polyline {
+ return self.mutate(style: value)
+ }
+
+ public func fill(_ value: String) -> Polyline {
+ return self.mutate(fill: value)
+ }
+
+ public func stroke(_ value: String) -> Polyline {
+ return self.mutate(stroke: value)
+ }
+
+ public func strokeWidth(_ size: Int) -> Polyline {
+ return self.mutate(strokewidth: size)
+ }
+
+ public func fillOpacity(_ value: Double) -> Polyline {
+ return self.mutate(fillopacity: value)
+ }
+
+ public func strokeOpacity(_ value: Double) -> Polyline {
+ return self.mutate(strokeopacity: value)
+ }
+
+ public func strokeLineCap(_ type: Linecap) -> Polyline {
+ return self.mutate(strokelinecap: type.rawValue)
+ }
+
+ public func strokeLineJoin(_ type: Linejoin) -> Polyline {
+ return self.mutate(strokelinejoin: type.rawValue)
+ }
+}
+
+extension Polyline: AnyContent {
+
+ public func prerender(_ formula: Renderer.Formula) throws {
+ try self.build(formula)
+ }
+
+ public func render(with manager: Renderer.ContextManager) throws -> String {
+ try self.build(with: manager)
+ }
+}
+
+/// ## Description
+/// The element represents ...
+///
+/// ## References
+/// https://html.spec.whatwg.org/#the-table-element
+///
+public struct Path: ContentNode, VectorElement {
+
+ internal var name: String { "path" }
+
+ internal var attributes: OrderedDictionary?
+
+ internal var content: [AnyContent]
+
+ public init(@ContentBuilder content: () -> [AnyContent]) {
+ self.content = content()
+ }
+
+ internal init(attributes: OrderedDictionary?, content: [AnyContent]) {
+ self.attributes = attributes
+ self.content = content
+ }
+}
+
+extension Path: GlobalVectorAttributes {
+
+ public func id(_ value: String) -> Path {
+ return self.mutate(id: value)
+ }
+
+ public func id(_ value: TemplateValue) -> Path {
+ return self.mutate(id: value.rawValue)
+ }
+
+ public func tabIndex(_ value: String) -> Path {
+ return self.mutate(tabindex: value)
+ }
+
+ public func `class`(_ value: String) -> Path {
+ return self.mutate(class: value)
+ }
+
+ public func style(_ value: String) -> Path {
+ return self.mutate(style: value)
+ }
+
+ public func fill(_ value: String) -> Path {
+ return self.mutate(fill: value)
+ }
+
+ public func stroke(_ value: String) -> Path {
+ return self.mutate(stroke: value)
+ }
+
+ public func strokeWidth(_ size: Int) -> Path {
+ return self.mutate(strokewidth: size)
+ }
+
+ public func fillOpacity(_ value: Double) -> Path {
+ return self.mutate(fillopacity: value)
+ }
+
+ public func strokeOpacity(_ value: Double) -> Path {
+ return self.mutate(strokeopacity: value)
+ }
+
+ public func strokeLineCap(_ type: Linecap) -> Path {
+ return self.mutate(strokelinecap: type.rawValue)
+ }
+
+ public func strokeLineJoin(_ type: Linejoin) -> Path {
+ return self.mutate(strokelinejoin: type.rawValue)
+ }
+}
+
+extension Path: AnyContent {
+
+ public func prerender(_ formula: Renderer.Formula) throws {
+ try self.build(formula)
+ }
+
+ public func render(with manager: Renderer.ContextManager) throws -> String {
+ try self.build(with: manager)
+ }
+}
+
+/// ## Description
+/// The element represents ...
+///
+/// ## References
+/// https://html.spec.whatwg.org/#the-table-element
+///
+public struct Use: ContentNode, VectorElement {
+
+ internal var name: String { "use" }
+
+ internal var attributes: OrderedDictionary?
+
+ internal var content: [AnyContent]
+
+ public init(@ContentBuilder content: () -> [AnyContent]) {
+ self.content = content()
+ }
+
+ internal init(attributes: OrderedDictionary?, content: [AnyContent]) {
+ self.attributes = attributes
+ self.content = content
+ }
+}
+
+extension Use: GlobalVectorAttributes, ReferenceAttribute, WidthAttribute, HeightAttribute {
+
+ public func id(_ value: String) -> Use {
+ return self.mutate(id: value)
+ }
+
+ public func id(_ value: TemplateValue) -> Use {
+ return self.mutate(id: value.rawValue)
+ }
+
+ public func tabIndex(_ value: String) -> Use {
+ return self.mutate(tabindex: value)
+ }
+
+ public func reference(_ value: String) -> Use {
+ return self.mutate(href: value)
+ }
+
+ public func reference(_ value: TemplateValue) -> Use {
+ return self.mutate(href: value.rawValue)
+ }
+
+ public func width(_ size: Int) -> Use {
+ return self.mutate(width: size)
+ }
+
+ public func height(_ size: Int) -> Use {
+ return self.mutate(height: size)
+ }
+
+ public func `class`(_ value: String) -> Use {
+ return self.mutate(class: value)
+ }
+
+ public func style(_ value: String) -> Use {
+ return self.mutate(style: value)
+ }
+
+ public func fill(_ value: String) -> Use {
+ return self.mutate(fill: value)
+ }
+
+ public func stroke(_ value: String) -> Use {
+ return self.mutate(stroke: value)
+ }
+
+ public func strokeWidth(_ size: Int) -> Use {
+ return self.mutate(strokewidth: size)
+ }
+
+ public func fillOpacity(_ value: Double) -> Use {
+ return self.mutate(fillopacity: value)
+ }
+
+ public func strokeOpacity(_ value: Double) -> Use {
+ return self.mutate(strokeopacity: value)
+ }
+
+ public func strokeLineCap(_ type: Linecap) -> Use {
+ return self.mutate(strokelinecap: type.rawValue)
+ }
+
+ public func strokeLineJoin(_ type: Linejoin) -> Use {
+ return self.mutate(strokelinejoin: type.rawValue)
+ }
+}
+
+extension Use: AnyContent {
+
+ public func prerender(_ formula: Renderer.Formula) throws {
+ try self.build(formula)
+ }
+
+ public func render(with manager: Renderer.ContextManager) throws -> String {
+ try self.build(with: manager)
+ }
+}
diff --git a/Sources/HTMLKit/External/Sizes.swift b/Sources/HTMLKit/External/Sizes.swift
new file mode 100644
index 00000000..8463f834
--- /dev/null
+++ b/Sources/HTMLKit/External/Sizes.swift
@@ -0,0 +1,5 @@
+public struct Point {
+
+ var x: Int
+ var y: Int
+}
diff --git a/Sources/HTMLKit/External/Types.swift b/Sources/HTMLKit/External/Types.swift
index c1260a6e..5cda6584 100644
--- a/Sources/HTMLKit/External/Types.swift
+++ b/Sources/HTMLKit/External/Types.swift
@@ -580,3 +580,27 @@ public enum Roles: String {
case widget
case window
}
+
+/// ## Description
+/// The type is for
+///
+/// ## References
+///
+public enum Linecap: String {
+
+ case butt
+ case square
+ case round
+}
+
+/// ## Description
+/// The type is for
+///
+/// ## References
+///
+public enum Linejoin: String {
+
+ case miter
+ case round
+ case bevel
+}
diff --git a/Sources/HTMLKit/Internal/Core/Elements.swift b/Sources/HTMLKit/Internal/Core/Elements.swift
index 647eeaa6..24214263 100644
--- a/Sources/HTMLKit/Internal/Core/Elements.swift
+++ b/Sources/HTMLKit/Internal/Core/Elements.swift
@@ -121,3 +121,11 @@ public protocol TableElement: AnyElement {
///
public protocol HtmlElement: AnyElement {
}
+
+/// ## Description
+/// The protocol defines a vector element.
+///
+/// ## References
+///
+public protocol VectorElement: AnyElement {
+}
diff --git a/Sources/HTMLKit/Internal/Core/Extensions/Datatypes+Content.swift b/Sources/HTMLKit/Internal/Core/Extensions/Datatypes+Content.swift
index 1c9770b4..bb223b9b 100644
--- a/Sources/HTMLKit/Internal/Core/Extensions/Datatypes+Content.swift
+++ b/Sources/HTMLKit/Internal/Core/Extensions/Datatypes+Content.swift
@@ -243,6 +243,21 @@ extension Array where Element == HtmlElement {
}
}
+extension Array where Element == VectorElement {
+
+ public func prerender(_ formula: Renderer.Formula) throws {
+ try forEach { try $0.prerender(formula) }
+ }
+
+ public func render(with manager: Renderer.ContextManager) throws -> String {
+ return try self.reduce("") { try $0 + $1.render(with: manager) }
+ }
+
+ public var scripts: AnyContent {
+ return self.reduce("") { $0 + $1.scripts }
+ }
+}
+
/// The extension is
///
///
diff --git a/Sources/HTMLKit/Internal/Core/Nodes.swift b/Sources/HTMLKit/Internal/Core/Nodes.swift
index 4a89e8be..40aefc12 100644
--- a/Sources/HTMLKit/Internal/Core/Nodes.swift
+++ b/Sources/HTMLKit/Internal/Core/Nodes.swift
@@ -501,6 +501,36 @@ extension ContentNode where Content == HtmlElement {
}
}
+extension ContentNode where Content == VectorElement {
+
+ internal func build(_ formula: Renderer.Formula) throws {
+
+ formula.add(string: "<\(name)")
+
+ if let attributes = attributes {
+
+ attributes.forEach { attribute in
+ formula.add(string: " \(attribute.key)=\"\(attribute.value)\"")
+ }
+ }
+
+ formula.add(string: ">")
+
+ try content.prerender(formula)
+
+ formula.add(string: "\(name)>")
+ }
+
+ internal func build(with manager: Renderer.ContextManager) throws -> String {
+
+ guard let attributes = attributes else {
+ return try "<\(name)>\(content.render(with: manager))\(name)>"
+ }
+
+ return try "<\(name)" + attributes.map { attribute in return " \(attribute.key)=\"\(attribute.value)\"" } + ">\(content.render(with: manager))\(name)>" as! String
+ }
+}
+
extension ContentNode where Content == String {
internal func build(_ formula: Renderer.Formula) throws {
diff --git a/Tests/HTMLKitTests/ElementTests.swift b/Tests/HTMLKitTests/ElementTests.swift
index f53d0b2d..2a928c37 100644
--- a/Tests/HTMLKitTests/ElementTests.swift
+++ b/Tests/HTMLKitTests/ElementTests.swift
@@ -1740,6 +1740,150 @@ final class ElementTests: XCTestCase {
"""
)
}
+
+ func testVectorElement() throws {
+
+ let view = TestPage {
+ Vector {
+ }
+ }
+
+ try renderer.add(view: view)
+
+ XCTAssertEqual(try renderer.render(raw: TestPage.self),
+ """
+
+ """
+ )
+ }
+
+ func testCircleElement() throws {
+
+ let view = TestPage {
+ Circle {
+ }
+ }
+
+ try renderer.add(view: view)
+
+ XCTAssertEqual(try renderer.render(raw: TestPage.self),
+ """
+
+ """
+ )
+ }
+
+ func testRectangleElement() throws {
+
+ let view = TestPage {
+ Rectangle {
+ }
+ }
+
+ try renderer.add(view: view)
+
+ XCTAssertEqual(try renderer.render(raw: TestPage.self),
+ """
+
+ """
+ )
+ }
+
+ func testEllipseElement() throws {
+
+ let view = TestPage {
+ Ellipse {
+ }
+ }
+
+ try renderer.add(view: view)
+
+ XCTAssertEqual(try renderer.render(raw: TestPage.self),
+ """
+
+ """
+ )
+ }
+
+ func testLineElement() throws {
+
+ let view = TestPage {
+ Line {
+ }
+ }
+
+ try renderer.add(view: view)
+
+ XCTAssertEqual(try renderer.render(raw: TestPage.self),
+ """
+
+ """
+ )
+ }
+
+ func testPolygonElement() throws {
+
+ let view = TestPage {
+ Polygon {
+ }
+ }
+
+ try renderer.add(view: view)
+
+ XCTAssertEqual(try renderer.render(raw: TestPage.self),
+ """
+
+ """
+ )
+ }
+
+ func testPolylineElement() throws {
+
+ let view = TestPage {
+ Polyline {
+ }
+ }
+
+ try renderer.add(view: view)
+
+ XCTAssertEqual(try renderer.render(raw: TestPage.self),
+ """
+
+ """
+ )
+ }
+
+ func testPathElement() throws {
+
+ let view = TestPage {
+ Path {
+ }
+ }
+
+ try renderer.add(view: view)
+
+ XCTAssertEqual(try renderer.render(raw: TestPage.self),
+ """
+
+ """
+ )
+ }
+
+ func testUseElement() throws {
+
+ let view = TestPage {
+ Use {
+ }
+ }
+
+ try renderer.add(view: view)
+
+ XCTAssertEqual(try renderer.render(raw: TestPage.self),
+ """
+
+ """
+ )
+ }
}
extension ElementTests {
@@ -1852,6 +1996,15 @@ extension ElementTests {
("testScriptElement", testScriptElement),
("testNoScriptElement", testNoScriptElement),
("testTemplateElement", testTemplateElement),
- ("testCanvasElement", testCanvasElement)
+ ("testCanvasElement", testCanvasElement),
+ ("testVectorElement", testVectorElement),
+ ("testCircleElement", testCircleElement),
+ ("testRectangleElement", testRectangleElement),
+ ("testEllipseElement", testEllipseElement),
+ ("testLineElement", testLineElement),
+ ("testPolygonElement", testPolygonElement),
+ ("testPolylineElement", testPolylineElement),
+ ("testPathElement", testPathElement),
+ ("testUseElement", testUseElement)
]
}