diff --git a/README.md b/README.md index 3df48b5..140e070 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,8 @@ Quick Reference [Stylus](./docs/stylus.md)<!--rehype:style=background: rgb(109 161 63);&class=tag&data-lang=CSS--> [Sass](./docs/sass.md)<!--rehype:style=background: rgb(207 100 154);&class=tag&data-lang=CSS--> [Less.js](./docs/lessjs.md)<!--rehype:style=background: rgb(29 54 93);&class=tag&data-lang=CSS--> -[Tailwind CSS](./docs/tailwindcss.md)<!--rehype:style=background: rgb(49 120 198);--> +[Tailwind CSS](./docs/tailwindcss.md)<!--rehype:style=background: rgb(49 120 198);&class=tag&data-lang=CSS--> +[StyleX](./docs/stylex.md)<!--rehype:style=background: rgb(91 79 163);&class=tag&data-lang=CSS--> <!--rehype:class=home-card--> ## Nodejs diff --git a/assets/stylex.svg b/assets/stylex.svg new file mode 100644 index 0000000..54cc442 --- /dev/null +++ b/assets/stylex.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" height="1em" width="1em" viewBox="0 0 151 180"><g fill="none"><path fill="#5BD3F3" d="M123.054863 93.4254443C124.041858 95.7626109 128.450105 105.044084 129.355779 107.321152 123.84289 116.561307 122.549601 118.95899 111.024753 133.60593 64.1232983 182.705627 27.9371992 190.639891 5.76263041 167.701852 3.59627766 165.361764 1.67512566 162.319274 0 158.574382.471825684 159.433291 1.09514745 160.379843 1.86996531 161.414039L2.15025371 161.78256C2.19772524 161.844746 2.24602235 161.906931 2.29473227 161.969534L2.59359648 162.349323 2.90484457 162.735791 3.22888933 163.12977 3.56531797 163.530845 3.91454328 163.939431 4.27615246 164.355113 4.65014553 164.77789 5.03734806 165.208179 5.23549007 165.426036 5.64126842 165.867176 5.84890474 166.090459 6.2732589 166.542451 6.49038953 166.771159C33.8818726 191.84228 61.2048315 170.332834 98.3027967 128.773838 103.902786 122.190123 112.153337 110.407464 123.054863 93.4254443ZM137.380118 14.1032604C154.739423 29.1884191 154.739423 52.5968124 141.717364 86.0295639 140.719637 83.5713654 136.323774 73.7444144 135.221609 71.226952 145.472981 42.8320467 145.710752 29.3332399 130.967334 15.8715774 122.485617 8.12762615 116.462513 7.80876984 104.995043 9.69477985L104.244168 9.82123726C104.118678 9.84252217 103.992775 9.86464178 103.866872 9.8867614L103.107328 10.0236526 102.342004 10.1663867 101.956866 10.2402579 92.9145722 12.0507273 92.9145722 12.0340333 93.1139526 11.9605794C111.260459 5.27670019 126.843916 4.74249067 137.380118 14.1032604L137.380118 14.1032604Z"/><path fill="#D573DE" d="M125.890167,63.5141248 C153.449324,115.583313 155.188797,143.75817 146.009025,163.468062 C142.702042,170.570383 134.455253,175.478804 130.907687,177.387749 C122.003636,182.178957 103.568032,179.793293 87.0876824,174.955283 L84.6173661,173.901615 C92.8984649,176.570162 110.89548,180.056296 120.598168,177.387749 C152.463016,168.623747 148.671973,130.669324 116.64467,71.0621007 C84.6173661,11.4548774 49.5757474,-4.8960329 21.9537585,6.3426811 C19.3015581,7.42161421 16.9891503,8.8960871 15,10.7226111 L15.212887,10.4952275 L15.6399012,10.0462588 L15.853615,9.82508786 L16.282696,9.38854448 C19.3635641,6.29215141 22.5576963,3.87542408 25.8493845,2.76294257 C50.8282672,-5.6788289 93.7099159,2.71324123 125.890167,63.5141248 Z"/></g></svg> \ No newline at end of file diff --git a/docs/quickreference.md b/docs/quickreference.md index 7fb2ce8..c04ba83 100644 --- a/docs/quickreference.md +++ b/docs/quickreference.md @@ -1009,7 +1009,7 @@ H2 部分 - 5列效果展示 ... ``` -[#示例](https://github.com/jaywcjlove/reference/blob/ee03850619440e3700ed68ccc2ed21d3591a1490/docs/quickreference.md?plain=1#L1063-L1077)<!--rehype:target=__blank--> +[#示例](https://github.com/jaywcjlove/reference/blob/ee03850619440e3700ed68ccc2ed21d3591a1490/docs/quickreference.md?plain=1#L986-L991)<!--rehype:target=__blank--> ### Two diff --git a/docs/stylex.md b/docs/stylex.md new file mode 100644 index 0000000..31132c5 --- /dev/null +++ b/docs/stylex.md @@ -0,0 +1,1046 @@ +StyleX 备忘清单 +==== + +这是 [StyleX](https://github.com/facebook/stylex) 用户界面的样式系统的快速参考指南备忘单 + +入门 StyleX +--- + +### 介绍 +<!--rehype:wrap-class=row-span-2--> + +StyleX 是一个 CSS In JS 的用户界面的样式系统 + +- [StyleX Intellisense](https://marketplace.visualstudio.com/items?itemName=yash-singh.stylex) _VSCode 插件_ + +#### Vite +<!--rehype:style=text-align: left;color: var(--primary-color)--> + +- [vite-plugin-stylex](https://www.npmjs.com/package/vite-plugin-stylex) +- [vite-plugin-stylex-dev](https://www.npmjs.com/package/vite-plugin-stylex-dev) + +#### Babel 插件 +<!--rehype:style=text-align: left;color: var(--primary-color)--> + +- [tailwind-to-stylex](https://www.npmjs.com/package/tailwind-to-stylex) 支持在 Tailwind CSS 中使用 +- [@stylex-extend/babel-plugin](https://github.com/nonzzz/stylex-extend/tree/main/packages/babel-plugin) 使用 JSX 属性定义 StyleX + +#### Prettier +<!--rehype:style=text-align: left;color: var(--primary-color)--> + +- [prettier-plugin-stylex-key-sort](https://github.com/nedjulius/prettier-plugin-stylex-key-sort) + +#### Bun +<!--rehype:style=text-align: left;color: var(--primary-color)--> + +- [bun-plugin-stylex](https://www.npmjs.com/package/bun-plugin-stylex) + +#### 入门模板 +<!--rehype:style=text-align: left;color: var(--primary-color)--> + +- [next.js](https://github.com/nmn/nextjs-app-dir-stylex) _支持 StyleX 的 next.js 项目_ +- [qwik](https://github.com/nmn/qwik-stylex) _使用 StyleX 和 tailwind-to-stylex 的 Qwik 项目_ +- [docusaurus 3](https://github.com/nmn/docusaurus-stylex) _支持 StyleX 的 docusaurus 3 项目_ +- [SvelteKit](https://github.com/nmn/sveltekit-stylex) _支持 StyleX 的 SvelteKit 项目_ + +### 配置编译器 + +```js +import plg from '@stylexjs/rollup-plugin'; + +const config = () => ({ + plugins: [ + plg({ ...options }) + ] +}) + +export default config; +``` + +### 使用样式 +<!--rehype:wrap-class=row-span-2--> + +```js +import * as React from 'react'; +import * as stylex from '@stylexjs/stylex'; + +const styles = stylex.create({ ... }); +const colorStyles = stylex.create({ ... }); +``` + +在 [React](./react.md) 中使用 + +```jsx +function ReactDemo( + { color,isActive,style } +) { + return ( + <div {...stylex.props( + styles.main, + // 有条件地应用样式 + isActive && styles.active, + // 根据属性选择样式变体 + colorStyles[color], + // 将样式作为 props 传递 + style, + )} + /> + ); +} +``` + +### 定义样式 + +```js +import * as stylex from '@stylexjs/stylex'; + +const styles = stylex.create({ + root: { + width: '100%', + maxWidth: 800, + minHeight: 40, + }, +}); +``` + +样式是使用对象语法和 `create()` API 定义的 + +安装 +---- +<!--rehype:body-class=cols-4--> + +### StyleX 运行时包 +<!--rehype:wrap-class=col-span-2--> + +```bash +npm install --save @stylexjs/stylex +``` + +### 编译器(生产) Rollup +<!--rehype:wrap-class=col-span-2 row-span-2--> + +```bash +npm install --save-dev @stylexjs/rollup-plugin +``` + +修改 Rollup 配置 _rollup.config.js_ + +```js +import stylexPlugin from '@stylexjs/rollup-plugin'; + +const config = { + input: './index.js', + output: { + file: './.build/bundle.js', + format: 'es', + }, + // 确保在 Babel 之前使用 stylex 插件 + plugins: [stylexPlugin({ + // 必需项。生成的 CSS 文件的文件路径。 + fileName: './.build/stylex.css', + // 默认值:false + dev: false, + // 所有生成的类名的前缀 + classNamePrefix: 'x', + // CSS 变量支持所必需 + unstable_moduleResolution: { + // 类型:'commonJS' | 'haste' + // 默认值:'commonJS' + type: 'commonJS', + // 项目根目录的绝对路径 + rootDir: __dirname, + }, + })], +}; + +export default config; +``` + +### 编译器(开发) +<!--rehype:wrap-class=col-span-2--> + +```bash +npm install --save-dev @stylexjs/babel-plugin +``` + +修改 Babel 配置 _(babel.config.js)_ + +```js +import styleX from '@stylexjs/babel-plugin'; + +const config = { + plugins: [ + [styleX, { + dev: true, + // 设置为 true 以进行快照测试 + // 默认值:false + test: false, + // CSS 变量支持所必需 + unstable_moduleResolution: { + // 类型:'commonJS' | 'haste' + // 默认值:'commonJS' + type: 'commonJS', + // 项目根目录的绝对路径 + rootDir: __dirname, + } + }], + ], +}; + +export default config; +``` + +### 编译器(生产) Webpack +<!--rehype:wrap-class=col-span-2--> + +```bash +npm install --save-dev @stylexjs/webpack-plugin +``` + +修改 Webpack 配置 _webpack.config.js_ + +```js +const StylexPlugin = require('@stylexjs/webpack-plugin'); +const path = require('path'); + +const config = (env, argv) => ({ + entry: { + main: './src/index.js', + }, + output: { + path: path.resolve(__dirname, '.build'), + filename: '[name].js', + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /node_modules/, + use: 'babel-loader', + }, + ], + }, + plugins: [ + // 确保在 Babel 之前使用 stylex 插件 + new StylexPlugin({ + filename: 'styles.[contenthash].css', + // 获取 webpack 的模式并为开发设置值 + dev: argv.mode === 'development', + // 使用静态生成的 CSS 文件,而不是运行时注入的 CSS。 + // 即使在开发环境中也是如此。 + runtimeInjection: false, + // 可选的。默认值:'x' + classNamePrefix: 'x', + // CSS 变量支持所必需 + unstable_moduleResolution: { + // 类型:'commonJS' | 'haste' + // 默认值:'commonJS' + type: 'commonJS', + // 项目根目录的绝对路径 + rootDir: __dirname, + }, + }), + ], + cache: true, +}); + +module.exports = config; +``` + +### 编译器(生产) Next.js +<!--rehype:wrap-class=col-span-2--> + +```bash +npm install --save-dev @stylexjs/nextjs-plugin \ + @stylexjs/babel-plugin rimraf +``` + +在 `package.json` 添加配置 + +```js +{ + "scripts": { + ..., + "predev": "rimraf .next", + "prebuild": "rimraf .next" + } +} +``` + +修改 Babel 配置 _.babelrc.js_ + +```js +module.exports = { + presets: ["next/babel"], + plugins: [ + [ + "@stylexjs/babel-plugin", { + dev: process.env.NODE_ENV === "development", + test: process.env.NODE_ENV === "test", + runtimeInjection: false, + genConditionalClasses: true, + treeshakeCompensation: true, + unstable_moduleResolution: { + type: "commonJS", + rootDir: __dirname, + }, + }, + ], + ], +}; +``` + +修改 Next.js 配置 _next.config.mjs_ + +```js +/** @type {import('next').NextConfig} */ +import stylexPlugin from "@stylexjs/nextjs-plugin"; + +const nextConfig = {}; + +const __dirname = new URL(".", import.meta.url).pathname; +export default stylexPlugin({ + rootDir: __dirname, +})(nextConfig); +``` + +### 仅限本地开发 +<!--rehype:wrap-class=col-span-2--> + +要开始使用 `StyleX` 而无需配置编译器和构建过程,您可以安装本地开发运行时 + +```bash +npm install --save-dev @stylexjs/dev-runtime +``` + +开发运行时必须导入到应用程序的 `JavaScript` 入口点并进行配置 + +```js +import inject from '@stylexjs/dev-runtime'; + +inject({ + classNamePrefix: 'x', + dev: true, + test: false, +}); +``` + +### 用 ESLint 捕捉错误 +<!--rehype:wrap-class=col-span-2--> + +```bash +npm install --save-dev @stylexjs/eslint-plugin +``` + +StyleX 编译器不会验证您的样式,并且会编译许多无效样式。当您创作样式时,您应该使用 ESLint 插件来捕获这些错误。修改 ESLint 配置 `.eslintrc.js` + +```js +module.exports = { + plugins: ["@stylexjs"], + rules: { + "@stylexjs/valid-styles": "error", + }, +}; +``` + +定义样式 +---- + +### 创建样式 + +```js +import * as stylex from '@stylexjs/stylex'; + +const styles = stylex.create({ + base: { + fontSize: 16, + lineHeight: 1.5, + color: 'rgb(60,60,60)', + }, + highlighted: { + color: 'rebeccapurple', + }, +}); +``` + +### 伪类 +<!--rehype:wrap-class=row-span-2--> + +```js +import * as stylex from '@stylexjs/stylex'; + +const styles = stylex.create({ + button: { + backgroundColor: 'lightblue', + }, +}); +``` + +样式名为 `button` 的背景样式上添加 `:hover` 和 `:active` 伪类 + +```js +import * as stylex from '@stylexjs/stylex'; + +const styles = stylex.create({ + button: { + backgroundColor: { + default: 'lightblue', + ':hover': 'blue', + ':active': 'darkblue', + }, + }, +}); +``` + +### 伪元素 +<!--rehype:wrap-class=row-span-2--> + +```js +import * as stylex from '@stylexjs/stylex'; + +const styles = stylex.create({ + input: { + // 伪元素 + '::placeholder': { + color: '#999', + }, + color: { + default: '#333', + // 伪类 + ':invalid': 'red', + }, + }, +}); +``` + +### 媒体查询(和其他@规则) + +```js +import * as stylex from '@stylexjs/stylex'; + +const styles = stylex.create({ + base: { + width: { + default: 800, + '@media (max-width: 800px)': '100%', + '@media (min-width: 1540px)': 1366, + }, + }, +}); +``` + +同样,媒体查询也可以作为样式值中的 "条件" + +### 组合条件 + +```js +import * as stylex from '@stylexjs/stylex'; + +const styles = stylex.create({ + button: { + color: { + default: 'var(--blue-link)', + ':hover': { + default: null, + '@media (hover: hover)': 'scale(1.1)', + }, + ':active': 'scale(0.9)', + }, + }, +}); +``` + +当您需要组合媒体查询和伪选择器时,嵌套超过`一层` + +### 后备样式 +<!--rehype:wrap-class=col-span-2--> + +```css +.header { + position: fixed; + position: -webkit-sticky; + position: sticky; +} +``` + +使用 `firstThatWorks` 函数来实现相同的目的 + +```js +import * as stylex from '@stylexjs/stylex'; + +const styles = stylex.create({ + header: { + position: stylex.firstThatWorks('sticky', '-webkit-sticky', 'fixed'), + }, +}); +``` + +### 关键帧动画 + +```js +import * as stylex from '@stylexjs/stylex'; + +const fadeIn = stylex.keyframes({ + from: {opacity: 0}, + to: {opacity: 1}, +}); + +const styles = stylex.create({ + base: { + animationName: fadeIn, + animationDuration: '1s', + }, +}); +``` + +使用 `stylex.keyframes()` 函数来定义关键帧动画 + +### 动态样式 +<!--rehype:wrap-class=col-span-2&style=background:#d7a100;--> + +```js +import * as stylex from '@stylexjs/stylex'; + +const styles = stylex.create({ + // 函数参数必须是简单标识符 + // -- 不允许解构或默认值 + bar: (height) => ({ + height, + // 函数体必须是对象字面量 + // -- 不允许使用 { return {} } + }), +}); + +function MyComponent() { + // `height` 的值在编译时不能确定。 + const [height, setHeight] = useState(10); + return <div {...stylex.props(styles.bar(height))} />; +} +``` + +注意:动态样式是一项高级功能,应谨慎使用。对于大多数用例,条件样式应该足够了。 + +使用样式 +---- + +### 合并样式 +<!--rehype:wrap-class=row-span-2--> + +```jsx +import * as stylex from '@stylexjs/stylex'; + +const styles = stylex.create({ + base: { + fontSize: 16, + lineHeight: 1.5, + color: 'grey', + }, + highlighted: { + color: 'rebeccapurple', + }, +}); + +<div {...stylex.props( + styles.base, styles.highlighted + )} +/>; +``` + +如果样式的顺序颠倒,文本将为灰色 + +```jsx +<div {...stylex.props( + styles.highlighted, styles.base + )} +/> +``` + +### 条件样式 + +```jsx +<div + {...stylex.props( + styles.base, + props.isHighlighted && styles.highlighted, + isActive ? styles.active : styles.inactive, + )} +/> +``` + +通过使用常见的 JavaScript 模式(例如三元表达式和 `&&` 运算符),可以在运行时有条件地应用样式。 `stylex.props` 忽略虚假值,例如 `null`、`undefined` 或 `false` + +### 样式变体 +<!--rehype:wrap-class=row-span-2--> + +```js +import * as stylex from '@stylexjs/stylex'; + +const styles = stylex.create({ + violet: { + backgroundColor: { + default: 'blueviolet', + ':hover': 'darkviolet', + }, + color: 'white', + }, + gray: { + backgroundColor: { + default: 'gainsboro', + ':hover': 'lightgray', + }, + }, + // ... more variants here ... +}); +``` + +然后,通过使用 `variant` 属性作为样式对象上的键来应用适当的样式 + +```jsx +function Button({variant, ...props}) { + return ( + <button {...props} + {...stylex.props(styles[variant])} + /> + ); +} +``` + +### 样式作为道具 + +```jsx +<CustomComponent style={styles.base} /> +``` + +`stylex.props` 函数返回具有 `className` 和 `style` 的对象。当样式要合并到组件内时不要使用它: + +```jsx +// ❌ 不要这样使用! ⚠️ +<CustomComponent + style={stylex.props(styles.base)} +/> +``` +<!--rehype:style=background: #ff00002b;--> + +```jsx +<CustomComponent + style={[ + styles.base, + isHighlighted && styles.highlighted + ]} +/> +``` + +### 接受组件中的样式 + +```jsx +import * as stylex from '@stylexjs/stylex'; + +// Local Styles +const styles = stylex.create({ + base: { + /*...*/ + }, +}); + +function CustomComponent({style}) { + return ( + <div + {...stylex.props(styles.base, style)} + /> + ); +} +``` + +将其与 `stylex.props` 函数一起应用 + +### “取消设置”样式 + +```jsx +import * as stylex from '@stylexjs/stylex'; + +const styles = stylex.create({ + base: { + color: null, + }, +}); +``` + +将样式属性设置为 `null` 会删除 StyleX 之前为其应用的任何样式。 + +主题 +---- + +### 使用媒体查询 +<!--rehype:wrap-class=col-span-2--> + +```js +import * as stylex from '@stylexjs/stylex'; + +// 可以使用常量来避免重复媒体查询 +const DARK = '@media (prefers-color-scheme: dark)'; + +export const colors = stylex.defineVars({ + primaryText: {default: 'black', [DARK]: 'white'}, + secondaryText: {default: '#333', [DARK]: '#ccc'}, + accent: {default: 'blue', [DARK]: 'lightblue'}, + background: {default: 'white', [DARK]: 'black'}, + lineColor: {default: 'gray', [DARK]: 'lightgray'}, +}); +``` + +### 定义变量 + +```js +import * as stylex from '@stylexjs/stylex'; + +export const tokens = stylex.defineVars({ + primaryText: 'black', + secondaryText: '#333', + borderRadius: '4px', + fontFamily: 'system-ui, sans-serif', + fontSize: '16px', +}); +``` + +这定义了 HTML 文档的 `:root` 处的变量。它们可以作为常量导入并在 `stylex.create` 调用中使用。 + +### 使用变量 +<!--rehype:wrap-class=col-span-2--> + +```jsx +import * as stylex from '@stylexjs/stylex'; + +// 可以使用常量来避免重复媒体查询 +const DARK = '@media (prefers-color-scheme: dark)'; + +export const colors = stylex.defineVars({ + primaryText: {default: 'black', [DARK]: 'white'}, + secondaryText: {default: '#333', [DARK]: '#ccc'}, + accent: {default: 'blue', [DARK]: 'lightblue'}, + background: {default: 'white', [DARK]: 'black'}, + lineColor: {default: 'gray', [DARK]: 'lightgray'}, +}); + +export const spacing = stylex.defineVars({ + none: '0px', + xsmall: '4px', + small: '8px', + medium: '12px', + large: '20px', + xlarge: '32px', + xxlarge: '48px', + xxxlarge: '96px', +}); +``` + +然后就可以像这样导入和使用这些样式: + +```js +import * as stylex from '@stylexjs/stylex'; +import {colors, spacing} from '../tokens.stylex'; + +const styles = stylex.create({ + container: { + color: colors.primaryText, + backgroundColor: colors.background, + padding: spacing.medium, + }, +}); +``` + +### 定义变量时的规则 + +变量必须定义在 `.stylex.js` 文件中,变量必须位于具有以下扩展名之一的文件中: + +- .stylex.js +- .stylex.mjs +- .stylex.cjs +- .stylex.ts +- .stylex.tsx +- .stylex.jsx + +变量必须命名为 `exports` + +```js +// ✅ - 命名导出 +export const colors = stylex.defineVars({ + /* ... */ +}); + +const sizeVars = { ... }; +// ✅ - 另一个命名导出 +export const sizes = stylex.defineVars(sizeVars); +``` + +不允许: + +```js +// ❌ - 只允许命名导出 +export default stylex.defineVars({ + /* ... */ +}); + +// ❌ - 变量必须直接导出 +const x = stylex.defineVars({ + /* ... */ +}); +export const colors = x; + +// ❌ - 变量不能嵌套在另一个对象内部 +export const colors = { + foregrounds: stylex.defineVars({ + /* ... */ + }), + backgrounds: stylex.defineVars({ + /* ... */ + }), +}; +``` +<!--rehype:style=background: #ff00001a;--> + +### 创建主题 +<!--rehype:wrap-class=col-span-2 row-span-2--> + +```js +import * as stylex from '@stylexjs/stylex'; +import {colors, spacing} from './tokens.stylex'; + +// 可以使用常量来避免重复媒体查询 +const DARK = '@media (prefers-color-scheme: dark)'; + +// Dracula 主题 +export const dracula = stylex.createTheme(colors, { + primaryText: {default: 'purple', [DARK]: 'lightpurple'}, + secondaryText: {default: 'pink', [DARK]: 'hotpink'}, + accent: 'red', + background: {default: '#555', [DARK]: 'black'}, + lineColor: 'red', +}); +``` + +应用主题,主题对象类似于使用 `stylex.create()` 创建的样式对象。使用 `stylex.props()` 将它们应用于元素,以覆盖该元素及其所有后代的变量。 + +```jsx +<div {...stylex.props(dracula, styles.container)}> + {children} +</div>; +``` + +- 创建主题时必须覆盖变量组中的所有变量。这一选择是为了帮助发现意外遗漏 +- 主题可以在代码库中的任何位置使用 `stylex.createTheme()` 创建,并在文件或组件之间传递 +- 如果同一变量组的多个主题应用于同一 HTML 元素,则最后应用的主题获胜 + +### 变量类型 + +```js +import * as stylex from '@stylexjs/stylex'; + +export const tokens = stylex.defineVars({ + primaryTxt: stylex.types.color('black'), + secondaryTxt: stylex.types.color('#333'), + borderRadius: stylex.types.length('4px'), + angle: stylex.types.angle('0deg'), + int: stylex.types.integer(2), +}); +``` + +所有值都可以是任意字符串。要将类型分配给变量,可以使用适当的类型函数包装它们 + +### 变量类型 & 条件值 + +```js +/// tokens.stylex.js +import * as stylex from '@stylexjs/stylex'; + +export const colors = stylex.defineVars({ + primaryText: stylex.types.color({ + default: 'black', [DARK]: 'white' + }), +}); +``` + +用法保持不变,以上内容完全有效 + +### 源代码中的类型安全 + +```js +// tokens.stylex.js +import * as stylex from '@stylexjs/stylex'; +import {tokens} from './tokens.stylex.js'; + +export const high = stylex.defineVars({ + primaryTxt: stylex.types.color('black'), + secondaryTxt: stylex.types.color('#222'), + borderRadius: stylex.types.length('8px'), + angle: stylex.types.angle('0deg'), + int: stylex.types.integer(4), +}); +``` + +当在 `stylex.defineVars` 中使用特定类型声明变量时,静态类型将强制在 `stylex.createTheme` 调用中为该变量设置主题时使用相同类型的函数 + +### 动画渐变 +<!--rehype:wrap-class=col-span-2 row-span-2--> + +```js +import * as stylex from '@stylexjs/stylex'; +import {tokens} from './tokens.stylex'; + +const rotate = stylex.keyframes({ + from: { [tokens.angle]: '0deg' }, + to: { [tokens.angle]: '360deg' }, +}); + +const styles = stylex.create({ + gradient: { + backgroundImage: `conic-gradient(from ${tokens.angle}, ...colors)`, + animationName: rotate, + animationDuration: '10s', + animationTimingFunction: 'linear', + animationIterationCount: 'infinite', + }, +}) +``` + +可以通过对其中使用的角度进行动画处理来对渐变进行动画处理 + +### 模拟 round() + +现代浏览器开始支持 CSS 中的 [round()](https://developer.mozilla.org/en-US/docs/Web/CSS/round) 函数。 + +```js +const styles = stylex.create({ + gradient: { + // Math.floor + [tokens.int]: `calc(16 / 9)` + + // Math.round + [tokens.int]: `calc((16 / 9) + 0.5)` + }, +}) +``` + +该功能通过一个整数类型的变量来模拟 + +TypeScript 类型 +--- + +### 样式 props 类型 + +```ts +import type {StyleXStyles} from '@stylexjs/stylex'; +import * as stylex from '@stylexjs/stylex'; + +type Props = { + ... + style?: StyleXStyles, +}; + +function MyComponent( + { style, ...otherProps }: Props +) { + return ( + <div + {...stylex.props( + localStyles.foo, + localStyles.bar, style + )} + > + {/* ... */} + </div> + ); +} +``` +<!--rehype:className=wrap-text--> + +### 禁止属性 +<!--rehype:wrap-class=col-span-2 row-span-3--> + +```ts +import type {StyleXStylesWithout} from '@stylexjs/stylex'; +import * as stylex from '@stylexjs/stylex'; + +type NoLayout = StyleXStylesWithout<{ + position: unknown, + display: unknown, + top: unknown, + start: unknown, + end: unknown, + bottom: unknown, + border: unknown, + borderWidth: unknown, + borderBottomWidth: unknown, + borderEndWidth: unknown, + borderStartWidth: unknown, + borderTopWidth: unknown, + margin: unknown, + marginBottom: unknown, + marginEnd: unknown, + marginStart: unknown, + marginTop: unknown, + padding: unknown, + paddingBottom: unknown, + paddingEnd: unknown, + paddingStart: unknown, + paddingTop: unknown, + width: unknown, + height: unknown, + flexBasis: unknown, + overflow: unknown, + overflowX: unknown, + overflowY: unknown, +}>; + +type Props = { + // ... + style?: NoLayout, +}; + +function MyComponent({style, ...}: Props) { + return ( + <div + {...stylex.props(localStyles.foo, localStyles.bar, style)} + > + {/* ... */} + </div> + ); +} +``` + +此处对象类型中列出的属性将被禁止,但所有其他样式仍将被接受。 + +### 从一组样式属性中接受 + +```ts +import type {StyleXStyles} from '@stylexjs/stylex'; + +type Props = { + // ... + style?: StyleXStyles<{ + color?: string; + backgroundColor?: string; + borderColor?: string; + borderTopColor?: string; + borderEndColor?: string; + borderBottomColor?: string; + borderStartColor?: string; + }>; +}; +``` +<!--rehype:className=wrap-text--> + +### 限制样式的可能值 + +```ts +import type {StyleXStyles} from '@stylexjs/stylex'; + +type Props = { + ... + // 只接受 marginTop 的样式,其他不接受。 + // marginTop 的值只能是 0、4、8 或 16。 + style?: StyleXStyles<{ + marginTop: 0 | 4 | 8 | 16 + }>, +}; +``` +<!--rehype:className=wrap-text-->