@slimr/css 2.1.11 → 2.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @slimr/css
2
2
 
3
- A tiny alternative to the popular emotion library
3
+ tiny css-in-js features, inspired by the popular emotion library
4
4
 
5
5
  `@slimr` is a set of slim React (hence '@slimr') libs:
6
6
 
@@ -16,9 +16,9 @@ A tiny alternative to the popular emotion library
16
16
 
17
17
  Pros:
18
18
 
19
- - Much less bundle size
19
+ - Much smaller (less bundle size)
20
20
  - Less is more: faster, less bugs, no breaking changes
21
- - Is progressive -- lazy loads styles along with component if component is lazy
21
+ - Is progressive -- lazy loads styles
22
22
  - Css shorthand props like [chakra-ui](https://chakra-ui.com/docs/styled-system/style-props):
23
23
  - `m` --> `margin`
24
24
  - `mx` --> `margin-left` and bottom
@@ -35,11 +35,7 @@ Pros:
35
35
  }
36
36
  ```
37
37
 
38
- - Breakpoints are `[30em, 48em, 62em, 80em, 96em]`
39
-
40
- Cons:
41
-
42
- - No SSR support
38
+ - Breakpoints are `[30em, 48em, 62em, 80em, 96em]` and can be overridden by setting `css.breakpoints`
43
39
 
44
40
  ## Setup/Install
45
41
 
@@ -47,6 +43,30 @@ Cons:
47
43
  npm i @slimr/css
48
44
  ```
49
45
 
46
+ ## addCss
47
+
48
+ Injects css to the page head
49
+
50
+ - Lazy: Will not be added until the component mounts, if called from within a component
51
+ - Batches dom changes for better performance
52
+ - Has local cache to recall prior adds, to reduce duplicates and dom changes
53
+
54
+ @param css - css to be injected
55
+ @returns void
56
+
57
+ ## `css` (alias for `createClass`)
58
+
59
+ ## `classJoin`
60
+
61
+ Joins class names and omits falsey props
62
+
63
+ ```typescript
64
+ classJoin('a', 'b', 'c') // 'a b c'
65
+ classJoin('a', 0, 'b', null, 'c') // 'a b c'
66
+ ```
67
+
68
+ ## Shorthang Props (`shorthandPropsMap` and `ShorthandProps`)
69
+
50
70
  ## Usage
51
71
 
