Skip to content

Commit bab9299

Browse files
committed
feat: add qwik adapter
1 parent 9b761f3 commit bab9299

File tree

12 files changed

+2823
-329
lines changed

12 files changed

+2823
-329
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ CSS-in-JS with <strong>zero runtime</strong>, <strong>type safety</strong> and <
1515
- First class Typescript support.
1616
- Supports both styled-components API and vanilla styling API.
1717
- [Stitches](https://stitches.dev/)-like variants API.
18-
- Out of box support for React and Solid.
18+
- Out of box support for React, Solid and Qwik.
1919
- Integrations for [esbuild](https://esbuild.github.io/) and [Vite](https://vitejs.dev/).
2020

2121
## Documentation

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"./packages/vite",
1414
"./packages/solid",
1515
"./packages/react",
16+
"./packages/qwik",
1617
"./packages/integration",
1718
"./packages/esbuild",
1819
"./packages/core",
@@ -65,4 +66,4 @@
6566
"tsup": "^6.0.1",
6667
"typescript": "^4.7.2"
6768
}
68-
}
69+
}

packages/babel/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"@babel/core": "^7.18.2",
1515
"@babel/generator": "^7.18.2",
1616
"@babel/helper-module-imports": "^7.16.7",
17-
"@babel/preset-typescript": "^7.17.12",
17+
"@babel/preset-typescript": "^7.22.5",
1818
"@emotion/hash": "^0.8.0",
1919
"@types/babel__core": "^7.1.19"
2020
},

packages/babel/yarn.lock

Lines changed: 523 additions & 0 deletions
Large diffs are not rendered by default.

packages/qwik/README.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# macaron
2+
3+
macaron is a zero-runtime and type-safe CSS-in-JS library made with performance in mind
4+
5+
- Powered by **vanilla-extract**
6+
- Allows defining styles in the same file as components
7+
- Zero runtime builds
8+
- Supports both styled-components API and plain styling api that returns classes.
9+
- Stitches-like variants
10+
- First class typescript support
11+
- Out of box support for react, solidjs and qwik
12+
- Supports esbuild and vite (with hmr)
13+
14+
## Example
15+
16+
### Styled API
17+
18+
```jsx
19+
import { styled } from '@macaron-css/solid';
20+
21+
const StyledButton = styled('button', {
22+
base: {
23+
borderRadius: 6,
24+
},
25+
variants: {
26+
color: {
27+
neutral: { background: 'whitesmoke' },
28+
brand: { background: 'blueviolet' },
29+
accent: { background: 'slateblue' },
30+
},
31+
size: {
32+
small: { padding: 12 },
33+
medium: { padding: 16 },
34+
large: { padding: 24 },
35+
},
36+
rounded: {
37+
true: { borderRadius: 999 },
38+
},
39+
},
40+
compoundVariants: [
41+
{
42+
variants: {
43+
color: 'neutral',
44+
size: 'large',
45+
},
46+
style: {
47+
background: 'ghostwhite',
48+
},
49+
},
50+
],
51+
52+
defaultVariants: {
53+
color: 'accent',
54+
size: 'medium',
55+
},
56+
});
57+
58+
// Use it like a regular solidjs component
59+
function App() {
60+
return (
61+
<StyledButton color="accent" size="small" rounded={true}>
62+
Click me!
63+
</StyledButton>
64+
);
65+
}
66+
```
67+
68+
### Styling API
69+
70+
The styling API is the same api is vanilla-extract, but allows styles to be defined in the same file, increasing the authoring experience.
71+
72+
Check out [vanilla-extract docs](https://vanilla-extract.style/documentation/styling-api/)

packages/qwik/package.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "@macaron-css/qwik",
3+
"version": "1.0.0",
4+
"license": "MIT",
5+
"main": "dist/index.js",
6+
"module": "dist/index.mjs",
7+
"types": "dist/index.d.ts",
8+
"repository": {
9+
"type": "git",
10+
"url": "https://github.com/mokshit06/macaron.git",
11+
"directory": "packages/qwik"
12+
},
13+
"exports": {
14+
".": {
15+
"import": "./dist/index.mjs",
16+
"require": "./dist/index.js"
17+
},
18+
"./dist/*": "./dist/*",
19+
"./runtime": {
20+
"import": "./dist/runtime.mjs",
21+
"require": "./dist/runtime.js"
22+
}
23+
},
24+
"devDependencies": {
25+
"@builder.io/qwik": "^1.1.5",
26+
"@vanilla-extract/recipes": "^0.2.5"
27+
},
28+
"peerDependencies": {
29+
"@builder.io/qwik": "^1.1.5",
30+
"@vanilla-extract/recipes": "^0.2.5"
31+
},
32+
"files": [
33+
"dist",
34+
"src"
35+
]
36+
}

