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

chore: master merge next #151

Merged
merged 13 commits into from
Nov 21, 2023
8 changes: 8 additions & 0 deletions docs/demo/css-var.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: CSS Variables
nav:
title: Demo
path: /demo
---

<code src="../examples/css-var.tsx"></code>
11 changes: 6 additions & 5 deletions docs/examples/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { CSSInterpolation, CSSObject } from '@ant-design/cssinjs';
import { useStyleRegister } from '@ant-design/cssinjs';
import { unit, useStyleRegister } from '@ant-design/cssinjs';
import classNames from 'classnames';
import React from 'react';
import type { DerivativeToken } from './theme';
Expand All @@ -14,6 +14,7 @@ const genSharedButtonStyle = (
borderColor: token.borderColor,
borderWidth: token.borderWidth,
borderRadius: token.borderRadius,
lineHeight: token.lineHeight,

cursor: 'pointer',

Expand Down Expand Up @@ -65,7 +66,7 @@ const genPrimaryButtonStyle = (
): CSSInterpolation =>
genSolidButtonStyle(prefixCls, token, () => ({
backgroundColor: token.primaryColor,
border: `${token.borderWidth}px solid ${token.primaryColor}`,
border: `${unit(token.borderWidth)} solid ${token.primaryColor}`,
color: token.reverseTextColor,

'&:hover': {
Expand All @@ -83,7 +84,7 @@ const genGhostButtonStyle = (
[`.${prefixCls}`]: {
backgroundColor: 'transparent',
color: token.primaryColor,
border: `${token.borderWidth}px solid ${token.primaryColor}`,
border: `${unit(token.borderWidth)} solid ${token.primaryColor}`,

'&:hover': {
borderColor: token.primaryColor,
Expand All @@ -102,7 +103,7 @@ const Button = ({ className, type, ...restProps }: ButtonProps) => {
const prefixCls = 'ant-btn';

// 【自定义】制造样式
const [theme, token, hashId] = useToken();
const [theme, token, hashId, cssVarKey] = useToken();

// default 添加默认样式选择器后可以省很多冲突解决问题
const defaultCls = `${prefixCls}-default`;
Expand All @@ -129,7 +130,7 @@ const Button = ({ className, type, ...restProps }: ButtonProps) => {

return wrapSSR(
<button
className={classNames(prefixCls, typeCls, hashId, className)}
className={classNames(prefixCls, typeCls, hashId, className, cssVarKey)}
{...restProps}
/>,
);
Expand Down
36 changes: 30 additions & 6 deletions docs/examples/components/theme.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { TinyColor } from '@ctrl/tinycolor';
import type { CSSObject, Theme } from '@ant-design/cssinjs';
import { createTheme, useCacheToken } from '@ant-design/cssinjs';
import { TinyColor } from '@ctrl/tinycolor';
import React from 'react';

export type GetStyle = (prefixCls: string, token: DerivativeToken) => CSSObject;

Expand All @@ -15,6 +15,9 @@ export interface DesignToken {
borderRadius: number;
borderColor: string;
borderWidth: number;

lineHeight: number;
lineHeightBase: number;
}

export interface DerivativeToken extends DesignToken {
Expand All @@ -31,6 +34,9 @@ const defaultDesignToken: DesignToken = {
borderRadius: 2,
borderColor: 'black',
borderWidth: 1,

lineHeight: 1.5,
lineHeightBase: 1.5,
};

// 模拟推导过程
Expand All @@ -48,21 +54,39 @@ export const ThemeContext = React.createContext(createTheme(derivative));
export const DesignTokenContext = React.createContext<{
token?: Partial<DesignToken>;
hashed?: string | boolean;
cssVar?: {
key: string;
};
}>({
token: defaultDesignToken,
});

export function useToken(): [Theme<any, any>, DerivativeToken, string] {
const { token: rootDesignToken = {}, hashed } =
React.useContext(DesignTokenContext);
export function useToken(): [
Theme<any, any>,
DerivativeToken,
string,
string | undefined,
] {
const {
token: rootDesignToken = {},
hashed,
cssVar,
} = React.useContext(DesignTokenContext);
const theme = React.useContext(ThemeContext);

const [token, hashId] = useCacheToken<DerivativeToken, DesignToken>(
theme,
[defaultDesignToken, rootDesignToken],
{
salt: typeof hashed === 'string' ? hashed : '',
cssVar: cssVar && {
prefix: 'rc',
key: cssVar.key,
unitless: {
lineHeight: true,
},
},
},
);
return [theme, token, hashed ? hashId : ''];
return [theme, token, hashed ? hashId : '', cssVar?.key];
}
52 changes: 52 additions & 0 deletions docs/examples/css-var.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import './basic.less';
import Button from './components/Button';
import { DesignTokenContext } from './components/theme';

export default function App() {
const [show, setShow] = React.useState(true);

const [, forceUpdate] = React.useState({});
React.useEffect(() => {
forceUpdate({});
}, []);

return (
<div style={{ background: 'rgba(0,0,0,0.1)', padding: 16 }}>
<h3>默认情况下不会自动删除添加的样式</h3>

<label>
<input type="checkbox" checked={show} onChange={() => setShow(!show)} />
Show Components
</label>

{show && (
<div>
<DesignTokenContext.Provider
value={{ cssVar: { key: 'default' }, hashed: true }}
>
<Button>Default</Button>
<Button type="primary">Primary</Button>
<Button type="ghost">Ghost</Button>

<Button className="btn-override">Override By ClassName</Button>
</DesignTokenContext.Provider>
<br />
<DesignTokenContext.Provider
value={{
token: { primaryColor: 'green' },
cssVar: { key: 'default2' },
hashed: true,
}}
>
<Button>Default</Button>
<Button type="primary">Primary</Button>
<Button type="ghost">Ghost</Button>

<Button className="btn-override">Override By ClassName</Button>
</DesignTokenContext.Provider>
</div>
)}
</div>
);
}
2 changes: 1 addition & 1 deletion docs/examples/ssr-hydrate-file.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createCache, StyleProvider } from '@ant-design/cssinjs';
import React from 'react';
import { hydrateRoot } from 'react-dom/client';
import { Demo } from './ssr-advanced';
import './ssr-hydrate-file.css';
// import './ssr-hydrate-file.css';

// Copy from `ssr-advanced-hydrate.tsx`
const HTML = `
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ant-design/cssinjs",
"version": "1.17.2",
"version": "1.18.0-alpha.1",
"description": "Component level cssinjs resolution for antd",
"keywords": [
"react",
Expand All @@ -25,11 +25,12 @@
"license": "MIT",
"scripts": {
"start": "dumi dev",
"dev": "father dev",
"docs:build": "dumi build",
"docs:deploy": "gh-pages -d .doc",
"compile": "father build",
"gh-pages": "npm run docs:build && npm run docs:deploy",
"prepublishOnly": "npm run compile && np --yolo --no-publish",
"prepublishOnly": "npm run compile && np --yolo --no-publish --branch=next --tag=next",
"postpublish": "npm run gh-pages",
"lint": "eslint src/ --ext .ts,.tsx,.jsx,.js,.md",
"prettier": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
Expand Down
83 changes: 83 additions & 0 deletions src/extractStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import type Cache from './Cache';
import {
extract as tokenExtractStyle,
TOKEN_PREFIX,
} from './hooks/useCacheToken';
import {
CSS_VAR_PREFIX,
extract as cssVarExtractStyle,
} from './hooks/useCSSVarRegister';
import {
extract as styleExtractStyle,
STYLE_PREFIX,
} from './hooks/useStyleRegister';
import { toStyleStr } from './util';
import {
ATTR_CACHE_MAP,
serialize as serializeCacheMap,
} from './util/cacheMapUtil';

const ExtractStyleFns = {
[STYLE_PREFIX]: styleExtractStyle,
[TOKEN_PREFIX]: tokenExtractStyle,
[CSS_VAR_PREFIX]: cssVarExtractStyle,
};

function isNotNull<T>(value: T | null): value is T {
return value !== null;
}

export default function extractStyle(cache: Cache, plain = false) {
const matchPrefixRegexp = new RegExp(
`^(${Object.keys(ExtractStyleFns).join('|')})%`,
);

// prefix with `style` is used for `useStyleRegister` to cache style context
const styleKeys = Array.from(cache.cache.keys()).filter((key) =>
matchPrefixRegexp.test(key),
);

// Common effect styles like animation
const effectStyles: Record<string, boolean> = {};

// Mapping of cachePath to style hash
const cachePathMap: Record<string, string> = {};

let styleText = '';

styleKeys
.map<[number, string] | null>((key) => {
const cachePath = key.replace(matchPrefixRegexp, '').replace(/%/g, '|');
const [prefix] = key.split('%');
const extractFn = ExtractStyleFns[prefix as keyof typeof ExtractStyleFns];
const extractedStyle = extractFn(cache.cache.get(key)![1], effectStyles, {
plain,
});
if (!extractedStyle) {
return null;
}
const [order, styleId, styleStr] = extractedStyle;
if (key.startsWith('style')) {
cachePathMap[cachePath] = styleId;
}
return [order, styleStr];
})
.filter(isNotNull)
.sort(([o1], [o2]) => o1 - o2)
.forEach(([, style]) => {
styleText += style;
});

// ==================== Fill Cache Path ====================
styleText += toStyleStr(
`.${ATTR_CACHE_MAP}{content:"${serializeCacheMap(cachePathMap)}";}`,
undefined,
undefined,
{
[ATTR_CACHE_MAP]: ATTR_CACHE_MAP,
},
plain,
);

return styleText;
}
Loading
Loading