52
72
  ```tsx
@@ -0,0 +1,43 @@
1
+ import { T2SProps } from '@slimr/util';
2
+ /**
3
+ * Injects css to the page head
4
+ *
5
+ * - Lazy: Will not be added until the component mounts, if called from within a component
6
+ * - Batches dom changes for better performance
7
+ * - Has local cache to recall prior adds, to reduce duplicates and dom changes
8
+ *
9
+ * @param css - css to be injected
10
+ * @returns void
11
+ */
12
+ export declare function addCss(css: string): void;
13
+ export declare namespace addCss {
14
+ var que: Set<string>;
15
+ var count: number;
16
+ }
17
+ /**
18
+ * Joins class names and omits falsey props
19
+ *
20
+ * @param classes - class names to be joined
21
+ * @returns a string of joined class names
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * classJoin('a', 'b', 'c') // 'a b c'
26
+ * classJoin('a', 0, 'b', null, 'c') // 'a b c'
27
+ * ```
28
+ */
29
+ export declare function classJoin(...classes: (string | 0 | null | undefined)[]): string;
30
+ /**
31
+ * Injects css and creates unique class names
32
+ *
33
+ * - Skips if already added
34
+ *
35
+ * @param cssString - string or template string, to be injected
36
+ * @returns a unique class name
37
+ */
38
+ export declare function createClass(...p: T2SProps): string;
39
+ export declare namespace createClass {
40
+ var breakPoints: string[];
41
+ var count: number;
42
+ var history: Map<string, string>;
43
+ }
@@ -1,13 +1,95 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createClass = exports.addCss = exports.t2s = exports.shorthandProps = exports.shorthandPropsMap = exports.classJoin = exports.breakPoints = void 0;
4
- /** Breakpoints like chakra */
5
- exports.breakPoints = ['30em', '48em', '62em', '80em', '96em'];
6
- /** Joins class names and filters out blanks */
3
+ exports.createClass = exports.classJoin = exports.addCss = void 0;
4
+ const util_1 = require("@slimr/util");
5
+ const shorthandProps_js_1 = require("./shorthandProps.js");
6
+ /**
7
+ * Injects css to the page head
8
+ *
9
+ * - Lazy: Will not be added until the component mounts, if called from within a component
10
+ * - Batches dom changes for better performance
11
+ * - Has local cache to recall prior adds, to reduce duplicates and dom changes
12
+ *
13
+ * @param css - css to be injected
14
+ * @returns void
15
+ */
16
+ function addCss(css) {
17
+ addCss.que.add(css);
18
+ setTimeout(() => {
19
+ const css = [...addCss.que].join('\n');
20
+ if (css) {
21
+ addCss.que.clear();
22
+ const s = document.createElement('style');
23
+ s.id = `u${addCss.count++}`;
24
+ s.innerHTML = css;
25
+ document.head.appendChild(s);
26
+ }
27
+ }, 0);
28
+ }
29
+ exports.addCss = addCss;
30
+ addCss.que = new Set();
31
+ addCss.count = 0;
32
+ /**
33
+ * Joins class names and omits falsey props
34
+ *
35
+ * @param classes - class names to be joined
36
+ * @returns a string of joined class names
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * classJoin('a', 'b', 'c') // 'a b c'
41
+ * classJoin('a', 0, 'b', null, 'c') // 'a b c'
42
+ * ```
43
+ */
7
44
  function classJoin(...classes) {
8
45
  return classes.filter(c => c && typeof c === 'string').join(' ');
9
46
  }
10
47
  exports.classJoin = classJoin;
48
+ /**
49
+ * Injects css and creates unique class names
50
+ *
51
+ * - Skips if already added
52
+ *
53
+ * @param cssString - string or template string, to be injected
54
+ * @returns a unique class name
55
+ */
56
+ function createClass(...p) {
57
+ let css = (0, util_1.t2s)(...p);
58
+ if (!css)
59
+ return '';
60
+ let className = createClass.history.get(css);
61
+ if (!className) {
62
+ className = 's' + createClass.count++;
63
+ createClass.history.set(css, className);
64
+ css = deleteComments(css);
65
+ css = (0, shorthandProps_js_1.expandShorthands)(css);
66
+ css = expandArrayValues(css);
67
+ const qs = findQueries(css);
68
+ for (const q of qs.reverse()) {
69
+ css = css.slice(0, q.start) + css.slice(q.end);
70
+ }
71
+ css = `.${className}{\n${css}\n}\n`;
72
+ css += qs
73
+ .map(q => {
74
+ if (q.query.startsWith('&')) {
75
+ return `.${className}${q.query.slice(1)}{\n${q.innerBody}\n}`;
76
+ }
77
+ if (q.query.startsWith('@keyframes')) {
78
+ return q.outerBody;
79
+ }
80
+ return `${q.query}{\n.${className}{${q.innerBody}\n}\n}`;
81
+ })
82
+ .join('\n');
83
+ css = trimByLine(css) + '\n\n';
84
+ addCss(css);
85
+ }
86
+ return className;
87
+ }
88
+ exports.createClass = createClass;
89
+ /** Breakpoints like chakra */
90
+ createClass.breakPoints = ['30em', '48em', '62em', '80em', '96em'];
91
+ createClass.count = 0;
92
+ createClass.history = new Map();
11
93
  /** delete css comments **/
12
94
  function deleteComments(css) {
13
95
  return css.replace(/{\/\*[\s\S]*?(?=\*\/})\*\/}/gm, '');
