From 2487ac5349ec9736210cf2ddd7ebb5de3e503b9c Mon Sep 17 00:00:00 2001 From: zhangfisher Date: Tue, 28 May 2024 14:55:07 +0800 Subject: [PATCH] update --- .github/workflows/webstite.yaml | 2 - docs/.vitepress/config.mts | 2 +- docs/best-practices.md | 6 + docs/guide/theme.md | 149 +++++++++--- example/src/App.tsx | 20 +- example/src/Card2.tsx | 4 +- example/src/ColorButton.tsx | 25 ++ example/src/cardStyle.ts | 3 +- example/src/theme.ts | 12 + readme.md | 408 +++++++++++++++++++++++++++++++- src/index.tsx | 7 +- src/parse.ts | 17 +- src/styled.ts | 41 +--- src/tag.tsx | 8 +- src/theme.ts | 236 ++++++++---------- src/types.ts | 12 +- src/utils.ts | 42 ++-- 17 files changed, 739 insertions(+), 255 deletions(-) create mode 100644 example/src/ColorButton.tsx create mode 100644 example/src/theme.ts diff --git a/.github/workflows/webstite.yaml b/.github/workflows/webstite.yaml index 06cac43..2144534 100644 --- a/.github/workflows/webstite.yaml +++ b/.github/workflows/webstite.yaml @@ -45,8 +45,6 @@ jobs: npm install -g pnpm - name: Install dependencies run: pnpm install # or npm ci / yarn install / bun install / - - name: Build packages - run: pnpm build:all - name: pnpm docs:build run: | pnpm docs:build # or npm run docs:build / yarn docs:build / bun run docs:build diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index c8d1bae..f762ed2 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -33,7 +33,7 @@ export default defineConfig({ { text: 'keyframes', link: '/guide/keyframes' }, { text: 'useStyled', link: '/guide/useStyled' }, { text: 'StyledObject', link: '/guide/styledObject' }, - // { text: '主题', link: '/guide/theme' }, + { text: '主题', link: '/guide/theme' }, ] }, { text: 'API', link: '/api' }, diff --git a/docs/best-practices.md b/docs/best-practices.md index 02b1737..67fa7ea 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -91,5 +91,11 @@ const Fit = styled({ height:'100%' }) + ``` +然后这样原子样式就可以在其他样式声明中被重新使用。详见[组合样式](/guide/combind)章节。 + + + + diff --git a/docs/guide/theme.md b/docs/guide/theme.md index a3702bb..94fbef1 100644 --- a/docs/guide/theme.md +++ b/docs/guide/theme.md @@ -2,54 +2,145 @@ 得益于`flexstyled`的灵活性,我们可以通过主题来实现全局样式的统一管理。 +## 创建主题 - ```tsx - +主题是一个对象,包含多个CSS变量样式,也可以包含一些预定义的样式。 -const light = styled({ - "--primaryColor":'red', - "--secondaryColor":'blue', - "--backgroundColor":'white', - "--color":'black', - "--borderRadius":'4px' + ```tsx +// theme.ts +import { createTheme } from "flexstyled" +export const theme = createTheme({ + primaryColor : "#007bff", + secondaryColor : "blue", + backgroundColor: "#e8f8ff", + textColor : "333", + fontSize : "16px", }) + ``` -const dark = styled({ - "--primaryColor":'red', - "--secondaryColor":'blue', - "--backgroundColor":'#333', - "--color":'white', - "--borderRadius":'4px' +## 使用主题 + +接下来就可以在组件中使用主题了。 + +```tsx + +import { theme } from "./theme" + +export type CardProps = React.PropsWithChildren<{ + title:string + footer?:string + }> + +export const Card = styled((props,{className})=>{ + const { title,children,footer} =props + return ( +
+
+ {title} +
+
{children}
+
{footer}
+
+ ) + },{ + position:"relative", + width:"100%", + border:"1px solid #ccc", + // 引用主题变量,具有类型提示 + backgroudColor: theme.backgroundColor, // [!code ++] + color: theme.primaryColor // [!code ++] + // 或者也可以直接引用 + backgroudColor: "var(--background-color)", // [!code ++] + color: "var(--primary-color)" // [!code ++] + borderRadius:"4px" + }) + +``` + +## 修改主题 + +能通过修改主题来修改全局样式。 + +```tsx +import { theme } from "./theme" + +// 具有类型提示,直接修改主题变量 +theme.primaryColor = "red" // ![code ++] + +// 也可以直接批量修改主题变量 +theme.update({ // ![code ++] + primaryColor : "#007bff", // ![code ++] + secondaryColor : "blue", // ![code ++] + backgroundColor: "#e8f8ff", // ![code ++] + textColor : "333", // ![code ++] + fontSize : "16px", // ![code ++] }) +``` -const theme = createTheme(light,dark) +## 保存主题 +修改主题后可以保存地,方便下次使用。 +```tsx +import { theme } from "./theme" -const Button = styled((props,{className,getStyle})=>{ - return
+// 也可以直接批量修改主题变量 +theme.update({ + primaryColor : "#007bff", + secondaryColor : "blue", + backgroundColor: "#e8f8ff", + textColor : "333", + fontSize : "16px", +}) -
-},{ - color:(props,theme)=>theme.primaryColor, - backgroundColor:theme.secondaryColor, - borderRadius:theme.borderRadius -},[theme]) +theme.save((data)=>{ // ![code ++] + // ![code ++] // 保存主题到 + localStorage.setItem("theme",JSON.stringify(data)) // ![code ++] +} ) // ![code ++] -const Input = styled({ - color:(props)=>theme.primaryColor, - backgroundColor:theme.secondaryColor, - borderRadius:theme.borderRadius -},[theme]) +``` +## 读取主题 +```tsx +import { theme } from "./theme" +theme.load(JSON.parse(localStorage.getItem("theme")) // ![code ++] +``` - ``` +## 变量前缀 + +主题变量本质上是创建一些全局CSS变量,为了避免冲突,可以给变量添加统一的前缀。 + +```ts +import { createTheme } from "flexstyled"; + +export const theme = createTheme({ + primaryColor : "#007bff", + secondaryColor : "blue", + backgroundColor: "#e8f8ff", + textColor : "333", + fontSize : "16px", +},{ + prefix:"v" +}) + +``` + +以下声明的变量都会自动添加前缀`v`,创建以下的全局变量: +```css +:root{ + --v-primary-color: #007bff; + --v-secondary-color: blue; + --v-background-color: #e8f8ff; + --v-text-color: 333; + --v-font-size: 16px; +} +``` \ No newline at end of file diff --git a/example/src/App.tsx b/example/src/App.tsx index 4d89bc7..405e08e 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -2,9 +2,10 @@ import { useState } from 'react' import './App.css' import { Card } from "./Card" import { Card2 } from "./Card2" -import { Card3 } from "./Card3" -import { MyButton } from './MyButton' -import { Card4 } from './Card4' +import { Card3 } from "./Card3" +import { Card4 } from './Card4' +import { ColorButton } from './ColorButton' +import { theme } from "./theme" function App() { @@ -13,7 +14,18 @@ function App() { const [showCard2,setShowCard2] = useState(true) return (
- Styled +
+ 主题: + theme.backgroundColor = 'red'}/> + theme.backgroundColor = '#0bcaf0'} /> + theme.backgroundColor = '#16ff3d'}/> + theme.backgroundColor = '#ff6600'}/> + theme.backgroundColor = '#ff08de'}/> + + + +
+ FlexStyled is a simple css-in-js library for react component

