Update
This commit is contained in:
parent
5cdb5e705a
commit
8010c774cd
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
||||
*.draft
|
||||
*.draft.*
|
||||
src/converts
|
||||
|
||||
# Logs
|
||||
logs
|
||||
|
12
package.json
12
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@aet/babel-tailwind",
|
||||
"version": "0.0.1-beta.8",
|
||||
"name": "@aet/tailwind",
|
||||
"version": "0.0.1-beta.5",
|
||||
"main": "dist/index.js",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
@ -12,9 +12,9 @@
|
||||
"dist"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@aet/eslint-rules": "^0.0.22",
|
||||
"@aet/eslint-rules": "^0.0.25",
|
||||
"@types/babel__core": "^7.20.5",
|
||||
"@types/bun": "^1.0.12",
|
||||
"@types/bun": "^1.1.0",
|
||||
"@types/dedent": "^0.7.2",
|
||||
"@types/lodash": "^4.17.0",
|
||||
"@types/node": "^20.12.7",
|
||||
@ -32,8 +32,8 @@
|
||||
"tailwindcss": "^3.4.3",
|
||||
"tsup": "^8.0.2",
|
||||
"typescript": "^5.4.5",
|
||||
"vite": "^5.2.8",
|
||||
"vitest": "^1.4.0"
|
||||
"vite": "^5.2.10",
|
||||
"vitest": "^1.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"tailwindcss": "^3.4.3"
|
||||
|
195
pnpm-lock.yaml
generated
195
pnpm-lock.yaml
generated
@ -20,14 +20,14 @@ dependencies:
|
||||
|
||||
devDependencies:
|
||||
'@aet/eslint-rules':
|
||||
specifier: ^0.0.22
|
||||
version: 0.0.22(eslint@8.57.0)(typescript@5.4.5)
|
||||
specifier: ^0.0.25
|
||||
version: 0.0.25(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@types/babel__core':
|
||||
specifier: ^7.20.5
|
||||
version: 7.20.5
|
||||
'@types/bun':
|
||||
specifier: ^1.0.12
|
||||
version: 1.0.12
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0
|
||||
'@types/dedent':
|
||||
specifier: ^0.7.2
|
||||
version: 0.7.2
|
||||
@ -80,11 +80,11 @@ devDependencies:
|
||||
specifier: ^5.4.5
|
||||
version: 5.4.5
|
||||
vite:
|
||||
specifier: ^5.2.8
|
||||
version: 5.2.8(@types/node@20.12.7)
|
||||
specifier: ^5.2.10
|
||||
version: 5.2.10(@types/node@20.12.7)
|
||||
vitest:
|
||||
specifier: ^1.4.0
|
||||
version: 1.4.0(@types/node@20.12.7)
|
||||
specifier: ^1.5.0
|
||||
version: 1.5.0(@types/node@20.12.7)
|
||||
|
||||
packages:
|
||||
|
||||
@ -93,18 +93,18 @@ packages:
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/@aet/eslint-rules@0.0.22(eslint@8.57.0)(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-PLAnaYlb6GdG6gKjQP5B8XckOa7driZL1rbw51wGTYTl/0Etqu5R/u4TkQSYePZab7xCIrJuPSC3PsBEhI5pvQ==}
|
||||
/@aet/eslint-rules@0.0.25(eslint@8.57.0)(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-6F6iSb5Oc8DAqUVIPzXMQuAgzPceowZMh/lGfV++sk9t36nVefy+8UDWoDixVyHjoAbGPWjV4xx1EHi2xawk9g==}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0
|
||||
typescript: ^5.4.4
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
|
||||
'@types/eslint': 8.56.7
|
||||
'@typescript-eslint/eslint-plugin': 7.5.0(@typescript-eslint/parser@7.5.0)(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/parser': 7.5.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/type-utils': 7.5.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/utils': 7.5.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@types/eslint': 8.56.10
|
||||
'@typescript-eslint/eslint-plugin': 7.7.0(@typescript-eslint/parser@7.7.0)(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/parser': 7.7.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/type-utils': 7.7.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/utils': 7.7.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
aria-query: 5.3.0
|
||||
axe-core: 4.9.0
|
||||
axobject-query: 4.0.0
|
||||
@ -117,10 +117,12 @@ packages:
|
||||
eslint-config-prettier: 9.1.0(eslint@8.57.0)
|
||||
eslint-define-config: 1.24.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.5.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0)
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.7.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0)
|
||||
eslint-plugin-es-x: 7.6.0(eslint@8.57.0)
|
||||
eslint-plugin-jsdoc: 48.2.3(eslint@8.57.0)
|
||||
eslint-plugin-unicorn: 52.0.0(eslint@8.57.0)
|
||||
esprima: 4.0.1
|
||||
esquery: 1.5.0
|
||||
estraverse: 5.3.0
|
||||
fast-glob: 3.3.2
|
||||
get-tsconfig: 4.7.3
|
||||
@ -1057,18 +1059,18 @@ packages:
|
||||
'@babel/types': 7.24.0
|
||||
dev: true
|
||||
|
||||
/@types/bun@1.0.12:
|
||||
resolution: {integrity: sha512-qPb5FcygbpSS1NDBjWyQCWeI9kKXwSYSR1Enu7yb+gMXgFwGMhlyOvgV/7FGrdvAjlSXWRY6IDepos7k8WzAtQ==}
|
||||
/@types/bun@1.1.0:
|
||||
resolution: {integrity: sha512-QGK0yU4jh0OK1A7DyhPkQuKjHQCC5jSJa3dpWIEhHv/rPfb6zLfdArc4/uUUZBMTcjilsafRXnPWO+1owb572Q==}
|
||||
dependencies:
|
||||
bun-types: 1.0.36
|
||||
bun-types: 1.1.0
|
||||
dev: true
|
||||
|
||||
/@types/dedent@0.7.2:
|
||||
resolution: {integrity: sha512-kRiitIeUg1mPV9yH4VUJ/1uk2XjyANfeL8/7rH1tsjvHeO9PJLBHJIYsFWmAvmGj5u8rj+1TZx7PZzW2qLw3Lw==}
|
||||
dev: true
|
||||
|
||||
/@types/eslint@8.56.7:
|
||||
resolution: {integrity: sha512-SjDvI/x3zsZnOkYZ3lCt9lOZWZLB2jIlNKz+LBgCtDurK0JZcwucxYHn1w2BJkD34dgX9Tjnak0txtq4WTggEA==}
|
||||
/@types/eslint@8.56.10:
|
||||
resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==}
|
||||
dependencies:
|
||||
'@types/estree': 1.0.5
|
||||
'@types/json-schema': 7.0.15
|
||||
@ -1118,8 +1120,8 @@ packages:
|
||||
'@types/node': 20.12.7
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/eslint-plugin@7.5.0(@typescript-eslint/parser@7.5.0)(eslint@8.57.0)(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==}
|
||||
/@typescript-eslint/eslint-plugin@7.7.0(@typescript-eslint/parser@7.7.0)(eslint@8.57.0)(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': ^7.0.0
|
||||
@ -1130,11 +1132,11 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.10.0
|
||||
'@typescript-eslint/parser': 7.5.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/scope-manager': 7.5.0
|
||||
'@typescript-eslint/type-utils': 7.5.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/utils': 7.5.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/visitor-keys': 7.5.0
|
||||
'@typescript-eslint/parser': 7.7.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/scope-manager': 7.7.0
|
||||
'@typescript-eslint/type-utils': 7.7.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/utils': 7.7.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/visitor-keys': 7.7.0
|
||||
debug: 4.3.4
|
||||
eslint: 8.57.0
|
||||
graphemer: 1.4.0
|
||||
@ -1147,8 +1149,8 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/parser@7.5.0(eslint@8.57.0)(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==}
|
||||
/@typescript-eslint/parser@7.7.0(eslint@8.57.0)(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.56.0
|
||||
@ -1157,10 +1159,10 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 7.5.0
|
||||
'@typescript-eslint/types': 7.5.0
|
||||
'@typescript-eslint/typescript-estree': 7.5.0(typescript@5.4.5)
|
||||
'@typescript-eslint/visitor-keys': 7.5.0
|
||||
'@typescript-eslint/scope-manager': 7.7.0
|
||||
'@typescript-eslint/types': 7.7.0
|
||||
'@typescript-eslint/typescript-estree': 7.7.0(typescript@5.4.5)
|
||||
'@typescript-eslint/visitor-keys': 7.7.0
|
||||
debug: 4.3.4
|
||||
eslint: 8.57.0
|
||||
typescript: 5.4.5
|
||||
@ -1168,16 +1170,16 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/scope-manager@7.5.0:
|
||||
resolution: {integrity: sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==}
|
||||
/@typescript-eslint/scope-manager@7.7.0:
|
||||
resolution: {integrity: sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 7.5.0
|
||||
'@typescript-eslint/visitor-keys': 7.5.0
|
||||
'@typescript-eslint/types': 7.7.0
|
||||
'@typescript-eslint/visitor-keys': 7.7.0
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/type-utils@7.5.0(eslint@8.57.0)(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==}
|
||||
/@typescript-eslint/type-utils@7.7.0(eslint@8.57.0)(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.56.0
|
||||
@ -1186,8 +1188,8 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 7.5.0(typescript@5.4.5)
|
||||
'@typescript-eslint/utils': 7.5.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/typescript-estree': 7.7.0(typescript@5.4.5)
|
||||
'@typescript-eslint/utils': 7.7.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
debug: 4.3.4
|
||||
eslint: 8.57.0
|
||||
ts-api-utils: 1.3.0(typescript@5.4.5)
|
||||
@ -1196,13 +1198,13 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/types@7.5.0:
|
||||
resolution: {integrity: sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==}
|
||||
/@typescript-eslint/types@7.7.0:
|
||||
resolution: {integrity: sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/typescript-estree@7.5.0(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==}
|
||||
/@typescript-eslint/typescript-estree@7.7.0(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
typescript: '*'
|
||||
@ -1210,12 +1212,12 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 7.5.0
|
||||
'@typescript-eslint/visitor-keys': 7.5.0
|
||||
'@typescript-eslint/types': 7.7.0
|
||||
'@typescript-eslint/visitor-keys': 7.7.0
|
||||
debug: 4.3.4
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.3
|
||||
minimatch: 9.0.4
|
||||
semver: 7.6.0
|
||||
ts-api-utils: 1.3.0(typescript@5.4.5)
|
||||
typescript: 5.4.5
|
||||
@ -1223,8 +1225,8 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/utils@7.5.0(eslint@8.57.0)(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==}
|
||||
/@typescript-eslint/utils@7.7.0(eslint@8.57.0)(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.56.0
|
||||
@ -1232,9 +1234,9 @@ packages:
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
|
||||
'@types/json-schema': 7.0.15
|
||||
'@types/semver': 7.5.8
|
||||
'@typescript-eslint/scope-manager': 7.5.0
|
||||
'@typescript-eslint/types': 7.5.0
|
||||
'@typescript-eslint/typescript-estree': 7.5.0(typescript@5.4.5)
|
||||
'@typescript-eslint/scope-manager': 7.7.0
|
||||
'@typescript-eslint/types': 7.7.0
|
||||
'@typescript-eslint/typescript-estree': 7.7.0(typescript@5.4.5)
|
||||
eslint: 8.57.0
|
||||
semver: 7.6.0
|
||||
transitivePeerDependencies:
|
||||
@ -1242,11 +1244,11 @@ packages:
|
||||
- typescript
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/visitor-keys@7.5.0:
|
||||
resolution: {integrity: sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==}
|
||||
/@typescript-eslint/visitor-keys@7.7.0:
|
||||
resolution: {integrity: sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 7.5.0
|
||||
'@typescript-eslint/types': 7.7.0
|
||||
eslint-visitor-keys: 3.4.3
|
||||
dev: true
|
||||
|
||||
@ -1254,38 +1256,38 @@ packages:
|
||||
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
|
||||
dev: true
|
||||
|
||||
/@vitest/expect@1.4.0:
|
||||
resolution: {integrity: sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==}
|
||||
/@vitest/expect@1.5.0:
|
||||
resolution: {integrity: sha512-0pzuCI6KYi2SIC3LQezmxujU9RK/vwC1U9R0rLuGlNGcOuDWxqWKu6nUdFsX9tH1WU0SXtAxToOsEjeUn1s3hA==}
|
||||
dependencies:
|
||||
'@vitest/spy': 1.4.0
|
||||
'@vitest/utils': 1.4.0
|
||||
'@vitest/spy': 1.5.0
|
||||
'@vitest/utils': 1.5.0
|
||||
chai: 4.4.1
|
||||
dev: true
|
||||
|
||||
/@vitest/runner@1.4.0:
|
||||
resolution: {integrity: sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==}
|
||||
/@vitest/runner@1.5.0:
|
||||
resolution: {integrity: sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==}
|
||||
dependencies:
|
||||
'@vitest/utils': 1.4.0
|
||||
'@vitest/utils': 1.5.0
|
||||
p-limit: 5.0.0
|
||||
pathe: 1.1.2
|
||||
dev: true
|
||||
|
||||
/@vitest/snapshot@1.4.0:
|
||||
resolution: {integrity: sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==}
|
||||
/@vitest/snapshot@1.5.0:
|
||||
resolution: {integrity: sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==}
|
||||
dependencies:
|
||||
magic-string: 0.30.8
|
||||
pathe: 1.1.2
|
||||
pretty-format: 29.7.0
|
||||
dev: true
|
||||
|
||||
/@vitest/spy@1.4.0:
|
||||
resolution: {integrity: sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==}
|
||||
/@vitest/spy@1.5.0:
|
||||
resolution: {integrity: sha512-vu6vi6ew5N5MMHJjD5PoakMRKYdmIrNJmyfkhRpQt5d9Ewhw9nZ5Aqynbi3N61bvk9UvZ5UysMT6ayIrZ8GA9w==}
|
||||
dependencies:
|
||||
tinyspy: 2.2.1
|
||||
dev: true
|
||||
|
||||
/@vitest/utils@1.4.0:
|
||||
resolution: {integrity: sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==}
|
||||
/@vitest/utils@1.5.0:
|
||||
resolution: {integrity: sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==}
|
||||
dependencies:
|
||||
diff-sequences: 29.6.3
|
||||
estree-walker: 3.0.3
|
||||
@ -1449,8 +1451,8 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/bun-types@1.0.36:
|
||||
resolution: {integrity: sha512-gaIb1SyhB0JZfIEg73/kSFhqolUqJXC68peguhXGwqr27HuvI8nkD0LTIHp/1DY4cNadfXHYgYrZIWX7oEoXlg==}
|
||||
/bun-types@1.1.0:
|
||||
resolution: {integrity: sha512-GhMDD7TosdJzQPGUOcQD5PZshvXVxDfwGAZs2dq+eSaPsRn3iUCzvpFlsg7Q51bXVzLAUs+FWHlnmpgZ5UggIg==}
|
||||
dependencies:
|
||||
'@types/node': 20.11.30
|
||||
'@types/ws': 8.5.10
|
||||
@ -1865,7 +1867,7 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-module-utils@2.8.1(@typescript-eslint/parser@7.5.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0):
|
||||
/eslint-module-utils@2.8.1(@typescript-eslint/parser@7.7.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0):
|
||||
resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
@ -1886,7 +1888,7 @@ packages:
|
||||
eslint-import-resolver-webpack:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 7.5.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/parser': 7.7.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
debug: 3.2.7
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
@ -2022,6 +2024,12 @@ packages:
|
||||
eslint-visitor-keys: 3.4.3
|
||||
dev: true
|
||||
|
||||
/esprima@4.0.1:
|
||||
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/esquery@1.5.0:
|
||||
resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
|
||||
engines: {node: '>=0.10'}
|
||||
@ -2636,13 +2644,6 @@ packages:
|
||||
brace-expansion: 1.1.11
|
||||
dev: true
|
||||
|
||||
/minimatch@9.0.3:
|
||||
resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
dev: true
|
||||
|
||||
/minimatch@9.0.4:
|
||||
resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
@ -3555,8 +3556,8 @@ packages:
|
||||
spdx-expression-parse: 3.0.1
|
||||
dev: true
|
||||
|
||||
/vite-node@1.4.0(@types/node@20.12.7):
|
||||
resolution: {integrity: sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==}
|
||||
/vite-node@1.5.0(@types/node@20.12.7):
|
||||
resolution: {integrity: sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
@ -3564,7 +3565,7 @@ packages:
|
||||
debug: 4.3.4
|
||||
pathe: 1.1.2
|
||||
picocolors: 1.0.0
|
||||
vite: 5.2.8(@types/node@20.12.7)
|
||||
vite: 5.2.10(@types/node@20.12.7)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- less
|
||||
@ -3576,8 +3577,8 @@ packages:
|
||||
- terser
|
||||
dev: true
|
||||
|
||||
/vite@5.2.8(@types/node@20.12.7):
|
||||
resolution: {integrity: sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==}
|
||||
/vite@5.2.10(@types/node@20.12.7):
|
||||
resolution: {integrity: sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@ -3612,15 +3613,15 @@ packages:
|
||||
fsevents: 2.3.3
|
||||
dev: true
|
||||
|
||||
/vitest@1.4.0(@types/node@20.12.7):
|
||||
resolution: {integrity: sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==}
|
||||
/vitest@1.5.0(@types/node@20.12.7):
|
||||
resolution: {integrity: sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@edge-runtime/vm': '*'
|
||||
'@types/node': ^18.0.0 || >=20.0.0
|
||||
'@vitest/browser': 1.4.0
|
||||
'@vitest/ui': 1.4.0
|
||||
'@vitest/browser': 1.5.0
|
||||
'@vitest/ui': 1.5.0
|
||||
happy-dom: '*'
|
||||
jsdom: '*'
|
||||
peerDependenciesMeta:
|
||||
@ -3638,11 +3639,11 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/node': 20.12.7
|
||||
'@vitest/expect': 1.4.0
|
||||
'@vitest/runner': 1.4.0
|
||||
'@vitest/snapshot': 1.4.0
|
||||
'@vitest/spy': 1.4.0
|
||||
'@vitest/utils': 1.4.0
|
||||
'@vitest/expect': 1.5.0
|
||||
'@vitest/runner': 1.5.0
|
||||
'@vitest/snapshot': 1.5.0
|
||||
'@vitest/spy': 1.5.0
|
||||
'@vitest/utils': 1.5.0
|
||||
acorn-walk: 8.3.2
|
||||
chai: 4.4.1
|
||||
debug: 4.3.4
|
||||
@ -3655,8 +3656,8 @@ packages:
|
||||
strip-literal: 2.1.0
|
||||
tinybench: 2.6.0
|
||||
tinypool: 0.8.3
|
||||
vite: 5.2.8(@types/node@20.12.7)
|
||||
vite-node: 1.4.0(@types/node@20.12.7)
|
||||
vite: 5.2.10(@types/node@20.12.7)
|
||||
vite-node: 1.5.0(@types/node@20.12.7)
|
||||
why-is-node-running: 2.2.2
|
||||
transitivePeerDependencies:
|
||||
- less
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { basename, dirname, extname, join } from "node:path";
|
||||
import type babel from "@babel/core";
|
||||
import { type NodePath, type types as t } from "@babel/core";
|
||||
import type { SourceLocation, StyleMap, StyleMapEntry } from "./shared";
|
||||
import { type TailwindPluginOptions, getClassName } from "./index";
|
||||
import type { SourceLocation, StyleMapEntry } from "./shared";
|
||||
import { type ResolveTailwindOptions, getClassName } from "./index";
|
||||
|
||||
const definePlugin =
|
||||
<T>(fn: (runtime: typeof babel) => babel.Visitor<babel.PluginPass & T>) =>
|
||||
@ -32,15 +32,18 @@ interface BabelPluginState {
|
||||
tailwindMap: Map<string, StyleMapEntry>;
|
||||
}
|
||||
|
||||
export type ClassNameCollector = (path: string, entries: StyleMapEntry[]) => void;
|
||||
|
||||
export function babelTailwind(
|
||||
styleMap: StyleMap,
|
||||
{
|
||||
styleMap,
|
||||
clsx,
|
||||
getClassName: getClass = getClassName,
|
||||
taggedTemplateName,
|
||||
jsxAttributeAction = "delete",
|
||||
jsxAttributeName = "css",
|
||||
}: TailwindPluginOptions
|
||||
}: ResolveTailwindOptions,
|
||||
onCollect: ClassNameCollector | undefined
|
||||
) {
|
||||
function getClsxImport(t: typeof babel.types, cx: t.Identifier) {
|
||||
switch (clsx) {
|
||||
@ -103,7 +106,10 @@ export function babelTailwind(
|
||||
t.importDeclaration([], t.stringLiteral(`tailwind:./${cssName}`))
|
||||
);
|
||||
|
||||
styleMap.set(join(dirname(filename), cssName), Array.from(tailwindMap.values()));
|
||||
const path = join(dirname(filename), cssName);
|
||||
const value = Array.from(tailwindMap.values());
|
||||
styleMap.set(path, value);
|
||||
onCollect?.(path, value);
|
||||
},
|
||||
},
|
||||
|
||||
@ -185,18 +191,24 @@ export function babelTailwind(
|
||||
|
||||
if (classNameAttribute) {
|
||||
const attrValue = classNameAttribute.value!;
|
||||
const valuePathNode = valuePath.node;
|
||||
const wrap = (originalValue: babel.types.Expression) =>
|
||||
t.callExpression(getCx(), [originalValue, extractJSXContainer(valuePathNode)]);
|
||||
|
||||
// If both are string literals, we can merge them directly here
|
||||
if (t.isStringLiteral(attrValue) && t.isStringLiteral(valuePath.node)) {
|
||||
if (t.isStringLiteral(attrValue) && t.isStringLiteral(valuePathNode)) {
|
||||
attrValue.value +=
|
||||
(attrValue.value.at(-1) === " " ? "" : " ") + valuePath.node.value;
|
||||
(attrValue.value.at(-1) === " " ? "" : " ") + valuePathNode.value;
|
||||
} else {
|
||||
classNameAttribute.value = t.jsxExpressionContainer(
|
||||
t.callExpression(getCx(), [
|
||||
extractJSXContainer(attrValue),
|
||||
extractJSXContainer(valuePath.node),
|
||||
])
|
||||
);
|
||||
const internalAttrValue = extractJSXContainer(attrValue);
|
||||
if (
|
||||
t.isArrowFunctionExpression(internalAttrValue) &&
|
||||
!t.isBlockStatement(internalAttrValue.body)
|
||||
) {
|
||||
internalAttrValue.body = wrap(internalAttrValue.body);
|
||||
} else {
|
||||
classNameAttribute.value = t.jsxExpressionContainer(wrap(internalAttrValue));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parent.attributes.push(
|
||||
|
@ -1,129 +0,0 @@
|
||||
import { type AtRule, type ChildNode, type Node, Rule } from "postcss";
|
||||
import { isAtRuleNode, isChildNode } from "./utils";
|
||||
|
||||
export interface ResolvedTailwindNode {
|
||||
rule: Rule;
|
||||
tailwindClasses: string[];
|
||||
}
|
||||
|
||||
interface UnresolvedTailwindNode {
|
||||
key: string;
|
||||
rootRuleSelector?: string | null;
|
||||
originalRule: Rule;
|
||||
classesPrefix: string;
|
||||
tailwindClasses: string[];
|
||||
}
|
||||
|
||||
export type TailwindNode = ResolvedTailwindNode | UnresolvedTailwindNode;
|
||||
|
||||
function isResolvedTailwindNode(node: TailwindNode): node is ResolvedTailwindNode {
|
||||
return "rule" in node;
|
||||
}
|
||||
|
||||
export class TailwindNodesManager {
|
||||
protected nodesMap: Map<string, ResolvedTailwindNode>;
|
||||
|
||||
constructor(initialNodes?: TailwindNode[]) {
|
||||
this.nodesMap = new Map();
|
||||
if (initialNodes?.length) {
|
||||
this.mergeNodes(initialNodes);
|
||||
}
|
||||
}
|
||||
|
||||
mergeNode(node: TailwindNode) {
|
||||
const nodeIsResolved = isResolvedTailwindNode(node);
|
||||
const nodeKey = nodeIsResolved
|
||||
? TailwindNodesManager.convertRuleToKey(node.rule)
|
||||
: node.key;
|
||||
const foundNode = this.nodesMap.get(nodeKey);
|
||||
|
||||
if (foundNode) {
|
||||
foundNode.tailwindClasses = foundNode.tailwindClasses.concat(
|
||||
nodeIsResolved
|
||||
? node.tailwindClasses
|
||||
: node.tailwindClasses.map(className => `${node.classesPrefix}${className}`)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodeIsResolved) {
|
||||
this.nodesMap.set(nodeKey, node);
|
||||
} else {
|
||||
let rule;
|
||||
|
||||
if (node.rootRuleSelector) {
|
||||
rule = new Rule({
|
||||
selector: node.rootRuleSelector,
|
||||
});
|
||||
|
||||
const rootChild = this.upToRootChild(node.originalRule);
|
||||
if (rootChild) {
|
||||
node.originalRule.root().insertBefore(rootChild, rule);
|
||||
}
|
||||
} else {
|
||||
rule = node.originalRule;
|
||||
}
|
||||
|
||||
this.nodesMap.set(nodeKey, {
|
||||
rule,
|
||||
tailwindClasses: node.tailwindClasses.map(
|
||||
className => `${node.classesPrefix}${className}`
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
mergeNodes(nodes: TailwindNode[]) {
|
||||
for (const node of nodes) {
|
||||
this.mergeNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
hasNode(key: string) {
|
||||
return this.nodesMap.has(key);
|
||||
}
|
||||
|
||||
getNode(key: string) {
|
||||
return this.nodesMap.get(key) || null;
|
||||
}
|
||||
|
||||
getNodes() {
|
||||
return Array.from(this.nodesMap.values());
|
||||
}
|
||||
|
||||
protected upToRootChild(node: Node) {
|
||||
let childNode: ChildNode | null = null;
|
||||
|
||||
while (node.parent && node.parent.type !== "root" && isChildNode(node.parent)) {
|
||||
childNode = node = node.parent;
|
||||
continue;
|
||||
}
|
||||
|
||||
return childNode;
|
||||
}
|
||||
|
||||
static convertRuleToKey(rule: Rule, overriddenSelector: string | null = null) {
|
||||
let currentParent = rule.parent;
|
||||
let parentKey = "";
|
||||
|
||||
while (isChildNode(currentParent)) {
|
||||
parentKey +=
|
||||
(isAtRuleNode(currentParent)
|
||||
? this.makeSingleAtRuleKey(currentParent)
|
||||
: this.makeSingleRuleKey(currentParent)) + "__";
|
||||
|
||||
currentParent = currentParent.parent;
|
||||
}
|
||||
|
||||
return parentKey + (overriddenSelector == null ? rule.selector : overriddenSelector);
|
||||
}
|
||||
|
||||
protected static makeSingleAtRuleKey(atRule: AtRule) {
|
||||
return `a(${atRule.name}|${atRule.params})`;
|
||||
}
|
||||
|
||||
protected static makeSingleRuleKey(atRule: Rule) {
|
||||
return `r(${atRule.selector})`;
|
||||
}
|
||||
}
|
@ -1,230 +0,0 @@
|
||||
# Convert CSS to TailwindCSS 3.x
|
||||
|
||||
[![npm package][npm-img]][npm-url]
|
||||
[![Build Status][build-img]][build-url]
|
||||
[![Downloads][downloads-img]][downloads-url]
|
||||
[![Issues][issues-img]][issues-url]
|
||||
[![Semantic Release][semantic-release-img]][semantic-release-url]
|
||||
|
||||
> Convert your CSS to TailwindCSS 3.x respecting TailwindCSS configuration
|
||||
|
||||
**[🔗 Demo](https://transform.tools/css-to-tailwind)**
|
||||
|
||||
**[🔗 VS Code Extension already available 🎉](https://github.com/Jackardios/vscode-css-to-tailwindcss)**
|
||||
|
||||

|
||||
|
||||
## Features:
|
||||
|
||||
- supports almost all the features (except custom plugins) currently available in TailwindCSS
|
||||
- the ability to set your own TailwindCSS configuration
|
||||
- colors are matched regardless of the format used
|
||||
- rem is converted to px (it is possible to configure the rem size)
|
||||
- non-convertible CSS declarations are simply skipped
|
||||
- [ambiguities](https://tailwindcss.com/docs/adding-custom-styles#resolving-ambiguities) when using css variables are resolved automatically
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install css-to-tailwindcss
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { TailwindConverter } from 'css-to-tailwindcss';
|
||||
|
||||
const converter = new TailwindConverter({
|
||||
remInPx: 16, // set null if you don't want to convert rem to pixels
|
||||
postCSSPlugins: [require('postcss-nested')], // add any postcss plugins to this array
|
||||
tailwindConfig: {
|
||||
// your tailwind config here
|
||||
content: [],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
'custom-color': {
|
||||
100: '#123456',
|
||||
200: 'hsla(210, 100%, 51.0%, 0.016)',
|
||||
300: '#654321',
|
||||
gold: 'hsl(41, 28.3%, 79.8%)',
|
||||
marine: 'rgb(4, 55, 242, 0.75)',
|
||||
},
|
||||
},
|
||||
screens: {
|
||||
'custom-screen': { min: '768px', max: '1024px' },
|
||||
},
|
||||
},
|
||||
supports: {
|
||||
grid: 'display: grid',
|
||||
flex: 'display: flex',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const inputCSS = `
|
||||
:root {
|
||||
--some-color: #090909;
|
||||
}
|
||||
|
||||
.foo {
|
||||
padding: 0.875em 256px;
|
||||
margin-left: 16px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
transition: color, background-color, border-color, text-decoration-color, fill,
|
||||
stroke 200ms cubic-bezier(0, 0, 0.2, 1);
|
||||
animation-delay: 200ms;
|
||||
|
||||
&:hover {
|
||||
filter: blur(4px) brightness(0.5) sepia(100%) contrast(1) hue-rotate(30deg)
|
||||
invert(0) opacity(0.05) saturate(1.5);
|
||||
color: hsl(41, 28.3%, 79.8%);
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
&[aria-disabled="true"] {
|
||||
width: 25%;
|
||||
color: var(--some-color);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
top: auto;
|
||||
bottom: auto;
|
||||
left: 25%;
|
||||
right: 25%;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 1024px) {
|
||||
min-width: 100%;
|
||||
margin-right: -24px;
|
||||
}
|
||||
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
grid-column: span 1 / span 1;
|
||||
}
|
||||
}
|
||||
|
||||
.foo.bar {
|
||||
padding: 0.875rem 256px 15%;
|
||||
transform: translateX(12px) translateY(-0.5em) skew(1deg, 3deg)
|
||||
scale(-0.75, 1.05) rotate(-0.25turn);
|
||||
|
||||
&::after {
|
||||
content: "*";
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
converter.convertCSS(inputCSS).then(({ convertedRoot, nodes }) => {
|
||||
console.log(convertedRoot.toString());
|
||||
console.log(nodes);
|
||||
});
|
||||
```
|
||||
|
||||
Console output
|
||||
|
||||
`convertedRoot.toString()`:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--some-color: #090909;
|
||||
}
|
||||
|
||||
.foo {
|
||||
@apply text-center text-xs transition-colors duration-200 ease-out ml-4 px-64 py-[0.875em] hover:blur-sm hover:brightness-50 hover:sepia hover:contrast-100 hover:hue-rotate-30 hover:invert-0 hover:opacity-5 hover:saturate-150 hover:text-custom-color-gold hover:text-xl disabled:w-3/12 disabled:text-[color:var(--some-color)] disabled:text-[1em] md:inset-x-1/4 md:inset-y-auto custom-screen:min-w-full custom-screen:-mr-6 supports-grid:grid supports-grid:col-span-1;
|
||||
animation-delay: 200ms;
|
||||
}
|
||||
|
||||
.foo.bar {
|
||||
@apply translate-x-3 translate-y-[-0.5em] skew-x-1 skew-y-3 rotate-[-0.25turn] pt-3.5 pb-[15%] px-64 -scale-x-75 scale-y-105 after:content-["*"] after:animate-spin;
|
||||
}
|
||||
```
|
||||
|
||||
`nodes`:
|
||||
|
||||
```js
|
||||
[
|
||||
{
|
||||
rule: {
|
||||
selector: '.foo',
|
||||
// ...
|
||||
},
|
||||
tailwindClasses: [
|
||||
'text-center',
|
||||
'text-xs',
|
||||
'transition-colors',
|
||||
'duration-200',
|
||||
'ease-out',
|
||||
'ml-4',
|
||||
'px-64',
|
||||
'py-[0.875em]',
|
||||
'hover:blur-sm',
|
||||
'hover:brightness-50',
|
||||
'hover:sepia',
|
||||
'hover:contrast-100',
|
||||
'hover:hue-rotate-30',
|
||||
'hover:invert-0',
|
||||
'hover:opacity-5',
|
||||
'hover:saturate-150',
|
||||
'hover:text-custom-color-gold',
|
||||
'hover:text-xl',
|
||||
'disabled:w-3/12',
|
||||
'disabled:text-[color:var(--some-color)]',
|
||||
'disabled:text-[1em]',
|
||||
'md:inset-x-1/4',
|
||||
'md:inset-y-auto',
|
||||
'custom-screen:min-w-full',
|
||||
'custom-screen:-mr-6',
|
||||
'supports-grid:grid',
|
||||
'supports-grid:col-span-1',
|
||||
],
|
||||
},
|
||||
{
|
||||
rule: {
|
||||
selector: '.foo.bar',
|
||||
// ...
|
||||
},
|
||||
tailwindClasses: [
|
||||
'translate-x-3',
|
||||
'translate-y-[-0.5em]',
|
||||
'skew-x-1',
|
||||
'skew-y-3',
|
||||
'rotate-[-0.25turn]',
|
||||
'pt-3.5',
|
||||
'pb-[15%]',
|
||||
'px-64',
|
||||
'-scale-x-75',
|
||||
'scale-y-105',
|
||||
'after:content-["*"]',
|
||||
'after:animate-spin',
|
||||
],
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### TailwindConverter(options?)
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
| ---------------------------- | ------------------ | ------- | ---------------------------------------------------------------------------------------- |
|
||||
| remInPx | `number` \| `null` | `null` | `rem` in `px` unit. Set null if you don't want to convert rem to pixels |
|
||||
| arbitraryPropertiesIsEnabled | `boolean` | `false` | defines whether non-convertible properties should be converted as "arbitrary properties" |
|
||||
| tailwindConfig | `Config` | {} | Set your tailwind config here |
|
||||
| postCSSPlugins | `AcceptedPlugin[]` | [] | Array of acceptable postcss plugins |
|
||||
|
||||
[build-img]: https://github.com/jackardios/css-to-tailwindcss/actions/workflows/release.yml/badge.svg
|
||||
[build-url]: https://github.com/jackardios/css-to-tailwindcss/actions/workflows/release.yml
|
||||
[downloads-img]: https://img.shields.io/npm/dt/css-to-tailwindcss
|
||||
[downloads-url]: https://www.npmtrends.com/css-to-tailwindcss
|
||||
[npm-img]: https://img.shields.io/npm/v/css-to-tailwindcss
|
||||
[npm-url]: https://www.npmjs.com/package/css-to-tailwindcss
|
||||
[issues-img]: https://img.shields.io/github/issues/jackardios/css-to-tailwindcss
|
||||
[issues-url]: https://github.com/jackardios/css-to-tailwindcss/issues
|
||||
[semantic-release-img]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
|
||||
[semantic-release-url]: https://github.com/semantic-release/semantic-release
|
@ -1,405 +0,0 @@
|
||||
import {
|
||||
type AttributeSelector,
|
||||
type Selector,
|
||||
isTraversal,
|
||||
parse,
|
||||
stringify,
|
||||
} from "css-what";
|
||||
import type { Config } from "tailwindcss";
|
||||
import type { Expand } from "tailwindcss/types/config";
|
||||
import type { CorePluginList } from "tailwindcss/types/generated/corePluginList";
|
||||
import baseResolveConfig from "tailwindcss/resolveConfig";
|
||||
import postcss, { AtRule } from "postcss";
|
||||
import type {
|
||||
AcceptedPlugin,
|
||||
Container,
|
||||
Declaration,
|
||||
Document,
|
||||
Root,
|
||||
Rule,
|
||||
} from "postcss";
|
||||
import postcssSafeParser from "postcss-safe-parser";
|
||||
import type { ConverterMapping } from "./types";
|
||||
import { type TailwindNode, TailwindNodesManager } from "./NodesManager";
|
||||
import {
|
||||
detectIndent,
|
||||
isAtRuleNode,
|
||||
isChildNode,
|
||||
removeUnnecessarySpaces,
|
||||
} from "./utils";
|
||||
import {
|
||||
converterMappingByTailwindTheme,
|
||||
normalizeAtRuleParams,
|
||||
} from "./utils/converterMappingByTailwindTheme";
|
||||
import {
|
||||
DECLARATION_CONVERTERS_MAPPING,
|
||||
convertDeclarationValue,
|
||||
prepareArbitraryValue,
|
||||
} from "./mappings/declaration-converters-mapping";
|
||||
import MEDIA_PARAMS_MAPPING from "./mappings/media-params-mapping.json";
|
||||
import PSEUDOS_MAPPING from "./mappings/pseudos-mapping.json";
|
||||
import { reduceTailwindClasses } from "./utils/reduceTailwindClasses";
|
||||
|
||||
export interface TailwindConverterConfig {
|
||||
remInPx?: number | null;
|
||||
tailwindConfig?: Config;
|
||||
postCSSPlugins: AcceptedPlugin[];
|
||||
arbitraryPropertiesIsEnabled: boolean;
|
||||
}
|
||||
|
||||
export const DEFAULT_CONVERTER_CONFIG: Omit<TailwindConverterConfig, "tailwindConfig"> = {
|
||||
postCSSPlugins: [],
|
||||
arbitraryPropertiesIsEnabled: false,
|
||||
};
|
||||
|
||||
export interface ResolvedTailwindConfig extends Config {
|
||||
prefix: string;
|
||||
separator: string;
|
||||
corePlugins: Expand<Partial<Record<CorePluginList, boolean>>>;
|
||||
}
|
||||
|
||||
export type ResolvedConfig = ReturnType<typeof resolveConfig>;
|
||||
export type CorePlugins = ResolvedTailwindConfig["corePlugins"];
|
||||
|
||||
export function resolveConfig(config: Config) {
|
||||
const resolved = baseResolveConfig(config);
|
||||
const corePlugins: CorePlugins = {};
|
||||
for (const current of resolved["corePlugins"] as CorePluginList[]) {
|
||||
corePlugins[current] = true;
|
||||
}
|
||||
|
||||
return {
|
||||
...resolved,
|
||||
prefix: resolved.prefix || "",
|
||||
separator: resolved.separator || ":",
|
||||
corePlugins,
|
||||
};
|
||||
}
|
||||
|
||||
export class TailwindConverter {
|
||||
protected config: TailwindConverterConfig;
|
||||
private tailwindConfig: ResolvedConfig;
|
||||
private mapping: ConverterMapping;
|
||||
|
||||
constructor({
|
||||
tailwindConfig,
|
||||
...converterConfig
|
||||
}: Partial<TailwindConverterConfig> = {}) {
|
||||
const resolvedTailwindConfig = resolveConfig(
|
||||
tailwindConfig || ({ content: [] } as Config)
|
||||
);
|
||||
this.tailwindConfig = resolvedTailwindConfig;
|
||||
this.mapping = converterMappingByTailwindTheme(
|
||||
resolvedTailwindConfig.theme,
|
||||
converterConfig.remInPx
|
||||
);
|
||||
|
||||
this.config = {
|
||||
...DEFAULT_CONVERTER_CONFIG,
|
||||
...converterConfig,
|
||||
};
|
||||
}
|
||||
|
||||
async convertCSS(css: string) {
|
||||
const nodesManager = new TailwindNodesManager();
|
||||
const parsed = await postcss(this.config.postCSSPlugins).process(css, {
|
||||
parser: postcssSafeParser,
|
||||
});
|
||||
|
||||
parsed.root.walkRules(rule => {
|
||||
const converted = this.convertRule(rule);
|
||||
if (converted) {
|
||||
nodesManager.mergeNode(converted);
|
||||
}
|
||||
});
|
||||
|
||||
const nodes = nodesManager.getNodes();
|
||||
for (const node of nodes) {
|
||||
if (node.tailwindClasses.length) {
|
||||
node.rule.prepend(
|
||||
new AtRule({
|
||||
name: "apply",
|
||||
params: node.tailwindClasses.join(" "),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.cleanRaws(parsed.root);
|
||||
|
||||
return {
|
||||
nodes,
|
||||
convertedRoot: parsed.root,
|
||||
};
|
||||
}
|
||||
|
||||
protected cleanRaws(root: Root | Document) {
|
||||
root.raws.indent = detectIndent(root);
|
||||
|
||||
root.walkRules(node => {
|
||||
if (node.nodes?.length === 0) {
|
||||
node.remove();
|
||||
} else {
|
||||
node.cleanRaws(true);
|
||||
}
|
||||
});
|
||||
|
||||
root.walkAtRules(node => {
|
||||
if (node.nodes?.length === 0) {
|
||||
node.remove();
|
||||
} else {
|
||||
node.cleanRaws(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected convertRule(rule: Rule): TailwindNode | null {
|
||||
let tailwindClasses: string[] = [];
|
||||
|
||||
rule.walkDecls(declaration => {
|
||||
const converted = this.convertDeclarationToClasses(declaration);
|
||||
|
||||
if (converted?.length) {
|
||||
declaration.remove();
|
||||
tailwindClasses = tailwindClasses.concat(converted);
|
||||
}
|
||||
});
|
||||
|
||||
if (tailwindClasses.length) {
|
||||
tailwindClasses = reduceTailwindClasses(tailwindClasses);
|
||||
|
||||
if (this.tailwindConfig.prefix) {
|
||||
tailwindClasses = tailwindClasses.map(className =>
|
||||
className[0] === "[" // is "arbitrary property" class
|
||||
? className
|
||||
: `${this.tailwindConfig.prefix}${className}`
|
||||
);
|
||||
}
|
||||
|
||||
return this.makeTailwindNode(rule, tailwindClasses);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected convertDeclarationToClasses(declaration: Declaration) {
|
||||
const converter = DECLARATION_CONVERTERS_MAPPING[declaration.prop];
|
||||
const classes =
|
||||
!converter.flag || this.tailwindConfig.corePlugins[converter.flag]
|
||||
? converter?.map(declaration, this.mapping, this.config, this.tailwindConfig)
|
||||
: [];
|
||||
|
||||
if (classes.length === 0 && this.config.arbitraryPropertiesIsEnabled) {
|
||||
return [`[${declaration.prop}:${prepareArbitraryValue(declaration.value)}]`];
|
||||
}
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
protected makeTailwindNode(rule: Rule, tailwindClasses: string[]): TailwindNode {
|
||||
const { baseSelector, classPrefix } = this.parseSelector(rule.selector);
|
||||
|
||||
const classPrefixByParentNodes = this.convertContainerToClassPrefix(rule.parent);
|
||||
|
||||
if (classPrefixByParentNodes) {
|
||||
return {
|
||||
key: baseSelector,
|
||||
rootRuleSelector: baseSelector,
|
||||
originalRule: rule,
|
||||
classesPrefix: classPrefixByParentNodes + classPrefix,
|
||||
tailwindClasses,
|
||||
};
|
||||
}
|
||||
|
||||
if (classPrefix) {
|
||||
const key = TailwindNodesManager.convertRuleToKey(rule, baseSelector);
|
||||
const isRootRule = key === baseSelector;
|
||||
|
||||
return {
|
||||
key,
|
||||
rootRuleSelector: isRootRule ? baseSelector : null,
|
||||
originalRule: rule,
|
||||
classesPrefix: classPrefix,
|
||||
tailwindClasses,
|
||||
};
|
||||
}
|
||||
|
||||
return { rule, tailwindClasses };
|
||||
}
|
||||
|
||||
protected parseSelector(rawSelector: string) {
|
||||
const parsedSelectors = parse(rawSelector);
|
||||
|
||||
if (parsedSelectors.length !== 1) {
|
||||
return { baseSelector: rawSelector, classPrefix: "" };
|
||||
}
|
||||
|
||||
const parsedSelector = parsedSelectors[0];
|
||||
let baseSelectors: Array<Selector> = [];
|
||||
let classPrefixes: Array<string> = [];
|
||||
parsedSelector?.forEach((selectorItem, index) => {
|
||||
if (isTraversal(selectorItem)) {
|
||||
baseSelectors = parsedSelector.slice(0, index + 1);
|
||||
classPrefixes = [];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const classPrefix = this.convertSelectorToClassPrefix(selectorItem);
|
||||
|
||||
if (classPrefix) {
|
||||
classPrefixes.push(classPrefix);
|
||||
} else {
|
||||
baseSelectors.push(selectorItem);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
baseSelector: stringify([baseSelectors]),
|
||||
classPrefix: classPrefixes.join(""),
|
||||
};
|
||||
}
|
||||
|
||||
protected convertSelectorToClassPrefix(selector: Selector) {
|
||||
if (selector.type === "pseudo" || selector.type === "pseudo-element") {
|
||||
const mapped = (PSEUDOS_MAPPING as any)[selector.name];
|
||||
|
||||
return mapped ? `${mapped}${this.tailwindConfig.separator}` : null;
|
||||
}
|
||||
|
||||
if (selector.type === "attribute") {
|
||||
if (selector.name.startsWith("aria-")) {
|
||||
const mappingKey = this.attributeSelectorToMappingKey(selector, 6);
|
||||
const mapped = this.mapping.aria?.[mappingKey];
|
||||
|
||||
if (!mapped) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return `${mapped}${this.tailwindConfig.separator}`;
|
||||
}
|
||||
|
||||
if (selector.name.startsWith("data-")) {
|
||||
const mappingKey = this.attributeSelectorToMappingKey(selector, 6);
|
||||
const mapped = this.mapping.data?.[mappingKey];
|
||||
|
||||
if (!mapped) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return `${mapped}${this.tailwindConfig.separator}`;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected attributeSelectorToMappingKey(selector: AttributeSelector, from = 1) {
|
||||
const stringifiedSelector = stringify([[selector]]);
|
||||
|
||||
return stringifiedSelector.substring(from, stringifiedSelector.length - 1);
|
||||
}
|
||||
|
||||
protected convertContainerToClassPrefix(container: Container | undefined) {
|
||||
let currentContainer: Document | Container | undefined = container;
|
||||
const mediaParams: string[] = [];
|
||||
const supportsParams: string[] = [];
|
||||
|
||||
while (isChildNode(currentContainer)) {
|
||||
if (!isAtRuleNode(currentContainer)) {
|
||||
// do not convert if parent is not at-rule
|
||||
return "";
|
||||
}
|
||||
|
||||
if (currentContainer.name === "media") {
|
||||
mediaParams.push(currentContainer.params);
|
||||
} else if (currentContainer.name === "supports") {
|
||||
supportsParams.push(currentContainer.params);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
currentContainer = currentContainer.parent;
|
||||
}
|
||||
|
||||
let mediaPrefixes = "";
|
||||
let supportsPrefixes = "";
|
||||
if (mediaParams.length) {
|
||||
mediaPrefixes = this.convertMediaParamsToClassPrefix(mediaParams.reverse());
|
||||
if (!mediaPrefixes) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsParams.length) {
|
||||
supportsPrefixes = this.convertSupportsParamsToClassPrefix(
|
||||
supportsParams.reverse()
|
||||
);
|
||||
if (!supportsPrefixes) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
return mediaPrefixes + supportsPrefixes;
|
||||
}
|
||||
|
||||
protected convertMediaParamsToClassPrefix(mediaParams: string[]) {
|
||||
const modifiers: string[] = [];
|
||||
const screens: string[] = [];
|
||||
|
||||
for (let i = 0; i < mediaParams.length; i++) {
|
||||
const splitted = mediaParams[i].split(" and ");
|
||||
for (let j = 0; j < splitted.length; j++) {
|
||||
const param = normalizeAtRuleParams(splitted[j].trim());
|
||||
|
||||
if (param === "screen") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (param.includes("width") || param.includes("height")) {
|
||||
screens.push(param);
|
||||
continue;
|
||||
}
|
||||
|
||||
const mapped = (MEDIA_PARAMS_MAPPING as any)[param.replace(/\s+/g, "")];
|
||||
if (mapped) {
|
||||
modifiers.push(mapped);
|
||||
continue;
|
||||
}
|
||||
|
||||
// do not convert if not convertable media
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
if (screens.length > 0) {
|
||||
const mappedScreen = this.mapping.screens[screens.join(" and ")];
|
||||
|
||||
if (!mappedScreen) {
|
||||
return "";
|
||||
}
|
||||
|
||||
modifiers.push(mappedScreen);
|
||||
}
|
||||
|
||||
const classPrefix = modifiers.join(this.tailwindConfig.separator);
|
||||
|
||||
return classPrefix ? classPrefix + this.tailwindConfig.separator : "";
|
||||
}
|
||||
|
||||
protected convertSupportsParamsToClassPrefix(supportParams: string[]) {
|
||||
const buildParams = supportParams.join(" and ");
|
||||
const classPrefix = convertDeclarationValue({
|
||||
value: {
|
||||
value:
|
||||
supportParams.length > 1
|
||||
? removeUnnecessarySpaces(buildParams)
|
||||
: normalizeAtRuleParams(buildParams),
|
||||
valuesMap: this.mapping.supports || {},
|
||||
classPrefix: "supports",
|
||||
},
|
||||
});
|
||||
|
||||
return classPrefix ? classPrefix.join(",") + this.tailwindConfig.separator : "";
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +0,0 @@
|
||||
{
|
||||
"print": "print",
|
||||
"orientation:portrait": "portrait",
|
||||
"orientation:landscape": "landscape",
|
||||
"prefers-contrast:more": "contrast-more",
|
||||
"prefers-contrast:less": "contrast-less",
|
||||
"prefers-color-scheme:dark": "dark",
|
||||
"prefers-reduced-motion:no-preference": "motion-safe",
|
||||
"prefers-reduced-motion:reduce": "motion-reduce"
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
{
|
||||
"hover": "hover",
|
||||
"focus": "focus",
|
||||
"focus-within": "focus-within",
|
||||
"focus-visible": "focus-visible",
|
||||
"active": "active",
|
||||
"visited": "visited",
|
||||
"target": "target",
|
||||
"first-child": "first",
|
||||
"last-child": "last",
|
||||
"only-child": "only",
|
||||
"nth-child(odd)": "odd",
|
||||
"nth-child(2n+1)": "odd",
|
||||
"nth-child(even)": "even",
|
||||
"nth-child(2n)": "even",
|
||||
"first-of-type": "first-of-type",
|
||||
"last-of-type": "last-of-type",
|
||||
"only-of-type": "only-of-type",
|
||||
"empty": "empty",
|
||||
"disabled": "disabled",
|
||||
"enabled": "enabled",
|
||||
"checked": "checked",
|
||||
"indeterminate": "indeterminate",
|
||||
"default": "default",
|
||||
"required": "required",
|
||||
"valid": "valid",
|
||||
"invalid": "invalid",
|
||||
"in-range": "in-range",
|
||||
"out-of-range": "out-of-range",
|
||||
"autofill": "autofill",
|
||||
"read-only": "read-only",
|
||||
"before": "before",
|
||||
"after": "after",
|
||||
"first-letter": "first-letter",
|
||||
"first-line": "first-line",
|
||||
"marker": "marker",
|
||||
"selection": "selection",
|
||||
"file-selector-button": "file",
|
||||
"backdrop": "backdrop"
|
||||
}
|
@ -1,445 +0,0 @@
|
||||
{
|
||||
"alignContent": {
|
||||
"center": "content-center",
|
||||
"flex-start": "content-start",
|
||||
"flex-end": "content-end",
|
||||
"space-between": "content-between",
|
||||
"space-around": "content-around",
|
||||
"space-evenly": "content-evenly",
|
||||
"baseline": "content-baseline"
|
||||
},
|
||||
"alignItems": {
|
||||
"flex-start": "items-start",
|
||||
"flex-end": "items-end",
|
||||
"center": "items-center",
|
||||
"baseline": "items-baseline",
|
||||
"stretch": "items-stretch"
|
||||
},
|
||||
"alignSelf": {
|
||||
"auto": "self-auto",
|
||||
"flex-start": "self-start",
|
||||
"flex-end": "self-end",
|
||||
"center": "self-center",
|
||||
"stretch": "self-stretch",
|
||||
"baseline": "self-baseline"
|
||||
},
|
||||
"appearance": {
|
||||
"none": "appearance-none"
|
||||
},
|
||||
"backgroundAttachment": {
|
||||
"fixed": "bg-fixed",
|
||||
"local": "bg-local",
|
||||
"scroll": "bg-scroll"
|
||||
},
|
||||
"backgroundBlendMode": {
|
||||
"normal": "bg-blend-normal",
|
||||
"multiply": "bg-blend-multiply",
|
||||
"screen": "bg-blend-screen",
|
||||
"overlay": "bg-blend-overlay",
|
||||
"darken": "bg-blend-darken",
|
||||
"lighten": "bg-blend-lighten",
|
||||
"color-dodge": "bg-blend-color-dodge",
|
||||
"color-burn": "bg-blend-color-burn",
|
||||
"hard-light": "bg-blend-hard-light",
|
||||
"soft-light": "bg-blend-soft-light",
|
||||
"difference": "bg-blend-difference",
|
||||
"exclusion": "bg-blend-exclusion",
|
||||
"hue": "bg-blend-hue",
|
||||
"saturation": "bg-blend-saturation",
|
||||
"color": "bg-blend-color",
|
||||
"luminosity": "bg-blend-luminosity"
|
||||
},
|
||||
"backgroundClip": {
|
||||
"border-box": "bg-clip-border",
|
||||
"padding-box": "bg-clip-padding",
|
||||
"content-box": "bg-clip-content",
|
||||
"text": "bg-clip-text"
|
||||
},
|
||||
"backgroundOrigin": {
|
||||
"border-box": "bg-origin-border",
|
||||
"padding-box": "bg-origin-padding",
|
||||
"content-box": "bg-origin-content"
|
||||
},
|
||||
"backgroundRepeat": {
|
||||
"repeat": "bg-repeat",
|
||||
"no-repeat": "bg-no-repeat",
|
||||
"repeat-x": "bg-repeat-x",
|
||||
"repeat-y": "bg-repeat-y",
|
||||
"round": "bg-repeat-round",
|
||||
"space": "bg-repeat-space"
|
||||
},
|
||||
"borderStyle": {
|
||||
"solid": "border-solid",
|
||||
"dashed": "border-dashed",
|
||||
"dotted": "border-dotted",
|
||||
"double": "border-double",
|
||||
"hidden": "border-hidden",
|
||||
"none": "border-none"
|
||||
},
|
||||
"borderCollapse": {
|
||||
"collapse": "border-collapse",
|
||||
"separate": "border-separate"
|
||||
},
|
||||
"boxDecorationBreak": {
|
||||
"slice": "box-decoration-slice",
|
||||
"clone": "box-decoration-clone"
|
||||
},
|
||||
"boxSizing": {
|
||||
"border-box": "box-border",
|
||||
"content-box": "box-content"
|
||||
},
|
||||
"breakAfter": {
|
||||
"auto": "break-after-auto",
|
||||
"avoid": "break-after-avoid",
|
||||
"all": "break-after-all",
|
||||
"avoid-page": "break-after-avoid-page",
|
||||
"page": "break-after-page",
|
||||
"left": "break-after-left",
|
||||
"right": "break-after-right",
|
||||
"column": "break-after-column"
|
||||
},
|
||||
"breakBefore": {
|
||||
"auto": "break-before-auto",
|
||||
"avoid": "break-before-avoid",
|
||||
"all": "break-before-all",
|
||||
"avoid-page": "break-before-avoid-page",
|
||||
"page": "break-before-page",
|
||||
"left": "break-before-left",
|
||||
"right": "break-before-right",
|
||||
"column": "break-before-column"
|
||||
},
|
||||
"breakInside": {
|
||||
"auto": "break-inside-auto",
|
||||
"avoid": "break-inside-avoid",
|
||||
"avoid-page": "break-inside-avoid-page",
|
||||
"avoid-column": "break-inside-avoid-column"
|
||||
},
|
||||
"clear": {
|
||||
"left": "clear-left",
|
||||
"right": "clear-right",
|
||||
"both": "clear-both",
|
||||
"none": "clear-none"
|
||||
},
|
||||
"display": {
|
||||
"block": "block",
|
||||
"inline-block": "inline-block",
|
||||
"inline": "inline",
|
||||
"flex": "flex",
|
||||
"inline-flex": "inline-flex",
|
||||
"table": "table",
|
||||
"inline-table": "inline-table",
|
||||
"table-caption": "table-caption",
|
||||
"table-cell": "table-cell",
|
||||
"table-column": "table-column",
|
||||
"table-column-group": "table-column-group",
|
||||
"table-footer-group": "table-footer-group",
|
||||
"table-header-group": "table-header-group",
|
||||
"table-row-group": "table-row-group",
|
||||
"table-row": "table-row",
|
||||
"flow-root": "flow-root",
|
||||
"grid": "grid",
|
||||
"inline-grid": "inline-grid",
|
||||
"contents": "contents",
|
||||
"list-item": "list-item",
|
||||
"none": "hidden"
|
||||
},
|
||||
"flexDirection": {
|
||||
"row": "flex-row",
|
||||
"row-reverse": "flex-row-reverse",
|
||||
"column": "flex-col",
|
||||
"column-reverse": "flex-col-reverse"
|
||||
},
|
||||
"flexWrap": {
|
||||
"wrap": "flex-wrap",
|
||||
"wrap-reverse": "flex-wrap-reverse",
|
||||
"nowrap": "flex-nowrap"
|
||||
},
|
||||
"float": {
|
||||
"right": "float-right",
|
||||
"left": "float-left",
|
||||
"none": "float-none"
|
||||
},
|
||||
"fontSmoothing": {
|
||||
"antialiased": "antialiased",
|
||||
"grayscale": "antialiased",
|
||||
"auto": "subpixel-antialiased"
|
||||
},
|
||||
"fontStyle": {
|
||||
"italic": "italic",
|
||||
"normal": "not-italic"
|
||||
},
|
||||
"fontVariantNumeric": {
|
||||
"normal": "normal-nums",
|
||||
"ordinal": "ordinal",
|
||||
"slashed-zero": "slashed-zero",
|
||||
"lining-nums": "lining-nums",
|
||||
"oldstyle-nums": "oldstyle-nums",
|
||||
"proportional-nums": "proportional-nums",
|
||||
"tabular-nums": "tabular-nums",
|
||||
"diagonal-fractions": "diagonal-fractions",
|
||||
"stacked-fractions": "stacked-fractions"
|
||||
},
|
||||
"gridAutoFlow": {
|
||||
"row": "grid-flow-row",
|
||||
"column": "grid-flow-col",
|
||||
"dense": "grid-flow-dense",
|
||||
"row dense": "grid-flow-row-dense",
|
||||
"column dense": "grid-flow-col-dense"
|
||||
},
|
||||
"isolation": {
|
||||
"isolate": "isolate",
|
||||
"auto": "isolation-auto"
|
||||
},
|
||||
"justifyContent": {
|
||||
"flex-start": "justify-start",
|
||||
"flex-end": "justify-end",
|
||||
"center": "justify-center",
|
||||
"space-between": "justify-between",
|
||||
"space-around": "justify-around",
|
||||
"space-evenly": "justify-evenly"
|
||||
},
|
||||
"justifyItems": {
|
||||
"flex-start": "justify-items-start",
|
||||
"flex-end": "justify-items-end",
|
||||
"start": "justify-items-start",
|
||||
"end": "justify-items-end",
|
||||
"center": "justify-items-center",
|
||||
"stretch": "justify-items-stretch"
|
||||
},
|
||||
"justifySelf": {
|
||||
"auto": "justify-self-auto",
|
||||
"flex-start": "justify-self-start",
|
||||
"flex-end": "justify-self-end",
|
||||
"start": "justify-self-start",
|
||||
"end": "justify-self-end",
|
||||
"center": "justify-self-center",
|
||||
"stretch": "justify-self-stretch"
|
||||
},
|
||||
"listStylePosition": {
|
||||
"inside": "list-inside",
|
||||
"outside": "list-outside"
|
||||
},
|
||||
"mixBlendMode": {
|
||||
"normal": "mix-blend-normal",
|
||||
"multiply": "mix-blend-multiply",
|
||||
"screen": "mix-blend-screen",
|
||||
"overlay": "mix-blend-overlay",
|
||||
"darken": "mix-blend-darken",
|
||||
"lighten": "mix-blend-lighten",
|
||||
"color-dodge": "mix-blend-color-dodge",
|
||||
"color-burn": "mix-blend-color-burn",
|
||||
"hard-light": "mix-blend-hard-light",
|
||||
"soft-light": "mix-blend-soft-light",
|
||||
"difference": "mix-blend-difference",
|
||||
"exclusion": "mix-blend-exclusion",
|
||||
"hue": "mix-blend-hue",
|
||||
"saturation": "mix-blend-saturation",
|
||||
"color": "mix-blend-color",
|
||||
"luminosity": "mix-blend-luminosity",
|
||||
"plus-lighter": "mix-blend-plus-lighter"
|
||||
},
|
||||
"objectFit": {
|
||||
"contain": "object-contain",
|
||||
"cover": "object-cover",
|
||||
"fill": "object-fill",
|
||||
"none": "object-none",
|
||||
"scale-down": "object-scale-down"
|
||||
},
|
||||
"outlineStyle": {
|
||||
"solid": "outline",
|
||||
"dashed": "outline-dashed",
|
||||
"dotted": "outline-dotted",
|
||||
"double": "outline-double"
|
||||
},
|
||||
"outline": {
|
||||
"2px solid transparent": "outline-none"
|
||||
},
|
||||
"overflow": {
|
||||
"auto": "overflow-auto",
|
||||
"hidden": "overflow-hidden",
|
||||
"clip": "overflow-clip",
|
||||
"visible": "overflow-visible",
|
||||
"scroll": "overflow-scroll"
|
||||
},
|
||||
"overflowWrap": {
|
||||
"break-word": "break-words"
|
||||
},
|
||||
"overflowX": {
|
||||
"auto": "overflow-x-auto",
|
||||
"hidden": "overflow-x-hidden",
|
||||
"clip": "overflow-x-clip",
|
||||
"visible": "overflow-x-visible",
|
||||
"scroll": "overflow-x-scroll"
|
||||
},
|
||||
"overflowY": {
|
||||
"auto": "overflow-y-auto",
|
||||
"hidden": "overflow-y-hidden",
|
||||
"clip": "overflow-y-clip",
|
||||
"visible": "overflow-y-visible",
|
||||
"scroll": "overflow-y-scroll"
|
||||
},
|
||||
"overscrollBehavior": {
|
||||
"auto": "overscroll-auto",
|
||||
"contain": "overscroll-contain",
|
||||
"none": "overscroll-none"
|
||||
},
|
||||
"overscrollBehaviorX": {
|
||||
"auto": "overscroll-x-auto",
|
||||
"contain": "overscroll-x-contain",
|
||||
"none": "overscroll-x-none"
|
||||
},
|
||||
"overscrollBehaviorY": {
|
||||
"auto": "overscroll-y-auto",
|
||||
"contain": "overscroll-y-contain",
|
||||
"none": "overscroll-y-none"
|
||||
},
|
||||
"placeContent": {
|
||||
"center": "place-content-center",
|
||||
"start": "place-content-start",
|
||||
"end": "place-content-end",
|
||||
"space-between": "place-content-between",
|
||||
"space-around": "place-content-around",
|
||||
"space-evenly": "place-content-evenly",
|
||||
"baseline": "place-content-baseline",
|
||||
"stretch": "place-content-stretch"
|
||||
},
|
||||
"placeItems": {
|
||||
"start": "place-items-start",
|
||||
"end": "place-items-end",
|
||||
"center": "place-items-center",
|
||||
"baseline": "place-items-baseline",
|
||||
"stretch": "place-items-stretch"
|
||||
},
|
||||
"placeSelf": {
|
||||
"auto": "place-self-auto",
|
||||
"start": "place-self-start",
|
||||
"end": "place-self-end",
|
||||
"center": "place-self-center",
|
||||
"stretch": "place-self-stretch"
|
||||
},
|
||||
"pointerEvents": {
|
||||
"none": "pointer-events-none",
|
||||
"auto": "pointer-events-auto"
|
||||
},
|
||||
"position": {
|
||||
"static": "static",
|
||||
"fixed": "fixed",
|
||||
"absolute": "absolute",
|
||||
"relative": "relative",
|
||||
"sticky": "sticky"
|
||||
},
|
||||
"resize": {
|
||||
"none": "resize-none",
|
||||
"vertical": "resize-y",
|
||||
"horizontal": "resize-x",
|
||||
"both": "resize"
|
||||
},
|
||||
"scrollBehavior": {
|
||||
"auto": "scroll-auto",
|
||||
"smooth": "scroll-smooth"
|
||||
},
|
||||
"scrollSnapAlign": {
|
||||
"start": "snap-start",
|
||||
"end": "snap-end",
|
||||
"center": "snap-center",
|
||||
"none": "snap-align-none"
|
||||
},
|
||||
"scrollSnapType": {
|
||||
"none": "snap-none",
|
||||
"x var(--tw-scroll-snap-strictness)": "snap-x",
|
||||
"x": "snap-x",
|
||||
"y var(--tw-scroll-snap-strictness)": "snap-y",
|
||||
"y": "snap-y",
|
||||
"both var(--tw-scroll-snap-strictness)": "snap-both",
|
||||
"both": "snap-both"
|
||||
},
|
||||
"scrollSnapStop": {
|
||||
"normal": "snap-normal",
|
||||
"always": "snap-always"
|
||||
},
|
||||
"tableLayout": {
|
||||
"auto": "table-auto",
|
||||
"fixed": "table-fixed"
|
||||
},
|
||||
"textAlign": {
|
||||
"left": "text-left",
|
||||
"center": "text-center",
|
||||
"right": "text-right",
|
||||
"justify": "text-justify",
|
||||
"start": "text-start",
|
||||
"end": "text-end"
|
||||
},
|
||||
"textDecorationLine": {
|
||||
"underline": "underline",
|
||||
"overline": "overline",
|
||||
"line-through": "line-through",
|
||||
"none": "no-underline"
|
||||
},
|
||||
"textDecorationStyle": {
|
||||
"solid": "decoration-solid",
|
||||
"double": "decoration-double",
|
||||
"dotted": "decoration-dotted",
|
||||
"dashed": "decoration-dashed",
|
||||
"wavy": "decoration-wavy"
|
||||
},
|
||||
"textTransform": {
|
||||
"uppercase": "uppercase",
|
||||
"lowercase": "lowercase",
|
||||
"capitalize": "capitalize",
|
||||
"none": "normal-case"
|
||||
},
|
||||
"textOverflow": {
|
||||
"ellipsis": "text-ellipsis",
|
||||
"clip": "text-clip"
|
||||
},
|
||||
"touchAction": {
|
||||
"auto": "touch-auto",
|
||||
"none": "touch-none",
|
||||
"pan-x": "touch-pan-x",
|
||||
"pan-left": "touch-pan-left",
|
||||
"pan-right": "touch-pan-right",
|
||||
"pan-y": "touch-pan-y",
|
||||
"pan-up": "touch-pan-up",
|
||||
"pan-down": "touch-pan-down",
|
||||
"pinch-zoom": "touch-pinch-zoom",
|
||||
"manipulation": "touch-manipulation"
|
||||
},
|
||||
"transform": {
|
||||
"translateZ(0)": "transform-gpu",
|
||||
"translate3d(0,0,0)": "transform-gpu",
|
||||
"none": "transform-none"
|
||||
},
|
||||
"userSelect": {
|
||||
"none": "select-none",
|
||||
"text": "select-text",
|
||||
"all": "select-all",
|
||||
"auto": "select-auto"
|
||||
},
|
||||
"verticalAlign": {
|
||||
"baseline": "align-baseline",
|
||||
"top": "align-top",
|
||||
"middle": "align-middle",
|
||||
"bottom": "align-bottom",
|
||||
"text-top": "align-text-top",
|
||||
"text-bottom": "align-text-bottom",
|
||||
"sub": "align-sub",
|
||||
"super": "align-super"
|
||||
},
|
||||
"visibility": {
|
||||
"visible": "visible",
|
||||
"hidden": "invisible",
|
||||
"collapse": "collapse"
|
||||
},
|
||||
"whitespace": {
|
||||
"normal": "whitespace-normal",
|
||||
"nowrap": "whitespace-nowrap",
|
||||
"pre": "whitespace-pre",
|
||||
"pre-line": "whitespace-pre-line",
|
||||
"pre-wrap": "whitespace-pre-wrap"
|
||||
},
|
||||
"wordBreak": {
|
||||
"normal": "break-normal",
|
||||
"break-all": "break-all",
|
||||
"keep-all": "break-keep"
|
||||
}
|
||||
}
|
23
src/converts/types.d.ts
vendored
23
src/converts/types.d.ts
vendored
@ -1,23 +0,0 @@
|
||||
import type { ThemeConfig } from "tailwindcss/types/config";
|
||||
|
||||
export type RemoveIndex<T> = {
|
||||
[P in keyof T as string extends P ? never : number extends P ? never : P]: T[P];
|
||||
};
|
||||
|
||||
export type KnownKeys<T> = keyof RemoveIndex<T>;
|
||||
|
||||
export type SetPartialProps<Type, Props extends keyof Type> = Partial<Pick<Type, Props>> &
|
||||
Omit<Type, Props>;
|
||||
|
||||
export type SetRequiredProps<Type, Props extends keyof Type> = Required<
|
||||
Pick<Type, Props>
|
||||
> &
|
||||
Type;
|
||||
|
||||
export type ConverterMappingKey = Exclude<
|
||||
KnownKeys<ThemeConfig>,
|
||||
"keyframes" | "container" | "fontFamily"
|
||||
>;
|
||||
|
||||
export type ConverterMapping = Record<ConverterMappingKey, Record<string, string>> &
|
||||
Record<"aria" | "data" | "supports", Record<string, string> | undefined>;
|
@ -1,99 +0,0 @@
|
||||
import type { AtRule, ChildNode, Container, Node } from "postcss";
|
||||
import type { Screen } from "tailwindcss/types/config";
|
||||
|
||||
export function isCSSVariable(value: string) {
|
||||
return /^var\((--.+?)\)$/.test(value.trim());
|
||||
}
|
||||
|
||||
export function isAtRuleNode(node: Node | undefined): node is AtRule {
|
||||
return !!(node?.type === "atrule");
|
||||
}
|
||||
|
||||
export function isChildNode(node: Node | undefined): node is ChildNode {
|
||||
return !!(
|
||||
node &&
|
||||
(node.type === "atrule" ||
|
||||
node.type === "rule" ||
|
||||
node.type === "decl" ||
|
||||
node.type === "comment")
|
||||
);
|
||||
}
|
||||
|
||||
export function buildMediaQueryByScreen(screens: string | Screen | Screen[]) {
|
||||
if (typeof screens === "string") {
|
||||
return `(min-width: ${screens})`;
|
||||
}
|
||||
|
||||
screens = Array.isArray(screens) ? screens : [screens];
|
||||
|
||||
return screens
|
||||
.map(screen => {
|
||||
if ("raw" in screen && screen["raw"]) {
|
||||
return screen["raw"];
|
||||
}
|
||||
|
||||
const conditions: string[] = [];
|
||||
if ("min" in screen && screen["min"]) {
|
||||
conditions.push(`(min-width: ${screen["min"]})`);
|
||||
}
|
||||
|
||||
if ("max" in screen && screen["max"]) {
|
||||
conditions.push(`(max-width: ${screen["max"]})`);
|
||||
}
|
||||
|
||||
if (conditions.length) {
|
||||
return conditions.join(" and ");
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join(", ");
|
||||
}
|
||||
|
||||
export function detectIndent(root: Container<any>) {
|
||||
if (root.raws.indent) return root.raws.indent;
|
||||
|
||||
let detectedIndent = " ";
|
||||
root.walk(node => {
|
||||
const p = node.parent;
|
||||
if (
|
||||
p &&
|
||||
p !== root &&
|
||||
p.parent &&
|
||||
p.parent === root &&
|
||||
node.raws.before !== undefined
|
||||
) {
|
||||
const parts = node.raws.before.split("\n");
|
||||
detectedIndent = parts.at(-1)!;
|
||||
detectedIndent = detectedIndent.replace(/\S/g, "");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return detectedIndent;
|
||||
}
|
||||
|
||||
export function flattenObject(
|
||||
object: Record<string | number | symbol, any>,
|
||||
separator = "-"
|
||||
) {
|
||||
const flatObject: Record<string, any> = {};
|
||||
|
||||
for (const [prop, value] of Object.entries(object)) {
|
||||
if (typeof value === "object" && value !== null) {
|
||||
const nestedFlatObject = flattenObject(value, separator);
|
||||
|
||||
for (const [nestedProp, nestedValue] of Object.entries(nestedFlatObject)) {
|
||||
flatObject[prop + separator + nestedProp] = nestedValue;
|
||||
}
|
||||
} else {
|
||||
flatObject[prop] = value;
|
||||
}
|
||||
}
|
||||
return flatObject;
|
||||
}
|
||||
|
||||
export function removeUnnecessarySpaces(string: string) {
|
||||
return string.replace(/(\s+)?([,:;])(\s+)?/gm, "$2");
|
||||
}
|
@ -1,216 +0,0 @@
|
||||
import { colord } from "colord";
|
||||
import type { Config } from "tailwindcss";
|
||||
import type {
|
||||
KeyValuePair,
|
||||
RecursiveKeyValuePair,
|
||||
ScreensConfig,
|
||||
} from "tailwindcss/types/config";
|
||||
import type { ConverterMapping } from "../types";
|
||||
import {
|
||||
buildMediaQueryByScreen,
|
||||
flattenObject,
|
||||
removeUnnecessarySpaces,
|
||||
} from "../utils";
|
||||
|
||||
const remValueRegexp = /^(\d+)?\.?\d+rem$/;
|
||||
|
||||
function remValueToPx(value: string, remInPx: number) {
|
||||
if (remValueRegexp.test(value.trim())) {
|
||||
const number = parseFloat(value);
|
||||
|
||||
return isNaN(number) ? value : `${number * remInPx}px`;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function normalizeNumbersInString(string: string) {
|
||||
return string.replace(/(^|[\s*+-/;])(\.\d+)/g, "$10$2");
|
||||
}
|
||||
|
||||
export function normalizeValue(value: string) {
|
||||
return removeUnnecessarySpaces(normalizeNumbersInString(value));
|
||||
}
|
||||
|
||||
export function normalizeColorValue(colorValue: string) {
|
||||
const parsed = colord(colorValue);
|
||||
return parsed.isValid() ? parsed.toHex() : colorValue;
|
||||
}
|
||||
|
||||
export function normalizeZeroSizeValue(value: string) {
|
||||
return value.trim() === "0px" ? "0" : value;
|
||||
}
|
||||
|
||||
export function normalizeSizeValue(
|
||||
sizeValue: string,
|
||||
remInPx: number | undefined | null
|
||||
) {
|
||||
return normalizeZeroSizeValue(
|
||||
normalizeNumbersInString(
|
||||
remInPx != null ? remValueToPx(sizeValue, remInPx) : sizeValue
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function normalizeAtRuleParams(atRuleParam: string) {
|
||||
return removeUnnecessarySpaces(atRuleParam.replace(/\(|\)/g, ""));
|
||||
}
|
||||
|
||||
function mapThemeTokens<V>(
|
||||
tokens: KeyValuePair<string, V>,
|
||||
valueConverterFn: (tokenValue: V, tokenKey: string) => string | null
|
||||
) {
|
||||
const result: Record<string, string> = {};
|
||||
|
||||
for (const [tokenKey, tokenValue] of Object.entries(tokens)) {
|
||||
const convertedTokenValue = valueConverterFn(tokenValue, tokenKey);
|
||||
|
||||
if (convertedTokenValue) {
|
||||
result[convertedTokenValue] = tokenKey;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function isColorKey(key: string) {
|
||||
return ["fill", "stroke"].includes(key) || key.toLowerCase().includes("color");
|
||||
}
|
||||
|
||||
function isSizeKey(key: string) {
|
||||
return [
|
||||
"backdropBlur",
|
||||
"backgroundSize",
|
||||
"blur",
|
||||
"borderRadius",
|
||||
"borderSpacing",
|
||||
"borderWidth",
|
||||
"columns",
|
||||
"divideWidth",
|
||||
"flexBasis",
|
||||
"gap",
|
||||
"height",
|
||||
"inset",
|
||||
"letterSpacing",
|
||||
"lineHeight",
|
||||
"margin",
|
||||
"maxHeight",
|
||||
"maxWidth",
|
||||
"minHeight",
|
||||
"minWidth",
|
||||
"outlineOffset",
|
||||
"outlineWidth",
|
||||
"padding",
|
||||
"ringOffsetWidth",
|
||||
"ringWidth",
|
||||
"scrollMargin",
|
||||
"scrollPadding",
|
||||
"space",
|
||||
"spacing",
|
||||
"strokeWidth",
|
||||
"textDecorationThickness",
|
||||
"textUnderlineOffset",
|
||||
"translate",
|
||||
"width",
|
||||
].includes(key);
|
||||
}
|
||||
|
||||
function convertFontSizes(
|
||||
fontSizes: KeyValuePair<
|
||||
string,
|
||||
| string
|
||||
| [fontSize: string, lineHeight: string]
|
||||
| [
|
||||
fontSize: string,
|
||||
configuration: Partial<{
|
||||
lineHeight: string;
|
||||
letterSpacing: string;
|
||||
fontWeight: string | number;
|
||||
}>,
|
||||
]
|
||||
>,
|
||||
remInPx?: number | null
|
||||
) {
|
||||
return mapThemeTokens(fontSizes, fontSizeValue => {
|
||||
if (!fontSizeValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Array.isArray(fontSizeValue)) {
|
||||
fontSizeValue = fontSizeValue[0];
|
||||
}
|
||||
|
||||
return normalizeSizeValue(fontSizeValue, remInPx);
|
||||
});
|
||||
}
|
||||
|
||||
function convertScreens(screens: ScreensConfig) {
|
||||
if (Array.isArray(screens)) {
|
||||
return {} as Record<string, string>;
|
||||
}
|
||||
|
||||
return mapThemeTokens(screens, screenValue =>
|
||||
screenValue ? normalizeAtRuleParams(buildMediaQueryByScreen(screenValue)) : null
|
||||
);
|
||||
}
|
||||
|
||||
function convertColors(colors: RecursiveKeyValuePair) {
|
||||
const flatColors = flattenObject(colors);
|
||||
|
||||
return mapThemeTokens(flatColors, (colorValue: string) => {
|
||||
colorValue = colorValue?.toString();
|
||||
|
||||
return colorValue ? normalizeColorValue(colorValue) : null;
|
||||
});
|
||||
}
|
||||
|
||||
function convertSizes(sizes: KeyValuePair, remInPx: number | null | undefined) {
|
||||
return mapThemeTokens(sizes, (sizeValue: string) => {
|
||||
sizeValue = sizeValue?.toString();
|
||||
|
||||
return sizeValue ? normalizeSizeValue(sizeValue, remInPx) : null;
|
||||
});
|
||||
}
|
||||
|
||||
function convertOtherThemeTokens(tokens: KeyValuePair | null | undefined) {
|
||||
return tokens
|
||||
? mapThemeTokens(tokens, (tokenValue: string) => {
|
||||
tokenValue = tokenValue?.toString();
|
||||
|
||||
return tokenValue ? normalizeValue(tokenValue) : null;
|
||||
})
|
||||
: tokens;
|
||||
}
|
||||
|
||||
export function converterMappingByTailwindTheme(
|
||||
resolvedTailwindTheme: Config["theme"],
|
||||
remInPx?: number | null
|
||||
) {
|
||||
const converterMapping = {} as ConverterMapping;
|
||||
|
||||
if (!resolvedTailwindTheme) {
|
||||
return converterMapping;
|
||||
}
|
||||
|
||||
for (const [key, themeItem] of Object.entries(
|
||||
resolvedTailwindTheme as Record<string, any>
|
||||
)) {
|
||||
if (["keyframes", "container", "fontFamily"].includes(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key === "fontSize") {
|
||||
converterMapping[key] = convertFontSizes(themeItem, remInPx);
|
||||
} else if (key === "screens") {
|
||||
converterMapping[key] = convertScreens(themeItem);
|
||||
} else if (isColorKey(key)) {
|
||||
(converterMapping as any)[key] = convertColors(themeItem);
|
||||
} else if (isSizeKey(key)) {
|
||||
(converterMapping as any)[key] = convertSizes(themeItem, remInPx);
|
||||
} else {
|
||||
(converterMapping as any)[key] = convertOtherThemeTokens(themeItem);
|
||||
}
|
||||
}
|
||||
|
||||
return converterMapping;
|
||||
}
|
@ -1,228 +0,0 @@
|
||||
class TailwindClassesReductionManager {
|
||||
protected resolvedClasses: string[] = [];
|
||||
protected map: Record<string, any> = {
|
||||
m: { mx: { ml: [], mr: [] }, my: { mt: [], mb: [] } },
|
||||
p: { px: { pl: [], pr: [] }, py: { pt: [], pb: [] } },
|
||||
"scroll-m": {
|
||||
"scroll-mx": {
|
||||
"scroll-ml": [],
|
||||
"scroll-mr": [],
|
||||
},
|
||||
"scroll-my": {
|
||||
"scroll-mt": [],
|
||||
"scroll-mb": [],
|
||||
},
|
||||
},
|
||||
"scroll-p": {
|
||||
"scroll-px": {
|
||||
"scroll-pl": [],
|
||||
"scroll-pr": [],
|
||||
},
|
||||
"scroll-py": {
|
||||
"scroll-pt": [],
|
||||
"scroll-pb": [],
|
||||
},
|
||||
},
|
||||
rounded: {
|
||||
"rounded-t": {
|
||||
"rounded-tl": [],
|
||||
"rounded-tr": [],
|
||||
},
|
||||
"rounded-r": {
|
||||
"rounded-tr": [],
|
||||
"rounded-br": [],
|
||||
},
|
||||
"rounded-b": {
|
||||
"rounded-bl": [],
|
||||
"rounded-br": [],
|
||||
},
|
||||
"rounded-l": {
|
||||
"rounded-tl": [],
|
||||
"rounded-bl": [],
|
||||
},
|
||||
},
|
||||
border: {
|
||||
"border-x": {
|
||||
"border-l": [],
|
||||
"border-r": [],
|
||||
},
|
||||
"border-y": {
|
||||
"border-t": [],
|
||||
"border-b": [],
|
||||
},
|
||||
},
|
||||
scale: {
|
||||
"scale-x": [],
|
||||
"scale-y": [],
|
||||
},
|
||||
inset: {
|
||||
"inset-x": {
|
||||
left: [],
|
||||
right: [],
|
||||
},
|
||||
"inset-y": {
|
||||
top: [],
|
||||
bottom: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
appendClassName(className: string) {
|
||||
const { value, classPrefix } = this.parseTailwindClass(className);
|
||||
|
||||
if (!value || !this.recursiveSetValue(classPrefix, value, this.map)) {
|
||||
this.resolvedClasses.push(className);
|
||||
}
|
||||
}
|
||||
|
||||
reduce() {
|
||||
for (const [mapKey, mapValue] of Object.entries(this.map)) {
|
||||
for (const value of this.recursiveResolveClasses(
|
||||
mapValue,
|
||||
this.resolvedClasses
|
||||
).keys()) {
|
||||
this.resolvedClasses.push(this.toTailwindClass(mapKey, value));
|
||||
}
|
||||
}
|
||||
|
||||
return this.resolvedClasses;
|
||||
}
|
||||
|
||||
protected recursiveSetValue(
|
||||
key: string,
|
||||
value: string,
|
||||
targetObject: Record<string, any>
|
||||
) {
|
||||
for (const objectKey in targetObject) {
|
||||
if (!Object.prototype.hasOwnProperty.call(targetObject, objectKey)) continue;
|
||||
|
||||
const objectValue = targetObject[objectKey];
|
||||
|
||||
if (objectKey === key) {
|
||||
if (isObject(objectValue)) {
|
||||
this.recursiveSetValueToAllKeys(value, objectValue);
|
||||
} else if (Array.isArray(objectValue)) {
|
||||
objectValue.push(value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isObject(objectValue)) {
|
||||
const isSet = this.recursiveSetValue(key, value, objectValue);
|
||||
|
||||
if (isSet) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected recursiveSetValueToAllKeys(value: string, targetObject: Record<string, any>) {
|
||||
for (const key of Object.keys(targetObject)) {
|
||||
this.recursiveSetValue(key, value, targetObject);
|
||||
}
|
||||
}
|
||||
|
||||
protected recursiveResolveClasses(
|
||||
targetObject: Record<string, any>,
|
||||
resolvedClasses: string[]
|
||||
) {
|
||||
let commonValuesMap: null | Map<string, string> = null;
|
||||
|
||||
const intersectCommonValues = (valuesMap: Map<string, string>) => {
|
||||
if (commonValuesMap == null) {
|
||||
commonValuesMap = valuesMap;
|
||||
} else {
|
||||
for (const [commonValue, commonClassPrefix] of commonValuesMap) {
|
||||
const classPrefix = valuesMap.get(commonValue);
|
||||
if (classPrefix) {
|
||||
commonValuesMap?.set(commonValue, classPrefix);
|
||||
} else {
|
||||
commonValuesMap?.delete(commonValue);
|
||||
resolvedClasses.push(this.toTailwindClass(commonClassPrefix, commonValue));
|
||||
}
|
||||
}
|
||||
|
||||
for (const [value, classPrefix] of valuesMap) {
|
||||
if (commonValuesMap?.has(value)) {
|
||||
commonValuesMap.set(value, classPrefix);
|
||||
} else {
|
||||
resolvedClasses.push(this.toTailwindClass(classPrefix, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (const [currentClassPrefix, objectValue] of Object.entries(targetObject)) {
|
||||
if (isObject(objectValue)) {
|
||||
const commonValuesMap = this.recursiveResolveClasses(
|
||||
objectValue,
|
||||
resolvedClasses
|
||||
);
|
||||
for (const key of commonValuesMap.keys()) {
|
||||
commonValuesMap.set(key, currentClassPrefix);
|
||||
}
|
||||
intersectCommonValues(commonValuesMap);
|
||||
} else if (Array.isArray(objectValue)) {
|
||||
intersectCommonValues(
|
||||
new Map(objectValue.map(value => [value, currentClassPrefix]))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return commonValuesMap || new Map<string, string>();
|
||||
}
|
||||
|
||||
protected toTailwindClass(classPrefix: string, value: any) {
|
||||
if (typeof value !== "string") {
|
||||
value = value == null ? "" : value.toString();
|
||||
}
|
||||
|
||||
if (value.startsWith("-")) {
|
||||
value = value.slice(1);
|
||||
classPrefix = `-${classPrefix}`;
|
||||
}
|
||||
|
||||
return `${classPrefix}-${value}`;
|
||||
}
|
||||
|
||||
protected parseTailwindClass(tailwindClass: string) {
|
||||
const isNegativeValue = tailwindClass.startsWith("-");
|
||||
if (isNegativeValue) {
|
||||
tailwindClass = tailwindClass.slice(1);
|
||||
}
|
||||
|
||||
const lastDashIndex = tailwindClass.lastIndexOf("-");
|
||||
if (lastDashIndex === -1) {
|
||||
return {
|
||||
value: null,
|
||||
classPrefix: tailwindClass,
|
||||
};
|
||||
}
|
||||
|
||||
const classPrefix = tailwindClass.slice(0, lastDashIndex);
|
||||
const absoluteValue = tailwindClass.slice(lastDashIndex + 1);
|
||||
|
||||
return {
|
||||
value: isNegativeValue ? `-${absoluteValue}` : absoluteValue,
|
||||
classPrefix,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function reduceTailwindClasses(tailwindClasses: string[]) {
|
||||
const manager = new TailwindClassesReductionManager();
|
||||
|
||||
for (const className of tailwindClasses) {
|
||||
manager.appendClassName(className);
|
||||
}
|
||||
|
||||
return manager.reduce();
|
||||
}
|
||||
|
||||
function isObject(value: any): value is Record<keyof any, any> {
|
||||
return value && typeof value === "object" && !Array.isArray(value);
|
||||
}
|
@ -6,7 +6,7 @@ import type * as esbuild from "esbuild";
|
||||
import { transformSync } from "@babel/core";
|
||||
|
||||
/**
|
||||
* An esbuild plugin that processes files with Babel if `getPlugins` returns any plugins.
|
||||
* An esbuild plugin that processes files with Babel if `plugins` is not empty.
|
||||
*/
|
||||
export const babelPlugin = ({
|
||||
filter = /\.[jt]sx?$/,
|
||||
@ -36,6 +36,7 @@ export const babelPlugin = ({
|
||||
|
||||
const { code } = transformSync(load(), {
|
||||
parserOpts: {
|
||||
createImportExpressions: true,
|
||||
plugins: [
|
||||
"jsx",
|
||||
"decorators",
|
||||
|
@ -28,7 +28,7 @@ export const esbuildPlugin = (styleMap: StyleMap, compile: Compile): esbuild.Plu
|
||||
build.onLoad({ filter: /.*/, namespace: ESBUILD_NAMESPACE }, async ({ path }) => {
|
||||
if (path === "directive:base") {
|
||||
return {
|
||||
contents: (await compile("@tailwind base")).css,
|
||||
contents: await compile("@tailwind base"),
|
||||
loader: "css",
|
||||
};
|
||||
}
|
||||
@ -40,7 +40,7 @@ export const esbuildPlugin = (styleMap: StyleMap, compile: Compile): esbuild.Plu
|
||||
try {
|
||||
const result = await compile(toCSSText(styles));
|
||||
return {
|
||||
contents: result.css,
|
||||
contents: result,
|
||||
loader: "css",
|
||||
};
|
||||
} catch (e) {
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* eslint-disable unicorn/string-content */
|
||||
import { promises as fs } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import { type BuildOptions, type OutputFile, build, transformSync } from "esbuild";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import * as esbuild from "esbuild";
|
||||
import dedent from "dedent";
|
||||
import { name } from "../package.json" with { type: "json" };
|
||||
import {
|
||||
@ -24,8 +25,9 @@ describe("babel-tailwind", () => {
|
||||
});
|
||||
|
||||
it("supports ESBuild", async () => {
|
||||
const outputFiles = await compileESBuild({
|
||||
const { files } = await compileESBuild({
|
||||
clsx: "emotion",
|
||||
expectFiles: 2,
|
||||
javascript: /* tsx */ `
|
||||
export function Hello() {
|
||||
return (
|
||||
@ -36,20 +38,17 @@ describe("babel-tailwind", () => {
|
||||
}
|
||||
`,
|
||||
});
|
||||
expect(outputFiles).toHaveLength(2);
|
||||
|
||||
const js = findByExt(outputFiles, ".js");
|
||||
const css = findByExt(outputFiles, ".css");
|
||||
|
||||
const clsName = getClassName("text-center");
|
||||
expect(js.text).toContain(`className: "${clsName}"`);
|
||||
expect(css.text).toMatch(`.${clsName} {\n text-align: center;\n}`);
|
||||
expect(files.js.text).toContain(`className: "${clsName}"`);
|
||||
expect(files.css.text).toMatch(`.${clsName} {\n text-align: center;\n}`);
|
||||
});
|
||||
|
||||
it("does not remove the attribute if `preserveAttribute` is true", async () => {
|
||||
const outputFiles = await compileESBuild({
|
||||
const { files } = await compileESBuild({
|
||||
clsx: "emotion",
|
||||
jsxAttributeAction: "preserve",
|
||||
expectFiles: 2,
|
||||
javascript: /* tsx */ `
|
||||
export function Hello() {
|
||||
return (
|
||||
@ -60,10 +59,52 @@ describe("babel-tailwind", () => {
|
||||
}
|
||||
`,
|
||||
});
|
||||
expect(outputFiles).toHaveLength(2);
|
||||
|
||||
const js = findByExt(outputFiles, ".js");
|
||||
expect(js.text).toContain(`css: "text-center"`);
|
||||
expect(files.js.text).toContain(`css: "text-center"`);
|
||||
});
|
||||
|
||||
describe('merges with existing "className" attribute', () => {
|
||||
it("string literal", async () => {
|
||||
const { files } = await compileESBuild({
|
||||
clsx: "emotion",
|
||||
expectFiles: 2,
|
||||
javascript: /* tsx */ `
|
||||
export function Hello() {
|
||||
return (
|
||||
<div className="text-center" css="text-center">
|
||||
Hello, world!
|
||||
</div>
|
||||
);
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
const clsName = getClassName("text-center");
|
||||
expect(files.js.text).toContain(`className: "text-center ${clsName}"`);
|
||||
expect(files.css.text).toMatch(`.${clsName} {\n text-align: center;\n}`);
|
||||
});
|
||||
|
||||
it("existing function", async () => {
|
||||
const { files } = await compileESBuild({
|
||||
clsx: "emotion",
|
||||
expectFiles: 2,
|
||||
javascript: /* tsx */ `
|
||||
export function Hello() {
|
||||
return (
|
||||
<div className={({ isEntering }) => isEntering ? "enter" : "exit"} css="text-center">
|
||||
Hello, world!
|
||||
</div>
|
||||
);
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
const clsName = getClassName("text-center");
|
||||
expect(files.js.text).toContain(
|
||||
`className: ({\n isEntering\n }) => _cx(isEntering ? "enter" : "exit", "${clsName}")`
|
||||
);
|
||||
expect(files.css.text).toMatch(`.${clsName} {\n text-align: center;\n}`);
|
||||
});
|
||||
});
|
||||
|
||||
it("reports errors with correct position", async () => {
|
||||
@ -98,9 +139,10 @@ describe("babel-tailwind", () => {
|
||||
});
|
||||
|
||||
it("supports custom jsxAttributeName", async () => {
|
||||
const outputFiles = await compileESBuild({
|
||||
const { files } = await compileESBuild({
|
||||
clsx: "emotion",
|
||||
jsxAttributeName: "tw",
|
||||
expectFiles: 2,
|
||||
javascript: /* tsx */ `
|
||||
export function Hello() {
|
||||
return (
|
||||
@ -111,34 +153,29 @@ describe("babel-tailwind", () => {
|
||||
}
|
||||
`,
|
||||
});
|
||||
expect(outputFiles).toHaveLength(2);
|
||||
|
||||
const js = findByExt(outputFiles, ".js");
|
||||
const css = findByExt(outputFiles, ".css");
|
||||
|
||||
const clsName = getClassName("text-center");
|
||||
expect(js.text).toContain(`className: "${clsName}"`);
|
||||
expect(css.text).toMatch(`.${clsName} {\n text-align: center;\n}`);
|
||||
expect(files.js.text).toContain(`className: "${clsName}"`);
|
||||
expect(files.css.text).toMatch(`.${clsName} {\n text-align: center;\n}`);
|
||||
});
|
||||
|
||||
it("supports importing tailwind/base", async () => {
|
||||
const postcss = createPostCSS({ tailwindConfig: {} });
|
||||
const base = (await postcss("@tailwind base;")).css;
|
||||
const outputFiles = await compileESBuild({
|
||||
const postcss = createPostCSS({
|
||||
tailwindConfig: {},
|
||||
postCSSPlugins: [],
|
||||
directives: [],
|
||||
});
|
||||
const base = await postcss("@tailwind base;");
|
||||
const { files } = await compileESBuild({
|
||||
clsx: "emotion",
|
||||
expectFiles: 2,
|
||||
javascript: /* tsx */ `
|
||||
import "${name}/base";
|
||||
`,
|
||||
});
|
||||
expect(outputFiles).toHaveLength(2);
|
||||
|
||||
const js = findByExt(outputFiles, ".js");
|
||||
const css = findByExt(outputFiles, ".css");
|
||||
|
||||
// expect(js.text).toContain(`import "./base.css";`);
|
||||
expect(js.text).toBe("");
|
||||
|
||||
expect(minCSS(css.text)).toContain(minCSS(base));
|
||||
expect(files.js.text).toBe("");
|
||||
expect(minCSS(files.css.text)).toContain(minCSS(base));
|
||||
});
|
||||
});
|
||||
|
||||
@ -149,37 +186,48 @@ async function write(path: string, content: string) {
|
||||
}
|
||||
|
||||
const minCSS = (text: string) =>
|
||||
transformSync(text, { minify: true, loader: "css" }).code;
|
||||
esbuild.transformSync(text, { minify: true, loader: "css" }).code;
|
||||
|
||||
const findByExt = (outputFiles: OutputFile[], ext: string) =>
|
||||
const findByExt = (outputFiles: esbuild.OutputFile[], ext: string) =>
|
||||
outputFiles.find(file => file.path.endsWith(ext))!;
|
||||
|
||||
async function compileESBuild({
|
||||
javascript,
|
||||
esbuild,
|
||||
esbuild: esbuildOptions,
|
||||
expectFiles,
|
||||
...options
|
||||
}: TailwindPluginOptions & {
|
||||
esbuild?: BuildOptions;
|
||||
esbuild?: esbuild.BuildOptions;
|
||||
javascript: string;
|
||||
expectFiles?: number;
|
||||
}) {
|
||||
const tailwind = getTailwindPlugins({
|
||||
tailwindConfig: {},
|
||||
...options,
|
||||
});
|
||||
const result = await build({
|
||||
const result = await esbuild.build({
|
||||
bundle: true,
|
||||
write: false,
|
||||
external: ["react/jsx-runtime"],
|
||||
external: ["react/jsx-runtime", "@emotion/css", "clsx"],
|
||||
outdir: "dist",
|
||||
format: "esm",
|
||||
entryPoints: [await write("index.tsx", dedent(javascript))],
|
||||
plugins: [babelPlugin({ plugins: [tailwind.babel] }), tailwind.esbuild],
|
||||
...esbuild,
|
||||
plugins: [babelPlugin({ plugins: [tailwind.babel()] }), tailwind.esbuild()],
|
||||
...esbuildOptions,
|
||||
});
|
||||
|
||||
const { errors, warnings, outputFiles } = result;
|
||||
expect(errors).toHaveLength(0);
|
||||
expect(warnings).toHaveLength(0);
|
||||
|
||||
return outputFiles!;
|
||||
if (expectFiles != null) {
|
||||
expect(outputFiles).toHaveLength(expectFiles);
|
||||
}
|
||||
|
||||
return {
|
||||
outputFiles: outputFiles!,
|
||||
files: new Proxy({} as Record<string, esbuild.OutputFile>, {
|
||||
get: (_, ext: string) => findByExt(outputFiles!, ext),
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
46
src/index.ts
46
src/index.ts
@ -2,7 +2,7 @@ import hash from "@emotion/hash";
|
||||
import type { Config } from "tailwindcss";
|
||||
import type postcss from "postcss";
|
||||
import { memoize } from "lodash";
|
||||
import { babelTailwind } from "./babel-tailwind";
|
||||
import { type ClassNameCollector, babelTailwind } from "./babel-tailwind";
|
||||
import { esbuildPlugin } from "./esbuild-postcss";
|
||||
import { vitePlugin } from "./vite-plugin";
|
||||
import { type StyleMap, createPostCSS, type tailwindDirectives } from "./shared";
|
||||
@ -27,7 +27,7 @@ export interface TailwindPluginOptions {
|
||||
/**
|
||||
* Directives to prefix to all Tailwind stylesheets
|
||||
*/
|
||||
directives?: (typeof tailwindDirectives)[number][] | "all";
|
||||
directives?: (typeof tailwindDirectives)[number][] | "all" | undefined;
|
||||
|
||||
/**
|
||||
* Additional PostCSS plugins (optional)
|
||||
@ -53,7 +53,7 @@ export interface TailwindPluginOptions {
|
||||
* declare const tw: TaggedTailwindFunction;
|
||||
* "tw" => tw`p-2 text-center`
|
||||
*/
|
||||
taggedTemplateName?: string;
|
||||
taggedTemplateName?: string | undefined;
|
||||
|
||||
/**
|
||||
* The prefix to use for the generated class names.
|
||||
@ -65,8 +65,22 @@ export interface TailwindPluginOptions {
|
||||
* Preferred library for classnames
|
||||
*/
|
||||
clsx: "clsx" | "classnames" | "emotion";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
styleMap?: StyleMap;
|
||||
|
||||
/**
|
||||
* Custom CSS compile function
|
||||
* @example
|
||||
* async css => (await postcss.process(css, { plugins: [tailwindcss()] })).css
|
||||
*/
|
||||
compile(css: string): Promise<string>;
|
||||
}
|
||||
|
||||
export type ResolveTailwindOptions = Required<TailwindPluginOptions>;
|
||||
|
||||
/**
|
||||
* Hashes and prefixes a string of Tailwind class names.
|
||||
* @example getClassName("p-2 text-center") // "tw-1r6fxxz"
|
||||
@ -90,15 +104,31 @@ export const getClassName: GetClassName = cls => "tw-" + hash(cls);
|
||||
* });
|
||||
*/
|
||||
export function getTailwindPlugins(options: TailwindPluginOptions) {
|
||||
const styleMap: StyleMap = new Map();
|
||||
const compile = memoize(createPostCSS(options));
|
||||
const resolvedOptions: ResolveTailwindOptions = {
|
||||
directives: undefined,
|
||||
getClassName,
|
||||
jsxAttributeAction: "delete",
|
||||
jsxAttributeName: "css",
|
||||
postCSSPlugins: [],
|
||||
styleMap: new Map(),
|
||||
taggedTemplateName: undefined,
|
||||
tailwindConfig: {},
|
||||
...options,
|
||||
};
|
||||
|
||||
const getCompiler = () => createPostCSS(resolvedOptions);
|
||||
|
||||
const { styleMap } = resolvedOptions;
|
||||
const compile = options.compile ?? memoize(getCompiler());
|
||||
|
||||
return {
|
||||
compile,
|
||||
babel: babelTailwind(styleMap, options),
|
||||
esbuild: esbuildPlugin(styleMap, compile),
|
||||
vite: vitePlugin(styleMap, compile),
|
||||
babel: (onCollect?: ClassNameCollector) => babelTailwind(resolvedOptions, onCollect),
|
||||
esbuild: () => esbuildPlugin(styleMap, compile),
|
||||
vite: () => vitePlugin(styleMap, compile),
|
||||
styleMap,
|
||||
options,
|
||||
getCompiler,
|
||||
[Symbol.dispose]() {
|
||||
styleMap.clear();
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
import tailwind from "tailwindcss";
|
||||
import postcss from "postcss";
|
||||
import type { TailwindPluginOptions } from "./index";
|
||||
import type { ResolveTailwindOptions } from "./index";
|
||||
|
||||
export const { name: pkgName } = [require][0](
|
||||
process.env.BABEL_TAILWIND_BUILD ? "./package.json" : "../package.json"
|
||||
@ -30,9 +30,9 @@ export type StyleMap = Map</* filename */ string, StyleMapEntry[]>;
|
||||
|
||||
export function createPostCSS({
|
||||
tailwindConfig,
|
||||
postCSSPlugins = [],
|
||||
postCSSPlugins,
|
||||
directives,
|
||||
}: Pick<TailwindPluginOptions, "tailwindConfig" | "postCSSPlugins" | "directives">) {
|
||||
}: Pick<ResolveTailwindOptions, "tailwindConfig" | "postCSSPlugins" | "directives">) {
|
||||
const post = postcss([
|
||||
tailwind({
|
||||
...tailwindConfig,
|
||||
@ -44,7 +44,10 @@ export function createPostCSS({
|
||||
const appliedDirectives = directives === "all" ? tailwindDirectives : directives;
|
||||
const directiveTexts = appliedDirectives?.map(d => `@tailwind ${d};\n`).join("") ?? "";
|
||||
|
||||
return (css: string) => post.process(directiveTexts + css, { from: undefined });
|
||||
return async (css: string) => {
|
||||
const result = await post.process(directiveTexts + css, { from: undefined });
|
||||
return result.css;
|
||||
};
|
||||
}
|
||||
|
||||
export type Compile = ReturnType<typeof createPostCSS>;
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { dirname, join } from "node:path";
|
||||
import type * as vite from "vite";
|
||||
import { memoize } from "lodash";
|
||||
import { type Compile, type StyleMap, pkgName, toCSSText } from "./shared";
|
||||
|
||||
const ROLLUP_PREFIX = "\0tailwind:";
|
||||
@ -29,12 +28,11 @@ export const vitePlugin = (styleMap: StyleMap, compile: Compile): vite.Plugin =>
|
||||
if (id.startsWith(ROLLUP_PREFIX)) {
|
||||
const resolved = id.slice(ROLLUP_PREFIX.length);
|
||||
if (resolved === "directive:base") {
|
||||
return (await compile("@tailwind base")).css;
|
||||
return await compile("@tailwind base");
|
||||
}
|
||||
|
||||
if (styleMap.has(resolved)) {
|
||||
const result = await compile(toCSSText(styleMap.get(resolved)!));
|
||||
return result.css;
|
||||
return await compile(toCSSText(styleMap.get(resolved)!));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -4,6 +4,7 @@
|
||||
"allowArbitraryExtensions": true,
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"jsx": "react-jsx",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
|
Loading…
x
Reference in New Issue
Block a user