@@ -35,7 +117,7 @@ function expandArrayValues(css) {
35
117
  if (i === 0) {
36
118
  return `${prop}: ${val};`;
37
119
  }
38
- return `@media (min-width: ${exports.breakPoints[i - 1]}) { ${prop}: ${val}; }`;
120
+ return `@media (min-width: ${createClass.breakPoints[i - 1]}) { ${prop}: ${val}; }`;
39
121
  })
40
122
  .join('\n');
41
123
  }
@@ -43,48 +125,6 @@ function expandArrayValues(css) {
43
125
  })
44
126
  .join('\n');
45
127
  }
46
- exports.shorthandPropsMap = {
47
- ai: 'align-items',
48
- b: 'border',
49
- br: 'border-radius',
50
- bg: 'background',
51
- c: 'color',
52
- d: 'display',
53
- f: 'flex',
54
- fd: 'flex-direction',
55
- i: 'inset',
56
- h: 'height',
57
- jc: 'justify-content',
58
- m: 'margin',
59
- ml: 'margin-left',
60
- mr: 'margin-right',
61
- mt: 'margin-top',
62
- mb: 'margin-bottom',
63
- maxW: 'max-width',
64
- minW: 'min-width',
65
- p: 'padding',
66
- pl: 'padding-left',
67
- pr: 'padding-right',
68
- pt: 'padding-top',
69
- pb: 'padding-bottom',
70
- pos: 'position',
71
- ta: 'text-align',
72
- w: 'width',
73
- z: 'z-index',
74
- };
75
- exports.shorthandProps = [...Object.keys(exports.shorthandPropsMap), 'mx', 'my', 'px', 'py'];
76
- /** Expand short-hand css props to full */
77
- function expandProps(css) {
78
- css = '\n' + css; // inject a newline to make the regex easier
79
- // Handle 'mx', 'my', 'px', 'py'
80
- css = css
81
- .replace(/([mp])x:([^;]*)/g, '$1l:$2;\n$1r:$2')
82
- .replace(/([mp])y:([^;]*);/g, '$1t:$2;\n$1b:$2');
83
- Object.entries(exports.shorthandPropsMap).forEach(([k, v]) => {
84
- css = css.replace(new RegExp(`([ \n\t;])${k}:`, 'g'), `$1${v}:`);
85
- });
86
- return css.trim();
87
- }
88
128
  /** Find @keyframes, @media, @container queries in css **/
