@paganaye/stylets 0.1.0

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.
Files changed (70) hide show
  1. package/README.md +13 -0
  2. package/dist/BaseStyles.d.ts +44 -0
  3. package/dist/BaseStyles.js +166 -0
  4. package/dist/Button.d.ts +69 -0
  5. package/dist/Button.js +56 -0
  6. package/dist/CssColor.d.ts +44 -0
  7. package/dist/CssColor.js +196 -0
  8. package/dist/CssColor.test.d.ts +1 -0
  9. package/dist/CssColor.test.js +68 -0
  10. package/dist/CssExpr.d.ts +9 -0
  11. package/dist/CssExpr.js +35 -0
  12. package/dist/CssFilter.d.ts +18 -0
  13. package/dist/CssFilter.js +40 -0
  14. package/dist/CssNum.d.ts +30 -0
  15. package/dist/CssNum.js +106 -0
  16. package/dist/CssNum.test.d.ts +1 -0
  17. package/dist/CssNum.test.js +30 -0
  18. package/dist/CssReset.d.ts +1 -0
  19. package/dist/CssReset.js +15 -0
  20. package/dist/CssShadow.d.ts +19 -0
  21. package/dist/CssShadow.js +42 -0
  22. package/dist/DefaultTheme.d.ts +14 -0
  23. package/dist/DefaultTheme.js +6 -0
  24. package/dist/EmptyTheme.d.ts +14 -0
  25. package/dist/EmptyTheme.js +2 -0
  26. package/dist/HTML.d.ts +9 -0
  27. package/dist/HTML.jsx +7 -0
  28. package/dist/ScopeStyles.d.ts +24 -0
  29. package/dist/ScopeStyles.js +67 -0
  30. package/dist/State.d.ts +36 -0
  31. package/dist/State.js +107 -0
  32. package/dist/State.test.d.ts +1 -0
  33. package/dist/State.test.js +41 -0
  34. package/dist/StyleWriter.d.ts +25 -0
  35. package/dist/StyleWriter.js +156 -0
  36. package/dist/Theme.d.ts +56 -0
  37. package/dist/Theme.js +29 -0
  38. package/dist/Tone.d.ts +1 -0
  39. package/dist/Tone.js +1 -0
  40. package/dist/index.d.ts +1 -0
  41. package/dist/index.js +1 -0
  42. package/dist/index.test.d.ts +1 -0
  43. package/dist/index.test.js +9 -0
  44. package/dist/props.d.ts +7 -0
  45. package/dist/props.js +104 -0
  46. package/dist/types.d.ts +239 -0
  47. package/dist/types.js +1 -0
  48. package/package.json +36 -0
  49. package/src/BaseStyles.ts +192 -0
  50. package/src/Button.ts +68 -0
  51. package/src/CssColor.test.ts +82 -0
  52. package/src/CssColor.ts +175 -0
  53. package/src/CssExpr.ts +25 -0
  54. package/src/CssFilter.ts +44 -0
  55. package/src/CssNum.test.ts +37 -0
  56. package/src/CssNum.ts +93 -0
  57. package/src/CssReset.ts +17 -0
  58. package/src/CssShadow.ts +46 -0
  59. package/src/DefaultTheme.ts +8 -0
  60. package/src/HTML.tsx +17 -0
  61. package/src/ScopeStyles.ts +100 -0
  62. package/src/State.test.ts +47 -0
  63. package/src/State.ts +164 -0
  64. package/src/StyleWriter.ts +163 -0
  65. package/src/Theme.ts +95 -0
  66. package/src/Tone.ts +1 -0
  67. package/src/index.test.ts +10 -0
  68. package/src/index.ts +1 -0
  69. package/src/props.ts +118 -0
  70. package/src/types.ts +311 -0
