css-in-props 3.8.0 → 3.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,9 +57,9 @@ The prefix-to-handler registry that powers media queries, selectors, conditional
57
57
  | `[` | Attribute selector | `[disabled]`, `[data-active]` |
58
58
  | `>` | Child combinator | `> .child` |
59
59
  | `&` | Self selector | `&.active` |
60
- | `$` | Case conditional | `$isActive` |
61
- | `.` | Truthy conditional | `.visible` |
62
- | `!` | Falsy conditional | `!hidden` |
60
+ | `$` | Global case (from `context.cases`) | `$isSafari` |
61
+ | `.` | Truthy conditional (props/state, then `context.cases`) | `.visible` |
62
+ | `!` | Falsy conditional (props/state, then `context.cases`) | `!hidden` |
63
63
  | `-` | CSS variable | `--my-var` |
64
64
  | `*`, `+`, `~` | CSS combinators | `* div`, `+ .sibling`, `~ .general` |
65
65
 
@@ -88,3 +88,48 @@ if (CSS_SELECTOR_PREFIXES.has(firstChar)) {
88
88
  ```
89
89
 
90
90
  > **Lesson learned:** Without the define-awareness check, keys like `$propsCollection` were moved into `props` and became invisible to the define system, breaking collection-based rendering in projects like Rosi and BigBrother.
91
+
92
+ ## Global Cases
93
+
94
+ Cases are defined in `symbols/cases.js` and added to `context.cases` (not `designSystem`). Case functions receive the element as `this` and as the first argument, but must also work without element context (arrow functions).
95
+
96
+ ```javascript
97
+ // symbols/cases.js
98
+ export default {
99
+ isSafari: () => /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent),
100
+ isGeorgian () { return this?.state?.root?.language === 'ka' },
101
+ isMobile: () => window.innerWidth < 768
102
+ }
103
+ ```
104
+
105
+ ```javascript
106
+ // symbols/context.js
107
+ import cases from './cases.js'
108
+ export default { cases, /* ...other context */ }
109
+ ```
110
+
111
+ ### Resolution order
112
+
113
+ - **`$` prefix**: Checks `context.cases[key]` first (call if function, check truthiness if value). Falls back to `element.props[key]`.
114
+ - **`.` prefix**: Checks `element.props[key]` / `element.state[key]` / `element[key]` first. Falls back to `context.cases[key]`.
115
+ - **`!` prefix**: Same as `.` but inverted — applies when condition is falsy.
116
+
117
+ ```javascript
118
+ const Button = {
119
+ padding: 'A',
120
+ '$isSafari': { padding: 'B' }, // global case
121
+ '.isActive': { background: 'blue' }, // props/state, then cases
122
+ '!isMobile': { maxWidth: '1200px' } // inverted
123
+ }
124
+ ```
125
+
126
+ ## CSS Variable Resolution
127
+
128
+ String values starting with `--` are automatically wrapped in `var()` for all CSS properties:
129
+
130
+ ```javascript
131
+ const Box = {
132
+ padding: '--my-gap', // → var(--my-gap)
133
+ fontSize: '--base-size', // → var(--base-size)
134
+ }
135
+ ```
@@ -141,6 +141,12 @@ const BLOCK_PROPS = {
141
141
  ...(0, import_scratch.transformSize)("marginBlockEnd", marginBlockEnd || marginBlockStart)
142
142
  };
143
143
  },
144
+ // Traditional directional margin
145
+ marginTop: (val, { props }) => (0, import_scratch.transformSizeRatio)("marginBlockStart", val, props),
146
+ marginBottom: (val, { props }) => (0, import_scratch.transformSizeRatio)("marginBlockEnd", val, props),
147
+ marginLeft: (val, { props }) => (0, import_scratch.transformSizeRatio)("marginInlineStart", val, props),
148
+ marginRight: (val, { props }) => (0, import_scratch.transformSizeRatio)("marginInlineEnd", val, props),
149
+ // Logical properties
144
150
  marginInlineStart: (val, { props }) => (0, import_scratch.transformSizeRatio)("marginInlineStart", val, props),
145
151
  marginInlineEnd: (val, { props }) => (0, import_scratch.transformSizeRatio)("marginInlineEnd", val, props),
146
152
  marginBlockStart: (val, { props }) => (0, import_scratch.transformSizeRatio)("marginBlockStart", val, props),
@@ -66,7 +66,10 @@ const usePropsAsCSS = (sourceObj, element, opts) => {
66
66
  if (result) setToObj(key, result);
67
67
  if (!isProd && (0, import_utils.isObject)(obj[key])) obj[key].label = key;
68
68
  } else if (import_defaults.DEFAULT_CSS_PROPERTIES_LIST.has(key)) {
69
- const result = (0, import_utils.exec)(value, element);
69
+ let result = (0, import_utils.exec)(value, element);
70
+ if (typeof result === "string" && result.charCodeAt(0) === 45 && result.charCodeAt(1) === 45) {
71
+ result = `var(${result})`;
72
+ }
70
73
  setToObj(key, { [key]: result });
71
74
  if (!isProd && (0, import_utils.isObject)(obj[key])) obj[key].label = key;
72
75
  } else {
@@ -22,6 +22,7 @@ __export(transformers_exports, {
22
22
  transformersByPrefix: () => transformersByPrefix
23
23
  });
24
24
  module.exports = __toCommonJS(transformers_exports);
25
+ var import_utils = require("@domql/utils");
25
26
  var import_executors = require("./executors");
26
27
  const applyMediaProps = (key, selectorProps, element) => {
27
28
  const { context } = element;
@@ -38,10 +39,18 @@ const applySelectorProps = (key, selectorProps, element) => {
38
39
  const selectorKey = `&${key}`;
39
40
  return { [selectorKey]: (0, import_executors.useCssInProps)(selectorProps, element) };
40
41
  };
42
+ const resolveCase = (caseKey, element) => {
43
+ const caseFn = element.context?.cases?.[caseKey];
44
+ if (caseFn === void 0) return void 0;
45
+ if ((0, import_utils.isFunction)(caseFn)) return caseFn.call(element, element);
46
+ return !!caseFn;
47
+ };
41
48
  const applyCaseProps = (key, selectorProps, element) => {
42
- const { cases: CASES } = element.context?.designSystem || {};
43
49
  const caseKey = key.slice(1);
44
- const isCaseTrue = !CASES?.[caseKey] && !element.props[caseKey];
50
+ let isCaseTrue = resolveCase(caseKey, element);
51
+ if (isCaseTrue === void 0) {
52
+ isCaseTrue = !!element.props?.[caseKey];
53
+ }
45
54
  if (!isCaseTrue) return;
46
55
  return (0, import_executors.useCssInProps)(selectorProps, element);
47
56
  };
@@ -50,13 +59,21 @@ const applyVariableProps = (key, selectorVal, element) => {
50
59
  };
51
60
  const applyConditionalCaseProps = (key, selectorProps, element) => {
52
61
  const caseKey = key.slice(1);
53
- const isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey];
62
+ let isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey];
63
+ if (!isCaseTrue) {
64
+ const caseResult = resolveCase(caseKey, element);
65
+ if (caseResult !== void 0) isCaseTrue = caseResult;
66
+ }
54
67
  if (!isCaseTrue) return;
55
68
  return (0, import_executors.useCssInProps)(selectorProps, element);
56
69
  };
57
70
  const applyConditionalFalsyProps = (key, selectorProps, element) => {
58
71
  const caseKey = key.slice(1);
59
- const isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey];
72
+ let isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey];
73
+ if (!isCaseTrue) {
74
+ const caseResult = resolveCase(caseKey, element);
75
+ if (caseResult !== void 0) isCaseTrue = caseResult;
76
+ }
60
77
  if (isCaseTrue) return;
61
78
  return (0, import_executors.useCssInProps)(selectorProps, element);
62
79
  };
@@ -124,6 +124,12 @@ const BLOCK_PROPS = {
124
124
  ...transformSize("marginBlockEnd", marginBlockEnd || marginBlockStart)
125
125
  };
126
126
  },
127
+ // Traditional directional margin
128
+ marginTop: (val, { props }) => transformSizeRatio("marginBlockStart", val, props),
129
+ marginBottom: (val, { props }) => transformSizeRatio("marginBlockEnd", val, props),
130
+ marginLeft: (val, { props }) => transformSizeRatio("marginInlineStart", val, props),
131
+ marginRight: (val, { props }) => transformSizeRatio("marginInlineEnd", val, props),
132
+ // Logical properties
127
133
  marginInlineStart: (val, { props }) => transformSizeRatio("marginInlineStart", val, props),
128
134
  marginInlineEnd: (val, { props }) => transformSizeRatio("marginInlineEnd", val, props),
129
135
  marginBlockStart: (val, { props }) => transformSizeRatio("marginBlockStart", val, props),
@@ -40,7 +40,10 @@ const usePropsAsCSS = (sourceObj, element, opts) => {
40
40
  if (result) setToObj(key, result);
41
41
  if (!isProd && isObject(obj[key])) obj[key].label = key;
42
42
  } else if (DEFAULT_CSS_PROPERTIES_LIST.has(key)) {
43
- const result = exec(value, element);
43
+ let result = exec(value, element);
44
+ if (typeof result === "string" && result.charCodeAt(0) === 45 && result.charCodeAt(1) === 45) {
45
+ result = `var(${result})`;
46
+ }
44
47
  setToObj(key, { [key]: result });
45
48
  if (!isProd && isObject(obj[key])) obj[key].label = key;
46
49
  } else {
@@ -1,3 +1,4 @@
1
+ import { isFunction } from "@domql/utils";
1
2
  import { useCssInProps } from "./executors";
2
3
  const applyMediaProps = (key, selectorProps, element) => {
3
4
  const { context } = element;
@@ -14,10 +15,18 @@ const applySelectorProps = (key, selectorProps, element) => {
14
15
  const selectorKey = `&${key}`;
15
16
  return { [selectorKey]: useCssInProps(selectorProps, element) };
16
17
  };
18
+ const resolveCase = (caseKey, element) => {
19
+ const caseFn = element.context?.cases?.[caseKey];
20
+ if (caseFn === void 0) return void 0;
21
+ if (isFunction(caseFn)) return caseFn.call(element, element);
22
+ return !!caseFn;
23
+ };
17
24
  const applyCaseProps = (key, selectorProps, element) => {
18
- const { cases: CASES } = element.context?.designSystem || {};
19
25
  const caseKey = key.slice(1);
20
- const isCaseTrue = !CASES?.[caseKey] && !element.props[caseKey];
26
+ let isCaseTrue = resolveCase(caseKey, element);
27
+ if (isCaseTrue === void 0) {
28
+ isCaseTrue = !!element.props?.[caseKey];
29
+ }
21
30
  if (!isCaseTrue) return;
22
31
  return useCssInProps(selectorProps, element);
23
32
  };
@@ -26,13 +35,21 @@ const applyVariableProps = (key, selectorVal, element) => {
26
35
  };
27
36
  const applyConditionalCaseProps = (key, selectorProps, element) => {
28
37
  const caseKey = key.slice(1);
29
- const isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey];
38
+ let isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey];
39
+ if (!isCaseTrue) {
40
+ const caseResult = resolveCase(caseKey, element);
41
+ if (caseResult !== void 0) isCaseTrue = caseResult;
42
+ }
30
43
  if (!isCaseTrue) return;
31
44
  return useCssInProps(selectorProps, element);
32
45
  };
33
46
  const applyConditionalFalsyProps = (key, selectorProps, element) => {
34
47
  const caseKey = key.slice(1);
35
- const isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey];
48
+ let isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey];
49
+ if (!isCaseTrue) {
50
+ const caseResult = resolveCase(caseKey, element);
51
+ if (caseResult !== void 0) isCaseTrue = caseResult;
52
+ }
36
53
  if (isCaseTrue) return;
37
54
  return useCssInProps(selectorProps, element);
38
55
  };
@@ -49,7 +49,7 @@ var CssInProps = (() => {
49
49
  });
50
50
 
51
51
  // src/transform/executors.js
52
- var import_utils5 = __require("@domql/utils");
52
+ var import_utils6 = __require("@domql/utils");
53
53
 
54
54
  // src/props/animation.js
55
55
  var import_utils = __require("@domql/utils");
@@ -272,6 +272,12 @@ var CssInProps = (() => {
272
272
  ...(0, import_scratch2.transformSize)("marginBlockEnd", marginBlockEnd || marginBlockStart)
273
273
  };
274
274
  },
275
+ // Traditional directional margin
276
+ marginTop: (val, { props }) => (0, import_scratch2.transformSizeRatio)("marginBlockStart", val, props),
277
+ marginBottom: (val, { props }) => (0, import_scratch2.transformSizeRatio)("marginBlockEnd", val, props),
278
+ marginLeft: (val, { props }) => (0, import_scratch2.transformSizeRatio)("marginInlineStart", val, props),
279
+ marginRight: (val, { props }) => (0, import_scratch2.transformSizeRatio)("marginInlineEnd", val, props),
280
+ // Logical properties
275
281
  marginInlineStart: (val, { props }) => (0, import_scratch2.transformSizeRatio)("marginInlineStart", val, props),
276
282
  marginInlineEnd: (val, { props }) => (0, import_scratch2.transformSizeRatio)("marginInlineEnd", val, props),
277
283
  marginBlockStart: (val, { props }) => (0, import_scratch2.transformSizeRatio)("marginBlockStart", val, props),
@@ -888,6 +894,7 @@ var CssInProps = (() => {
888
894
  ]);
889
895
 
890
896
  // src/transform/transformers.js
897
+ var import_utils5 = __require("@domql/utils");
891
898
  var applyMediaProps = (key, selectorProps, element) => {
892
899
  const { context } = element;
893
900
  if (!context.designSystem?.media) return;
@@ -903,10 +910,18 @@ var CssInProps = (() => {
903
910
  const selectorKey = `&${key}`;
904
911
  return { [selectorKey]: useCssInProps(selectorProps, element) };
905
912
  };
913
+ var resolveCase = (caseKey, element) => {
914
+ const caseFn = element.context?.cases?.[caseKey];
915
+ if (caseFn === void 0) return void 0;
916
+ if ((0, import_utils5.isFunction)(caseFn)) return caseFn.call(element, element);
917
+ return !!caseFn;
918
+ };
906
919
  var applyCaseProps = (key, selectorProps, element) => {
907
- const { cases: CASES } = element.context?.designSystem || {};
908
920
  const caseKey = key.slice(1);
909
- const isCaseTrue = !CASES?.[caseKey] && !element.props[caseKey];
921
+ let isCaseTrue = resolveCase(caseKey, element);
922
+ if (isCaseTrue === void 0) {
923
+ isCaseTrue = !!element.props?.[caseKey];
924
+ }
910
925
  if (!isCaseTrue) return;
911
926
  return useCssInProps(selectorProps, element);
912
927
  };
@@ -915,13 +930,21 @@ var CssInProps = (() => {
915
930
  };
916
931
  var applyConditionalCaseProps = (key, selectorProps, element) => {
917
932
  const caseKey = key.slice(1);
918
- const isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey];
933
+ let isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey];
934
+ if (!isCaseTrue) {
935
+ const caseResult = resolveCase(caseKey, element);
936
+ if (caseResult !== void 0) isCaseTrue = caseResult;
937
+ }
919
938
  if (!isCaseTrue) return;
920
939
  return useCssInProps(selectorProps, element);
921
940
  };
922
941
  var applyConditionalFalsyProps = (key, selectorProps, element) => {
923
942
  const caseKey = key.slice(1);
924
- const isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey];
943
+ let isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey];
944
+ if (!isCaseTrue) {
945
+ const caseResult = resolveCase(caseKey, element);
946
+ if (caseResult !== void 0) isCaseTrue = caseResult;
947
+ }
925
948
  if (isCaseTrue) return;
926
949
  return useCssInProps(selectorProps, element);
927
950
  };
@@ -946,7 +969,7 @@ var CssInProps = (() => {
946
969
  };
947
970
 
948
971
  // src/transform/executors.js
949
- var isProd = (0, import_utils5.isProduction)();
972
+ var isProd = (0, import_utils6.isProduction)();
950
973
  var usePropsAsCSS = (sourceObj, element, opts) => {
951
974
  let obj = {};
952
975
  const rest = {};
@@ -963,30 +986,33 @@ var CssInProps = (() => {
963
986
  const val = value.split(" ");
964
987
  if (val.length) {
965
988
  const CLASS = element.context.designSystem.class;
966
- const result = val.reduce((acc, curr) => (0, import_utils5.merge)(acc, CLASS[curr]), {});
989
+ const result = val.reduce((acc, curr) => (0, import_utils6.merge)(acc, CLASS[curr]), {});
967
990
  obj.designSystemClass = result;
968
991
  }
969
992
  } else if (key === "true") {
970
- const val = (0, import_utils5.exec)(value, element);
971
- (0, import_utils5.merge)(obj, applyTrueProps(val, element));
993
+ const val = (0, import_utils6.exec)(value, element);
994
+ (0, import_utils6.merge)(obj, applyTrueProps(val, element));
972
995
  } else if (element.classlist[key]) {
973
996
  const originalFromClass = element.classlist[key];
974
- const result = (0, import_utils5.isFunction)(originalFromClass) ? originalFromClass(element, element.state, element.context) : originalFromClass;
997
+ const result = (0, import_utils6.isFunction)(originalFromClass) ? originalFromClass(element, element.state, element.context) : originalFromClass;
975
998
  if (result) setToObj(key, result);
976
- if (!isProd && (0, import_utils5.isObject)(obj[key])) obj[key].label = key;
999
+ if (!isProd && (0, import_utils6.isObject)(obj[key])) obj[key].label = key;
977
1000
  } else if (CSS_PROPS_REGISTRY[key]) {
978
- let val = (0, import_utils5.exec)(value, element);
979
- if ((0, import_utils5.isArray)(val)) {
980
- val = val.reduce((a, c) => (0, import_utils5.merge)(a, c), {});
1001
+ let val = (0, import_utils6.exec)(value, element);
1002
+ if ((0, import_utils6.isArray)(val)) {
1003
+ val = val.reduce((a, c) => (0, import_utils6.merge)(a, c), {});
981
1004
  }
982
1005
  let result = CSS_PROPS_REGISTRY[key](val, element, element.state, element.context);
983
- if ((0, import_utils5.isArray)(result)) result = result.reduce((a, c) => (0, import_utils5.merge)(a, c), {});
1006
+ if ((0, import_utils6.isArray)(result)) result = result.reduce((a, c) => (0, import_utils6.merge)(a, c), {});
984
1007
  if (result) setToObj(key, result);
985
- if (!isProd && (0, import_utils5.isObject)(obj[key])) obj[key].label = key;
1008
+ if (!isProd && (0, import_utils6.isObject)(obj[key])) obj[key].label = key;
986
1009
  } else if (DEFAULT_CSS_PROPERTIES_LIST.has(key)) {
987
- const result = (0, import_utils5.exec)(value, element);
1010
+ let result = (0, import_utils6.exec)(value, element);
1011
+ if (typeof result === "string" && result.charCodeAt(0) === 45 && result.charCodeAt(1) === 45) {
1012
+ result = `var(${result})`;
1013
+ }
988
1014
  setToObj(key, { [key]: result });
989
- if (!isProd && (0, import_utils5.isObject)(obj[key])) obj[key].label = key;
1015
+ if (!isProd && (0, import_utils6.isObject)(obj[key])) obj[key].label = key;
990
1016
  } else {
991
1017
  rest[key] = value;
992
1018
  }
@@ -1003,7 +1029,7 @@ var CssInProps = (() => {
1003
1029
  for (const k in result) {
1004
1030
  if (Object.prototype.hasOwnProperty.call(result, k)) {
1005
1031
  if (obj[k] && typeof obj[k] === "object" && typeof result[k] === "object") {
1006
- (0, import_utils5.overwriteDeep)(obj[k], result[k]);
1032
+ (0, import_utils6.overwriteDeep)(obj[k], result[k]);
1007
1033
  } else {
1008
1034
  obj[k] = result[k];
1009
1035
  }
@@ -1023,7 +1049,7 @@ var CssInProps = (() => {
1023
1049
  break;
1024
1050
  }
1025
1051
  if (hasSelectors) {
1026
- if (opts.unpack) return (0, import_utils5.overwrite)(cssObj, selectorsObj);
1052
+ if (opts.unpack) return (0, import_utils6.overwrite)(cssObj, selectorsObj);
1027
1053
  cssObj._selectors = selectorsObj;
1028
1054
  }
1029
1055
  return cssObj;
@@ -1039,11 +1065,11 @@ var CssInProps = (() => {
1039
1065
  };
1040
1066
 
1041
1067
  // src/emotion.js
1042
- var import_utils6 = __require("@domql/utils");
1068
+ var import_utils7 = __require("@domql/utils");
1043
1069
  var import_emotion2 = __require("@symbo.ls/emotion");
1044
1070
  var { css } = import_emotion2.emotion;
1045
1071
  var transformEmotion = (props, callback) => {
1046
- return (0, import_utils6.isFunction)(callback) ? callback(props) : css(props);
1072
+ return (0, import_utils7.isFunction)(callback) ? callback(props) : css(props);
1047
1073
  };
1048
1074
  return __toCommonJS(index_exports);
1049
1075
  })();
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "css-in-props",
3
3
  "description": "Utilize props as CSS methods",
4
4
  "author": "symbo.ls",
5
- "version": "3.8.0",
5
+ "version": "3.8.1",
6
6
  "repository": "https://github.com/symbo-ls/smbls",
7
7
  "type": "module",
8
8
  "module": "./dist/esm/index.js",
@@ -35,9 +35,9 @@
35
35
  "src"
36
36
  ],
37
37
  "dependencies": {
38
- "@domql/utils": "^3.8.0",
39
- "@symbo.ls/emotion": "^3.8.0",
40
- "@symbo.ls/scratch": "^3.8.0"
38
+ "@domql/utils": "^3.8.1",
39
+ "@symbo.ls/emotion": "^3.8.1",
40
+ "@symbo.ls/scratch": "^3.8.1"
41
41
  },
42
42
  "gitHead": "9fc1b79b41cdc725ca6b24aec64920a599634681",
43
43
  "browser": "./dist/esm/index.js",
@@ -142,6 +142,13 @@ export const BLOCK_PROPS = {
142
142
  ...transformSize('marginBlockEnd', marginBlockEnd || marginBlockStart)
143
143
  }
144
144
  },
145
+ // Traditional directional margin
146
+ marginTop: (val, { props }) => transformSizeRatio('marginBlockStart', val, props),
147
+ marginBottom: (val, { props }) => transformSizeRatio('marginBlockEnd', val, props),
148
+ marginLeft: (val, { props }) => transformSizeRatio('marginInlineStart', val, props),
149
+ marginRight: (val, { props }) => transformSizeRatio('marginInlineEnd', val, props),
150
+
151
+ // Logical properties
145
152
  marginInlineStart: (val, { props }) => transformSizeRatio('marginInlineStart', val, props),
146
153
  marginInlineEnd: (val, { props }) => transformSizeRatio('marginInlineEnd', val, props),
147
154
  marginBlockStart: (val, { props }) => transformSizeRatio('marginBlockStart', val, props),
@@ -56,7 +56,10 @@ export const usePropsAsCSS = (sourceObj, element, opts) => {
56
56
  if (!isProd && isObject(obj[key])) obj[key].label = key
57
57
  } else if (DEFAULT_CSS_PROPERTIES_LIST.has(key)) {
58
58
  // they can be grouped
59
- const result = exec(value, element)
59
+ let result = exec(value, element)
60
+ if (typeof result === 'string' && result.charCodeAt(0) === 45 && result.charCodeAt(1) === 45) {
61
+ result = `var(${result})`
62
+ }
60
63
  setToObj(key, { [key]: result })
61
64
  if (!isProd && isObject(obj[key])) obj[key].label = key
62
65
  } else {
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ import { isFunction } from '@domql/utils'
3
4
  import { useCssInProps } from './executors'
4
5
 
5
6
  /**
@@ -32,11 +33,21 @@ const applySelectorProps = (key, selectorProps, element) => {
32
33
  return { [selectorKey]: useCssInProps(selectorProps, element) }
33
34
  }
34
35
 
35
- // Conditional applicators
36
+ // Resolve a case value from context.cases
37
+ const resolveCase = (caseKey, element) => {
38
+ const caseFn = element.context?.cases?.[caseKey]
39
+ if (caseFn === undefined) return undefined
40
+ if (isFunction(caseFn)) return caseFn.call(element, element)
41
+ return !!caseFn
42
+ }
43
+
44
+ // $ prefix: Global cases from context.cases
36
45
  const applyCaseProps = (key, selectorProps, element) => {
37
- const { cases: CASES } = element.context?.designSystem || {}
38
46
  const caseKey = key.slice(1)
39
- const isCaseTrue = !CASES?.[caseKey] && !element.props[caseKey]
47
+ let isCaseTrue = resolveCase(caseKey, element)
48
+ if (isCaseTrue === undefined) {
49
+ isCaseTrue = !!element.props?.[caseKey]
50
+ }
40
51
  if (!isCaseTrue) return
41
52
  return useCssInProps(selectorProps, element)
42
53
  }
@@ -45,16 +56,26 @@ const applyVariableProps = (key, selectorVal, element) => {
45
56
  return { [key]: selectorVal }
46
57
  }
47
58
 
59
+ // . prefix: Truthy conditional (props/state first, then context.cases)
48
60
  const applyConditionalCaseProps = (key, selectorProps, element) => {
49
61
  const caseKey = key.slice(1)
50
- const isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey]
62
+ let isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey]
63
+ if (!isCaseTrue) {
64
+ const caseResult = resolveCase(caseKey, element)
65
+ if (caseResult !== undefined) isCaseTrue = caseResult
66
+ }
51
67
  if (!isCaseTrue) return
52
68
  return useCssInProps(selectorProps, element)
53
69
  }
54
70
 
71
+ // ! prefix: Falsy conditional (props/state first, then context.cases)
55
72
  const applyConditionalFalsyProps = (key, selectorProps, element) => {
56
73
  const caseKey = key.slice(1)
57
- const isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey]
74
+ let isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey]
75
+ if (!isCaseTrue) {
76
+ const caseResult = resolveCase(caseKey, element)
77
+ if (caseResult !== undefined) isCaseTrue = caseResult
78
+ }
58
79
  if (isCaseTrue) return
59
80
  return useCssInProps(selectorProps, element)
60
81
  }