From d02a59ad4984144125b98a4b1900138d8363eb3e Mon Sep 17 00:00:00 2001 From: Nathanael Sensfelder Date: Mon, 25 May 2020 18:20:56 +0200 Subject: Adds a way to do some additive CSS. As baffling as it may appear, Cascading Style Sheets cannot actually do cascading property values through multiple classes (you can only override the previous value, not see it). You'd think there would be a "current()" function which returns the not-yet-evaluated, about-to-be-overridden current value of the attribute, but no, there is not. There is no way to have any equivalent either, and since it's been nearly a decade they've seen propositions to address this deficiency without actually adding any, I wouldn't expect things to change within the next decade either. Doesn't help that they seem to consider the issue to be intertwined with the animation attributes, whereas it ought to be a generic thing. --- src/css/src/shared/additive-css.scss | 185 +++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 src/css/src/shared/additive-css.scss (limited to 'src') diff --git a/src/css/src/shared/additive-css.scss b/src/css/src/shared/additive-css.scss new file mode 100644 index 0000000..da077e9 --- /dev/null +++ b/src/css/src/shared/additive-css.scss @@ -0,0 +1,185 @@ +@use "sass:list"; +@use "sass:map"; + +$collections: (); +$properties: (); +$var-prefix: additive; + +@function variable-name ($collection, $property, $instance) +{ + @return --#{$var-prefix}-#{$collection}-#{$property}-#{$instance}; +} + +@mixin new-collection ($collection) +{ + @if (map-has-key($collections, $collection)) + { + @warn "Additive collection #{$collection} is declared multiple times." + } + @else + { + $new_collection: + ( + "instances": 0, + "has_been_used": false, + "properties": () + ); + + $collections: + map-merge($collections, ($collection: $new_collection)) + !global; + } +} + +@mixin new-property ($property, $neutral-value) +{ + @if (map-has-key($properties, $property)) + { + @if (not (map-get($properties, $property) == $neutral-value)) + { + @warn "Additive property #{$property} has multiple default values."; + } + } + @else + { + $properties: + map-merge($properties, ($property: $neutral-value)) + !global; + } +} + +@mixin add-property-to-collection ($collection, $property) +{ + @if (not map-has-key($properties, $property)) + { + @warn "Adding property to a collection prior to defining default value."; + } + @if (not map-has-key($collections, $collection)) + { + @error "Adding property to undefined collection."; + } + $collection-state: map-get($collections, $collection); + $collection-state: + map-merge( + $collection-state, + ( + "properties": + append( + map-get($collection-state, "properties"), + $property + ) + ) + ); + $collections: + map-merge($collections, ($collection: $collection-state)) + !global; +} + +@mixin set-property ($collection, $property, $value) +{ + @if (not map-has-key($properties, $property)) + { + @error "Using undefined property #{$property}."; + } + @if (not map-has-key($collections, $collection)) + { + @error "Using undefined collection #{$collection}."; + } + + $collection-state: map-get($collections, $collection); + + @if (map-get($collection-state, "has_been_used")) + { + @error "Adding to a property after it already has been used."; + } + + $instances: map-get($collection-state, "instances"); + $collection-state: + map-merge( + $collection-state, + ( + "instances":($instances + 1) + ) + ); + $collections: + map-merge($collections, ($collection: $collection-state)) + !global; + + #{variable-name($collection, $property, $instances)}: $value; +} + +@mixin use-property ($collection, $property, $separator) +{ + @if (not map-has-key($properties, $property)) + { + @error "Using undefined property #{$property}."; + } + @if (not map-has-key($collections, $collection)) + { + @error "Using undefined collection #{$collection}."; + } + $collection-state: map-get($collections, $collection); + $instances: map-get($collection-state, "instances"); + $collection-state: + map-merge( + $collection-state, + ( + "has_been_used": true + ) + ); + $collections: + map-merge($collections, ($collection: $collection-state)) + !global; + + @if (index(map-get($collection-state, "properties"), $property) == null) + { + @warn "Attempting to get value for unused additive property." + } + @else + { + $value: (); + @for $i from 0 to $instances + { + $value: + append( + $value, + var(#{variable_name($collection, $property, $i)}), + $separator + ); + } + + #{$property}: #{$value}; + } +} + +@mixin define-all-neutral-values () +{ + :root + { + @each $collection, $env in $collections + { + $collections: + map-merge( + $collections, + ( + $collection: + map-merge( + $env, + ( + "has_been_used": true + ) + ) + ) + ) + !global; + @each $property in map-get($env, "properties") + { + $default-value: map-get($properties, $property); + @for $i from 0 to map-get($env, "instances") + { + #{variable_name($collection, $property, $i)}: $default-value; + } + } + } + } +} -- cgit v1.2.3-70-g09d2