purse-styles 0.0.1

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/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Tanishq Kancharla
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # Purse
2
+
3
+ A basic styling solution for web apps with an emphasis on simplicity and purity. The goal is to build a CSS-in-JS version of Tailwind's classname composition model.
4
+
5
+ ```tsx
6
+ // Define styles outside your components
7
+ const truncate = style({
8
+ overflow: "hidden",
9
+ lineClamp: 1,
10
+ textOverflow: "ellipsis",
11
+ })
12
+
13
+ // Compose styles together
14
+ const actionButton = style(
15
+ truncate,
16
+ text[14],
17
+ fonts.interface,
18
+ border[1]
19
+ )
20
+
21
+ // Use pseudo or other complex selectors
22
+ const button = style({
23
+ "&:disabled": {
24
+ backgroundColor: indigo.indigo8,
25
+ },
26
+ "&:hover[disabled=false]": {
27
+ backgroundColor: indigo.indigo10,
28
+ },
29
+ })
30
+
31
+ // Use styles in your components dynamically
32
+ const buttonClassName = useStyles(props.quiet ? quietButtonStyles : buttonStyles)
33
+
34
+ // Can also use CSS properties directly
35
+ const blueTextClassName = useStyles({
36
+ backgroundColor: "blue",
37
+ })
38
+ ```
39
+
40
+ ## Setup
41
+
42
+ ```sh
43
+ npm i purse-styles
44
+ ```
45
+
46
+ Wrap your app in `PurseProvider`:
47
+
48
+ ```tsx
49
+ <PurseProvider>
50
+ <App/>
51
+ </PurseProvider>
52
+ ```
53
+
54
+ That's all! No build step.
55
+
56
+ ## Exports
57
+
58
+ ```ts
59
+ // Declare styles outside React component
60
+ export declare function style(...styleElementsOrCSS: (CSSProperties | StyleElement)[]): StyleElement;
61
+
62
+ // Use declared styles or ad-hoc styles inside react component and get back a classname
63
+ export declare function useStyles(...styleElementsOrCSS: (CSSProperties | StyleElement)[]): string;
64
+
65
+ // Inject global styles into the app, you may want to do this as an escape hatch
66
+ export declare function useInjectGlobalStyles(
67
+ selector: string,
68
+ cssProperties: BaseCSSProperties & CSSVarDeclarations,
69
+ deps: DependencyList
70
+ ): void;
71
+
72
+ // Wrap your app in this so Purse can inject styles into the app
73
+ export declare function PurseProvider(props: {
74
+ children?: React.ReactNode;
75
+ }): React.JSX.Element;
76
+
77
+ // An in-memory style API for testing
78
+ export type InMemoryStyleApi = {
79
+ styleRulesRef: {
80
+ current: string[];
81
+ };
82
+ addStyleElement: StyleApi["addStyleElement"];
83
+ addGlobalStyle: StyleApi["addGlobalStyle"];
84
+ };
85
+ export declare function createInMemoryStyleApi(): InMemoryStyleApi;
86
+ ```
87
+
88
+ ## TODO
89
+ - [ ] E2E tests with Playwright
90
+ - [ ] Consider exporting a simple `styled` alternative
package/dist/clsx.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function clsx(...classNames: (string | undefined | false | null)[]): string;
@@ -0,0 +1,2 @@
1
+ export type CSSVar = `var(--${string})`;
2
+ export declare function createCssVar(name: string): CSSVar;
@@ -0,0 +1,2 @@
1
+ export type Destructor = () => void;
2
+ export declare function joinDestructors(destructors: Destructor[]): () => void;
@@ -0,0 +1 @@
1
+ export declare const hashObject: (value: Object) => string;
@@ -0,0 +1 @@
1
+ export declare function hyphenateStyleName(name: string): string;
@@ -0,0 +1 @@
1
+ export { CSSProperties, InMemoryStyleApi, PurseProvider, StyleApi, StyleElement, createInMemoryStyleApi, style, useInjectGlobalStyles, useStyles, } from "./purse";
package/dist/index.js ADDED
@@ -0,0 +1,411 @@
1
+ // src/purse.tsx
2
+ import { entries, isObject, mapValues } from "lodash-es";
3
+ import {
4
+ createContext,
5
+ useInsertionEffect,
6
+ useLayoutEffect,
7
+ useMemo
8
+ } from "react";
9
+
10
+ // src/clsx.ts
11
+ function clsx(...classNames) {
12
+ return classNames.filter(Boolean).join(" ");
13
+ }
14
+
15
+ // src/destructors.ts
16
+ function joinDestructors(destructors) {
17
+ return () => {
18
+ destructors.forEach((destructor) => destructor());
19
+ };
20
+ }
21
+
22
+ // src/hashObject.ts
23
+ function toAlphabeticChar(code) {
24
+ return String.fromCharCode(code + (code > 25 ? 39 : 97));
25
+ }
26
+ function toAlphabeticName(code) {
27
+ let name = "";
28
+ let x;
29
+ for (x = Math.abs(code); x > 52; x = x / 52 | 0)
30
+ name = toAlphabeticChar(x % 52) + name;
31
+ return toAlphabeticChar(x % 52) + name;
32
+ }
33
+ function toPhash(h, x) {
34
+ let i = x.length;
35
+ while (i) {
36
+ i--;
37
+ h = h * 33 ^ x.charCodeAt(i);
38
+ }
39
+ return h;
40
+ }
41
+ var hashObject = (value) => toAlphabeticName(toPhash(5381, JSON.stringify(value)) >>> 0);
42
+
43
+ // src/hyphenateStyleName.ts
44
+ var uppercasePattern = /[A-Z]/g;
45
+ var msPattern = /^ms-/;
46
+ var cache = {};
47
+ function toHyphenLower(match) {
48
+ return "-" + match.toLowerCase();
49
+ }
50
+ function hyphenateStyleName(name) {
51
+ if (cache.hasOwnProperty(name)) {
52
+ return cache[name];
53
+ }
54
+ var hName = name.replace(uppercasePattern, toHyphenLower);
55
+ return cache[name] = msPattern.test(hName) ? "-" + hName : hName;
56
+ }
57
+
58
+ // src/useRequiredContext.tsx
59
+ import { useContext } from "react";
60
+ function useRequiredContext(context) {
61
+ const value = useContext(context);
62
+ if (value === void 0) {
63
+ throw new Error(`Expected value of ${context} to be defined`);
64
+ }
65
+ return value;
66
+ }
67
+
68
+ // src/purse.tsx
69
+ import { jsx } from "react/jsx-runtime";
70
+ var UNITLESS_NUMBER_PROPS = [
71
+ "animation-iteration-count",
72
+ "border-image-outset",
73
+ "border-image-slice",
74
+ "border-image-width",
75
+ "box-flex",
76
+ "box-flex-group",
77
+ "box-ordinal-group",
78
+ "column-count",
79
+ "columns",
80
+ "flex",
81
+ "flex-grow",
82
+ "flex-positive",
83
+ "flex-shrink",
84
+ "flex-negative",
85
+ "flex-order",
86
+ "grid-row",
87
+ "grid-row-end",
88
+ "grid-row-span",
89
+ "grid-row-start",
90
+ "grid-column",
91
+ "grid-column-end",
92
+ "grid-column-span",
93
+ "grid-column-start",
94
+ "font-weight",
95
+ "line-clamp",
96
+ "line-height",
97
+ "opacity",
98
+ "order",
99
+ "orphans",
100
+ "tabSize",
101
+ "widows",
102
+ "z-index",
103
+ "zoom",
104
+ // SVG-related properties
105
+ "fill-opacity",
106
+ "flood-opacity",
107
+ "stop-opacity",
108
+ "stroke-dasharray",
109
+ "stroke-dashoffset",
110
+ "stroke-miterlimit",
111
+ "stroke-opacity",
112
+ "stroke-width"
113
+ ];
114
+ var PurseContext = createContext(void 0);
115
+ var __style__ = Symbol("style-element");
116
+ function isStyleElement(o) {
117
+ return "__style__" in o && o["__style__"] === __style__;
118
+ }
119
+ var DEV = true;
120
+ function createInMemoryStyleApi() {
121
+ let styleRules = [];
122
+ const insertedStyleElementClassNames = /* @__PURE__ */ new Map();
123
+ function addStyleRule(rule) {
124
+ styleRules.push(rule);
125
+ return () => {
126
+ const ruleToRemove = rule;
127
+ styleRules = styleRules.filter((rule2) => rule2 !== ruleToRemove);
128
+ };
129
+ }
130
+ function removeStyleElement(styleElement) {
131
+ for (const composed of styleElement.composed) {
132
+ removeStyleElement(composed);
133
+ }
134
+ if (styleElement.owned) {
135
+ const { className } = styleElement.owned;
136
+ const maybeInsertedStyleElement = insertedStyleElementClassNames.get(className);
137
+ if (!maybeInsertedStyleElement) return;
138
+ const { refCount, destructor } = maybeInsertedStyleElement;
139
+ const newRefCount = refCount - 1;
140
+ if (newRefCount <= 0) {
141
+ insertedStyleElementClassNames.delete(className);
142
+ destructor();
143
+ } else {
144
+ insertedStyleElementClassNames.set(className, {
145
+ refCount: newRefCount,
146
+ destructor
147
+ });
148
+ }
149
+ }
150
+ }
151
+ function addStyleElement(styleElement) {
152
+ for (const composed of styleElement.composed) {
153
+ addStyleElement(composed);
154
+ }
155
+ if (styleElement.owned) {
156
+ const { className, styleRules: styleRules2 } = styleElement.owned;
157
+ const maybeInsertedStyleElement = insertedStyleElementClassNames.get(className);
158
+ if (maybeInsertedStyleElement) {
159
+ const { destructor, refCount } = maybeInsertedStyleElement;
160
+ insertedStyleElementClassNames.set(className, {
161
+ destructor,
162
+ refCount: refCount + 1
163
+ });
164
+ } else {
165
+ const destructors = styleRules2.map(addStyleRule);
166
+ const destructor = joinDestructors(destructors);
167
+ insertedStyleElementClassNames.set(className, {
168
+ destructor,
169
+ refCount: 1
170
+ });
171
+ }
172
+ }
173
+ return () => removeStyleElement(styleElement);
174
+ }
175
+ return {
176
+ addStyleElement,
177
+ addGlobalStyle: addStyleRule,
178
+ styleRulesRef: {
179
+ get current() {
180
+ return styleRules;
181
+ }
182
+ }
183
+ };
184
+ }
185
+ function PurseProvider(props) {
186
+ const htmlStyleElement = useMemo(() => document.createElement("style"), []);
187
+ const atRuleHtmlStyleElement = useMemo(
188
+ () => document.createElement("style"),
189
+ []
190
+ );
191
+ useInsertionEffect(() => {
192
+ document.head.appendChild(htmlStyleElement);
193
+ document.head.appendChild(atRuleHtmlStyleElement);
194
+ return () => {
195
+ document.head.removeChild(htmlStyleElement);
196
+ document.head.removeChild(atRuleHtmlStyleElement);
197
+ };
198
+ }, [htmlStyleElement, atRuleHtmlStyleElement]);
199
+ const styleApi = useMemo(() => {
200
+ const insertedStyleElementClassNames = /* @__PURE__ */ new Map();
201
+ function addStyleRule(rule) {
202
+ const styleSheet = htmlStyleElement.sheet;
203
+ if (!styleSheet)
204
+ throw new Error(`Could not get style sheet of style element`);
205
+ try {
206
+ const isAtRule = rule.startsWith("@");
207
+ const styleText = new Text(rule);
208
+ if (isAtRule) {
209
+ atRuleHtmlStyleElement.appendChild(styleText);
210
+ return () => atRuleHtmlStyleElement.removeChild(styleText);
211
+ } else {
212
+ htmlStyleElement.appendChild(styleText);
213
+ return () => {
214
+ htmlStyleElement.removeChild(styleText);
215
+ };
216
+ }
217
+ } catch (error) {
218
+ if (DEV) {
219
+ throw new Error(`Could not add style rule ${rule}`);
220
+ } else {
221
+ console.warn(`Could not add style rule ${rule}`);
222
+ return () => {
223
+ };
224
+ }
225
+ }
226
+ }
227
+ function removeStyleElement(styleElement) {
228
+ for (const composed of styleElement.composed) {
229
+ removeStyleElement(composed);
230
+ }
231
+ if (styleElement.owned) {
232
+ const { className } = styleElement.owned;
233
+ const maybeInsertedStyleElement = insertedStyleElementClassNames.get(className);
234
+ if (!maybeInsertedStyleElement) return;
235
+ const { refCount, destructor } = maybeInsertedStyleElement;
236
+ const newRefCount = refCount - 1;
237
+ if (newRefCount <= 0) {
238
+ insertedStyleElementClassNames.delete(className);
239
+ destructor();
240
+ } else {
241
+ insertedStyleElementClassNames.set(className, {
242
+ refCount: newRefCount,
243
+ destructor
244
+ });
245
+ }
246
+ }
247
+ }
248
+ function addStyleElement(styleElement) {
249
+ for (const composed of styleElement.composed) {
250
+ addStyleElement(composed);
251
+ }
252
+ if (styleElement.owned) {
253
+ const { className, styleRules } = styleElement.owned;
254
+ const maybeInsertedStyleElement = insertedStyleElementClassNames.get(className);
255
+ if (maybeInsertedStyleElement) {
256
+ const { destructor, refCount } = maybeInsertedStyleElement;
257
+ insertedStyleElementClassNames.set(className, {
258
+ destructor,
259
+ refCount: refCount + 1
260
+ });
261
+ } else {
262
+ const destructors = styleRules.map(addStyleRule);
263
+ const destructor = joinDestructors(destructors);
264
+ insertedStyleElementClassNames.set(className, {
265
+ destructor,
266
+ refCount: 1
267
+ });
268
+ }
269
+ }
270
+ return () => removeStyleElement(styleElement);
271
+ }
272
+ return { addStyleElement, addGlobalStyle: addStyleRule };
273
+ }, []);
274
+ return /* @__PURE__ */ jsx(PurseContext.Provider, { value: styleApi, children: props.children });
275
+ }
276
+ function compileDeclarations(declarations) {
277
+ return entries(declarations).map(([camelCaseProperty, value]) => {
278
+ const kebabProperty = hyphenateStyleName(camelCaseProperty);
279
+ const needToAddPixelsUnit = typeof value === "number" && !UNITLESS_NUMBER_PROPS.includes(kebabProperty);
280
+ if (needToAddPixelsUnit) {
281
+ return `${kebabProperty}:${value}px;`;
282
+ } else {
283
+ return `${kebabProperty}:${value};`;
284
+ }
285
+ }).join("");
286
+ }
287
+ function isObjectEmpty(obj) {
288
+ return Object.keys(obj).length === 0;
289
+ }
290
+ function mergeCSSProperties(...groups) {
291
+ const merged = {};
292
+ for (const group of groups) {
293
+ for (const _propertyOrSelector in group) {
294
+ const propertyOrSelector = _propertyOrSelector;
295
+ const isNestedRule = isObject(group[propertyOrSelector]);
296
+ if (isNestedRule) {
297
+ const selector = propertyOrSelector;
298
+ const existingStyles = merged[selector] || {};
299
+ merged[selector] = {
300
+ ...existingStyles,
301
+ ...group[selector]
302
+ };
303
+ } else {
304
+ const property = propertyOrSelector;
305
+ merged[property] = group[property];
306
+ }
307
+ }
308
+ }
309
+ return merged;
310
+ }
311
+ function groupCSSProperties(properties) {
312
+ const styleDeclarationsBySelector = { "": {} };
313
+ for (const _propertyOrSelector in properties) {
314
+ const propertyOrSelector = _propertyOrSelector;
315
+ const value = properties[propertyOrSelector];
316
+ if (value === void 0 || value === null) continue;
317
+ const isNestedRule = isObject(value);
318
+ if (isNestedRule) {
319
+ const selector = propertyOrSelector;
320
+ const existingStyles = styleDeclarationsBySelector[selector] || {};
321
+ styleDeclarationsBySelector[selector] = {
322
+ ...existingStyles,
323
+ ...properties[selector]
324
+ };
325
+ } else {
326
+ const property = propertyOrSelector;
327
+ const value2 = properties[property];
328
+ styleDeclarationsBySelector[""][property] = value2;
329
+ }
330
+ }
331
+ for (const selector in styleDeclarationsBySelector) {
332
+ const declarations = styleDeclarationsBySelector[selector];
333
+ if (declarations && isObjectEmpty(declarations)) {
334
+ delete styleDeclarationsBySelector[selector];
335
+ }
336
+ }
337
+ return styleDeclarationsBySelector;
338
+ }
339
+ function compileCSS(properties) {
340
+ if (isObjectEmpty(properties)) {
341
+ return void 0;
342
+ }
343
+ const groupedCSSProperties = groupCSSProperties(properties);
344
+ const compiledStyleDeclarationsByGroup = mapValues(
345
+ groupedCSSProperties,
346
+ compileDeclarations
347
+ );
348
+ const className = hashObject(compiledStyleDeclarationsByGroup);
349
+ const styleRules = entries(compiledStyleDeclarationsByGroup).map(
350
+ ([group, styles]) => {
351
+ if (group === "") {
352
+ return `.${className}{${styles}}`;
353
+ } else if (group.startsWith("@")) {
354
+ return `${group}{.${className}{${styles}}}`;
355
+ } else {
356
+ const selector = group.replace(/&/g, `.${className}`);
357
+ return `${selector}{${styles}}`;
358
+ }
359
+ }
360
+ );
361
+ return { styleRules, className };
362
+ }
363
+ function style(...styleElementsOrCSS) {
364
+ let composed = [];
365
+ let cssPropertyGroups = [];
366
+ for (const styleElementOrCSS of styleElementsOrCSS) {
367
+ if (isStyleElement(styleElementOrCSS)) {
368
+ composed.push(styleElementOrCSS);
369
+ } else {
370
+ cssPropertyGroups.push(styleElementOrCSS);
371
+ }
372
+ }
373
+ const cssProperties = mergeCSSProperties(...cssPropertyGroups);
374
+ const owned = compileCSS(cssProperties);
375
+ const composedClassNames = composed.map((composed2) => composed2.className);
376
+ const className = clsx(...composedClassNames, owned?.className);
377
+ return {
378
+ __style__,
379
+ composed,
380
+ className,
381
+ owned
382
+ };
383
+ }
384
+ function useInjectGlobalStyles(selector, cssProperties, deps) {
385
+ const styleApi = useRequiredContext(PurseContext);
386
+ useLayoutEffect(() => {
387
+ const styleRule = `${selector}{${compileDeclarations(cssProperties)}}`;
388
+ const destructor = styleApi.addGlobalStyle(styleRule);
389
+ return destructor;
390
+ }, deps);
391
+ }
392
+ function useStyles(...styleElementsOrCSS) {
393
+ const styleApi = useRequiredContext(PurseContext);
394
+ const styleElement = style(...styleElementsOrCSS);
395
+ useLayoutEffect(() => {
396
+ if (styleElement.className === "bpsHRa jwfJGj") {
397
+ console.log(styleElement);
398
+ }
399
+ const destructor = styleApi.addStyleElement(styleElement);
400
+ return destructor;
401
+ }, [styleElement.className]);
402
+ return styleElement.className;
403
+ }
404
+ export {
405
+ PurseProvider,
406
+ createInMemoryStyleApi,
407
+ style,
408
+ useInjectGlobalStyles,
409
+ useStyles
410
+ };
411
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/purse.tsx", "../src/clsx.ts", "../src/destructors.ts", "../src/hashObject.ts", "../src/hyphenateStyleName.ts", "../src/useRequiredContext.tsx"],
4
+ "mappings": "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",
5
+ "names": ["rule", "styleRules", "value", "composed"]
6
+ }
@@ -0,0 +1,42 @@
1
+ import CSS from "csstype";
2
+ import React, { DependencyList } from "react";
3
+ import { CSSVar } from "./cssVar";
4
+ import { Destructor } from "./destructors";
5
+ type BaseCSSProperties = CSS.Properties<number | string, string & {}>;
6
+ type CSSVarDeclarations = Record<CSSVar, string>;
7
+ type NestedRuleKey = `&${CSS.SimplePseudos}` | `${CSS.AtRules}${string}` | `.${string}` | `&${string}`;
8
+ export type CSSProperties = {
9
+ [Key in keyof BaseCSSProperties]?: BaseCSSProperties[Key];
10
+ } & {
11
+ [Key in NestedRuleKey]?: BaseCSSProperties;
12
+ };
13
+ export type StyleApi = {
14
+ addStyleElement: (styleElement: StyleElement) => Destructor;
15
+ addGlobalStyle: (styleRule: string) => Destructor;
16
+ };
17
+ declare const __style__: unique symbol;
18
+ type StyleRule = string;
19
+ export type StyleElement = {
20
+ __style__: typeof __style__;
21
+ composed: StyleElement[];
22
+ owned?: {
23
+ styleRules: StyleRule[];
24
+ className: string;
25
+ };
26
+ className: string;
27
+ };
28
+ export type InMemoryStyleApi = {
29
+ styleRulesRef: {
30
+ current: string[];
31
+ };
32
+ addStyleElement: StyleApi["addStyleElement"];
33
+ addGlobalStyle: StyleApi["addGlobalStyle"];
34
+ };
35
+ export declare function createInMemoryStyleApi(): InMemoryStyleApi;
36
+ export declare function PurseProvider(props: {
37
+ children?: React.ReactNode;
38
+ }): import("react/jsx-runtime").JSX.Element;
39
+ export declare function style(...styleElementsOrCSS: (CSSProperties | StyleElement)[]): StyleElement;
40
+ export declare function useInjectGlobalStyles(selector: string, cssProperties: BaseCSSProperties & CSSVarDeclarations, deps: DependencyList): void;
41
+ export declare function useStyles(...styleElementsOrCSS: (CSSProperties | StyleElement)[]): string;
42
+ export {};
@@ -0,0 +1,2 @@
1
+ import React from "react";
2
+ export declare function useRequiredContext<T>(context: React.Context<T | undefined>): T;
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "purse-styles",
3
+ "type": "module",
4
+ "main": "./dist/index.js",
5
+ "version": "0.0.1",
6
+ "author": "Tanishq Kancharla <tanishqkancharla3@gmail.com>",
7
+ "description": "A basic styling solution for web apps with an emphasis on simplicity and purity.",
8
+ "keywords": [],
9
+ "license": "MIT",
10
+ "source": "./src/index.ts",
11
+ "types": "./dist/index.d.ts",
12
+ "files": [
13
+ "dist",
14
+ "src"
15
+ ],
16
+ "repository": {
17
+ "url": "https://github.com/tanishqkancharla/npm-ts-boilerplate"
18
+ },
19
+ "scripts": {
20
+ "build": "tsx scripts/build.ts",
21
+ "check": "tsc --noEmit",
22
+ "test": "vitest",
23
+ "release": "npm run build; npm publish",
24
+ "bundlesize": "esbuild ./dist/index.js --minify --outfile=bundled; rm bundled"
25
+ },
26
+ "devDependencies": {
27
+ "@types/lodash-es": "^4.17.12",
28
+ "@types/node": "^20.14.2",
29
+ "@types/react": "^18.3.3",
30
+ "ansi-colors": "^4.1.3",
31
+ "esbuild": "^0.21.5",
32
+ "tsx": "^4.15.5",
33
+ "typescript": "^5.4.5",
34
+ "vitest": "^1.6.0"
35
+ },
36
+ "peerDependencies": {
37
+ "react": "^18.3.1"
38
+ },
39
+ "dependencies": {
40
+ "csstype": "^3.1.3",
41
+ "extendable-expect": "^1.0.2",
42
+ "lodash-es": "^4.17.21"
43
+ }
44
+ }
package/src/clsx.ts ADDED
@@ -0,0 +1,3 @@
1
+ export function clsx(...classNames: (string | undefined | false | null)[]) {
2
+ return classNames.filter(Boolean).join(" ")
3
+ }
package/src/cssVar.ts ADDED
@@ -0,0 +1,5 @@
1
+ export type CSSVar = `var(--${string})`
2
+
3
+ export function createCssVar(name: string): CSSVar {
4
+ return `var(--${name})`
5
+ }
@@ -0,0 +1,7 @@
1
+ export type Destructor = () => void
2
+
3
+ export function joinDestructors(destructors: Destructor[]) {
4
+ return () => {
5
+ destructors.forEach((destructor) => destructor())
6
+ }
7
+ }