UNPKG

28.4 kBSCSSView Raw
1
2//
3// This file defines the public Sass API to ag-Grid's styles.
4// https://ag-grid.com/javascript-data-grid/global-style-customisation-sass/
5//
6
7@use "sass:map";
8@use "sass:list";
9@use "sass:meta";
10@use "sass:string";
11@use "sass:color";
12@use "sass:math";
13@use "./css-content";
14@use "./icon-font-codes" as *;
15
16@forward "./shared";
17
18// Emit styles for the grid. This mixin validates the parameters passed to it,
19// converts the parameters to CSS variables, and combines all the necessary CSS
20// files for the grid and selected theme.
21@mixin grid-styles($global-params: ()) {
22 $no-native-widgets: map.get($global-params, "suppress-native-widget-styling");
23 $global-params: map.remove($global-params, "suppress-native-widget-styling");
24
25 $themes: -get-themes($global-params);
26
27 @if $no-native-widgets {
28 @include -load-css-file("ag-grid-no-native-widgets.css");
29 } @else {
30 @include -load-css-file("ag-grid.css");
31 }
32
33 $global-extended-theme-name: -clean-theme-name(map.get($global-params, "extend-theme"));
34
35 @each $theme-name, $theme-params in $themes {
36 @include -validate-params($theme-params, $theme-name);
37
38 @include -load-theme-css-file($theme-name);
39 $extended-theme-name: -get-extended-theme-name($theme-params, $default: $global-extended-theme-name);
40 @if $extended-theme-name and not -is-provided-theme($extended-theme-name) {
41 @error "Invalid extend-theme: \"#{$extended-theme-name}\": only provided themes can be extended, use one of #{meta.inspect(map.keys($-theme-css-files))}";
42 }
43 @if $extended-theme-name and -is-provided-theme($theme-name) {
44 @error "Can't use a provided theme (#{$theme-name}) and also extend a provided theme (#{$extended-theme-name}). If you want to extend #{$extended-theme-name}, provide your own custom theme name.";
45 }
46 @if $extended-theme-name {
47 @include -load-theme-css-file($extended-theme-name);
48 }
49
50 $font: map.get($theme-params, "--ag-icon-font-family");
51 $font: map.get($-theme-fonts, $theme-name) !default;
52 $font: map.get($-theme-fonts, $extended-theme-name) !default;
53 @if $font {
54 @include -load-css-file("#{$font}Font.css", $ignore-missing: true);
55 }
56 }
57
58 @each $theme-name, $theme-params in $themes {
59 $extended-theme-name: -get-extended-theme-name($theme-params, $default: $global-extended-theme-name);
60
61 @if $extended-theme-name and $extended-theme-name != $theme-name {
62 // alias all the styles in the extended theme to the new theme name
63 .ag-theme-#{$theme-name} {
64 @extend .ag-theme-#{$extended-theme-name};
65 }
66 }
67
68 // Emit CSS variable declarations for a set of params, converting (foo: bar) to `--ag-foo: bar`
69 .ag-theme-#{$theme-name} {
70 $color-blend-theme-name: $extended-theme-name;
71 $color-blend-theme-name: $theme-name !default;
72 $blend-function-name: "-theme-#{$color-blend-theme-name}-color-blends";
73 @if meta.function-exists($blend-function-name) {
74 $theme-color-blends: meta.get-function($blend-function-name);
75 $theme-params: meta.call($theme-color-blends, $theme-params);
76 }
77 $theme-params: -base-color-blends($theme-params);
78
79 @each $name, $value in $theme-params {
80 // use meta.inspect to preserve the quote style of strings
81 @if map.has-key($-variable-param-types, $name) {
82 #{$name}: #{meta.inspect($value)};
83 }
84 }
85 }
86 }
87}
88
89//
90// PRIVATE IMPLEMENTATION
91//
92
93$-loaded-css-files: ();
94
95// Fulfils the same role as meta.load-css, which we can't use due to this issue:
96// https://github.com/sass/dart-sass/issues/1627
97//
98// NOTE the above bug was fixed in Sass 1.52.4 in June 2022, this workaround should
99// be kept as long as we want to support earlier Sass versions
100@mixin -load-css-file($file, $ignore-missing: false) {
101 @if not map.get($-loaded-css-files, $file) {
102 $-loaded-css-files: map.set($-loaded-css-files, $file, true);
103 @include css-content.output-css-file($file, $ignore-missing: $ignore-missing);
104 }
105}
106
107@mixin -load-theme-css-file($theme-name, $ignore-missing: false) {
108 $css-file: map.get($-theme-css-files, $theme-name);
109 @if $css-file {
110 @include -load-css-file($css-file);
111 }
112}
113
114@function -clean-theme-name($name) {
115 @if $name == null {
116 @return null;
117 }
118 $name: string.to-lower-case($name);
119 $remove-prefix: "ag-theme-";
120 @if string.index($name, $remove-prefix) == 1 {
121 $name: string.slice($name, string.length($remove-prefix) + 1);
122 }
123 @return $name;
124}
125
126@function -clean-variable-name($name) {
127 @if $name == null {
128 @return null;
129 }
130 $name: string.to-lower-case($name);
131
132 $proposed-variable-name: "--ag-#{$name}";
133 @if map.has-key($-variable-param-types, $proposed-variable-name) {
134 $name: $proposed-variable-name;
135 }
136
137 $remove-prefix: "ag-theme-";
138 @if string.index($name, $remove-prefix) == 1 {
139 $name: string.slice($name, string.length($remove-prefix) + 1);
140 }
141 @return $name;
142}
143
144@function -get-extended-theme-name($theme-params, $default) {
145 $extended-theme-name: -clean-theme-name(map.get($theme-params, "extend-theme"));
146 @if $extended-theme-name {
147 @return $extended-theme-name;
148 }
149 @return $default;
150}
151
152$-theme-variables: (
153 "alpine": (alpine-active-color: "color"),
154 "alpine-dark": (alpine-active-color: "color"),
155 "balham": (balham-active-color: "color"),
156 "balham-dark": (balham-active-color: "color"),
157 "material": (material-primary-color: "color", material-accent-color: "color"),
158);
159
160$-theme-css-files: (
161 "alpine": "ag-theme-alpine-no-font.css",
162 "alpine-dark": "ag-theme-alpine-no-font.css",
163 "balham": "ag-theme-balham-no-font.css",
164 "balham-dark": "ag-theme-balham-no-font.css",
165 "material": "ag-theme-material-no-font.css",
166);
167
168$-theme-fonts: (
169 "alpine": "agGridAlpine",
170 "alpine-dark": "agGridAlpine",
171 "balham": "agGridBalham",
172 "balham-dark": "agGridBalham",
173 "material": "agGridMaterial",
174);
175
176@function -is-provided-theme($theme-name) {
177 @return map.has-key($-theme-variables, $theme-name);
178}
179
180@function -get-themes($params) {
181 $themes: map.get($params, "themes");
182 $themes: () !default;
183
184 @if meta.type-of($themes) == string {
185 $themes: ($themes,) // comma makes this a single element list
186 }
187
188 // treat ("alpine", "balham") as (alpine: (), "balham": ())
189 @if meta.type-of($themes) == list {
190 $themes-list: $themes;
191 $themes: ();
192 @each $theme in $themes-list {
193 $themes: map.set($themes, $theme, ());
194 }
195 }
196
197 @if map.has-key($params, "theme") {
198 $theme: map.get($params, "theme");
199 @if meta.type-of($theme) == list {
200 @error "Expected theme to be a string, got a list (if you intend to use multiple themes, use the plural `themes` parameter)";
201 }
202 @else if meta.type-of($theme) != string {
203 @error "Expected theme to be a string, got #{meta.inspect($theme)})";
204 }
205 $themes: map.set($themes, $theme, ());
206 }
207
208 @if list.length($themes) == 0 {
209 $themes: (alpine: ());
210 }
211
212 $params: map.remove($params, "theme", "themes");
213
214 $cleaned: ();
215 @each $name, $extra-params in $themes {
216 $theme-params: internal-preprocess-params(map.merge($params, $extra-params));
217 $cleaned: map.set($cleaned, -clean-theme-name($name), $theme-params);
218 }
219 @return $cleaned;
220}
221
222// Return a version of $params with colour blending applied
223@function -base-color-blends($params) {
224 // Simple defaults. We need to define the defaults for any parameters
225 // that are used in blending below
226 $params: -param-default($params, --ag-foreground-color, #000);
227 $params: -param-default($params, --ag-background-color, #fff);
228 $params: -param-default($params, --ag-range-selection-border-color, --ag-foreground-color);
229
230 // Blended defaults.
231 $params: -param-default($params, --ag-disabled-foreground-color, --ag-foreground-color, $alpha: 0.5);
232 $params: -param-default($params, --ag-modal-overlay-background-color, --ag-background-color, $alpha: 0.66);
233 $params: -param-default($params, --ag-range-selection-background-color, --ag-range-selection-border-color, $alpha: 0.2);
234 $params: -param-default($params, --ag-range-selection-background-color-2, --ag-range-selection-background-color, $self-overlay: 2);
235 $params: -param-default($params, --ag-range-selection-background-color-3, --ag-range-selection-background-color, $self-overlay: 3);
236 $params: -param-default($params, --ag-range-selection-background-color-4, --ag-range-selection-background-color, $self-overlay: 4);
237 $params: -param-default($params, --ag-border-color, --ag-foreground-color, $alpha: 0.25);
238 $params: -param-default($params, --ag-header-column-separator-color, --ag-border-color, $alpha: 0.5);
239 $params: -param-default($params, --ag-header-column-resize-handle-color, --ag-border-color, $alpha: 0.5);
240 $params: -param-default($params, --ag-input-disabled-border-color, --ag-input-border-color, $alpha: 0.3);
241 @return $params;
242}
243
244@function -theme-alpine-color-blends($params) {
245 // Simple defaults. We need to define the defaults for any parameters
246 // that are used in blending either below or in the base color blends
247 $params: -param-default($params, --ag-background-color, #fff);
248 $params: -param-default($params, --ag-foreground-color, #181d1f);
249 $params: -param-default($params, --ag-subheader-background-color, #fff);
250 $params: -param-default($params, --ag-alpine-active-color, #2196f3);
251 $params: -param-default($params, --ag-range-selection-border-color, --ag-alpine-active-color);
252
253 // Blended defaults
254 $params: -param-default($params, --ag-subheader-toolbar-background-color, --ag-subheader-background-color, $alpha: 0.5);
255 $params: -param-default($params, --ag-selected-row-background-color, --ag-alpine-active-color, $alpha: 0.1);
256 $params: -param-default($params, --ag-row-hover-color, --ag-alpine-active-color, $alpha: 0.1);
257 $params: -param-default($params, --ag-column-hover-color, --ag-alpine-active-color, $alpha: 0.1);
258 $params: -param-default($params, --ag-chip-background-color, --ag-foreground-color, $alpha: 0.07);
259 $params: -param-default($params, --ag-input-disabled-background-color, --ag-border-color, $alpha: 0.15);
260 $params: -param-default($params, --ag-input-disabled-border-color, --ag-border-color, $alpha: 0.3);
261 $params: -param-default($params, --ag-disabled-foreground-color, --ag-foreground-color, $alpha: 0.5);
262 $params: -param-default($params, --ag-input-focus-border-color, --ag-alpine-active-color, $alpha: 0.4);
263 @return $params;
264}
265
266@function -theme-alpine-dark-color-blends($params) {
267 $params: -param-default($params, --ag-background-color, #181d1f);
268 $params: -param-default($params, --ag-foreground-color, #fff);
269 $params: -param-default($params, --ag-subheader-background-color, #000);
270
271 @return -theme-alpine-color-blends($params);
272}
273
274@function -theme-balham-color-blends($params) {
275 // Simple defaults. We need to define the defaults for any parameters
276 // that are used in blending either below or in the base color blends
277 $params: -param-default($params, --ag-background-color, #fff);
278 $params: -param-default($params, --ag-foreground-color, #000);
279 $params: -param-default($params, --ag-border-color, #bdc3c7);
280 $params: -param-default($params, --ag-subheader-background-color, #e2e9eb);
281 $params: -param-default($params, --ag-balham-active-color, #0091ea);
282 $params: -param-default($params, --ag-range-selection-border-color, --ag-balham-active-color);
283
284 // Blended defaults
285 $params: -param-default($params, --ag-secondary-foreground-color, --ag-foreground-color, $alpha: 0.54);
286 $params: -param-default($params, --ag-disabled-foreground-color, --ag-foreground-color, $alpha: 0.38);
287 $params: -param-default($params, --ag-subheader-toolbar-background-color, --ag-subheader-background-color, $alpha: 0.5);
288 $params: -param-default($params, --ag-row-border-color, --ag-border-color, $alpha: 0.58);
289 $params: -param-default($params, --ag-chip-background-color, --ag-foreground-color, $alpha: 0.1);
290 $params: -param-default($params, --ag-selected-row-background-color, --ag-balham-active-color, $alpha: 0.28);
291 $params: -param-default($params, --ag-header-column-separator-color, --ag-border-color, $alpha: 0.5);
292 @return $params;
293}
294
295@function -theme-balham-dark-color-blends($params) {
296 $params: -param-default($params, --ag-background-color, #181d1f);
297 $params: -param-default($params, --ag-foreground-color, #fff);
298 $params: -param-default($params, --ag-border-color, #424242);
299 $params: -param-default($params, --ag-subheader-background-color, #000);
300 $params: -param-default($params, --ag-balham-active-color, #00B0FF);
301
302 $params: -param-default($params, --ag-disabled-foreground-color, --ag-foreground-color, $alpha: 0.38);
303 $params: -param-default($params, --ag-header-foreground-color, --ag-foreground-color, $alpha: 0.64);
304
305 @return -theme-balham-color-blends($params);
306}
307
308@function -theme-material-color-blends($params) {
309 // Simple defaults. We need to define the defaults for any parameters
310 // that are used in blending either below or in the base color blends
311 $params: -param-default($params, --ag-background-color, #fff);
312 $params: -param-default($params, --ag-foreground-color, rgba(0, 0, 0, 0.87));
313 $params: -param-default($params, --ag-subheader-background-color, #eee);
314 $params: -param-default($params, --ag-material-primary-color, #3f51b5);
315 $params: -param-default($params, --ag-range-selection-border-color, --ag-material-primary-color);
316 $params: -param-default($params, --ag-range-selection-background-color, rgba(122, 134, 203, 0.1));
317 $params: -param-default($params, --ag-border-color, #e2e2e2);
318
319 // Blended defaults
320 $params: -param-default($params, --ag-secondary-foreground-color, --ag-foreground-color, $alpha: 0.54);
321 $params: -param-default($params, --ag-disabled-foreground-color, --ag-foreground-color, $alpha: 0.38);
322 $params: -param-default($params, --ag-subheader-toolbar-background-color, --ag-subheader-background-color, $alpha: 0.5);
323 @return $params;
324}
325
326// Apply a default value to a parameter
327// $params: -param-default($params, x, #f08) - default x to a specific color value
328// $params: -param-default($params, x, y) - default x to the value of y (if y is set)
329// $params: -param-default($params, x, y, $alpha: 0.5) - default x to the value of y made 50% transparent
330@function -param-default($params, $target, $source, $alpha: null, $self-overlay: null) {
331 @if string.index($target, "--ag-") != 1 {
332 @error "Internal error: $target to -param-default should start --ag-";
333 }
334 $value: null;
335 @if type-of($source) == "color" {
336 $value: $source;
337 } @else {
338 @if string.index($source, "--ag-") != 1 {
339 @error "Internal error: $source to -param-default should start --ag-";
340 }
341 $value: map.get($params, $source);
342 }
343 @if map.has-key($params, $target) or $value == null {
344 @return $params;
345 }
346 @if $alpha != null {
347 $value: color.change($value, $alpha: color.alpha($value) * $alpha);
348 }
349 @if $self-overlay != null {
350 // this formula produces the same opacity value as overlaying the color on top
351 // of itself $self-overlay times
352 $value: color.change($value, $alpha: 1-(math.pow(1 - color.alpha($value), $self-overlay)));
353 }
354 @return map.set($params, $target, $value);
355}
356
357$-param-type-descriptions: (
358 "color": "a CSS color (e.g. `red` or `#fff`)",
359 "length": "a CSS length (e.g. `0`, `4px` or `50%`)",
360 "border-style": "a CSS border style (e.g. `dotted` or `solid`)",
361 "duration": "a number with time duration units (e.g. `3s` or `250ms`)",
362 "border-style-and-size": "either `none`, or a CSS border-style and size (e.g. `solid 1px`), or a boolean (true -> `solid 1px` and false -> `none`)",
363 "border-style-and-color": "a CSS border-style and color (e.g. `solid red`)",
364 "display": "A CSS display value (`block` to show, `none` to hide - `true` and `false` are also accepted)",
365 "any": "any value",
366);
367
368// params that are copied to --ag-param-name variables
369$-variable-param-types: (
370 --ag-foreground-color: "color",
371 --ag-data-color: "color",
372 --ag-secondary-foreground-color: "color",
373 --ag-header-foreground-color: "color",
374 --ag-disabled-foreground-color: "color",
375 --ag-background-color: "color",
376 --ag-header-background-color: "color",
377 --ag-tooltip-background-color: "color",
378 --ag-subheader-background-color: "color",
379 --ag-subheader-toolbar-background-color: "color",
380 --ag-control-panel-background-color: "color",
381 --ag-side-button-selected-background-color: "color",
382 --ag-selected-row-background-color: "color",
383 --ag-odd-row-background-color: "color",
384 --ag-modal-overlay-background-color: "color",
385 --ag-row-hover-color: "color",
386 --ag-column-hover-color: "color",
387 --ag-range-selection-border-color: "color",
388 --ag-range-selection-border-style: "border-style",
389 --ag-range-selection-background-color: "color",
390 --ag-range-selection-background-color-2: "color",
391 --ag-range-selection-background-color-3: "color",
392 --ag-range-selection-background-color-4: "color",
393 --ag-range-selection-highlight-color: "color",
394 --ag-selected-tab-underline-color: "color",
395 --ag-selected-tab-underline-width: "length",
396 --ag-selected-tab-underline-transition-speed: "duration",
397 --ag-range-selection-chart-category-background-color: "color",
398 --ag-range-selection-chart-background-color: "color",
399 --ag-header-cell-hover-background-color: "color",
400 --ag-header-cell-moving-background-color: "color",
401 --ag-value-change-value-highlight-background-color: "color",
402 --ag-value-change-delta-up-color: "color",
403 --ag-value-change-delta-down-color: "color",
404 --ag-chip-background-color: "color",
405 --ag-borders: "border-style-and-size",
406 --ag-border-color: "color",
407 --ag-borders-critical: "border-style-and-size",
408 --ag-borders-secondary: "border-style-and-size",
409 --ag-secondary-border-color: "color",
410
411 --ag-row-border-style: "border-style",
412 --ag-row-border-width: "length",
413 --ag-row-border-color: "color",
414
415 --ag-cell-horizontal-border: "border-style-and-color",
416 --ag-borders-input: "border-style-and-size",
417 --ag-input-border-color: "color",
418 --ag-borders-input-invalid: "border-style-and-size",
419 --ag-input-border-color-invalid: "color",
420 --ag-borders-side-button: "border-style-and-size",
421 --ag-border-radius: "length",
422 --ag-header-column-separator-display: "display",
423 --ag-header-column-separator-height: "length",
424 --ag-header-column-separator-width: "length",
425 --ag-header-column-separator-color: "color",
426 --ag-header-column-resize-handle-display: "display",
427 --ag-header-column-resize-handle-height: "length",
428 --ag-header-column-resize-handle-width: "length",
429 --ag-header-column-resize-handle-color: "color",
430 --ag-invalid-color: "color",
431 --ag-input-disabled-border-color: "color",
432 --ag-input-disabled-background-color: "color",
433 --ag-checkbox-background-color: "color",
434 --ag-checkbox-border-radius: "length",
435 --ag-checkbox-checked-color: "color",
436 --ag-checkbox-unchecked-color: "color",
437 --ag-checkbox-indeterminate-color: "color",
438 --ag-toggle-button-off-border-color: "color",
439 --ag-toggle-button-off-background-color: "color",
440 --ag-toggle-button-on-border-color: "color",
441 --ag-toggle-button-on-background-color: "color",
442 --ag-toggle-button-switch-background-color: "color",
443 --ag-toggle-button-switch-border-color: "color",
444 --ag-toggle-button-border-width: "length",
445 --ag-toggle-button-height: "length",
446 --ag-toggle-button-width: "length",
447 --ag-input-focus-box-shadow: "any",
448 --ag-input-focus-border-color: "color",
449 --ag-minichart-selected-chart-color: "color",
450 --ag-minichart-selected-page-color: "color",
451 --ag-grid-size: "length",
452 --ag-icon-size: "length",
453 --ag-widget-container-horizontal-padding: "length",
454 --ag-widget-container-vertical-padding: "length",
455 --ag-widget-horizontal-spacing: "length",
456 --ag-widget-vertical-spacing: "length",
457 --ag-cell-horizontal-padding: "length",
458 --ag-cell-widget-spacing: "length",
459 --ag-row-height: "length",
460 --ag-header-height: "length",
461 --ag-list-item-height: "length",
462 --ag-column-select-indent-size: "length",
463 --ag-set-filter-indent-size: "length",
464 --ag-row-group-indent-size: "length",
465 --ag-filter-tool-panel-group-indent: "length",
466 --ag-tab-min-width: "length",
467 --ag-menu-min-width: "length",
468 --ag-side-bar-panel-width: "length",
469 --ag-font-family: "any",
470 --ag-font-size: "length",
471 --ag-card-radius: "length",
472 --ag-card-shadow: "any",
473 --ag-popup-shadow: "any",
474 --ag-alpine-active-color: "color",
475 --ag-balham-active-color: "color",
476 --ag-material-primary-color: "color",
477 --ag-material-accent-color: "color",
478 --ag-icon-font-family: "any"
479);
480
481@each $icon-name in map.keys($icon-font-codes) {
482 $-variable-param-types: map.set($-variable-param-types, "--ag-icon-font-code-#{$icon-name}", "any");
483}
484
485// params that are not copied to CSS variables
486$-non-variable-param-types: (
487 suppress-native-widget-styling: "bool",
488 extend-theme: "string"
489);
490
491// Apply Sass API sugar over CSS variable API
492@function internal-preprocess-params($params) {
493 $processed: ();
494 @each $name, $value in $params {
495 $name: -clean-variable-name($name);
496 $type: map.get($-variable-param-types, $name);
497 // Allow `null` for colours
498 @if $type == "color" and $value == null {
499 $value: transparent;
500 }
501 // Allow booleans for borders params
502 @if string.index($name, "borders") and $value == true {
503 $value: solid 1px;
504 }
505 @if string.index($name, "borders") and $value == false {
506 $value: none;
507 }
508 // Allow booleans for display params
509 @if $type == "display" and not $value {
510 $value: none;
511 }
512 @if $type == "display" and $value == true {
513 $value: block;
514 }
515 $processed: map.set($processed, $name, $value);
516 }
517 @return $processed;
518}
519
520@mixin -validate-params($params, $theme: null) {
521 $error: internal-get-params-error($params, $theme);
522 @if $error {
523 @error $error;
524 }
525}
526
527@function internal-get-params-error($params, $theme: null) {
528 $theme-variables: ();
529 @if $theme and map.has-key($-theme-variables, $theme) {
530 $theme-variables: map.get($-theme-variables, $theme);
531 }
532
533 $param-types: map.merge($-variable-param-types, $theme-variables);
534 $errors: ();
535 @each $name, $value in $params {
536
537 @if $name == "suppress-native-widget-styling" {
538 $errors: list.append($errors, "suppress-native-widget-styling can not be specified at the theme level, only at the top level");
539 }
540
541 @if -is-runtime-expression($value) {
542 // You can pass variable expressions as values and we'll just trust
543 // that it's an appropriate value because we can't check at compile time
544 } @else {
545 $expected-type: map.get($param-types, $name);
546 @if $expected-type {
547 $is-valid: -validate-value($value, $expected-type);
548
549 @if not $is-valid {
550 $expected: map.get($-param-type-descriptions, $expected-type);
551 $expected: $expected-type !default;
552 $errors: list.append($errors, "Invalid parameter `#{$name}: #{meta.inspect($value)}` (expected #{$expected})");
553 }
554 } @else if not map.has-key($-non-variable-param-types, $name) {
555 $errors: list.append($errors, "Unrecognised parameter '#{$name}'");
556 }
557 }
558 }
559 @if list.length($errors) > 0 {
560 $message: "";
561 @each $error in $errors {
562 @if $message == "" {
563 $message: $error;
564 }
565 @else {
566 $message: "#{$message}; #{$error}";
567 }
568 }
569 @if list.length($errors) > 1 {
570 $message: "#{list.length($errors)} errors in #{$theme} parameters: #{$message}";
571 }
572 @else {
573 $message: "Error in #{$theme} parameters: #{$message}";
574 }
575 @return $message;
576 }
577 @return null;
578}
579
580@function -validate-value($value, $expected-type) {
581 $validator-name: "-validate-#{$expected-type}";
582 $validator: meta.get-function($validator-name);
583 @if not $validator {
584 @error "Internal error: no validator function #{$validator-name}";
585 }
586 @return meta.call($validator, $value);
587}
588
589@function -is-runtime-expression($value) {
590 $value: string.to-lower-case(meta.inspect($value));
591 @return string.index($value, "var(") != null or string.index($value, "calc(") != null;
592}
593
594@function -validate-color($value) {
595 @return meta.type-of($value) == "color";
596}
597
598@function -validate-length($value) {
599 @return meta.type-of($value) == "number" and (unit($value) != "" or $value == 0);
600}
601
602$border-styles: (none, hidden, dotted, dashed, solid, double, groove, ridge, inset, outset, initial);
603@function -validate-border-style($value) {
604 $value-preserve-quotes: meta.inspect($value);
605 @return list.index($border-styles, $value-preserve-quotes) != null;
606}
607
608@function -validate-duration($value) {
609 @return meta.type-of($value) == "number" and (unit($value) == "s" or unit($value) == "ms" or $value == 0);
610}
611
612@function -validate-display($value) {
613 @return $value == block or $value == none;
614}
615
616@function -validate-border-style-and-size($value) {
617 @return -validate-two-in-any-order($value, "border-style", "length");
618}
619
620@function -validate-border-style-and-color($value) {
621 @return -validate-two-in-any-order($value, "border-style", "color");
622}
623
624@function -validate-bool($value) {
625 @return meta.type-of($value) == "bool";
626}
627
628@function -validate-string($value) {
629 @return meta.type-of($value) == "string";
630}
631
632@function -validate-any($value) {
633 @return true;
634}
635
636@function -validate-two-in-any-order($value, $type-a, $type-b) {
637 @if meta.type-of($value) == "string" and $value == "none" {
638 @return true;
639 }
640
641 @if meta.type-of($value) != "list" or list.length($value) != 2 {
642 @return false;
643 }
644
645 $value-1: list.nth($value, 1);
646 $value-2: list.nth($value, 2);
647 @return (
648 (-validate-value($value-1, $type-a) and -validate-value($value-2, $type-b))
649 or
650 (-validate-value($value-2, $type-a) and -validate-value($value-1, $type-b))
651 );
652}
653
654// check that we defined all the validator functions
655@each $variable-name, $type in $-variable-param-types {
656 @if not map.has-key($-param-type-descriptions, $type) {
657 @error "Internal error: missing type description for #{$type} (used on #{$variable-name})";
658 }
659 @if not meta.function-exists("-validate-#{$type}") {
660 @error "Internal error: missing validator function for #{$type} (used on #{$variable-name})";
661 }
662}
\No newline at end of file