packages/qwik/src/index.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import {
2+
PatternOptions,
3+
VariantGroups,
4+
VariantSelection,
5+
} from '@vanilla-extract/recipes/dist/declarations/src/types';
6+
import {
7+
Component,
8+
JSXChildren,
9+
QwikIntrinsicElements,
10+
} from '@builder.io/qwik';
11+
12+
type IntrinsicProps<TComponent> = TComponent extends keyof QwikIntrinsicElements
13+
? QwikIntrinsicElements[TComponent]
14+
: any;
15+
16+
type StyledComponent<
17+
TProps = {},
18+
Variants extends VariantGroups = {}
19+
> = Component<TProps & { class?: string; children?: JSXChildren }> & {
20+
variants: Array<keyof Variants>;
21+
selector: (variants: VariantSelection<Variants>) => string;
22+
};
23+
24+
export function styled<
25+
TProps,
26+
TComponent extends string | keyof QwikIntrinsicElements,
27+
Variants extends VariantGroups = {}
28+
>(
29+
component: TComponent,
30+
options: PatternOptions<Variants>
31+
): StyledComponent<
32+
IntrinsicProps<TComponent> & VariantSelection<Variants>,
33+
Variants
34+
>;
35+
36+
export function styled<TProps, Variants extends VariantGroups = {}>(
37+
component: Component<TProps & {}>,
38+
options: PatternOptions<Variants>
39+
): StyledComponent<TProps & VariantSelection<Variants>, Variants>;
40+
41+
export function styled(component: any, options: any): any {
42+
// the following doesn't work because vanilla-extract's function serializer
43+
// cannot serialize complex functions like `$$styled`
44+
45+
// const runtimeFn = recipe(options);
46+
47+
// return addFunctionSerializer($$styled(component, runtimeFn as any), {
48+
// importPath: '@macaron-css/qwik/runtime',
49+
// args: [component, runtimeFn],
50+
// importName: '$$styled',
51+
// });
52+
53+
throw new Error(
54+
"This function shouldn't be there in your final code. If you're seeing this, there is probably some issue with your build config. If you think everything looks fine, then file an issue at https://github.com/mokshit06/macaron/issues"
55+
);
56+
}
57+
58+
export type StyleVariants<T extends StyledComponent<any, any>> =
59+
T extends StyledComponent<any, infer TVariants>
60+
? VariantSelection<TVariants>
61+
: unknown;

packages/qwik/src/runtime.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { component$, h, useComputed$ } from '@builder.io/qwik';
2+
3+
export function $$styled(
4+
Comp: any,
5+
styles: ((options?: any) => string) & {
6+
macaronMeta: {
7+
variants: string[];
8+
defaultClassName: string;
9+
variantConcat(options: any): string;
10+
};
11+
}
12+
) {
13+
const StyledComponent: any = component$(({ as, ...props }: any) => {
14+
let CompToRender = as ?? Comp;
15+
const propsSignal = useComputed$(() => {
16+
const [classes, others]: any[] = [{}, {}];
17+
18+
for (const [key, value] of Object.entries(props)) {
19+
if (StyledComponent.variants.includes(key)) {
20+
classes[key] = value;
21+
} else {
22+
others[key] = value;
23+
}
24+
}
25+
26+
return { variants: classes, others };
27+
});
28+
const className = useComputed$(() => {
29+
const classes = StyledComponent.classes(
30+
propsSignal.value.variants,
31+
props.className
32+
);
33+
return classes.join(' ');
34+
});
35+
36+
if (typeof CompToRender === 'string') {
37+
return h(CompToRender, { ...propsSignal.value.others, className });
38+
}
39+
40+
return h(CompToRender, { ...props, className });
41+
});
42+
43+
StyledComponent.toString = () => StyledComponent.selector(null);
44+
StyledComponent.variants = [
45+
...(styles.macaronMeta.variants ?? []),
46+
...(Comp.variants ?? []),
47+
];
48+
StyledComponent.variantConcat = styles.macaronMeta.variantConcat;
49+
StyledComponent.classes = (
50+
variants: any,
51+
merge?: string,
52+
fn: any = styles
53+
) => {
54+
const classes = new Set(
55+
classNames(fn(variants) + (merge ? ` ${merge}` : ''))
56+
);
57+
58+
if (Comp.classes) {
59+
for (const c of Comp.classes(
60+
variants,
61+
merge,
62+
Comp.variantConcat
63+
) as string[]) {
64+
classes.add(c);
65+
}
66+
}
67+
68+
return Array.from(classes);
69+
};
70+
StyledComponent.selector = (variants: any) => {
71+
const classes = StyledComponent.classes(
72+
variants,
73+
undefined,
74+
styles.macaronMeta.variantConcat
75+
);
76+
// first element isn't empty
77+
if (classes.length > 0 && classes[0].length > 0) {
78+
return '.' + classes.join('.');
79+
}
80+
return classes.join('.');
81+
};
82+
83+
return StyledComponent;
84+
}
85+
86+
function classNames(className: string) {
87+
return className.split(' ');
88+
}

packages/qwik/tsconfig.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ESNext",
4+
"moduleResolution": "node",
5+
"esModuleInterop": true,
6+
"declaration": true,
7+
"outDir": "build",
8+
"strict": true,
9+
"skipLibCheck": true,
10+
"emitDeclarationOnly": true,
11+
},
12+
"include": [
13+
"src/**/*.ts",
14+
],
15+
"exclude": [
16+
"dist",
17+
"node_modules"
18+
]
19+
}

scripts/build.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const packages: Array<[string, string[]]> = [
1010
'packages/core',
1111
['src/index.ts', 'src/create-runtime-fn.ts', 'src/dynamic.ts'],
1212
],
13+
['packages/qwik', ['src/index.ts', 'src/runtime.ts']],
1314
['packages/react', ['src/index.ts', 'src/runtime.ts']],
1415
['packages/solid', ['src/index.ts', 'src/runtime.ts']],
1516
];

0 commit comments

Comments
 (0)