Skip to content

Commit b0c5b0e

Browse files
committed
Wire unified CSS-to-RN runtime into cssx
1 parent 9c8bcb4 commit b0c5b0e

19 files changed

Lines changed: 1020 additions & 168 deletions

File tree

packages/babel-plugin-rn-stylename-inline/__tests__/__snapshots__/index.spec.js.snap

Lines changed: 672 additions & 71 deletions
Large diffs are not rendered by default.

packages/babel-plugin-rn-stylename-inline/__tests__/index.spec.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,22 @@ pluginTester({
197197
background-color: green;
198198
}
199199
\`
200+
`,
201+
'Local css interpolation': /* js */`
202+
import React from 'react'
203+
import { css } from 'cssxjs'
204+
import { View } from 'react-native'
205+
206+
export default function Card ({ color, pad }) {
207+
return <View styleName='root' />
208+
209+
css\`
210+
.root {
211+
color: \${color};
212+
padding: \${pad} 2u;
213+
}
214+
\`
215+
}
200216
`
201217
}
202218
})

packages/babel-plugin-rn-stylename-inline/index.js

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,28 @@ const getVisitor = ({ $program, usedCompilers }) => ({
2929
// 0. process only templates which are in usedCompilers (imported from our library)
3030
if (!shouldProcess($this, usedCompilers)) return
3131

32-
// I. validate template
33-
validateTemplate($this)
34-
3532
const compiler = usedCompilers.get($this.node.tag.name)
33+
const { source, expressions } = lowerTemplate($this.node.quasi)
34+
const hasExpressions = expressions.length > 0
35+
36+
// I. find parent function or program
37+
const $function = $this.getFunctionParent()
38+
if (hasExpressions && !$function) {
39+
throw $this.buildCodeFrameError(`
40+
[@cssxjs/babel-plugin-rn-stylename-inline] Expression interpolations are supported only inside function-scoped css\`\` and styl\`\` templates.
41+
`)
42+
}
3643

3744
// II. compile template
38-
const source = $this.node.quasi.quasis[0]?.value?.raw || ''
3945
const filename = state.file?.opts?.filename
4046
const platform = state.opts?.platform || state.file?.opts?.caller?.platform || DEFAULT_PLATFORM
41-
const compiledString = compiler(source, filename, { platform })
47+
const compiledString = compiler(source, filename, {
48+
platform,
49+
template: hasExpressions
50+
})
4251
const compiledExpression = parser.parseExpression(compiledString)
4352

44-
// III. find parent function or program
45-
const $function = $this.getFunctionParent()
46-
47-
// IV. LOCAL. if parent is function -- handle local
53+
// III. LOCAL. if parent is function -- handle local
4854
if ($function) {
4955
// 1. define a `const` variable at the top of the file
5056
// with the unique identifier
@@ -54,14 +60,21 @@ const getVisitor = ({ $program, usedCompilers }) => ({
5460
value: compiledExpression
5561
}))
5662

57-
// 2. reassign this unique identifier to a constant LOCAL_NAME
63+
const localValue = hasExpressions
64+
? t.objectExpression([
65+
t.objectProperty(t.identifier('sheet'), localIdentifier),
66+
t.objectProperty(t.identifier('values'), t.arrayExpression(expressions))
67+
])
68+
: localIdentifier
69+
70+
// 2. reassign this unique identifier or local dynamic layer to a constant LOCAL_NAME
5871
// in the scope of current function
5972
$function.get('body').unshiftContainer('body', buildConst({
6073
variable: t.identifier(LOCAL_NAME),
61-
value: localIdentifier
74+
value: localValue
6275
}))
6376

64-
// V. GLOBAL. if parent is program -- handle global
77+
// IV. GLOBAL. if parent is program -- handle global
6578
} else {
6679
// 1. define a `const` variable at the top of the file
6780
// with the constant GLOBAL_NAME
@@ -71,7 +84,7 @@ const getVisitor = ({ $program, usedCompilers }) => ({
7184
}))
7285
}
7386

74-
// VI. Remove template expression after processing
87+
// V. Remove template expression after processing
7588
$this.remove()
7689

