css-in-props 3.8.9 → 3.14.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.
Files changed (55) hide show
  1. package/README.md +6 -22
  2. package/dist/cjs/{props/defaults.js → defaults.js} +2 -2
  3. package/dist/cjs/index.js +19 -2
  4. package/dist/cjs/package.json +4 -0
  5. package/dist/cjs/props/animation.js +16 -80
  6. package/dist/cjs/props/block.js +71 -89
  7. package/dist/cjs/props/font.js +8 -7
  8. package/dist/cjs/props/index.js +0 -32
  9. package/dist/cjs/props/misc.js +9 -8
  10. package/dist/cjs/props/position.js +17 -14
  11. package/dist/cjs/props/theme.js +73 -70
  12. package/dist/cjs/props/timing.js +11 -11
  13. package/dist/cjs/registry.js +39 -0
  14. package/dist/cjs/set.js +1 -1
  15. package/dist/cjs/transform.js +80 -0
  16. package/index.js +1 -0
  17. package/package.json +13 -15
  18. package/src/index.js +4 -4
  19. package/src/props/animation.js +28 -23
  20. package/src/props/block.js +49 -57
  21. package/src/props/flex.js +4 -5
  22. package/src/props/index.js +18 -19
  23. package/src/props/misc.js +10 -3
  24. package/src/props/theme.js +10 -7
  25. package/src/set.js +11 -4
  26. package/src/transform/executors.js +60 -52
  27. package/src/transform/index.js +2 -2
  28. package/src/transform/transformers.js +85 -23
  29. package/dist/cjs/_transform.js +0 -30
  30. package/dist/cjs/props/flex.js +0 -45
  31. package/dist/cjs/props/grid.js +0 -39
  32. package/dist/cjs/transform/executors.js +0 -124
  33. package/dist/cjs/transform/index.js +0 -19
  34. package/dist/cjs/transform/transformers.js +0 -107
  35. package/dist/esm/_transform.js +0 -10
  36. package/dist/esm/emotion.js +0 -9
  37. package/dist/esm/index.js +0 -4
  38. package/dist/esm/props/animation.js +0 -101
  39. package/dist/esm/props/block.js +0 -171
  40. package/dist/esm/props/defaults.js +0 -321
  41. package/dist/esm/props/flex.js +0 -25
  42. package/dist/esm/props/font.js +0 -16
  43. package/dist/esm/props/grid.js +0 -19
  44. package/dist/esm/props/index.js +0 -35
  45. package/dist/esm/props/misc.js +0 -15
  46. package/dist/esm/props/position.js +0 -31
  47. package/dist/esm/props/theme.js +0 -134
  48. package/dist/esm/props/timing.js +0 -26
  49. package/dist/esm/set.js +0 -9
  50. package/dist/esm/transform/executors.js +0 -104
  51. package/dist/esm/transform/index.js +0 -2
  52. package/dist/esm/transform/transformers.js +0 -87
  53. package/dist/iife/index.js +0 -1084
  54. package/src/_transform.js +0 -10
  55. package/src/emotion.js +0 -9
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- import { isUndefined, isString } from '@domql/utils'
3
+ import { isUndefined, isString } from '@symbo.ls/utils'
4
4
 
