@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.
- package/README.md +13 -0
- package/dist/BaseStyles.d.ts +44 -0
- package/dist/BaseStyles.js +166 -0
- package/dist/Button.d.ts +69 -0
- package/dist/Button.js +56 -0
- package/dist/CssColor.d.ts +44 -0
- package/dist/CssColor.js +196 -0
- package/dist/CssColor.test.d.ts +1 -0
- package/dist/CssColor.test.js +68 -0
- package/dist/CssExpr.d.ts +9 -0
- package/dist/CssExpr.js +35 -0
- package/dist/CssFilter.d.ts +18 -0
- package/dist/CssFilter.js +40 -0
- package/dist/CssNum.d.ts +30 -0
- package/dist/CssNum.js +106 -0
- package/dist/CssNum.test.d.ts +1 -0
- package/dist/CssNum.test.js +30 -0
- package/dist/CssReset.d.ts +1 -0
- package/dist/CssReset.js +15 -0
- package/dist/CssShadow.d.ts +19 -0
- package/dist/CssShadow.js +42 -0
- package/dist/DefaultTheme.d.ts +14 -0
- package/dist/DefaultTheme.js +6 -0
- package/dist/EmptyTheme.d.ts +14 -0
- package/dist/EmptyTheme.js +2 -0
- package/dist/HTML.d.ts +9 -0
- package/dist/HTML.jsx +7 -0
- package/dist/ScopeStyles.d.ts +24 -0
- package/dist/ScopeStyles.js +67 -0
- package/dist/State.d.ts +36 -0
- package/dist/State.js +107 -0
- package/dist/State.test.d.ts +1 -0
- package/dist/State.test.js +41 -0
- package/dist/StyleWriter.d.ts +25 -0
- package/dist/StyleWriter.js +156 -0
- package/dist/Theme.d.ts +56 -0
- package/dist/Theme.js +29 -0
- package/dist/Tone.d.ts +1 -0
- package/dist/Tone.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +9 -0
- package/dist/props.d.ts +7 -0
- package/dist/props.js +104 -0
- package/dist/types.d.ts +239 -0
- package/dist/types.js +1 -0
- package/package.json +36 -0
- package/src/BaseStyles.ts +192 -0
- package/src/Button.ts +68 -0
- package/src/CssColor.test.ts +82 -0
- package/src/CssColor.ts +175 -0
- package/src/CssExpr.ts +25 -0
- package/src/CssFilter.ts +44 -0
- package/src/CssNum.test.ts +37 -0
- package/src/CssNum.ts +93 -0
- package/src/CssReset.ts +17 -0
- package/src/CssShadow.ts +46 -0
- package/src/DefaultTheme.ts +8 -0
- package/src/HTML.tsx +17 -0
- package/src/ScopeStyles.ts +100 -0
- package/src/State.test.ts +47 -0
- package/src/State.ts +164 -0
- package/src/StyleWriter.ts +163 -0
- package/src/Theme.ts +95 -0
- package/src/Tone.ts +1 -0
- package/src/index.test.ts +10 -0
- package/src/index.ts +1 -0
- package/src/props.ts +118 -0
- package/src/types.ts +311 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { CssColor } from "./CssColor";
|
|
2
|
+
import { CssFilter } from "./CssFilter";
|
|
3
|
+
import { Num } from "./CssNum";
|
|
4
|
+
import { CssShadow } from "./CssShadow";
|
|
5
|
+
export type OverrideProperties = ShadowProperties & PaddingProperties & MarginProperties & BorderProperties & BackgroundProperties & LayoutProperties & TypographyProperties;
|
|
6
|
+
export type CssProperties = Omit<Partial<CSSStyleDeclaration>, keyof OverrideProperties> & OverrideProperties & {
|
|
7
|
+
[key: CssVariableName]: string | number | boolean | Num;
|
|
8
|
+
};
|
|
9
|
+
export type CssVariableName = `--${string}`;
|
|
10
|
+
export type ThemeArgs = {
|
|
11
|
+
variants: Record<string, Record<string, any>>;
|
|
12
|
+
colors: string;
|
|
13
|
+
vars: string;
|
|
14
|
+
paddings: string;
|
|
15
|
+
margins: string;
|
|
16
|
+
borders: string;
|
|
17
|
+
backgrounds: string;
|
|
18
|
+
typography: string;
|
|
19
|
+
layouts: string;
|
|
20
|
+
shadows: string;
|
|
21
|
+
classes: string;
|
|
22
|
+
};
|
|
23
|
+
export type ThemeKey = keyof ThemeArgs;
|
|
24
|
+
export interface IThemeParts<A extends ThemeArgs> {
|
|
25
|
+
name?: string;
|
|
26
|
+
variants?: {
|
|
27
|
+
[K in keyof A['variants']]?: Record<keyof A['variants'][K] & string, CssProperties>;
|
|
28
|
+
};
|
|
29
|
+
colors?: Record<A['colors'], string | CssColor>;
|
|
30
|
+
vars?: Record<A['vars'], string | number>;
|
|
31
|
+
paddings?: Record<A['paddings'], PaddingProperties>;
|
|
32
|
+
margins?: Record<A['margins'], MarginProperties>;
|
|
33
|
+
borders?: Record<A['borders'], BorderProperties>;
|
|
34
|
+
backgrounds?: Record<A['backgrounds'], BackgroundProperties>;
|
|
35
|
+
typography?: Record<A['typography'], TypographyProperties>;
|
|
36
|
+
layouts?: Record<A['layouts'], LayoutProperties>;
|
|
37
|
+
shadows?: Record<A['shadows'], ShadowProperties>;
|
|
38
|
+
classes?: Record<A['classes'], CssProperties>;
|
|
39
|
+
styles?: Record<string, CssProperties>;
|
|
40
|
+
}
|
|
41
|
+
export type ShadowProperties = {
|
|
42
|
+
boxShadow?: CssShadow | string;
|
|
43
|
+
textShadow?: CssShadow | string;
|
|
44
|
+
filter?: CssFilter | CssFilter[] | string;
|
|
45
|
+
backdropFilter?: CssFilter | string;
|
|
46
|
+
opacity?: Num | string;
|
|
47
|
+
};
|
|
48
|
+
export type PaddingProperties = {
|
|
49
|
+
padding?: Num;
|
|
50
|
+
paddingTop?: Num;
|
|
51
|
+
paddingRight?: Num;
|
|
52
|
+
paddingBottom?: Num;
|
|
53
|
+
paddingLeft?: Num;
|
|
54
|
+
};
|
|
55
|
+
export type MarginProperties = {
|
|
56
|
+
margin?: Num;
|
|
57
|
+
marginTop?: Num;
|
|
58
|
+
marginRight?: Num;
|
|
59
|
+
marginBottom?: Num;
|
|
60
|
+
marginLeft?: Num;
|
|
61
|
+
};
|
|
62
|
+
export type BorderProperties = {
|
|
63
|
+
border?: string;
|
|
64
|
+
borderWidth?: Num;
|
|
65
|
+
borderStyle?: CssBorderStyle;
|
|
66
|
+
borderColor?: CssColor | string;
|
|
67
|
+
borderCollapse?: CssBorderCollapse;
|
|
68
|
+
borderSpacing?: Num;
|
|
69
|
+
borderTop?: string;
|
|
70
|
+
borderTopWidth?: Num;
|
|
71
|
+
borderTopStyle?: CssBorderStyle;
|
|
72
|
+
borderTopColor?: CssColor | string;
|
|
73
|
+
borderRight?: string;
|
|
74
|
+
borderRightWidth?: Num;
|
|
75
|
+
borderRightStyle?: CssBorderStyle;
|
|
76
|
+
borderRightColor?: CssColor | string;
|
|
77
|
+
borderBottom?: string;
|
|
78
|
+
borderBottomWidth?: Num;
|
|
79
|
+
borderBottomStyle?: CssBorderStyle;
|
|
80
|
+
borderBottomColor?: CssColor | string;
|
|
81
|
+
borderLeft?: string;
|
|
82
|
+
borderLeftWidth?: Num;
|
|
83
|
+
borderLeftStyle?: CssBorderStyle;
|
|
84
|
+
borderLeftColor?: CssColor | string;
|
|
85
|
+
borderRadius?: Num;
|
|
86
|
+
borderTopLeftRadius?: Num;
|
|
87
|
+
borderTopRightRadius?: Num;
|
|
88
|
+
borderBottomLeftRadius?: Num;
|
|
89
|
+
borderBottomRightRadius?: Num;
|
|
90
|
+
cornerTopLeftShape?: CssCornerShape;
|
|
91
|
+
cornerTopRightShape?: CssCornerShape;
|
|
92
|
+
cornerBottomLeftShape?: CssCornerShape;
|
|
93
|
+
cornerBottomRightShape?: CssCornerShape;
|
|
94
|
+
outline?: string;
|
|
95
|
+
outlineWidth?: Num;
|
|
96
|
+
outlineStyle?: CssBorderStyle;
|
|
97
|
+
outlineColor?: CssColor | string;
|
|
98
|
+
outlineOffset?: Num;
|
|
99
|
+
};
|
|
100
|
+
export type BackgroundProperties = {
|
|
101
|
+
background?: string;
|
|
102
|
+
backgroundColor?: CssColor | string;
|
|
103
|
+
backgroundImage?: string;
|
|
104
|
+
backgroundRepeat?: string;
|
|
105
|
+
backgroundPosition?: string;
|
|
106
|
+
backgroundSize?: string;
|
|
107
|
+
backgroundAttachment?: 'scroll' | 'fixed' | 'local' | string;
|
|
108
|
+
backgroundClip?: string;
|
|
109
|
+
backgroundOrigin?: string;
|
|
110
|
+
};
|
|
111
|
+
export type LayoutProperties = {
|
|
112
|
+
position?: 'static' | 'relative' | 'absolute' | 'fixed' | 'sticky' | string;
|
|
113
|
+
inset?: string | Num;
|
|
114
|
+
top?: Num | string;
|
|
115
|
+
right?: Num | string;
|
|
116
|
+
bottom?: Num | string;
|
|
117
|
+
left?: Num | string;
|
|
118
|
+
zIndex?: number | string;
|
|
119
|
+
display?: string;
|
|
120
|
+
boxSizing?: 'content-box' | 'border-box' | string;
|
|
121
|
+
width?: Num | string;
|
|
122
|
+
minWidth?: Num | string;
|
|
123
|
+
maxWidth?: Num | string;
|
|
124
|
+
height?: Num | string;
|
|
125
|
+
minHeight?: Num | string;
|
|
126
|
+
maxHeight?: Num | string;
|
|
127
|
+
flex?: string | Num;
|
|
128
|
+
flexBasis?: Num | string;
|
|
129
|
+
flexGrow?: number | string;
|
|
130
|
+
flexShrink?: number | string;
|
|
131
|
+
flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse' | string;
|
|
132
|
+
flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse' | string;
|
|
133
|
+
justifyContent?: string;
|
|
134
|
+
alignItems?: string;
|
|
135
|
+
alignContent?: string;
|
|
136
|
+
alignSelf?: string;
|
|
137
|
+
order?: number | string;
|
|
138
|
+
gap?: Num | string;
|
|
139
|
+
gridTemplateColumns?: string;
|
|
140
|
+
gridTemplateRows?: string;
|
|
141
|
+
gridColumn?: string;
|
|
142
|
+
gridRow?: string;
|
|
143
|
+
gridGap?: Num | string;
|
|
144
|
+
gridAutoFlow?: string;
|
|
145
|
+
columnCount?: number | string;
|
|
146
|
+
columnWidth?: Num | string;
|
|
147
|
+
columnGap?: Num | string;
|
|
148
|
+
columnRule?: string;
|
|
149
|
+
overflow?: 'visible' | 'hidden' | 'scroll' | 'auto' | string;
|
|
150
|
+
overflowX?: 'visible' | 'hidden' | 'scroll' | 'auto' | string;
|
|
151
|
+
overflowY?: 'visible' | 'hidden' | 'scroll' | 'auto' | string;
|
|
152
|
+
scrollBehavior?: 'auto' | 'smooth' | string;
|
|
153
|
+
overscrollBehavior?: string;
|
|
154
|
+
scrollSnapType?: string;
|
|
155
|
+
scrollSnapAlign?: string;
|
|
156
|
+
};
|
|
157
|
+
export type TypographyProperties = {
|
|
158
|
+
font?: string;
|
|
159
|
+
fontFamily?: string;
|
|
160
|
+
fontSize?: Num;
|
|
161
|
+
fontWeight?: Num;
|
|
162
|
+
fontStyle?: 'normal' | 'italic' | 'oblique' | string;
|
|
163
|
+
lineHeight?: Num;
|
|
164
|
+
letterSpacing?: Num;
|
|
165
|
+
wordSpacing?: Num;
|
|
166
|
+
textTransform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase' | string;
|
|
167
|
+
textDecoration?: string;
|
|
168
|
+
textAlign?: 'left' | 'right' | 'center' | 'justify' | string;
|
|
169
|
+
whiteSpace?: string;
|
|
170
|
+
textOverflow?: 'clip' | 'ellipsis' | string;
|
|
171
|
+
overflowWrap?: 'normal' | 'break-word' | 'anywhere';
|
|
172
|
+
};
|
|
173
|
+
export type CssBorderStyle = 'none' | 'hidden' | 'dotted' | 'dashed' | 'solid' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset';
|
|
174
|
+
export type CssBorderCollapse = 'collapse' | 'separate' | 'inherit' | 'initial' | 'revert' | 'revert-layer' | 'unset';
|
|
175
|
+
export type CssCornerShape = 'bevel' | 'notch' | 'round' | 'scoop' | 'square' | 'squircle';
|
|
176
|
+
export interface IScopeStylesParts<A extends ThemeArgs> extends IThemeParts<A> {
|
|
177
|
+
}
|
|
178
|
+
export interface ITheme<A extends ThemeArgs = any> {
|
|
179
|
+
colors: Record<A['colors'], string>;
|
|
180
|
+
paddings: Record<A['paddings'], string>;
|
|
181
|
+
margins: Record<A['margins'], string>;
|
|
182
|
+
borders: Record<A['borders'], string>;
|
|
183
|
+
shadows: Record<A['shadows'], string>;
|
|
184
|
+
backgrounds: Record<A['backgrounds'], string>;
|
|
185
|
+
typography: Record<A['typography'], string>;
|
|
186
|
+
vars: Record<A['vars'], string>;
|
|
187
|
+
classes: Identity<A['classes']>;
|
|
188
|
+
}
|
|
189
|
+
export type CssClass<TTheme extends ITheme<any>> = Extract<keyof TTheme['classes'], string>;
|
|
190
|
+
export type ClassList<T extends string = any> = T | Array<T | undefined | null | Record<T, boolean | undefined | null>> | Record<T, boolean | undefined | null>;
|
|
191
|
+
export type ThemeClass<TTheme extends ITheme> = ClassList<CssClass<TTheme>>;
|
|
192
|
+
export type IThemeFromArgs<Args extends ThemeArgs> = ITheme<Args>;
|
|
193
|
+
export type ExtractNames<P, K extends ThemeKey> = P extends {
|
|
194
|
+
[Key in K]: Record<infer Names, any>;
|
|
195
|
+
} ? Extract<Names, string> : never;
|
|
196
|
+
export type MergeNames<K extends ThemeKey, A extends ThemeArgs, P> = [
|
|
197
|
+
A[K]
|
|
198
|
+
] extends [never] ? ExtractNames<P, K> : ([ExtractNames<P, K>] extends [never] ? A[K] : A[K] | ExtractNames<P, K>);
|
|
199
|
+
export type Simplify<T> = {
|
|
200
|
+
[K in keyof T]: T[K];
|
|
201
|
+
} & {};
|
|
202
|
+
export type Identity<T extends string> = {
|
|
203
|
+
[K in T]: K;
|
|
204
|
+
};
|
|
205
|
+
export type ExtractVariantRecord<P> = P extends {
|
|
206
|
+
variants: infer V extends Record<string, any>;
|
|
207
|
+
} ? V : {};
|
|
208
|
+
export type MergeVariants<A extends ThemeArgs, P> = Simplify<A['variants'] & ExtractVariantRecord<P>>;
|
|
209
|
+
export type ExtractVariants<P> = P extends {
|
|
210
|
+
variants: infer V;
|
|
211
|
+
} ? V : {};
|
|
212
|
+
export type HasDefault<T> = "default" extends keyof T ? true : false;
|
|
213
|
+
export type RemoveIndexSignature<T> = {
|
|
214
|
+
[K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K];
|
|
215
|
+
};
|
|
216
|
+
export type VariantProps<S> = S extends {
|
|
217
|
+
variants: infer V extends Record<string, any>;
|
|
218
|
+
} ? Simplify<{
|
|
219
|
+
[K in keyof RemoveIndexSignature<V> as K extends string ? (HasDefault<V[K]> extends true ? K : never) : never]?: Extract<keyof V[K], string>;
|
|
220
|
+
} & {
|
|
221
|
+
[K in keyof RemoveIndexSignature<V> as K extends string ? (HasDefault<V[K]> extends true ? never : K) : never]: Extract<keyof V[K], string>;
|
|
222
|
+
}> : {};
|
|
223
|
+
export type ElementPropsRecord = {
|
|
224
|
+
class: string;
|
|
225
|
+
[dataAttr: `data-${string}`]: string | undefined;
|
|
226
|
+
};
|
|
227
|
+
export type MergeThemeArgs<A extends ThemeArgs, P> = Simplify<{
|
|
228
|
+
colors: MergeNames<'colors', A, P>;
|
|
229
|
+
vars: MergeNames<'vars', A, P>;
|
|
230
|
+
paddings: MergeNames<'paddings', A, P>;
|
|
231
|
+
margins: MergeNames<'margins', A, P>;
|
|
232
|
+
borders: MergeNames<'borders', A, P>;
|
|
233
|
+
backgrounds: MergeNames<'backgrounds', A, P>;
|
|
234
|
+
typography: MergeNames<'typography', A, P>;
|
|
235
|
+
shadows: MergeNames<'shadows', A, P>;
|
|
236
|
+
layouts: MergeNames<'layouts', A, P>;
|
|
237
|
+
classes: MergeNames<'classes', A, P>;
|
|
238
|
+
variants: MergeVariants<A, P>;
|
|
239
|
+
}>;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@paganaye/stylets",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"src"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"source": "src/index.ts",
|
|
24
|
+
"description": "A small typescript library to build powerful familiar CSS stylesheets in typescript.",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"typescript": "~5.9.3",
|
|
28
|
+
"vitest": "^2.1.8"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc -p tsconfig.build.json",
|
|
32
|
+
"dev": "tsc -w -p tsconfig.build.json",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"test:watch": "vitest"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { CssColor } from "./CssColor";
|
|
2
|
+
import { StyleWriter } from "./StyleWriter";
|
|
3
|
+
import { ITheme, CssProperties, IThemeParts, ThemeArgs, Identity, BorderProperties, MarginProperties, PaddingProperties, ShadowProperties, BackgroundProperties, TypographyProperties, LayoutProperties } from "./types";
|
|
4
|
+
|
|
5
|
+
export abstract class BaseStyles<
|
|
6
|
+
A extends ThemeArgs>
|
|
7
|
+
implements ITheme<A> {
|
|
8
|
+
|
|
9
|
+
protected _name = "";
|
|
10
|
+
protected readonly _variants: Record<string, Record<string, CssProperties>> = {};
|
|
11
|
+
protected readonly _colors: Record<string, CssColor> = {};
|
|
12
|
+
protected readonly _sizes: Record<string, any> = {};
|
|
13
|
+
protected readonly _paddings: Record<string, PaddingProperties> = {};
|
|
14
|
+
protected readonly _margins: Record<string, MarginProperties> = {};
|
|
15
|
+
protected readonly _borders: Record<string, BorderProperties> = {};
|
|
16
|
+
protected readonly _shadows: Record<string, ShadowProperties> = {};
|
|
17
|
+
protected readonly _backgrounds: Record<string, BackgroundProperties> = {};
|
|
18
|
+
protected readonly _typography: Record<string, TypographyProperties> = {};
|
|
19
|
+
protected readonly _layouts: Record<string, LayoutProperties> = {};
|
|
20
|
+
protected readonly _vars: Record<string, string> = {};
|
|
21
|
+
protected readonly _classes: Record<string, CssProperties> = {};
|
|
22
|
+
protected readonly _styles: Record<string, CssProperties> = {};
|
|
23
|
+
|
|
24
|
+
// this is a record of record but probably not totally rightly typed
|
|
25
|
+
public readonly variants: { [K in keyof A['variants']as K extends string ? K : never]: { [V in keyof A['variants'][K] & string]: V } } = {} as any;
|
|
26
|
+
|
|
27
|
+
public readonly colors: Record<A['colors'], `var(--${A['colors']})`> = {} as any;
|
|
28
|
+
public readonly vars: Record<A['vars'], `var(--${A['vars']})`> = {} as any;
|
|
29
|
+
|
|
30
|
+
public readonly paddings: Record<A['paddings'], `padding-${A['paddings']}`> = {} as any;
|
|
31
|
+
public readonly margins: Record<A['margins'], `margin-${A['margins']}`> = {} as any;
|
|
32
|
+
public readonly borders: Record<A['borders'], `border-${A['borders']}`> = {} as any;
|
|
33
|
+
public readonly shadows: Record<A['shadows'], `shadow-${A['shadows']}`> = {} as any;
|
|
34
|
+
public readonly backgrounds: Record<A['backgrounds'], `background-${A['backgrounds']}`> = {} as any;
|
|
35
|
+
public readonly typography: Record<A['typography'], `typography-${A['typography']}`> = {} as any;
|
|
36
|
+
public readonly layouts: Record<A['layouts'], `layouts-${A['layouts']}`> = {} as any;
|
|
37
|
+
public readonly classes: Identity<A['classes']> = {} as any;
|
|
38
|
+
|
|
39
|
+
protected get name() { return this._name; }
|
|
40
|
+
protected readonly builder: StyleWriter;
|
|
41
|
+
|
|
42
|
+
constructor(themeParts: IThemeParts<A>) {
|
|
43
|
+
let name = themeParts.name ?? "theme";
|
|
44
|
+
this.builder = StyleWriter.byName(name);
|
|
45
|
+
this.add(themeParts);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
protected add(parts: IThemeParts<A> & { name?: string; }) {
|
|
49
|
+
if (parts.name) this._name = parts.name;
|
|
50
|
+
if (parts.variants) Object.assign(this._variants, parts.variants);
|
|
51
|
+
if (parts.colors) Object.assign(this._colors, parts.colors);
|
|
52
|
+
if (parts.vars) Object.assign(this._vars, parts.vars);
|
|
53
|
+
if (parts.paddings) Object.assign(this._paddings, parts.paddings);
|
|
54
|
+
if (parts.margins) Object.assign(this._margins, parts.margins);
|
|
55
|
+
if (parts.borders) Object.assign(this._borders, parts.borders);
|
|
56
|
+
if (parts.layouts) Object.assign(this._layouts, parts.layouts);
|
|
57
|
+
if (parts.shadows) Object.assign(this._shadows, parts.shadows);
|
|
58
|
+
if (parts.classes) Object.assign(this._classes, parts.classes);
|
|
59
|
+
if (parts.styles) Object.assign(this._styles, parts.styles);
|
|
60
|
+
|
|
61
|
+
this.preProcess();
|
|
62
|
+
}
|
|
63
|
+
protected preProcess(): void {
|
|
64
|
+
// Build root variables from multiple sources in a single pass
|
|
65
|
+
const preProcessVars = (src: Record<string, any>, type:
|
|
66
|
+
'colors'
|
|
67
|
+
| 'vars'
|
|
68
|
+
| 'paddings'
|
|
69
|
+
| 'margins'
|
|
70
|
+
| 'borders'
|
|
71
|
+
| 'backgrounds'
|
|
72
|
+
| 'typography'
|
|
73
|
+
| 'layouts', output: Record<string, string>) => {
|
|
74
|
+
let entries = Object.entries(src);
|
|
75
|
+
for (let [key, value] of Object.entries(src)) {
|
|
76
|
+
output[key] = `var(--${key})`;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
preProcessVars(this._colors, 'colors', this.colors);
|
|
80
|
+
preProcessVars(this._vars, 'vars', this.vars);
|
|
81
|
+
|
|
82
|
+
// Process variants
|
|
83
|
+
for (const [groupKey, groupValue] of Object.entries(this._variants)) {
|
|
84
|
+
const variantGroup: Record<string, string> = {};
|
|
85
|
+
for (const variantKey of Object.keys(groupValue)) {
|
|
86
|
+
variantGroup[variantKey] = variantKey;
|
|
87
|
+
}
|
|
88
|
+
(this.variants as any)[groupKey] = variantGroup;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const preProcessRules = (src: Record<string, any>,
|
|
92
|
+
label: string,
|
|
93
|
+
output: Record<string, string>,
|
|
94
|
+
prefix?: string) => {
|
|
95
|
+
const entries = Object.entries(src);
|
|
96
|
+
let isClass = (label === 'classes');
|
|
97
|
+
|
|
98
|
+
for (const [k, v] of entries) {
|
|
99
|
+
output[k] = prefix ? (prefix + k) : k;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
preProcessRules(this._paddings, 'paddings', this.paddings, 'padding-');
|
|
103
|
+
preProcessRules(this._margins, 'margins', this.margins, 'margin-');
|
|
104
|
+
preProcessRules(this._borders, 'borders', this.borders, 'border-');
|
|
105
|
+
preProcessRules(this._backgrounds, 'backgrounds', this.backgrounds, 'background-');
|
|
106
|
+
preProcessRules(this._typography, 'typography', this.typography, 'typography-');
|
|
107
|
+
preProcessRules(this._layouts, 'layouts', this.layouts, 'layouts-');
|
|
108
|
+
preProcessRules(this._shadows, 'shadows', this.shadows, 'shadow-');
|
|
109
|
+
preProcessRules(this._classes, 'classes', this.classes);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
protected renderHeader(): void {
|
|
114
|
+
// this.builder.addLine(`/* ${this.name} start */`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
protected render(): void {
|
|
119
|
+
this.builder.clear();
|
|
120
|
+
this.renderHeader();
|
|
121
|
+
// Build root variables from multiple sources in a single pass
|
|
122
|
+
const processVars = (src: Record<string, any>, type: 'vars' | 'colors' | 'sizes' | 'paddings' | 'margins' | 'backgrounds' | 'typography' | 'layouts') => {
|
|
123
|
+
let entries = Object.entries(src);
|
|
124
|
+
if (entries.length === 0) return;
|
|
125
|
+
this.builder.addLine(`/* ${this.name} ${type} */`);
|
|
126
|
+
this.builder.addLine(`:root {`);
|
|
127
|
+
this.builder.indentLevel++;
|
|
128
|
+
for (let [key, value] of Object.entries(src)) {
|
|
129
|
+
switch (typeof value) {
|
|
130
|
+
case 'number':
|
|
131
|
+
value = `${value}rem`;
|
|
132
|
+
break;
|
|
133
|
+
case 'object':
|
|
134
|
+
value = value.toString();
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
this.builder.addLine(`--${key}: ${value};`);
|
|
138
|
+
}
|
|
139
|
+
this.builder.indentLevel--;
|
|
140
|
+
this.builder.addLine(`}`);
|
|
141
|
+
};
|
|
142
|
+
processVars(this._colors, 'colors');
|
|
143
|
+
processVars(this._sizes, 'sizes');
|
|
144
|
+
processVars(this._vars, 'vars');
|
|
145
|
+
|
|
146
|
+
// Helper to emit classes/styles to avoid repetition
|
|
147
|
+
const processRules = (src: Record<string, any>, label: string, prefix?: string) => {
|
|
148
|
+
const entries = Object.entries(src);
|
|
149
|
+
if (entries.length === 0) return;
|
|
150
|
+
this.builder.addLine(`/* ${this.name} ${label} */`);
|
|
151
|
+
|
|
152
|
+
for (const [k, v] of entries) {
|
|
153
|
+
const selector = prefix ? `${prefix}${k}` : k;
|
|
154
|
+
this.builder.addRule(selector, v as any);
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
processRules(this._paddings, 'paddings', ".padding-");
|
|
159
|
+
processRules(this._margins, 'margins', ".margin-");
|
|
160
|
+
processRules(this._borders, 'borders', ".border-");
|
|
161
|
+
processRules(this._backgrounds, 'backgrounds', ".background-");
|
|
162
|
+
processRules(this._typography, 'typography', ".typography-");
|
|
163
|
+
processRules(this._layouts, 'layouts', ".layouts-");
|
|
164
|
+
processRules(this._shadows, 'shadows', ".shadow-");
|
|
165
|
+
processRules(this._classes, 'classes', ".");
|
|
166
|
+
processRules(this._styles, 'styles', "");
|
|
167
|
+
|
|
168
|
+
// Process variants with attribute selectors
|
|
169
|
+
const processVariants = () => {
|
|
170
|
+
const entries = Object.entries(this._variants);
|
|
171
|
+
if (entries.length === 0) return;
|
|
172
|
+
this.builder.addLine(`/* ${this.name} variants */`);
|
|
173
|
+
|
|
174
|
+
for (const [groupKey, groupValue] of entries) {
|
|
175
|
+
for (const [variantKey, variantStyles] of Object.entries(groupValue)) {
|
|
176
|
+
const selector = `[${groupKey}="${variantKey}"]`;
|
|
177
|
+
this.builder.addRule(selector, variantStyles as any);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
processVariants();
|
|
183
|
+
|
|
184
|
+
this.renderFooter();
|
|
185
|
+
this.builder.render();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
protected renderFooter(): void {
|
|
189
|
+
this.builder.addLine(`/* ${this.name} end */`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
}
|
package/src/Button.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { prepareProps, completeProps, Elt } from "./props";
|
|
2
|
+
import { theme as theme } from "./DefaultTheme"; // --- IGNORE ---
|
|
3
|
+
import { alter } from "./CssColor";
|
|
4
|
+
import { v } from "./CssExpr";
|
|
5
|
+
import { IDivProps } from "./HTML";
|
|
6
|
+
import { Tone } from "./Tone";
|
|
7
|
+
import { VariantProps } from "./types";
|
|
8
|
+
|
|
9
|
+
let styles = theme.declareScope({
|
|
10
|
+
class: 'btn',
|
|
11
|
+
scopeEnd: 'img',
|
|
12
|
+
colors: {},
|
|
13
|
+
sizes: {},
|
|
14
|
+
vars: {},
|
|
15
|
+
classes: {
|
|
16
|
+
customButton: { padding: '10px 15px' }
|
|
17
|
+
},
|
|
18
|
+
styles: {
|
|
19
|
+
':scope': {
|
|
20
|
+
transition: 'all 0.25s ease',
|
|
21
|
+
borderRadius: `var(--buttonRadius)`,
|
|
22
|
+
borderColor: alter(v('tone'), {
|
|
23
|
+
l: { min: v('BdLum'), max: v('BdLum') },
|
|
24
|
+
c: { mul: v('BdChroma') }
|
|
25
|
+
}),
|
|
26
|
+
},
|
|
27
|
+
':scope:hover': {
|
|
28
|
+
'--BgLum': '0.45',
|
|
29
|
+
'--BdLum': '0.95',
|
|
30
|
+
outline: '1px solid yellow',
|
|
31
|
+
},
|
|
32
|
+
':scope:active': {
|
|
33
|
+
'--BgLum': '0',
|
|
34
|
+
'--BdLum': '0.3',
|
|
35
|
+
transform: 'translate(.1rem,.2rem)',
|
|
36
|
+
outline: '1px solid',
|
|
37
|
+
outlineColor: theme.colors.primary
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
variants: {
|
|
41
|
+
buttonType: {
|
|
42
|
+
outline: { borderColor: 'red' },
|
|
43
|
+
normal: { borderColor: 'blue' },
|
|
44
|
+
default: { borderColor: 'gray' }
|
|
45
|
+
},
|
|
46
|
+
buttonSize: {
|
|
47
|
+
small: { width: '200px' },
|
|
48
|
+
large: { width: '400px' },
|
|
49
|
+
default: { width: '300px' }
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
}).render();
|
|
53
|
+
|
|
54
|
+
export interface IButtonProps extends IDivProps, VariantProps<typeof styles> {
|
|
55
|
+
tone?: Tone;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function Button(props: IButtonProps, ...children: any[]) {
|
|
59
|
+
const newProps = prepareProps(props, styles);
|
|
60
|
+
if (props.tone) {
|
|
61
|
+
newProps.class.tone = true;
|
|
62
|
+
newProps.class[props.tone] = true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return Elt('button', newProps, children);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
// TODO: Update imports once CssColor is fully integrated
|
|
3
|
+
// import { alpha, contrast, complement, triadic, analogous, mix, alter, lch } from './CssColor';
|
|
4
|
+
// import { v } from './CssExpr';
|
|
5
|
+
|
|
6
|
+
describe('colorUtils', () => {
|
|
7
|
+
it.skip('cssVar returns a CSS variable string', () => {
|
|
8
|
+
// expect(v('primary').toString()).toBe('var(--primary)');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it.skip('col creates a Color instance representing a CSS var', () => {
|
|
12
|
+
// const val = v('accent');
|
|
13
|
+
// expect(String(val)).toBe('var(--accent)');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it.skip('mixColors returns base when ratio <= 0', () => {
|
|
17
|
+
// const base = lch(0.5, 0.2, 200);
|
|
18
|
+
// const other = lch(0.7, 0.3, 100);
|
|
19
|
+
// expect(mix(base, other, 0)).toBe('oklch(0.5 0.2 200)');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it.skip('mixColors returns other when ratio >= 1', () => {
|
|
23
|
+
// const base = lch(0.5, 0.2, 200);
|
|
24
|
+
// const other = lch(0.7, 0.3, 100);
|
|
25
|
+
// expect(mix(base, other, 1)).toBe('oklch(0.7 0.3 100)');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it.skip('mixColors returns mix string for intermediate ratio', () => {
|
|
29
|
+
// const base = lch(0.5, 0.2, 200);
|
|
30
|
+
// const other = lch(0.7, 0.3, 100);
|
|
31
|
+
// expect(mix(base, other, 0.25)).toBe('mix(oklch(0.5 0.2 200) 75%, oklch(0.7 0.3 100), 25%)');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it.skip('alterColor with numeric alterations', () => {
|
|
35
|
+
// const base = lch(0.5, 0.2, 200);
|
|
36
|
+
// const out = alter(base, { l: 0.3, c: { mul: 2 }, h: { add: 10 } });
|
|
37
|
+
// expect(out).toBe('oklch(from oklch(0.5 0.2 200) 0.3 calc(c * 2) calc(h + 10))');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it.skip('alterColor with clamp alterations', () => {
|
|
41
|
+
// const base = lch(0.5, 0.2, 200);
|
|
42
|
+
// const out = alter(base, { l: { min: 0, max: 1 }, c: { min: v('cMin') as any, max: v('cMax') as any } });
|
|
43
|
+
// expect(out).toBe('oklch(from oklch(0.5 0.2 200) clamp(0, l, 1) clamp(var(--cMin), c, var(--cMax)) h)');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it.skip('alterColor with multiple alterations', () => {
|
|
47
|
+
// const base = lch(0.6, 0.4, 120);
|
|
48
|
+
// const out = alter(base, { l: { mul: 0.5, add: 0.1, min: 0, max: 1 }, c: { mul: v('scale'), add: 0.02 }, h: 180 });
|
|
49
|
+
// expect(out).toBe('oklch(from oklch(0.6 0.4 120) clamp(0, calc((l * 0.5) + 0.1), 1) calc((c * var(--scale)) + 0.02) 180)');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it.skip('alpha wraps color with opacity', () => {
|
|
53
|
+
// const base = lch(0.5, 0.2, 200);
|
|
54
|
+
// expect(alpha(base, 0.4)).toBe('color(oklch(0.5 0.2 200) / 0.4)');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it.skip('contrast returns black for light lch', () => {
|
|
58
|
+
// const light = lch(0.9, 0.1, 10);
|
|
59
|
+
// expect(contrast(light)).toBe('black');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it.skip('contrast returns white for dark lch', () => {
|
|
63
|
+
// const dark = lch(0.2, 0.2, 10);
|
|
64
|
+
// expect(contrast(dark)).toBe('white');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it.skip('complement rotates hue by 180', () => {
|
|
68
|
+
// const c = lch(0.5, 0.2, 30);
|
|
69
|
+
// expect(complement(c)).toBe('oklch(0.5 0.2 210)');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it.skip('triadic produces rotated hues', () => {
|
|
73
|
+
// const c = lch(0.5, 0.2, 30);
|
|
74
|
+
// expect(triadic(c, 1)).toBe('oklch(0.5 0.2 150)');
|
|
75
|
+
// expect(triadic(c, 2)).toBe('oklch(0.5 0.2 270)');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it.skip('analogous returns two nearby hues', () => {
|
|
79
|
+
// const c = lch(0.5, 0.2, 60);
|
|
80
|
+
// expect(analogous(c, 20)).toBe('oklch(0.5 0.2 80), oklch(0.5 0.2 40)');
|
|
81
|
+
});
|
|
82
|
+
});
|