diff --git a/Sources/CSS/Rules/MediaRule.swift b/Sources/CSS/Rules/MediaRule.swift index 74a9401..962863c 100644 --- a/Sources/CSS/Rules/MediaRule.swift +++ b/Sources/CSS/Rules/MediaRule.swift @@ -9,15 +9,15 @@ import JavaScriptKit infix operator / : AdditionPrecedence /// e.g. `8/5` -public func / (lhs: MediaRule.MediaFeature.AspectRatioPart, rhs: MediaRule.MediaFeature.AspectRatioPart) -> MediaRule.MediaFeature.AspectRatioValue { - .init(stringLiteral: "\(lhs)/\(rhs)") +public func / (lhs: MediaRule.MediaType.AspectRatioPart, rhs: MediaRule.MediaType.AspectRatioPart) -> MediaRule.MediaType.AspectRatioValue { + .init("\(lhs.value)/\(rhs.value)") } prefix operator ! /// write `!.screen` /// to reach `"not screen"` in CSS public prefix func ! (rhs: MediaRule.MediaType) -> MediaRule.MediaType { - .init("!\(rhs.value)") + .init("not \(rhs.value)") } /// A conditional group rule that will apply its content @@ -119,79 +119,80 @@ public class MediaRule: RulesContent, CSSRulable { } /// Suitable for all devices. + /// + /// ``` + /// !.all // to reach `not all` + /// ``` + /// public static var all: Self { .init("all") } /// Intended for paged material and documents viewed on a screen in print preview mode. /// + /// ``` + /// !.print // to reach `not print` + /// ``` + /// /// Please see [paged media](https://developer.mozilla.org/en-US/docs/Web/CSS/Paged_Media) /// for information about formatting issues that are specific to these formats. public static var print: Self { .init("print") } + + /// + /// ``` + /// !.screen // to reach `not screen` + /// ``` + /// public static var screen: Self { .init("screen") } - public func and(_ feature: MediaFeature) -> MediaType { + // MARK: Helper + + func and(_ feature: MediaFeature) -> MediaType { .init("\(self.value) and (\(feature.description))") } - } - - public struct MediaFeature: CustomStringConvertible { - public let name: String - public let value: String? - public var description: String { - var result = name - if let value = value { - result.append(": \(value)") - } - return result - } + // MARK: Media Features - public init (name: String, value: String?) { - self.name = name - self.value = value - } - - public struct AnyHoverValue: ExpressibleByStringLiteral { + public struct AnyHoverValue { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// None of the available input mechanism(s) can hover conveniently, or there is no pointing input mechanism. - public static var none: Self { "none" } + public static var none: Self { .init("none") } /// One or more available input mechanisms can conveniently hover over elements. - public static var hover: Self { "hover" } + public static var hover: Self { .init("hover") } } /// Does any available input mechanism allow the user to hover over elements? /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-hover) - public static func anyHover(_ value: AnyHoverValue) -> Self { - .init(name: "any-hover", value: value.value) + public func anyHover(_ value: AnyHoverValue) -> MediaType { + and(.init(name: "any-hover", value: value.value)) } - public struct AnyPointerValue: ExpressibleByStringLiteral { + public struct AnyPointerValue { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// No pointing device is available. - public static var none: Self { "none" } + public static var none: Self { .init("none") } /// At least one input mechanism includes a pointing device of limited accuracy. - public static var coarse: Self { "coarse" } + public static var coarse: Self { .init("coarse") } /// At least one input mechanism includes an accurate pointing device. - public static var fine: Self { "fine" } + public static var fine: Self { .init("fine") } } /// Is any available input mechanism a pointing device, and if so, how accurate is it? /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-pointer) - public static func anyPointer(_ value: AnyPointerValue) -> Self { - .init(name: "any-pointer", value: value.value) + public func anyPointer(_ value: AnyPointerValue) -> MediaType { + and(.init(name: "any-pointer", value: value.value)) } public struct AspectRatioPart: ExpressibleByIntegerLiteral { @@ -202,138 +203,150 @@ public class MediaRule: RulesContent, CSSRulable { } } - public struct AspectRatioValue: ExpressibleByStringLiteral { + public struct AspectRatioValue { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } } /// Width-to-height aspect ratio of the viewport /// + /// ``` + /// .aspectRatio(4 / 3) + /// ``` + /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/aspect-ratio) - public static func aspectRatio(_ value: AspectRatioValue) -> Self { - .init(name: "aspect-ratio", value: value.value) + public func aspectRatio(_ value: AspectRatioValue) -> MediaType { + and(.init(name: "aspect-ratio", value: value.value)) } /// Width-to-height aspect ratio of the viewport /// + /// ``` + /// .minAspectRatio(4 / 3) + /// ``` + /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/aspect-ratio) - public static func minAspectRatio(_ value: AspectRatioValue) -> Self { - .init(name: "min-aspect-ratio", value: value.value) + public func minAspectRatio(_ value: AspectRatioValue) -> MediaType { + and(.init(name: "min-aspect-ratio", value: value.value)) } /// Width-to-height aspect ratio of the viewport /// + /// ``` + /// .maxAspectRatio(4 / 3) + /// ``` + /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/aspect-ratio) - public static func maxAspectRatio(_ value: AspectRatioValue) -> Self { - .init(name: "max-aspect-ratio", value: value.value) + public func maxAspectRatio(_ value: AspectRatioValue) -> MediaType { + and(.init(name: "max-aspect-ratio", value: value.value)) } /// Any color device /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/color) - public static var color: Self { - .init(name: "color", value: nil) + public var color: MediaType { + and(.init(name: "color", value: nil)) } /// Number of bits per color component of the output device, or zero if the device isn't color /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/color) - public static func minColor(_ bits: UInt) -> Self { - .init(name: "min-color", value: "\(bits)") + public func minColor(_ bits: UInt) -> MediaType { + and(.init(name: "min-color", value: "\(bits)")) } - public struct ColorGamut: ExpressibleByStringLiteral { + public struct ColorGamut { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// The output device can support approximately the sRGB gamut or more. /// This includes the vast majority of color displays. - public static var srgb: Self { "srgb" } + public static var srgb: Self { .init("srgb") } /// The output device can support approximately the gamut specified by the Display P3 Color Space or more. /// The p3 gamut is larger than and includes the srgb gamut. - public static var p3: Self { "p3" } + public static var p3: Self { .init("p3") } /// The output device can support approximately the gamut /// specified by the ITU-R Recommendation BT.2020 Color Space or more. /// The rec2020 gamut is larger than and includes the p3 gamut. - public static var rec2020: Self { "rec2020" } + public static var rec2020: Self { .init("rec2020") } } /// Approximate range of colors that are supported by the user agent and output device. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/color-gamut) - public static func colorGamut(_ value: ColorGamut) -> Self { - .init(name: "color-gamut", value: value.value) + public func colorGamut(_ value: ColorGamut) -> MediaType { + and(.init(name: "color-gamut", value: value.value)) } /// Number of entries in the output device's color lookup table, or zero if the device does not use such a table /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/color-index) - public static var colorIndex: Self { - .init(name: "color-index", value: nil) + public var colorIndex: Self { + and(.init(name: "color-index", value: nil)) } /// Number of entries in the output device's color lookup table, or zero if the device does not use such a table /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/color-index) - public static func minColorIndex(_ index: UInt) -> Self { - .init(name: "min-color-index", value: "\(index)") + public func minColorIndex(_ index: UInt) -> MediaType { + and(.init(name: "min-color-index", value: "\(index)")) } - public struct DisplayMode: ExpressibleByStringLiteral { + public struct DisplayMode { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// All of the available display area is used and no user agent chrome is shown. - public static var fullscreen: Self { "fullscreen" } + public static var fullscreen: Self { .init("fullscreen") } /// The application will look and feel like a standalone application. /// This can include the application having a different window, its own icon /// in the application launcher, etc. In this mode, the user agent will exclude UI elements /// for controlling navigation, but can include other UI elements such as a status bar. - public static var standalone: Self { "standalone" } + public static var standalone: Self { .init("standalone") } /// The application will look and feel like a standalone application, /// but will have a minimal set of UI elements for controlling navigation. /// The elements will vary by browser. - public static var minimalUI: Self { "minimal-ui" } + public static var minimalUI: Self { .init("minimal-ui") } /// The application opens in a conventional browser tab or new window, /// depending on the browser and platform. - public static var browser: Self { "browser" } + public static var browser: Self { .init("browser") } /// In this mode, the application looks and feels like a standalone desktop application, /// and the Window Controls Overlay feature is enabled. - public static var windowControlsOverlay: Self { "window-controls-overlay" } + public static var windowControlsOverlay: Self { .init("window-controls-overlay") } } /// The display mode of the application, as specified in the web app manifest's display member. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/display-mode) - public static func displayMode(_ value: DisplayMode) -> Self { - .init(name: "display-mode", value: value.value) + public func displayMode(_ value: DisplayMode) -> MediaType { + and(.init(name: "display-mode", value: value.value)) } - public struct DynamicRange: ExpressibleByStringLiteral { + public struct DynamicRange { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// This value matches any visual device and excludes devices lacking visual capabilities. /// A user agent or an output device that matches high will also match the standard value. - public static var standard: Self { "standard" } + public static var standard: Self { .init("standard") } /// This value matches user agents and output devices that support high peak brightness, /// high contrast ratio, and color depth greater than 24 bit or 8 bit per color component of RGB. @@ -343,375 +356,375 @@ public class MediaRule: RulesContent, CSSRulable { /// of the luminance of the brightest color to that of the darkest color that the system is capable of producing. /// Currently, there is no precise way to measure peak brightness and contrast ratio, and the determination /// of what counts as high peak brightness and high contrast ratio depends on the user agent. - public static var high: Self { "high" } + public static var high: Self { .init("high") } } /// Combination of brightness, contrast ratio, and color depth /// that are supported by the user agent and the output device. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/dynamic-range) - public static func dynamicRange(_ value: DynamicRange) -> Self { - .init(name: "dynamic-range", value: value.value) + public func dynamicRange(_ value: DynamicRange) -> MediaType { + and(.init(name: "dynamic-range", value: value.value)) } - public struct ForcedColors: ExpressibleByStringLiteral { + public struct ForcedColors { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// Forced colors mode is not active; the page's colors are not being forced into a limited palette. - public static var none: Self { "none" } + public static var none: Self { .init("none") } /// Indicates that forced colors mode is active. The browser provides the color palette /// to authors through the CSS system color keywords and, if appropriate, /// triggers the appropriate value of prefers-color-scheme so that authors can adapt the page. /// The browser selects the value for prefers-color-scheme based on the lightness /// of the Canvas system color (see the color adjust spec for more details). - public static var active: Self { "active" } + public static var active: Self { .init("active") } } /// Detect whether user agent restricts color palette. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/forced-colors) - public static func forcedColors(_ value: ForcedColors) -> Self { - .init(name: "forced-colors", value: value.value) + public func forcedColors(_ value: ForcedColors) -> MediaType { + and(.init(name: "forced-colors", value: value.value)) } /// Does the device use a grid or bitmap screen? /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/grid) - public static func grid(_ value: Bool) -> Self { - .init(name: "grid", value: value ? "1" : "0") + public func grid(_ value: Bool) -> MediaType { + and(.init(name: "grid", value: value ? "1" : "0")) } /// Height of the viewport. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/height) - public func height(_ value: U) -> Self { - .init(name: "height", value: UnitValue(value.value.doubleValue, value.unit).description) + public func height(_ value: U) -> MediaType { + and(.init(name: "height", value: UnitValue(value.value.doubleValue, value.unit).description)) } /// Min height of the viewport. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/height) - public func minHeight(_ value: U) -> Self { - .init(name: "min-height", value: UnitValue(value.value.doubleValue, value.unit).description) + public func minHeight(_ value: U) -> MediaType { + and(.init(name: "min-height", value: UnitValue(value.value.doubleValue, value.unit).description)) } /// Max height of the viewport. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/height) - public func maxHeight(_ value: U) -> Self { - .init(name: "max-height", value: UnitValue(value.value.doubleValue, value.unit).description) + public func maxHeight(_ value: U) -> MediaType { + and(.init(name: "max-height", value: UnitValue(value.value.doubleValue, value.unit).description)) } - public struct Hover: ExpressibleByStringLiteral { + public struct Hover { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// The primary input mechanism cannot hover at all /// or cannot conveniently hover (e.g., many mobile devices emulate hovering /// when the user performs an inconvenient long tap), or there is no primary pointing input mechanism. - public static var none: Self { "none" } + public static var none: Self { .init("none") } /// The primary input mechanism can conveniently hover over elements. - public static var hover: Self { "hover" } + public static var hover: Self { .init("hover") } } /// Does the primary input mechanism allow the user to hover over elements? /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/hover) - public static func hover(_ value: Hover) -> Self { - .init(name: "hover", value: value.value) + public func hover(_ value: Hover) -> MediaType { + and(.init(name: "hover", value: value.value)) } - public struct InvertedColors: ExpressibleByStringLiteral { + public struct InvertedColors { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// Colors are displayed normally. - public static var none: Self { "none" } + public static var none: Self { .init("none") } /// All pixels within the displayed area have been inverted. - public static var inverted: Self { "inverted" } + public static var inverted: Self { .init("inverted") } } /// Is the user agent or underlying OS inverting colors? /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/inverted-colors) - public static func invertedColors(_ value: InvertedColors) -> Self { - .init(name: "inverted-colors", value: value.value) + public func invertedColors(_ value: InvertedColors) -> MediaType { + and(.init(name: "inverted-colors", value: value.value)) } /// Bits per pixel in the output device's monochrome frame buffer, or zero if the device isn't monochrome. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/monochrome) - public static var monochrome: Self { - .init(name: "monochrome", value: nil) + public var monochrome: MediaType { + and(.init(name: "monochrome", value: nil)) } /// Bits per pixel in the output device's monochrome frame buffer, or zero if the device isn't monochrome. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/monochrome) - public static func monochrome(_ value: UInt) -> Self { - .init(name: "monochrome", value: "\(value)") + public func monochrome(_ value: UInt) -> MediaType { + and(.init(name: "monochrome", value: "\(value)")) } /// Bits per pixel in the output device's monochrome frame buffer, or zero if the device isn't monochrome. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/monochrome) - public static func minMonochrome(_ value: UInt) -> Self { - .init(name: "min-monochrome", value: "\(value)") + public func minMonochrome(_ value: UInt) -> MediaType { + and(.init(name: "min-monochrome", value: "\(value)")) } /// Bits per pixel in the output device's monochrome frame buffer, or zero if the device isn't monochrome. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/monochrome) - public static func maxMonochrome(_ value: UInt) -> Self { - .init(name: "max-monochrome", value: "\(value)") + public func maxMonochrome(_ value: UInt) -> MediaType { + and(.init(name: "max-monochrome", value: "\(value)")) } - public struct Orientation: ExpressibleByStringLiteral { + public struct Orientation { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// The viewport is in a portrait orientation, i.e., the height is greater than or equal to the width. - public static var portrait: Self { "portrait" } + public static var portrait: Self { .init("portrait") } /// The viewport is in a landscape orientation, i.e., the width is greater than the height. - public static var landscape: Self { "landscape" } + public static var landscape: Self { .init("landscape") } } /// Orientation of the viewport. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/orientation) - public static func orientation(_ value: Orientation) -> Self { - .init(name: "orientation", value: value.value) + public func orientation(_ value: Orientation) -> MediaType { + and(.init(name: "orientation", value: value.value)) } - public struct OverflowBlock: ExpressibleByStringLiteral { + public struct OverflowBlock { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// Content that overflows the block axis is not displayed. - public static var none: Self { "none" } + public static var none: Self { .init("none") } /// Content that overflows the block axis can be seen by scrolling to it. - public static var scroll: Self { "scroll" } + public static var scroll: Self { .init("scroll") } /// Content that overflows the block axis can be seen by scrolling to it, /// but page breaks can be manually triggered (such as via break-inside, etc.) /// to cause the following content to display on the following page. - public static var optionalPaged: Self { "optional-paged" } + public static var optionalPaged: Self { .init("optional-paged") } /// Content is broken up into discrete pages; content that overflows /// one page in the block axis is displayed on the following page. - public static var paged: Self { "paged" } + public static var paged: Self { .init("paged") } } /// How does the output device handle content that overflows the viewport along the block axis? /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/overflow-block) - public static func overflowBlock(_ value: OverflowBlock) -> Self { - .init(name: "overflow-block", value: value.value) + public func overflowBlock(_ value: OverflowBlock) -> MediaType { + and(.init(name: "overflow-block", value: value.value)) } - public struct OverflowInline: ExpressibleByStringLiteral { + public struct OverflowInline { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// Content that overflows the inline axis is not displayed. - public static var none: Self { "none" } + public static var none: Self { .init("none") } /// Content that overflows the inline axis can be seen by scrolling to it. - public static var scroll: Self { "scroll" } + public static var scroll: Self { .init("scroll") } } /// Can content that overflows the viewport along the inline axis be scrolled? /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/overflow-inline) - public static func overflowInline(_ value: OverflowInline) -> Self { - .init(name: "overflow-inline", value: nil) + public func overflowInline(_ value: OverflowInline) -> MediaType { + and(.init(name: "overflow-inline", value: nil)) } - public struct Pointer: ExpressibleByStringLiteral { + public struct Pointer { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// The primary input mechanism does not include a pointing device. - public static var none: Self { "none" } + public static var none: Self { .init("none") } /// The primary input mechanism includes a pointing device of limited accuracy. - public static var coarse: Self { "coarse" } + public static var coarse: Self { .init("coarse") } /// The primary input mechanism includes an accurate pointing device. - public static var fine: Self { "fine" } + public static var fine: Self { .init("fine") } } /// Is the primary input mechanism a pointing device, and if so, how accurate is it? /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer) - public static func pointer(_ value: Pointer) -> Self { - .init(name: "pointer", value: value.value) + public func pointer(_ value: Pointer) -> MediaType { + and(.init(name: "pointer", value: value.value)) } - public struct PrefersColorScheme: ExpressibleByStringLiteral { + public struct PrefersColorScheme { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// Indicates that user has notified that they prefer an interface /// that has a light theme, or has not expressed an active preference. - public static var light: Self { "light" } + public static var light: Self { .init("light") } /// Indicates that user has notified that they prefer an interface that has a dark theme. - public static var dark: Self { "dark" } + public static var dark: Self { .init("dark") } } /// Detect if the user prefers a light or dark color scheme. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) - public static func prefersColorScheme(_ value: PrefersColorScheme) -> Self { - .init(name: "prefers-color-scheme", value: value.value) + public func prefersColorScheme(_ value: PrefersColorScheme) -> MediaType { + and(.init(name: "prefers-color-scheme", value: value.value)) } - public struct PrefersContrast: ExpressibleByStringLiteral { + public struct PrefersContrast { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// Indicates that the user has made no preference known to the system. /// This keyword value evaluates as false in the Boolean context. - public static var noPreference: Self { "no-preference" } + public static var noPreference: Self { .init("no-preference") } /// Indicates that user has notified the system that they prefer /// an interface that has a higher level of contrast. - public static var more: Self { "more" } + public static var more: Self { .init("more") } /// Indicates that user has notified the system that they prefer /// an interface that has a lower level of contrast. - public static var less: Self { "less" } + public static var less: Self { .init("less") } /// Indicates that user has notified the system for using a specific set of colors, /// and the contrast implied by these colors matches neither more nor less. /// This value will match the color palette specified by users of `forced-colors: active`. - public static var custom: Self { "custom" } + public static var custom: Self { .init("custom") } } /// Detects if the user has requested the system /// increase or decrease the amount of contrast between adjacent colors. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast) - public static func prefersContrast(_ value: PrefersContrast) -> Self { - .init(name: "prefers-contrast", value: value.value) + public func prefersContrast(_ value: PrefersContrast) -> MediaType { + and(.init(name: "prefers-contrast", value: value.value)) } /// The user prefers less motion on the page. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) - public static var prefersReducedMotion: Self { - .init(name: "prefers-reduced-motion", value: nil) + public var prefersReducedMotion: MediaType { + and(.init(name: "prefers-reduced-motion", value: nil)) } /// Pixel density of the output device. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/resolution) - public static func resolution(_ dpi: UInt) -> Self { - .init(name: "resolution", value: "\(dpi)dpi") + public func resolution(_ dpi: UInt) -> MediaType { + and(.init(name: "resolution", value: "\(dpi)dpi")) } - public struct Scripting: ExpressibleByStringLiteral { + public struct Scripting { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// Scripting is completely unavailable on the current document. - public static var none: Self { "none" } + public static var none: Self { .init("none") } /// Scripting is enabled during the initial page load, but not afterwards. - public static var initialOnly: Self { "initial-only" } + public static var initialOnly: Self { .init("initial-only") } /// Scripting is supported and active on the current document. - public static var enabled: Self { "enabled" } + public static var enabled: Self { .init("enabled") } } /// Detects whether scripting (i.e. JavaScript) is available. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/scripting) - public static func scripting(_ value: Scripting) -> Self { - .init(name: "scripting", value: value.value) + public func scripting(_ value: Scripting) -> MediaType { + and(.init(name: "scripting", value: value.value)) } - public struct Update: ExpressibleByStringLiteral { + public struct Update { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// Once it has been rendered, the layout can no longer be updated. /// /// Example: documents printed on paper. - public static var none: Self { "none" } + public static var none: Self { .init("none") } /// The layout may change dynamically according to the usual rules of CSS, /// but the output device is not able to render or display changes quickly enough /// for them to be perceived as a smooth animation. /// /// Examples: e-book readers or severely underpowered devices. - public static var slow: Self { "slow" } + public static var slow: Self { .init("slow") } /// The layout may change dynamically according to the usual rules of CSS, /// and the output device is not unusually constrained in speed, /// so regularly-updating things like CSS Animations can be used. /// /// Example: computer screens. - public static var fast: Self { "fast" } + public static var fast: Self { .init("fast") } } /// How frequently the output device can modify the appearance of content. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/update-frequency) - public static func update(_ value: Update) -> Self { - .init(name: "update", value: value.value) + public func update(_ value: Update) -> MediaType { + and(.init(name: "update", value: value.value)) } - public struct VideoDynamicRange: ExpressibleByStringLiteral { + public struct VideoDynamicRange { public let value: String - public init(stringLiteral value: String) { + public init(_ value: String) { self.value = value } /// This value matches any visual device and excludes devices lacking visual capabilities. /// A user agent or an output device that matches high will also match the standard value. - public static var standard: Self { "standard" } + public static var standard: Self { .init("standard") } /// This value matches user agents and output devices that support high peak brightness, /// high contrast ratio, and color depth greater than 24 bit or 8 bit per color component of RGB. @@ -721,36 +734,54 @@ public class MediaRule: RulesContent, CSSRulable { /// of the luminance of the brightest color to that of the darkest color that the system is capable of producing. /// Currently, there is no precise way to measure peak brightness and contrast ratio, /// and the determination of what counts as high peak brightness and high contrast ratio depends on the user agent. - public static var high: Self { "high" } + public static var high: Self { .init("high") } } /// Combination of brightness, contrast ratio, and color depth /// that are supported by the video plane of user agent and the output device. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/video-dynamic-range) - public static func videoDynamicRange(_ value: VideoDynamicRange) -> Self { - .init(name: "video-dynamic-range", value: value.value) + public func videoDynamicRange(_ value: VideoDynamicRange) -> MediaType { + and(.init(name: "video-dynamic-range", value: value.value)) } /// Width of the viewport including width of scrollbar. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/width) - public static func width(_ value: U) -> Self { - .init(name: "width", value: UnitValue(value.value.doubleValue, value.unit).description) + public func width(_ value: U) -> MediaType { + and(.init(name: "width", value: UnitValue(value.value.doubleValue, value.unit).description)) } /// Minimum width of the viewport including width of scrollbar. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/width) - public static func minWidth(_ value: U) -> Self { - .init(name: "min-width", value: UnitValue(value.value.doubleValue, value.unit).description) + public func minWidth(_ value: U) -> MediaType { + and(.init(name: "min-width", value: UnitValue(value.value.doubleValue, value.unit).description)) } /// Maximum width of the viewport including width of scrollbar. /// /// [Learn more](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/width) - public static func maxWidth(_ value: U) -> Self { - .init(name: "max-width", value: UnitValue(value.value.doubleValue, value.unit).description) + public func maxWidth(_ value: U) -> MediaType { + and(.init(name: "max-width", value: UnitValue(value.value.doubleValue, value.unit).description)) + } + } + + public struct MediaFeature: CustomStringConvertible { + public let name: String + public let value: String? + + public var description: String { + var result = name + if let value = value { + result.append(": \(value)") + } + return result + } + + public init (name: String, value: String?) { + self.name = name + self.value = value } }