5
5
  import {
6
6
  getSpacingBasedOnRatio,
@@ -11,16 +11,12 @@ import {
11
11
  } from '@symbo.ls/scratch'
12
12
 
13
13
  export const BLOCK_PROPS = {
14
- show: (val, el, s, ctx) => !!(ctx.utils.exec(val, el, s) === false) && ({
15
- display: 'none !important'
16
- }),
14
+ show: (val) => !val ? ({ display: 'none !important' }) : undefined,
17
15
 
18
- hide: (val, el, s, ctx) => !!ctx.utils.exec(val, el, s) && ({
19
- display: 'none !important'
20
- }),
16
+ hide: (val) => val ? ({ display: 'none !important' }) : undefined,
21
17
 
22
- height: (val, { props }) => transformSizeRatio('height', val, props),
23
- width: (val, { props }) => transformSizeRatio('width', val, props),
18
+ height: (val, el) => transformSizeRatio('height', val, el),
19
+ width: (val, el) => transformSizeRatio('width', val, el),
24
20
 
25
21
  boxSizing: (val) => !isUndefined(val)
26
22
  ? ({ boxSizing: val })
@@ -35,11 +31,11 @@ export const BLOCK_PROPS = {
35
31
  }
36
32
  },
37
33
 
38
- inlineSize: (val, { props }) => transformSizeRatio('inlineSize', val, props),
39
- blockSize: (val, { props }) => transformSizeRatio('blockSize', val, props),
34
+ inlineSize: (val, el) => transformSizeRatio('inlineSize', val, el),
35
+ blockSize: (val, el) => transformSizeRatio('blockSize', val, el),
40
36
 
41
- minWidth: (val, { props }) => transformSizeRatio('minWidth', val, props),
42
- maxWidth: (val, { props }) => transformSizeRatio('maxWidth', val, props),
37
+ minWidth: (val, el) => transformSizeRatio('minWidth', val, el),
38
+ maxWidth: (val, el) => transformSizeRatio('maxWidth', val, el),
43
39
  widthRange: (val) => {
44
40
  if (!isString(val)) return
45
41
  const [minWidth, maxWidth] = val.split(' ')
@@ -49,8 +45,8 @@ export const BLOCK_PROPS = {
49
45
  }
50
46
  },
51
47
 
52
- minHeight: (val, { props }) => transformSizeRatio('minHeight', val, props),
53
- maxHeight: (val, { props }) => transformSizeRatio('maxHeight', val, props),
48
+ minHeight: (val, el) => transformSizeRatio('minHeight', val, el),
49
+ maxHeight: (val, el) => transformSizeRatio('maxHeight', val, el),
54
50
  heightRange: (val) => {
55
51
  if (!isString(val)) return
56
52
  const [minHeight, maxHeight] = val.split(' ')
@@ -69,11 +65,11 @@ export const BLOCK_PROPS = {
69
65
  }
70
66
  },
71
67
 
72
- minBlockSize: (val, { props }) => transformSizeRatio('minBlockSize', val, props),
73
- minInlineSize: (val, { props }) => transformSizeRatio('minInlineSize', val, props),
68
+ minBlockSize: (val, el) => transformSizeRatio('minBlockSize', val, el),
69
+ minInlineSize: (val, el) => transformSizeRatio('minInlineSize', val, el),
74
70
 
75
- maxBlockSize: (val, { props }) => transformSizeRatio('maxBlockSize', val, props),
76
- maxInlineSize: (val, { props }) => transformSizeRatio('maxInlineSize', val, props),
71
+ maxBlockSize: (val, el) => transformSizeRatio('maxBlockSize', val, el),
72
+ maxInlineSize: (val, el) => transformSizeRatio('maxInlineSize', val, el),
77
73
 
78
74
  minSize: (val) => {
79
75
  if (!isString(val)) return
@@ -93,10 +89,10 @@ export const BLOCK_PROPS = {
93
89
  }
94
90
  },
95
91
 
96
- borderWidth: (val, { props }) => transformSizeRatio('borderWidth', val, props),
92
+ borderWidth: (val, el) => transformSizeRatio('borderWidth', val, el),
97
93
 
98
- padding: (val, { props }) => transformSizeRatio('padding', val, props),
99
- scrollPadding: (val, { props }) => transformSizeRatio('scrollPadding', val, props),
94
+ padding: (val, el) => transformSizeRatio('padding', val, el),
95
+ scrollPadding: (val, el) => transformSizeRatio('scrollPadding', val, el),
100
96
  paddingInline: (val) => {
101
97
  if (!isString(val)) return
102
98
  const [paddingInlineStart, paddingInlineEnd] = val.split(' ')
@@ -113,19 +109,17 @@ export const BLOCK_PROPS = {
113
109
  ...transformSize('paddingBlockEnd', paddingBlockEnd || paddingBlockStart)
114
110
  }
115
111
  },
116
- // Traditional directional padding
117
- paddingTop: (val, { props }) => transformSizeRatio('paddingBlockStart', val, props),
118
- paddingBottom: (val, { props }) => transformSizeRatio('paddingBlockEnd', val, props),
119
- paddingLeft: (val, { props }) => transformSizeRatio('paddingInlineStart', val, props),
120
- paddingRight: (val, { props }) => transformSizeRatio('paddingInlineEnd', val, props),
121
-
122
- // Logical properties (for reference)
123
- paddingBlockStart: (val, { props }) => transformSizeRatio('paddingBlockStart', val, props), // maps to top
124
- paddingBlockEnd: (val, { props }) => transformSizeRatio('paddingBlockEnd', val, props), // maps to bottom
125
- paddingInlineStart: (val, { props }) => transformSizeRatio('paddingInlineStart', val, props), // maps to left
126
- paddingInlineEnd: (val, { props }) => transformSizeRatio('paddingInlineEnd', val, props), // maps to right
127
-
128
- margin: (val, { props }) => transformSizeRatio('margin', val, props),
112
+ paddingTop: (val, el) => transformSizeRatio('paddingBlockStart', val, el),
113
+ paddingBottom: (val, el) => transformSizeRatio('paddingBlockEnd', val, el),
114
+ paddingLeft: (val, el) => transformSizeRatio('paddingInlineStart', val, el),
115
+ paddingRight: (val, el) => transformSizeRatio('paddingInlineEnd', val, el),
116
+
117
+ paddingBlockStart: (val, el) => transformSizeRatio('paddingBlockStart', val, el),
118
+ paddingBlockEnd: (val, el) => transformSizeRatio('paddingBlockEnd', val, el),
119
+ paddingInlineStart: (val, el) => transformSizeRatio('paddingInlineStart', val, el),
120
+ paddingInlineEnd: (val, el) => transformSizeRatio('paddingInlineEnd', val, el),
121
+
122
+ margin: (val, el) => transformSizeRatio('margin', val, el),
129
123
  marginInline: (val) => {
130
124
  if (!isString(val)) return
131
125
  const [marginInlineStart, marginInlineEnd] = val.split(' ')
@@ -134,39 +128,37 @@ export const BLOCK_PROPS = {
134
128
  ...transformSize('marginInlineEnd', marginInlineEnd || marginInlineStart)
135
129
  }
136
130
  },
137
- marginBlock: (val, { props }) => {
138
- if (!isString(props.marginBlock)) return
139
- const [marginBlockStart, marginBlockEnd] = props.marginBlock.split(' ')
131
+ marginBlock: (val, el) => {
132
+ if (!isString(el.marginBlock)) return
133
+ const [marginBlockStart, marginBlockEnd] = el.marginBlock.split(' ')
140
134
  return {
141
135
  ...transformSize('marginBlockStart', marginBlockStart),
142
136
  ...transformSize('marginBlockEnd', marginBlockEnd || marginBlockStart)
143
137
  }
144
138
  },
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
152
- marginInlineStart: (val, { props }) => transformSizeRatio('marginInlineStart', val, props),
153
- marginInlineEnd: (val, { props }) => transformSizeRatio('marginInlineEnd', val, props),
154
- marginBlockStart: (val, { props }) => transformSizeRatio('marginBlockStart', val, props),
155
- marginBlockEnd: (val, { props }) => transformSizeRatio('marginBlockEnd', val, props),
139
+ marginTop: (val, el) => transformSizeRatio('marginBlockStart', val, el),
140
+ marginBottom: (val, el) => transformSizeRatio('marginBlockEnd', val, el),
141
+ marginLeft: (val, el) => transformSizeRatio('marginInlineStart', val, el),
142
+ marginRight: (val, el) => transformSizeRatio('marginInlineEnd', val, el),
143
+
144
+ marginInlineStart: (val, el) => transformSizeRatio('marginInlineStart', val, el),
145
+ marginInlineEnd: (val, el) => transformSizeRatio('marginInlineEnd', val, el),
146
+ marginBlockStart: (val, el) => transformSizeRatio('marginBlockStart', val, el),
147
+ marginBlockEnd: (val, el) => transformSizeRatio('marginBlockEnd', val, el),
156
148
 
157
149
  gap: (val) => ({
158
150
  gap: transfromGap(val)
159
151
  }),
160
152
 
161
- columnGap: (val, { props }) => getSpacingBasedOnRatio(props, 'columnGap', val),
162
- rowGap: (val, { props }) => getSpacingBasedOnRatio(props, 'rowGap', val),
153
+ columnGap: (val, el) => getSpacingBasedOnRatio(el, 'columnGap', val),
154
+ rowGap: (val, el) => getSpacingBasedOnRatio(el, 'rowGap', val),
163
155
 
164
- flexWrap: (val, { props }) => ({
156
+ flexWrap: (val) => ({
165
157
  display: 'flex',
166
- flexFlow: (val || 'row').split(' ')[0] + ' ' + props.flexWrap
158
+ flexWrap: val
167
159
  }),
168
- flexFlow: (val, { props }) => {
169
- const { reverse } = props
160
+ flexFlow: (val, el) => {
161
+ const reverse = el.reverse
170
162
  if (!isString(val)) return
171
163
  let [direction, wrap] = (val || 'row').split(' ')
172
164
  if (val.startsWith('x') || val === 'row') direction = 'row'
@@ -186,6 +178,6 @@ export const BLOCK_PROPS = {
186
178
  }
187
179
  },
188
180
 
189
- round: (val, { props }) => transformBorderRadius(val || props.borderRadius, props, 'round'),
190
- borderRadius: (val, { props }) => transformBorderRadius(val || props.round, props, 'borderRadius')
181
+ round: (val, el) => transformBorderRadius(val ?? el.borderRadius, el, 'round'),
182
+ borderRadius: (val, el) => transformBorderRadius(val ?? el.round, el, 'borderRadius')
191
183
  }
package/src/props/flex.js CHANGED
@@ -1,11 +1,10 @@
1
1
  'use strict'
2
2
 
3
- import { isString } from '@domql/utils'
3
+ import { isString } from '@symbo.ls/utils'
4
4
 
5
5
  export const FLEX_PROPS = {
6
6
  flow: (value, el) => {
7
- const { props } = el
8
- const { reverse } = props
7
+ const reverse = el.reverse
9
8
  if (!isString(value)) return
10
9
  let [direction, wrap] = (value || 'row').split(' ')
11
10
  if (value.startsWith('x') || value === 'row') direction = 'row'
@@ -20,11 +19,11 @@ export const FLEX_PROPS = {
20
19
  }
21
20
  },
22
21
 
23
- wrap: (value, { props }) => {
22
+ wrap: (value, el) => {
24
23
  return { display: 'flex', flexWrap: value }
25
24
  },
26
25
 
27
- align: (value, { props }) => {
26
+ align: (value, el) => {
28
27
  const [alignItems, justifyContent] = value.split(' ')
29
28
  return { display: 'flex', alignItems, justifyContent }
30
29
  }
@@ -1,31 +1,30 @@
1
1
  'use strict'
2
2
 
3
- import { ANIMATION_PROPS } from './animation'
4
- import { BLOCK_PROPS } from './block'
5
- import { FONT_PROPS } from './font'
6
- import { MISC_PROPS } from './misc'
7
- import { POSITION_PROPS } from './position'
8
- import { THEME_PROPS } from './theme'
9
- import { TIMING_PROPS } from './timing'
10
- import { FLEX_PROPS } from './flex'
11
- import { GRID_PROPS } from './grid'
3
+ import { ANIMATION_PROPS } from './animation.js'
4
+ import { BLOCK_PROPS } from './block.js'
5
+ import { FONT_PROPS } from './font.js'
6
+ import { MISC_PROPS } from './misc.js'
7
+ import { POSITION_PROPS } from './position.js'
8
+ import { THEME_PROPS } from './theme.js'
9
+ import { TIMING_PROPS } from './timing.js'
10
+ import { FLEX_PROPS } from './flex.js'
11
+ import { GRID_PROPS } from './grid.js'
12
12
 
13
- export * from './animation'
14
- export * from './block'
15
- export * from './font'
16
- export * from './misc'
17
- export * from './position'
18
- export * from './theme'
19
- export * from './timing'
20
- export * from './flex'
21
- export * from './grid'
13
+ export * from './animation.js'
14
+ export * from './block.js'
15
+ export * from './font.js'
16
+ export * from './misc.js'
17
+ export * from './position.js'
18
+ export * from './theme.js'
19
+ export * from './timing.js'
20
+ export * from './flex.js'
21
+ export * from './grid.js'
22
22
 
23
23
  export const CSS_PROPS_REGISTRY = {
24
24
  ...ANIMATION_PROPS,
25
25
  ...BLOCK_PROPS,
26
26
  ...FONT_PROPS,
27
27
  ...MISC_PROPS,
28
- ...MISC_PROPS,
29
28
  ...POSITION_PROPS,
30
29
  ...THEME_PROPS,
31
30
  ...TIMING_PROPS,
package/src/props/misc.js CHANGED
@@ -8,9 +8,16 @@ export const MISC_PROPS = {
8
8
  cursor: (value, el, s, ctx) => {
9
9
  if (!value) return
10
10
 
11
- const file = ctx.files && ctx.files[value]
12
- if (file && file.content) value = `url(${file.content.src})`
11
+ const asset = ctx.assets && ctx.assets[value]
12
+ if (asset && asset.content) value = `url(${asset.content.src})`
13
+ else {
14
+ const file = ctx.files && ctx.files[value]
15
+ if (file && file.content) value = `url(${file.content.src})`
16
+ }
13
17
 
14
18
  return ({ cursor: value })
15
- }
19
+ },
20
+ opacity: (value) => value != null ? ({ opacity: String(value) }) : undefined,
21
+ visibility: (value) => value != null ? ({ visibility: value }) : undefined,
22
+ pointerEvents: (value) => value != null ? ({ pointerEvents: value }) : undefined
16
23
  }
@@ -12,7 +12,7 @@ import {
12
12
  transformSizeRatio
13
13
  } from '@symbo.ls/scratch'
14
14
 
15
- import { isDefined, isString } from '@domql/utils'
15
+ import { isDefined, isString } from '@symbo.ls/utils'
16
16
 
17
17
  export const getSystemGlobalTheme = ({ context, state }) => {
18
18
  const theme = state?.root?.globalTheme || context.designSystem?.globalTheme
@@ -21,12 +21,11 @@ export const getSystemGlobalTheme = ({ context, state }) => {
21
21
 
22
22
  export const THEME_PROPS = {
23
23
  theme: (val, element) => {
24
- const { props } = element
25
24
  if (!val) return
26
25
 
27
26
  // themeModifier explicitly forces a scheme on this component
28
- if (props.themeModifier) {
29
- return getMediaTheme(val, `@${props.themeModifier}`)
27
+ if (element.themeModifier) {
28
+ return getMediaTheme(val, `@${element.themeModifier}`)
30
29
  }
31
30
 
32
31
  // CSS vars handle dark/light switching — no modifier needed, no DOMQL re-render
@@ -63,8 +62,12 @@ export const THEME_PROPS = {
63
62
  backgroundImage: (val, element, s, ctx) => {
64
63
  const globalTheme = getSystemGlobalTheme(element)
65
64
  if (!val) return
66
- const file = ctx.files && ctx.files[val]
67
- if (file && file.content) val = file.content.src
65
+ const asset = ctx.assets && ctx.assets[val]
66
+ if (asset && asset.content) val = asset.content.src
67
+ else {
68
+ const file = ctx.files && ctx.files[val]
69
+ if (file && file.content) val = file.content.src
70
+ }
68
71
  return {
69
72
  backgroundImage: transformBackgroundImage(val, globalTheme)
70
73
  }
@@ -78,7 +81,7 @@ export const THEME_PROPS = {
78
81
  outline: transformBorder(val)
79
82
  }),
80
83
 
81
- outlineOffset: (val, { props }) => transformSizeRatio('outlineOffset', val, props),
84
+ outlineOffset: (val, el) => transformSizeRatio('outlineOffset', val, el),
82
85
 
83
86
  border: (val) => ({
84
87
  border: transformBorder(val)
package/src/set.js CHANGED
@@ -1,9 +1,16 @@
1
1
  'use strict'
2
2
 
3
- import { transformClassname } from './_transform'
4
- import { transformEmotion } from './emotion'
3
+ import { isObject } from '@symbo.ls/utils'
4
+ import { useCssInProps } from './transform/index.js'
5
+ import { css } from '@symbo.ls/css'
5
6
 
6
- export const setClassname = (props, emotionCss) => {
7
+ export const transformClassname = (element) => {
8
+ if (!isObject(element)) return
9
+ return useCssInProps(element, element)
10
+ }
11
+
12
+ export const setClassname = (props, cssEngine) => {
7
13
  const transform = transformClassname(props)
8
- return transformEmotion(transform, emotionCss)
14
+ if (typeof cssEngine === 'function') return cssEngine(transform)
15
+ return css(transform)
9
16
  }
@@ -1,9 +1,10 @@
1
1
  'use strict'
2
2
 
3
- import { exec, isArray, isFunction, isObject, isProduction, merge, overwrite, overwriteDeep } from '@domql/utils'
4
- import { CSS_PROPS_REGISTRY } from '../props'
5
- import { DEFAULT_CSS_PROPERTIES_LIST } from '../props/defaults'
6
- import { applyTrueProps, transformersByPrefix } from './transformers'
3
+ import { exec, isArray, isFunction, isObject, isProduction, merge, overwrite, overwriteDeep } from '@symbo.ls/utils'
4
+ import { pushConfig, popConfig } from '@symbo.ls/scratch'
5
+ import { CSS_PROPS_REGISTRY } from '../props/index.js'
6
+ import { DEFAULT_CSS_PROPERTIES_LIST } from '../props/defaults.js'
7
+ import { applyTrueProps, transformersByPrefix } from './transformers.js'
7
8
 
8
9
  /**
9
10
  * CLASS ASSIGNMENT
@@ -14,60 +15,67 @@ const isProd = isProduction()
14
15
 
15
16
  // Process non-setter properties and return remaining props
16
17
  export const usePropsAsCSS = (sourceObj, element, opts) => {
17
- let obj = {}
18
- const rest = {}
18
+ const ds = element?.context?.designSystem
19
+ if (ds) pushConfig(ds)
19
20
 
20
- const setToObj = (key, val) => {
21
- if (opts.unpack) {
22
- obj = { ...obj, ...val }
23
- return
24
- }
25
- obj[key] = val
26
- }
21
+ try {
22
+ let obj = {}
23
+ const rest = {}
27
24
 
28
- for (const key in sourceObj) {
29
- const value = sourceObj[key]
30
- if (key === 'class' && element.call('isString', sourceObj.class)) {
31
- const val = value.split(' ')
32
- if (val.length) {
33
- const CLASS = element.context.designSystem.class
34
- const result = val
35
- .reduce((acc, curr) => merge(acc, CLASS[curr]), {})
36
- obj.designSystemClass = result
25
+ const setToObj = (key, val) => {
26
+ if (opts.unpack) {
27
+ obj = { ...obj, ...val }
28
+ return
37
29
  }
38
- } else if (key === 'true') {
39
- const val = exec(value, element)
40
- merge(obj, applyTrueProps(val, element))
41
- } else if (element.classlist[key]) {
42
- const originalFromClass = element.classlist[key]
43
- const result = isFunction(originalFromClass)
44
- ? originalFromClass(element, element.state, element.context)
45
- : originalFromClass
46
- if (result) setToObj(key, result)
47
- if (!isProd && isObject(obj[key])) obj[key].label = key
48
- } else if (CSS_PROPS_REGISTRY[key]) {
49
- let val = exec(value, element)
50
- if (isArray(val)) {
51
- val = val.reduce((a, c) => merge(a, c), {})
52
- }
53
- let result = CSS_PROPS_REGISTRY[key](val, element, element.state, element.context)
54
- if (isArray(result)) result = result.reduce((a, c) => merge(a, c), {})
55
- if (result) setToObj(key, result)
56
- if (!isProd && isObject(obj[key])) obj[key].label = key
57
- } else if (DEFAULT_CSS_PROPERTIES_LIST.has(key)) {
58
- // they can be grouped
59
- let result = exec(value, element)
60
- if (typeof result === 'string' && result.charCodeAt(0) === 45 && result.charCodeAt(1) === 45) {
61
- result = `var(${result})`
30
+ obj[key] = val
31
+ }
32
+
33
+ for (const key in sourceObj) {
34
+ const value = sourceObj[key]
35
+ if (key === 'class' && element.call('isString', sourceObj.class)) {
36
+ const val = value.split(' ')
37
+ if (val.length) {
38
+ const CLASS = element.context.designSystem.class
39
+ const result = val
40
+ .reduce((acc, curr) => merge(acc, CLASS[curr]), {})
41
+ obj.designSystemClass = result
42
+ }
43
+ } else if (key === 'true') {
44
+ const val = exec(value, element)
45
+ merge(obj, applyTrueProps(val, element))
46
+ } else if (element.classlist[key]) {
47
+ const originalFromClass = element.classlist[key]
48
+ const result = isFunction(originalFromClass)
49
+ ? originalFromClass(element, element.state, element.context)
50
+ : originalFromClass
51
+ if (result) setToObj(key, result)
52
+ if (!isProd && isObject(obj[key])) obj[key].label = key
53
+ } else if (CSS_PROPS_REGISTRY[key]) {
54
+ let val = exec(value, element)
55
+ if (isArray(val)) {
56
+ val = val.reduce((a, c) => merge(a, c), {})
57
+ }
58
+ let result = CSS_PROPS_REGISTRY[key](val, element, element.state, element.context)
59
+ if (isArray(result)) result = result.reduce((a, c) => merge(a, c), {})
60
+ if (result) setToObj(key, result)
61
+ if (!isProd && isObject(obj[key])) obj[key].label = key
62
+ } else if (DEFAULT_CSS_PROPERTIES_LIST.has(key)) {
63
+ // they can be grouped
64
+ let result = exec(value, element)
65
+ if (typeof result === 'string' && result.charCodeAt(0) === 45 && result.charCodeAt(1) === 45) {
66
+ result = `var(${result})`
67
+ }
68
+ setToObj(key, { [key]: result })
69
+ if (!isProd && isObject(obj[key])) obj[key].label = key
70
+ } else {
71
+ rest[key] = value
62
72
  }
63
- setToObj(key, { [key]: result })
64
- if (!isProd && isObject(obj[key])) obj[key].label = key
65
- } else {
66
- rest[key] = value
67
73
  }
68
- }
69
74
 
70
- return [obj, rest]
75
+ return [obj, rest]
76
+ } finally {
77
+ if (ds) popConfig()
78
+ }
71
79
  }
72
80
 
73
81
  export const useSelectorsAsCSS = (sourceObj, element) => {
@@ -1,4 +1,4 @@
1
1
  'use strict'
2
2
 
3
- export * from './executors'
4
- export * from './transformers'
3
+ export * from './executors.js'
4
+ export * from './transformers.js'
@@ -1,34 +1,58 @@
1
1
  'use strict'
2
2
 
3
- import { isFunction } from '@domql/utils'
4
- import { useCssInProps } from './executors'
3
+ import { isFunction } from '@symbo.ls/utils'
4
+ import { useCssInProps } from './executors.js'
5
5
 
6
6
  /**
7
7
  * PROP APPLICATORS
8
8
  * Functions that handle different types of property applications
9
9
  */
10
10
 
11
+ // Match `[data-theme="dark"]` / `[data-theme='light']` with either quote
12
+ // style, grabbing the scheme name (`dark` / `light` / custom) for pairing
13
+ // with `prefers-color-scheme`.
14
+ const DATA_THEME_RE = /^\[data-theme=(?:"([^"]+)"|'([^']+)')\]$/
15
+
11
16
  // Media query handler
12
17
  const applyMediaProps = (key, selectorProps, element) => {
13
18
  const { context } = element
14
19
  if (!context.designSystem?.media) return
15
20
 
16
- const mediaValue = context.designSystem.media[key.slice(1)]
21
+ const schemeKey = key.slice(1)
22
+ const mediaValue = context.designSystem.media[schemeKey]
17
23
  const generatedClass = useCssInProps(selectorProps, element)
18
24
 
19
- let mediaKey
20
25
  if (!mediaValue) {
21
- mediaKey = key
22
- } else if (mediaValue === 'print') {
23
- mediaKey = '@media print'
24
- } else if (mediaValue[0] === '(') {
25
- mediaKey = `@media screen and ${mediaValue}`
26
- } else {
27
- // CSS selector (e.g. [data-theme="dark"]) use as parent selector
28
- mediaKey = `${mediaValue} &`
26
+ return { [key]: generatedClass }
27
+ }
28
+ if (mediaValue === 'print') {
29
+ return { '@media print': generatedClass }
30
+ }
31
+ if (mediaValue[0] === '(') {
32
+ return { [`@media screen and ${mediaValue}`]: generatedClass }
29
33
  }
30
34
 
31
- return { [mediaKey]: generatedClass }
35
+ // CSS selector (e.g. `[data-theme="dark"]`). Always emit the selector
36
+ // rule so explicit `data-theme="dark"` wins. For the standard `dark` /
37
+ // `light` schemes, ALSO emit a `@media (prefers-color-scheme: X)`
38
+ // fallback so the component adopts the OS scheme when `data-theme` is
39
+ // absent (i.e. `globalTheme: 'auto'`). Guard the fallback with
40
+ // `:not([data-theme])` on the app scope root so an explicit
41
+ // `data-theme="light"` (stamped on the app root) forces light even when
42
+ // the OS prefers dark. Other schemes (`sepia`, custom) are opt-in only.
43
+ const match = mediaValue.match(DATA_THEME_RE)
44
+ const scheme = match ? (match[1] || match[2]) : schemeKey
45
+ const result = { [`${mediaValue} &`]: generatedClass }
46
+ if (scheme === 'dark' || scheme === 'light') {
47
+ const scopeSelector = context.designSystem?.scopeSelector || ':root'
48
+ const guard = scopeSelector === ':root'
49
+ ? ':root:not([data-theme])'
50
+ : `${scopeSelector}:not([data-theme])`
51
+ result[`@media (prefers-color-scheme: ${scheme})`] = {
52
+ [`${guard} &`]: generatedClass
53
+ }
54
+ }
55
+ return result
32
56
  }
33
57
 
34
58
  // Simple applicators
@@ -38,7 +62,37 @@ const applyAndProps = (key, selectorProps, element) => {
38
62
 
39
63
  const applySelectorProps = (key, selectorProps, element) => {
40
64
  const selectorKey = `&${key}`
41
- return { [selectorKey]: useCssInProps(selectorProps, element) }
65
+ const resolved = useCssInProps(selectorProps, element)
66
+
67
+ // When the selector has commas and the resolved value contains nested selectors
68
+ // (e.g. '> h1'), distribute each nested selector across all comma parts
69
+ if (key.includes(',') && resolved) {
70
+ const flat = {}
71
+ const nested = {}
72
+ for (const k in resolved) {
73
+ if (typeof resolved[k] === 'object' && resolved[k] !== null) {
74
+ nested[k] = resolved[k]
75
+ } else {
76
+ flat[k] = resolved[k]
77
+ }
78
+ }
79
+ if (Object.keys(nested).length) {
80
+ const parts = selectorKey.split(',').map(p => p.trim())
81
+ const result = {}
82
+ // Flat styles apply to the combined selector
83
+ if (Object.keys(flat).length) {
84
+ result[selectorKey] = flat
85
+ }
86
+ // Each nested selector is distributed across all comma parts
87
+ for (const nestedKey in nested) {
88
+ const distributed = parts.map(p => `${p} ${nestedKey}`).join(', ')
89
+ result[distributed] = nested[nestedKey]
90
+ }
91
+ return result
92
+ }
93
+ }
94
+
95
+ return { [selectorKey]: resolved }
42
96
  }
43
97
 
44
98
  // Resolve a case value from context.cases
@@ -54,7 +108,7 @@ const applyCaseProps = (key, selectorProps, element) => {
54
108
  const caseKey = key.slice(1)
55
109
  let isCaseTrue = resolveCase(caseKey, element)
56
110
  if (isCaseTrue === undefined) {
57
- isCaseTrue = !!element.props?.[caseKey]
111
+ isCaseTrue = !!element[caseKey]
58
112
  }
59
113
  if (!isCaseTrue) return
60
114
  return useCssInProps(selectorProps, element)
@@ -64,25 +118,33 @@ const applyVariableProps = (key, selectorVal, element) => {
64
118
  return { [key]: selectorVal }
65
119
  }
66
120
 
67
- // . prefix: Truthy conditional (props/state first, then context.cases)
121
+ // . prefix: Truthy conditional (element/state first, then context.cases)
68
122
  const applyConditionalCaseProps = (key, selectorProps, element) => {
69
123
  const caseKey = key.slice(1)
70
- let isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey]
124
+ let isCaseTrue = element[caseKey] === true || element.state?.[caseKey]
71
125
  if (!isCaseTrue) {
72
- const caseResult = resolveCase(caseKey, element)
73
- if (caseResult !== undefined) isCaseTrue = caseResult
126
+ if (typeof element[caseKey] === 'function') {
127
+ try { isCaseTrue = element[caseKey](element, element.state, element.context) } catch (e) {}
128
+ } else {
129
+ const caseResult = resolveCase(caseKey, element)
130
+ if (caseResult !== undefined) isCaseTrue = caseResult
131
+ }
74
132
  }
75
133
  if (!isCaseTrue) return
76
134
  return useCssInProps(selectorProps, element)
77
135
  }
78
136
 
79
- // ! prefix: Falsy conditional (props/state first, then context.cases)
137
+ // ! prefix: Falsy conditional (element/state first, then context.cases)
80
138
  const applyConditionalFalsyProps = (key, selectorProps, element) => {
81
139
  const caseKey = key.slice(1)
82
- let isCaseTrue = element.props[caseKey] === true || element.state[caseKey] || element[caseKey]
140
+ let isCaseTrue = element[caseKey] === true || element.state?.[caseKey]
83
141
  if (!isCaseTrue) {
84
- const caseResult = resolveCase(caseKey, element)
85
- if (caseResult !== undefined) isCaseTrue = caseResult
142
+ if (typeof element[caseKey] === 'function') {
143
+ try { isCaseTrue = element[caseKey](element, element.state, element.context) } catch (e) {}
144
+ } else {
145
+ const caseResult = resolveCase(caseKey, element)
146
+ if (caseResult !== undefined) isCaseTrue = caseResult
147
+ }
86
148
  }
87
149
  if (isCaseTrue) return
88
150
  return useCssInProps(selectorProps, element)