Size={size}

diff --git a/example/src/Card2.tsx b/example/src/Card2.tsx index 87d1ea5..378886c 100644 --- a/example/src/Card2.tsx +++ b/example/src/Card2.tsx @@ -1,5 +1,5 @@ import { useState } from "react" -import { useStyle } from "../../src" +import { useStyled } from "../../src" import { getRandColor } from "./utils" import { CardProps, cardStyle } from "./cardStyle" @@ -7,7 +7,7 @@ import { CardProps, cardStyle } from "./cardStyle" export const Card2:React.FC> = ((props:CardProps)=>{ const { title } = props const [titleColor,setTitleColor] = useState("blue") - const {className,getStyle} = useStyle(cardStyle,{id:"mycard2"}) + const {className,getStyle} = useStyled(cardStyle,{id:"mycard2"}) return (
diff --git a/example/src/ColorButton.tsx b/example/src/ColorButton.tsx new file mode 100644 index 0000000..ad483bc --- /dev/null +++ b/example/src/ColorButton.tsx @@ -0,0 +1,25 @@ +/** + * 显示颜色按钮 + */ + +import React from 'react'; +import { styled } from "../../src" + + +export type ColorButtonProps = { + color?: string +} + + +export const ColorButton = styled.span({ + width: '24px', + height: '24px', + padding:"8px", + borderRadius: 5, + margin: "4px", + backgroundColor: (props)=>props.color, + cursor: "pointer", + "&:hover":{ + outline: "1px solid #aaa" + } +}); \ No newline at end of file diff --git a/example/src/cardStyle.ts b/example/src/cardStyle.ts index 730424b..01b5e1b 100644 --- a/example/src/cardStyle.ts +++ b/example/src/cardStyle.ts @@ -1,4 +1,5 @@ import { CSSRuleObject } from "../../src" +import { theme } from "./theme" export type CardProps = React.PropsWithChildren<{ title:string @@ -32,7 +33,7 @@ export const cardStyle:CSSRuleObject = { }, "& > .title":{ padding : "8px", - background : "#f9f9f9", + background : theme.backgroundColor, fontSize : "18px", fontWeight : "bold", borderBottom : "1px solid #ccc", diff --git a/example/src/theme.ts b/example/src/theme.ts new file mode 100644 index 0000000..aedfb1c --- /dev/null +++ b/example/src/theme.ts @@ -0,0 +1,12 @@ +import { createTheme } from "../../src/theme"; + +export const theme = createTheme({ + primaryColor : "#007bff", + secondaryColor : "blue", + backgroundColor: "#e8f8ff", + textColor : "333", + fontSize : "16px", +},{ + prefix:"v" +}) + diff --git a/readme.md b/readme.md index abea7da..484d94b 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,408 @@ -# StyledFc +# FlexStyled +FlexStyled is a simple runtime `css-in-js` library for react component -rename to `flexstyled` +[中文](./readme_CN.md) -https://github.com/zhangfisher/flexstyled \ No newline at end of file +- zero dependencies. +- runtime css generation. +- support css variables. +- support nested css. +- support props dynamic css. +- typescript support. + +[Open demo on CodeSandbox](https://codesandbox.io/p/sandbox/FlexStyled-demo-x7w94w?layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522clstzj2mg0006356lkdcmsv3s%2522%252C%2522sizes%2522%253A%255B70%252C30%255D%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522id%2522%253A%2522clstzj2mg0002356lq7y9whne%2522%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522SHELLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522id%2522%253A%2522clstzj2mg0003356lip4fhd1w%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522id%2522%253A%2522clstzj2mg0005356l6vsjkkfr%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%252C%2522sizes%2522%253A%255B50%252C50%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clstzj2mg0002356lq7y9whne%2522%253A%257B%2522id%2522%253A%2522clstzj2mg0002356lq7y9whne%2522%252C%2522tabs%2522%253A%255B%255D%257D%252C%2522clstzj2mg0005356l6vsjkkfr%2522%253A%257B%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clstzj2mg0004356l6rts8s1f%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522UNASSIGNED_PORT%2522%252C%2522port%2522%253A0%252C%2522path%2522%253A%2522%252F%2522%257D%255D%252C%2522id%2522%253A%2522clstzj2mg0005356l6vsjkkfr%2522%252C%2522activeTabId%2522%253A%2522clstzj2mg0004356l6rts8s1f%2522%257D%252C%2522clstzj2mg0003356lip4fhd1w%2522%253A%257B%2522tabs%2522%253A%255B%255D%252C%2522id%2522%253A%2522clstzj2mg0003356lip4fhd1w%2522%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showShells%2522%253Atrue%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A15%257D) + +## Installation + +```bash +pnpm add FlexStyled +# or +npm install FlexStyled +# or +yarn add FlexStyled +``` + +## Usage + +We plan to develop a `Card` component, which has a `title` attribute for displaying titles, a `footer`' attribute for displaying bottom content, and a `children` attribute as the content area of the card. + + +### Basic Usage + + +```tsx +import { styled } from "FlexStyled" + +export type CardProps = React.PropsWithChildren<{ + title:string + footer?:string + }> + +export const Card = styled((props,{className})=>{ + const { title,children,footer} =props + return ( +
+
+ {title} +
+
{children}
+
{footer}
+
+ ) + },{ + position:"relative", + width:"100%", + border:"1px solid #ccc", + borderRadius:"4px" + }) + +``` + +-The above code will create a `Card` component, generate a style class (with a randomly generated name) for the style, and insert it into the `head` tag. +-Then pass the `className` prop to the component, which will use this class name to apply the style. + +You can find a CSS style similar to this in the `head`, where the `className` and `style.id` are both automatically generated. You can also specify `styleId` and `className` through the `options` parameter. + +```html + +``` + +### Nested Style + +Next, let's add styles to the `title` and `footer` of the `Card` component + + +```tsx +export const Card = styled((props,{className})=>{ + const { title,children,footer} =props + return ( +
+
+ {title} +
+
{children}
+
{footer}
+
+ )},{ + position:"relative", + width:"100%", + border:"1px solid #ccc", + borderRadius:"4px", + "& > .title":{ + fontSize:"20px", + fontWeight:"bold", + }, + "& > .footer":{ + borderTop:"1px solid #ccc", + padding:"8px", + textAlign:"right" + } + }) +``` + +-We have added styles to the `title` and `footer` above. +-Use the `&` symbol to represent the current parent element, similar to the syntax of nested CSS such as `less` and `sass`. + + +The style generated in `head` is as follows: + +```html + +``` + +### Dynamic Style + +`FlexStyled` supports using `props` to dynamically set styles. + +For example, we want the background color of the `content` card to be specified by the `props.bgColor` attribute. + + +```tsx + +export const Card = styled((props,{className,getStyle})=>{ + const { title,children,footer} =props + return ( +
+
+ {title} +
+
{children}
+
{footer}
+
+ )},{ + position:"relative", + width:"100%", + border:"1px solid #ccc", + borderRadius:"4px", + "& > .title":{ + fontSize:"20px", + fontWeight:"bold", + }, + "& > .footer":{ + borderTop:"1px solid #ccc", + padding:"8px", + textAlign:"right" + }, + "& > .content":{ + padding:"8px", + backgroundColor:(props)=>props.bgColor + } + }) +``` + +- The above code uses `props.bgColor` to dynamically set the background color of the `content` card. +- In order to support dynamic properties, we need to use the `getStyle` function to get the dynamic style and inject it into the root element of the component. +- The `getStyle` function returns a `css` style object that can be passed directly to the `style` attribute. +- Any `css` property can use `(props)=>{....}` to dynamically generate CSS property values. + +### CSS Variables + +`FlexStyled` supports using `css` variables. + +We can use `css` variables in the root style declaration, and then use the `setVar` function to dynamically modify the `css` variable in the component. + + +```tsx + +export const Card = styled((props,{className,getStyle})=>{ + const { title,children,footer} =props + const [primaryColor,setPrimaryColor] = React.useState("blue") + return ( +
+
+
{children}
+
{footer}
+
+ )},{ + position:"relative", + width:"100%", + border:"1px solid #ccc", + borderRadius:"4px", + "--primary-color":"blue", + "& > .title":{ + fontSize:"20px", + fontWeight:"bold", + color:"var(--primary-color)" + }, + "& > .footer":{ + borderTop:"1px solid #ccc", + padding:"8px", + textAlign:"right" + }, + "& > .content":{ + padding:"8px", + backgroundColor:(props)=>props.bgColor + } + }) +``` + + +- The above code uses `css` variables. +- We declare a `--primary-color` `css` variable in the root style. +- Then we use the `--primary-color` variable in the `title` style. +- In order to modify the `css` variable, we need to introduce `ref` and pass `ref` to the root element, and then use the `setVar` function to modify the `css` variable. + +### Summary + +`FlexStyled` is a very simple `css-in-js` library that can help you quickly encapsulate `react` components and support `css` variables and dynamic `css` properties. + +- By default, you only need to reference `className` in the component. +- If you need to dynamically modify `css` variables, you need to introduce `ref`, pass `ref` to the root element, and then use the `setVar` function to modify `css` variables. +- If you need to use `props` dynamic `css` properties, you need to use the `getStyle` function to get the dynamic css style and inject it into the root element. + + +## creteStyle + +`styled` function can also be used to create styles only and insert into head. + +```tsx +// card.style.ts + +import { styled } from "FlexStyled" + +// create style and insert into head +export default styled({ // 组件样式 + position:"relative", + width:"100%", + border:"1px solid #ccc", + borderRadius:"4px", + "--primary-color":"blue", + "& > .title":{ + fontSize:"20px", + fontWeight:"bold", + color:"var(--primary-color)" + }, + "& > .footer":{ + borderTop:"1px solid #ccc", + padding:"8px", + textAlign:"right" + }, + "& > .content":{ + padding:"8px", + backgroundColor:(props)=>props.bgColor + } +}) + +// card.tsx +import cardStyle from "./card.style" + +export default (props:CardProps)=>{ + return ( +
+
+ {props.title} +
+
{props.children}
+
{props.footer}
+
+ ) + } +``` + + +using `createStyle.props` to simplify the parameter passing, as follows: + +```tsx + +export default (props:CardProps)=>{ + return ( +
+ ... +
+ ) + } + +
+
+
+ +``` + +## Hook + +`FlexStyled` also provides a hook `useStyled` to help you quickly encapsulate `react` components. + + +```tsx +import { useStyle } from "FlexStyled" +export const Card2:React.FC> = ((props:CardProps)=>{ + const { title } = props + const [titleColor,setTitleColor] = useState("blue") + const {className,getStyle } = useStyle({ + // style + }) + return ( +
+
+ {title} + +
+
+ {props.children} +
+
{props.footer}
+
+ ) + }) +``` + +- The `useStyle` hook returns `className` and `getStyle`, which are used to inject style class names and dynamic styles. +- The `getStyle` function returns a `css` style object that can be passed directly to the `style` attribute. +- The `useStyle` hook supports passing `options` parameters to configure `styleId` and `className`. +- The `useStyle` hook is the same as the `styled` function, the only difference is that the `style` sheet injected into the `head` will be automatically removed when the component is uninstalled. + +### Create Styled component + +`FlexStyled` supports creating styled components, use html tag name. + +```tsx + +import { styled } from "FlexStyled" + +const MyButton = styled.div({ + color:"red", + "&:hover":{ + color:"blue" + } +}) + +``` +- You can also create other HTML tags, such as `span`, `button`, etc. + + +## Performance + +Due to the limitations of `css-in-js`, there may be performance issues. A recommended performance optimization method is to create all styles at once during the application's startup phase and insert them into the `head`, and then reference the styles in the component. + +```tsx +// styles.tsx +import { styled } from "FlexStyled" +export style1 = styled({...}) +export style2 = styled({...}) +export style3 = styled({...}) +``` + +## Options + + +```tsx + +// styled(,,) + +export interface StyledOptions{ + // The ID of the style sheet, if not specified, will be automatically generated + styleId?:string + // The generated class name, if not specified, will be automatically generated + className?:string +} +``` + + +## API + +```tsx +export interface StyledOptions{ + // stylesheet id, if not provided, it will be generated automatically + styleId?:string + // generated className, if not provided, it will be generated automatically + className?:string +} +export type StyledComponentParams ={ + // generated css class name + className:string + // generated css style id + styleId:string + vars:Record + // get the css style object,only use when use props dynamic css + getStyle : ()=>Record +} + +export type StyledComponent = (props:React.PropsWithChildren,params:StyledComponentParams)=>React.ReactElement + +styled(FC: StyledComponent,styles:CSSObject,options?:StyledOptions) + +``` \ No newline at end of file diff --git a/src/index.tsx b/src/index.tsx index ee73e69..6c1e858 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -43,7 +43,8 @@ useInsertionEffect export * from "./styled" export * from "./types" -export { useStyled as useStyle } from "./hooks" -export { insertStylesheet } from "./utils" export * from "./tag" -export * from "./keyframes" \ No newline at end of file +export * from "./keyframes" +export * from "./theme" +export { useStyled } from "./hooks" +export { insertStylesheet } from "./utils" \ No newline at end of file diff --git a/src/parse.ts b/src/parse.ts index 0e0b6ad..4233875 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -51,7 +51,7 @@ import { CSSRuleObject, ComputedStyles, StyledOptions, CSSVars } from './types'; import { shortHash } from "./hash" -import { toCssStyleName, fromCssVariableName } from './utils'; +import { toCssVarName, fromCssVarName, toCssRuleName } from './utils'; @@ -71,7 +71,7 @@ function isIfRule(ruleName:string){ export function parseStyles(styles:T,options?:StyledOptions){ const opts = Object.assign({},options) as Required - const { className,rootVars } = opts + const { className,asRoot,varPrefix} = opts const rules:string[] = [] const vars:CSSVars = {} const computedStyles:ComputedStyles = {} // 保存动态样式函数,如(props)=>{} @@ -107,21 +107,22 @@ export function parseStyles(styles:T,op let varName = parentRule+"-"+ruleName if(varName.startsWith(className)) varName = varName.substring(className.length) varName = `--p-${shortHash(varName)}` - rule += `${toCssStyleName(ruleName)}: var(${varName});\n` + rule += `${toCssRuleName(ruleName)}: var(${varName});\n` computedVars.push( `${varName}: unset;\n`) computedStyles[varName] = value // 保存动态样式函数 }else{ const isCssVar = ruleName.startsWith("--") //注意: CSS变量只能在根样式中定义,将CSS变量转换为JS变量保存起来 if(isCssVar){ + const cssVarName = ruleName.replace("--",`--${varPrefix}-`) // @ts-ignore - vars[fromCssVariableName(ruleName)] = value - if(rootVars){ - rootVarsMap.push(` ${ruleName}: ${value};`) + vars[fromCssVarName(ruleName)] = `var(${cssVarName})` + if(asRoot){ + rootVarsMap.push(` ${cssVarName}: ${value};`) } } - if(!rootVars || (rootVars && !isCssVar)){ - rule += ` ${toCssStyleName(ruleName)}: ${value};\n` + if(!asRoot || (asRoot && !isCssVar)){ + rule += ` ${toCssRuleName(ruleName)}: ${value};\n` } } } diff --git a/src/styled.ts b/src/styled.ts index 373ce8f..cbb2c6c 100644 --- a/src/styled.ts +++ b/src/styled.ts @@ -40,7 +40,7 @@ * */ -import { CSSRuleObject, ComponentStyledObject, StyledComponent, StyledObject, StyledOptions, CSSVars, PickCombindVars } from './types'; +import { CSSRuleObject, ComponentStyledObject, StyledComponent, StyledObject, StyledOptions, CSSVars } from './types'; import { parseStyles } from "./parse" import { generateClassName, generateStyleId, getComputedStyles, insertStylesheet, isPlainObject, joinClassNames } from "./utils" import type { CSSProperties,ReactElement } from "react" @@ -52,9 +52,10 @@ export function createStyled = CSS export function createStyled = CSSRuleObject, CombindStyles extends StyledObject[]=StyledObject[]>():any{ let FC:StyledComponent | undefined=undefined,styleData:CSSRuleObject let opts:Required = { - className:generateClassName(), - id:generateStyleId(), - rootVars : false + className: generateClassName(), + id : generateStyleId(), + asRoot : false, + varPrefix: '' } let combindStyledObjects:StyledObject[] = [] // 需要合并的样式对象 // 参数处理 @@ -88,7 +89,7 @@ export function createStyled = CSS insertStylesheet(style.css,opts.id) const combindVars = Object.assign(style.vars,...combindStyledObjects.map(s=>s.vars)) - + // 3. 创建样式对象 const createStyledObject = (fcProps?:any) =>{ const computedStyles = [...combindStyledObjects.map(s=>s.computedStyles), style.computedStyles] @@ -127,32 +128,4 @@ export function createStyled = CSS } } - - -// const theme1 = createStyled({ -// border:1, -// "--primary-color":"red", -// "--secondary-color-1":"blue" -// }) - - -// theme1.vars.primaryColor = 'green' -// theme1.vars['primary-color'] -// theme1.vars.primaryColor -// theme1.vars - -// const theme2 = createStyled({ -// color:'red', -// "--primary-bgcolor":"red", -// "--secondary-bgcolor":"blue" -// }) -// theme2.vars - - -// const themes= createStyled({ -// border:1, -// "--theme-color":"red" -// },[theme1,theme2]) - -// themes.vars.themeColor - + \ No newline at end of file diff --git a/src/tag.tsx b/src/tag.tsx index f8b7fec..88d1e4e 100644 --- a/src/tag.tsx +++ b/src/tag.tsx @@ -26,14 +26,14 @@ export interface StyledComponentCreatorOptions extends StyledOptions{ export type StyledComponentCreator =(style:CSSRuleObject,options?:StyledComponentCreatorOptions)=> React.FC,'className' | 'style'> & Props>> +React.HTMLAttributes> & Props> -export type StyledFcObject = typeof createStyled & { +export type FlexStyledObject = typeof createStyled & { [K in keyof HTMLElementTagNameMap]: StyledComponentCreator; }; -export const styled = new Proxy(createStyled as StyledFcObject,{ +export const styled = new Proxy(createStyled as FlexStyledObject,{ get(target: typeof createStyled, key: string | symbol, receiver: any){ if(typeof(key) == 'string' && VALID_HTML_TAGS.includes(key)){ return (style:CSSRuleObject,options?:StyledComponentCreatorOptions)=>{ @@ -41,7 +41,7 @@ export const styled = new Proxy(createStyled as StyledFcObject, return React.createElement(key,{ ...props, className, - style:getStyle() + style:getStyle(), },props.children) },style,options) } diff --git a/src/theme.ts b/src/theme.ts index 7d25826..934bb66 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -1,164 +1,118 @@ -import { parseStyles } from './parse'; -import { CSSRuleObject, CSSVars, ComputedStyles, IStyledObject, StyledObject } from './types'; +import { styled } from '.'; +import { CSSVariables, Dict } from './types'; +import { fromCssVarName, toCssVarName } from './utils'; /** * Create a theme * - * const light = styled({ - * "--primary-color": "red", - * "--secondary-color": "blue", - * }) - * - * const dark = styled({ - * "--primary-color": "green", - * "--secondary-color": "yellow", - * },{rootVars:true}) 将css变量提升到全局 - * - * - * - * const theme = new themeManager([light,dark]) - * - * - * - * - * btn = styled