1
|
|
# frozen_string_literal: true
|
2
|
|
|
3
|
5
|
require 'forwardable'
|
4
|
|
|
5
|
5
|
module Roadie
|
6
|
|
# @api private
|
7
|
|
# A style block is the combination of a {Selector} and a list of {StyleProperty}.
|
8
|
5
|
class StyleBlock
|
9
|
5
|
extend Forwardable
|
10
|
5
|
attr_reader :selector, :properties, :media
|
11
|
|
|
12
|
|
# @param [Selector] selector
|
13
|
|
# @param [Array<StyleProperty>] properties
|
14
|
|
# @param [Array<String>] media Array of media types, e.g.
|
15
|
|
# @media screen, print and (max-width 800px) will become
|
16
|
|
# ['screen', 'print and (max-width 800px)']
|
17
|
5
|
def initialize(selector, properties, media)
|
18
|
5
|
@selector = selector
|
19
|
5
|
@properties = properties
|
20
|
5
|
@media = media.map(&:to_s)
|
21
|
|
end
|
22
|
|
|
23
|
|
# @!method specificity
|
24
|
|
# @see Selector#specificity
|
25
|
5
|
def_delegators :selector, :specificity
|
26
|
|
# @!method selector_string
|
27
|
|
# @see Selector#to_s
|
28
|
5
|
def_delegator :selector, :to_s, :selector_string
|
29
|
|
|
30
|
|
# Checks whether the media query can be inlined
|
31
|
|
# @see inlineable_media
|
32
|
|
# @return {Boolean}
|
33
|
5
|
def inlinable?
|
34
|
5
|
inlinable_media? && selector.inlinable?
|
35
|
|
end
|
36
|
|
|
37
|
|
# String representation of the style block. This is valid CSS and can be
|
38
|
|
# used in the DOM.
|
39
|
|
# @return {String}
|
40
|
5
|
def to_s
|
41
|
|
# NB - leave off redundant final semicolon - see https://www.w3.org/TR/CSS2/syndata.html#declaration
|
42
|
5
|
"#{selector}{#{properties.map(&:to_s).join(';')}}"
|
43
|
|
end
|
44
|
|
|
45
|
5
|
private
|
46
|
|
|
47
|
|
# A media query cannot be inlined if it contains any advanced rules
|
48
|
|
# e.g. @media only screen {...} is ok to inline but
|
49
|
|
# @media only screen and (max-width: 600px) {...} cannot be inlined
|
50
|
|
# @return {Boolean}
|
51
|
5
|
def inlinable_media?
|
52
|
5
|
@media.none? { |media_query| media_query.include? '(' }
|
53
|
|
end
|
54
|
|
end
|
55
|
|
end
|