Skip to content

Commit

Permalink
rework
Browse files Browse the repository at this point in the history
  • Loading branch information
layershifter committed Jul 18, 2023
1 parent a73330f commit c0dac7e
Show file tree
Hide file tree
Showing 18 changed files with 227 additions and 178 deletions.
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Expand Up @@ -102,6 +102,7 @@ export {
StyleBucketName,
// Util
GriffelRenderer,
GriffelInsertionFactory,
} from './types';

// Private exports, are used by devtools
Expand Down
17 changes: 6 additions & 11 deletions packages/core/src/makeResetStyles.ts
Expand Up @@ -3,14 +3,16 @@ import type { GriffelResetStyle } from '@griffel/style-types';
import { DEBUG_RESET_CLASSES } from './constants';
import { resolveResetStyleRules } from './runtime/resolveResetStyleRules';
import type { GriffelRenderer } from './types';
import type { GriffelInsertionFactory } from './types';
import { insertionFactory } from './makeStyles';

export interface MakeResetStylesOptions {
dir: 'ltr' | 'rtl';
renderer: GriffelRenderer;
}

export function makeResetStyles(styles: GriffelResetStyle) {
const insertionCache: Record<string, boolean> = {};
export function makeResetStyles(styles: GriffelResetStyle, factory: GriffelInsertionFactory = insertionFactory) {
const insertStyles = factory();

let ltrClassName: string | null = null;
let rtlClassName: string | null = null;
Expand All @@ -24,16 +26,9 @@ export function makeResetStyles(styles: GriffelResetStyle) {
[ltrClassName, rtlClassName, cssRules] = resolveResetStyleRules(styles);
}

const isLTR = dir === 'ltr';
// As RTL classes are different they should have a different cache key for insertion
const rendererId = isLTR ? renderer.id : renderer.id + 'r';
insertStyles(renderer, dir, { r: cssRules! });

if (insertionCache[rendererId] === undefined) {
renderer.insertCSSRules({ r: cssRules! });
insertionCache[rendererId] = true;
}

const className = isLTR ? ltrClassName : rtlClassName || ltrClassName;
const className = dir === 'ltr' ? ltrClassName : rtlClassName || ltrClassName;

if (process.env.NODE_ENV !== 'production') {
DEBUG_RESET_CLASSES[className] = 1;
Expand Down
27 changes: 11 additions & 16 deletions packages/core/src/makeStaticStyles.ts
Expand Up @@ -2,30 +2,25 @@ import type { GriffelStaticStyles } from '@griffel/style-types';

import { resolveStaticStyleRules } from './runtime/resolveStaticStyleRules';
import type { GriffelRenderer } from './types';
import type { GriffelInsertionFactory } from './types';
import { insertionFactory } from './makeStyles';

export interface MakeStaticStylesOptions {
renderer: GriffelRenderer;
}

/**
* Register static css.
* @param styles - styles object or string.
*/
export function makeStaticStyles(styles: GriffelStaticStyles | GriffelStaticStyles[]) {
const styleCache: Record<string, true> = {};
export function makeStaticStyles(
styles: GriffelStaticStyles | GriffelStaticStyles[],
factory: GriffelInsertionFactory = insertionFactory,
) {
const insertStyles = factory();
const stylesSet: GriffelStaticStyles[] = Array.isArray(styles) ? styles : [styles];

function useStaticStyles(options: MakeStaticStylesOptions): void {
const cacheKey = options.renderer.id;
if (styleCache[cacheKey]) {
return;
}

for (const styleRules of stylesSet) {
options.renderer.insertCSSRules(resolveStaticStyleRules(styleRules));
}

styleCache[cacheKey] = true;
insertStyles(options.renderer, 'ltr', {
// 👇 static rules should be inserted into default bucket
d: resolveStaticStyleRules(stylesSet),
});
}

return useStaticStyles;
Expand Down
26 changes: 19 additions & 7 deletions packages/core/src/makeStyles.ts
Expand Up @@ -2,15 +2,31 @@ import { debugData, isDevToolsEnabled, getSourceURLfromError } from './devtools'
import { resolveStyleRulesForSlots } from './resolveStyleRulesForSlots';
import { reduceToClassNameForSlots } from './runtime/reduceToClassNameForSlots';
import type { CSSClassesMapBySlot, CSSRulesByBucket, GriffelRenderer, StylesBySlots } from './types';
import type { GriffelInsertionFactory } from './types';

export interface MakeStylesOptions {
dir: 'ltr' | 'rtl';
renderer: GriffelRenderer;
}

export function makeStyles<Slots extends string | number>(stylesBySlots: StylesBySlots<Slots>) {
export const insertionFactory: GriffelInsertionFactory = () => {
const insertionCache: Record<string, boolean> = {};

return function insert(renderer: GriffelRenderer, dir: string, cssRules: CSSRulesByBucket) {
console.log('insert', renderer.id, insertionCache[renderer.id], cssRules);
if (insertionCache[renderer.id] === undefined) {
renderer.insertCSSRules(cssRules!);
insertionCache[renderer.id] = true;
}
};
};

export function makeStyles<Slots extends string | number>(
stylesBySlots: StylesBySlots<Slots>,
factory: GriffelInsertionFactory = insertionFactory,
) {
const insertStyles = factory();

let classesMapBySlot: CSSClassesMapBySlot<Slots> | null = null;
let cssRules: CSSRulesByBucket | null = null;

Expand All @@ -30,8 +46,6 @@ export function makeStyles<Slots extends string | number>(stylesBySlots: StylesB
}

const isLTR = dir === 'ltr';
// As RTL classes are different they should have a different cache key for insertion
const rendererId = isLTR ? renderer.id : renderer.id + 'r';

if (isLTR) {
if (ltrClassNamesForSlots === null) {
Expand All @@ -43,10 +57,8 @@ export function makeStyles<Slots extends string | number>(stylesBySlots: StylesB
}
}

if (insertionCache[rendererId] === undefined) {
renderer.insertCSSRules(cssRules!);
insertionCache[rendererId] = true;
}
insertStyles(renderer, dir, cssRules!);

const classNamesForSlots = isLTR
? (ltrClassNamesForSlots as Record<Slots, string>)
: (rtlClassNamesForSlots as Record<Slots, string>);
Expand Down
60 changes: 29 additions & 31 deletions packages/core/src/runtime/resolveStaticStyleRules.test.ts
Expand Up @@ -3,50 +3,48 @@ import { resolveStaticStyleRules } from './resolveStaticStyleRules';
describe('resolveStaticStyleRules', () => {
it('handles font-face', () => {
expect(
resolveStaticStyleRules({
'@font-face': {
fontFamily: 'Open Sans',
src: `url("webfont.woff2") format("woff2")`,
resolveStaticStyleRules([
{
'@font-face': {
fontFamily: 'Open Sans',
src: `url("webfont.woff2") format("woff2")`,
},
},
}),
]),
).toMatchInlineSnapshot(`
Object {
"d": Array [
"@font-face{font-family:Open Sans;src:url(\\"webfont.woff2\\") format(\\"woff2\\");}",
],
}
Array [
"@font-face{font-family:Open Sans;src:url(\\"webfont.woff2\\") format(\\"woff2\\");}",
]
`);
});

it('handles static css', () => {
expect(
resolveStaticStyleRules({
body: {
background: 'blue',
resolveStaticStyleRules([
{
body: {
background: 'blue',
},
'.foo': {
background: 'yellow',
marginLeft: '5px',
},
},
'.foo': {
background: 'yellow',
marginLeft: '5px',
},
}),
]),
).toMatchInlineSnapshot(`
Object {
"d": Array [
"body{background:blue;}",
".foo{background:yellow;margin-left:5px;}",
],
}
Array [
"body{background:blue;}",
".foo{background:yellow;margin-left:5px;}",
]
`);
});

it('handles css string', () => {
expect(resolveStaticStyleRules('body {background: red;} div {color: green;}')).toMatchInlineSnapshot(`
Object {
"d": Array [
"body{background:red;}",
"div{color:green;}",
],
}
expect(resolveStaticStyleRules(['body {background: red;} div {color: green;}'])).toMatchInlineSnapshot(`
Array [
"body{background:red;}",
"div{color:green;}",
]
`);
});
});
38 changes: 19 additions & 19 deletions packages/core/src/runtime/resolveStaticStyleRules.ts
@@ -1,30 +1,30 @@
import type { GriffelStaticStyles } from '@griffel/style-types';
import type { CSSRulesByBucket } from '../types';

import type { CSSBucketEntry } from '../types';
import { compileCSSRules } from './compileCSSRules';
import { compileStaticCSS } from './compileStaticCSS';

export function resolveStaticStyleRules(styles: GriffelStaticStyles, result: CSSRulesByBucket = {}): CSSRulesByBucket {
if (typeof styles === 'string') {
const cssRules = compileCSSRules(styles, false);
export function resolveStaticStyleRules(
stylesSet: GriffelStaticStyles[],
result: CSSBucketEntry[] = [],
): CSSBucketEntry[] {
for (const styles of stylesSet) {
if (typeof styles === 'string') {
const cssRules = compileCSSRules(styles, false);

for (const rule of cssRules) {
addResolvedStyles(rule, result);
}
} else {
// eslint-disable-next-line guard-for-in
for (const property in styles) {
const value = styles[property];
const staticCSS = compileStaticCSS(property, value);
for (const rule of cssRules) {
result.push(rule);
}
} else {
// eslint-disable-next-line guard-for-in
for (const property in styles) {
const value = styles[property];
const staticCSS = compileStaticCSS(property, value);

addResolvedStyles(staticCSS, result);
result.push(staticCSS);
}
}
}

return result;
}

function addResolvedStyles(cssRule: string, result: CSSRulesByBucket = {}): void {
// 👇 static rules should be inserted into default bucket
result.d = result.d || [];
result.d.push(cssRule);
}
6 changes: 6 additions & 0 deletions packages/core/src/types.ts
Expand Up @@ -87,6 +87,12 @@ export type CSSRulesByBucket = {
c?: CSSBucketEntry[];
};

export type GriffelInsertionFactory = () => (
renderer: GriffelRenderer,
dir: string,
cssRules: CSSRulesByBucket,
) => void;

/** @internal */
export type CSSBucketEntry = string | [string, Record<string, unknown>];

Expand Down
3 changes: 3 additions & 0 deletions packages/react/jest.config.ts
Expand Up @@ -5,6 +5,9 @@ export default {
transform: {
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/react/babel'] }],
},
globals: {
IS_REACT_ACT_ENVIRONMENT: true,
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/packages/react',
};
11 changes: 3 additions & 8 deletions packages/react/src/RendererContext.tsx
@@ -1,6 +1,8 @@
import { createDOMRenderer, rehydrateRendererCache } from '@griffel/core';
import * as React from 'react';
import type { GriffelRenderer } from '@griffel/core';
import * as React from 'react';

import { canUseDOM } from './utils/canUseDOM';

export interface RendererProviderProps {
/** An instance of Griffel renderer. */
Expand All @@ -17,13 +19,6 @@ export interface RendererProviderProps {
children: React.ReactNode;
}

/**
* Verifies if an application can use DOM.
*/
function canUseDOM(): boolean {
return typeof window !== 'undefined' && !!(window.document && window.document.createElement);
}

/**
* @private
*/
Expand Down
30 changes: 5 additions & 25 deletions packages/react/src/__styles.ts
@@ -1,9 +1,8 @@
import { reduceToClassNameForSlots } from '@griffel/core';
import { __styles as vanillaStyles } from '@griffel/core';
import type { CSSClassesMapBySlot, CSSRulesByBucket } from '@griffel/core';

import { useRenderer } from './RendererContext';
import { useTextDirection } from './TextDirectionContext';
import { useInsertionEffect } from './useInsertionEffect';

/**
* A version of makeStyles() that accepts build output as an input and skips all runtime transforms.
Expand All @@ -15,31 +14,12 @@ export function __styles<Slots extends string>(
classesMapBySlot: CSSClassesMapBySlot<Slots>,
cssRules: CSSRulesByBucket,
) {
let ltrClassNamesForSlots: Record<Slots, string> | null = null;
let rtlClassNamesForSlots: Record<Slots, string> | null = null;
const getStyles = vanillaStyles(classesMapBySlot, cssRules);

function computeClasses(): Record<Slots, string> {
return function useClasses(): Record<Slots, string> {
const dir = useTextDirection();
const renderer = useRenderer();

const isLTR = dir === 'ltr';

if (isLTR) {
if (ltrClassNamesForSlots === null) {
ltrClassNamesForSlots = reduceToClassNameForSlots(classesMapBySlot, dir);
}
} else {
if (rtlClassNamesForSlots === null) {
rtlClassNamesForSlots = reduceToClassNameForSlots(classesMapBySlot, dir);
}
}

useInsertionEffect(() => {
renderer.insertCSSRules(cssRules!);
}, [isLTR, renderer]);

return isLTR ? (ltrClassNamesForSlots as Record<Slots, string>) : (rtlClassNamesForSlots as Record<Slots, string>);
}

return computeClasses;
return getStyles({ dir, renderer });
};
}

0 comments on commit c0dac7e

Please sign in to comment.