-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.ts
86 lines (64 loc) 路 2.33 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import { lazyEvaluation } from "jigjs/template/render";
export type ElementStyle = {
'@media': {
[query: string]: ElementStyle
}
} | Record<string, Partial<CSSStyleDeclaration> | Record<string, string>>;
const SEED = 5381;
// When we have separate strings it's useful to run a progressive
// version of djb2 where we pretend that we're still looping over
// the same string
// same of
// https://github.com/styled-components/styled-components/blob/216f03deb084b8c8c8980a35e25924457ff8f6e4/packages/styled-components/src/utils/generateAlphabeticName.js
const phash = (h: number, x: string): number => {
let i = x.length;
while (i) {
h = (h * 33) ^ x.charCodeAt(--i);
}
return h;
};
// This is a djb2 hashing function
const hash = (x: string): number => {
return phash(SEED, x);
};
const JIG_STYLE_ID = 'jig-style-element'
export type JigCssClass = {
jigLazyRun: (document: Document) => string;
};
export const css = (template: TemplateStringsArray, ...values: unknown[]): JigCssClass =>
lazyEvaluation((document) => jigcss(document)(template, ...values))
const jigcss = (document: Document) => {
const getOrCreateStyleElement = () => {
return document.getElementById(JIG_STYLE_ID) || createStyleElement();
}
const createStyleElement = () => {
const element = document.createElement('style');
element.id = JIG_STYLE_ID;
document.head.appendChild(element);
return element;
}
const styleElement = getOrCreateStyleElement();
const appendToElement = (classes: string) => {
styleElement.appendChild(document.createTextNode(classes));
}
const hasClassHash = (className: string) => {
return styleElement.innerHTML.includes(className);
}
const formatStyle = (style: string, className: string) => {
const ampPlaceholder = '__jigcss-placeholder_amp_to_be_kept_jigcss-placeholder__';
return style
.replace(/\\&/g, ampPlaceholder)
.replace(/&/g, `.${className}`)
.replace(new RegExp(ampPlaceholder, 'g'), '&');
}
return (template: TemplateStringsArray, ...values: unknown[]): string => {
const style = String.raw(template, ...values);
const styleHash = hash(style);
const className = `jc-${styleHash}`;
if (hasClassHash(`.${className}`)) {
return className;
}
appendToElement(formatStyle(style, className));
return className;
};
}