├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .npmignore
├── .prettierrc.js
├── @docs
├── assets
│ ├── logo
│ │ ├── taddy1.png
│ │ ├── taddy1.svg
│ │ ├── taddy11.png
│ │ ├── taddy11.svg
│ │ ├── taddy2.png
│ │ ├── taddy2.svg
│ │ ├── taddy9.png
│ │ └── taddy9.svg
│ └── package.json
└── website
│ ├── .gitignore
│ ├── README.md
│ ├── compiler
│ ├── index.ts
│ └── stubs
│ │ ├── babel-core.js
│ │ ├── fs.js
│ │ ├── module.js
│ │ ├── path.js
│ │ └── sync-rpc.js
│ ├── components
│ ├── BaseLink.tsx
│ ├── Link.tsx
│ ├── LinkButton.tsx
│ ├── Sidebar
│ │ ├── index.tsx
│ │ └── styles.module.css
│ ├── layout.tsx
│ └── playground
│ │ ├── CompiledCode.tsx
│ │ ├── Editor.tsx
│ │ ├── EditorLayer.tsx
│ │ ├── LiveEditor.tsx
│ │ ├── Options.tsx
│ │ ├── ReactRender.tsx
│ │ ├── atoms.ts
│ │ └── index.tsx
│ ├── next-env.d.ts
│ ├── next.config.js
│ ├── package.json
│ ├── pages
│ ├── _app.tsx
│ ├── index.tsx
│ ├── playground
│ │ └── index.tsx
│ └── roadmap.md
│ ├── public
│ ├── favicon.ico
│ └── logo
│ │ ├── taddy1.png
│ │ ├── taddy1.svg
│ │ ├── taddy11.png
│ │ ├── taddy11.svg
│ │ ├── taddy2.png
│ │ ├── taddy2.svg
│ │ ├── taddy9.png
│ │ └── taddy9.svg
│ ├── styles
│ ├── globals.css
│ ├── index.ts
│ ├── mixins.ts
│ ├── reset.css
│ └── taddy.css
│ ├── taddy-plugin.js
│ ├── tsconfig.json
│ ├── utils
│ ├── code.tsx
│ └── history.tsx
│ └── vercel.json
├── @examples
├── astro
│ ├── .gitignore
│ ├── README.md
│ ├── astro.config.mjs
│ ├── package.json
│ ├── public
│ │ └── favicon.svg
│ ├── src
│ │ ├── components
│ │ │ └── Card.astro
│ │ ├── env.d.ts
│ │ ├── layouts
│ │ │ └── Layout.astro
│ │ └── pages
│ │ │ └── index.astro
│ └── tsconfig.json
├── nextjs
│ ├── .eslintrc.json
│ ├── .gitignore
│ ├── README.md
│ ├── app
│ │ ├── SuperComponent.tsx
│ │ ├── api
│ │ │ └── hello
│ │ │ │ └── route.ts
│ │ ├── favicon.ico
│ │ ├── layout.tsx
│ │ └── page.tsx
│ ├── next.config.js
│ ├── package.json
│ ├── public
│ │ ├── next.svg
│ │ ├── thirteen.svg
│ │ └── vercel.svg
│ └── tsconfig.json
├── nuxt
│ ├── .gitignore
│ ├── .npmrc
│ ├── README.md
│ ├── app.vue
│ ├── components
│ │ ├── Test.tsx
│ │ └── Test2.tsx
│ ├── nuxt.config.ts
│ ├── package.json
│ ├── pages
│ │ └── index.vue
│ ├── public
│ │ └── favicon.ico
│ └── tsconfig.json
├── parcel
│ ├── .babelrc
│ ├── App.tsx
│ ├── index.html
│ ├── index.tsx
│ ├── package.json
│ └── tsconfig.json
├── react-native-expo
│ ├── .gitignore
│ ├── App.tsx
│ ├── app.json
│ ├── assets
│ │ ├── adaptive-icon.png
│ │ ├── favicon.png
│ │ ├── icon.png
│ │ └── splash.png
│ ├── babel.config.js
│ ├── index.tsx
│ ├── package.json
│ └── tsconfig.json
├── remix
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── README.md
│ ├── app
│ │ ├── root.tsx
│ │ └── routes
│ │ │ ├── index.tsx
│ │ │ └── test
│ │ │ └── index.tsx
│ ├── package.json
│ ├── public
│ │ └── favicon.ico
│ ├── remix.config.js
│ ├── remix.env.d.ts
│ └── tsconfig.json
├── solid-start
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ ├── public
│ │ └── favicon.ico
│ ├── src
│ │ ├── components
│ │ │ ├── Counter.tsx
│ │ │ └── Hello.tsx
│ │ ├── entry-client.tsx
│ │ ├── entry-server.tsx
│ │ ├── root.tsx
│ │ └── routes
│ │ │ ├── [...404].tsx
│ │ │ └── index.tsx
│ ├── tsconfig.json
│ └── vite.config.ts
└── svelte-kit
│ ├── .gitignore
│ ├── .npmrc
│ ├── README.md
│ ├── package.json
│ ├── src
│ ├── app.d.ts
│ ├── app.html
│ └── routes
│ │ ├── +layout.svelte
│ │ ├── +page.svelte
│ │ └── test
│ │ └── +page.svelte
│ ├── static
│ └── favicon.png
│ ├── svelte.config.js
│ ├── tsconfig.json
│ └── vite.config.ts
├── @taddy
├── babel-plugin
│ ├── .gitignore
│ ├── .npmignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── cache
│ │ └── index.js
│ ├── index.ts
│ ├── macro.ts
│ ├── package.json
│ ├── src
│ │ ├── Output.ts
│ │ ├── Processor.ts
│ │ ├── TSProcessor.ts
│ │ ├── config.js
│ │ ├── handlers.ts
│ │ ├── helpers
│ │ │ ├── BindingOptimizer.ts
│ │ │ ├── buildCodeByPath.ts
│ │ │ ├── evaluate.ts
│ │ │ ├── evaluate.worker.cjs
│ │ │ ├── findBindings.ts
│ │ │ ├── getObjectPropertyKey.ts
│ │ │ ├── mergeObjectProperties.ts
│ │ │ ├── optimizeStaticStyles.ts
│ │ │ ├── taggedTemplateToObject.ts
│ │ │ └── utils.cjs
│ │ ├── index.ts
│ │ ├── macro-plugin.ts
│ │ ├── plugin.ts
│ │ ├── source-maps.ts
│ │ ├── tests
│ │ │ ├── common.ts
│ │ │ ├── data
│ │ │ │ └── mixins.ts
│ │ │ ├── evaluate.test.ts
│ │ │ ├── index.test.ts
│ │ │ ├── static.test.ts
│ │ │ └── typescript.test.ts
│ │ └── types.ts
│ └── tsconfig.json
├── core
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── NameGenerator
│ │ ├── index.test.ts
│ │ └── index.ts
│ ├── README.md
│ ├── common.ts
│ ├── config.ts
│ ├── h.ts
│ ├── index.test.ts
│ ├── index.ts
│ ├── package.json
│ ├── rollup.config.js
│ ├── static
│ │ └── index.ts
│ └── tsconfig.json
├── esbuild-plugin
│ ├── CHANGELOG.md
│ ├── index.js
│ ├── package.json
│ └── tsconfig.json
├── next-plugin
│ ├── CHANGELOG.md
│ ├── index.js
│ ├── loader.cjs
│ ├── package.json
│ ├── rollup.config.js
│ └── tsconfig.json
└── vite-plugin
│ ├── index.js
│ ├── package.json
│ └── tsconfig.json
├── @types
└── global.d.ts
├── LICENSE
├── README.md
├── ROADMAP.md
├── babel.config.js
├── jest.config.js
├── lerna.json
├── package.json
├── prettier.config.js
├── rollup.config.common.js
├── taddy.macro
├── .gitignore
├── CHANGELOG.md
├── README.md
├── index.d.ts
├── index.ts
├── package.json
├── rollup.config.js
└── tsconfig.json
├── taddy
├── $css.ts
├── .gitignore
├── CHANGELOG.md
├── README.md
├── RuleInjector
│ ├── Sheet.ts
│ ├── StyleSheet.ts
│ ├── VirtualStyleSheet.ts
│ ├── common.ts
│ └── index.ts
├── at.ts
├── css.js
├── index.native.ts
├── index.ts
├── mixin.ts
├── package.json
├── react-native
│ └── processStyles.ts
├── rollup.config.js
├── tests
│ ├── index.test.ts
│ └── utils.ts
├── tsconfig.json
├── types.ts
└── vue
│ └── index.ts
├── tsconfig.build.json
├── tsconfig.json
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 4
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .DS_Store
3 | node_modules
4 | dist
5 | *.code-workspace
6 | .vscode
7 | .cache
8 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /** @type {import('eslint').Linter.Config} */
2 | module.exports = {
3 | root: true,
4 | parser: '@typescript-eslint/parser',
5 | parserOptions: {
6 | ecmaVersion: 12,
7 | sourceType: 'module',
8 | },
9 | extends: [
10 | 'eslint:recommended',
11 | 'plugin:import/recommended',
12 | 'plugin:import/typescript',
13 | 'plugin:@typescript-eslint/recommended',
14 | 'plugin:react/recommended',
15 | 'plugin:react/jsx-runtime',
16 | 'plugin:react-hooks/recommended',
17 | 'prettier',
18 | ],
19 | settings: {
20 | 'import/ignore': ['react-native'],
21 |
22 | react: {
23 | version: '18',
24 | },
25 | },
26 | rules: {
27 | 'react/react-in-jsx-scope': 'off',
28 | },
29 | overrides: [
30 | {
31 | files: ['**/*.{js,cjs}', '@taddy/babel-plugin/**'],
32 | rules: {
33 | '@typescript-eslint/no-var-requires': 'off',
34 | },
35 | },
36 | ],
37 | env: {
38 | browser: true,
39 | es2022: true,
40 | node: true,
41 | },
42 | };
43 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on: [push]
3 | jobs:
4 | build:
5 | runs-on: ubuntu-latest
6 |
7 | steps:
8 | - uses: actions/checkout@v3
9 | with:
10 | fetch-depth: 0
11 |
12 | - uses: actions/setup-node@v3
13 | with:
14 | node-version: 18
15 | cache: 'yarn'
16 |
17 | - run: yarn install --frozen-lockfile
18 | env:
19 | CI: true
20 |
21 | - name: Build
22 | run: yarn build --ci
23 | env:
24 | CI: true
25 |
26 | - name: Lint
27 | run: yarn lint
28 | env:
29 | CI: true
30 |
31 | - name: Typescript
32 | run: yarn check:ts --ci
33 | env:
34 | CI: true
35 |
36 | - name: Test
37 | run: yarn test --ci --coverage
38 | env:
39 | CI: true
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .DS_Store
3 |
4 | node_modules
5 |
6 | dist
7 | lib
8 | *.code-workspace
9 | .vscode
10 | .cache
11 |
12 | !packages/taddy/.cache
13 | # taddy.css
14 | cache/*.css
15 |
16 | .vercel
17 |
18 | *.tsbuildinfo
19 | .parcel-cache
20 | .rollup.cache
21 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | *.tsbuildinfo
2 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | /** @type import('prettier').Options */
2 | module.exports = {
3 | printWidth: 80,
4 | semi: true,
5 | singleQuote: true,
6 | trailingComma: 'all',
7 | bracketSpacing: false,
8 | };
9 |
--------------------------------------------------------------------------------
/@docs/assets/logo/taddy1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@docs/assets/logo/taddy1.png
--------------------------------------------------------------------------------
/@docs/assets/logo/taddy11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@docs/assets/logo/taddy11.png
--------------------------------------------------------------------------------
/@docs/assets/logo/taddy2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@docs/assets/logo/taddy2.png
--------------------------------------------------------------------------------
/@docs/assets/logo/taddy9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@docs/assets/logo/taddy9.png
--------------------------------------------------------------------------------
/@docs/assets/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "@docs/assets",
4 | "description": "taddy documentation assets",
5 | "version": "0.0.0"
6 | }
7 |
--------------------------------------------------------------------------------
/@docs/website/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env.local
29 | .env.development.local
30 | .env.test.local
31 | .env.production.local
32 |
33 | # vercel
34 | .vercel
35 |
--------------------------------------------------------------------------------
/@docs/website/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | ```
12 |
13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
14 |
15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
16 |
17 | ## Learn More
18 |
19 | To learn more about Next.js, take a look at the following resources:
20 |
21 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
22 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
23 |
24 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
25 |
26 | ## Deploy on Vercel
27 |
28 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/import?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
29 |
30 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
31 |
--------------------------------------------------------------------------------
/@docs/website/compiler/stubs/babel-core.js:
--------------------------------------------------------------------------------
1 | import {transformSync} from '@babel/core';
2 |
3 | module.exports = {transformAsync: transformSync};
4 |
--------------------------------------------------------------------------------
/@docs/website/compiler/stubs/fs.js:
--------------------------------------------------------------------------------
1 | const {fs} = require('filer');
2 |
3 | const noop = () => void 0;
4 |
5 | fs.writeFileSync = (...args) => fs.writeFile(...args, noop);
6 | fs.existsSync = (...args) => fs.exists(...args, noop);
7 | fs.readFileSync = (...args) => fs.readFile(...args, noop);
8 | fs.appendFileSync = (...args) => fs.appendFile(...args, noop);
9 | fs.mkdirSync = (...args) => fs.mkdir(...args, noop);
10 |
11 | module.exports = fs;
12 |
--------------------------------------------------------------------------------
/@docs/website/compiler/stubs/module.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/@docs/website/compiler/stubs/path.js:
--------------------------------------------------------------------------------
1 | const {path} = require('filer');
2 |
3 | module.exports = path;
4 |
--------------------------------------------------------------------------------
/@docs/website/compiler/stubs/sync-rpc.js:
--------------------------------------------------------------------------------
1 | const transformWorker = require('@taddy/babel-plugin/src/helpers/evaluate.worker.cjs');
2 |
3 | module.exports = () => transformWorker();
4 |
--------------------------------------------------------------------------------
/@docs/website/components/BaseLink.tsx:
--------------------------------------------------------------------------------
1 | import type {PropsWithChildren, CSSProperties} from 'react';
2 |
3 | import NextLink from 'next/link';
4 | import {useRouter} from 'next/router';
5 |
6 | export const Link = ({
7 | href,
8 | ...props
9 | }: PropsWithChildren<{
10 | href: string;
11 | style?: CSSProperties;
12 | className?: string;
13 | }>) => {
14 | const router = useRouter();
15 | const currentPage = router.pathname === href;
16 | return (
17 |
22 | );
23 | };
24 |
--------------------------------------------------------------------------------
/@docs/website/components/Link.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {css} from 'taddy';
3 |
4 | import {Link as BaseLink} from './BaseLink';
5 |
6 | export const Link = ({
7 | href,
8 | className,
9 | style,
10 | children,
11 | }: {
12 | href: string;
13 | style?: object;
14 | className?: string;
15 | children: React.ReactNode;
16 | }) => {
17 | return (
18 |
29 | {children}
30 |
31 | );
32 | };
33 |
--------------------------------------------------------------------------------
/@docs/website/components/LinkButton.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {css} from 'taddy';
3 |
4 | import {Link} from './BaseLink';
5 |
6 | const styles = {
7 | _variant: {
8 | normal: css({
9 | color: 'violet',
10 | background: 'none',
11 | }),
12 | action: css({
13 | color: 'white',
14 | background: 'violet',
15 | }),
16 | pseudo: css({
17 | color: 'violet',
18 | borderColor: 'transparent',
19 | }),
20 | },
21 | };
22 |
23 | export const LinkButton = ({
24 | href,
25 | variant = 'normal',
26 | className,
27 | style,
28 | children,
29 | }: {
30 | href: string;
31 | variant?: string;
32 | style?: object;
33 | className?: string;
34 | children: React.ReactNode;
35 | }) => {
36 | return (
37 |
52 | {children}
53 |
54 | );
55 | };
56 |
--------------------------------------------------------------------------------
/@docs/website/components/Sidebar/styles.module.css:
--------------------------------------------------------------------------------
1 | .burger {
2 | position: absolute;
3 | display: none;
4 | flex-direction: column;
5 | justify-content: space-between;
6 | height: 20px;
7 | z-index: 11;
8 | color: #333;
9 | }
10 |
11 | .input {
12 | position: absolute;
13 | display: none;
14 | margin: 0;
15 | width: 40px;
16 | height: 40px;
17 | opacity: 0;
18 | z-index: 12;
19 | cursor: pointer;
20 | }
21 |
22 | .burger,
23 | .input {
24 | top: 15px;
25 | left: 50%;
26 | transform: translateX(-50%);
27 | }
28 |
29 | .burger span {
30 | display: inline-block;
31 | width: 40px;
32 | height: 4px;
33 | background-color: currentColor;
34 | border-radius: 4px;
35 | }
36 |
37 | @media screen and (max-width: 900px) {
38 | .content {
39 | margin-top: 10px;
40 | }
41 |
42 | .burger {
43 | display: flex;
44 | }
45 |
46 | .input {
47 | display: block;
48 | }
49 |
50 | .input:checked ~ .menu {
51 | display: inline-flex;
52 | justify-content: center;
53 | }
54 |
55 | .input:checked ~ .burger {
56 | color: black;
57 | justify-content: flex-end;
58 | }
59 |
60 | .input:checked ~ .burger span {
61 | transform: rotate(45deg);
62 | }
63 |
64 | .input:checked ~ .burger span:first-child {
65 | display: none;
66 | }
67 |
68 | .input:checked ~ .burger span:last-child {
69 | transform: translate(-1px, -5px) rotate(-45deg);
70 | }
71 |
72 | .menu {
73 | display: none;
74 | position: absolute;
75 | width: 100%;
76 | height: 100%;
77 | z-index: 2;
78 | background: rgba(243 240 243 / 95%);
79 | font-size: 30px;
80 | z-index: 10;
81 | padding-top: 60px;
82 | }
83 | }
84 |
85 | .content {
86 | max-width: 100vw;
87 | }
88 |
--------------------------------------------------------------------------------
/@docs/website/components/layout.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import {css} from 'taddy';
4 |
5 | const size = (v: number) => `${v * 4}px`;
6 | const margin = (gapY: number, gapX: number) =>
7 | `${size(gapY / 2)} ${size(gapX / 2)}`;
8 |
9 | function flex({inline}) {
10 | return css({
11 | display: inline ? 'inline-flex' : 'flex',
12 |
13 | ...(!inline && {
14 | flex: 1,
15 | maxWidth: '100%',
16 |
17 | '> *': {
18 | flex: 1,
19 | maxWidth: '100%',
20 | },
21 | }),
22 | });
23 | }
24 |
25 | type Size = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
26 |
27 | export function row({
28 | gap = 0,
29 | gapY = gap,
30 | gapX = gap,
31 | inline = false,
32 | }: {
33 | gap?: Size;
34 | gapY?: Size;
35 | gapX?: Size;
36 | inline?: boolean;
37 | wrap?: any;
38 | } = {}) {
39 | return css({
40 | ...flex({inline}),
41 |
42 | flexDirection: 'row',
43 |
44 | margin: margin(-gapY, -gapX),
45 |
46 | ...(!inline && {
47 | width: `calc(100% + ${size(gapX)})`,
48 | }),
49 |
50 | '> *:not(:empty)': {
51 | display: 'flex',
52 | margin: margin(gapY, gapX),
53 | },
54 | });
55 | }
56 |
57 | export function column({
58 | gap = 0,
59 | inline = false,
60 | }: {gap?: Size; gapY?: Size; gapX?: Size; inline?: boolean} = {}) {
61 | return css({
62 | ...flex({inline}),
63 |
64 | flexDirection: 'column',
65 |
66 | '> *:not(:empty) + *:not(:empty)': {
67 | display: 'flex',
68 | marginTop: size(gap),
69 | },
70 | });
71 | }
72 |
73 | function shouldWrap(child) {
74 | return !(child == undefined || !!child.type.__unit__);
75 | }
76 |
77 | function wrapChildren(children) {
78 | return React.Children.map(children, (child) =>
79 | shouldWrap(child) ?
{child}
: child,
80 | );
81 | }
82 |
83 | export const Column = ({
84 | as: Tag = 'div',
85 | gap,
86 | inline,
87 | style,
88 | className,
89 | children,
90 | ...props
91 | }: Partial<{
92 | as: keyof JSX.IntrinsicElements;
93 | gap: Size;
94 | inline: boolean;
95 | className?: string;
96 | style?: object;
97 | children: React.ReactNode;
98 | }>) => (
99 |
100 | {wrapChildren(children)}
101 |
102 | );
103 |
104 | export const Row = ({
105 | as: Tag = 'div',
106 | gap = 0,
107 | gapY = gap,
108 | gapX = gap,
109 | inline = false,
110 | style,
111 | className,
112 | children,
113 | ...props
114 | }: Partial<{
115 | as: keyof JSX.IntrinsicElements;
116 | gap: Size;
117 | gapY: Size;
118 | gapX: Size;
119 | inline: boolean;
120 | className?: string;
121 | style?: object;
122 | children: React.ReactNode;
123 | wrap?: string;
124 | }>) => (
125 |
136 |
145 | {wrapChildren(children)}
146 |
147 |
148 | );
149 |
--------------------------------------------------------------------------------
/@docs/website/components/playground/CompiledCode.tsx:
--------------------------------------------------------------------------------
1 | import {css} from 'taddy';
2 |
3 | import {useAtom} from '@reatom/react';
4 | import type {PropsWithChildren} from 'react';
5 |
6 | import {Column, Row} from '../layout';
7 | import {transformAtom} from './atoms';
8 | import {Editor} from './Editor';
9 | import {EditorLayer} from './EditorLayer';
10 | import {ReactRender} from './ReactRender';
11 |
12 | const Title = ({children}: PropsWithChildren) => {children}
;
13 |
14 | const Wrapper = ({children}: PropsWithChildren) => (
15 |
26 | {children}
27 |
28 | );
29 |
30 | export const CompiledCode = ({
31 | showCompiledCode,
32 | showCompiledCSS,
33 | showRender,
34 | }: {
35 | showCompiledCode?: boolean;
36 | showCompiledCSS?: boolean;
37 | showRender?: boolean;
38 | }) => {
39 | const data = useAtom(transformAtom);
40 |
41 | let layerProps: React.ComponentProps = {};
42 |
43 | if (data.status === 'error') {
44 | layerProps = {variant: 'error', children: data.error.toString()};
45 | } else if (data.status === 'pending') {
46 | layerProps = {variant: 'compiling', children: 'Compiling...'};
47 | }
48 |
49 | const content = (
50 |
60 | {showRender && (
61 |
62 | Render
63 |
64 |
65 |
66 | )}
67 |
68 | {showCompiledCode && (
69 |
70 | Compiled Module
71 |
72 |
79 |
80 | )}
81 |
82 | {showCompiledCSS && (
83 |
84 | Compiled CSS
85 |
86 |
94 |
95 | )}
96 |
97 | );
98 |
99 | return (
100 |
106 | {content}
107 |
108 |
109 |
110 | );
111 | };
112 |
--------------------------------------------------------------------------------
/@docs/website/components/playground/Editor.tsx:
--------------------------------------------------------------------------------
1 | import dynamic from 'next/dynamic';
2 |
3 | import * as React from 'react';
4 | import type {ComponentProps} from 'react';
5 |
6 | import {css} from 'taddy';
7 |
8 | // @see https://github.com/securingsincity/react-ace/issues/725
9 | const AceEditor = dynamic(
10 | async () => {
11 | const reactAce = await import('react-ace');
12 |
13 | await Promise.all([
14 | // prevent warning in console about misspelled props name.
15 | import('ace-builds/src-min-noconflict/ext-language_tools'),
16 | import('ace-builds/src-min-noconflict/ext-beautify'),
17 |
18 | import('ace-builds/src-min-noconflict/mode-typescript'),
19 | import('ace-builds/src-min-noconflict/mode-tsx'),
20 | import('ace-builds/src-min-noconflict/mode-css'),
21 |
22 | import('ace-builds/src-min-noconflict/theme-textmate'),
23 | ]);
24 |
25 | // await import('ace-builds/src-min-noconflict/ext-language_tools');
26 | // await import('ace-builds/src-min-noconflict/ext-beautify');
27 |
28 | // // import your theme/mode here.
29 | // await import('ace-builds/src-min-noconflict/mode-typescript');
30 | // await import('ace-builds/src-min-noconflict/mode-css');
31 | // await import('ace-builds/src-min-noconflict/theme-textmate');
32 |
33 | // as @Holgrabus commented you can paste these file into your /public folder.
34 | // You will have to set basePath and setModuleUrl accordingly.
35 | // eslint-disable-next-line @typescript-eslint/no-var-requires
36 | const ace = require('ace-builds/src-min-noconflict/ace');
37 | ace.config.set(
38 | 'basePath',
39 | 'https://cdn.jsdelivr.net/npm/ace-builds@1.16.0/src-noconflict/',
40 | );
41 | ace.config.setModuleUrl(
42 | 'ace/mode/javascript_worker',
43 | 'https://cdn.jsdelivr.net/npm/ace-builds@1.16.0/src-noconflict/worker-javascript.js',
44 | );
45 |
46 | return reactAce;
47 | },
48 | {
49 | ssr: false, // react-ace doesn't support server side rendering as it uses the window object.
50 | loading: () => Loading...
,
51 | },
52 | );
53 |
54 | export const Editor = ({
55 | className,
56 | style,
57 | ...props
58 | }: ComponentProps) => (
59 |
81 | );
82 |
--------------------------------------------------------------------------------
/@docs/website/components/playground/EditorLayer.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import {css} from 'taddy';
4 |
5 | const styles = {
6 | base: css({
7 | position: 'absolute',
8 | left: 0,
9 | top: 0,
10 | width: '100%',
11 | height: '100%',
12 | whiteSpace: 'pre',
13 | zIndex: 5,
14 | padding: '20px',
15 | fontSize: '14px',
16 | overflowX: 'scroll',
17 | fontFamily: 'monospace',
18 | fontWeight: 'bold',
19 | textAlign: 'left',
20 | }),
21 | _variant: {
22 | compiling: css({
23 | background: 'rgba(255 255 255 / 95%)',
24 | color: 'black',
25 | }),
26 | error: css({
27 | background: 'rgba(2 10 10 / 80%)',
28 | color: 'white',
29 | }),
30 | },
31 | _animated: css({
32 | transitionProperty: 'opacity',
33 | transitionDuration: '150ms',
34 | }),
35 | _hidden: css({opacity: 0, zIndex: -1}),
36 | };
37 |
38 | export const EditorLayer = ({
39 | children,
40 | variant,
41 | className,
42 | }: {
43 | children?: React.ReactNode;
44 | variant?: keyof typeof styles._variant;
45 | className?: string;
46 | }) => {
47 | return (
48 |
56 | {children}
57 |
58 | );
59 | };
60 |
--------------------------------------------------------------------------------
/@docs/website/components/playground/LiveEditor.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {useAction, useAtom} from '@reatom/react';
3 |
4 | import {css, $} from 'taddy';
5 |
6 | import {stripIndent} from 'common-tags';
7 |
8 | import {useCode} from '../../utils/code';
9 | import {playgroundAtom, updatePlayground} from './atoms';
10 | import {Editor} from './Editor';
11 |
12 | export const LiveEditor = ({
13 | initialCode,
14 | persistent,
15 | }: {
16 | initialCode?: string;
17 | persistent?: boolean;
18 | }) => {
19 | const code = useAtom(playgroundAtom, (x) => x.code, ['code']);
20 | const storageCode = useCode(persistent ? code : null);
21 |
22 | const handleCode = useAction((code) => {
23 | return updatePlayground({code});
24 | });
25 |
26 | React.useEffect(() => {
27 | setTimeout(() => {
28 | handleCode(storageCode || stripIndent(initialCode) + '\n');
29 | }, 0);
30 | }, []);
31 |
32 | return (
33 |
34 |
Code
35 |
36 |
69 |
70 | );
71 | };
72 |
--------------------------------------------------------------------------------
/@docs/website/components/playground/Options.tsx:
--------------------------------------------------------------------------------
1 | import {css} from 'taddy';
2 | import {useAtom, useAction} from '@reatom/react';
3 |
4 | import {Column, Row} from '../layout';
5 |
6 | import {playgroundAtom, updatePlayground} from './atoms';
7 |
8 | export const Options = () => {
9 | const options = useAtom(playgroundAtom, (x) => x.options, ['options']);
10 | const handleOption = useAction((e) => {
11 | return updatePlayground({
12 | // @ts-expect-error expected partial options
13 | options: {[e.target.name]: !!e.target.checked},
14 | });
15 | });
16 |
17 | const compileOptionsDisabled = !options.taddy;
18 |
19 | return (
20 |
21 |
30 |
31 |
32 |
33 | Compile Options:
34 |
35 |
36 |
46 |
47 |
57 |
58 |
68 |
69 |
70 | );
71 | };
72 |
--------------------------------------------------------------------------------
/@docs/website/components/playground/atoms.ts:
--------------------------------------------------------------------------------
1 | import {declareAction, declareAtom} from '@reatom/core';
2 |
3 | import {stripIndent} from 'common-tags';
4 |
5 | type Playground = {
6 | options: {
7 | taddy: true;
8 | evaluate: boolean;
9 | unstable_typescript: boolean;
10 | unstable_CSSVariableFallback: boolean;
11 | unstable_useTaggedTemplateLiterals: boolean;
12 | };
13 | code: string;
14 | };
15 |
16 | export const updatePlayground = declareAction>(
17 | async (payload, store) => {
18 | const {code: source, options} = store.getState(playgroundAtom);
19 |
20 | store.dispatch(setTransformedCode({status: 'pending'}));
21 |
22 | if (!options.taddy) {
23 | store.dispatch(
24 | setTransformedCode({
25 | status: 'done',
26 | result: {code: source, css: ''},
27 | }),
28 | );
29 |
30 | return;
31 | }
32 |
33 | const transformCode = await import('../../compiler').then(
34 | (x) => x.transformCode,
35 | );
36 |
37 | transformCode(source, options)
38 | .then((result) => {
39 | store.dispatch(setTransformedCode({status: 'done', result}));
40 | })
41 | .catch((error) => {
42 | console.error(error);
43 |
44 | store.dispatch(
45 | setTransformedCode({
46 | status: 'error',
47 | error,
48 | }),
49 | );
50 | });
51 | },
52 | );
53 | export const playgroundAtom = declareAtom(
54 | {
55 | code: '',
56 | options: {
57 | taddy: true,
58 | unstable_typescript: true,
59 | evaluate: true,
60 | unstable_CSSVariableFallback: true,
61 | unstable_useTaggedTemplateLiterals: true,
62 | },
63 | },
64 | (on) => [
65 | on(updatePlayground, (state, payload) => ({
66 | ...state,
67 | ...payload,
68 | options: {
69 | ...state.options,
70 | ...payload.options,
71 | },
72 | })),
73 | ],
74 | );
75 |
76 | export type CompiledData = {result?: {code: string; css: string}} & (
77 | | {status: 'pending'}
78 | | {status: 'done'}
79 | | {error: Error; status: 'error'}
80 | );
81 |
82 | export const setTransformedCode = declareAction();
83 | export const transformAtom = declareAtom(
84 | {status: 'done', result: {code: '', css: ''}},
85 | (on) => [
86 | on(setTransformedCode, (state, payload) => ({...state, ...payload})),
87 | ],
88 | );
89 |
--------------------------------------------------------------------------------
/@docs/website/components/playground/index.tsx:
--------------------------------------------------------------------------------
1 | import Head from 'next/head';
2 |
3 | import {css} from 'taddy';
4 |
5 | import {Column, Row} from '../layout';
6 |
7 | import {LiveEditor} from './LiveEditor';
8 | import {Options} from './Options';
9 | import {CompiledCode} from './CompiledCode';
10 |
11 | import {createStore} from '@reatom/core';
12 | import {context} from '@reatom/react';
13 |
14 | export default function Playground({
15 | initialCode,
16 | showOptions,
17 | showCompiledCode,
18 | showCompiledCSS,
19 | showRender,
20 | persistent,
21 | }: {
22 | initialCode?: string;
23 | showOptions?: boolean;
24 | showCompiledCode?: boolean;
25 | showCompiledCSS?: boolean;
26 | showRender?: boolean;
27 | persistent?: boolean;
28 | }) {
29 | const store = createStore();
30 |
31 | return (
32 |
33 |
34 |
35 |
39 |
40 |
41 |
42 | {showOptions && }
43 |
44 |
45 |
49 |
50 |
53 |
54 |
55 |
56 |
57 | );
58 | }
59 |
--------------------------------------------------------------------------------
/@docs/website/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/@docs/website/next.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const withMDX = require('@next/mdx');
3 | const withTaddy = require('@taddy/next-plugin');
4 |
5 | /** @type {import('next').NextConfig} */
6 | const config = {
7 | transpilePackages: ['@taddy/babel-plugin', '@taddy/core', 'taddy'],
8 |
9 | pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
10 |
11 | webpack(config) {
12 | Object.assign(config.resolve.alias, {
13 | fs: require.resolve('./compiler/stubs/fs'),
14 | path: 'path-browserify',
15 | module: require.resolve('./compiler/stubs/module'),
16 | 'sync-rpc': require.resolve('./compiler/stubs/sync-rpc'),
17 | });
18 |
19 | // config.plugins.push(
20 | // new webpack.ContextReplacementPlugin(
21 | // /\/filer\/|\/ts-morph\/|babel\/standalone/,
22 | // (data) => {
23 | // delete data.dependencies[0].critical;
24 | // return data;
25 | // },
26 | // ),
27 | // );
28 |
29 | // handle "node:assert" etc.
30 | config.plugins.push(
31 | new webpack.NormalModuleReplacementPlugin(/^node:/, (resource) => {
32 | resource.request = resource.request.replace(/^node:/, '');
33 | }),
34 | );
35 |
36 | config.externals.push({
37 | typescript: 'window.ts',
38 | });
39 |
40 | config.module = {
41 | ...config.module,
42 | // there are some packages like "@babel/standalone", "ts-morph" and "filer" that use require
43 | // @see https://github.com/babel/babel/issues/14301
44 | exprContextCritical: false,
45 | };
46 |
47 | return config;
48 | },
49 |
50 | typescript: {
51 | ignoreBuildErrors: true,
52 | },
53 |
54 | eslint: {
55 | ignoreDuringBuilds: true,
56 | },
57 | };
58 |
59 | module.exports = withTaddy()(
60 | withMDX({
61 | extension: /\.mdx?$/,
62 | })(config),
63 | );
64 |
--------------------------------------------------------------------------------
/@docs/website/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "@docs/website",
4 | "description": "taddy documentation website",
5 | "version": "0.0.0",
6 | "scripts": {
7 | "dev": "next dev",
8 | "build": "next build",
9 | "start": "next start"
10 | },
11 | "dependencies": {
12 | "@babel/preset-react": "^7.18.6",
13 | "@babel/preset-typescript": "^7.21.5",
14 | "@babel/standalone": "^7.21.2",
15 | "@mdx-js/react": "2.3.0",
16 | "@reatom/core": "1.1.5",
17 | "@reatom/react": "1.1.5",
18 | "@taddy/babel-plugin": "^0.1.0-alpha.0",
19 | "@taddy/next-plugin": "^0.1.0-alpha.0",
20 | "filer": "1.4.1",
21 | "history": "5.3.0",
22 | "lz-string": "1.5.0",
23 | "next": "13.2.4",
24 | "path-browserify": "^1.0.1",
25 | "postcss-js": "4.0.1",
26 | "prettier": "2.8.4",
27 | "qhistory": "1.1.0",
28 | "qs": "6.11.1",
29 | "react": "18.2.0",
30 | "react-ace": "10.1.0",
31 | "react-dom": "18.2.0",
32 | "sharp": "^0.31.3",
33 | "taddy": "^0.1.0-alpha.0"
34 | },
35 | "devDependencies": {
36 | "@mdx-js/loader": "^2.3.0",
37 | "@next/mdx": "^13.2.4",
38 | "@types/babel__standalone": "^7.1.4",
39 | "@types/node": "^18.15.0",
40 | "@types/react": "^18.0.28",
41 | "imagemin-svgo": "^10.0.1",
42 | "next-compose-plugins": "2.2.1",
43 | "svg-sprite-loader": "^6.0.11",
44 | "webpack": "^5.76.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/@docs/website/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import Head from 'next/head';
2 |
3 | import '@docs/website/styles/globals.css';
4 | import '@docs/website/styles/reset.css';
5 |
6 | // import '@taddy/babel-plugin/.cache';
7 | // import '@taddy/babel-plugin/.cache/index.css';
8 |
9 | import {css} from 'taddy';
10 |
11 | import {MDXProvider} from '@mdx-js/react';
12 |
13 | import {createStore} from '@reatom/core';
14 | import {context} from '@reatom/react';
15 |
16 | import {Sidebar} from '@docs/website/components/Sidebar/index';
17 | import sidebarStyles from '@docs/website/components/Sidebar/styles.module.css';
18 |
19 | import {Link} from '@docs/website/components/Link';
20 | import {AppProps} from 'next/app';
21 |
22 | import ico from '@docs/website/public/favicon.ico';
23 |
24 | const store = createStore();
25 |
26 | const components = {
27 | a: (props) => ,
28 | pre: (props) => ,
29 | code: ({...props}) =>
,
30 | inlineCode: ({className, ...props}) => (
31 |
43 | ),
44 | };
45 |
46 | function MyApp({Component, pageProps, router}: AppProps) {
47 | const name = router.pathname.slice(1);
48 | const title = 'taddy' + (name ? ' | ' + name : '');
49 |
50 | return (
51 |
52 |
53 |
54 |
55 |
59 |
60 |
61 |
62 |
{title}
63 |
64 |
65 |
88 |
89 |
90 |
91 | );
92 | }
93 |
94 | export default MyApp;
95 |
--------------------------------------------------------------------------------
/@docs/website/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import {css} from 'taddy';
2 |
3 | import {Link} from '@docs/website/components/BaseLink';
4 | import {Row, Column} from '@docs/website/components/layout';
5 | import {LinkButton} from '@docs/website/components/LinkButton';
6 |
7 | import logo1Image from '@docs/website/public/logo/taddy1.png';
8 | import logo11Image from '@docs/website/public/logo/taddy11.png';
9 |
10 | export default function Home() {
11 | return (
12 |
24 |
25 |
26 |
27 | {/* */}
43 |
44 |
45 |
52 |
57 | Get Started
58 |
59 |
60 |
61 | Playground
62 |
63 |
64 |
65 | );
66 | }
67 |
68 | const Logos = () => {
69 | const transition = css.mixin({
70 | transitionProperty: 'opacity',
71 | transitionDuration: '500ms',
72 | });
73 |
74 | const second = css({
75 | ...transition,
76 |
77 | position: 'absolute',
78 | width: '100%',
79 | height: '100%',
80 | top: 0,
81 | left: 0,
82 | opacity: 0,
83 | });
84 | const first = css({
85 | ...transition,
86 | });
87 |
88 | return (
89 |
103 |
109 |

115 |
116 |

122 |
123 |
124 |
130 | taddy
131 |
132 |
133 | );
134 | };
135 |
--------------------------------------------------------------------------------
/@docs/website/pages/playground/index.tsx:
--------------------------------------------------------------------------------
1 | import dynamic from 'next/dynamic';
2 |
3 | import {css} from 'taddy';
4 |
5 | import {Column} from '@docs/website/components/layout';
6 |
7 | const Playground = dynamic(
8 | () => import('@docs/website/components/playground'),
9 | {
10 | ssr: false,
11 | loading: () => loading ...
,
12 | },
13 | );
14 |
15 | export default function PlaygroundPage() {
16 | return (
17 |
18 |
25 |
Playground
26 |
27 |
41 | Hello, world!
42 |
43 | )
44 | `}
45 | />
46 |
47 |
48 | );
49 | }
50 |
--------------------------------------------------------------------------------
/@docs/website/pages/roadmap.md:
--------------------------------------------------------------------------------
1 | ../../../ROADMAP.md
--------------------------------------------------------------------------------
/@docs/website/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@docs/website/public/favicon.ico
--------------------------------------------------------------------------------
/@docs/website/public/logo/taddy1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@docs/website/public/logo/taddy1.png
--------------------------------------------------------------------------------
/@docs/website/public/logo/taddy11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@docs/website/public/logo/taddy11.png
--------------------------------------------------------------------------------
/@docs/website/public/logo/taddy2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@docs/website/public/logo/taddy2.png
--------------------------------------------------------------------------------
/@docs/website/public/logo/taddy9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@docs/website/public/logo/taddy9.png
--------------------------------------------------------------------------------
/@docs/website/styles/globals.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
7 | }
8 |
9 | a {
10 | color: inherit;
11 | text-decoration: none;
12 | }
13 |
14 | * {
15 | box-sizing: border-box;
16 | }
17 |
18 | html,
19 | body {
20 | /* background: #fafafa; */
21 | height: 100%;
22 | color: #333;
23 | width: 100vw;
24 | overflow-x: hidden;
25 | }
26 |
27 | use {
28 | stroke: violet !important;
29 | }
30 |
31 | svg * {
32 | all: inherit;
33 | }
34 |
35 | li + li,
36 | li > ul {
37 | margin-top: 10px;
38 | }
39 |
--------------------------------------------------------------------------------
/@docs/website/styles/index.ts:
--------------------------------------------------------------------------------
1 | export const COLORS = {
2 | base0: 'violet',
3 | base1: 'darkslateblue',
4 | base2: 'royalblue',
5 | base3: 'cornflowerblue',
6 | base4: 'white',
7 | };
8 |
--------------------------------------------------------------------------------
/@docs/website/styles/mixins.ts:
--------------------------------------------------------------------------------
1 | import {$, css} from 'taddy';
2 |
3 | const size = (v: number) => `${v * 4}px`;
4 |
5 | export const row = ({gap = 0, gapY = gap, gapX = gap, inline = false} = {}) =>
6 | css.mixin({
7 | display: 'flex',
8 | flexDirection: 'row',
9 |
10 | margin: `${size(-gapY / 2)} ${size(-gapX / 2)}`,
11 |
12 | [$`> *:not(:empty)`]: {
13 | margin: `${size(gapY / 2)} ${size(gapX / 2)}`,
14 | },
15 |
16 | ...(!inline && {
17 | flex: '1',
18 | width: `calc(100% + ${size(gapX)})`,
19 |
20 | [$`> *`]: {
21 | flex: '1',
22 | },
23 | }),
24 | });
25 |
26 | export const column = ({gap = 0, inline = false} = {}) =>
27 | css.mixin({
28 | display: 'flex',
29 | flexDirection: 'column',
30 |
31 | [$`> *:not(:empty) + *:not(:empty)`]: {
32 | marginTop: size(gap),
33 | },
34 |
35 | ...(!inline && {
36 | flex: '1',
37 |
38 | [$`> *`]: {
39 | flex: '1',
40 | },
41 | }),
42 | });
43 |
--------------------------------------------------------------------------------
/@docs/website/styles/reset.css:
--------------------------------------------------------------------------------
1 | /***
2 | The new CSS reset - version 1.8.4 (last updated 14.2.2023)
3 | GitHub page: https://github.com/elad2412/the-new-css-reset
4 | ***/
5 |
6 | /*
7 | Remove all the styles of the "User-Agent-Stylesheet", except for the 'display' property
8 | - The "symbol *" part is to solve Firefox SVG sprite bug
9 | */
10 | *:where(
11 | :not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)
12 | ) {
13 | margin: 0;
14 | }
15 |
16 | /* Preferred box-sizing value */
17 | *,
18 | *::before,
19 | *::after {
20 | box-sizing: border-box;
21 | }
22 |
23 | /* Remove default margin */
24 | body,
25 | h1,
26 | h2,
27 | h3,
28 | h4,
29 | p,
30 | figure,
31 | blockquote,
32 | dl,
33 | dd {
34 | margin: 0;
35 | }
36 |
37 | /* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */
38 | ul[role='list'],
39 | ol[role='list'] {
40 | list-style: none;
41 | }
42 |
43 | /* Set core root defaults */
44 | html:focus-within {
45 | scroll-behavior: smooth;
46 | }
47 |
48 | /* Set core body defaults */
49 | body {
50 | min-height: 100vh;
51 | text-rendering: optimizeSpeed;
52 | line-height: 1.5;
53 | }
54 |
55 | /* A elements that don't have a class get default styles */
56 | a:not([class]) {
57 | text-decoration-skip-ink: auto;
58 | }
59 |
60 | /* Make images easier to work with */
61 | img,
62 | picture {
63 | max-width: 100%;
64 | display: block;
65 | }
66 |
67 | /* Inherit fonts for inputs and buttons */
68 | input,
69 | button,
70 | textarea,
71 | select {
72 | font: inherit;
73 | }
74 |
75 | /* Remove all animations, transitions and smooth scroll for people that prefer not to see them */
76 | @media (prefers-reduced-motion: reduce) {
77 | html:focus-within {
78 | scroll-behavior: auto;
79 | }
80 |
81 | *,
82 | *::before,
83 | *::after {
84 | animation-duration: 0.01ms !important;
85 | animation-iteration-count: 1 !important;
86 | transition-duration: 0.01ms !important;
87 | scroll-behavior: auto !important;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/@docs/website/taddy-plugin.js:
--------------------------------------------------------------------------------
1 | module.exports =
2 | (pluginOptions = {}) =>
3 | (nextConfig = {}) => {
4 | const extension = pluginOptions.extension || /\.mdx$/;
5 |
6 | return Object.assign({}, nextConfig, {
7 | webpack(config, options) {
8 | config.module.rules.push({
9 | test: /@taddy\/babel-plugin.*\.css/,
10 | use: [],
11 | });
12 |
13 | if (typeof nextConfig.webpack === 'function') {
14 | return nextConfig.webpack(config, options);
15 | }
16 |
17 | return config;
18 | },
19 | });
20 | };
21 |
--------------------------------------------------------------------------------
/@docs/website/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "target": "es5",
5 | "lib": ["dom", "dom.iterable", "esnext"],
6 | "allowJs": true,
7 | "skipLibCheck": true,
8 | "strict": false,
9 | "forceConsistentCasingInFileNames": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "baseUrl": ".",
17 | "noEmit": true
18 | },
19 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
20 | "exclude": ["node_modules"]
21 | }
22 |
--------------------------------------------------------------------------------
/@docs/website/utils/code.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import LZString from 'lz-string';
3 | import history from './history';
4 |
5 | const NEWLINE = '❤';
6 |
7 | export const encode = (value) =>
8 | LZString.compressToEncodedURIComponent(
9 | value.replace(/\n/g, NEWLINE).replace(/\s/g, ' '),
10 | );
11 | export const decode = (value) =>
12 | LZString.decompressFromEncodedURIComponent(value).replace(
13 | new RegExp(NEWLINE, 'g'),
14 | '\n',
15 | );
16 |
17 | class CodeHandler {
18 | value: string;
19 | timerId: any;
20 |
21 | constructor(initial) {
22 | this.value = decode(initial);
23 | }
24 |
25 | getHash = () => {
26 | return encode(this.value);
27 | };
28 |
29 | onChange = (code) => {
30 | this.value = code;
31 | };
32 |
33 | updateCodeLink = () => {
34 | if (!this.value) return;
35 |
36 | history.replace({
37 | pathname: globalThis.location.pathname,
38 | query: {
39 | ...history.location.query,
40 | code: this.getHash(),
41 | },
42 | });
43 | };
44 |
45 | scheduleLinkUpdate(timeout = 1000) {
46 | if (this.timerId) {
47 | clearTimeout(this.timerId);
48 | }
49 |
50 | this.timerId = setTimeout(this.updateCodeLink, timeout);
51 | }
52 | }
53 |
54 | export const code = new CodeHandler(history.location.query.code);
55 |
56 | export const useCode = (value?: string | null): string => {
57 | React.useEffect(() => {
58 | if (value === null) return;
59 |
60 | code.onChange(value);
61 |
62 | code.scheduleLinkUpdate();
63 | }, [value]);
64 |
65 | /**
66 | * Code will subscribe only if there is an initial code
67 | */
68 | React.useEffect(() => {
69 | if (value === null) return;
70 |
71 | window.addEventListener('blur', code.updateCodeLink);
72 |
73 | return () => {
74 | window.removeEventListener('blur', code.updateCodeLink);
75 | };
76 | }, []);
77 |
78 | return code.value;
79 | };
80 |
--------------------------------------------------------------------------------
/@docs/website/utils/history.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {createBrowserHistory, createMemoryHistory} from 'history';
3 | import type {History, State, To} from 'history';
4 | import qhistory from 'qhistory';
5 | import {stringify, parse} from 'qs';
6 |
7 | type QueryParams = object & {code: string};
8 |
9 | type QueryOptions = {
10 | query: QueryParams;
11 | };
12 |
13 | type QTo = To & QueryOptions;
14 |
15 | interface QHistory extends History {
16 | replace(to: QTo, state?: State): ReturnType;
17 | location: History['location'] & QueryOptions;
18 | }
19 |
20 | const history = qhistory(
21 | typeof window === 'undefined'
22 | ? createMemoryHistory()
23 | : createBrowserHistory(),
24 | stringify,
25 | parse,
26 | ) as QHistory;
27 |
28 | export const Location = ({children}) => {
29 | const [state, setState] = React.useState({history});
30 |
31 | history.listen(() => {
32 | setState({history});
33 | });
34 |
35 | return children(state.history);
36 | };
37 |
38 | export default history;
39 |
--------------------------------------------------------------------------------
/@docs/website/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 2,
3 | "alias": ["taddy.dev", "taddy"]
4 | }
5 |
--------------------------------------------------------------------------------
/@examples/astro/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 |
4 | # generated types
5 | .astro/
6 |
7 | # dependencies
8 | node_modules/
9 |
10 | # logs
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # environment variables
17 | .env
18 | .env.production
19 |
20 | # macOS-specific files
21 | .DS_Store
22 |
--------------------------------------------------------------------------------
/@examples/astro/README.md:
--------------------------------------------------------------------------------
1 | # Astro Starter Kit: Basics
2 |
3 | ```
4 | npm create astro@latest -- --template basics
5 | ```
6 |
7 | [](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
8 | [](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
9 | [](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
10 |
11 | > 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
12 |
13 | 
14 |
15 |
16 | ## 🚀 Project Structure
17 |
18 | Inside of your Astro project, you'll see the following folders and files:
19 |
20 | ```
21 | /
22 | ├── public/
23 | │ └── favicon.svg
24 | ├── src/
25 | │ ├── components/
26 | │ │ └── Card.astro
27 | │ ├── layouts/
28 | │ │ └── Layout.astro
29 | │ └── pages/
30 | │ └── index.astro
31 | └── package.json
32 | ```
33 |
34 | Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
35 |
36 | There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
37 |
38 | Any static assets, like images, can be placed in the `public/` directory.
39 |
40 | ## 🧞 Commands
41 |
42 | All commands are run from the root of the project, from a terminal:
43 |
44 | | Command | Action |
45 | | :--------------------- | :----------------------------------------------- |
46 | | `npm install` | Installs dependencies |
47 | | `npm run dev` | Starts local dev server at `localhost:3000` |
48 | | `npm run build` | Build your production site to `./dist/` |
49 | | `npm run preview` | Preview your build locally, before deploying |
50 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
51 | | `npm run astro --help` | Get help using the Astro CLI |
52 |
53 | ## 👀 Want to learn more?
54 |
55 | Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
56 |
--------------------------------------------------------------------------------
/@examples/astro/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import taddy from '@taddy/vite-plugin';
2 | import {defineConfig} from 'astro/config';
3 |
4 | // https://astro.build/config
5 | export default defineConfig({
6 | vite: {
7 | plugins: [taddy()],
8 | },
9 | });
10 |
--------------------------------------------------------------------------------
/@examples/astro/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "@examples/astro",
4 | "version": "0.0.1",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "astro dev",
8 | "start": "astro dev",
9 | "build": "astro build",
10 | "preview": "astro preview",
11 | "astro": "astro"
12 | },
13 | "dependencies": {
14 | "astro": "^2.0.18",
15 | "taddy": "^0.1.0-alpha.0"
16 | },
17 | "devDependencies": {
18 | "@taddy/vite-plugin": "^0.1.0-alpha.0"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/@examples/astro/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/@examples/astro/src/components/Card.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import {css} from 'taddy';
3 |
4 | export interface Props {
5 | title: string;
6 | body: string;
7 | href: string;
8 | }
9 |
10 | const {href, title, body} = Astro.props;
11 | ---
12 |
13 |
14 |
15 | test
16 |
17 | {title}
18 | →
19 |
20 |
21 | {body}
22 |
23 |
24 |
25 |
68 |
--------------------------------------------------------------------------------
/@examples/astro/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/@examples/astro/src/layouts/Layout.astro:
--------------------------------------------------------------------------------
1 | ---
2 | export interface Props {
3 | title: string;
4 | }
5 |
6 | const { title } = Astro.props;
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {title}
17 |
18 |
19 |
20 |
21 |
22 |
36 |
--------------------------------------------------------------------------------
/@examples/astro/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Layout from '../layouts/Layout.astro';
3 | import Card from '../components/Card.astro';
4 | import {css} from 'taddy';
5 | ---
6 |
7 |
8 |
9 | Welcome to Astro
10 |
11 | Hello world!
12 |
13 |
14 | To get started, open the directory src/pages
in your project.
16 | Code Challenge: Tweak the "Welcome to Astro" message
17 | above.
18 |
19 |
41 |
42 |
43 |
44 |
88 |
--------------------------------------------------------------------------------
/@examples/astro/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["../../tsconfig.json", "astro/tsconfigs/strict"],
3 | "compilerOptions": {
4 | "baseUrl": "."
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/@examples/nextjs/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/@examples/nextjs/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/@examples/nextjs/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | ```
14 |
15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
16 |
17 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
18 |
19 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
20 |
21 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
22 |
23 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
24 |
25 | ## Learn More
26 |
27 | To learn more about Next.js, take a look at the following resources:
28 |
29 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
30 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
31 |
32 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
33 |
34 | ## Deploy on Vercel
35 |
36 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
37 |
38 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
39 |
--------------------------------------------------------------------------------
/@examples/nextjs/app/SuperComponent.tsx:
--------------------------------------------------------------------------------
1 | import {css} from 'taddy';
2 |
3 | export const SuperComponent = () => {
4 | return (
5 |
6 | hello, super!!!
7 |
8 | );
9 | };
10 |
--------------------------------------------------------------------------------
/@examples/nextjs/app/api/hello/route.ts:
--------------------------------------------------------------------------------
1 | export async function GET(request: Request) {
2 | return new Response('Hello, Next.js!')
3 | }
4 |
--------------------------------------------------------------------------------
/@examples/nextjs/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@examples/nextjs/app/favicon.ico
--------------------------------------------------------------------------------
/@examples/nextjs/app/layout.tsx:
--------------------------------------------------------------------------------
1 | // import '@taddy/babel-plugin/lib/cache/taddy.css';
2 |
3 | export const metadata = {
4 | title: 'Create Next App',
5 | description: 'Generated by create next app',
6 | };
7 |
8 | export default function RootLayout({children}: {children: React.ReactNode}) {
9 | return (
10 |
11 | {children}
12 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/@examples/nextjs/app/page.tsx:
--------------------------------------------------------------------------------
1 | import {css} from 'taddy';
2 |
3 | import {SuperComponent} from './SuperComponent';
4 |
5 | export default function Home() {
6 | return (
7 |
8 | hello, hoh!!!
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/@examples/nextjs/next.config.js:
--------------------------------------------------------------------------------
1 | const withTaddy = require('@taddy/next-plugin');
2 |
3 | /** @type {import('next').NextConfig} */
4 | const nextConfig = {
5 | experimental: {
6 | appDir: true,
7 | },
8 | };
9 |
10 | module.exports = withTaddy()(nextConfig);
11 |
--------------------------------------------------------------------------------
/@examples/nextjs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@types/node": "18.15.3",
13 | "@types/react": "18.0.28",
14 | "@types/react-dom": "18.0.11",
15 | "eslint": "8.36.0",
16 | "eslint-config-next": "13.2.4",
17 | "next": "13.2.4",
18 | "react": "18.2.0",
19 | "react-dom": "18.2.0",
20 | "taddy": "^0.1.0-alpha.0"
21 | },
22 | "devDependencies": {
23 | "@taddy/next-plugin": "^0.1.0-alpha.0",
24 | "tslib": "2.5.0"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/@examples/nextjs/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/@examples/nextjs/public/thirteen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/@examples/nextjs/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/@examples/nextjs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "baseUrl": ".",
5 |
6 | "target": "es5",
7 | "lib": ["dom", "dom.iterable", "esnext"],
8 | "allowJs": true,
9 | "skipLibCheck": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "noEmit": true,
13 | "esModuleInterop": true,
14 | "module": "esnext",
15 | "moduleResolution": "node",
16 | "resolveJsonModule": true,
17 | "isolatedModules": true,
18 | "jsx": "preserve",
19 | "incremental": true,
20 | "plugins": [
21 | {
22 | "name": "next"
23 | }
24 | ],
25 | "paths": {
26 | "@/*": ["./*"]
27 | }
28 | },
29 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
30 | "exclude": ["node_modules"]
31 | }
32 |
--------------------------------------------------------------------------------
/@examples/nuxt/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log*
3 | .nuxt
4 | .nitro
5 | .cache
6 | .output
7 | .env
8 | dist
9 | .DS_Store
10 |
--------------------------------------------------------------------------------
/@examples/nuxt/.npmrc:
--------------------------------------------------------------------------------
1 | shamefully-hoist=true
2 | strict-peer-dependencies=false
3 |
--------------------------------------------------------------------------------
/@examples/nuxt/README.md:
--------------------------------------------------------------------------------
1 | # Nuxt 3 Minimal Starter
2 |
3 | Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
4 |
5 | ## Setup
6 |
7 | Make sure to install the dependencies:
8 |
9 | ```bash
10 | # yarn
11 | yarn install
12 |
13 | # npm
14 | npm install
15 |
16 | # pnpm
17 | pnpm install
18 | ```
19 |
20 | ## Development Server
21 |
22 | Start the development server on http://localhost:3000
23 |
24 | ```bash
25 | npm run dev
26 | ```
27 |
28 | ## Production
29 |
30 | Build the application for production:
31 |
32 | ```bash
33 | npm run build
34 | ```
35 |
36 | Locally preview production build:
37 |
38 | ```bash
39 | npm run preview
40 | ```
41 |
42 | Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
43 |
--------------------------------------------------------------------------------
/@examples/nuxt/app.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/@examples/nuxt/components/Test.tsx:
--------------------------------------------------------------------------------
1 | import {css} from 'taddy';
2 |
3 | export default defineComponent({
4 | render: () => {
5 | return (
6 |
7 | Hello World
8 |
9 | );
10 | },
11 | });
12 |
--------------------------------------------------------------------------------
/@examples/nuxt/components/Test2.tsx:
--------------------------------------------------------------------------------
1 | import {css} from 'taddy';
2 |
3 | export default defineComponent({
4 | render: () => {
5 | return (
6 |
7 | Hello World 2
8 |
9 | );
10 | },
11 | });
12 |
--------------------------------------------------------------------------------
/@examples/nuxt/nuxt.config.ts:
--------------------------------------------------------------------------------
1 | import taddyPlugin from '@taddy/vite-plugin';
2 |
3 | // https://nuxt.com/docs/api/configuration/nuxt-config
4 | export default defineNuxtConfig({
5 | vite: {
6 | plugins: [taddyPlugin()],
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/@examples/nuxt/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "@examples/nuxt",
4 | "version": "0.0.0",
5 | "scripts": {
6 | "build": "nuxt build",
7 | "dev": "nuxt dev",
8 | "generate": "nuxt generate",
9 | "preview": "nuxt preview",
10 | "prepare": "nuxt prepare"
11 | },
12 | "dependencies": {
13 | "taddy": "^0.1.0-alpha.0"
14 | },
15 | "devDependencies": {
16 | "nuxt": "^3.3.1",
17 | "@taddy/babel-plugin": "^0.1.0-alpha.0",
18 | "@taddy/vite-plugin": "^0.1.0-alpha.0"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/@examples/nuxt/pages/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/@examples/nuxt/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@examples/nuxt/public/favicon.ico
--------------------------------------------------------------------------------
/@examples/nuxt/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // https://nuxt.com/docs/guide/concepts/typescript
3 | "extends": ["../../tsconfig.json", "./.nuxt/tsconfig.json"],
4 | "compilerOptions": {
5 | "baseUrl": "."
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/@examples/parcel/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/react"]
3 | }
4 |
--------------------------------------------------------------------------------
/@examples/parcel/App.tsx:
--------------------------------------------------------------------------------
1 | import {css} from 'taddy';
2 |
3 | import Test from './Test';
4 |
5 | function App() {
6 | return (
7 |
8 | Hello world
9 |
10 |
11 | );
12 | }
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/@examples/parcel/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Taddy Parcel Example
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/@examples/parcel/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as ReactDOM from 'react-dom';
3 |
4 | import 'taddy/css';
5 |
6 | import App from './App';
7 |
8 | const render = () => {
9 | ReactDOM.render(
10 |
11 |
12 | ,
13 | document.getElementById('root'),
14 | );
15 | };
16 |
17 | render();
18 |
--------------------------------------------------------------------------------
/@examples/parcel/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "@examples/parcel",
4 | "version": "0.0.0",
5 | "main": "index.js",
6 | "license": "MIT",
7 | "scripts": {
8 | "start": "parcel index.html",
9 | "build": "parcel build index.html"
10 | },
11 | "dependencies": {
12 | "react": "18.2.0",
13 | "react-dom": "18.2.0",
14 | "taddy": "^0.1.0-alpha.0"
15 | },
16 | "devDependencies": {
17 | "@babel/core": "^7.11.1",
18 | "@types/react": "^18.0.28",
19 | "@types/react-dom": "^18.0.11",
20 | "parcel": "^2.8.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/@examples/parcel/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "baseUrl": "."
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/@examples/react-native-expo/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .expo/
3 | dist/
4 | npm-debug.*
5 | *.jks
6 | *.p8
7 | *.p12
8 | *.key
9 | *.mobileprovision
10 | *.orig.*
11 | web-build/
12 |
13 | # macOS
14 | .DS_Store
15 |
16 | # Temporary files created by Metro to check the health of the file watcher
17 | .metro-health-check*
18 |
--------------------------------------------------------------------------------
/@examples/react-native-expo/App.tsx:
--------------------------------------------------------------------------------
1 | import {StatusBar} from 'expo-status-bar';
2 | import {StyleSheet, Text, View} from 'react-native';
3 |
4 | import {css} from 'taddy';
5 |
6 | export default function App() {
7 | return (
8 |
9 |
10 | Open up App.js to start working on your app!
11 |
12 |
13 |
14 | );
15 | }
16 |
17 | const styles = StyleSheet.create({
18 | container: {
19 | flex: 1,
20 | backgroundColor: '#fff',
21 | alignItems: 'center',
22 | justifyContent: 'center',
23 | },
24 | });
25 |
--------------------------------------------------------------------------------
/@examples/react-native-expo/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "react-native-expo",
4 | "slug": "react-native-expo",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "userInterfaceStyle": "light",
9 | "splash": {
10 | "image": "./assets/splash.png",
11 | "resizeMode": "contain",
12 | "backgroundColor": "#ffffff"
13 | },
14 | "assetBundlePatterns": ["**/*"],
15 | "ios": {
16 | "supportsTablet": true
17 | },
18 | "android": {
19 | "adaptiveIcon": {
20 | "foregroundImage": "./assets/adaptive-icon.png",
21 | "backgroundColor": "#ffffff"
22 | }
23 | },
24 | "web": {
25 | "favicon": "./assets/favicon.png"
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/@examples/react-native-expo/assets/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@examples/react-native-expo/assets/adaptive-icon.png
--------------------------------------------------------------------------------
/@examples/react-native-expo/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@examples/react-native-expo/assets/favicon.png
--------------------------------------------------------------------------------
/@examples/react-native-expo/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@examples/react-native-expo/assets/icon.png
--------------------------------------------------------------------------------
/@examples/react-native-expo/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@examples/react-native-expo/assets/splash.png
--------------------------------------------------------------------------------
/@examples/react-native-expo/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | plugins: [
6 | [
7 | 'module-resolver',
8 | {
9 | alias: {
10 | crypto: 'expo-crypto',
11 | },
12 | },
13 | ],
14 | ],
15 | };
16 | };
17 |
--------------------------------------------------------------------------------
/@examples/react-native-expo/index.tsx:
--------------------------------------------------------------------------------
1 | import {registerRootComponent} from 'expo';
2 |
3 | import App from './App';
4 |
5 | registerRootComponent(App);
6 |
--------------------------------------------------------------------------------
/@examples/react-native-expo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "react-native-expo",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start",
7 | "android": "expo start --android",
8 | "ios": "expo start --ios",
9 | "web": "expo start --web"
10 | },
11 | "dependencies": {
12 | "expo": "~48.0.6",
13 | "expo-crypto": "^12.2.1",
14 | "expo-status-bar": "~1.4.4",
15 | "react": "18.2.0",
16 | "react-native": "0.71.3",
17 | "taddy": "^0.1.0-alpha.0"
18 | },
19 | "devDependencies": {
20 | "@babel/core": "^7.20.0",
21 | "@types/react-native": "0.71.3"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/@examples/react-native-expo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["../../tsconfig.json", "expo/tsconfig.base"],
3 | "compilerOptions": {
4 | "baseUrl": "."
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/@examples/remix/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /** @type {import('eslint').Linter.Config} */
2 | module.exports = {
3 | extends: ["@remix-run/eslint-config", "@remix-run/eslint-config/node"],
4 | };
5 |
--------------------------------------------------------------------------------
/@examples/remix/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /.cache
4 | /build
5 | /public/build
6 | .env
7 |
--------------------------------------------------------------------------------
/@examples/remix/README.md:
--------------------------------------------------------------------------------
1 | # Welcome to Remix!
2 |
3 | - [Remix Docs](https://remix.run/docs)
4 |
5 | ## Development
6 |
7 | From your terminal:
8 |
9 | ```sh
10 | npm run dev
11 | ```
12 |
13 | This starts your app in development mode, rebuilding assets on file changes.
14 |
15 | ## Deployment
16 |
17 | First, build your app for production:
18 |
19 | ```sh
20 | npm run build
21 | ```
22 |
23 | Then run the app in production mode:
24 |
25 | ```sh
26 | npm start
27 | ```
28 |
29 | Now you'll need to pick a host to deploy it to.
30 |
31 | ### DIY
32 |
33 | If you're familiar with deploying node applications, the built-in Remix app server is production-ready.
34 |
35 | Make sure to deploy the output of `remix build`
36 |
37 | - `build/`
38 | - `public/build/`
39 |
40 | ### Using a Template
41 |
42 | When you ran `npx create-remix@latest` there were a few choices for hosting. You can run that again to create a new project, then copy over your `app/` folder to the new project that's pre-configured for your target server.
43 |
44 | ```sh
45 | cd ..
46 | # create a new project, and pick a pre-configured host
47 | npx create-remix@latest
48 | cd my-new-remix-app
49 | # remove the new project's app (not the old one!)
50 | rm -rf app
51 | # copy your app over
52 | cp -R ../my-old-remix-app/app app
53 | ```
54 |
--------------------------------------------------------------------------------
/@examples/remix/app/root.tsx:
--------------------------------------------------------------------------------
1 | import type {MetaFunction, LinksFunction} from '@remix-run/node';
2 | import {
3 | Links,
4 | LiveReload,
5 | Meta,
6 | Outlet,
7 | Scripts,
8 | ScrollRestoration,
9 | } from '@remix-run/react';
10 | import {cssBundleHref} from '@remix-run/css-bundle';
11 |
12 | export const meta: MetaFunction = () => ({
13 | charset: 'utf-8',
14 | title: 'New Remix App',
15 | viewport: 'width=device-width,initial-scale=1',
16 | });
17 |
18 | export const links: LinksFunction = () => {
19 | return [
20 | ...(cssBundleHref ? [{rel: 'stylesheet', href: cssBundleHref}] : []),
21 | // ...
22 | ];
23 | };
24 |
25 | export default function App() {
26 | return (
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/@examples/remix/app/routes/index.tsx:
--------------------------------------------------------------------------------
1 | import {css} from 'taddy';
2 |
3 | export default function Index() {
4 | return (
5 |
6 |
Welcome to Remix
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/@examples/remix/app/routes/test/index.tsx:
--------------------------------------------------------------------------------
1 | import {css} from 'taddy';
2 |
3 | export default function Index() {
4 | return (
5 |
6 |
7 | Test Page
8 |
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/@examples/remix/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@examples/remix",
3 | "version": "0.0.0",
4 | "private": true,
5 | "sideEffects": false,
6 | "scripts": {
7 | "build": "remix build",
8 | "dev": "remix dev",
9 | "start": "remix-serve build",
10 | "typecheck": "tsc",
11 | "postinstall": "remix-esbuild-override"
12 | },
13 | "dependencies": {
14 | "@remix-run/css-bundle": "^1.14.3",
15 | "@remix-run/node": "^1.14.3",
16 | "@remix-run/react": "^1.14.3",
17 | "@remix-run/serve": "^1.14.3",
18 | "D": "^1.0.0",
19 | "isbot": "^3.6.5",
20 | "react": "^18.2.0",
21 | "react-dom": "^18.2.0",
22 | "remix-esbuild-override": "^3.0.4",
23 | "taddy": "^0.1.0-alpha.0"
24 | },
25 | "devDependencies": {
26 | "@remix-run/dev": "^1.14.3",
27 | "@remix-run/eslint-config": "^1.14.3",
28 | "@taddy/babel-plugin": "^0.1.0-alpha.0",
29 | "@taddy/esbuild-plugin": "^0.1.0-alpha.0",
30 | "@types/react": "^18.0.25",
31 | "@types/react-dom": "^18.0.8",
32 | "eslint": "^8.27.0"
33 | },
34 | "engines": {
35 | "node": ">=14"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/@examples/remix/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@examples/remix/public/favicon.ico
--------------------------------------------------------------------------------
/@examples/remix/remix.config.js:
--------------------------------------------------------------------------------
1 | const {withEsbuildOverride} = require('remix-esbuild-override');
2 | const taddyPlugin = require('@taddy/esbuild-plugin');
3 |
4 | withEsbuildOverride((option) => {
5 | option.plugins.unshift(taddyPlugin());
6 |
7 | return option;
8 | });
9 |
10 | /** @type {import('@remix-run/dev').AppConfig} */
11 | module.exports = {
12 | ignoredRouteFiles: ['**/.*'],
13 |
14 | serverDependenciesToBundle: [/@taddy/],
15 |
16 | future: {
17 | unstable_cssSideEffectImports: true,
18 | },
19 |
20 | // appDirectory: "app",
21 | // assetsBuildDirectory: "public/build",
22 | // serverBuildPath: "build/index.js",
23 | // publicPath: "/build/",
24 | };
25 |
--------------------------------------------------------------------------------
/@examples/remix/remix.env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/@examples/remix/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["../../tsconfig.json"],
3 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
4 | "compilerOptions": {
5 | "baseUrl": ".",
6 |
7 | "lib": ["DOM", "DOM.Iterable", "ES2019"],
8 | "isolatedModules": true,
9 | "esModuleInterop": true,
10 | "jsx": "react-jsx",
11 | "moduleResolution": "node",
12 | "resolveJsonModule": true,
13 | "target": "ES2019",
14 | "strict": true,
15 | "allowJs": true,
16 | "forceConsistentCasingInFileNames": true,
17 | "paths": {
18 | "~/*": ["./app/*"]
19 | },
20 | // Remix takes care of building everything in `remix build`.
21 | "noEmit": true
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/@examples/solid-start/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | dist
3 | .solid
4 | .output
5 | .vercel
6 | .netlify
7 | netlify
8 |
9 | # dependencies
10 | /node_modules
11 |
12 | # IDEs and editors
13 | /.idea
14 | .project
15 | .classpath
16 | *.launch
17 | .settings/
18 |
19 | # Temp
20 | gitignore
21 |
22 | # System Files
23 | .DS_Store
24 | Thumbs.db
25 |
--------------------------------------------------------------------------------
/@examples/solid-start/README.md:
--------------------------------------------------------------------------------
1 | # SolidStart
2 |
3 | Everything you need to build a Solid project, powered by [`solid-start`](https://start.solidjs.com);
4 |
5 | ## Creating a project
6 |
7 | ```bash
8 | # create a new project in the current directory
9 | npm init solid@latest
10 |
11 | # create a new project in my-app
12 | npm init solid@latest my-app
13 | ```
14 |
15 | ## Developing
16 |
17 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
18 |
19 | ```bash
20 | npm run dev
21 |
22 | # or start the server and open the app in a new browser tab
23 | npm run dev -- --open
24 | ```
25 |
26 | ## Building
27 |
28 | Solid apps are built with _adapters_, which optimise your project for deployment to different environments.
29 |
30 | By default, `npm run build` will generate a Node app that you can run with `npm start`. To use a different adapter, add it to the `devDependencies` in `package.json` and specify in your `vite.config.js`.
31 |
--------------------------------------------------------------------------------
/@examples/solid-start/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "@examples/solid-start",
4 | "version": "0.0.0",
5 | "scripts": {
6 | "dev": "solid-start dev",
7 | "build": "solid-start build",
8 | "start": "solid-start start"
9 | },
10 | "type": "module",
11 | "devDependencies": {
12 | "@taddy/vite-plugin": "^0.1.0-alpha.0",
13 | "@types/node": "^18.11.18",
14 | "esbuild": "^0.14.54",
15 | "postcss": "^8.4.21",
16 | "solid-start-node": "^0.2.19",
17 | "vite": "^4.1.4"
18 | },
19 | "dependencies": {
20 | "@solidjs/meta": "^0.28.2",
21 | "@solidjs/router": "^0.7.0",
22 | "solid-js": "^1.6.11",
23 | "solid-start": "^0.2.23",
24 | "undici": "^5.15.1",
25 | "taddy": "^0.1.0-alpha.0"
26 | },
27 | "engines": {
28 | "node": ">=16.8"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/@examples/solid-start/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@examples/solid-start/public/favicon.ico
--------------------------------------------------------------------------------
/@examples/solid-start/src/components/Counter.tsx:
--------------------------------------------------------------------------------
1 | import {createSignal} from 'solid-js';
2 | import {css} from 'taddy';
3 |
4 | export default function Counter() {
5 | const [count, setCount] = createSignal(0);
6 | return (
7 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/@examples/solid-start/src/components/Hello.tsx:
--------------------------------------------------------------------------------
1 | import {css} from 'taddy';
2 |
3 | export default function Hello() {
4 | return (
5 |
6 | Hello World
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/@examples/solid-start/src/entry-client.tsx:
--------------------------------------------------------------------------------
1 | import { mount, StartClient } from "solid-start/entry-client";
2 |
3 | mount(() => , document);
4 |
--------------------------------------------------------------------------------
/@examples/solid-start/src/entry-server.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | createHandler,
3 | renderAsync,
4 | StartServer,
5 | } from "solid-start/entry-server";
6 |
7 | export default createHandler(
8 | renderAsync((event) => )
9 | );
10 |
--------------------------------------------------------------------------------
/@examples/solid-start/src/root.tsx:
--------------------------------------------------------------------------------
1 | // @refresh reload
2 | import {Suspense} from 'solid-js';
3 | import {
4 | A,
5 | Body,
6 | ErrorBoundary,
7 | FileRoutes,
8 | Head,
9 | Html,
10 | Meta,
11 | Routes,
12 | Scripts,
13 | Title,
14 | } from 'solid-start';
15 |
16 | export default function Root() {
17 | return (
18 |
19 |
20 | SolidStart - Bare
21 |
22 |
26 |
27 |
28 |
29 |
30 | Index
31 | About
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/@examples/solid-start/src/routes/[...404].tsx:
--------------------------------------------------------------------------------
1 | import { Title } from "solid-start";
2 | import { HttpStatusCode } from "solid-start/server";
3 |
4 | export default function NotFound() {
5 | return (
6 |
7 | Not Found
8 |
9 | Page Not Found
10 |
11 | Visit{" "}
12 |
13 | start.solidjs.com
14 | {" "}
15 | to learn how to build SolidStart apps.
16 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/@examples/solid-start/src/routes/index.tsx:
--------------------------------------------------------------------------------
1 | import {Title} from 'solid-start';
2 |
3 | import Hello from '../components/Hello';
4 | import Counter from '../components/Counter';
5 |
6 | export default function Home() {
7 | return (
8 |
9 | Hello World
10 |
11 |
12 |
13 | Visit{' '}
14 |
19 | start.solidjs.com
20 | {' '}
21 | to learn how to build SolidStart apps.
22 |
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/@examples/solid-start/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "baseUrl": ".",
5 |
6 | "allowSyntheticDefaultImports": true,
7 | "esModuleInterop": true,
8 | "target": "ESNext",
9 | "module": "ESNext",
10 | "moduleResolution": "node",
11 | "jsxImportSource": "solid-js",
12 | "jsx": "preserve",
13 | "strict": true,
14 | "types": ["solid-start/env"]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/@examples/solid-start/vite.config.ts:
--------------------------------------------------------------------------------
1 | import taddy from '@taddy/vite-plugin';
2 | import solid from 'solid-start/vite';
3 | import {defineConfig} from 'vite';
4 |
5 | export default defineConfig({
6 | plugins: [solid(), taddy()],
7 | });
8 |
--------------------------------------------------------------------------------
/@examples/svelte-kit/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | .env
7 | .env.*
8 | !.env.example
9 | vite.config.js.timestamp-*
10 | vite.config.ts.timestamp-*
11 |
--------------------------------------------------------------------------------
/@examples/svelte-kit/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict=true
2 |
--------------------------------------------------------------------------------
/@examples/svelte-kit/README.md:
--------------------------------------------------------------------------------
1 | # create-svelte
2 |
3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
4 |
5 | ## Creating a project
6 |
7 | If you're seeing this, you've probably already done this step. Congrats!
8 |
9 | ```bash
10 | # create a new project in the current directory
11 | npm create svelte@latest
12 |
13 | # create a new project in my-app
14 | npm create svelte@latest my-app
15 | ```
16 |
17 | ## Developing
18 |
19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
20 |
21 | ```bash
22 | npm run dev
23 |
24 | # or start the server and open the app in a new browser tab
25 | npm run dev -- --open
26 | ```
27 |
28 | ## Building
29 |
30 | To create a production version of your app:
31 |
32 | ```bash
33 | npm run build
34 | ```
35 |
36 | You can preview the production build with `npm run preview`.
37 |
38 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
39 |
--------------------------------------------------------------------------------
/@examples/svelte-kit/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@examples/svelte-kit",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vite dev",
7 | "build": "vite build",
8 | "preview": "vite preview",
9 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
10 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
11 | },
12 | "dependencies": {
13 | "taddy": "^0.1.0-alpha.0"
14 | },
15 | "devDependencies": {
16 | "@sveltejs/adapter-auto": "^2.0.0",
17 | "@sveltejs/kit": "^1.5.0",
18 | "@taddy/babel-plugin": "^0.1.0-alpha.0",
19 | "svelte": "^3.54.0",
20 | "svelte-check": "^3.0.1",
21 | "svelte-preprocess": "^5.0.3",
22 | "tslib": "^2.4.1",
23 | "vite": "^4.0.0"
24 | },
25 | "type": "module"
26 | }
27 |
--------------------------------------------------------------------------------
/@examples/svelte-kit/src/app.d.ts:
--------------------------------------------------------------------------------
1 | // See https://kit.svelte.dev/docs/types#app
2 | // for information about these interfaces
3 | declare global {
4 | namespace App {
5 | // interface Error {}
6 | // interface Locals {}
7 | // interface PageData {}
8 | // interface Platform {}
9 | }
10 | }
11 |
12 | export {};
13 |
--------------------------------------------------------------------------------
/@examples/svelte-kit/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | %sveltekit.head%
8 |
9 |
10 | %sveltekit.body%
11 |
12 |
13 |
--------------------------------------------------------------------------------
/@examples/svelte-kit/src/routes/+layout.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/@examples/svelte-kit/src/routes/+page.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | Welcome to SvelteKit
8 | Visit kit.svelte.dev to read the documentation
9 |
--------------------------------------------------------------------------------
/@examples/svelte-kit/src/routes/test/+page.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | Welcome to SvelteKit
8 | Visit kit.svelte.dev to read the documentation
9 |
10 |
--------------------------------------------------------------------------------
/@examples/svelte-kit/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lttb/taddy/44700650aa6000138104af1b43df944d82e0971d/@examples/svelte-kit/static/favicon.png
--------------------------------------------------------------------------------
/@examples/svelte-kit/svelte.config.js:
--------------------------------------------------------------------------------
1 | import adapter from '@sveltejs/adapter-auto';
2 | import preprocess from 'svelte-preprocess';
3 |
4 | /** @type {import('@sveltejs/kit').Config} */
5 | const config = {
6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors
7 | // for more information about preprocessors
8 | preprocess: preprocess({
9 | babel: {
10 | plugins: [['@taddy']],
11 | },
12 | }),
13 |
14 | kit: {
15 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
16 | // If your environment is not supported or you settled on a specific environment, switch out the adapter.
17 | // See https://kit.svelte.dev/docs/adapters for more information about adapters.
18 | adapter: adapter(),
19 | },
20 | };
21 |
22 | export default config;
23 |
--------------------------------------------------------------------------------
/@examples/svelte-kit/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["../../tsconfig.json", "./.svelte-kit/tsconfig.json"],
3 | "compilerOptions": {
4 | "baseUrl": ".",
5 |
6 | "allowJs": true,
7 | "checkJs": true,
8 | "esModuleInterop": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "resolveJsonModule": true,
11 | "skipLibCheck": true,
12 | "sourceMap": true,
13 | "strict": true
14 | }
15 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
16 | //
17 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
18 | // from the referenced tsconfig.json - TypeScript does not merge them in
19 | }
20 |
--------------------------------------------------------------------------------
/@examples/svelte-kit/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { sveltekit } from '@sveltejs/kit/vite';
2 | import { defineConfig } from 'vite';
3 |
4 | export default defineConfig({
5 | plugins: [sveltekit()]
6 | });
7 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/.gitignore:
--------------------------------------------------------------------------------
1 | cache/*
2 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/.npmignore:
--------------------------------------------------------------------------------
1 | tsconfig.json
2 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/README.md:
--------------------------------------------------------------------------------
1 | # @taddy/babel-plugin
2 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/cache/index.js:
--------------------------------------------------------------------------------
1 | // require('./taddy.css');
2 |
3 | // console.log(require.context(__dirname, true, /.*\.css/));
4 |
5 | // function requireAll(requireContext) {
6 | // return requireContext.keys().map(requireContext);
7 | // }
8 |
9 | // requireAll(require.context(__dirname, true, /.*\.css/));
10 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/index.ts:
--------------------------------------------------------------------------------
1 | export {default} from './src';
2 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/macro.ts:
--------------------------------------------------------------------------------
1 | export {macro} from './src/macro-plugin';
2 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@taddy/babel-plugin",
3 | "version": "0.1.0-alpha.10",
4 | "author": "Kenzhaev Artur ",
5 | "license": "MIT",
6 | "main": "lib/index.js",
7 | "publishConfig": {
8 | "access": "public"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/lttb/taddy.git",
13 | "directory": "@taddy/babel-plugin"
14 | },
15 | "scripts": {
16 | "clean": "rm -rf lib",
17 | "check:ts": "tsc --noEmit",
18 | "precompile": "yarn clean",
19 | "compile": "tsc",
20 | "prestart": "yarn clean",
21 | "start": "yarn compile --watch",
22 | "prebuild": "yarn clean",
23 | "build": "yarn compile"
24 | },
25 | "dependencies": {
26 | "@babel/core": "^7.21.0",
27 | "@babel/helper-module-imports": "^7.10.1",
28 | "@babel/preset-env": "^7.10.4",
29 | "@babel/preset-react": "^7.18.6",
30 | "@babel/preset-typescript": "^7.10.4",
31 | "@babel/register": "^7.21.0",
32 | "@babel/standalone": "^7.21.2",
33 | "@babel/types": "^7.11.0",
34 | "@taddy/core": "^0.1.0-alpha.3",
35 | "babel-helper-evaluate-path": "^0.5.0",
36 | "common-tags": "^1.8.2",
37 | "convert-source-map": "^2.0.0",
38 | "find-cache-dir": "3.3.2",
39 | "lilconfig": "^2.1.0",
40 | "postcss": "^8.4.21",
41 | "postcss-js": "^4.0.1",
42 | "resolve": "^1.22.1",
43 | "source-map": "^0.7.4",
44 | "string-hash": "^1.1.3",
45 | "sync-rpc": "^1.3.6",
46 | "taddy": "^0.1.0-alpha.5",
47 | "ts-morph": "^17.0.1"
48 | },
49 | "devDependencies": {
50 | "@types/babel__register": "^7.17.0",
51 | "@types/babel__standalone": "^7.1.4",
52 | "@types/find-cache-dir": "3.2.1",
53 | "@types/node": "18.15.0",
54 | "@types/string-hash": "1.1.1",
55 | "@types/workerpool": "^6.4.0"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/config.js:
--------------------------------------------------------------------------------
1 | import * as path from 'path';
2 |
3 | export const MACRO_NAME = 'taddy.macro';
4 | export const PACKAGE_NAME = 'taddy';
5 |
6 | /**
7 | * @param {import('@babel/core').ConfigAPI} babel
8 | * @returns {import('./types').Env}
9 | */
10 | export function getEnv(babel) {
11 | try {
12 | return babel.env();
13 | } catch (e) {
14 | // console.log('error', e);
15 | }
16 |
17 | const DEFAULT_ENV = 'production';
18 |
19 | if (!(typeof process && process.env)) {
20 | return DEFAULT_ENV;
21 | }
22 |
23 | return process.env.BABEL_ENV || process.env.NODE_ENV || DEFAULT_ENV;
24 | }
25 |
26 | // TODO: add config resolution
27 |
28 | /*
29 | function loadConfig(filepath: string): object {
30 | const {Project} = require('ts-morph');
31 |
32 | // empty project to parse the config
33 | const project: TSProject = new Project();
34 |
35 | const sourceFile = project.addSourceFileAtPath(filepath);
36 |
37 | const decl = sourceFile.getDefaultExportSymbol();
38 |
39 | const properties = getType(decl)
40 | ?.getProperties()
41 | .find((x) => x.getEscapedName() === 'properties');
42 |
43 | const result = parseObject(getType(properties));
44 |
45 | const compiled = project.emitToMemory().getFiles()[0].text;
46 |
47 | // eslint-disable-next-line
48 | const emit = new Function('exports', `${compiled};return exports;`);
49 |
50 | return {
51 | ...emit({}).default,
52 | _properties: result,
53 | };
54 | }
55 |
56 | export const config = lilconfigSync(PACKAGE_NAME, {
57 | searchPlaces: [`${PACKAGE_NAME}.config.ts`],
58 | loaders: {
59 | '.ts': loadConfig,
60 | },
61 | }).search()?.config;
62 | */
63 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/helpers/BindingOptimizer.ts:
--------------------------------------------------------------------------------
1 | import type {NodePath, Binding} from '@babel/traverse';
2 | import * as t from '@babel/types';
3 |
4 | import {findBindings, addBinding} from './findBindings';
5 | import type {BindingMap} from './findBindings';
6 |
7 | function isTaddy(binding: Binding) {
8 | const {path} = binding;
9 |
10 | if (!path.isImportSpecifier()) return false;
11 |
12 | const {imported} = path.node;
13 |
14 | return (
15 | t.isIdentifier(imported) &&
16 | (((path.parentPath as NodePath).node.source
17 | .value === 'taddy' &&
18 | imported.name === 'css') ||
19 | imported.name === 'mixin')
20 | );
21 | }
22 |
23 | export class BindingOptimizer {
24 | cache: BindingMap = new Map();
25 |
26 | process(referentPath: NodePath) {
27 | let bindings: ReturnType;
28 |
29 | try {
30 | bindings = findBindings(referentPath);
31 | } catch (error) {
32 | return;
33 | }
34 |
35 | for (const [binding, paths] of bindings) {
36 | if (isTaddy(binding)) continue;
37 |
38 | if (binding.path.removed) continue;
39 |
40 | this.process(binding.path);
41 |
42 | addBinding(this.cache, binding, paths);
43 |
44 | if (this.cache.get(binding)!.size < binding.references) {
45 | continue;
46 | }
47 |
48 | binding.path.remove();
49 |
50 | const {parentPath} = binding.path;
51 |
52 | const isImportToRemove =
53 | parentPath?.isImportDeclaration() &&
54 | parentPath.node.specifiers.length === 0;
55 |
56 | // // keep imports for development build
57 | // if (env === 'development') {
58 | // return;
59 | // }
60 |
61 | if (!isImportToRemove) {
62 | continue;
63 | }
64 |
65 | parentPath.remove();
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/helpers/buildCodeByPath.ts:
--------------------------------------------------------------------------------
1 | import type {NodePath} from '@babel/traverse';
2 |
3 | import {findBindings} from './findBindings';
4 |
5 | function getPathsByBindings(
6 | bindings: ReturnType,
7 | ): Set> {
8 | const paths = new Set>();
9 |
10 | for (const x of bindings.keys()) {
11 | if (x.path.isImportSpecifier() || x.path.isVariableDeclarator()) {
12 | paths.add(x.path.parentPath);
13 | continue;
14 | }
15 |
16 | paths.add(x.path);
17 | }
18 |
19 | return paths;
20 | }
21 |
22 | export function buildCodeByPath(path: NodePath): string {
23 | return Array.from(
24 | getPathsByBindings(findBindings(path, {throwError: true})),
25 | )
26 | .sort((a, b) => a.node.start - b.node.start)
27 | .map((x) => x.toString())
28 | .join('\n');
29 | }
30 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/helpers/evaluate.ts:
--------------------------------------------------------------------------------
1 | import type {NodePath} from '@babel/core';
2 |
3 | import evaluatePath from 'babel-helper-evaluate-path';
4 |
5 | import {MACRO_NAME, PACKAGE_NAME} from '../config';
6 |
7 | import {findBindings} from './findBindings';
8 | import {buildCodeByPath} from './buildCodeByPath';
9 |
10 | import ev from './evaluate.worker.cjs';
11 |
12 | // NOTE: bun doesn't support sync-rps
13 | // TODO: support bun environment and avoid transpiling
14 | const evaluateChunk = process.versions.bun
15 | ? ev()
16 | : require('sync-rpc')(__dirname + '/evaluate.worker.cjs', 'Evaluate');
17 |
18 | const macroRe = new RegExp(MACRO_NAME.replace('.', '\\.'), 'g');
19 |
20 | export function evaluate(
21 | currentPath: NodePath,
22 | {exec = true}: {exec?: boolean},
23 | ):
24 | | {
25 | value: any;
26 | }
27 | | {error: Error} {
28 | const result = evaluatePath(currentPath);
29 |
30 | if (result.confident) {
31 | findBindings(currentPath);
32 |
33 | return {value: result.value};
34 | }
35 |
36 | if (!exec) return {error: new Error('EXEC_REQUIRED')};
37 |
38 | let content = '';
39 |
40 | try {
41 | const callbackName = '__taddy__';
42 |
43 | content = buildCodeByPath(currentPath)
44 | // hack to avoid processing by babel-macro
45 | .replace(macroRe, PACKAGE_NAME)
46 | .concat(`\n\n;${callbackName}(${currentPath.toString()})`);
47 |
48 | // TODO: improve Hub type
49 | const {opts} = (currentPath.hub as any).file;
50 |
51 | const {value, error} = evaluateChunk({
52 | content,
53 | filename: opts.filename,
54 | callbackName,
55 | });
56 |
57 | if (error) return {error};
58 |
59 | return {value: JSON.parse(value)};
60 | } catch (error: any) {
61 | // console.log('evaluate error', {content, error});
62 |
63 | return {error};
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/helpers/evaluate.worker.cjs:
--------------------------------------------------------------------------------
1 | const {transform, registerPreset} = require('@babel/standalone');
2 | const path = require('path');
3 | const fs = require('fs');
4 | const resolve = require('resolve');
5 |
6 | const EXTENSIONS = ['.es6', '.es', '.js', '.mjs', '.jsx', '.tsx', '.ts'];
7 | const DEFAULT_PRESETS = [
8 | ['@babel/typescript', {allExtensions: true, isTSX: true}],
9 | ['@babel/env', {targets: {node: '12'}, modules: 'cjs'}],
10 | ];
11 |
12 | const {config} = require('taddy');
13 |
14 | const {EVAL_FILENAME_POSTFIX} = require('./utils.cjs');
15 |
16 | // webpack "require" critical dependency issue workaround
17 | const nodeRequire = new Function(
18 | 'require',
19 | `return typeof require !== 'undefined'
20 | ? require
21 | : (typeof globalThis !== 'undefined' ? globalThis : global).require; `,
22 | )(module.require);
23 |
24 | const transformCode = async ({content, filename}) => {
25 | /** @type {import('@babel/core').TransformOptions} */
26 | const transformOptions = {
27 | filename,
28 | presets: DEFAULT_PRESETS,
29 | };
30 |
31 | // TODO: switch to async transform (need to support sync browser version)
32 | return transform(content, transformOptions);
33 | };
34 |
35 | const evaluate = async ({content, filename, callbackName}) => {
36 | const ext = path.extname(filename);
37 | const basename = path.basename(filename, ext);
38 | const dirname = path.dirname(filename);
39 | const evalFilename = path.join(
40 | dirname,
41 | basename + EVAL_FILENAME_POSTFIX + ext,
42 | );
43 |
44 | const {code} = await transformCode({content, filename: evalFilename});
45 |
46 | if (!code) return {error: new Error('TRANSPILATION_ERROR')};
47 |
48 | // console.log({code});
49 |
50 | const exec = new Function('require', callbackName, code);
51 |
52 | let value;
53 | try {
54 | const currentTarget = config.unstable_target;
55 |
56 | config({unstable_target: 'compiler'});
57 | exec(
58 | (filepath) => {
59 | const requirePath = resolve.sync(filepath, {
60 | extensions: EXTENSIONS,
61 | basedir: path.dirname(filename),
62 | });
63 |
64 | return nodeRequire(requirePath);
65 | },
66 | (result) => {
67 | value = result;
68 | },
69 | );
70 | config({unstable_target: currentTarget});
71 |
72 | // console.log('eval success', value);
73 | } catch (error) {
74 | // console.log('eval error', error);
75 |
76 | return {error};
77 | }
78 |
79 | // console.log('VALUE', {value});
80 |
81 | // for some reason, there is an additional ":" prefix on deserialisation/serialisation
82 | // for example, {':hover': {color: 'red'}} becomes {'::hover': {color: 'red'}}
83 | return {value: JSON.stringify(value)};
84 | };
85 |
86 | module.exports = () => {
87 | registerPreset('@babel/env', require('@babel/preset-env'));
88 | registerPreset('@babel/typescript', require('@babel/preset-typescript'));
89 |
90 | if (!process.version.bun) {
91 | require('@babel/register')({
92 | ignore: [
93 | (filename) => {
94 | // consider symlinks
95 | const realpath = fs.realpathSync(filename);
96 |
97 | if (realpath.includes('node_modules')) return true;
98 |
99 | return false;
100 | },
101 | ],
102 | presets: DEFAULT_PRESETS,
103 | cache: false,
104 | extensions: EXTENSIONS,
105 | });
106 | }
107 |
108 | return evaluate;
109 | };
110 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/helpers/getObjectPropertyKey.ts:
--------------------------------------------------------------------------------
1 | import * as t from '@babel/types';
2 | import type {NodePath} from '@babel/traverse';
3 |
4 | export function getObjectPropertyKey(path: NodePath) {
5 | if (path.isIdentifier()) {
6 | return path.node.name;
7 | }
8 |
9 | if (path.isLiteral() && 'value' in path.node) {
10 | return String(path.node.value);
11 | }
12 |
13 | return null;
14 | }
15 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/helpers/mergeObjectProperties.ts:
--------------------------------------------------------------------------------
1 | import * as t from '@babel/types';
2 |
3 | type Properties = t.ObjectExpression['properties'];
4 |
5 | export function mergeObjectProperties(properties: Properties) {
6 | const map = new Map();
7 |
8 | function move(key, value) {
9 | map.delete(key);
10 | map.set(key, value);
11 | }
12 |
13 | for (const x of properties) {
14 | if (!t.isObjectProperty(x)) {
15 | move(x, x);
16 | continue;
17 | }
18 |
19 | const {key} = x;
20 |
21 | if (t.isIdentifier(key)) {
22 | move(key.name, x);
23 | continue;
24 | }
25 |
26 | if (t.isStringLiteral(key)) {
27 | move(key.value, x);
28 | continue;
29 | }
30 |
31 | move(x, x);
32 | }
33 |
34 | // TODO: there was a problem with typescript compiler with the variant [...map.values()]
35 |
36 | return Array.from(map.values());
37 | }
38 |
39 | export function mergeObjects(objects: t.ObjectExpression[]) {
40 | const properties: Properties = [];
41 | objects.forEach((obj) => {
42 | properties.push(...obj.properties);
43 | });
44 | return mergeObjectProperties(properties);
45 | }
46 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/helpers/optimizeStaticStyles.ts:
--------------------------------------------------------------------------------
1 | import * as t from '@babel/types';
2 |
3 | import type {NodePath} from '@babel/traverse';
4 |
5 | import {VARS_KEY} from '@taddy/core';
6 |
7 | import {getObjectPropertyKey} from './getObjectPropertyKey';
8 |
9 | export function optimizeStaticStyles(path: NodePath) {
10 | const props: t.ObjectProperty[] = [];
11 |
12 | let quasis: t.TemplateElement[] = [];
13 | let expressions: t.Expression[] = [];
14 |
15 | let currQuasi = '';
16 |
17 | for (const propPath of path.get('properties')) {
18 | if (!propPath.isObjectProperty()) {
19 | throw new Error('Cant optimize this path');
20 | }
21 |
22 | const keyPath = (propPath as NodePath).get('key');
23 | const key = getObjectPropertyKey(keyPath);
24 |
25 | if (!key) continue;
26 |
27 | const valuePath = (propPath as NodePath).get('value');
28 |
29 | if (key === 'className' || key === 'style' || key === VARS_KEY) {
30 | if (currQuasi) {
31 | quasis.push(t.templateElement({raw: currQuasi}));
32 |
33 | props.push(
34 | t.objectProperty(
35 | t.templateLiteral(quasis, expressions),
36 | t.booleanLiteral(true),
37 | ),
38 | );
39 | }
40 |
41 | props.push(propPath.node);
42 |
43 | quasis = [];
44 | expressions = [];
45 | currQuasi = '';
46 |
47 | continue;
48 | }
49 |
50 | // append " " delimiter for the continuous value or if that's not the first quasi
51 | if (currQuasi || quasis.length !== 0) {
52 | currQuasi += ' ';
53 | }
54 |
55 | if (valuePath.isStringLiteral()) {
56 | currQuasi += key + valuePath.node.value;
57 | } else if (valuePath.isBooleanLiteral()) {
58 | currQuasi += key;
59 | } else {
60 | currQuasi += key;
61 |
62 | quasis.push(t.templateElement({raw: currQuasi}));
63 | expressions.push(valuePath.node as t.Expression);
64 |
65 | currQuasi = '';
66 | }
67 | }
68 |
69 | if (currQuasi) {
70 | quasis.push(t.templateElement({raw: currQuasi}));
71 | }
72 |
73 | if (expressions.length === quasis.length) {
74 | quasis.push(t.templateElement({raw: ''}));
75 | }
76 |
77 | if (quasis.length) {
78 | if (props.length === 0) {
79 | path.replaceWith(t.templateLiteral(quasis, expressions));
80 |
81 | return;
82 | }
83 |
84 | props.push(
85 | t.objectProperty(
86 | t.templateLiteral(quasis, expressions),
87 | t.booleanLiteral(true),
88 | ),
89 | );
90 | }
91 |
92 | path.node.properties = props;
93 | }
94 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/helpers/taggedTemplateToObject.ts:
--------------------------------------------------------------------------------
1 | import * as t from '@babel/types';
2 | import type {NodePath} from '@babel/traverse';
3 |
4 | export function taggedTemplateToObject(
5 | path: NodePath,
6 | ): t.ObjectExpression {
7 | const postcss = require('postcss');
8 | const postcssJS = require('postcss-js');
9 | const {quasis, expressions} = path.node.quasi;
10 |
11 | type Expression = (typeof expressions)[number];
12 |
13 | const cache: {[placeholder: string]: Expression} = {};
14 |
15 | // this tricky placeholder has special syntax to avoid any conflicts with css parsing
16 | const re = /@\^var__\w+__/;
17 | const getPlaceholder = (index) => `@^var__${index}__`;
18 |
19 | let pseudoCSS = '';
20 | for (let i = 0; i < quasis.length; i++) {
21 | pseudoCSS += quasis[i].value.raw;
22 | if (expressions[i]) {
23 | const placeholder = getPlaceholder(i);
24 | cache[placeholder] = expressions[i];
25 | pseudoCSS += placeholder;
26 | }
27 | }
28 |
29 | const root = postcss.parse(pseudoCSS);
30 | const CSSObject = postcssJS.objectify(root);
31 |
32 | function parseString(str) {
33 | const expr: Expression[] = [];
34 | str.replace(new RegExp(re, 'g'), (match) => {
35 | expr.push(cache[match]);
36 | });
37 |
38 | if (expr.length === 0) {
39 | return t.stringLiteral(str);
40 | }
41 |
42 | return t.templateLiteral(
43 | str.split(re).map((q) => t.templateElement({raw: q, cooked: q})),
44 | expr,
45 | );
46 | }
47 |
48 | function traverse(obj: object): t.ObjectExpression {
49 | const props: t.ObjectExpression['properties'] = [];
50 |
51 | for (const key in obj) {
52 | const value = obj[key];
53 |
54 | if (value === true) {
55 | props.push(t.spreadElement(cache[key] as t.Expression));
56 |
57 | continue;
58 | }
59 |
60 | const cssKey = key.replace(/^&/, '');
61 |
62 | const keyNode = parseString(cssKey);
63 | let valueNode;
64 |
65 | if (typeof value === 'object') {
66 | valueNode = traverse(value);
67 | } else {
68 | valueNode = parseString(String(value));
69 | }
70 |
71 | props.push(
72 | t.objectProperty(
73 | keyNode,
74 | valueNode,
75 | !t.isStringLiteral(keyNode),
76 | ),
77 | );
78 | }
79 |
80 | return t.objectExpression(props);
81 | }
82 |
83 | return traverse(CSSObject);
84 | }
85 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/helpers/utils.cjs:
--------------------------------------------------------------------------------
1 | const EVAL_FILENAME_POSTFIX = '@__TADDY_EVALUATE__';
2 |
3 | /**
4 | * @param {import('@babel/core').PluginPass} state
5 | * @returns {boolean}
6 | */
7 | function isTaddyEvaluation(state) {
8 | return !!state.filename?.includes(EVAL_FILENAME_POSTFIX);
9 | }
10 |
11 | module.exports = {EVAL_FILENAME_POSTFIX, isTaddyEvaluation};
12 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/index.ts:
--------------------------------------------------------------------------------
1 | import plugin from './plugin';
2 |
3 | export default plugin;
4 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/plugin.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | types as t,
3 | PluginPass,
4 | NodePath,
5 | ConfigAPI,
6 | PluginObj,
7 | } from '@babel/core';
8 | import type {NodePaths} from '@babel/traverse';
9 |
10 | import {PACKAGE_NAME, getEnv} from './config';
11 | import * as utils from './helpers/utils.cjs';
12 | import {macro, type MacroConfig} from './macro-plugin';
13 |
14 | type ImportSpecifiers = NodePaths;
15 |
16 | function getImportNames(path: ImportSpecifiers[number]): {
17 | localName: string;
18 | importedName: string;
19 | } {
20 | const localName = path.node.local.name;
21 |
22 | if (path.isImportSpecifier()) {
23 | const imported = path.node.imported as t.Identifier;
24 |
25 | return {
26 | localName,
27 | importedName: imported.name,
28 | };
29 | }
30 |
31 | if (path.isImportDefaultSpecifier()) {
32 | return {localName, importedName: 'default'};
33 | }
34 |
35 | return {localName, importedName: 'namespace'};
36 | }
37 |
38 | function findReferences(paths: ImportSpecifiers) {
39 | const references = {};
40 | for (const path of paths) {
41 | const {localName, importedName} = getImportNames(path);
42 | const binding = path.scope.getBinding(localName);
43 | if (binding?.referencePaths) {
44 | references[importedName] = binding.referencePaths;
45 | }
46 | }
47 | return references;
48 | }
49 |
50 | interface TaddyPluginPass extends PluginPass {
51 | references: Record;
52 | }
53 |
54 | export default function plugin(
55 | babel: ConfigAPI,
56 | options: MacroConfig,
57 | ): PluginObj {
58 | const env = getEnv(babel);
59 |
60 | return {
61 | name: '@taddy/babel-plugin',
62 |
63 | pre() {
64 | this.references = {};
65 | },
66 |
67 | visitor: {
68 | // TODO: support require expression
69 |
70 | ImportDeclaration(path, state) {
71 | // console.log('run', state.file.code, state.filename);
72 |
73 | if (utils.isTaddyEvaluation(state)) {
74 | return;
75 | }
76 |
77 | if (path.node.source.value !== PACKAGE_NAME) {
78 | return;
79 | }
80 |
81 | Object.assign(
82 | this.references,
83 | findReferences(path.get('specifiers')),
84 | );
85 |
86 | if (!(this.references.css || this.references.mixin)) {
87 | return;
88 | }
89 |
90 | macro({
91 | references: this.references,
92 | babel,
93 | state,
94 | config: {
95 | env,
96 | ...options,
97 | },
98 | });
99 | },
100 | },
101 | };
102 | }
103 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/source-maps.ts:
--------------------------------------------------------------------------------
1 | // @flow
2 | import {SourceMapGenerator} from 'source-map';
3 | import * as convert from 'convert-source-map';
4 |
5 | export {SourceMapGenerator};
6 |
7 | export function getGeneratorOpts(file) {
8 | return file.opts.generatorOpts ? file.opts.generatorOpts : file.opts;
9 | }
10 |
11 | // export function makeSourceMapGenerator(file) {
12 | // const generator = new SourceMapGenerator();
13 |
14 | // return generator;
15 | // }
16 |
17 | export function makeSourceMapGenerator(file) {
18 | const generatorOpts = getGeneratorOpts(file);
19 | const filename = generatorOpts.sourceFileName;
20 | const generator = new SourceMapGenerator({
21 | file: filename,
22 | sourceRoot: generatorOpts.sourceRoot,
23 | });
24 |
25 | // console.log('root', generatorOpts.sourceRoot);
26 |
27 | generator.setSourceContent(filename, file.code);
28 | return generator;
29 | }
30 |
31 | export function convertGeneratorToComment(generator) {
32 | return convert.fromObject(generator).toComment({multiline: true});
33 | }
34 |
35 | export function getSourceMap(
36 | offset: {
37 | line: number;
38 | column: number;
39 | },
40 | state,
41 | ): string {
42 | const generator = makeSourceMapGenerator(state.file);
43 | const generatorOpts = getGeneratorOpts(state.file);
44 | if (
45 | generatorOpts.sourceFileName &&
46 | generatorOpts.sourceFileName !== 'unknown'
47 | ) {
48 | generator.addMapping({
49 | generated: {
50 | line: 1,
51 | column: 0,
52 | },
53 | source: generatorOpts.sourceFileName,
54 | original: offset,
55 | });
56 | return convert.fromObject(generator).toComment({multiline: true});
57 | }
58 | return '';
59 | }
60 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/tests/common.ts:
--------------------------------------------------------------------------------
1 | import {transformAsync, createConfigItem} from '@babel/core';
2 | import type {TransformOptions} from '@babel/core';
3 |
4 | import {stripIndent} from 'common-tags';
5 |
6 | import {$css, StyleSheet} from 'taddy';
7 |
8 | import taddyPlugin from '../plugin';
9 | import type {MacroConfig} from '../macro-plugin';
10 |
11 | export {PACKAGE_NAME} from '../config';
12 |
13 | export function getStyles(): string {
14 | return [...$css.ruleInjector.styleSheet.rules]
15 | .map((rule) => rule.cssText)
16 | .join('\n');
17 | }
18 |
19 | export function resetStyles() {
20 | if ($css.ruleInjector.styleSheet instanceof StyleSheet) {
21 | $css.ruleInjector.styleSheet.node.remove();
22 | }
23 |
24 | $css.ruleInjector.reset();
25 | }
26 |
27 | export const getBabelOptions = (
28 | options: MacroConfig = {},
29 | ): TransformOptions => ({
30 | filename: `test.virtual.tsx`,
31 | babelrc: false,
32 | configFile: false,
33 | plugins: [
34 | ['@babel/plugin-syntax-typescript', {isTSX: true}],
35 |
36 | createConfigItem((babel) =>
37 | taddyPlugin(babel, {
38 | compileOptions: {
39 | evaluate: false,
40 | unstable_typescript: false,
41 | ...options.compileOptions,
42 | },
43 | outputOptions: {
44 | ...options.outputOptions,
45 | },
46 | }),
47 | ),
48 | ],
49 | });
50 |
51 | type Optional = T | null | void;
52 |
53 | export async function transform(
54 | code: string,
55 | babelOptions?: MacroConfig,
56 | transformOptions?: TransformOptions,
57 | ): Promise> {
58 | return (
59 | await transformAsync(stripIndent(code), {
60 | ...getBabelOptions(babelOptions),
61 | ...transformOptions,
62 | })
63 | )?.code;
64 | }
65 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/tests/data/mixins.ts:
--------------------------------------------------------------------------------
1 | import {css} from 'taddy';
2 |
3 | export const box = css.mixin({fontWeight: 'bold'});
4 |
5 | export const typo = css.mixin({lineHeight: 1, ':hover': {color: 'red'}});
6 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/tests/typescript.test.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 |
3 | import {PACKAGE_NAME, transform, getStyles, resetStyles} from './common';
4 |
5 | const options = {
6 | compileOptions: {unstable_typescript: true},
7 | };
8 |
9 | describe('taddy.macro.typescript', () => {
10 | beforeEach((done) => {
11 | resetStyles();
12 |
13 | done();
14 | });
15 |
16 | // TODO: fix the filename consistency between local/CI tests
17 | test.skip('typed mixins', async () => {
18 | expect(
19 | await transform(
20 | `
21 | import {css} from '${PACKAGE_NAME}'
22 |
23 | function box({direction = 'column' as D}: {direction?: D}) {
24 | return css.mixin({
25 | display: 'flex',
26 | flexDirection: direction,
27 | captionSide: 'block-end',
28 |
29 | composes: [
30 | css.mixin({':hover': {
31 | color: 'red',
32 | }}),
33 |
34 | css.mixin({':focus': {
35 | border: '1px solid red',
36 | }}),
37 | ],
38 | });
39 | }
40 |
41 | export default css({
42 | ...box({direction: 'row'}),
43 | })
44 | `,
45 | options,
46 | {filename: './test.infer-mixins.tsx'},
47 | ),
48 | ).toMatchInlineSnapshot(`
49 | "import { css } from "@taddy/core";
50 | import ".cache/taddy/kukjmn/1rx2e9b.taddy.css";
51 | export default css(\`_rnbphe_1vf95 _-g4lbay_2fa2 _-wnpzmr_eeql5n _t3u24i_1kgt43_2f0x _t2q38e_-mvl0b8_2c7gol\`, "__1p9m90k");"
52 | `);
53 |
54 | expect(getStyles()).toMatchInlineSnapshot(`
55 | "._rnbphe_1vf95 { display: flex; }
56 | ._-g4lbay_2fa2 { flex-direction: row; }
57 | ._-wnpzmr_eeql5n { caption-side: block-end; }
58 | ._t3u24i_1kgt43_2f0x:hover { color: red; }
59 | ._t2q38e_-mvl0b8_2c7gol:focus { border: 1px solid red; }"
60 | `);
61 | });
62 |
63 | // TODO: fix the filename consistency between local/CI tests
64 | test.skip('should support infer types', async () => {
65 | expect(
66 | await transform(
67 | `
68 | import {css} from '${PACKAGE_NAME}'
69 | import {box, typo} from '@taddy/babel-plugin/src/tests/data/mixins'
70 |
71 | function mixin(size: T) {
72 | return css.mixin({
73 | ...box,
74 | ...typo,
75 | display: 'flex',
76 | fontSize: size
77 | })
78 | }
79 |
80 | const display = 'flex'
81 |
82 | export default css({
83 | ...mixin('smaller'),
84 | ...box,
85 | ...typo,
86 | color: 'red',
87 | display,
88 | })
89 | `,
90 | options,
91 | {filename: './test.infer-types.tsx'},
92 | ),
93 | ).toMatchInlineSnapshot(`
94 | "import { css } from "@taddy/core";
95 | import ".cache/taddy/o2loos/hqitgk.taddy.css";
96 | export default css("_-q8b8sh_-yoym18 _9wido6_1sxol _-k3s8v4_1d _t3u24i_1kgt43_2f0x _1kgt43_2f0x _rnbphe_1vf95", "__2hq8osn");"
97 | `);
98 |
99 | expect(getStyles()).toMatchInlineSnapshot(`
100 | "._rnbphe_1vf95 { display: flex; }
101 | ._-q8b8sh_-yoym18 { font-size: smaller; }
102 | ._-k3s8v4_1d { line-height: 1; }
103 | ._t3u24i_1kgt43_2f0x:hover,._1kgt43_2f0x { color: red; }
104 | ._9wido6_1sxol { font-weight: bold; }"
105 | `);
106 | });
107 | });
108 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/src/types.ts:
--------------------------------------------------------------------------------
1 | export type Env = 'development' | 'production' | 'test';
2 |
3 | export type Target = 'auto' | 'vue' | 'remix';
4 |
--------------------------------------------------------------------------------
/@taddy/babel-plugin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "lib",
5 | "module": "CommonJS",
6 |
7 | "baseUrl": ".",
8 | "rootDir": "."
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/@taddy/core/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .DS_Store
3 |
4 | node_modules
5 |
6 | dist
7 | *.code-workspace
8 | .vscode
9 | .cache
10 |
11 | !packages/taddy/.cache
12 | taddy.css
13 |
14 | .vercel
15 |
16 | *.tsbuildinfo
17 |
--------------------------------------------------------------------------------
/@taddy/core/NameGenerator/index.ts:
--------------------------------------------------------------------------------
1 | import {isInvalidValue} from '../common';
2 |
3 | function hash(s: string) {
4 | let h = 0;
5 | for (let i = 0; i < s.length; i++)
6 | h = (Math.imul(31, h) + s.charCodeAt(i)) | 0;
7 |
8 | return h.toString(36);
9 | }
10 |
11 | type NameOptions = {
12 | postfix?: string;
13 | at?: {query?: string; name: string};
14 | };
15 |
16 | function generateHash(value: string) {
17 | // if (__DEV__) {
18 | // const cssesc = require('cssesc');
19 | // return cssesc(value, {isIdentifier: true}).replace(/\s/g, '-');
20 | // }
21 |
22 | return hash(String(value));
23 | }
24 |
25 | export class NameGenerator {
26 | cache: {[name: string]: string} = {};
27 |
28 | getHash = (value?: string): string => {
29 | if (isInvalidValue(value)) return '';
30 | if (value[0] === '_') return value;
31 |
32 | const key = `_${value}`;
33 |
34 | if (!(key in this.cache)) {
35 | this.cache[key] = generateHash(value);
36 | }
37 |
38 | return `_${this.cache[key]}`;
39 | };
40 |
41 | getName = (
42 | prop: string,
43 | value: string,
44 | {postfix = '', at}: NameOptions = {},
45 | ) => {
46 | return [
47 | this.getHash(at?.name),
48 | this.getHash(at?.query),
49 | this.getHash(postfix),
50 | this.getHash(prop),
51 | this.getHash(value),
52 | ] as const;
53 | };
54 | }
55 |
--------------------------------------------------------------------------------
/@taddy/core/README.md:
--------------------------------------------------------------------------------
1 | # @taddy/core
2 |
--------------------------------------------------------------------------------
/@taddy/core/common.ts:
--------------------------------------------------------------------------------
1 | export const VARS_KEY = '__VARS__';
2 |
3 | export const MIXIN_KEY = Symbol('__MIXIN__');
4 |
5 | export const ID_KEY = Symbol('ID_KEY');
6 |
7 | type InvalidValue = '' | false | null | void;
8 | export function isInvalidValue(value: any): value is InvalidValue {
9 | return !(!!value || value === 0);
10 | }
11 |
--------------------------------------------------------------------------------
/@taddy/core/config.ts:
--------------------------------------------------------------------------------
1 | import {NameGenerator} from './NameGenerator';
2 |
3 | const nameGenerator = new NameGenerator();
4 |
5 | type MapStylesOpts = {className: string; style?: object};
6 |
7 | export type TaddyConfig = {
8 | nameGenerator: NameGenerator;
9 |
10 | /** map "style" and "className" to the needed value */
11 | unstable_mapStyles: (value: MapStylesOpts) => any;
12 |
13 | /** can be used to pregenarate atoms */
14 | unstable_properties?: {
15 | [key: string]:
16 | | void
17 | | string
18 | | number
19 | | object
20 | | ((...args: any[]) => object | string | number | null);
21 | };
22 |
23 | unstable_target?: 'react' | 'react-native' | 'vue' | 'svelte' | 'compiler';
24 | };
25 |
26 | type ValidatedShape = T & {
27 | [key in keyof T]: key extends keyof Shape ? T[key] : never;
28 | };
29 |
30 | declare function setConfig>(
31 | value: ValidatedShape,
32 | ): T;
33 |
34 | export const config: typeof setConfig & TaddyConfig = Object.assign(
35 | >(value: T) => {
36 | Object.assign(config, value);
37 | return value;
38 | },
39 | {
40 | nameGenerator,
41 | unstable_mapStyles: (x: MapStylesOpts) => x,
42 | },
43 | );
44 |
--------------------------------------------------------------------------------
/@taddy/core/h.ts:
--------------------------------------------------------------------------------
1 | import {config} from './config';
2 |
3 | export const h = (x: any) => config.nameGenerator.getHash(x);
4 |
--------------------------------------------------------------------------------
/@taddy/core/index.test.ts:
--------------------------------------------------------------------------------
1 | import {expect, describe, it} from '@jest/globals';
2 |
3 | import {config, css} from '.';
4 |
5 | const getClassName = (key, value) =>
6 | config.nameGenerator.getName(key, value).join('');
7 |
8 | describe('@taddy/core', () => {
9 | it('should merge styles', () => {
10 | const elem = css(
11 | `${getClassName('color', 'red')} ${getClassName(
12 | 'background',
13 | 'blue',
14 | )}`,
15 | '__id1 _',
16 | );
17 |
18 | expect(
19 | css(
20 | {
21 | ...elem,
22 | [getClassName('color', 'blue')]: true,
23 | },
24 | '__id2',
25 | ).className,
26 | ).toEqual(
27 | `${getClassName('color', 'blue')} ${getClassName(
28 | 'background',
29 | 'blue',
30 | )} __id1 __id2 _`,
31 | );
32 |
33 | expect(
34 | css(
35 | {
36 | [getClassName('color', 'blue')]: true,
37 | ...elem,
38 | },
39 | '__id2',
40 | ).className,
41 | ).toEqual(
42 | `${getClassName('color', 'red')} ${getClassName(
43 | 'background',
44 | 'blue',
45 | )} __id1 __id2 _`,
46 | );
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/@taddy/core/index.ts:
--------------------------------------------------------------------------------
1 | export {NameGenerator} from './NameGenerator';
2 |
3 | export * from './static';
4 | export * from './common';
5 | export * from './config';
6 | export * from './h';
7 |
--------------------------------------------------------------------------------
/@taddy/core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@taddy/core",
3 | "version": "0.1.0-alpha.3",
4 | "author": "Kenzhaev Artur ",
5 | "license": "MIT",
6 | "main": "lib/index.cjs",
7 | "module": "lib/index.js",
8 | "publishConfig": {
9 | "access": "public"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/lttb/taddy.git"
14 | },
15 | "scripts": {
16 | "clean": "rm -rf lib",
17 | "check:ts": "tsc --noEmit",
18 | "compile": "rollup -c --bundleConfigAsCjs",
19 | "prestart": "yarn clean",
20 | "start": "yarn compile --watch",
21 | "prebuild": "yarn clean",
22 | "build": "yarn compile"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/@taddy/core/rollup.config.js:
--------------------------------------------------------------------------------
1 | import commonConfig from '../../rollup.config.common';
2 |
3 | const config = {
4 | ...commonConfig,
5 |
6 | input: ['index.ts'],
7 | };
8 |
9 | export default config;
10 |
--------------------------------------------------------------------------------
/@taddy/core/static/index.ts:
--------------------------------------------------------------------------------
1 | import {VARS_KEY, MIXIN_KEY, ID_KEY} from '../common';
2 |
3 | import {config} from '../config';
4 |
5 | export const staticCache = {};
6 | export const mapStaticClassName = (className?: string): object => {
7 | if (!className) return {};
8 | const v = staticCache[className];
9 | if (v) return v;
10 | return (staticCache[className] = className.split(' ').reduce((acc, v) => {
11 | if (v === '_') return acc;
12 |
13 | // ignore classes which don't have '_' prefix or have '__' prefix
14 | if (v[0] !== '_' || v[1] === '_') {
15 | acc[v] = true;
16 | return acc;
17 | }
18 |
19 | const hashes = v.split('_');
20 | if (hashes.length === 2) {
21 | acc[v] = true;
22 | } else {
23 | const lastHash = hashes.pop();
24 | acc[hashes.join('_')] = '_' + lastHash;
25 | }
26 |
27 | return acc;
28 | }, {}));
29 | };
30 |
31 | export const joinClassName = (className: object): string => {
32 | let classNameString = '';
33 | for (const key in className) {
34 | if (!className[key]) continue;
35 |
36 | classNameString += (classNameString ? ' ' : '') + key;
37 | if (typeof className[key] === 'string') {
38 | classNameString += className[key];
39 | }
40 | }
41 | return classNameString;
42 | };
43 |
44 | export const withId = (result, id?: string | void) => {
45 | if (!result) return result;
46 |
47 | /**
48 | * For the reference between different styles
49 | */
50 | const value =
51 | id || '__' + config.nameGenerator.getHash('id' + result.className);
52 |
53 | result[ID_KEY] = value;
54 | result[Symbol?.toPrimitive || 'toString'] = () => '.' + value;
55 | result.className += (result.className ? ' ' : '') + value;
56 |
57 | // append "_" to the final className to maintain specificity
58 | result.className += ' _';
59 |
60 | return result;
61 | };
62 |
63 | const _css = (
64 | rule?:
65 | | string
66 | | Partial<{
67 | className: string;
68 | style: object;
69 | [VARS_KEY]: object;
70 | [key: string]: any;
71 | }>,
72 | id?: string,
73 | ): {className: string; style?: object} => {
74 | if (!rule) return {className: ''};
75 |
76 | if (typeof rule === 'string') {
77 | return withId({className: rule}, id);
78 | }
79 |
80 | const result: any = {className: ''};
81 |
82 | let style;
83 |
84 | const className = {};
85 |
86 | for (const key in rule) {
87 | if (!rule[key]) continue;
88 |
89 | if (rule[key] === true) {
90 | Object.assign(className, mapStaticClassName(key));
91 |
92 | continue;
93 | }
94 | if (key === 'className') {
95 | Object.assign(className, mapStaticClassName(rule[key]));
96 |
97 | continue;
98 | }
99 | if (key === 'style' || key === VARS_KEY) {
100 | Object.assign((style = style || {}), rule[key]);
101 |
102 | continue;
103 | }
104 | }
105 |
106 | result.className = joinClassName(className);
107 |
108 | if (style) {
109 | result.style = style;
110 | }
111 |
112 | return withId(result, id);
113 | };
114 |
115 | export const css = (
116 | ...args: Parameters
117 | ): ReturnType => config.unstable_mapStyles(_css(...args));
118 |
119 | css.h = (x) => config.nameGenerator.getHash(x);
120 | // eslint-disable-next-line no-sequences
121 | css.mixin = (x: object) => ((x[MIXIN_KEY] = _css(x)), x);
122 |
123 | css.static = css;
124 | // @ts-expect-error TODO: fix
125 | css.mixin.static = css.mixin;
126 |
127 | export function $(strs: TemplateStringsArray, ...values: any[]): string {
128 | let selector = '';
129 | strs.forEach((chunk, index) => {
130 | selector += chunk;
131 | if (values[index]) {
132 | selector += '.' + values[index][ID_KEY];
133 | }
134 | });
135 | return selector;
136 | }
137 |
--------------------------------------------------------------------------------
/@taddy/core/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "lib",
5 |
6 | "baseUrl": "."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/@taddy/esbuild-plugin/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | # 0.1.0-alpha.1 (2023-03-19)
7 |
8 | ### Features
9 |
10 | - **esbuild-plugin:** initial implementation ([3635a81](https://github.com/lttb/taddy/commit/3635a816605821caae0800f77680cb0db42a1fdf))
11 | - make it work with vue jsx ([334939e](https://github.com/lttb/taddy/commit/334939e203f5e5a5a6afd34ec093eee429e490cc))
12 |
--------------------------------------------------------------------------------
/@taddy/esbuild-plugin/index.js:
--------------------------------------------------------------------------------
1 | const babel = require('@babel/core');
2 | const taddyBabelPlugin = require('@taddy/babel-plugin');
3 | const fs = require('fs');
4 | const path = require('path');
5 |
6 | function taddyPlugin() {
7 | /** @type {import('esbuild').Plugin} */
8 | const plugin = {
9 | name: '@taddy/esbuild-plugin',
10 | setup({onLoad}) {
11 | const root = process.cwd();
12 |
13 | onLoad({filter: /\.[tj]sx$/}, async (args) => {
14 | const id = args.path;
15 |
16 | if (id.includes('.taddy.js')) return;
17 |
18 | const code = await fs.promises.readFile(id, 'utf8');
19 |
20 | const extname = path.extname(id);
21 |
22 | const isTypescript = extname === '.tsx' || extname === '.ts';
23 |
24 | const result = await babel.transformAsync(code, {
25 | babelrc: false,
26 | configFile: false,
27 | ast: false,
28 | root,
29 | filename: id,
30 | parserOpts: {
31 | allowAwaitOutsideFunction: true,
32 | plugins: [
33 | 'importMeta',
34 | 'topLevelAwait',
35 | 'classProperties',
36 | 'classPrivateProperties',
37 | 'classPrivateMethods',
38 | 'jsx',
39 | ].concat(isTypescript ? ['typescript'] : []),
40 | },
41 | generatorOpts: {
42 | decoratorsBeforeExport: true,
43 | },
44 | plugins: [taddyBabelPlugin],
45 | sourceMaps: true,
46 | inputSourceMap: false,
47 | });
48 |
49 | return {
50 | contents:
51 | result.code +
52 | `//# sourceMappingURL=data:application/json;base64,` +
53 | Buffer.from(JSON.stringify(result.map)).toString(
54 | 'base64',
55 | ),
56 | loader: isTypescript ? 'tsx' : 'jsx',
57 | resolveDir: path.dirname(id),
58 | };
59 | });
60 | },
61 | };
62 |
63 | return plugin;
64 | }
65 |
66 | module.exports = taddyPlugin;
67 |
--------------------------------------------------------------------------------
/@taddy/esbuild-plugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "@taddy/esbuild-plugin",
4 | "version": "0.1.0-alpha.1",
5 | "author": "Kenzhaev Artur ",
6 | "license": "MIT",
7 | "main": "index.js",
8 | "publishConfig": {
9 | "access": "public"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/lttb/taddy.git"
14 | },
15 | "dependencies": {
16 | "@taddy/babel-plugin": "^0.1.0-alpha.1"
17 | },
18 | "devDependencies": {
19 | "esbuild": "^0.17.12"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/@taddy/esbuild-plugin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "lib",
5 |
6 | "baseUrl": "."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/@taddy/next-plugin/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | # [0.1.0-alpha.12](https://github.com/lttb/taddy/compare/@taddy/next-plugin@0.1.0-alpha.11...@taddy/next-plugin@0.1.0-alpha.12) (2024-04-10)
7 |
8 | ### Bug Fixes
9 |
10 | - **next-plugin:** fix bun check ([7e44b92](https://github.com/lttb/taddy/commit/7e44b9268345e8a63079536be56e162603724989))
11 |
12 | # [0.1.0-alpha.11](https://github.com/lttb/taddy/compare/@taddy/next-plugin@0.1.0-alpha.10...@taddy/next-plugin@0.1.0-alpha.11) (2024-04-10)
13 |
14 | ### Features
15 |
16 | - **next-plugin:** import typescript module for bun ([cfe799b](https://github.com/lttb/taddy/commit/cfe799bea7b92c5fa692dd8646b979309b13194d))
17 |
18 | # [0.1.0-alpha.10](https://github.com/lttb/taddy/compare/@taddy/next-plugin@0.1.0-alpha.9...@taddy/next-plugin@0.1.0-alpha.10) (2024-04-10)
19 |
20 | **Note:** Version bump only for package @taddy/next-plugin
21 |
22 | # [0.1.0-alpha.9](https://github.com/lttb/taddy/compare/@taddy/next-plugin@0.1.0-alpha.8...@taddy/next-plugin@0.1.0-alpha.9) (2024-04-10)
23 |
24 | **Note:** Version bump only for package @taddy/next-plugin
25 |
26 | # [0.1.0-alpha.8](https://github.com/lttb/taddy/compare/@taddy/next-plugin@0.1.0-alpha.7...@taddy/next-plugin@0.1.0-alpha.8) (2024-03-18)
27 |
28 | **Note:** Version bump only for package @taddy/next-plugin
29 |
30 | # [0.1.0-alpha.7](https://github.com/lttb/taddy/compare/@taddy/next-plugin@0.1.0-alpha.6...@taddy/next-plugin@0.1.0-alpha.7) (2023-06-05)
31 |
32 | **Note:** Version bump only for package @taddy/next-plugin
33 |
34 | # [0.1.0-alpha.6](https://github.com/lttb/taddy/compare/@taddy/next-plugin@0.1.0-alpha.5...@taddy/next-plugin@0.1.0-alpha.6) (2023-06-05)
35 |
36 | **Note:** Version bump only for package @taddy/next-plugin
37 |
38 | # [0.1.0-alpha.5](https://github.com/lttb/taddy/compare/@taddy/next-plugin@0.1.0-alpha.4...@taddy/next-plugin@0.1.0-alpha.5) (2023-04-30)
39 |
40 | **Note:** Version bump only for package @taddy/next-plugin
41 |
42 | # [0.1.0-alpha.4](https://github.com/lttb/taddy/compare/@taddy/next-plugin@0.1.0-alpha.3...@taddy/next-plugin@0.1.0-alpha.4) (2023-04-29)
43 |
44 | **Note:** Version bump only for package @taddy/next-plugin
45 |
46 | # [0.1.0-alpha.3](https://github.com/lttb/taddy/compare/@taddy/next-plugin@0.1.0-alpha.2...@taddy/next-plugin@0.1.0-alpha.3) (2023-04-14)
47 |
48 | ### Features
49 |
50 | - **next-plugin:** support mdx ([47d4a41](https://github.com/lttb/taddy/commit/47d4a41a502d491e11fa78d95fa902be09cab895))
51 |
52 | # [0.1.0-alpha.2](https://github.com/lttb/taddy/compare/@taddy/next-plugin@0.1.0-alpha.1...@taddy/next-plugin@0.1.0-alpha.2) (2023-04-05)
53 |
54 | ### Bug Fixes
55 |
56 | - **taddy/next-plugin:** add @babel/core as a dependency ([de352e2](https://github.com/lttb/taddy/commit/de352e29aa00c8af0a4460756a9d2ef3665c6031))
57 |
58 | ### Features
59 |
60 | - **taddy/next-plugin:** add lib ([a0f89d2](https://github.com/lttb/taddy/commit/a0f89d29ebd1fde3c8120660f842f2323d008e1d))
61 |
62 | # 0.1.0-alpha.1 (2023-04-05)
63 |
64 | ### Bug Fixes
65 |
66 | - **taddy/next-plugin:** use taddy subdir in .next ([d855ea0](https://github.com/lttb/taddy/commit/d855ea094747ceac849dc7e7fd79345b84b7f2f5))
67 |
68 | ### Features
69 |
70 | - **next-plugin:** make next-plugin public ([75ccabf](https://github.com/lttb/taddy/commit/75ccabf9aac3d11d2aafe378011003178f96c9dd))
71 | - **taddy/next-plugin:** initial implementation ([7b6963a](https://github.com/lttb/taddy/commit/7b6963aec98c9d369b6d2cc64078b9102e14b797))
72 | - **taddy/next-plugin:** pass options to babel plugin ([3ce8489](https://github.com/lttb/taddy/commit/3ce8489b971a801671f5a4abd4a5a251b328bac1))
73 | - **taddy/next-plugin:** support .next for caching ([0ffd051](https://github.com/lttb/taddy/commit/0ffd051fb3e2491da0a5ea1b807ea5b67c091714))
74 |
--------------------------------------------------------------------------------
/@taddy/next-plugin/index.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | /** @param {{}} [pluginOptions] */
4 | module.exports = function (pluginOptions = {}) {
5 | /** @param {import('next').NextConfig} nextConfig */
6 | return (nextConfig) => {
7 | /** @type {import('next').NextConfig} */
8 | const config = {
9 | webpack(config, options) {
10 | const {dev, dir} = options;
11 |
12 | const taddyOptions = {
13 | ...pluginOptions,
14 | outputOptions: {
15 | cacheDir: path.join(dir, '.next/cache/taddy'),
16 |
17 | ...pluginOptions.outputOptions,
18 | },
19 | };
20 |
21 | if (!dev) {
22 | // @see https://github.com/webpack-contrib/mini-css-extract-plugin#extracting-all-css-in-a-single-file
23 | config.optimization.splitChunks.cacheGroups = {
24 | ...config.optimization.splitChunks.cacheGroups,
25 | styles: {
26 | name: 'styles',
27 | type: 'css/mini-extract',
28 | test: /\.taddy\.css$/,
29 | chunks: 'all',
30 | enforce: true,
31 | },
32 | };
33 | }
34 |
35 | config.module.rules.push({
36 | test: /\.(tsx|ts|js|mjs|jsx|mdx|md)$/,
37 | exclude: /node_modules/,
38 | use: {
39 | loader: require.resolve('./loader.cjs'),
40 | options: taddyOptions,
41 | },
42 | });
43 |
44 | const cssRules = config.module.rules.find(
45 | (rule) =>
46 | Array.isArray(rule.oneOf) &&
47 | rule.oneOf.some(({test}) => test.test?.('global.css')),
48 | ).oneOf;
49 |
50 | let globalCSSLoader;
51 | for (const rule of cssRules) {
52 | if (rule.test.test?.('global.css') && rule.sideEffects) {
53 | globalCSSLoader = rule;
54 |
55 | break;
56 | }
57 | }
58 |
59 | if (globalCSSLoader) {
60 | cssRules.unshift({
61 | test: /\.taddy\.css$/i,
62 | sideEffects: true,
63 | use: globalCSSLoader.use,
64 | });
65 | }
66 |
67 | if (typeof nextConfig.webpack === 'function') {
68 | return nextConfig.webpack(config, options);
69 | }
70 |
71 | return config;
72 | },
73 | };
74 |
75 | return Object.assign({}, nextConfig, config);
76 | };
77 | };
78 |
--------------------------------------------------------------------------------
/@taddy/next-plugin/loader.cjs:
--------------------------------------------------------------------------------
1 | const babel = require('@babel/core');
2 | const taddyBabelPlugin = process.versions.bun
3 | ? // import typescript module for bun
4 | require('@taddy/babel-plugin/index')
5 | : require('@taddy/babel-plugin');
6 | const path = require('path');
7 |
8 | /** @type {import('webpack').LoaderDefinition} */
9 | const loader = function (code) {
10 | const callback = this.async();
11 | const id = this.resourcePath;
12 | const options = this.getOptions();
13 |
14 | if (id.includes('.taddy.js')) {
15 | callback(null, code);
16 |
17 | return;
18 | }
19 |
20 | const root = process.cwd();
21 |
22 | const extname = path.extname(id);
23 |
24 | const isTypescript = extname === '.tsx' || extname === '.ts';
25 |
26 | babel
27 | .transformAsync(code, {
28 | babelrc: false,
29 | configFile: false,
30 | ast: false,
31 | root,
32 | filename: id,
33 | parserOpts: {
34 | allowAwaitOutsideFunction: true,
35 | plugins: [
36 | 'importMeta',
37 | 'topLevelAwait',
38 | 'classProperties',
39 | 'classPrivateProperties',
40 | 'classPrivateMethods',
41 | 'jsx',
42 | ].concat(isTypescript ? ['typescript'] : []),
43 | },
44 | generatorOpts: {
45 | decoratorsBeforeExport: true,
46 | },
47 | plugins: [[taddyBabelPlugin, options]],
48 | sourceMaps: true,
49 | inputSourceMap: false,
50 | })
51 | .then((result) => {
52 | callback(null, result.code, result.map);
53 | })
54 | .catch((err) => {
55 | callback(err);
56 | });
57 | };
58 |
59 | module.exports = loader;
60 |
--------------------------------------------------------------------------------
/@taddy/next-plugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@taddy/next-plugin",
3 | "version": "0.1.0-alpha.12",
4 | "author": "Kenzhaev Artur ",
5 | "license": "MIT",
6 | "main": "index.js",
7 | "publishConfig": {
8 | "access": "public"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/lttb/taddy.git",
13 | "directory": "@taddy/next-plugin"
14 | },
15 | "scripts": {
16 | "clean": "rm -rf lib",
17 | "check:ts": "tsc --noEmit",
18 | "compile": "rollup -c --bundleConfigAsCjs",
19 | "prestart": "yarn clean",
20 | "start": "yarn compile --watch",
21 | "prebuild": "yarn clean",
22 | "build": "yarn compile"
23 | },
24 | "dependencies": {
25 | "@babel/core": "^7.0.0",
26 | "@taddy/babel-plugin": "^0.1.0-alpha.10"
27 | },
28 | "devDependencies": {
29 | "next": "13.2.4",
30 | "webpack": "^5.77.0"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/@taddy/next-plugin/rollup.config.js:
--------------------------------------------------------------------------------
1 | import commonConfig from '../../rollup.config.common';
2 |
3 | const config = {
4 | ...commonConfig,
5 |
6 | input: ['index.js', 'loader.cjs'],
7 | };
8 |
9 | export default config;
10 |
--------------------------------------------------------------------------------
/@taddy/next-plugin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "lib",
5 |
6 | "baseUrl": "."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/@taddy/vite-plugin/index.js:
--------------------------------------------------------------------------------
1 | const babel = require('@babel/core');
2 | const taddyBabelPlugin = require('@taddy/babel-plugin');
3 | const path = require('path');
4 |
5 | const SUPPORTED_EXTENSIONS = new Set(['.tsx', '.ts', '.jsx', '.js', '.astro']);
6 |
7 | /**
8 | * @param {object} options
9 | * @param {string} [options.unstable_target]
10 | **/
11 | function taddyPlugin({unstable_target} = {}) {
12 | /** @type {import('vite').Plugin} */
13 | const plugin = {
14 | name: '@taddy/vite-plugin',
15 |
16 | async transform(code, id) {
17 | if (id.includes('.taddy.js')) return;
18 |
19 | const extname = path.extname(id);
20 |
21 | if (!SUPPORTED_EXTENSIONS.has(extname)) {
22 | return;
23 | }
24 |
25 | const root = process.cwd();
26 |
27 | const isTypescript = extname === '.tsx' || extname === '.ts';
28 |
29 | const result = await babel.transformAsync(code, {
30 | babelrc: false,
31 | configFile: false,
32 | ast: false,
33 | root,
34 | filename: id,
35 | parserOpts: {
36 | allowAwaitOutsideFunction: true,
37 | plugins: [
38 | 'importMeta',
39 | 'topLevelAwait',
40 | 'classProperties',
41 | 'classPrivateProperties',
42 | 'classPrivateMethods',
43 | 'jsx',
44 | ].concat(isTypescript ? ['typescript'] : []),
45 | },
46 | generatorOpts: {
47 | decoratorsBeforeExport: true,
48 | },
49 | plugins: [[taddyBabelPlugin, {unstable_target}]],
50 | sourceMaps: true,
51 | inputSourceMap: false,
52 | });
53 |
54 | return {
55 | code: result.code,
56 | map: result.map,
57 | };
58 | },
59 | };
60 |
61 | return plugin;
62 | }
63 |
64 | module.exports = taddyPlugin;
65 |
--------------------------------------------------------------------------------
/@taddy/vite-plugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "@taddy/vite-plugin",
4 | "version": "0.1.0-alpha.0",
5 | "author": "Kenzhaev Artur ",
6 | "license": "MIT",
7 | "main": "index.js",
8 | "publishConfig": {
9 | "access": "public"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/lttb/taddy.git"
14 | },
15 | "dependencies": {
16 | "@taddy/babel-plugin": "^0.1.0-alpha.0"
17 | },
18 | "devDependencies": {
19 | "vite": "^4.2.1"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/@taddy/vite-plugin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "lib",
5 |
6 | "baseUrl": "."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/@types/global.d.ts:
--------------------------------------------------------------------------------
1 | // Declare global variables for TypeScript and VSCode.
2 | // Do not rename this file or move these types into index.d.ts
3 | // @see https://code.visualstudio.com/docs/nodejs/working-with-javascript#_global-variables-and-type-checking
4 | declare const __DEV__: boolean;
5 | declare const __VERSION__: string;
6 | declare const $FixMe: any;
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Artur Kenzhaev
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.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ./taddy/README.md
--------------------------------------------------------------------------------
/ROADMAP.md:
--------------------------------------------------------------------------------
1 | # Roadmap
2 |
3 | The list of key ideas and features that would be great to implement to improve the overall usage experience.
4 |
5 | Please fill free to share any your idea and [add your proposal](https://github.com/lttb/taddy/issues/new?labels=enhancement&title=[dx]%20my%20proposal) to help `taddy` become better.
6 |
7 | ## Overall
8 |
9 | - [ ] Support `styled` function for components, by `@taddy/styled` (?)
10 | - [ ] Provide tools and adaptors for easier `taddy` adoption
11 | - [ ] support `keyframes` and `media`
12 | - [ ] support global styles (?)
13 |
14 | ## Runtime
15 |
16 | - [ ] support runtime vendor prefixes
17 | - [ ] optimize `class` atomic merge (?)
18 | - [ ] improve the detection of styles that were already declared
19 | - [ ] improve styles object caching (eg `css({ color: 'red' })` === `css({ color: 'red' }`)
20 |
21 | ## Compiler
22 |
23 | - [ ] Optimize `babel-plugin`:
24 | - [ ] Improve the way plugin schedules the persistent cache updates
25 | - [ ] Research the ways to make the pre-evaluation more efficient
26 | - [ ] Support `taddy.config.ts`
27 | - [ ] Support atoms pregeneration based on the `config`
28 | - [ ] Support theming (?)
29 | - [ ] Improve `typescript` usage:
30 | - [ ] improve dynamic types infer
31 | - [ ] improve types usage for the complex pre-evaluation (e.g. calculate all the combinations of the calculation based on dynamic typed values)
32 | - [ ] make it stable
33 | - [ ] Optional bindings optimization (?) (at the moment that's always enabled)
34 | - [ ] Support `tagged template literals` by default (at the moment, it's under the unstable flag)
35 | - [ ] Optional `taddy/css` auto-import
36 | - [ ] Support custom paths in `taddy/css`
37 |
38 | ## Developer Experience
39 |
40 | - [ ] Check the usage of `taddy/css` and report if styles were not included to the app
41 | - [ ] Provide better compiler errors and tips
42 | - For example, show errors on `&` usage in selectors
43 | - [ ] Serialize `class` values as readable names instead of the hashes for the `DEV` mode
44 | - [ ] Provide optional warnings, errors and tips if compiler can't statically extract the css code
45 | - [ ] Provide `css source maps` for the declared css-in-js styles
46 | - [ ] Improve and document the Developer Experience with popular frameworks like Next.js
47 |
48 | ## Documentation
49 |
50 | - [ ] Describe the tradeoffs and edge cases
51 | - [ ] Provide different examples and tips for different environments (CRA, next.js, Svelte etc.)
52 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | ['@babel/preset-env', {targets: {node: 'current'}, modules: 'auto'}],
4 | '@babel/preset-typescript',
5 | ],
6 | };
7 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('jest').Config} */
2 | module.exports = {
3 | testEnvironment: '@happy-dom/jest-environment',
4 | modulePathIgnorePatterns: ['lib', '.cache'],
5 | };
6 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "registry": "https://registry.npmjs.org/",
3 | "publishConfig": {
4 | "access": "public"
5 | },
6 | "packages": ["@taddy/*", "taddy", "taddy.macro", "@docs/*"],
7 | "version": "independent",
8 | "npmClient": "yarn",
9 | "useWorkspaces": true,
10 | "command": {
11 | "publish": {
12 | "conventionalCommits": true
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "root",
4 | "workspaces": {
5 | "packages": [
6 | "@examples/*",
7 | "@taddy/*",
8 | "@docs/*",
9 | "taddy",
10 | "taddy.macro"
11 | ],
12 | "nohoist": [
13 | "tslib",
14 | "**/@remix-run/**"
15 | ]
16 | },
17 | "license": "MIT",
18 | "engines": {
19 | "node": "18.x"
20 | },
21 | "scripts": {
22 | "start": "lerna run start --stream --parallel --no-private",
23 | "lint": "eslint --ext .js,.ts,.tsx",
24 | "test": "jest --runInBand",
25 | "check:ts": "lerna run check:ts --parallel --no-private",
26 | "build": "lerna run build --parallel --no-private",
27 | "website": "yarn lerna run --scope @docs/website",
28 | "prewebsite:build": "yarn build",
29 | "website:build": "yarn website build",
30 | "prepub": "lerna run build --no-private",
31 | "pub": "lerna publish from-package --contents lib --exact --no-private",
32 | "prepub:version": "lerna version --no-private",
33 | "pub:version": "yarn pub"
34 | },
35 | "devDependencies": {
36 | "@babel/cli": "^7.21.0",
37 | "@babel/core": "7.21.0",
38 | "@babel/preset-env": "^7.20.2",
39 | "@babel/preset-typescript": "^7.21.0",
40 | "@happy-dom/jest-environment": "^8.9.0",
41 | "@jest/globals": "29.5.0",
42 | "@rollup/plugin-typescript": "^11.0.0",
43 | "@types/jest": "^29.4.0",
44 | "@typescript-eslint/eslint-plugin": "^5.54.1",
45 | "@typescript-eslint/parser": "^5.54.1",
46 | "babel-jest": "^29.5.0",
47 | "eslint": "^8.36.0",
48 | "eslint-config-prettier": "^8.7.0",
49 | "eslint-import-resolver-typescript": "^3.5.3",
50 | "eslint-plugin-import": "^2.27.5",
51 | "eslint-plugin-react": "^7.32.2",
52 | "eslint-plugin-react-hooks": "^4.6.0",
53 | "happy-dom": "^8.9.0",
54 | "husky": "8.0.3",
55 | "jest": "^29.5.0",
56 | "jest-environment-jsdom": "^29.5.0",
57 | "lerna": "6.5.1",
58 | "prettier": "2.8.4",
59 | "rollup": "^3.19.1",
60 | "rollup-plugin-copy": "^3.4.0",
61 | "rollup-plugin-node-externals": "^5.1.2",
62 | "typescript": "5.0.3"
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | tabWidth: 4,
3 | singleQuote: true,
4 | trailingComa: 'all',
5 | bracketSpacing: false,
6 | };
7 |
--------------------------------------------------------------------------------
/rollup.config.common.js:
--------------------------------------------------------------------------------
1 | import typescript from '@rollup/plugin-typescript';
2 | import externals from 'rollup-plugin-node-externals';
3 | import copy from 'rollup-plugin-copy';
4 |
5 | /** @type {import('rollup').RollupOptions} */
6 | const config =
7 | // ES module build (replaces broken basic TypeScript compilation)
8 | // * ref: ,
9 | // * ref:
10 | // * ref:
11 | {
12 | output: [
13 | {
14 | dir: 'lib',
15 | format: 'esm',
16 | entryFileNames: '[name].js',
17 | sourcemap: true,
18 | preserveModules: true, // or `false` to bundle as a single file
19 | },
20 | {
21 | dir: 'lib',
22 | format: 'cjs',
23 | entryFileNames: '[name].cjs',
24 | sourcemap: true,
25 | preserveModules: true, // or `false` to bundle as a single file
26 | },
27 | ],
28 | plugins: [
29 | externals(),
30 |
31 | typescript({
32 | exclude: ['**/tests/**', '**/*.test.*'],
33 | compilerOptions: {
34 | incremental: false,
35 | },
36 | }),
37 |
38 | copy({
39 | targets: [
40 | {src: 'README.md', dest: 'lib'},
41 | {src: 'CHANGELOG.md', dest: 'lib'},
42 | {
43 | src: 'package.json',
44 | dest: 'lib',
45 | transform: (contents) => {
46 | const packageJson = JSON.parse(contents.toString());
47 |
48 | return JSON.stringify({
49 | ...packageJson,
50 |
51 | main: 'index.cjs',
52 | module: 'index.js',
53 | exports: {
54 | ...packageJson.exports,
55 |
56 | ...(packageJson.name ===
57 | '@taddy/babel-plugin' && {
58 | './lib/': './',
59 | './cache/': './cache/',
60 | './macro': {
61 | import: './macro.js',
62 | require: './macro.cjs',
63 | },
64 | }),
65 |
66 | ...(packageJson.name === 'taddy' && {
67 | './vue': {
68 | import: './vue/index.js',
69 | require: './vue/index.cjs',
70 | },
71 | }),
72 |
73 | '.': {
74 | import: './index.js',
75 | require: './index.cjs',
76 | },
77 | './package.json': './package.json',
78 | },
79 | });
80 | },
81 | },
82 | ],
83 | }),
84 | ],
85 | };
86 |
87 | export default config;
88 |
--------------------------------------------------------------------------------
/taddy.macro/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .DS_Store
3 |
4 | node_modules
5 |
6 | dist
7 | *.code-workspace
8 | .vscode
9 | .cache
10 |
11 | !packages/taddy/.cache
12 | taddy.css
13 |
14 | .vercel
15 |
16 | *.tsbuildinfo
17 |
--------------------------------------------------------------------------------
/taddy.macro/README.md:
--------------------------------------------------------------------------------
1 | # taddy.macro
2 |
--------------------------------------------------------------------------------
/taddy.macro/index.d.ts:
--------------------------------------------------------------------------------
1 | export * from 'taddy';
2 |
--------------------------------------------------------------------------------
/taddy.macro/index.ts:
--------------------------------------------------------------------------------
1 | import {createMacro} from 'babel-plugin-macros';
2 | import {macro} from '@taddy/babel-plugin/macro';
3 |
4 | // TODO: make compatible types
5 | export default createMacro(macro as any, {configName: 'taddy'});
6 |
--------------------------------------------------------------------------------
/taddy.macro/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "taddy.macro",
3 | "version": "0.1.0-alpha.10",
4 | "author": "Kenzhaev Artur ",
5 | "license": "MIT",
6 | "main": "lib/index.cjs",
7 | "publishConfig": {
8 | "access": "public"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/lttb/taddy.git"
13 | },
14 | "scripts": {
15 | "clean": "rm -rf lib",
16 | "check:ts": "tsc --noEmit",
17 | "compile": "rollup -c --bundleConfigAsCjs",
18 | "prestart": "yarn clean",
19 | "start": "yarn compile --watch",
20 | "prebuild": "yarn clean",
21 | "build": "yarn compile"
22 | },
23 | "dependencies": {
24 | "@taddy/babel-plugin": "^0.1.0-alpha.10",
25 | "taddy": "^0.1.0-alpha.5"
26 | },
27 | "peerDependencies": {
28 | "babel-plugin-macros": "^3.0.0"
29 | },
30 | "devDependencies": {
31 | "@types/babel-plugin-macros": "^3.1.0",
32 | "babel-plugin-macros": "^3.0.0"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/taddy.macro/rollup.config.js:
--------------------------------------------------------------------------------
1 | import commonConfig from '../rollup.config.common';
2 |
3 | const config = {
4 | ...commonConfig,
5 |
6 | input: ['index.ts'],
7 | };
8 |
9 | export default config;
10 |
--------------------------------------------------------------------------------
/taddy.macro/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "lib",
5 |
6 | "baseUrl": "."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/taddy/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .DS_Store
3 |
4 | node_modules
5 |
6 | dist
7 | *.code-workspace
8 | .vscode
9 | .cache
10 |
11 | !packages/taddy/.cache
12 | taddy.css
13 |
14 | .vercel
15 |
16 | *.tsbuildinfo
17 |
--------------------------------------------------------------------------------
/taddy/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | taddy
7 |
8 |
9 |
10 | Compile-time Atomic CSS-in-JS
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | ## Quick Start
29 |
30 | ```sh
31 | npm install --save taddy
32 | ```
33 |
34 |
35 | ```jsx
36 | import React from 'react'
37 |
38 | import {css} from 'taddy'
39 |
40 | export function Title() {
41 | return (
42 |
43 | Hello, taddy!
44 |
45 | )
46 | }
47 | ```
48 |
49 | ## Usage
50 |
51 | ### css
52 |
53 | There is an agnostic `css` function, that returns an object of `className` and `style`.
54 |
55 | That's a framework-agnostic function, so it's ready for the usage at any environment.
56 |
57 | ```js
58 | // button = {className: 'hash1 hash2', style: {}}
59 | const button = css({padding: '10px', border: 'none'});
60 | ```
61 |
62 | #### pseudo classes
63 |
64 | ```js
65 | const button = css({
66 | padding: '10px',
67 | border: 'none',
68 | color: 'red',
69 |
70 | ':hover': {
71 | color: 'blue',
72 | },
73 | });
74 | ```
75 |
76 | ### css.mixin
77 |
78 | In terms of `taddy`, mixin is a special styling object, that can be used as a part of styles by `css`.
79 |
80 | To declare the mixin styles, there is a special function `css.mixin`:
81 |
82 | ```js
83 | const heading = css.mixin({
84 | fontSize: '20px',
85 | fontWeight: 'bold',
86 | });
87 | ```
88 |
89 | `mixin` also could be used as a named export:
90 |
91 | ```js
92 | import {mixin} from 'taddy';
93 |
94 | const heading = mixin({
95 | fontSize: '20px',
96 | fontWeight: 'bold',
97 | });
98 | ```
99 |
100 | #### merge
101 |
102 | Mixin can be applied by spreading to the styles, consumed by `css`:
103 |
104 | ```js
105 | const heading = css.mixin({
106 | fontSize: '20px',
107 | fontWeight: 'bold',
108 | });
109 |
110 | const Title = ({children}) => (
111 | {children}
112 | );
113 | ```
114 |
115 | Mixins also could be used on the nested level:
116 |
117 | ```js
118 | const halfTransparent = css.mixin({
119 | opacity: 0.5,
120 | });
121 |
122 | const Title = ({children}) => (
123 |
130 | {children}
131 |
132 | );
133 | ```
134 |
135 | #### composes
136 |
137 | Mixins are cool, but they have some restrictions.
138 |
139 | For example, let's consider two mixins:
140 |
141 | ```js
142 | const colorStateful = css.mixin({
143 | color: 'red',
144 |
145 | ':hover': {
146 | color: 'blue',
147 | },
148 | });
149 |
150 | const opacityStateful = css.mixin({
151 | opacity: 1,
152 |
153 | ':hover': {
154 | opacity: 0.5,
155 | },
156 | });
157 | ```
158 |
159 | In terms of merge, the result of `css({...colorStateful, ...opacityStateful})` would be `{color: 'red', opacity: 1, ':hover': {opacity: 0.5}}`
160 |
161 | But what if we want to apply both mixins together?
162 |
163 | There is `composes` interface for that (mixins and styles as `css` arguments):
164 |
165 | ```js
166 | const Title = ({children}) => (
167 |
172 | {children}
173 |
174 | );
175 | ```
176 |
--------------------------------------------------------------------------------
/taddy/RuleInjector/Sheet.ts:
--------------------------------------------------------------------------------
1 | import {config} from '@taddy/core';
2 |
3 | import {camelToKebab} from './common';
4 |
5 | export type SheetOptions = {
6 | mergeDeclarations?: boolean;
7 | virtual?: boolean;
8 | };
9 |
10 | abstract class Sheet {
11 | options: SheetOptions;
12 | cache: Map;
13 | rulesCache: Map;
14 |
15 | abstract insertAtRule(key: {name: string; query: string}): number;
16 |
17 | abstract insertAtomicRule(
18 | className: string,
19 | key: string,
20 | value: string,
21 | options: {postfix?: string; atRuleIndex?: number},
22 | ): number;
23 |
24 | abstract appendSelector(
25 | ruleIndex: number,
26 | selector: string,
27 | options?: {atRuleIndex?: number},
28 | ): void;
29 |
30 | constructor(options: SheetOptions = {}) {
31 | this.options = Object.assign({mergeDeclarations: true}, options);
32 |
33 | this.cache = new Map();
34 | this.rulesCache = new Map();
35 | }
36 |
37 | insert(
38 | key: string,
39 | value: any,
40 | {
41 | postfix = '',
42 | at,
43 | hash = '',
44 | }: {
45 | postfix?: string;
46 | at?: {name: string; query: string};
47 | hash?: string;
48 | },
49 | ) {
50 | hash = hash ? '-' + hash : '';
51 | const {nameGenerator} = config;
52 |
53 | const name = nameGenerator.getName(key, value, {
54 | postfix,
55 | at,
56 | });
57 |
58 | const cssKey = camelToKebab(key);
59 |
60 | const result = Object.create(null);
61 | // result[propHash + postfixHash] = value + hash
62 | result[name[0] + name[1] + name[2] + name[3]] = name[4] + hash;
63 |
64 | const nameHash = name.join('');
65 |
66 | if (this.cache.has(nameHash)) {
67 | return result;
68 | }
69 |
70 | const atHash = at ? at.name + at.query : '';
71 | let atRuleIndex = atHash ? this.rulesCache.get(atHash) : undefined;
72 |
73 | if (at && atRuleIndex === undefined) {
74 | atRuleIndex = this.insertAtRule(at);
75 | this.rulesCache.set(atHash, atRuleIndex);
76 | }
77 |
78 | const originalName = nameGenerator.getName(cssKey, value, {at});
79 | const originalHash = originalName.join('');
80 |
81 | let ruleIndex;
82 |
83 | const className = `${nameHash}${hash}${postfix}`;
84 |
85 | if (this.rulesCache.has(originalHash)) {
86 | ruleIndex = this.rulesCache.get(originalHash);
87 |
88 | this.appendSelector(ruleIndex, `.${className}`, {atRuleIndex});
89 | }
90 |
91 | if (ruleIndex === undefined) {
92 | ruleIndex = this.insertAtomicRule(className, cssKey, value, {
93 | postfix,
94 | atRuleIndex,
95 | });
96 | }
97 |
98 | this.cache.set(nameHash, {
99 | name,
100 | hash,
101 | key,
102 | value,
103 | postfix,
104 | at,
105 | ruleIndex,
106 | });
107 |
108 | if (
109 | this.options.mergeDeclarations &&
110 | ruleIndex !== undefined &&
111 | ruleIndex >= 0
112 | ) {
113 | this.rulesCache.set(originalHash, ruleIndex);
114 | }
115 |
116 | return result;
117 | }
118 | }
119 |
120 | export default Sheet;
121 |
--------------------------------------------------------------------------------
/taddy/RuleInjector/VirtualStyleSheet.ts:
--------------------------------------------------------------------------------
1 | import {buildAtomicRule} from './common';
2 |
3 | import Sheet from './Sheet';
4 | import type {SheetOptions} from './Sheet';
5 |
6 | interface VirtualCSSStyleRule extends Partial {
7 | $className: string;
8 | $key: string;
9 | $value: string;
10 | $postfix: string;
11 | }
12 |
13 | type VirtualCSSConditionRule = Partial;
14 |
15 | export class VirtualStyleSheet extends Sheet {
16 | cssRules: (VirtualCSSStyleRule | VirtualCSSConditionRule)[];
17 |
18 | sheet: {cssRules: VirtualStyleSheet['cssRules']};
19 |
20 | constructor(options?: SheetOptions) {
21 | super(options);
22 |
23 | this.sheet = {
24 | cssRules: [],
25 | };
26 | this.cssRules = this.sheet.cssRules;
27 | }
28 |
29 | get rules() {
30 | return this.cssRules;
31 | }
32 |
33 | insertDevRule(rule) {
34 | this.cssRules.push({
35 | cssText: rule,
36 | });
37 | }
38 |
39 | insertAtomicRule(
40 | className: string,
41 | key: string,
42 | value: string,
43 | {
44 | postfix = '',
45 | atRuleIndex,
46 | }: {postfix?: string; atRuleIndex?: number} = {},
47 | ): number {
48 | const isAtRule = atRuleIndex !== undefined;
49 |
50 | const selectorPrefix = isAtRule ? '._' : '';
51 | const selectorText = selectorPrefix + `.${className}`;
52 | const cssText = buildAtomicRule(selectorText, key, value);
53 |
54 | let insertSheet = this.sheet;
55 |
56 | if (isAtRule) {
57 | // cast media rule type
58 | insertSheet = this.sheet.cssRules[
59 | atRuleIndex
60 | ] as any as typeof insertSheet;
61 | }
62 |
63 | const index = insertSheet.cssRules.length;
64 |
65 | insertSheet.cssRules.push({
66 | cssText,
67 | selectorText,
68 | $className: className,
69 | $key: key,
70 | $value: value,
71 | $postfix: postfix,
72 | });
73 | return index;
74 | }
75 |
76 | insertAtRule(key: {name: string; query: string}): number {
77 | const index = this.sheet.cssRules.length;
78 | const cssRules = [] as any;
79 | this.sheet.cssRules.push({
80 | get cssText() {
81 | return `${key.name} (${key.query}) {${this.cssRules
82 | .map((x) => x.cssText || '')
83 | .join('')}}`;
84 | },
85 | cssRules,
86 | conditionText: key.query,
87 | });
88 | return index;
89 | }
90 |
91 | appendSelector(
92 | ruleIndex: number,
93 | selector: string,
94 | {atRuleIndex}: {atRuleIndex?: number} = {},
95 | ): void {
96 | let sheet = this.sheet;
97 |
98 | if (atRuleIndex !== undefined) {
99 | // cast media rule type
100 | sheet = this.cssRules[atRuleIndex] as any as typeof sheet;
101 | }
102 |
103 | const rule = sheet.cssRules[ruleIndex] as VirtualCSSStyleRule;
104 |
105 | const selectorText = `${rule.selectorText},${selector}`;
106 | rule.selectorText = selectorText;
107 | rule.cssText = buildAtomicRule(selectorText, rule.$key, rule.$value);
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/taddy/RuleInjector/common.ts:
--------------------------------------------------------------------------------
1 | export function buildAtomicRule(
2 | selector: string,
3 | key: string,
4 | value: string,
5 | ): string {
6 | return `${selector}{${key}:${value}}`;
7 | }
8 |
9 | const camelToKebabRe = /([a-z0-9]|(?=[A-Z]))([A-Z])/g;
10 | export function camelToKebab(string): string {
11 | return string.replace(camelToKebabRe, '$1-$2').toLowerCase();
12 | }
13 |
14 | export function getStyleNodeById(id: string): HTMLStyleElement {
15 | let node = document.getElementById(id) as HTMLStyleElement;
16 | if (!node) {
17 | node = document.createElement('style');
18 | node.id = id;
19 | document.head.appendChild(node);
20 | }
21 | return node;
22 | }
23 |
--------------------------------------------------------------------------------
/taddy/at.ts:
--------------------------------------------------------------------------------
1 | import type {TaddyRule, SupportedAtRulesNames} from './types';
2 |
3 | export function at(
4 | ruleName: SupportedAtRulesNames,
5 | query: string,
6 | rule: TaddyRule,
7 | ) {
8 | const name = `@${ruleName}`;
9 | return {[name + query]: {'@at': {name, query}, rule}};
10 | }
11 |
--------------------------------------------------------------------------------
/taddy/css.js:
--------------------------------------------------------------------------------
1 | require('@taddy/babel-plugin/cache');
2 |
--------------------------------------------------------------------------------
/taddy/index.native.ts:
--------------------------------------------------------------------------------
1 | import {processRules} from './react-native/processStyles';
2 |
3 | export function css(...rule) {
4 | return processRules(rule);
5 | }
6 |
--------------------------------------------------------------------------------
/taddy/index.ts:
--------------------------------------------------------------------------------
1 | import type {Properties} from 'csstype';
2 |
3 | import {
4 | css as staticCSS,
5 | $,
6 | withId,
7 | config,
8 | MIXIN_KEY,
9 | ID_KEY,
10 | joinClassName,
11 | } from '@taddy/core';
12 | import {$css} from './$css';
13 | import type {TaddyRule} from './types';
14 |
15 | import {mixin} from './mixin';
16 | import {at} from './at';
17 | import {processRules} from './react-native/processStyles';
18 |
19 | export type ExactProp = Exclude<
20 | Properties[T],
21 | object
22 | >;
23 |
24 | export type TaddyStyle = {style?: any; className: string};
25 |
26 | export * from './RuleInjector';
27 |
28 | export {$css, config};
29 |
30 | /*
31 |
32 | // TODO: at the moment, this kind of opaque type will not work for external modules
33 | // for example, const styles = {base: css({color: 'red'})}
34 |
35 | const TADDY: unique symbol = Symbol('TADDY');
36 | */
37 |
38 | type CSSResult = TaddyStyle & Record;
39 |
40 | const getId = (rule: any[]): string | void => {
41 | if (rule.length <= 1) return;
42 | const maybeId = rule[rule.length - 1];
43 | if (maybeId && maybeId[0] === '_' && maybeId[1] === '_') {
44 | return rule.pop();
45 | }
46 | };
47 |
48 | function _css(
49 | rule: (T | TaddyRule | false | void | null | string)[],
50 | ): CSSResult {
51 | const id = getId(rule);
52 |
53 | const result = $css(rule.length <= 1 ? rule[0] : {composes: rule});
54 |
55 | if (result.className) {
56 | delete result.className[MIXIN_KEY];
57 |
58 | // @ts-expect-error fix types
59 | result.className = joinClassName(result.className);
60 | }
61 |
62 | return withId(result, id);
63 | }
64 |
65 | /**
66 | * tagged template literal interface works only with babel-plugin
67 | */
68 | export function css(str: TemplateStringsArray, ...values: any[]): CSSResult;
69 | export function css(
70 | ...rule: Parameters[0]
71 | ): ReturnType;
72 |
73 | export function css(...rule) {
74 | if (config.unstable_target === 'react-native') {
75 | return processRules(rule);
76 | }
77 |
78 | return config.unstable_mapStyles(_css(rule));
79 | }
80 |
81 | css.mixin = mixin;
82 | css.at = at;
83 |
84 | export const h = (x) => config.nameGenerator.getHash(x);
85 |
86 | css.h = h;
87 |
88 | css.static = (...args: any[]) => staticCSS(...args);
89 |
90 | // @ts-expect-error "static" doesn't exist
91 | css.mixin.static = staticCSS.mixin;
92 |
93 | export {mixin, at, $};
94 |
--------------------------------------------------------------------------------
/taddy/mixin.ts:
--------------------------------------------------------------------------------
1 | import {MIXIN_KEY} from '@taddy/core';
2 |
3 | import {$css} from './$css';
4 | import type {TaddyRule} from './types';
5 |
6 | type TaddyMixin = T;
7 |
8 | // The union hack to improve autocomplete
9 | export function mixin(rule: TaddyRule | T): TaddyMixin;
10 |
11 | export function mixin(rule) {
12 | rule[MIXIN_KEY] = $css(rule);
13 | return rule;
14 | }
15 |
--------------------------------------------------------------------------------
/taddy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "taddy",
3 | "version": "0.1.0-alpha.5",
4 | "author": "Kenzhaev Artur ",
5 | "license": "MIT",
6 | "main": "lib/index.cjs",
7 | "module": "lib/index.js",
8 | "publishConfig": {
9 | "access": "public"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/lttb/taddy.git"
14 | },
15 | "scripts": {
16 | "clean": "rm -rf lib",
17 | "check:ts": "tsc --noEmit",
18 | "compile": "rollup -c --bundleConfigAsCjs",
19 | "prestart": "yarn clean",
20 | "start": "yarn compile --watch",
21 | "prebuild": "yarn clean",
22 | "build": "yarn compile"
23 | },
24 | "dependencies": {
25 | "@taddy/core": "^0.1.0-alpha.3",
26 | "csstype": "3.1.1"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/taddy/react-native/processStyles.ts:
--------------------------------------------------------------------------------
1 | export function processRules(rules: any[]) {
2 | return {
3 | style: rules
4 | .flatMap((x) => (x ? x.style || x : []))
5 | .reduce((acc, x) => {
6 | for (const key in x) {
7 | if (key[0] === ':' || key[0] === '@') continue;
8 |
9 | acc[key] = x[key];
10 | }
11 | return acc;
12 | }, {}),
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/taddy/rollup.config.js:
--------------------------------------------------------------------------------
1 | import commonConfig from '../rollup.config.common';
2 |
3 | const config = {
4 | ...commonConfig,
5 |
6 | input: ['index.ts', 'index.native.ts', 'vue/index.ts'],
7 | };
8 |
9 | export default config;
10 |
--------------------------------------------------------------------------------
/taddy/tests/utils.ts:
--------------------------------------------------------------------------------
1 | import {RuleInjector} from '../RuleInjector';
2 | import {getStyleNodeById} from '../RuleInjector/common';
3 |
4 | import {$css} from '..';
5 |
6 | export function getStyles(): string {
7 | return Array.from(getStyleNodeById('taddy').sheet?.cssRules || [])
8 | .map((rule) => rule.cssText)
9 | .join('\n');
10 | }
11 |
12 | export function resetStyles() {
13 | getStyleNodeById('taddy').remove();
14 |
15 | // @ts-expect-error - fix compiled/source types resolution
16 | $css.ruleInjector = new RuleInjector();
17 | }
18 |
--------------------------------------------------------------------------------
/taddy/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "lib",
5 |
6 | "baseUrl": "."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/taddy/types.ts:
--------------------------------------------------------------------------------
1 | import type {Properties} from 'csstype';
2 |
3 | export type SupportedAtRulesNames = 'media' | 'supports' | 'container';
4 | export type SupportedAtRules = `@${SupportedAtRulesNames}`;
5 |
6 | /* that could be {[key in SimplePseudos]: TaddyRule}, but there would be problems with autocomplete */
7 | type TaddyRuleBase = Properties & {
8 | ':-khtml-any-link'?: TaddyRuleBase;
9 | ':-moz-any-link'?: TaddyRuleBase;
10 | ':-moz-focusring'?: TaddyRuleBase;
11 | ':-moz-full-screen'?: TaddyRuleBase;
12 | ':-moz-placeholder'?: TaddyRuleBase;
13 | ':-moz-read-only'?: TaddyRuleBase;
14 | ':-moz-read-write'?: TaddyRuleBase;
15 | ':-ms-fullscreen'?: TaddyRuleBase;
16 | ':-ms-input-placeholder'?: TaddyRuleBase;
17 | ':-webkit-any-link'?: TaddyRuleBase;
18 | ':-webkit-full-screen'?: TaddyRuleBase;
19 | '::-moz-placeholder'?: TaddyRuleBase;
20 | '::-moz-progress-bar'?: TaddyRuleBase;
21 | '::-moz-range-progress'?: TaddyRuleBase;
22 | '::-moz-range-thumb'?: TaddyRuleBase;
23 | '::-moz-range-track'?: TaddyRuleBase;
24 | '::-moz-selection'?: TaddyRuleBase;
25 | '::-ms-backdrop'?: TaddyRuleBase;
26 | '::-ms-browse'?: TaddyRuleBase;
27 | '::-ms-check'?: TaddyRuleBase;
28 | '::-ms-clear'?: TaddyRuleBase;
29 | '::-ms-fill'?: TaddyRuleBase;
30 | '::-ms-fill-lower'?: TaddyRuleBase;
31 | '::-ms-fill-upper'?: TaddyRuleBase;
32 | '::-ms-input-placeholder'?: TaddyRuleBase;
33 | '::-ms-reveal'?: TaddyRuleBase;
34 | '::-ms-thumb'?: TaddyRuleBase;
35 | '::-ms-ticks-after'?: TaddyRuleBase;
36 | '::-ms-ticks-before'?: TaddyRuleBase;
37 | '::-ms-tooltip'?: TaddyRuleBase;
38 | '::-ms-track'?: TaddyRuleBase;
39 | '::-ms-value'?: TaddyRuleBase;
40 | '::-webkit-backdrop'?: TaddyRuleBase;
41 | '::-webkit-input-placeholder'?: TaddyRuleBase;
42 | '::-webkit-progress-bar'?: TaddyRuleBase;
43 | '::-webkit-progress-inner-value'?: TaddyRuleBase;
44 | '::-webkit-progress-value'?: TaddyRuleBase;
45 | '::-webkit-slider-runnable-track'?: TaddyRuleBase;
46 | '::-webkit-slider-thumb'?: TaddyRuleBase;
47 | '::after'?: TaddyRuleBase;
48 | '::backdrop'?: TaddyRuleBase;
49 | '::before'?: TaddyRuleBase;
50 | '::cue'?: TaddyRuleBase;
51 | '::cue-region'?: TaddyRuleBase;
52 | '::first-letter'?: TaddyRuleBase;
53 | '::first-line'?: TaddyRuleBase;
54 | '::grammar-error'?: TaddyRuleBase;
55 | '::marker'?: TaddyRuleBase;
56 | '::placeholder'?: TaddyRuleBase;
57 | '::selection'?: TaddyRuleBase;
58 | '::spelling-error'?: TaddyRuleBase;
59 | ':active'?: TaddyRuleBase;
60 | ':after'?: TaddyRuleBase;
61 | ':any-link'?: TaddyRuleBase;
62 | ':before'?: TaddyRuleBase;
63 | ':blank'?: TaddyRuleBase;
64 | ':checked'?: TaddyRuleBase;
65 | ':default'?: TaddyRuleBase;
66 | ':defined'?: TaddyRuleBase;
67 | ':disabled'?: TaddyRuleBase;
68 | ':empty'?: TaddyRuleBase;
69 | ':enabled'?: TaddyRuleBase;
70 | ':first'?: TaddyRuleBase;
71 | ':first-child'?: TaddyRuleBase;
72 | ':first-letter'?: TaddyRuleBase;
73 | ':first-line'?: TaddyRuleBase;
74 | ':first-of-type'?: TaddyRuleBase;
75 | ':focus'?: TaddyRuleBase;
76 | ':focus-visible'?: TaddyRuleBase;
77 | ':focus-within'?: TaddyRuleBase;
78 | ':fullscreen'?: TaddyRuleBase;
79 | ':hover'?: TaddyRuleBase;
80 | ':in-range'?: TaddyRuleBase;
81 | ':indeterminate'?: TaddyRuleBase;
82 | ':invalid'?: TaddyRuleBase;
83 | ':last-child'?: TaddyRuleBase;
84 | ':last-of-type'?: TaddyRuleBase;
85 | ':left'?: TaddyRuleBase;
86 | ':link'?: TaddyRuleBase;
87 | ':only-child'?: TaddyRuleBase;
88 | ':only-of-type'?: TaddyRuleBase;
89 | ':optional'?: TaddyRuleBase;
90 | ':out-of-range'?: TaddyRuleBase;
91 | ':placeholder-shown'?: TaddyRuleBase;
92 | ':read-only'?: TaddyRuleBase;
93 | ':read-write'?: TaddyRuleBase;
94 | ':required'?: TaddyRuleBase;
95 | ':right'?: TaddyRuleBase;
96 | ':root'?: TaddyRuleBase;
97 | ':scope'?: TaddyRuleBase;
98 | ':target'?: TaddyRuleBase;
99 | ':valid'?: TaddyRuleBase;
100 | ':visited'?: TaddyRuleBase;
101 | };
102 |
103 | export type TaddyRule = TaddyRuleBase & {
104 | composes?: object[];
105 | className?: string;
106 | style?: object;
107 | } & Partial<{
108 | [key in SupportedAtRules]: Record;
109 | }>;
110 |
--------------------------------------------------------------------------------
/taddy/vue/index.ts:
--------------------------------------------------------------------------------
1 | import {config} from 'taddy';
2 |
3 | config({
4 | unstable_mapStyles: (result) => ({
5 | class: result.className,
6 | style: result.style,
7 | }),
8 | });
9 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "allowSyntheticDefaultImports": true,
5 | "alwaysStrict": true,
6 | "declaration": true,
7 | "esModuleInterop": true,
8 | "importHelpers": true,
9 | "jsx": "react-jsx",
10 | "lib": ["dom", "dom.iterable", "esnext"],
11 | "moduleResolution": "nodenext",
12 | "noFallthroughCasesInSwitch": false,
13 | "noImplicitAny": false,
14 | "noImplicitReturns": true,
15 | "noImplicitThis": true,
16 | "noUnusedLocals": false,
17 | "noUnusedParameters": false,
18 | "pretty": true,
19 | "sourceMap": true,
20 | "strict": true,
21 | "strictFunctionTypes": true,
22 | "strictNullChecks": true,
23 | "strictPropertyInitialization": true,
24 | "stripInternal": true,
25 | "target": "ESNext",
26 | "downlevelIteration": true,
27 | "skipLibCheck": true,
28 | "outDir": "lib"
29 | },
30 | "exclude": ["**/node_modules/**", "**/lib/**"]
31 | }
32 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.build.json",
3 | "compilerOptions": {
4 | "incremental": true
5 | }
6 | }
7 |
--------------------------------------------------------------------------------