From 1257a534af5ebda9f167b5bfd283e0ade8ed7b80 Mon Sep 17 00:00:00 2001 From: Volpeon Date: Fri, 18 Oct 2024 13:02:18 +0200 Subject: New CSS variable management --- src/_props.scss | 454 ++++++++------------------------------------------------ 1 file changed, 62 insertions(+), 392 deletions(-) (limited to 'src/_props.scss') diff --git a/src/_props.scss b/src/_props.scss index 14295bd..c80c18b 100644 --- a/src/_props.scss +++ b/src/_props.scss @@ -1,434 +1,104 @@ -//// -/// Property trees. -/// -/// Property trees allow you to organize properties in a tree structure (internally nested maps). -/// The intended use is to store all your properties at the beginning and for the rest of the -/// stylesheet you just get them. -/// -/// @group Property trees -/// -/// @access public -//// - -@use 'sass:map'; @use 'sass:list'; -@use 'sass:string'; +@use 'sass:map'; @use 'sass:meta'; -@use './functions'; -@use './contexts'; - -/// -/// The maximum depth of resolved iro-prop-ref() references. -/// -/// @type number -/// -$native-assign-max-depth: 2 !default; - -/// -/// Indicate if property names must start with two dashes (--). -/// This is required if property trees are also used for native CSS custom properties. -/// -/// @type bool -/// -$enforce-double-dashes: true !default; - -/// -/// Default tree name to use if no name is specified. -/// -/// @type string -/// -$default-tree: 'default' !default; - -/// -/// List of all created property trees. -/// -/// @type list -/// -/// @access private -/// -$trees: (); - -/// -/// Default context name used for the namespace context. -/// -/// @type string -/// -$namespace-context-id: 'namespace' !default; - -/// -/// Declare a namespace, meaning that all variables declared and accessed. -/// -/// @param {string} $name - Name of the namespace -/// -@mixin namespace($name) { - $key: '--#{$name}'; - - $ns-key: get-ns-key(); - - @if $ns-key != null { - $key: list.append($ns-key, $key); - } @else { - $key: ($key); - } - - @include contexts.push($namespace-context-id, 'namespace', ( - 'name': $name, - 'key': $key - )); - - @content; - - @include contexts.pop($namespace-context-id); -} - -/// -/// Get the current namespace name. -/// -@function namespace() { - $noop: contexts.assert-stack-must-contain($namespace-context-id, 'namespace'); - - $data: list.nth(contexts.get($namespace-context-id, 'namespace'), 2); - $name: map.get($data, 'name'); - - @return $name; -} - -/// -/// Save a property tree. If a tree with the sane name already exists, the trees -/// will be merged. -/// -/// @param {map} $map - Map containing properties -/// @param {string} $tree [$default-tree] - ID the map is saved as -/// @param {bool} $merge [true] - If a tree named $tree already exists and this value is set to true, they will be merged. Otherwise an error will be emitted. -/// -@mixin store($map, $tree: $default-tree, $merge: true, $global: false) { - $noop: store($map, $tree, $merge, $global); -} - -/// -/// Save a property tree. -/// -/// @param {map} $map - Map containing properties -/// @param {string} $tree [$default-tree] - ID the map is saved as -/// @param {bool} $merge [true] - If a tree named $tree already exists and this value is set to true, they will be merged. Otherwise an error will be emitted. -/// -@function store($map, $tree: $default-tree, $merge: true, $global: false) { - $prop-map: null; +@use 'functions'; - @if $enforce-double-dashes { - @if not validate($map) { - @error 'Property tree keys must start with two dashes (--). If you don\'t use property trees for native CSS custom properties, set $enforce-double-dashes to false.'; - } +@function is-prop-ref($value) { + @if meta.type-of($value) != 'list' { + @return false; } - - @if not $global { - $ns-key: get-ns-key(); - - @if $ns-key != null { - $map: ($ns-key: $map); - } + @if list.length($value) != 4 { + @return false; } - - @if map.has-key($trees, $tree) { - @if $merge { - $map: map.deep-merge(map.get($trees, $tree), $map); - } @else { - @error 'Property tree #{inspect($tree)} does already exist.'; - } + @if list.nth($value, 1) != 'prop-ref' { + @return false; } - - $trees: map.merge($trees, ($tree: $map)) !global; - - @return null; + @return true; } -/// -/// Delete a property tree. -/// -/// @param {string} $tree [$default-tree] - ID of the tree to be deleted -/// -@mixin clear($tree: $default-tree) { - $noop: clear($tree); +@function def($name, $value: (), $metadata: null) { + @return ('prop-ref' $name $value $metadata); } -/// -/// Delete a property tree. -/// -/// @param {string} $tree [$default-tree] - ID of the tree to be deleted -/// -/// @throw If the property tree does not exist -/// -@function clear($tree: $default-tree) { - @if not map.has-key($trees, $tree) { - @error 'Property tree "#{inspect($tree)}" does not exist.'; +@function merge($ref, $value) { + @if not is-prop-ref($ref) { + @return $ref; } - $trees: map.remove($trees, $tree) !global; - - @return null; + $v: list.nth($ref, 3); + $ref: list.set-nth($ref, 3, map.deep-merge($v, $value)); + @return $ref; } -/// -/// Access a whole property or a subsection (i.e. value) of it. -/// -/// @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. -/// @param {string} $tree [$default-tree] - ID of the property tree to use -/// @param {any} $default [null] - Default value to return of no match was found. If null, this function will throw an error instead. -/// -/// @return {any} Value assigned to property or $default -/// -/// @throw If there was no match for $key and $default is null -/// -@function get-static($key: (), $tree: $default-tree, $default: null, $global: false) { - @if not map.has-key($trees, $tree) { - @error 'Unknown tree "#{$tree}".'; - } - - $result: map.get($trees, $tree); - - @if not $global { - $ns-key: get-ns-key(); - - @if $ns-key != null { - $orig-key: $key; - $key: $ns-key; - - @if meta.type-of($orig-key) == list { - @each $subkey in $orig-key { - $key: list.append($key, $subkey); - } - } @else { - $key: list.append($key, $orig-key); - } - } - } - - @if meta.type-of($key) == list { - $stop: false; - - @each $k in $key { - @if not $stop and map.has-key($result, $k) { - $result: map.get($result, $k); - - @if meta.type-of($result) == list and list.nth($result, 1) == 'iro-prop-ref' { - @if list.length($result) == 2 { - $result: get-static($tree: list.nth($result, 2), $global: true); - } @else { - $result: get-static(list.nth($result, 3), nth($result, 2), $global: true); - } - } - } @else { - $stop: true; - } - } - - @if $stop { - $result: null; - } - } @else { - $result: map.get($result, $key); - - @if meta.type-of($result) == list and list.nth($result, 1) == 'iro-prop-ref' { - @if list.length($result) == 2 { - $result: get-static($tree: list.nth($result, 2), $global: true); - } @else { - $result: get-static(list.nth($result, 3), nth($result, 2), $global: true); - } - } +@function get-deep($name, $value, $key: null, $keys...) { + @if is-prop-ref($value) { + @return get($value, $key, $keys); } - - @if $result == null { - @if $default == null { - @error '"#{$key}" is null.'; - } @else { - @return $default; - } + @if meta.type-of($value) == 'map' and $key != null { + @return get-deep(#{$name}#{$key}, map.get($value, $key), $keys...); } - - @return $result; + @return $name $value; } -/// -/// Generate a var() function call to get native CSS custom property. -/// -/// @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. -/// @param {string | null} $tree [null] - Optional tree to check if the property actually exists. -/// @param {any} $default [null] - Default value to return of no match was found. -/// -/// @return {string} var() -/// -@function get($key, $tree: $default-tree, $default: null, $global: false) { - @if $tree != null { - $value: get-static($key, $tree, $default, $global); - - @if meta.type-of($value) == map { - $result: (); - @each $k in map.keys($value) { - $result: map.set($result, $k, get(list.append($key, $k), $tree, $default, $global)); - } - @return $result; - } - } - - @if not $global { - $ns-key: get-ns-key(); - - @if $ns-key != null { - $orig-key: $key; - $key: $ns-key; - - @if meta.type-of($orig-key) == list { - @each $subkey in $orig-key { - $key: list.append($key, $subkey); - } - } @else { - $key: list.append($key, $orig-key); - } - } +@function map-to-vars($name, $map) { + @if meta.type-of($map) != 'map' { + @return var($name); } - $native-var: ''; + $out: (); - @if meta.type-of($key) == list { - @each $subkey in $key { - $native-var: $native-var + $subkey; - } - } @else { - $native-var: $key; + @each $key, $value in $map { + $out: map.set($out, $key, map-to-vars(#{$name}#{$key}, $value)); } - @if $default == null { - @return var(#{$native-var}); - } @else { - @return var(#{$native-var}, #{$default}); - } + @return $out; } -/// -/// Generate assignments for native CSS custom properties with the values from the specified tree. -/// -/// @param {string} $tree [$default-tree] - ID of the property tree to use -/// @param {string} $root [()] - Sub-tree to use for assignment -/// -@mixin assign($tree: $default-tree, $root: (), $skip: (), $prefix: $root, $global: false) { - $map: get-static($root, $tree, $global: $global); - $map: map.remove($map, $skip...); - - @if meta.type-of($prefix) == list { - $prefix: functions.str-implode($prefix); +@function get($ref, $key: null, $keys...) { + @if not is-prop-ref($ref) { + @return $ref; } - @if not $global { - $ns-key: get-ns-key(); + $name: list.nth($ref, 2); + $value: get(list.nth($ref, 3)); - @if $ns-key != null { - $prefix: $prefix + functions.str-implode($ns-key); + @if meta.type-of($value) == 'map' { + $res: get-deep($name, $value, $key, $keys...); + $name: list.nth($res, 1); + $value: list.nth($res, 2); + } @else if meta.type-of($value) == 'list' { + $i: 1; + @each $item in $value { + $value: list.set-nth($value, $i, get($item)); + $i: $i + 1; } } - @include assign-internal($map, $prefix); + @return map-to-vars($name, $value); } -/// -/// @access private -/// -@mixin assign-internal($map, $prefix: '', $ref-depth: $native-assign-max-depth) { - @each $key, $value in $map { - $rd: $ref-depth; - @if meta.type-of($value) == list and list.length($value) > 0 and list.nth($value, 1) == 'iro-prop-ref' { - @if $ref-depth != 0 { - $rd: $rd - 1; - @if list.length($value) == 2 { - $value: get-static($tree: list.nth($value, 2)); - } @else { - $value: get-static(list.nth($value, 3), nth($value, 2)); - } - } @else { - $value: null; - } - } - @if meta.type-of($value) != map and $value != () { - #{$prefix + $key}: #{$value}; - } @else { - @include assign-internal($value, $prefix + $key, $rd); +@mixin materialize-helper($name, $value) { + @if meta.type-of($value) == 'map' { + @each $key, $value in $value { + @include materialize-helper(#{$name}#{$key}, $value); } + } @else { + #{$name}: #{$value}; } } -/// -/// Validate property names. -/// -/// @access private -/// -@function validate($map) { - @each $key, $value in $map { - @if string.index($key, '--') != 1 { - @return false; - } +@mixin materialize($ref, $match-meta: null) { + @if is-prop-ref($ref) { + $name: list.nth($ref, 2); + $value: get(list.nth($ref, 3)); + $meta: get(list.nth($ref, 4)); - @if meta.type-of($value) == map { - @if not validate($value) { - @return false; - } + @if $meta == $match-meta { + @include materialize-helper($name, $value); } - } - - @return true; -} - -/// -/// Generate a reference to another tree. Dereferencing is lazy, so you may specify a tree that hasn't been created yet. -/// -/// @param {string} $tree [$default-tree] - ID of the property tree to use -/// @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. -/// -/// @return {list} A special list that let's Ignis know that this is a lazy value. -/// -/// @throw If there was no match for $key and $default is null -/// -@function ref($tree: $default-tree, $key: null, $global: false) { - @if not $global { - $ns-key: get-ns-key(); - - @if $ns-key != null { - $orig-key: $key; - $key: $ns-key; - - @if $orig-key != null { - @if meta.type-of($orig-key) == list { - @each $subkey in $orig-key { - $key: list.append($key, $subkey); - } - } @else { - $key: list.append($key, $orig-key); - } - } + } @else if meta.type-of($ref) == 'list' { + @each $r in $ref { + @include materialize($r); } } - - @if $key == null { - @return ('iro-prop-ref' $tree); - } @else { - @return ('iro-prop-ref' $tree $key); - } } - -/// -/// Get the current namespace key. -/// -/// @access private -/// -@function get-ns-key() { - $ctx: contexts.get($namespace-context-id, 'namespace'); - - @if $ctx == null { - @return null; - } - - $data: list.nth($ctx, 2); - $key: map.get($data, 'key'); - - @return $key; -} - -@include contexts.create($namespace-context-id); -- cgit v1.2.3-70-g09d2