Skip to content

Commit

Permalink
✨ feat: 支持 StyleProvider container 与默认位置隔离的样式插入策略
Browse files Browse the repository at this point in the history
需求:同一个组件想在同一个页面的两个不同地方使用,一处是正常引用,style标签插在header中,另一处是在页面中的iframe里去引入这个组件,通过styleProvider来配置插入位置
  • Loading branch information
arvinxx committed May 5, 2023
1 parent 4f5e36c commit a51d72a
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 56 deletions.
33 changes: 10 additions & 23 deletions src/factories/createStyleProvider/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { DEFAULT_CSS_PREFIX_KEY } from '@/core';
import { createEmotion, Emotion } from '@/core/createEmotion';
import { StyleManager } from '@/types';
import { StyleProvider as AntdStyleProvider } from '@ant-design/cssinjs';
import type { StyleContextProps } from '@ant-design/cssinjs/es/StyleContext';
import { StylisPlugin } from '@emotion/cache';
import { Context, FC, memo, ReactNode, useEffect, useMemo } from 'react';
import { Context, FC, memo, ReactNode, useContext, useEffect, useMemo } from 'react';

export interface StyleProviderProps
extends Partial<
Expand All @@ -30,37 +29,25 @@ export interface StyleProviderProps
children: ReactNode;
}

interface DefaultProps {
prefix: string;
speedy?: boolean;
container?: Node;
defaultEmotion: Emotion;
}