@@ -0,0 +1,35 @@
1
+ export class CssExpr {
2
+ unit;
3
+ type;
4
+ constructor(unit, type) {
5
+ this.unit = unit;
6
+ this.type = type;
7
+ }
8
+ }
9
+ class CssVar extends CssExpr {
10
+ varName;
11
+ constructor(varName, unit, type) {
12
+ super('%', 'unknown');
13
+ this.varName = varName;
14
+ }
15
+ toString() { return `var(--${this.varName})`; }
16
+ }
17
+ class CssCustomExpr extends CssExpr {
18
+ expr;
19
+ constructor(expr, unit, type) {
20
+ super(unit, type);
21
+ this.expr = expr;
22
+ }
23
+ toString() { return this.expr; }
24
+ }
25
+ class CssArg extends CssExpr {
26
+ argName;
27
+ constructor(argName, unit, type) {
28
+ super(unit, type);
29
+ this.argName = argName;
30
+ }
31
+ toString() { return this.argName; }
32
+ }
33
+ export function customCss(expr, unit = 'unknown', type = 'unknown') { return new CssCustomExpr(expr, unit, type); }
34
+ export function arg(name, unit = 'unknown', type = 'unknown') { return new CssArg(name, unit, type); }
35
+ export function v(name, unit = 'unknown', type = 'unknown') { return new CssVar(name, unit, type); }
@@ -0,0 +1,18 @@
1
+ import { CssExpr } from "./CssExpr";
2
+ import { Num } from "./CssNum";
3
+ export declare class CssFilter extends CssExpr {
4
+ readonly options: FilterOptions | FilterOptions[];
5
+ constructor(options: FilterOptions | FilterOptions[]);
6
+ toString(): string;
7
+ }
8
+ export type FilterOptions = {
9
+ blur?: Num;
10
+ brightness?: Num;
11
+ contrast?: Num;
12
+ hueRotate?: Num;
13
+ saturate?: Num;
14
+ invert?: Num;
15
+ grayscale?: Num;
16
+ sepia?: Num;
17
+ opacity?: Num;
18
+ };
@@ -0,0 +1,40 @@
1
+ import { CssExpr } from "./CssExpr";
2
+ import { numToStr } from "./CssNum";
3
+ export class CssFilter extends CssExpr {
4
+ options;
5
+ constructor(options) {
6
+ super('none', 'filter');
7
+ this.options = options;
8
+ }
9
+ toString() {
10
+ const serializeOne = (opt) => {
11
+ const result = [];
12
+ if (opt.blur !== undefined)
13
+ result.push(`blur(${numToStr(opt.blur)})`);
14
+ if (opt.brightness !== undefined)
15
+ result.push(`brightness(${numToStr(opt.brightness)})`);
16
+ if (opt.contrast !== undefined)
17
+ result.push(`contrast(${numToStr(opt.contrast)})`);
18
+ if (opt.hueRotate !== undefined)
19
+ result.push(`hue-rotate(${numToStr(opt.hueRotate)})`);
20
+ if (opt.saturate !== undefined)
21
+ result.push(`saturate(${numToStr(opt.saturate)})`);
22
+ if (opt.invert !== undefined)
23
+ result.push(`invert(${numToStr(opt.invert)})`);
24
+ if (opt.grayscale !== undefined)
25
+ result.push(`grayscale(${numToStr(opt.grayscale)})`);
26
+ if (opt.sepia !== undefined)
27
+ result.push(`sepia(${numToStr(opt.sepia)})`);
28
+ if (opt.opacity !== undefined)
29
+ result.push(`opacity(${numToStr(opt.opacity)})`);
30
+ return result.join(' ');
31
+ };
32
+ if (Array.isArray(this.options)) {
33
+ const parts = this.options.map(o => serializeOne(o));
34
+ return parts.join(' ');
35
+ }
36
+ else {
37
+ return serializeOne(this.options);
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,30 @@
1
+ import { CssExpr } from "./CssExpr";
2
+ export type Num = number | string | CssExpr;
3
+ export type ArgVariable = 'l' | 'c' | 'h';
4
+ export type NumberType = 'length' | 'angle' | 'time' | 'frequency' | 'flex' | 'resolution';
5
+ export type LengthUnit = 'px' | 'rem' | 'em' | 'vw' | 'vh' | '%';
6
+ export type AngleUnit = 'deg' | 'rad';
7
+ export type TimeUnit = 's' | 'ms';
8
+ export type FrequencyUnit = 'hz' | 'khz';
9
+ export type FlexUnit = 'fr';
10
+ export type ResolutionUnit = 'dpi' | 'dpcm' | 'dppx';
11
+ export type CssUnit = LengthUnit | AngleUnit | TimeUnit | FrequencyUnit | FlexUnit | ResolutionUnit | 'none' | 'unknown';
12
+ export type CssType = NumberType | 'color' | 'shadow' | 'filter' | 'unknown';
13
+ export declare function numToStr(num: Num): string;
14
+ declare abstract class NumExpr extends CssExpr {
15
+ static arg: typeof numArg;
16
+ static mul: typeof mul;
17
+ static add: typeof add;
18
+ static clamp: typeof clamp;
19
+ static min: typeof min;
20
+ static max: typeof max;
21
+ static new: typeof num;
22
+ }
23
+ export declare function numArg(name: string, unit?: CssUnit, type?: CssType): CssExpr;
24
+ export declare function mul(expr: NumExpr, factor: number | NumExpr): NumExpr;
25
+ export declare function add(expr: NumExpr, addend: number | NumExpr): NumExpr;
26
+ export declare function clamp(min: number | NumExpr, expr: NumExpr, max: number | NumExpr): NumExpr;
27
+ export declare function min(...args: Array<number | NumExpr>): NumExpr;
28
+ export declare function max(...args: Array<number | NumExpr>): NumExpr;
29
+ export declare function num(value: number, unit?: CssUnit, type?: CssType): NumExpr;
30
+ export {};
package/dist/CssNum.js ADDED
@@ -0,0 +1,106 @@
1
+ import { CssExpr } from "./CssExpr";
2
+ export function numToStr(num) {
3
+ if (typeof num === 'number')
4
+ return String(num);
5
+ return `${num.toString()}`;
6
+ }
7
+ // ==== Num ===== //
8
+ class NumExpr extends CssExpr {
9
+ static arg = numArg;
10
+ static mul = mul;
11
+ static add = add;
12
+ static clamp = clamp;
13
+ static min = min;
14
+ static max = max;
15
+ static new = num;
16
+ }
17
+ class LitteralNumExpr extends NumExpr {
18
+ value;
19
+ unit;
20
+ constructor(value, unit, type) {
21
+ super(unit, type);
22
+ this.value = value;
23
+ this.unit = unit;
24
+ }
25
+ toString() { return `${this.value}${this.unit ?? ''}`; }
26
+ }
27
+ class CssNumArg extends NumExpr {
28
+ argName;
29
+ constructor(argName, unit, type) {
30
+ super(unit, type);
31
+ this.argName = argName;
32
+ }
33
+ toString() { return this.argName; }
34
+ }
35
+ class MulExpr extends NumExpr {
36
+ expr;
37
+ factor;
38
+ constructor(expr, factor) {
39
+ super('unknown', 'unknown');
40
+ this.expr = expr;
41
+ this.factor = factor;
42
+ }
43
+ toString() {
44
+ const f = numToStr(this.factor);
45
+ return `calc(${numToStr(this.expr)} * ${f})`;
46
+ }
47
+ }
48
+ class AddExpr extends NumExpr {
49
+ expr;
50
+ addend;
51
+ constructor(expr, addend) {
52
+ super('unknown', 'unknown');
53
+ this.expr = expr;
54
+ this.addend = addend;
55
+ }
56
+ toString() {
57
+ const a = numToStr(this.addend);
58
+ return `calc(${numToStr(this.expr)} + ${a})`;
59
+ }
60
+ }
61
+ class ClampExpr extends NumExpr {
62
+ min;
63
+ expr;
64
+ max;
65
+ constructor(min, expr, max) {
66
+ super('unknown', 'unknown');
67
+ this.min = min;
68
+ this.expr = expr;
69
+ this.max = max;
70
+ }
71
+ toString() {
72
+ const mn = numToStr(this.min);
73
+ const ex = numToStr(this.expr);
74
+ const mx = numToStr(this.max);
75
+ return `clamp(${mn}, ${ex}, ${mx})`;
76
+ }
77
+ }
78
+ class MinExpr extends NumExpr {
79
+ args;
80
+ constructor(args) {
81
+ super('unknown', 'unknown');
82
+ this.args = args;
83
+ }
84
+ toString() {
85
+ const parts = this.args.map(a => numToStr(a));
86
+ return `min(${parts.join(', ')})`;
87
+ }
88
+ }
89
+ class MaxExpr extends NumExpr {
90
+ args;
91
+ constructor(args) {
92
+ super('unknown', 'unknown');
93
+ this.args = args;
94
+ }
95
+ toString() {
96
+ const parts = this.args.map(a => numToStr(a));
97
+ return `max(${parts.join(', ')})`;
98
+ }
99
+ }
100
+ export function numArg(name, unit = 'none', type = 'length') { return new CssNumArg(name, unit, type); }
101
+ export function mul(expr, factor) { return new MulExpr(expr, factor); }
102
+ export function add(expr, addend) { return new AddExpr(expr, addend); }
103
+ export function clamp(min, expr, max) { return new ClampExpr(min, expr, max); }
104
+ export function min(...args) { return new MinExpr(args); }
105
+ export function max(...args) { return new MaxExpr(args); }
106
+ export function num(value, unit = 'unknown', type = 'unknown') { return new LitteralNumExpr(value, unit, type); }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,30 @@
1
+ import { describe, it } from 'vitest';
2
+ // TODO: Update imports once CssNum is fully integrated
3
+ // import { mul, add, clamp, min, max, num } from './CssNum';
4
+ // import { l, h, c } from './CssColor';
5
+ // import { v, customCss } from './CssExpr';
6
+ describe('CssNumUtils', () => {
7
+ it.skip('numVar creates CSS var string', () => {
8
+ // expect(v('x').toString()).toBe('var(--x)');
9
+ });
10
+ it.skip('clamp/min/max produce expected strings', () => {
11
+ // expect(clamp(0, l, 1).toString()).toBe('clamp(0, l, 1)');
12
+ // expect(min(0, l, 2).toString()).toBe('min(0, l, 2)');
13
+ // expect(max(0, l, 2).toString()).toBe('max(0, l, 2)');
14
+ // expect(max(num(0, 'rem'), l, num(2, 'px')).toString()).toBe('max(0rem, l, 2px)');
15
+ });
16
+ it.skip('customCssExpr returns custom expression', () => {
17
+ // expect(customCss('calc(var(--a) + 1)').toString()).toBe('calc(var(--a) + 1)');
18
+ });
19
+ it.skip('num returns expected string', () => {
20
+ // expect(num(5, 'px').toString()).toBe('5px');
21
+ });
22
+ it.skip('min/max accept many args and nested expressions', () => {
23
+ // const nested = mul(l, 0.5);
24
+ // expect(clamp(0, nested, 100).toString()).toBe('clamp(0, calc(l * 0.5), 100)');
25
+ // expect(min(0, l, 2, mul(c, 3)).toString())
26
+ // .toBe('min(0, l, 2, calc(c * 3))');
27
+ // expect(max(0, l, 2, add(c, 1)).toString())
28
+ // .toBe('max(0, l, 2, calc(c + 1))');
29
+ });
30
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,15 @@
1
+ import { addStyles } from "./StyleWriter";
2
+ addStyles("css-reset", (builder) => {
3
+ builder.addLines([`/* John W Comeau Modern CSS Reset */`,
4
+ `*, *::before, *::after { box-sizing: border-box; }`,
5
+ `*:not(dialog) { margin: 0; }`,
6
+ `@media (prefers-reduced-motion: no-preference) { html { interpolate-size: allow-keywords; } }`,
7
+ `body { line-height: 1.5; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial; }`,
8
+ `img, picture, video, canvas, svg { display: block; max-width: 100%; }`,
9
+ `input, button, textarea, select { font: inherit; }`,
10
+ `p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }`,
11
+ `p { text-wrap: pretty; }`,
12
+ `h1, h2, h3, h4, h5, h6 { text-wrap: balance; }`,
13
+ `#root, #__next { isolation: isolate; }`,
14
+ ]);
15
+ });
@@ -0,0 +1,19 @@
1
+ import { CssColor } from "./CssColor";
2
+ import { CssExpr } from "./CssExpr";
3
+ import { Num } from "./CssNum";
4
+ export type BoxShadowOptions = {
5
+ offsetX: Num;
6
+ offsetY: Num;
7
+ blur?: Num;
8
+ spread?: Num;
9
+ color?: string | CssColor;
10
+ inset?: boolean;
11
+ };
12
+ export declare class CssShadow extends CssExpr {
13
+ readonly kind: 'box' | 'text';
14
+ opts: BoxShadowOptions | BoxShadowOptions[];
15
+ constructor(kind: 'box' | 'text', opts: BoxShadowOptions | BoxShadowOptions[]);
16
+ toString(): string;
17
+ }
18
+ export declare function textShadow(options: BoxShadowOptions | BoxShadowOptions[]): CssShadow;
19
+ export declare function boxShadow(options: BoxShadowOptions | BoxShadowOptions[]): CssShadow;
@@ -0,0 +1,42 @@
1
+ import { CssExpr } from "./CssExpr";
2
+ export class CssShadow extends CssExpr {
3
+ kind;
4
+ opts;
5
+ constructor(kind, opts) {
6
+ super('none', 'shadow');
7
+ this.kind = kind;
8
+ this.opts = opts;
9
+ }
10
+ toString() {
11
+ let serializeOne = (opt) => {
12
+ const { offsetX, offsetY, blur, spread, color, inset } = opt;
13
+ const parts = [];
14
+ // For text shadows, 'inset' and 'spread' are not valid
15
+ if (inset && this.kind === 'box')
16
+ parts.push('inset');
17
+ const sx = typeof offsetX === 'string' ? offsetX : offsetX.toString();
18
+ const sy = typeof offsetY === 'string' ? offsetY : offsetY.toString();
19
+ parts.push(sx, sy);
20
+ if (blur !== undefined)
21
+ parts.push(typeof blur === 'string' ? blur : blur.toString());
22
+ if (spread !== undefined && this.kind === 'box')
23
+ parts.push(typeof spread === 'string' ? spread : spread.toString());
24
+ if (color)
25
+ parts.push(typeof color === 'string' ? color : color.toString());
26
+ return parts.join(' ');
27
+ };
28
+ if (Array.isArray(this.opts)) {
29
+ const parts = this.opts.map(o => serializeOne(o));
30
+ return parts.join(', ');
31
+ }
32
+ else {
33
+ return serializeOne(this.opts);
34
+ }
35
+ }
36
+ }
37
+ export function textShadow(options) {
38
+ return new CssShadow('text', options);
39
+ }
40
+ export function boxShadow(options) {
41
+ return new CssShadow('box', options);
42
+ }
@@ -0,0 +1,14 @@
1
+ export declare const theme: import("./Theme").ThemeBuilder<{
2
+ colors: "primary";
3
+ sizes: never;
4
+ paddings: never;
5
+ margins: never;
6
+ borders: never;
7
+ backgrounds: never;
8
+ layouts: never;
9
+ typography: never;
10
+ shadows: never;
11
+ vars: never;
12
+ classes: never;
13
+ variants: Record<string, never>;
14
+ }>;
@@ -0,0 +1,6 @@
1
+ import { createTheme } from "./Theme";
2
+ export const theme = createTheme({
3
+ colors: {
4
+ primary: '#3498db',
5
+ }
6
+ });
@@ -0,0 +1,14 @@
1
+ export declare const emptyTheme: import("./Theme").ThemeBuilder<{
2
+ colors: never;
3
+ sizes: never;
4
+ paddings: never;
5
+ margins: never;
6
+ borders: never;
7
+ backgrounds: never;
8
+ layouts: never;
9
+ typography: never;
10
+ shadows: never;
11
+ vars: never;
12
+ classes: never;
13
+ variants: Record<string, never>;
14
+ }>;
@@ -0,0 +1,2 @@
1
+ import { createTheme } from "./Theme";
2
+ export const emptyTheme = createTheme({});
package/dist/HTML.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { CssProperties, ThemeClass } from "./types";
2
+ import { theme } from "./DefaultTheme";
3
+ export interface IDivProps {
4
+ class?: ThemeClass<typeof theme>;
5
+ style?: CssProperties;
6
+ gap?: number;
7
+ }
8
+ export declare function Div(props: IDivProps, children: any[]): string;
9
+ export declare function P(props: IDivProps, children: any[]): string;
package/dist/HTML.jsx ADDED
@@ -0,0 +1,7 @@
1
+ import { Elt } from "./props";
2
+ export function Div(props, children) {
3
+ return Elt('div', props, children);
4
+ }
5
+ export function P(props, children) {
6
+ return Elt('p', props, children);
7
+ }
@@ -0,0 +1,24 @@
1
+ import { ThemeBuilder } from "./Theme";
2
+ import { BaseStyles } from "./BaseStyles";
3
+ import { IScopeStylesParts, MergeThemeArgs, ThemeArgs } from "./types";
4
+ export declare class ScopeStylesBuilder<A extends ThemeArgs, V extends A['variants'] = A['variants']> extends BaseStyles<A> {
5
+ readonly class: string;
6
+ scopeStart: string;
7
+ scopeEnd: string | undefined;
8
+ parent: ThemeBuilder<any>;
9
+ constructor(parent: ThemeBuilder<any>, themeParts: IScopeStylesParts<A> & {
10
+ class: string;
11
+ scopeStart: string;
12
+ scopeEnd?: string;
13
+ });
14
+ add<P extends IScopeStylesParts<any>>(parts: P): ScopeStylesBuilder<MergeThemeArgs<A, P>, MergeThemeArgs<A, P>['variants']>;
15
+ add<P extends (theme: ThemeBuilder<A>) => IScopeStylesParts<any>>(parts: P): ScopeStylesBuilder<MergeThemeArgs<A, ReturnType<P>>, MergeThemeArgs<A, ReturnType<P>>['variants']>;
16
+ protected renderHeader(): void;
17
+ protected renderVariants(): void;
18
+ renderFooter(): void;
19
+ render(): ScopeStylesPublic<A, V>;
20
+ }
21
+ export type ScopeStylesPublic<A extends ThemeArgs, V extends A['variants'] = A['variants']> = {
22
+ class: string;
23
+ variants: V;
24
+ };
@@ -0,0 +1,67 @@
1
+ import { BaseStyles } from "./BaseStyles";
2
+ export class ScopeStylesBuilder extends BaseStyles {
3
+ class;
4
+ scopeStart;
5
+ scopeEnd;
6
+ parent;
7
+ constructor(parent, themeParts) {
8
+ // Merge all parent properties into scope
9
+ const mergedParts = {
10
+ ...themeParts,
11
+ name: `@scope ${themeParts.class}`,
12
+ colors: { ...parent.colors, ...themeParts.colors },
13
+ vars: { ...parent.vars, ...themeParts.vars },
14
+ paddings: { ...parent.paddings, ...themeParts.paddings },
15
+ margins: { ...parent.margins, ...themeParts.margins },
16
+ borders: { ...parent.borders, ...themeParts.borders },
17
+ backgrounds: { ...parent.backgrounds, ...themeParts.backgrounds },
18
+ typography: { ...parent.typography, ...themeParts.typography },
19
+ layouts: { ...parent.layouts, ...themeParts.layouts },
20
+ shadows: { ...parent.shadows, ...themeParts.shadows },
21
+ classes: { ...parent.classes, ...themeParts.classes },
22
+ variants: { ...parent.variants, ...themeParts.variants }
23
+ };
24
+ super(mergedParts);
25
+ this.parent = parent;
26
+ this.class = themeParts.class ?? '';
27
+ this.scopeStart = themeParts.scopeStart ?? `.${themeParts.class}`;
28
+ this.scopeEnd = themeParts.scopeEnd;
29
+ }
30
+ add(parts) {
31
+ if (typeof parts === 'function')
32
+ parts = parts(this);
33
+ super.add(parts);
34
+ return this;
35
+ }
36
+ renderHeader() {
37
+ super.renderHeader();
38
+ this.builder.addLine(`@scope (${this.scopeStart})${this.scopeEnd ? ` to (${this.scopeEnd})` : ''} {`);
39
+ this.builder.indentLevel += 1;
40
+ }
41
+ renderVariants() {
42
+ if (Object.keys(this._variants).length === 0)
43
+ return;
44
+ this.builder.addLine(`/* variants */`);
45
+ for (const [variantKey, variantValues] of Object.entries(this._variants)) {
46
+ for (const [variantName, styles] of Object.entries(variantValues)) {
47
+ const selector = `&[${variantKey}="${variantName}"]`;
48
+ this.builder.addRule(selector, styles);
49
+ }
50
+ }
51
+ }
52
+ renderFooter() {
53
+ this.renderVariants();
54
+ this.builder.indentLevel -= 1;
55
+ this.builder.addLine(`}`);
56
+ super.renderFooter();
57
+ }
58
+ render() {
59
+ super.render();
60
+ let result = this;
61
+ return result;
62
+ }
63
+ }
64
+ // only for the IDE never instantiated, kept internal
65
+ class ScopeStyles extends BaseStyles {
66
+ class;
67
+ }
@@ -0,0 +1,36 @@
1
+ export type EqualityFunction<T> = (a: T, b: T) => boolean;
2
+ export declare abstract class BaseState<T = any> {
3
+ protected _listeners: Array<(data: T) => void>;
4
+ protected _value: T;
5
+ protected valueEquals: EqualityFunction<T>;
6
+ constructor(initialValue: T, equalityFunction?: EqualityFunction<T>);
7
+ get value(): T;
8
+ protected internalSetValue(newValue: T): void;
9
+ subscribe(listener: (data: T) => void): void;
10
+ unsubscribe(listener: (data: T) => void): void;
11
+ protected emit(data: T): void;
12
+ dispose(): void;
13
+ }
14
+ export declare class State<T = any> extends BaseState<T> {
15
+ constructor(initialValue: T, equals?: EqualityFunction<T>);
16
+ setValue(newValue: T): void;
17
+ }
18
+ export declare function createState<T>(value: T, equals?: EqualityFunction<T>): State<T>;
19
+ export declare function createState<T>(value?: T, equals?: EqualityFunction<T | undefined>): State<T | undefined>;
20
+ export declare class Effect {
21
+ private compute;
22
+ readonly dependencies: Array<BaseState>;
23
+ readonly recomputeBound: () => Promise<void>;
24
+ constructor(watch: BaseState | Array<BaseState>, compute: () => void);
25
+ protected recomputeValue(): Promise<void>;
26
+ dispose(): void;
27
+ }
28
+ export declare function effect<T>(watch: BaseState | Array<BaseState>, compute: () => T | undefined): Effect;
29
+ export declare class Computed<T = any> extends BaseState<T> {
30
+ private compute;
31
+ private readonly effect;
32
+ constructor(watch: BaseState | Array<BaseState>, compute: () => T, initialValue: T, isValidValue: boolean, equals?: EqualityFunction<T>);
33
+ dispose(): void;
34
+ }
35
+ export declare function computed<T>(watch: BaseState | Array<BaseState>, compute: () => T, initialValue: T, equals?: EqualityFunction<T>): Computed<T>;
36
+ export declare function computed<T>(watch: BaseState | Array<BaseState>, compute: () => T | undefined, equals?: EqualityFunction<T | undefined>): Computed<T | undefined>;
package/dist/State.js ADDED
@@ -0,0 +1,107 @@
1
+ export class BaseState {
2
+ _listeners = [];
3
+ _value;
4
+ valueEquals;
5
+ constructor(initialValue, equalityFunction) {
6
+ this._value = initialValue;
7
+ this.valueEquals = equalityFunction ?? ((a, b) => a === b);
8
+ }
9
+ get value() {
10
+ return this._value;
11
+ }
12
+ internalSetValue(newValue) {
13
+ let previousValue = this._value;
14
+ if (this.valueEquals(newValue, previousValue))
15
+ return;
16
+ this._value = newValue;
17
+ this.emit(newValue);
18
+ }
19
+ subscribe(listener) {
20
+ this._listeners.push(listener);
21
+ let currentValue = this._value;
22
+ listener(currentValue);
23
+ }
24
+ unsubscribe(listener) {
25
+ this._listeners = this._listeners.filter(l => l !== listener);
26
+ }
27
+ emit(data) {
28
+ for (const listener of this._listeners) {
29
+ listener(data);
30
+ }
31
+ }
32
+ dispose() {
33
+ this._listeners = [];
34
+ }
35
+ }
36
+ export class State extends BaseState {
37
+ constructor(initialValue, equals) {
38
+ super(initialValue, equals);
39
+ }
40
+ setValue(newValue) {
41
+ super.internalSetValue(newValue);
42
+ }
43
+ }
44
+ export function createState(value, equals) {
45
+ return new State(value, equals);
46
+ }
47
+ export class Effect {
48
+ compute;
49
+ dependencies;
50
+ recomputeBound = this.recomputeValue.bind(this);
51
+ constructor(watch, compute) {
52
+ this.compute = compute;
53
+ this.dependencies = Array.isArray(watch) ? watch : [watch];
54
+ for (let state of this.dependencies) {
55
+ state.subscribe(this.recomputeBound);
56
+ }
57
+ }
58
+ async recomputeValue() {
59
+ try {
60
+ this.compute();
61
+ }
62
+ catch (error) {
63
+ console.error("Error during effect computation:", error);
64
+ }
65
+ }
66
+ dispose() {
67
+ for (let state of this.dependencies) {
68
+ state.unsubscribe(this.recomputeBound);
69
+ }
70
+ }
71
+ }
72
+ export function effect(watch, compute) {
73
+ return new Effect(watch, compute);
74
+ }
75
+ export class Computed extends BaseState {
76
+ compute;
77
+ effect;
78
+ constructor(watch, compute, initialValue, isValidValue, equals) {
79
+ super(initialValue, equals);
80
+ this.compute = compute;
81
+ let recompute = () => {
82
+ const newValue = this.compute();
83
+ super.internalSetValue(newValue);
84
+ };
85
+ this.effect = new Effect(watch, recompute);
86
+ if (!isValidValue)
87
+ recompute();
88
+ }
89
+ dispose() {
90
+ this.effect.dispose();
91
+ }
92
+ }
93
+ export function computed(watch, compute, initialOrEquals, maybeEquals) {
94
+ if (typeof initialOrEquals === 'function' || initialOrEquals === undefined) {
95
+ const equals = initialOrEquals;
96
+ return new Computed(watch, compute,
97
+ /*initialValue*/ undefined,
98
+ /*isValidValue*/ false, equals);
99
+ }
100
+ else {
101
+ const initialValue = initialOrEquals;
102
+ const equals = maybeEquals;
103
+ return new Computed(watch, compute,
104
+ /*initialValue*/ initialValue,
105
+ /*isValidValue*/ true, equals);
106
+ }
107
+ }
@@ -0,0 +1 @@
1
+ export {};