@symbo.ls/element 3.14.2 → 3.14.3

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 (2) hide show
  1. package/package.json +3 -3
  2. package/src/create.js +23 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbo.ls/element",
3
- "version": "3.14.2",
3
+ "version": "3.14.3",
4
4
  "description": "Core element creation, update, and disposal engine for smbls v3.14",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -11,8 +11,8 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "@symbo.ls/signal": "^3.14.0",
14
- "@symbo.ls/state": "^3.14.0",
15
- "@symbo.ls/utils": "^3.14.0",
14
+ "@symbo.ls/state": "^3.14.2",
15
+ "@symbo.ls/utils": "^3.14.2",
16
16
  "css-in-props": "^3.14.0",
17
17
  "attrs-in-props": "^3.14.0"
18
18
  },
package/src/create.js CHANGED
@@ -1116,9 +1116,17 @@ function injectScopedCSS(node, rules) {
1116
1116
  for (const k in val) {
1117
1117
  const v = val[k]
1118
1118
  if (typeof v === 'object') {
1119
- const nestedSelector = k.replace(/&/g, '.' + id)
1120
- const nestedSuffix = ' ' + nestedSelector.replace('.' + id, '')
1121
- const fullSelector = resolvedSelector.split(', ').map(s => s + nestedSuffix).join(', ')
1119
+ // `&` in the nested key references the outer's resolved selector
1120
+ // (standard CSS-nesting semantics). `&.X` chains on the outer,
1121
+ // `& .X` is a descendant of the outer, `&:hover` / `&[disabled]`
1122
+ // chain a pseudo/attr selector — all of these work because the
1123
+ // replace preserves the user's whitespace and punctuation between
1124
+ // `&` and the rest. When the nested key has no `&`, treat it as
1125
+ // an implicit descendant (preserves keys like `'> h1'` rendering
1126
+ // as `outer > h1`).
1127
+ const fullSelector = k.includes('&')
1128
+ ? resolvedSelector.split(', ').map(s => k.replace(/&/g, s)).join(', ')
1129
+ : resolvedSelector.split(', ').map(s => `${s} ${k}`).join(', ')
1122
1130
  let nestedProps = ''
1123
1131
  for (const nk in v) {
1124
1132
  nestedProps += `${nk.replace(/[A-Z]/g, m => '-' + m.toLowerCase())}: ${v[nk]};`
@@ -1300,6 +1308,18 @@ function applyCssInProps(element) {
1300
1308
  cssStyles[prop] = val
1301
1309
  hasStyles = true
1302
1310
  }
1311
+ } else if (prop.charAt(0) === '&') {
1312
+ // Top-level scope-anchored selector — e.g. `'& .token': { '&.keyword': {color} }`
1313
+ // — flows straight to the atomic CSS engine, which substitutes `&` with
1314
+ // the generated class. The `:` and `@` branches below already do this for
1315
+ // pseudo-classes and at-rules; without this branch, top-level `&` keys
1316
+ // were silently dropped and projects had to wrap every scope rule in a
1317
+ // `style: {}` block (or inject a `<style>` child as a workaround).
1318
+ const val = element[prop]
1319
+ if (val && typeof val === 'object') {
1320
+ cssStyles[prop] = val
1321
+ hasStyles = true
1322
+ }
1303
1323
  } else if (prop.charAt(0) === '@' || prop.charAt(0) === ':') {
1304
1324
  // Selector-based CSS: @dark, @media, :hover
1305
1325
  const val = element[prop]