89
129
  function findQueries(css) {
90
130
  const queries = [];
@@ -120,95 +160,11 @@ function findQueries(css) {
120
160
  return queries;
121
161
  }
122
162
  /** Trims whitespace for every line */
123
- function trim(css) {
163
+ function trimByLine(css) {
124
164
  return css
125
165
  .split('\n')
126
166
  .map(l => l.trim())
127
167
  .filter(l => l)
128
168
  .join('\n');
129
169
  }
130
- /**
131
- * Assemble a string from a template string array and a list of placeholders.
132
- *
133
- * - If the first argument is a string, it is returned as is.
134
- *
135
- * i.e.
136
- * myFoo(...props: TemplateStringProps) => {
137
- * const inputStr = t2s(...props);
138
- * }
139
- * myFoo`hello ${name}` => 'hello world'
140
- * myFoo(`hello ${name}`) => 'hello world'
141
- */
142
- function t2s(...tsp) {
143
- const [s, ...p] = tsp;
144
- return typeof s === 'string' ? s : s.map((s, i) => s + (p?.[i] ?? '')).join('');
145
- }
146
- exports.t2s = t2s;
147
- /**
148
- * Injects css to the page
149
- *
150
- * - Batches adds for performance
151
- *
152
- * @param css - css to be injected
153
- * @returns void
154
- */
155
- function addCss(css) {
156
- addCss.que.add(css);
157
- setTimeout(() => {
158
- const css = [...addCss.que].join('\n');
159
- if (css) {
160
- addCss.que.clear();
161
- const s = document.createElement('style');
162
- s.id = `u${addCss.count++}`;
163
- s.innerHTML = css;
164
- document.head.appendChild(s);
165
- }
166
- }, 0);
167
- }
168
- exports.addCss = addCss;
169
- addCss.que = new Set();
170
- addCss.count = 0;
171
- /**
172
- * Injects css and creates unique class names
173
- *
174
- * - Skips if already added
175
- *
176
- * @param css - string or template string, to be injected
177
- * @returns a unique class name
178
- */
179
- function createClass(...p) {
180
- let css = t2s(...p);
181
- if (!css)
182
- return '';
183
- let className = createClass.history.get(css);
184
- if (!className) {
185
- className = 's' + createClass.count++;
186
- createClass.history.set(css, className);
187
- css = deleteComments(css);
188
- css = expandProps(css);
189
- css = expandArrayValues(css);
190
- const qs = findQueries(css);
191
- for (const q of qs.reverse()) {
192
- css = css.slice(0, q.start) + css.slice(q.end);
193
- }
194
- css = `.${className}{\n${css}\n}\n`;
195
- css += qs
196
- .map(q => {
197
- if (q.query.startsWith('&')) {
198
- return `.${className}${q.query.slice(1)}{\n${q.innerBody}\n}`;
199
- }
200
- if (q.query.startsWith('@keyframes')) {
201
- return q.outerBody;
202
- }
203
- return `${q.query}{\n.${className}{${q.innerBody}\n}\n}`;
204
- })
205
- .join('\n');
206
- css = trim(css) + '\n\n';
207
- addCss(css);
208
- }
209
- return className;
210
- }
211
- exports.createClass = createClass;
212
- createClass.count = 0;
213
- createClass.history = new Map();
214
170
  //# sourceMappingURL=createClass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createClass.js","sourceRoot":"","sources":["../src/createClass.ts"],"names":[],"mappings":";;;AAAA,sCAAyC;AAEzC,2DAAoD;AAEpD;;;;;;;;;GASG;AACH,SAAgB,MAAM,CAAC,GAAW;IAChC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACnB,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACtC,IAAI,GAAG,EAAE;YACP,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAA;YAClB,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;YACzC,CAAC,CAAC,EAAE,GAAG,IAAI,MAAM,CAAC,KAAK,EAAE,EAAE,CAAA;YAC3B,CAAC,CAAC,SAAS,GAAG,GAAG,CAAA;YACjB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;SAC7B;IACH,CAAC,EAAE,CAAC,CAAC,CAAA;AACP,CAAC;AAZD,wBAYC;AACD,MAAM,CAAC,GAAG,GAAG,IAAI,GAAG,EAAU,CAAA;AAC9B,MAAM,CAAC,KAAK,GAAG,CAAC,CAAA;AAEhB;;;;;;;;;;;GAWG;AACH,SAAgB,SAAS,CAAC,GAAG,OAA0C;IACrE,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAClE,CAAC;AAFD,8BAEC;AAED;;;;;;;GAOG;AACH,SAAgB,WAAW,CAAC,GAAG,CAAW;IACxC,IAAI,GAAG,GAAG,IAAA,UAAG,EAAC,GAAG,CAAC,CAAC,CAAA;IACnB,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAA;IACnB,IAAI,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC5C,IAAI,CAAC,SAAS,EAAE;QACd,SAAS,GAAG,GAAG,GAAG,WAAW,CAAC,KAAK,EAAE,CAAA;QACrC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QAEvC,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,CAAA;QACzB,GAAG,GAAG,IAAA,oCAAgB,EAAC,GAAG,CAAC,CAAA;QAC3B,GAAG,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAA;QAC5B,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;QAE3B,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE;YAC5B,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;SAC/C;QAED,GAAG,GAAG,IAAI,SAAS,MAAM,GAAG,OAAO,CAAA;QACnC,GAAG,IAAI,EAAE;aACN,GAAG,CAAC,CAAC,CAAC,EAAE;YACP,IAAI,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;gBAC3B,OAAO,IAAI,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,KAAK,CAAA;aAC9D;YACD,IAAI,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE;gBACpC,OAAO,CAAC,CAAC,SAAS,CAAA;aACnB;YACD,OAAO,GAAG,CAAC,CAAC,KAAK,OAAO,SAAS,IAAI,CAAC,CAAC,SAAS,QAAQ,CAAA;QAC1D,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAA;QAEb,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,MAAM,CAAA;QAE9B,MAAM,CAAC,GAAG,CAAC,CAAA;KACZ;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAnCD,kCAmCC;AACD,8BAA8B;AAC9B,WAAW,CAAC,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAClE,WAAW,CAAC,KAAK,GAAG,CAAC,CAAA;AACrB,WAAW,CAAC,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAA;AAE/C,2BAA2B;AAC3B,SAAS,cAAc,CAAC,GAAW;IACjC,OAAO,GAAG,CAAC,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC,CAAA;AACzD,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,GAAW;IACpC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAA;IAClC,OAAO,GAAG;SACP,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE;QACP,6CAA6C;QAC7C,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,iCAAiC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QACpF,IAAI,IAAI,EAAE;YACR,OAAO,IAAI;iBACR,KAAK,CAAC,GAAG,CAAC;iBACV,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;gBACd,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;gBAChB,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,WAAW;oBAAE,OAAO,EAAE,CAAA;gBAC5D,IAAI,CAAC,KAAK,CAAC,EAAE;oBACX,OAAO,GAAG,IAAI,KAAK,GAAG,GAAG,CAAA;iBAC1B;gBACD,OAAO,sBAAsB,WAAW,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,KAAK,GAAG,KAAK,CAAA;YACrF,CAAC,CAAC;iBACD,IAAI,CAAC,IAAI,CAAC,CAAA;SACd;QACD,OAAO,CAAC,CAAA;IACV,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,CAAC;AAED,0DAA0D;AAC1D,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,OAAO,GAAG,EAAE,CAAA;IAClB,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;QACtC,IAAI,KAAK,GAAG,EAAE,CAAA;QACd,IAAI,SAAS,GAAG,CAAC,CAAA;QACjB,IAAI,SAAS,GAAG,CAAC,CAAA;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,KAAM,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC1C,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;gBAClB,IAAI,SAAS,KAAK,CAAC,EAAE;oBACnB,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;oBACpC,SAAS,GAAG,CAAC,GAAG,CAAC,CAAA;iBAClB;gBACD,SAAS,EAAE,CAAA;aACZ;iBAAM,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;gBACzB,SAAS,EAAE,CAAA;gBACX,IAAI,SAAS,KAAK,CAAC,EAAE;oBACnB,OAAO,CAAC,IAAI,CAAC;wBACX,KAAK,EAAE,CAAC,CAAC,KAAK;wBACd,GAAG,EAAE,CAAC,GAAG,CAAC;wBACV,KAAK;wBACL,SAAS,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;wBACpC,SAAS,EAAE,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;qBACnC,CAAC,CAAA;oBACF,MAAK;iBACN;aACF;SACF;QACD,IAAI,SAAS,KAAK,CAAC;YAAE,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,iBAAiB,GAAG,GAAG,CAAC,CAAA;KACpE;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,sCAAsC;AACtC,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,GAAG;SACP,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SAClB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;SACd,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,CAAC"}
@@ -1,14 +1,98 @@
1
- /** Breakpoints like chakra */
2
- export const breakPoints = ['30em', '48em', '62em', '80em', '96em']
1
+ import {T2SProps, t2s} from '@slimr/util'
3
2
 
4
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
- type allowableAny = any
3
+ import {expandShorthands} from './shorthandProps.js'
6
4
 
7
- /** Joins class names and filters out blanks */
8
- export function classJoin(...classes: allowableAny[]) {
5
+ /**
6
+ * Injects css to the page head
7
+ *
8
+ * - Lazy: Will not be added until the component mounts, if called from within a component
9
+ * - Batches dom changes for better performance
10
+ * - Has local cache to recall prior adds, to reduce duplicates and dom changes
11
+ *
12
+ * @param css - css to be injected
13
+ * @returns void
14
+ */
15
+ export function addCss(css: string) {
16
+ addCss.que.add(css)
17
+ setTimeout(() => {
18
+ const css = [...addCss.que].join('\n')
19
+ if (css) {
20
+ addCss.que.clear()
21
+ const s = document.createElement('style')
22
+ s.id = `u${addCss.count++}`
23
+ s.innerHTML = css
24
+ document.head.appendChild(s)
25
+ }
26
+ }, 0)
27
+ }
28
+ addCss.que = new Set<string>()
29
+ addCss.count = 0
30
+
31
+ /**
32
+ * Joins class names and omits falsey props
33
+ *
34
+ * @param classes - class names to be joined
35
+ * @returns a string of joined class names
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * classJoin('a', 'b', 'c') // 'a b c'
40
+ * classJoin('a', 0, 'b', null, 'c') // 'a b c'
41
+ * ```
42
+ */
43
+ export function classJoin(...classes: (string | 0 | null | undefined)[]) {
9
44
  return classes.filter(c => c && typeof c === 'string').join(' ')
10
45
  }
11
46
 
47
+ /**
48
+ * Injects css and creates unique class names
49
+ *
50
+ * - Skips if already added
51
+ *
52
+ * @param cssString - string or template string, to be injected
53
+ * @returns a unique class name
54
+ */
55
+ export function createClass(...p: T2SProps) {
56
+ let css = t2s(...p)
57
+ if (!css) return ''
58
+ let className = createClass.history.get(css)
59
+ if (!className) {
60
+ className = 's' + createClass.count++
61
+ createClass.history.set(css, className)
62
+
63
+ css = deleteComments(css)
64
+ css = expandShorthands(css)
65
+ css = expandArrayValues(css)
66
+ const qs = findQueries(css)
67
+
68
+ for (const q of qs.reverse()) {
69
+ css = css.slice(0, q.start) + css.slice(q.end)
70
+ }
71
+
72
+ css = `.${className}{\n${css}\n}\n`
73
+ css += qs
74
+ .map(q => {
75
+ if (q.query.startsWith('&')) {
76
+ return `.${className}${q.query.slice(1)}{\n${q.innerBody}\n}`
77
+ }
78
+ if (q.query.startsWith('@keyframes')) {
79
+ return q.outerBody
80
+ }
81
+ return `${q.query}{\n.${className}{${q.innerBody}\n}\n}`
82
+ })
83
+ .join('\n')
84
+
85
+ css = trimByLine(css) + '\n\n'
86
+
87
+ addCss(css)
88
+ }
89
+ return className
90
+ }
91
+ /** Breakpoints like chakra */
92
+ createClass.breakPoints = ['30em', '48em', '62em', '80em', '96em']
93
+ createClass.count = 0
94
+ createClass.history = new Map<string, string>()
95
+
12
96
  /** delete css comments **/
13
97
  function deleteComments(css: string) {
14
98
  return css.replace(/{\/\*[\s\S]*?(?=\*\/})\*\/}/gm, '')
@@ -35,7 +119,7 @@ function expandArrayValues(css: string) {
35
119
  if (i === 0) {
36
120
  return `${prop}: ${val};`
37
121
  }
38
- return `@media (min-width: ${breakPoints[i - 1]}) { ${prop}: ${val}; }`
122
+ return `@media (min-width: ${createClass.breakPoints[i - 1]}) { ${prop}: ${val}; }`
39
123
  })
40
124
  .join('\n')
41
125
  }
@@ -44,117 +128,6 @@ function expandArrayValues(css: string) {
44
128
  .join('\n')
45
129
  }
46
130
 
47
- export interface ShorthandProps {
48
- /** shorthand for css:align-items */
49
- ai?: string
50
- /** shorthand for css:border */
51
- b?: string | number
52
- /** shorthand for css:border-radius */
53
- br?: string | number
54
- /** shorthand for css:background */
55
- bg?: string
56
- /** shorthand for css:color */
57
- c?: string
58
- /** shorthand for css:display */
59
- d?: string
60
- /** shorthand for css:flex */
61
- f?: string
62
- /** shorthand for css:flex-direction */
63
- fd?: string
64
- /** shorthand for css:height */
65
- h?: number | string
66
- /** shorthand for css:inset */
67
- i?: number | string
68
- /** shorthand for css:justify-content */
69
- jc?: string
70
- /** shorthand for css:margin */
71
- m?: number | string
72
- /** shorthand for css:margin-left */
73
- ml?: number | string
74
- /** shorthand for css:margin-right */
75
- mr?: number | string
76
- /** shorthand for css:margin-top */
77
- mt?: number | string
78
- /** shorthand for css:margin-bottom */
79
- mb?: number | string
80
- /** shorthand for css:margin-top & margin-bottom */
81
- my?: number | string
82
- /** shorthand for css:margin-left & margin-right */
83
- mx?: number | string
84
- /** shorthand for css:max-width */
85
- maxW?: number | string
86
- /** shorthand for css:min-width */
87
- minW?: number | string
88
- /** shorthand for css:padding */
89
- p?: number | string
90
- /** shorthand for css:padding-left */
91
- pl?: number | string
92
- /** shorthand for css:padding-right */
93
- pr?: number | string
94
- /** shorthand for css:padding-top */
95
- pt?: number | string
96
- /** shorthand for css:padding-bottom */
97
- pb?: number | string
98
- /** shorthand for css:padding-top & padding-bottom */
99
- py?: number | string
100
- /** shorthand for css:padding-left & padding-right */
101
- px?: number | string
102
- /** shorthand for css:position */
103
- pos?: number | string
104
- /** shorthand for css:text-align */
105
- ta?: string
106
- /** shorthand for css:width */
107
- w?: number | string
108
- /** shorthand for css:z-index */
109
- z?: number | string
110
- }
111
- export const shorthandPropsMap: Record<
112
- keyof Omit<ShorthandProps, 'mx' | 'my' | 'px' | 'py'>,
113
- string
114
- > = {
115
- ai: 'align-items',
116
- b: 'border',
117
- br: 'border-radius',
118
- bg: 'background',
119
- c: 'color',
120
- d: 'display',
121
- f: 'flex',
122
- fd: 'flex-direction',
123
- i: 'inset',
124
- h: 'height',
125
- jc: 'justify-content',
126
- m: 'margin',
127
- ml: 'margin-left',
128
- mr: 'margin-right',
129
- mt: 'margin-top',
130
- mb: 'margin-bottom',
131
- maxW: 'max-width',
132
- minW: 'min-width',
133
- p: 'padding',
134
- pl: 'padding-left',
135
- pr: 'padding-right',
136
- pt: 'padding-top',
137
- pb: 'padding-bottom',
138
- pos: 'position',
139
- ta: 'text-align',
140
- w: 'width',
141
- z: 'z-index',
142
- }
143
- export const shorthandProps = [...Object.keys(shorthandPropsMap), 'mx', 'my', 'px', 'py']
144
-
145
- /** Expand short-hand css props to full */
146
- function expandProps(css: string) {
147
- css = '\n' + css // inject a newline to make the regex easier
148
- // Handle 'mx', 'my', 'px', 'py'
149
- css = css
150
- .replace(/([mp])x:([^;]*)/g, '$1l:$2;\n$1r:$2')
151
- .replace(/([mp])y:([^;]*);/g, '$1t:$2;\n$1b:$2')
152
- Object.entries(shorthandPropsMap).forEach(([k, v]) => {
153
- css = css.replace(new RegExp(`([ \n\t;])${k}:`, 'g'), `$1${v}:`)
154
- })
155
- return css.trim()
156
- }
157
-
158
131
  /** Find @keyframes, @media, @container queries in css **/
159
132
  function findQueries(css: string) {
160
133
  const queries = []
@@ -189,102 +162,10 @@ function findQueries(css: string) {
189
162
  }
190
163
 
191
164
  /** Trims whitespace for every line */
192
- function trim(css: string) {
165
+ function trimByLine(css: string) {
193
166
  return css
194
167
  .split('\n')
195
168
  .map(l => l.trim())
196
169
  .filter(l => l)
197
170
  .join('\n')
198
171
  }
199
-
200
- /**
201
- * Assemble a string from a template string array and a list of placeholders.
202
- *
203
- * - If the first argument is a string, it is returned as is.
204
- *
205
- * i.e.
206
- * myFoo(...props: TemplateStringProps) => {
207
- * const inputStr = t2s(...props);
208
- * }
209
- * myFoo`hello ${name}` => 'hello world'
210
- * myFoo(`hello ${name}`) => 'hello world'
211
- */
212
- export function t2s(...tsp: TemplateStringProps) {
213
- const [s, ...p] = tsp
214
- return typeof s === 'string' ? s : s.map((s, i) => s + (p?.[i] ?? '')).join('')
215
- }
216
- export type TemplateStringProps = [
217
- strings: TemplateStringsArray | string,
218
- ...placeHolders: string[]
219
- ]
220
-
221
- /**
222
- * Injects css to the page
223
- *
224
- * - Batches adds for performance
225
- *
226
- * @param css - css to be injected
227
- * @returns void
228
- */
229
- export function addCss(css: string) {
230
- addCss.que.add(css)
231
- setTimeout(() => {
232
- const css = [...addCss.que].join('\n')
233
- if (css) {
234
- addCss.que.clear()
235
- const s = document.createElement('style')
236
- s.id = `u${addCss.count++}`
237
- s.innerHTML = css
238
- document.head.appendChild(s)
239
- }
240
- }, 0)
241
- }
242
- addCss.que = new Set<string>()
243
- addCss.count = 0
244
-
245
- /**
246
- * Injects css and creates unique class names
247
- *
248
- * - Skips if already added
249
- *
250
- * @param css - string or template string, to be injected
251
- * @returns a unique class name
252
- */
253
- export function createClass(...p: TemplateStringProps) {
254
- let css = t2s(...p)
255
- if (!css) return ''
256
- let className = createClass.history.get(css)
257
- if (!className) {
258
- className = 's' + createClass.count++
259
- createClass.history.set(css, className)
260
-
261
- css = deleteComments(css)
262
- css = expandProps(css)
263
- css = expandArrayValues(css)
264
- const qs = findQueries(css)
265
-
266
- for (const q of qs.reverse()) {
267
- css = css.slice(0, q.start) + css.slice(q.end)
268
- }
269
-
270
- css = `.${className}{\n${css}\n}\n`
271
- css += qs
272
- .map(q => {
273
- if (q.query.startsWith('&')) {
274
- return `.${className}${q.query.slice(1)}{\n${q.innerBody}\n}`
275
- }
276
- if (q.query.startsWith('@keyframes')) {
277
- return q.outerBody
278
- }
279
- return `${q.query}{\n.${className}{${q.innerBody}\n}\n}`
280
- })
281
- .join('\n')
282
-
283
- css = trim(css) + '\n\n'
284
-
285
- addCss(css)
286
- }
287
- return className
288
- }
289
- createClass.count = 0
290
- createClass.history = new Map<string, string>()