7790
// TODO: Throw error if global styles were already added or
@@ -98,14 +111,19 @@ function shouldProcess ($template, usedCompilers) {
98111
return true
99112
}
100113

101-
function validateTemplate ($template) {
102-
const { node: { quasi } } = $template
114+
function lowerTemplate (quasi) {
115+
let source = ''
116+
const expressions = []
103117

104-
if (quasi.expressions.length > 0) {
105-
throw $template.buildCodeFrameError(`
106-
[@cssxjs/babel-plugin-rn-stylename-inline] Expression interpolations are not supported in css\`\` and styl\`\`.
107-
`)
118+
for (let index = 0; index < quasi.quasis.length; index++) {
119+
source += quasi.quasis[index]?.value?.raw || ''
120+
const expression = quasi.expressions[index]
121+
if (!expression) continue
122+
source += `var(--__cssx_dynamic_${expressions.length})`
123+
expressions.push(expression)
108124
}
125+
126+
return { source, expressions }
109127
}
110128

111129
function getUsedCompilers ($program, state) {

packages/babel-plugin-rn-stylename-inline/package.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
],
1515
"main": "index.js",
1616
"scripts": {
17-
"test": "jest"
17+
"test": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --experimental-vm-modules -C cssx-ts\" jest --runInBand"
1818
},
1919
"author": "Pavel Zhukov",
2020
"license": "MIT",
@@ -33,5 +33,19 @@
3333
"@babel/plugin-syntax-jsx": "^7.0.0",
3434
"babel-plugin-tester": "^9.1.0",
3535
"jest": "^30.0.4"
36+
},
37+
"jest": {
38+
"transform": {
39+
"^.+\\.ts$": "./test/ts-transform.cjs"
40+
},
41+
"testEnvironmentOptions": {
42+
"customExportConditions": [
43+
"cssx-ts",
44+
"node"
45+
]
46+
},
47+
"extensionsToTreatAsEsm": [
48+
".ts"
49+
]
3650
}
3751
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const ts = require('typescript')
2+
3+
module.exports = {
4+
process (sourceText, sourcePath) {
5+
const result = ts.transpileModule(sourceText, {
6+
fileName: sourcePath,
7+
compilerOptions: {
8+
target: ts.ScriptTarget.ES2022,
9+
module: ts.ModuleKind.ESNext,
10+
sourceMap: false,
11+
inlineSourceMap: false,
12+
importsNotUsedAsValues: ts.ImportsNotUsedAsValues.Remove
13+
}
14+
})
15+
return { code: result.outputText }
16+
}
17+
}

packages/babel-plugin-rn-stylename-to-style/__tests__/__snapshots__/index.spec.js.snap

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,12 +1482,12 @@ SyntaxError: unknown file:
14821482
'part' attribute only supports literal or string keys in object.
14831483
Dynamic keys or spreads are not supported.
14841484
1485-
[0m [90m 2 |[39m [36mfunction[39m [33mTest[39m ({ variant }) {
1486-
[90m 3 |[39m [36mreturn[39m (
1487-
[31m[1m>[22m[39m[90m 4 |[39m [33m<[39m[33mCard[39m part[33m=[39m{{[variant][33m:[39m [36mtrue[39m}} [33m/[39m[33m>[39m
1488-
[90m |[39m [31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m
1489-
[90m 5 |[39m )
1490-
[90m 6 |[39m }[0m
1485+
2 | function Test ({ variant }) {
1486+
3 | return (
1487+
> 4 | <Card part={{[variant]: true}} />
1488+
| ^^^^^^^^^^^^^^^
1489+
5 | )
1490+
6 | }
14911491
14921492
`;
14931493
@@ -1505,12 +1505,12 @@ function Test ({ variant }) {
15051505
SyntaxError: unknown file:
15061506
'part' attribute only supports static strings or objects inside an array.
15071507
1508-
[0m [90m 2 |[39m [36mfunction[39m [33mTest[39m ({ variant }) {
1509-
[90m 3 |[39m [36mreturn[39m (
1510-
[31m[1m>[22m[39m[90m 4 |[39m [33m<[39m[33mCard[39m part[33m=[39m{[[32m'card'[39m[33m,[39m variant]} [33m/[39m[33m>[39m
1511-
[90m |[39m [31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m
1512-
[90m 5 |[39m )
1513-
[90m 6 |[39m }[0m
1508+
2 | function Test ({ variant }) {
1509+
3 | return (
1510+
> 4 | <Card part={['card', variant]} />
1511+
| ^^^^^^^
1512+
5 | )
1513+
6 | }
15141514
15151515
`;
15161516
@@ -1533,12 +1533,12 @@ SyntaxError: unknown file:
15331533
Basically the rule is that the name of the part must be static so that
15341534
it is possible to determine at compile time which parts are being used.
15351535
1536-
[0m [90m 2 |[39m [36mfunction[39m [33mTest[39m ({ variant }) {
1537-
[90m 3 |[39m [36mreturn[39m (
1538-
[31m[1m>[22m[39m[90m 4 |[39m [33m<[39m[33mCard[39m part[33m=[39m{variant} [33m/[39m[33m>[39m
1539-
[90m |[39m [31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m
1540-
[90m 5 |[39m )
1541-
[90m 6 |[39m }[0m
1536+
2 | function Test ({ variant }) {
1537+
3 | return (
1538+
> 4 | <Card part={variant} />
1539+
| ^^^^^^^^^^^^^^
1540+
5 | )
1541+
6 | }
15421542
15431543
`;
15441544

packages/css-to-rn/src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ export {
22
compileCss,
33
compileCssTemplate
44
} from './compiler.ts'
5+
export {
6+
cssxHash,
7+
simpleNumericHash
8+
} from './hash.ts'
59
export {
610
resolveCssValue
711
} from './values.ts'

packages/cssxjs/index.d.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,26 @@
11
import type React from 'react'
2+
export {
3+
CssxProvider,
4+
TrackedCssxSheet,
5+
configureCssx,
6+
cssx,
7+
defaultVariables,
8+
isTrackedCssxSheet,
9+
setDefaultVariables,
10+
useCompiledCss,
11+
useCssxConfig,
12+
useCssxSheet,
13+
useCssxTemplate,
14+
variables
15+
} from '@cssxjs/css-to-rn/react'
16+
export type {
17+
CssxProviderProps,
18+
CssxReactConfig,
19+
CssxResolvedProps,
20+
CssxRuntimeOptions,
21+
CssxStyleName,
22+
TrackedCssxSheetOptions
23+
} from '@cssxjs/css-to-rn/react'
224

325
export type CssxjsSimpleValue =
426
| string

packages/cssxjs/index.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1-
export { default as variables } from '@cssxjs/runtime/variables'
2-
export { defaultVariables, setDefaultVariables } from '@cssxjs/runtime/variables'
3-
export { default as dimensions } from '@cssxjs/runtime/dimensions'
4-
export { default as matcher } from '@cssxjs/runtime/matcher'
1+
export {
2+
CssxProvider,
3+
TrackedCssxSheet,
4+
configureCssx,
5+
cssx,
6+
defaultVariables,
7+
isTrackedCssxSheet,
8+
setDefaultVariables,
9+
useCompiledCss,
10+
useCssxConfig,
11+
useCssxSheet,
12+
useCssxTemplate,
13+
variables
14+
} from '@cssxjs/css-to-rn/react'
515

616
export function css (cssString) {
717
throw Error('[cssxjs] Unprocessed \'css\' template string. Bundler (Babel / Metro) did not process this file correctly.')

packages/cssxjs/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"@cssxjs/babel-plugin-rn-stylename-inline": "^0.3.0",
4040
"@cssxjs/babel-plugin-rn-stylename-to-style": "^0.3.0",
4141
"@cssxjs/bundler": "^0.3.0",
42+
"@cssxjs/css-to-rn": "^0.3.0",
4243
"@cssxjs/loaders": "^0.3.0",
4344
"@cssxjs/runtime": "^0.3.0",
4445
"@react-pug/babel-plugin-react-pug": "^0.1.18",

0 commit comments

Comments
 (0)