diff --git a/Sources/Plot/API/HTMLAttributes.swift b/Sources/Plot/API/HTMLAttributes.swift index 9c9b8f6..79a5c19 100644 --- a/Sources/Plot/API/HTMLAttributes.swift +++ b/Sources/Plot/API/HTMLAttributes.swift @@ -261,6 +261,24 @@ public extension Attribute where Context == HTML.PictureSourceContext { static func type(_ type: String) -> Attribute { Attribute(name: "type", value: type) } + + /// A string with a media query describing which image from the `srcset` attribute should be used. + /// - parameter sizes: The sizes used for the of sources that this element should point to. + static func sizes(_ sizes: String) -> Attribute { + Attribute(name: "sizes", value: sizes) + } + + /// Assign an integer giving the intinsic height of the `srcset` image in pixels. + /// - parameter height: The height of the image in the source. + static func height(_ height: Int) -> Attribute { + Attribute(name: "height", value: String(height)) + } + + /// Assign an integer giving the intrinsic width of the `srcset` image in pixels. + /// - parameter width: The width of the image in the source. + static func width(_ width: Int) -> Attribute { + Attribute(name: "width", value: String(width)) + } } // MARK: - Forms, input and options diff --git a/Sources/Plot/API/HTMLComponents.swift b/Sources/Plot/API/HTMLComponents.swift index 87ef29e..5dadc3c 100644 --- a/Sources/Plot/API/HTMLComponents.swift +++ b/Sources/Plot/API/HTMLComponents.swift @@ -578,6 +578,62 @@ extension List: ComponentContainer where Items == ComponentGroup { self.init(content()) { $0 } } } +// Component used to render a `` element for responsive image support. +public struct Picture: Component { + + /// Image to use as fallback. + public var image: Image + /// A set of `source` elments from which a user agent will chose based on its requirements. + public var sources: [Source] + + /// Initialize a `Picture` component with multiple `source` elements. + internal init(image: Image, sources: [Picture.Source] = []) { + self.image = image + self.sources = sources + } + + /// Initialize a `Picture` component with a single `source` element. + /// Image to use as fallback. + /// A set of `source` elments from which a user agent will chose based on its requirements. + public init(image: Image, source: Source) { + self.init(image: image, sources: [source]) + } + + public var body: Component { + Node.picture( + .forEach(sources) { source in + .source( + .srcset(source.sourceSet), + .media(source.media ?? ""), + .type(source.type ?? ""), + .sizes(source.sizes ?? ""), + .unwrap(source.height, Attribute.height), + .unwrap(source.width, Attribute.width) + ) + }, + .component(image) + ) + } +} + +public extension Picture { + /// Type used to define a Picture source, which points to an image file (or set of them) and associated media queries (and other paramaters). + struct Source { + /// Image or images to use - can have parameters + public var sourceSet: String + /// Sizes for the `srcset` to use - can have parameters + public var sizes: String? + /// Media querry (optional) + public var media: String? + /// Media type (optional) + public var type: String? + /// Intrinsic height of image in pixels - integer with no unit (optional) + public var height: Int? + /// Intrinsic width of image in pixels - integer with no unit (optional) + public var width: Int? + } + +} /// Convenience type that can be used to create an `Input` component /// for submitting an HTML form.