export const createStyleProvider = (
EmotionContext: Context<Emotion>,
defaultProps?: DefaultProps,
): FC<StyleProviderProps> =>
export const createStyleProvider = (EmotionContext: Context<Emotion>): FC<StyleProviderProps> =>
memo(
({
children,
prefix = defaultProps?.prefix || DEFAULT_CSS_PREFIX_KEY,
speedy = defaultProps?.speedy,
prefix: outerPrefix,
speedy: outSpeedy,
getStyleManager,
container = defaultProps?.container,
container: outerContainer,
nonce,
insertionPoint,
stylisPlugins,
...antdStyleProviderProps
}) => {
// FIXME: 现在的解决方案比较 hack,通过修改默认传入的 defaultEmotion 的方式来实现,后续新方案里要考虑通过 context 的方式来实现
if (container && defaultProps) {
defaultProps.defaultEmotion.sheet.container = container;
}
const defaultEmotion = useContext(EmotionContext);

const prefix = outerPrefix ?? defaultEmotion.sheet.key;
const container = outerContainer ?? defaultEmotion.sheet.container;
const speedy = outSpeedy ?? defaultEmotion.sheet.isSpeedy;

// useEffect(() => {
// console.log(container);
// }, [container]);
const emotion = useMemo(() => {
const defaultSpeedy = process.env.NODE_ENV === 'development';

Expand Down
18 changes: 9 additions & 9 deletions src/factories/createStyles/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useMemo } from 'react';
import { Context, useContext, useMemo } from 'react';

import { createCSS, serializeCSS } from '@/core';
import { Emotion, createCSS, serializeCSS } from '@/core';
import type {
BaseReturnType,
CSSObject,
Expand All @@ -9,13 +9,12 @@ import type {
ReturnStyleToUse,
} from '@/types';
import { isReactCssResult } from '@/utils';
import { EmotionCache } from '@emotion/css/create-instance';

import { convertResponsiveStyleToString, useMediaQueryMap } from './response';
import { ReturnStyles, StyleOrGetStyleFn } from './types';

interface CreateStylesFactory {
cache: EmotionCache;
EmotionContext: Context<Emotion>;
hashPriority?: HashPriority;
useTheme: () => any;
}
Expand All @@ -28,18 +27,19 @@ export interface CreateStyleOptions {
* 创建样式基础写法
*/
export const createStylesFactory =
({ hashPriority, cache, useTheme }: CreateStylesFactory) =>
({ hashPriority, useTheme, EmotionContext }: CreateStylesFactory) =>
<Props, Input extends BaseReturnType = BaseReturnType>(
styleOrGetStyle: StyleOrGetStyleFn<Input, Props>,
options?: CreateStyleOptions,
) => {
// 由于 toClassName 方法依赖了用户给 createStyle 传递的 hashPriority,所以需要在这里重新生成 cx 和 toClassName 方法
const { cx, css: toClassName } = createCSS(cache, options?.hashPriority || hashPriority);

// 返回 useStyles 方法,作为 hooks 使用
return (props?: Props): ReturnStyles<Input> => {
const theme = useTheme();

const { cache } = useContext(EmotionContext);
// 由于 toClassName 方法依赖了用户给 createStyle 传递的 hashPriority,所以需要在这里重新生成 cx 和 toClassName 方法
const { cx, css: toClassName } = createCSS(cache, options?.hashPriority || hashPriority);

const responsiveMap = useMediaQueryMap();

const styles = useMemo(() => {
Expand Down Expand Up @@ -103,7 +103,7 @@ export const createStylesFactory =

return useMemo(() => {
const { prefixCls, ...res } = theme;
return { styles, cx: cx, theme: res, prefixCls };
return { styles, cx, theme: res, prefixCls };
}, [styles, theme]);
};
};
45 changes: 21 additions & 24 deletions src/functions/createInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,63 +57,60 @@ export interface CreateOptions<T> {
* 创建一个新的 antd-style 实例
*/
export const createInstance = <T = any>(options: CreateOptions<T>) => {
const defaultKey = options.key || 'css';
const internalOptions = {
...options,
key: options.key ?? 'zcss', // 新建的 instance key 如果不传,则设为 zcss- 使得该 key 和 acss 不一样
speedy: options.speedy ?? false,
};

// TODO: 此处的 emotion 应该是 emotion context 中的 emotion,需要允许外部通过 Provider 进行修改
const emotion = createEmotion({
key: defaultKey,
speedy: options.speedy,
container: options.container,
key: internalOptions.key,
speedy: internalOptions.speedy,
container: internalOptions.container,
});
// 将 cache 存到一个全局
cacheManager.add(emotion.cache);

const { cache, injectGlobal, keyframes } = emotion;
const EmotionContext = createEmotionContext(emotion);

const { cx } = createCSS(cache, options.hashPriority);
const StyleProvider = createStyleProvider(EmotionContext);

// 将 cache 存到全局管理器中
cacheManager.add(emotion.cache);

// ******* 下面这些都和主题相关,如果做了任何改动,都需要排查一遍 ************* //

const CustomThemeContext = createContext<T>(
(options.customToken ? options.customToken : {}) as T,
(internalOptions.customToken ? internalOptions.customToken : {}) as T,
);

const styledThemeContext = options.styled?.ThemeContext;
const styledThemeContext = internalOptions.styled?.ThemeContext;

const StyleEngineContext = createContext<StyleEngine>({
CustomThemeContext,
StyledThemeContext: styledThemeContext,
prefixCls: options?.prefixCls,
prefixCls: internalOptions?.prefixCls,
});

const useTheme = createUseTheme({ StyleEngineContext });

const createStyles = createStylesFactory({
cache,
hashPriority: options.hashPriority,
hashPriority: internalOptions.hashPriority,
useTheme,
EmotionContext,
});

const createGlobalStyle = createGlobalStyleFactory(useTheme);

const createStylish = createStylishFactory(createStyles);

const ThemeProvider = createThemeProvider({
styledConfig: options.styled,
styledConfig: internalOptions.styled,
StyleEngineContext,
useTheme,
});

// ******** 上面这些都和主题相关,如果做了任何改动,都需要排查一遍 ************ //

const EmotionContext = createEmotionContext(emotion);

const StyleProvider = createStyleProvider(EmotionContext, {
speedy: options.speedy,
prefix: defaultKey,
container: options.container,
defaultEmotion: emotion,
});
const { cx } = createCSS(emotion.cache, internalOptions.hashPriority);
const { injectGlobal, keyframes } = emotion;

return {
// ******************** //
Expand Down

0 comments on commit a51d72a

Please sign in to comment.