diff options
Diffstat (limited to 'src/_props.scss')
-rw-r--r-- | src/_props.scss | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/src/_props.scss b/src/_props.scss new file mode 100644 index 0000000..7377c88 --- /dev/null +++ b/src/_props.scss | |||
@@ -0,0 +1,281 @@ | |||
1 | //// | ||
2 | /// Property trees. | ||
3 | /// | ||
4 | /// Property trees allow you to organize properties in a tree structure (internally nested maps). | ||
5 | /// The intended use is to store all your properties at the beginning and for the rest of the | ||
6 | /// stylesheet you just get them. | ||
7 | /// | ||
8 | /// @group Property trees | ||
9 | /// | ||
10 | /// @access public | ||
11 | //// | ||
12 | |||
13 | /// | ||
14 | /// The maximum depth of resolved iro-prop-ref() references. | ||
15 | /// | ||
16 | /// @type number | ||
17 | /// | ||
18 | $iro-props-native-assing-max-depth: 2 !default; | ||
19 | |||
20 | /// | ||
21 | /// Indicate if property names must start with two dashes (--). | ||
22 | /// This is required if property trees are also used for native CSS custom properties. | ||
23 | /// | ||
24 | /// @type bool | ||
25 | /// | ||
26 | $iro-props-enforce-double-dashes: true !default; | ||
27 | |||
28 | /// | ||
29 | /// Default tree name to use if no name is specified. | ||
30 | /// | ||
31 | /// @type string | ||
32 | /// | ||
33 | $iro-props-default-tree: 'default' !default; | ||
34 | |||
35 | /// | ||
36 | /// List of all created property trees. | ||
37 | /// | ||
38 | /// @type list | ||
39 | /// | ||
40 | /// @access private | ||
41 | /// | ||
42 | $iro-props-trees: (); | ||
43 | |||
44 | /// | ||
45 | /// Save a property tree. If a tree with the sane name already exists, the trees | ||
46 | /// will be merged. | ||
47 | /// | ||
48 | /// @param {map} $map - Map containing properties | ||
49 | /// @param {string} $tree [$iro-props-default-tree] - ID the map is saved as | ||
50 | /// @param {bool} $merge [false] - If a tree named $tree already exists and this value is set to true, they will be merged. Otherwise an error will be emitted. | ||
51 | /// | ||
52 | @mixin iro-props-save($map, $tree: $iro-props-default-tree, $merge: false) { | ||
53 | $noop: iro-props-save($map, $tree, $merge); | ||
54 | } | ||
55 | |||
56 | /// | ||
57 | /// Save a property tree. | ||
58 | /// | ||
59 | /// @param {map} $map - Map containing properties | ||
60 | /// @param {string} $tree [$iro-props-default-tree] - ID the map is saved as | ||
61 | /// @param {bool} $merge [false] - If a tree named $tree already exists and this value is set to true, they will be merged. Otherwise an error will be emitted. | ||
62 | /// | ||
63 | @function iro-props-save($map, $tree: $iro-props-default-tree, $merge: false) { | ||
64 | $prop-map: null; | ||
65 | |||
66 | @if $iro-props-enforce-double-dashes { | ||
67 | @if not iro-props-validate($map) { | ||
68 | @error 'Property tree keys must start with two dashes (--). If you don\'t use property trees for native CSS custom properties, set $iro-props-enforce-double-dashes to false.'; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | @if map-has-key($iro-props-trees, $tree) { | ||
73 | @if $merge { | ||
74 | $map: iro-map-merge-recursive(map-get($iro-props-trees, $tree), $map); | ||
75 | } @else { | ||
76 | @error 'Property tree #{inspect($tree)} does already exist.'; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | $iro-props-trees: map-merge($iro-props-trees, ($tree: $map)) !global; | ||
81 | |||
82 | @return null; | ||
83 | } | ||
84 | |||
85 | /// | ||
86 | /// Delete a property tree. | ||
87 | /// | ||
88 | /// @param {string} $tree [$iro-props-default-tree] - ID of the tree to be deleted | ||
89 | /// | ||
90 | @mixin iro-props-delete($tree: $iro-props-default-tree) { | ||
91 | $noop: iro-props-delete($tree); | ||
92 | } | ||
93 | |||
94 | /// | ||
95 | /// Unset a property tree. | ||
96 | /// | ||
97 | /// @param {string} $tree [$iro-props-default-tree] - ID of the tree to be deleted | ||
98 | /// | ||
99 | /// @throw If the property tree does not exist | ||
100 | /// | ||
101 | @function iro-props-delete($tree: $iro-props-default-tree) { | ||
102 | @if not map-has-key($iro-props-trees, $tree) { | ||
103 | @error 'Property tree "#{inspect($tree)}" does not exist.'; | ||
104 | } | ||
105 | |||
106 | $iro-props-trees: map-remove($iro-props-trees, $tree) !global; | ||
107 | |||
108 | @return null; | ||
109 | } | ||
110 | |||
111 | /// | ||
112 | /// Access a whole property or a subsection (i.e. value) of it. | ||
113 | /// | ||
114 | /// @param {string | list} $key [null] - Key of the property to read. If this is a list of keys, the map will be traversed in that order. | ||
115 | /// @param {string} $tree [$iro-props-default-tree] - ID of the property tree to use | ||
116 | /// @param {any} $default [null] - Default value to return of no match was found. If null, this function will throw an error instead. | ||
117 | /// | ||
118 | /// @return {any} Value assigned to property or $default | ||
119 | /// | ||
120 | /// @throw If there was no match for $key and $default is null | ||
121 | /// | ||
122 | @function iro-props-get($key: (), $tree: $iro-props-default-tree, $default: null) { | ||
123 | @if not map-has-key($iro-props-trees, $tree) { | ||
124 | @error 'Unknown tree "#{$tree}".'; | ||
125 | } | ||
126 | |||
127 | $result: map-get($iro-props-trees, $tree); | ||
128 | |||
129 | @if type-of($key) == list { | ||
130 | $stop: false; | ||
131 | |||
132 | @each $k in $key { | ||
133 | @if map-has-key($result, $k) and not $stop { | ||
134 | $result: map-get($result, $k); | ||
135 | |||
136 | @if type-of($result) == list and nth($result, 1) == 'iro-prop-ref' { | ||
137 | @if length($result) == 2 { | ||
138 | $result: iro-props-get($tree: nth($result, 2)); | ||
139 | } @else { | ||
140 | $result: iro-props-get(nth($result, 3), nth($result, 2)); | ||
141 | } | ||
142 | } | ||
143 | } @else { | ||
144 | $stop: true; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | @if $stop { | ||
149 | $result: null; | ||
150 | } | ||
151 | } @else { | ||
152 | $result: map-get($result, $key); | ||
153 | |||
154 | @if type-of($result) == list and nth($result, 1) == 'iro-prop-ref' { | ||
155 | @if length($result) == 2 { | ||
156 | $result: iro-props-get($tree: nth($result, 2)); | ||
157 | } @else { | ||
158 | $result: iro-props-get(nth($result, 3), nth($result, 2)); | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | |||
163 | @if $result == null { | ||
164 | @if $default == null { | ||
165 | @error '"#{$key}" is null.'; | ||
166 | } @else { | ||
167 | @return $default; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | @return $result; | ||
172 | } | ||
173 | |||
174 | /// | ||
175 | /// Generate a var() function call to get native CSS custom property. | ||
176 | /// | ||
177 | /// @param {string | list} $key - Key of the property to read. If this is a list of keys, the map will be traversed in that order. | ||
178 | /// @param {string | null} $tree [null] - Optional tree to check if the property actually exists. | ||
179 | /// @param {any} $default [null] - Default value to return of no match was found. | ||
180 | /// | ||
181 | /// @return {string} var() | ||
182 | /// | ||
183 | @function iro-props-get-native($key, $tree: null, $default: null) { | ||
184 | @if $tree != null { | ||
185 | $noop: iro-props-get($key, $tree, $default); | ||
186 | } | ||
187 | |||
188 | $native-var: ''; | ||
189 | |||
190 | @if type-of($key) == list { | ||
191 | @each $subkey in $key { | ||
192 | $native-var: $native-var + $subkey; | ||
193 | } | ||
194 | } @else { | ||
195 | $native-var: $key; | ||
196 | } | ||
197 | |||
198 | @if $default == null { | ||
199 | @return var(#{$native-var}); | ||
200 | } @else { | ||
201 | @return var(#{$native-var}, #{$default}); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | /// | ||
206 | /// Generate assignments for native CSS custom properties with the values from the specified tree. | ||
207 | /// | ||
208 | /// @param {string} $tree [$iro-props-default-tree] - ID of the property tree to use | ||
209 | /// @param {string} $root [()] - Sub-tree to use for assignment | ||
210 | /// | ||
211 | @mixin iro-props-assign-native($tree: $iro-props-default-tree, $root: (), $skip: ()) { | ||
212 | $map: iro-props-get($root, $tree); | ||
213 | $map: map-remove($map, $skip...); | ||
214 | |||
215 | @include iro-props-assign-native-internal($map); | ||
216 | } | ||
217 | |||
218 | /// | ||
219 | /// @access private | ||
220 | /// | ||
221 | @mixin iro-props-assign-native-internal($map, $prefix: '', $ref-depth: $iro-props-native-assing-max-depth) { | ||
222 | @each $key, $value in $map { | ||
223 | $rd: $ref-depth; | ||
224 | @if type-of($value) == list and nth($value, 1) == 'iro-prop-ref' { | ||
225 | @if $ref-depth != 0 { | ||
226 | $rd: $rd - 1; | ||
227 | @if length($value) == 2 { | ||
228 | $value: iro-props-get($tree: nth($value, 2)); | ||
229 | } @else { | ||
230 | $value: iro-props-get(nth($value, 3), nth($value, 2)); | ||
231 | } | ||
232 | } @else { | ||
233 | $value: null; | ||
234 | } | ||
235 | } | ||
236 | @if type-of($value) != map { | ||
237 | #{$prefix + $key}: #{$value}; | ||
238 | } @else { | ||
239 | @include iro-props-assign-native-internal($value, $prefix + $key, $rd); | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | |||
244 | /// | ||
245 | /// Validate property names. | ||
246 | /// | ||
247 | /// @access private | ||
248 | /// | ||
249 | @function iro-props-validate($map) { | ||
250 | @each $key, $value in $map { | ||
251 | @if str-index($key, '--') != 1 { | ||
252 | @return false; | ||
253 | } | ||
254 | |||
255 | @if type-of($value) == map { | ||
256 | @if not iro-props-validate($value) { | ||
257 | @return false; | ||
258 | } | ||
259 | } | ||
260 | } | ||
261 | |||
262 | @return true; | ||
263 | } | ||
264 | |||
265 | /// | ||
266 | /// Generate a reference to another tree. Dereferencing is lazy, so you may specify a tree that hasn't been created yet. | ||
267 | /// | ||
268 | /// @param {string} $tree [$iro-props-default-tree] - ID of the property tree to use | ||
269 | /// @param {string | list} $key - Key of the property to read. If this is a list of keys, the map will be traversed in that order. | ||
270 | /// | ||
271 | /// @return {list} A special list that let's Ignis know that this is a lazy value. | ||
272 | /// | ||
273 | /// @throw If there was no match for $key and $default is null | ||
274 | /// | ||
275 | @function iro-props-ref($tree: $iro-props-default-tree, $key: null) { | ||
276 | @if $key == null { | ||
277 | @return ('iro-prop-ref' $tree); | ||
278 | } @else { | ||
279 | @return ('iro-prop-ref' $tree $key); | ||
280 | } | ||
281 | } | ||