Skip to content

Commit

Permalink
Merge f22b766 into ddf9cf7
Browse files Browse the repository at this point in the history
  • Loading branch information
benduran committed Sep 27, 2020
2 parents ddf9cf7 + f22b766 commit fcd6ca6
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 11 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,21 @@ const [styles] = createStyles({
},
});
// you can also update an existing stylesheet by adding or removing styles. Only applies when "flush" is set to true
const [styles, _, updateSheet] = createStyles({
myRule: {
height: '400px,
},
});
const [updatedStyles] = updateSheet({
anotherRule: {
textTransform: 'uppercase',
},
myRule: {
height: '200px',
},
}); // will update replace the existing sheet's contents and you can use the updatedClassnames here

```

```javascript
Expand Down
46 changes: 37 additions & 9 deletions src/createStyles.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Properties } from 'csstype';

import { SimpleStyleRules } from './types';
import generateClassName from './generateClassName';
import { generateClassName } from './generateClassName';
import { getPosthooks } from './plugins';

export interface CreateStylesOptions {
Expand Down Expand Up @@ -98,13 +98,20 @@ function replaceBackReferences<O extends { [key: string]: string }>(out: O, shee
return getPosthooks().reduce((prev, hook) => hook(prev), outputSheetContents);
}

function flushSheetContents(sheetContents: string) {
// In case we're in come weird test environment that doesn't support JSDom
if (typeof document !== 'undefined' && document.head && document.head.appendChild) {
function createSheet(sheetContents: string) {
if (typeof document !== 'undefined' && document.head && document.head.appendChild && typeof document.createElement === 'function') {
const styleTag = document.createElement('style');
styleTag.innerHTML = sheetContents;
document.head.appendChild(styleTag);
return styleTag;
}
return null;
}

function flushSheetContents(sheetContents: string) {
// In case we're in come weird test environment that doesn't support JSDom
const styleTag = createSheet(sheetContents);
if (styleTag) document.head.appendChild(styleTag);
return styleTag;
}

function coerceCreateStylesOptions(options?: Partial<CreateStylesOptions>): CreateStylesOptions {
Expand Down Expand Up @@ -142,19 +149,40 @@ export default function createStyles<
>(
rules: T,
options?: Partial<CreateStylesOptions>,
): [O, string] {
) {
const coerced = coerceCreateStylesOptions(options);
const [out, sheetContents, mediaQueriesContents] = execCreateStyles(rules, coerced, null);

const mergedContents = `${sheetContents}${mediaQueriesContents}`;

const replacedSheetContents = replaceBackReferences(out, mergedContents);

if (coerced.flush) flushSheetContents(replacedSheetContents);
let sheet: ReturnType<typeof flushSheetContents> = null;

const updateSheet = <
T2 extends SimpleStyleRules,
K2 extends keyof T2,
O2 extends { [classKey in K2]: string },
>(updatedRules: T2): [O2, string] | null => {
if (sheet) {
const [updatedOut, updatedSheetContents, updatedMediaQueriesContents] = execCreateStyles(updatedRules, { flush: false }, null);

const updatedMergedContents = `${updatedSheetContents}${updatedMediaQueriesContents}`;

const updatedReplacedSheetContents = replaceBackReferences(out, updatedMergedContents);
sheet.innerHTML = updatedReplacedSheetContents;
return [updatedOut as unknown as O2, updatedReplacedSheetContents];
}
return null;
};

if (coerced.flush) sheet = flushSheetContents(replacedSheetContents);
// Need this TS cast to get solid code assist from the consumption-side
return [
out as unknown as O,
out as unknown,
replacedSheetContents,
];
updateSheet,
] as [O, string, typeof updateSheet];
}

export type CreateStylesArgs = Parameters<typeof createStyles>;
2 changes: 1 addition & 1 deletion src/generateClassName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ export function getUniqueSuffix(): string {
return out;
}

export default function generateClassName(c: string): string {
export function generateClassName(c: string): string {
return `${c}${getUniqueSuffix()}`;
}
2 changes: 1 addition & 1 deletion test/generateClassName.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import generateClassName, { setSeed } from '../src/generateClassName';
import { generateClassName, setSeed } from '../src/generateClassName';

describe('generateClassName tests', () => {
it('Should generate multiple unique classnames', () => {
Expand Down
30 changes: 30 additions & 0 deletions test/updateStyles.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { createStyles } from '../src';

describe('updateStyles tests', () => {
beforeAll(() => {
document.querySelectorAll('style').forEach(s => s.remove());
});
it('Should create styles, then update them without creating a new sheet', () => {
const [originalStyles, originalContents, updateSheet] = createStyles({
one: {
backgroundColor: 'grape',
boxSizing: 'border-box',
},
});
expect(typeof updateSheet).toBe('function');
const sheet = document.head.querySelector('style');
expect(sheet?.innerHTML).toBe(originalContents);
const updates = updateSheet({
one: {
backgroundColor: 'red',
},
});
expect(updates).not.toBeNull();
const [updatedStyles, updatedContents] = updates!;
expect(originalStyles).not.toBe(updatedStyles);
expect(originalContents).not.toBe(updatedContents);
expect(document.head.querySelectorAll('style').length).toBe(1);
expect(document.head.querySelector('style')?.innerHTML).toBe(updatedContents);
expect(updatedContents).toBe(`.${updatedStyles.one}{background-color:red;}`);
});
});

0 comments on commit fcd6ca6

Please sign in to comment.