Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 新增file文件 #2865

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
"packages/taro-with-weapp",
"packages/taroize",
"packages/stylelint-taro-rn",
"packages/stylelint-config-taro-rn"
"packages/stylelint-config-taro-rn",
"packages/taro-css-to-react-native"
],
"command": {
"publish": {
Expand Down
3 changes: 3 additions & 0 deletions packages/css-to-react-native/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env"]
}
196 changes: 196 additions & 0 deletions packages/css-to-react-native/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
# taro-css-to-react-native

fork from [css-to-react-native-transform](https://github.com/kristerkari/css-to-react-native-transform)

A lightweight wrapper on top of
[css-to-react-native](https://github.com/styled-components/css-to-react-native)
to allow valid CSS to be turned into React Native Stylesheet objects.

To keep things simple it only transforms class selectors (e.g. `.myClass {}`) and grouped class selectors (e.g. `.myClass, .myOtherClass {}`). Parsing of more complex selectors can be added as a new feature behind a feature flag (e.g. `transform(css, { parseAllSelectors: true })`) in the future if needed.

Example:

```css
.myClass {
font-size: 18px;
line-height: 24px;
color: red;
}

.other {
padding: 1rem;
}
```

is transformed to:

```js
{
myClass: {
fontSize: 18,
lineHeight: 24,
color: "red"
},
other: {
paddingBottom: 16,
paddingLeft: 16,
paddingRight: 16,
paddingTop: 16
}
}
```

## API

### Transform CSS

```js
import transform from "taro-css-to-react-native";
// or const transform = require("taro-css-to-react-native").default;

transform(`
.foo {
color: #f00;
}
`);
```

↓ ↓ ↓ ↓ ↓ ↓

```js
{
foo: {
color: "#f00";
}
}
```

### CSS Modules :export block

Parsing the [CSS Modules (ICSS) :export](https://github.com/css-modules/icss#export) is supported. The `:export` is often used to share variables from CSS or from a preprocessor like Sass/Less/Stylus to Javascript:

```js
transform(`
.foo {
color: #f00;
}

:export {
myProp: #fff;
}
`);
```

↓ ↓ ↓ ↓ ↓ ↓

```js
{
foo: {
color: "#f00";
},
myProp: "#fff";
}
```

### CSS Media Queries (experimental)

_The API and parsed syntax for CSS Media Queries might change in the future_

```js
transform(
`
.container {
background-color: #f00;
}

@media (orientation: landscape) {
.container {
background-color: #00f;
}
}
`,
{ parseMediaQueries: true },
);
```

↓ ↓ ↓ ↓ ↓ ↓

```js
{
__mediaQueries: {
"@media (orientation: landscape)": [{
expressions: [
{
feature: "orientation",
modifier: undefined,
value: "landscape",
},
],
inverse: false,
type: "all",
}],
},
container: {
backgroundColor: "#f00",
},
"@media (orientation: landscape)": {
container: {
backgroundColor: "#00f",
},
},
}
```

You can also speficy a platform as the media query type ("android", "dom", "ios", "macos", "web", "windows"):

```js
transform(
`
.container {
background-color: #f00;
}

@media android and (orientation: landscape) {
.container {
background-color: #00f;
}
}
`,
{ parseMediaQueries: true },
);
```

### CSS Viewport Units (experimental)

When [CSS Viewport Units](https://caniuse.com/#feat=viewport-units) are used, a special `__viewportUnits` feature flag is added to the result. This is done so that the implementation that transforms viewport units to pixels knows that the style object has viewport units inside it, and can avoid doing extra work if the style object does not contain any viewport units.

```js
transform(`.foo { font-size: 1vh; }`);
```

↓ ↓ ↓ ↓ ↓ ↓

```js
{
__viewportUnits: true,
foo: {
fontSize: "1vh";
}
}
```

## Limitations

- For `rem` unit the root element `font-size` is currently set to 16 pixels. A
setting needs to be implemented to allow the user to define the root element
`font-size`.
- There is also support for the `box-shadow` shorthand, and this converts into
`shadow-` properties. Note that these only work on iOS.

## Dependencies

This library has the following packages as dependencies:

- [css](https://github.com/reworkcss/css#readme) - CSS parser / stringifier
- [css-mediaquery](https://github.com/ericf/css-mediaquery) - Parses and determines if a given CSS Media Query matches a set of values.
- [css-to-react-native](https://github.com/styled-components/css-to-react-native) - Convert CSS text to a React Native stylesheet object
3 changes: 3 additions & 0 deletions packages/css-to-react-native/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function transform(css: string, options?: {
parseMediaQueries?: boolean;
}): { [selector: string]: unknown; };
82 changes: 82 additions & 0 deletions packages/css-to-react-native/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"name": "taro-css-to-react-native",
"description": "Convert CSS text to a React Native stylesheet object",
"version": "1.9.0",
"main": "dist/index.js",
"license": "MIT",
"scripts": {
"prettify": "prettier --write '**/*.@(js|json|md)'",
"precommit": "lint-staged",
"build": "babel src --ignore *.spec.js --out-dir dist",
"test": "jest --coverage",
"prepublish": "npm run build",
"release": "npmpub"
},
"devDependencies": {
"@babel/cli": "^7.2.3",
"@babel/core": "^7.3.4",
"@babel/preset-env": "^7.3.4",
"babel-jest": "^24.3.1",
"coveralls": "^3.0.3",
"husky": "^1.3.1",
"jest": "^24.3.1",
"lint-staged": "^8.1.5",
"npmpub": "^4.1.0",
"prettier": "^1.16.4"
},
"jest": {
"transform": {
"^.+\\.jsx?$": "babel-jest"
},
"coverageDirectory": "./.coverage/",
"coverageReporters": [
"lcov",
"text"
],
"coverageThreshold": {
"global": {
"branches": 75,
"functions": 75,
"lines": 75,
"statements": 75
}
},
"testPathIgnorePatterns": [
"<rootDir>/dist",
"<rootDir>/node_modules"
]
},
"lint-staged": {
"*.{js,json,md}": [
"prettier --write",
"git add"
]
},
"prettier": {
"trailingComma": "all"
},
"dependencies": {
"camelize": "^1.0.0",
"css": "^2.2.4",
"css-mediaquery": "^0.1.2",
"css-color-keywords": "^1.0.0",
"postcss-value-parser": "^3.3.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/NervJS/taro.git"
},
"keywords": [
"React",
"ReactNative",
"styles",
"CSS"
],
"files": [
"dist",
"src",
"index.d.ts",
"CHANGELOG.md",
"README.md"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
const SYMBOL_MATCH = "SYMBOL_MATCH";

export default class TokenStream {
constructor(nodes, parent) {
this.index = 0;
this.nodes = nodes;
this.functionName = parent != null ? parent.value : null;
this.lastValue = null;
this.rewindIndex = -1;
}

hasTokens() {
return this.index <= this.nodes.length - 1;
}

[SYMBOL_MATCH](...tokenDescriptors) {
if (!this.hasTokens()) return null;

const node = this.nodes[this.index];

for (let i = 0; i < tokenDescriptors.length; i += 1) {
const tokenDescriptor = tokenDescriptors[i];
const value = tokenDescriptor(node);
if (value !== null) {
this.index += 1;
this.lastValue = value;
return value;
}
}

return null;
}

matches(...tokenDescriptors) {
return this[SYMBOL_MATCH](...tokenDescriptors) !== null;
}

expect(...tokenDescriptors) {
const value = this[SYMBOL_MATCH](...tokenDescriptors);
return value !== null ? value : this.throw();
}

matchesFunction() {
const node = this.nodes[this.index];
if (node.type !== "function") return null;
const value = new TokenStream(node.nodes, node);
this.index += 1;
this.lastValue = null;
return value;
}

expectFunction() {
const value = this.matchesFunction();
return value !== null ? value : this.throw();
}

expectEmpty() {
if (this.hasTokens()) this.throw();
}

throw() {
throw new Error(`Unexpected token type: ${this.nodes[this.index].type}`);
}

saveRewindPoint() {
this.rewindIndex = this.index;
}

rewind() {
if (this.rewindIndex === -1) throw new Error("Internal error");
this.index = this.rewindIndex;
this.lastValue = null;
}
}
Loading