├── .gitignore
├── .prettierignore
├── .prettierrc.json
├── LICENSE
├── README.md
├── babel-jest.config.js
├── babel.config.js
├── examples
└── react
│ ├── index.html
│ ├── package.json
│ ├── pnpm-lock.yaml
│ ├── src
│ ├── App.tsx
│ ├── Box.tsx
│ ├── Button
│ │ ├── Button.css.ts
│ │ └── Button.tsx
│ ├── Text
│ │ ├── Text.css.ts
│ │ └── Text.tsx
│ ├── atoms.css.ts
│ ├── main.tsx
│ └── styled.css.ts
│ └── vite.config.ts
├── jest.config.js
├── package.json
├── packages
├── core
│ ├── README.md
│ ├── package.json
│ └── src
│ │ └── index.tsx
└── react
│ ├── README.md
│ ├── package.json
│ ├── pnpm-lock.yaml
│ ├── src
│ ├── index.ts
│ ├── styled.ts
│ ├── styledRuntime.ts
│ └── types.ts
│ └── styledRuntime
│ └── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── tests
└── core
│ └── core.test.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
3 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vscode/
3 | node_modules
4 | dist
5 | README.md
6 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021 Victor Tortolero
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 | # 🍰 Dessert Box
2 |
3 | A set of utilities to build UI and components with [vanilla-extract][vanilla-extract].
4 |
5 |
6 | - [🍰 Dessert Box](#-dessert-box)
7 | - [Installation](#installation)
8 | - [Styled](#styled)
9 | - [Box](#box)
10 | - [Usage](#usage)
11 | - [Escape Hatch](#escape-hatch)
12 | - [Variants](#variants)
13 | - [API](#api)
14 | - [createBox(options: { atoms: AtomsFn, defaultClassName?: string })](#createboxoptions--atoms-atomsfn-defaultclassname-string-)
15 | - [createBoxWithAtomsProp(options: { atoms: AtomsFn, defaultClassName?: string })](#createboxwithatomspropoptions--atoms-atomsfn-defaultclassname-string-)
16 | - [Running the example app](#running-the-example-app)
17 | - [How does it work?](#how-does-it-work)
18 | - [Thanks](#thanks)
19 | - [FAQ](#faq)
20 |
21 | ## Installation
22 |
23 | :warning: If you are not familiar with [vanilla-extract][vanilla-extract], we recommend going trough their docs first and have a working setup before trying any of the dessert box packages.
24 |
25 | ```sh
26 | $ npm install @dessert-box/react
27 | ```
28 |
29 | ## Styled
30 |
31 | A `styled-components`-like API to create components in your `*.css.ts` files. To use this, you can define your components
32 |
33 | ```ts
34 | // styledComponents.css.ts
35 | import { styled } from '@dessert-box/react';
36 |
37 | export const StyledHeadline = styled('h1', {
38 | color: 'white',
39 | fontSize: '16px',
40 | fontWeight: 'bold'
41 | });
42 | ```
43 |
44 | ```ts
45 | import { StyledHeadline } from './styledComponents.css.ts';
46 |
47 | function App() {
48 | return (
49 | I have 0 runtime styles 🤯
50 | )
51 | }
52 | ```
53 |
54 | ## Box
55 |
56 | A box component that will make consuming your [sprinkles][sprinkles] from a breeze. It provides a zero-CSS-runtime `` component (similar to the one in [Braid](https://seek-oss.github.io/braid-design-system/components/Box) or [Chakra](https://chakra-ui.com/docs/layout/box)).
57 |
58 | [Try it on CodeSandbox!](https://codesandbox.io/s/dessert-box-demo-wxgy8?file=/src/App.tsx)
59 |
60 | It works by consuming `atoms` created with [`vanilla-extract`][vanilla-extract]) and [`sprinkles`][sprinkles]. Shout out to the team at Seek for making these awesome libraries!
61 |
62 | 1. Step 1, create your Box with your `atoms` created with sprinkles:
63 |
64 | ```tsx
65 | // Box.tsx
66 | import { createBox } from '@dessert-box/react';
67 | import { atoms } from './sprinkles.css';
68 |
69 | const Box = createBox({
70 | atoms,
71 | // optional: pass your CSS reset className here
72 | // useful if you want to scope your reset to your Box element
73 | defaultClassName: 'resetClassName',
74 | });
75 |
76 | export default Box;
77 | ```
78 |
79 | 2. Step 2, import it enjoy the sweetness:
80 |
81 | ```tsx
82 | // OtherFileOrComponent.tsx
83 | import Box from './Box';
84 |
85 | const MyComponent = () => {
86 | return What a sweet treat!;
87 | };
88 | ```
89 |
90 | **Wondering why using a Box component may be a good idea? or what is a Box component? Check the [FAQ](#FAQ).**
91 |
92 | > Wondering how to use `variants` with this library? Check out the [variants](#variants) section.
93 |
94 | 
95 |
96 | [Try it on CodeSandbox!](https://codesandbox.io/s/dessert-box-demo-wxgy8?file=/src/App.tsx)
97 |
98 | ### Usage
99 |
100 | Install the package:
101 |
102 | ```
103 | $ npm install @dessert-box/react
104 | ```
105 |
106 | Configure [vanilla-extract](https://github.com/seek-oss/vanilla-extract) and [`sprinkles`](https://github.com/seek-oss/vanilla-extract/tree/master/packages/sprinkles) and have your atoms ready:
107 |
108 | ```js
109 | // atoms.css.ts
110 | import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles';
111 |
112 | const space = {
113 | none: 0,
114 | small: 4,
115 | medium: 8,
116 | large: 16,
117 | };
118 |
119 | const colors = {
120 | primary: 'blue',
121 | // ...
122 | };
123 |
124 | const atomicStyles = defineProperties({
125 | conditions: {
126 | mobile: {},
127 | tablet: { '@media': 'screen and (min-width: 768px)' },
128 | desktop: { '@media': 'screen and (min-width: 1024px)' },
129 | },
130 | properties: {
131 | padding: space,
132 | backgroundColor: colors,
133 | // ...
134 | },
135 | // ...
136 | });
137 |
138 | export const atoms = createSprinkles(atomicStyles);
139 | ```
140 |
141 | > Check `sprinkles` [docs](https://github.com/seek-oss/vanilla-extract/tree/3360bdfc9220024e7ffa49b3b198b72743d4e264/packages/sprinkles#setup) for more context into how to create these atoms.
142 |
143 | Now let's create our `` using these atoms:
144 |
145 | ```tsx
146 | // Box.ts
147 | import { createBox } from '@dessert-box/react';
148 | import { atoms } from './sprinkles.css';
149 |
150 | const { Box } = createBox({ atoms });
151 |
152 | export default Box;
153 | ```
154 |
155 | ```tsx
156 | // otherFile.tsx
157 | import Box from './Box';
158 |
159 | const App = () => {
160 | return Hello;
161 | };
162 | ```
163 |
164 | Notice we can pass every property, shorthand, or condition we can normally pass to our `atomsFn` function. For example, we could leverage the conditions for responsive design we have here:
165 |
166 | ```jsx
167 |
168 | ```
169 |
170 | If you need to render a tag different than a `div`, you can use the `as` prop:
171 |
172 | ```jsx
173 |
174 | Link to example
175 |
176 | ```
177 |
178 | ### Escape Hatch
179 |
180 | We have a way of specifying an arbitrary value (non design token) for any of your atoms properties like the following:
181 |
182 | ```jsx
183 |
184 | Link to example
185 |
186 | ```
187 |
188 | This is useful for those cases where we need to exit our system to accomplish something.
189 |
190 | [Try it on CodeSandbox!](https://codesandbox.io/s/dessert-box-demo-wxgy8?file=/src/App.tsx)
191 |
192 | ### Variants
193 |
194 | The official [@vanilla-extract/recipes][recipes] package has an excelent API for dealing with variants, this can be combined with our `Box` component to create [variant-based components](https://ped.ro/blog/variant-driven-components):
195 |
196 | NOTE: (Assuming you already have created your `Box` component following the example above).
197 |
198 | 1. First define your recipe using the `recipe` function:
199 |
200 | ```tsx
201 | // Button.css.ts
202 | import { recipe } from '@vanilla-extract/recipes';
203 | import { atoms } from '../atoms.css';
204 |
205 | export const buttonRecipe = recipe({
206 | variants: {
207 | kind: {
208 | primary: atoms({ background: 'blue50' }),
209 | secondary: atoms({ background: 'yellow' }),
210 | },
211 | size: {
212 | md: atoms({ fontSize: 'large' }),
213 | lg: atoms({ fontSize: 'extraLarge' }),
214 | },
215 | },
216 | });
217 |
218 | export type ButtonVariants = Parameters[0];
219 | ```
220 |
221 | 2. Then use the `recipes` function to create variants and apply them to your `Box`:
222 |
223 | ```tsx
224 | // Button.tsx
225 | import { Box } from './Box';
226 | import { buttonRecipe, ButtonVariants } from './Button.css';
227 |
228 | type Props = {
229 | children: React.ReactNode;
230 | } & ButtonVariants;
231 |
232 | export const Button = ({
233 | children,
234 | size = 'md',
235 | kind = 'secondary',
236 | }: Props) => {
237 | return (
238 |
239 | {children}
240 |
241 | );
242 | };
243 |
244 | export default Button;
245 | ```
246 |
247 | For more context, refer to [@vanilla-extract/recipe][recipes] or feel free [to open an issue in this project](https://github.com/TheMightyPenguin/dessert-box/issues/new) if the integration is not working as you'd expect!
248 |
249 | ## API
250 |
251 | ### createBox(options: { atoms: AtomsFn, defaultClassName?: string })
252 |
253 | Creates a `` component that takes atoms at the root level.
254 |
255 | ```jsx
256 | import { createBox } from '@dessert-box/react';
257 | import { atoms } from './atoms.css';
258 |
259 | const Box = createBox({ atoms });
260 |
261 | ;
262 | ```
263 |
264 | ### createBoxWithAtomsProp(options: { atoms: AtomsFn, defaultClassName?: string })
265 |
266 | Creates a `` component that takes atoms as a prop called `atoms`.
267 |
268 | ```jsx
269 | import { createBoxWithAtomsProp } from '@dessert-box/react';
270 | import { atoms } from './atoms.css';
271 |
272 | const Box = createBoxWithAtomsProp({ atoms });
273 |
274 | ;
275 | ```
276 |
277 | ## Running the example app
278 |
279 | Run `npm install` then `npm run build` in the root folder (the one with this README file).
280 |
281 | Then move into the example folder `cd example` and run `npm install` and `npm start`.
282 |
283 | ## How does it work?
284 |
285 | This works by depending on build-time generated CSS by [sprinkles](https://github.com/seek-oss/vanilla-extract/tree/3360bdfc9220024e7ffa49b3b198b72743d4e264/packages/sprinkles), and then using the `atomsFn` function to lookup classNames in runtime. So it does have a runtime footprint, but should be pretty minimal. I'm still experimenting to see if it's possible to remove that, but other approaches may lead to other constraints or similar runtime.
286 |
287 | ## Thanks
288 |
289 | - Thanks to the team at Seek for [vanilla-extract](https://github.com/seek-oss/vanilla-extract) and [`sprinkles`](https://github.com/seek-oss/vanilla-extract/tree/master/packages/sprinkles), this would not be possible without these great libs and the technical feats they accomplish.
290 |
291 | ## FAQ
292 |
293 | - What is a Box component?
294 |
295 | > It's a generic element that allows you to prototype fast and takes a variety of styling props (think of exposing a lot of CSS attributes as props on a component).
296 |
297 | - Why should I use a Box component?
298 |
299 | > There are many versions and flavors of a Box component, some are more [flexible](https://chakra-ui.com/docs/layout/box), while others are more [restrictive](https://seek-oss.github.io/braid-design-system/components/Box). The Box in this library falls into the latter category (restrictive), and it's more geared towards being the a lower level API of your Design System (or serving as inspiration for it).
300 |
301 | This Box component is meant to be used as a primitive for consuming design tokens, giving you a nice balance between flexibility and constraints. You can use it as an lower level API to implement your other components (Buttons, Card, Layout components, ...), and also as a prototyping and general usage component:
302 |
303 | - As a prototyping tool, it allows you to use all of your design tokens to generate new designs and evaluate if you need to iterate on your foundations, or to validate if they work for your use cases.
304 | - For general usage you can still have the guarantee that users of your system won't do anything impossible (e.g.: using a value that is not part of the design tokens) but still have a productive experience working on UI.
305 |
306 | [sprinkles]: https://github.com/seek-oss/vanilla-extract/tree/master/packages/sprinkles
307 | [vanilla-extract]: https://github.com/seek-oss/vanilla-extract
308 | [recipes]: https://github.com/seek-oss/vanilla-extract#recipes-api
309 |
--------------------------------------------------------------------------------
/babel-jest.config.js:
--------------------------------------------------------------------------------
1 | const baseConfig = require('./babel.config');
2 |
3 | module.exports = {
4 | ...baseConfig,
5 | plugins: [...(baseConfig.plugins ?? []), '@vanilla-extract/babel-plugin'],
6 | };
7 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@babel/preset-typescript',
4 | '@babel/preset-react',
5 | ['@babel/preset-env', { targets: { node: 12 } }],
6 | ],
7 | };
8 |
--------------------------------------------------------------------------------
/examples/react/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Example
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dessert-box-example-react",
3 | "version": "1.0.0",
4 | "description": "",
5 | "private": true,
6 | "author": "Victor Tortolero ",
7 | "scripts": {
8 | "dev": "vite",
9 | "build": "vite build",
10 | "preview": "vite preview"
11 | },
12 | "keywords": [],
13 | "license": "MIT",
14 | "dependencies": {
15 | "@dessert-box/react": "*",
16 | "@vanilla-extract/css": "^1.11.0",
17 | "@vanilla-extract/recipes": "^0.4.0",
18 | "@vanilla-extract/sprinkles": "^1.6.0",
19 | "react": "^18.2.0",
20 | "react-dom": "^18.2.0"
21 | },
22 | "devDependencies": {
23 | "@types/react": "^18.0.24",
24 | "@types/react-dom": "^18.0.8",
25 | "@vanilla-extract/vite-plugin": "^3.6.1",
26 | "@vitejs/plugin-react": "^2.2.0",
27 | "vite": "^3.2.2"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/examples/react/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: 5.4
2 |
3 | specifiers:
4 | '@dessert-box/react': ^0.4.0
5 | '@types/react': ^18.0.24
6 | '@types/react-dom': ^18.0.8
7 | '@vanilla-extract/css': ^1.9.1
8 | '@vanilla-extract/recipes': ^0.2.5
9 | '@vanilla-extract/sprinkles': ^1.5.0
10 | '@vanilla-extract/vite-plugin': ^3.6.1
11 | '@vitejs/plugin-react': ^2.2.0
12 | react: ^18.2.0
13 | react-dom: ^18.2.0
14 | vite: ^3.2.2
15 |
16 | dependencies:
17 | '@dessert-box/react': 0.4.0_react@18.2.0
18 | '@vanilla-extract/css': 1.9.1
19 | '@vanilla-extract/recipes': 0.2.5_@vanilla-extract+css@1.9.1
20 | '@vanilla-extract/sprinkles': 1.5.0_@vanilla-extract+css@1.9.1
21 | react: 18.2.0
22 | react-dom: 18.2.0_react@18.2.0
23 |
24 | devDependencies:
25 | '@types/react': 18.0.24
26 | '@types/react-dom': 18.0.8
27 | '@vanilla-extract/vite-plugin': 3.6.1_vite@3.2.2
28 | '@vitejs/plugin-react': 2.2.0_vite@3.2.2
29 | vite: 3.2.2
30 |
31 | packages:
32 |
33 | /@ampproject/remapping/2.2.0:
34 | resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==}
35 | engines: {node: '>=6.0.0'}
36 | dependencies:
37 | '@jridgewell/gen-mapping': 0.1.1
38 | '@jridgewell/trace-mapping': 0.3.17
39 | dev: true
40 |
41 | /@babel/code-frame/7.18.6:
42 | resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==}
43 | engines: {node: '>=6.9.0'}
44 | dependencies:
45 | '@babel/highlight': 7.18.6
46 | dev: true
47 |
48 | /@babel/compat-data/7.20.0:
49 | resolution: {integrity: sha512-Gt9jszFJYq7qzXVK4slhc6NzJXnOVmRECWcVjF/T23rNXD9NtWQ0W3qxdg+p9wWIB+VQw3GYV/U2Ha9bRTfs4w==}
50 | engines: {node: '>=6.9.0'}
51 | dev: true
52 |
53 | /@babel/core/7.19.6:
54 | resolution: {integrity: sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==}
55 | engines: {node: '>=6.9.0'}
56 | dependencies:
57 | '@ampproject/remapping': 2.2.0
58 | '@babel/code-frame': 7.18.6
59 | '@babel/generator': 7.20.0
60 | '@babel/helper-compilation-targets': 7.20.0_@babel+core@7.19.6
61 | '@babel/helper-module-transforms': 7.19.6
62 | '@babel/helpers': 7.20.0
63 | '@babel/parser': 7.20.0
64 | '@babel/template': 7.18.10
65 | '@babel/traverse': 7.20.0
66 | '@babel/types': 7.20.0
67 | convert-source-map: 1.9.0
68 | debug: 4.3.4
69 | gensync: 1.0.0-beta.2
70 | json5: 2.2.1
71 | semver: 6.3.0
72 | transitivePeerDependencies:
73 | - supports-color
74 | dev: true
75 |
76 | /@babel/generator/7.20.0:
77 | resolution: {integrity: sha512-GUPcXxWibClgmYJuIwC2Bc2Lg+8b9VjaJ+HlNdACEVt+Wlr1eoU1OPZjZRm7Hzl0gaTsUZNQfeihvZJhG7oc3w==}
78 | engines: {node: '>=6.9.0'}
79 | dependencies:
80 | '@babel/types': 7.20.0
81 | '@jridgewell/gen-mapping': 0.3.2
82 | jsesc: 2.5.2
83 | dev: true
84 |
85 | /@babel/helper-annotate-as-pure/7.18.6:
86 | resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==}
87 | engines: {node: '>=6.9.0'}
88 | dependencies:
89 | '@babel/types': 7.20.0
90 | dev: true
91 |
92 | /@babel/helper-compilation-targets/7.20.0_@babel+core@7.19.6:
93 | resolution: {integrity: sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==}
94 | engines: {node: '>=6.9.0'}
95 | peerDependencies:
96 | '@babel/core': ^7.0.0
97 | dependencies:
98 | '@babel/compat-data': 7.20.0
99 | '@babel/core': 7.19.6
100 | '@babel/helper-validator-option': 7.18.6
101 | browserslist: 4.21.4
102 | semver: 6.3.0
103 | dev: true
104 |
105 | /@babel/helper-environment-visitor/7.18.9:
106 | resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==}
107 | engines: {node: '>=6.9.0'}
108 | dev: true
109 |
110 | /@babel/helper-function-name/7.19.0:
111 | resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==}
112 | engines: {node: '>=6.9.0'}
113 | dependencies:
114 | '@babel/template': 7.18.10
115 | '@babel/types': 7.20.0
116 | dev: true
117 |
118 | /@babel/helper-hoist-variables/7.18.6:
119 | resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==}
120 | engines: {node: '>=6.9.0'}
121 | dependencies:
122 | '@babel/types': 7.20.0
123 | dev: true
124 |
125 | /@babel/helper-module-imports/7.18.6:
126 | resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==}
127 | engines: {node: '>=6.9.0'}
128 | dependencies:
129 | '@babel/types': 7.20.0
130 | dev: true
131 |
132 | /@babel/helper-module-transforms/7.19.6:
133 | resolution: {integrity: sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==}
134 | engines: {node: '>=6.9.0'}
135 | dependencies:
136 | '@babel/helper-environment-visitor': 7.18.9
137 | '@babel/helper-module-imports': 7.18.6
138 | '@babel/helper-simple-access': 7.19.4
139 | '@babel/helper-split-export-declaration': 7.18.6
140 | '@babel/helper-validator-identifier': 7.19.1
141 | '@babel/template': 7.18.10
142 | '@babel/traverse': 7.20.0
143 | '@babel/types': 7.20.0
144 | transitivePeerDependencies:
145 | - supports-color
146 | dev: true
147 |
148 | /@babel/helper-plugin-utils/7.19.0:
149 | resolution: {integrity: sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==}
150 | engines: {node: '>=6.9.0'}
151 | dev: true
152 |
153 | /@babel/helper-simple-access/7.19.4:
154 | resolution: {integrity: sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==}
155 | engines: {node: '>=6.9.0'}
156 | dependencies:
157 | '@babel/types': 7.20.0
158 | dev: true
159 |
160 | /@babel/helper-split-export-declaration/7.18.6:
161 | resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==}
162 | engines: {node: '>=6.9.0'}
163 | dependencies:
164 | '@babel/types': 7.20.0
165 | dev: true
166 |
167 | /@babel/helper-string-parser/7.19.4:
168 | resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==}
169 | engines: {node: '>=6.9.0'}
170 | dev: true
171 |
172 | /@babel/helper-validator-identifier/7.19.1:
173 | resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==}
174 | engines: {node: '>=6.9.0'}
175 | dev: true
176 |
177 | /@babel/helper-validator-option/7.18.6:
178 | resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==}
179 | engines: {node: '>=6.9.0'}
180 | dev: true
181 |
182 | /@babel/helpers/7.20.0:
183 | resolution: {integrity: sha512-aGMjYraN0zosCEthoGLdqot1oRsmxVTQRHadsUPz5QM44Zej2PYRz7XiDE7GqnkZnNtLbOuxqoZw42vkU7+XEQ==}
184 | engines: {node: '>=6.9.0'}
185 | dependencies:
186 | '@babel/template': 7.18.10
187 | '@babel/traverse': 7.20.0
188 | '@babel/types': 7.20.0
189 | transitivePeerDependencies:
190 | - supports-color
191 | dev: true
192 |
193 | /@babel/highlight/7.18.6:
194 | resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==}
195 | engines: {node: '>=6.9.0'}
196 | dependencies:
197 | '@babel/helper-validator-identifier': 7.19.1
198 | chalk: 2.4.2
199 | js-tokens: 4.0.0
200 | dev: true
201 |
202 | /@babel/parser/7.20.0:
203 | resolution: {integrity: sha512-G9VgAhEaICnz8iiJeGJQyVl6J2nTjbW0xeisva0PK6XcKsga7BIaqm4ZF8Rg1Wbaqmy6znspNqhPaPkyukujzg==}
204 | engines: {node: '>=6.0.0'}
205 | hasBin: true
206 | dependencies:
207 | '@babel/types': 7.20.0
208 | dev: true
209 |
210 | /@babel/plugin-syntax-jsx/7.18.6_@babel+core@7.19.6:
211 | resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==}
212 | engines: {node: '>=6.9.0'}
213 | peerDependencies:
214 | '@babel/core': ^7.0.0-0
215 | dependencies:
216 | '@babel/core': 7.19.6
217 | '@babel/helper-plugin-utils': 7.19.0
218 | dev: true
219 |
220 | /@babel/plugin-syntax-typescript/7.20.0_@babel+core@7.19.6:
221 | resolution: {integrity: sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==}
222 | engines: {node: '>=6.9.0'}
223 | peerDependencies:
224 | '@babel/core': ^7.0.0-0
225 | dependencies:
226 | '@babel/core': 7.19.6
227 | '@babel/helper-plugin-utils': 7.19.0
228 | dev: true
229 |
230 | /@babel/plugin-transform-react-jsx-development/7.18.6_@babel+core@7.19.6:
231 | resolution: {integrity: sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==}
232 | engines: {node: '>=6.9.0'}
233 | peerDependencies:
234 | '@babel/core': ^7.0.0-0
235 | dependencies:
236 | '@babel/core': 7.19.6
237 | '@babel/plugin-transform-react-jsx': 7.19.0_@babel+core@7.19.6
238 | dev: true
239 |
240 | /@babel/plugin-transform-react-jsx-self/7.18.6_@babel+core@7.19.6:
241 | resolution: {integrity: sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==}
242 | engines: {node: '>=6.9.0'}
243 | peerDependencies:
244 | '@babel/core': ^7.0.0-0
245 | dependencies:
246 | '@babel/core': 7.19.6
247 | '@babel/helper-plugin-utils': 7.19.0
248 | dev: true
249 |
250 | /@babel/plugin-transform-react-jsx-source/7.19.6_@babel+core@7.19.6:
251 | resolution: {integrity: sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==}
252 | engines: {node: '>=6.9.0'}
253 | peerDependencies:
254 | '@babel/core': ^7.0.0-0
255 | dependencies:
256 | '@babel/core': 7.19.6
257 | '@babel/helper-plugin-utils': 7.19.0
258 | dev: true
259 |
260 | /@babel/plugin-transform-react-jsx/7.19.0_@babel+core@7.19.6:
261 | resolution: {integrity: sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==}
262 | engines: {node: '>=6.9.0'}
263 | peerDependencies:
264 | '@babel/core': ^7.0.0-0
265 | dependencies:
266 | '@babel/core': 7.19.6
267 | '@babel/helper-annotate-as-pure': 7.18.6
268 | '@babel/helper-module-imports': 7.18.6
269 | '@babel/helper-plugin-utils': 7.19.0
270 | '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.19.6
271 | '@babel/types': 7.20.0
272 | dev: true
273 |
274 | /@babel/runtime/7.20.0:
275 | resolution: {integrity: sha512-NDYdls71fTXoU8TZHfbBWg7DiZfNzClcKui/+kyi6ppD2L1qnWW3VV6CjtaBXSUGGhiTWJ6ereOIkUvenif66Q==}
276 | engines: {node: '>=6.9.0'}
277 | dependencies:
278 | regenerator-runtime: 0.13.10
279 |
280 | /@babel/template/7.18.10:
281 | resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==}
282 | engines: {node: '>=6.9.0'}
283 | dependencies:
284 | '@babel/code-frame': 7.18.6
285 | '@babel/parser': 7.20.0
286 | '@babel/types': 7.20.0
287 | dev: true
288 |
289 | /@babel/traverse/7.20.0:
290 | resolution: {integrity: sha512-5+cAXQNARgjRUK0JWu2UBwja4JLSO/rBMPJzpsKb+oBF5xlUuCfljQepS4XypBQoiigL0VQjTZy6WiONtUdScQ==}
291 | engines: {node: '>=6.9.0'}
292 | dependencies:
293 | '@babel/code-frame': 7.18.6
294 | '@babel/generator': 7.20.0
295 | '@babel/helper-environment-visitor': 7.18.9
296 | '@babel/helper-function-name': 7.19.0
297 | '@babel/helper-hoist-variables': 7.18.6
298 | '@babel/helper-split-export-declaration': 7.18.6
299 | '@babel/parser': 7.20.0
300 | '@babel/types': 7.20.0
301 | debug: 4.3.4
302 | globals: 11.12.0
303 | transitivePeerDependencies:
304 | - supports-color
305 | dev: true
306 |
307 | /@babel/types/7.20.0:
308 | resolution: {integrity: sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg==}
309 | engines: {node: '>=6.9.0'}
310 | dependencies:
311 | '@babel/helper-string-parser': 7.19.4
312 | '@babel/helper-validator-identifier': 7.19.1
313 | to-fast-properties: 2.0.0
314 | dev: true
315 |
316 | /@dessert-box/core/0.2.0:
317 | resolution: {integrity: sha512-Vqaec6i0cvS1r54kU6CfOQECi6dPWzz6DVVxJABOxqPmVk8fOSy6pIKsK0YyPFGRpZK/FXkJ1YhURUOW1OxOVQ==}
318 | dev: false
319 |
320 | /@dessert-box/react/0.4.0_react@18.2.0:
321 | resolution: {integrity: sha512-r2sqkX4y+fDLtRGGpCitI5ckzLZl3DPMUhKBstf3qoZbfoAVHB0HRHgrfRni3F0qZZgXowR880lL8IDpPpRiGg==}
322 | peerDependencies:
323 | react: '>=16.8.0'
324 | dependencies:
325 | '@dessert-box/core': 0.2.0
326 | react: 18.2.0
327 | dev: false
328 |
329 | /@emotion/hash/0.8.0:
330 | resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==}
331 |
332 | /@esbuild/android-arm/0.15.12:
333 | resolution: {integrity: sha512-IC7TqIqiyE0MmvAhWkl/8AEzpOtbhRNDo7aph47We1NbE5w2bt/Q+giAhe0YYeVpYnIhGMcuZY92qDK6dQauvA==}
334 | engines: {node: '>=12'}
335 | cpu: [arm]
336 | os: [android]
337 | requiresBuild: true
338 | dev: true
339 | optional: true
340 |
341 | /@esbuild/linux-loong64/0.15.12:
342 | resolution: {integrity: sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw==}
343 | engines: {node: '>=12'}
344 | cpu: [loong64]
345 | os: [linux]
346 | requiresBuild: true
347 | dev: true
348 | optional: true
349 |
350 | /@jridgewell/gen-mapping/0.1.1:
351 | resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==}
352 | engines: {node: '>=6.0.0'}
353 | dependencies:
354 | '@jridgewell/set-array': 1.1.2
355 | '@jridgewell/sourcemap-codec': 1.4.14
356 | dev: true
357 |
358 | /@jridgewell/gen-mapping/0.3.2:
359 | resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==}
360 | engines: {node: '>=6.0.0'}
361 | dependencies:
362 | '@jridgewell/set-array': 1.1.2
363 | '@jridgewell/sourcemap-codec': 1.4.14
364 | '@jridgewell/trace-mapping': 0.3.17
365 | dev: true
366 |
367 | /@jridgewell/resolve-uri/3.1.0:
368 | resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
369 | engines: {node: '>=6.0.0'}
370 | dev: true
371 |
372 | /@jridgewell/set-array/1.1.2:
373 | resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
374 | engines: {node: '>=6.0.0'}
375 | dev: true
376 |
377 | /@jridgewell/sourcemap-codec/1.4.14:
378 | resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
379 | dev: true
380 |
381 | /@jridgewell/trace-mapping/0.3.17:
382 | resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==}
383 | dependencies:
384 | '@jridgewell/resolve-uri': 3.1.0
385 | '@jridgewell/sourcemap-codec': 1.4.14
386 | dev: true
387 |
388 | /@types/prop-types/15.7.5:
389 | resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
390 | dev: true
391 |
392 | /@types/react-dom/18.0.8:
393 | resolution: {integrity: sha512-C3GYO0HLaOkk9dDAz3Dl4sbe4AKUGTCfFIZsz3n/82dPNN8Du533HzKatDxeUYWu24wJgMP1xICqkWk1YOLOIw==}
394 | dependencies:
395 | '@types/react': 18.0.24
396 | dev: true
397 |
398 | /@types/react/18.0.24:
399 | resolution: {integrity: sha512-wRJWT6ouziGUy+9uX0aW4YOJxAY0bG6/AOk5AW5QSvZqI7dk6VBIbXvcVgIw/W5Jrl24f77df98GEKTJGOLx7Q==}
400 | dependencies:
401 | '@types/prop-types': 15.7.5
402 | '@types/scheduler': 0.16.2
403 | csstype: 3.1.1
404 | dev: true
405 |
406 | /@types/scheduler/0.16.2:
407 | resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
408 | dev: true
409 |
410 | /@vanilla-extract/babel-plugin-debug-ids/1.0.0:
411 | resolution: {integrity: sha512-Q2Nh/0FEAENfcphAv+fvcMoKfl3bhPWO/2x3MPviNAhsTsvuvYPuRtLjcXwoe4aJ8MxxI46JLY33j8NBEzpTIg==}
412 | dependencies:
413 | '@babel/core': 7.19.6
414 | transitivePeerDependencies:
415 | - supports-color
416 | dev: true
417 |
418 | /@vanilla-extract/css/1.9.1:
419 | resolution: {integrity: sha512-pu2SFiff5jRhPwvGoj8cM5l/qIyLvigOmy22ss5DGjwV5pJYezRjDLxWumi2luIwioMWvh9EozCjyfH8nq+7fQ==}
420 | dependencies:
421 | '@emotion/hash': 0.8.0
422 | '@vanilla-extract/private': 1.0.3
423 | ahocorasick: 1.0.2
424 | chalk: 4.1.2
425 | css-what: 5.1.0
426 | cssesc: 3.0.0
427 | csstype: 3.1.1
428 | deep-object-diff: 1.1.7
429 | deepmerge: 4.2.2
430 | media-query-parser: 2.0.2
431 | outdent: 0.8.0
432 |
433 | /@vanilla-extract/integration/6.0.0:
434 | resolution: {integrity: sha512-uBz4QAhKYswyhN3LYd4duuN3uq7WT1jKckd0sP2+Y8gL+6UXdhN9QOUvNBfvofkrYYWqS8efH4hnsGyyWW8f+w==}
435 | dependencies:
436 | '@babel/core': 7.19.6
437 | '@babel/plugin-syntax-typescript': 7.20.0_@babel+core@7.19.6
438 | '@vanilla-extract/babel-plugin-debug-ids': 1.0.0
439 | '@vanilla-extract/css': 1.9.1
440 | esbuild: 0.11.23
441 | eval: 0.1.6
442 | find-up: 5.0.0
443 | javascript-stringify: 2.1.0
444 | lodash: 4.17.21
445 | outdent: 0.8.0
446 | transitivePeerDependencies:
447 | - supports-color
448 | dev: true
449 |
450 | /@vanilla-extract/private/1.0.3:
451 | resolution: {integrity: sha512-17kVyLq3ePTKOkveHxXuIJZtGYs+cSoev7BlP+Lf4916qfDhk/HBjvlYDe8egrea7LNPHKwSZJK/bzZC+Q6AwQ==}
452 |
453 | /@vanilla-extract/recipes/0.2.5_@vanilla-extract+css@1.9.1:
454 | resolution: {integrity: sha512-OWXUUiFJdswD3+Xg8f8avuw/vAHZRFS4oHqFeoV1TcO8cfbDQ0zmkreBHvyspoJU+qsyWK48yPHKSptqNRPy9Q==}
455 | peerDependencies:
456 | '@vanilla-extract/css': ^1.0.0
457 | dependencies:
458 | '@vanilla-extract/css': 1.9.1
459 | dev: false
460 |
461 | /@vanilla-extract/sprinkles/1.5.0_@vanilla-extract+css@1.9.1:
462 | resolution: {integrity: sha512-W58f2Rzz5lLmk0jbhgStVlZl5wEiPB1Ur3fRvUaBM+MrifZ3qskmFq/CiH//fEYeG5Dh9vF1qRviMMH46cX9Nw==}
463 | peerDependencies:
464 | '@vanilla-extract/css': ^1.0.0
465 | dependencies:
466 | '@vanilla-extract/css': 1.9.1
467 | dev: false
468 |
469 | /@vanilla-extract/vite-plugin/3.6.1_vite@3.2.2:
470 | resolution: {integrity: sha512-Pn3LhndH0NYPLdJejoExS1KdoFE2ZhtGnc2aH3EJDXKqobmDucdtmNZiIJ2NtI/1/cJ9ZnHuzXxpTE6V9yy8Cg==}
471 | peerDependencies:
472 | vite: ^2.2.3 || ^3.0.0
473 | dependencies:
474 | '@vanilla-extract/integration': 6.0.0
475 | outdent: 0.8.0
476 | postcss: 8.4.18
477 | postcss-load-config: 3.1.4_postcss@8.4.18
478 | vite: 3.2.2
479 | transitivePeerDependencies:
480 | - supports-color
481 | - ts-node
482 | dev: true
483 |
484 | /@vitejs/plugin-react/2.2.0_vite@3.2.2:
485 | resolution: {integrity: sha512-FFpefhvExd1toVRlokZgxgy2JtnBOdp4ZDsq7ldCWaqGSGn9UhWMAVm/1lxPL14JfNS5yGz+s9yFrQY6shoStA==}
486 | engines: {node: ^14.18.0 || >=16.0.0}
487 | peerDependencies:
488 | vite: ^3.0.0
489 | dependencies:
490 | '@babel/core': 7.19.6
491 | '@babel/plugin-transform-react-jsx': 7.19.0_@babel+core@7.19.6
492 | '@babel/plugin-transform-react-jsx-development': 7.18.6_@babel+core@7.19.6
493 | '@babel/plugin-transform-react-jsx-self': 7.18.6_@babel+core@7.19.6
494 | '@babel/plugin-transform-react-jsx-source': 7.19.6_@babel+core@7.19.6
495 | magic-string: 0.26.7
496 | react-refresh: 0.14.0
497 | vite: 3.2.2
498 | transitivePeerDependencies:
499 | - supports-color
500 | dev: true
501 |
502 | /ahocorasick/1.0.2:
503 | resolution: {integrity: sha512-hCOfMzbFx5IDutmWLAt6MZwOUjIfSM9G9FyVxytmE4Rs/5YDPWQrD/+IR1w+FweD9H2oOZEnv36TmkjhNURBVA==}
504 |
505 | /ansi-styles/3.2.1:
506 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
507 | engines: {node: '>=4'}
508 | dependencies:
509 | color-convert: 1.9.3
510 | dev: true
511 |
512 | /ansi-styles/4.3.0:
513 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
514 | engines: {node: '>=8'}
515 | dependencies:
516 | color-convert: 2.0.1
517 |
518 | /browserslist/4.21.4:
519 | resolution: {integrity: sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==}
520 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
521 | hasBin: true
522 | dependencies:
523 | caniuse-lite: 1.0.30001427
524 | electron-to-chromium: 1.4.284
525 | node-releases: 2.0.6
526 | update-browserslist-db: 1.0.10_browserslist@4.21.4
527 | dev: true
528 |
529 | /caniuse-lite/1.0.30001427:
530 | resolution: {integrity: sha512-lfXQ73oB9c8DP5Suxaszm+Ta2sr/4tf8+381GkIm1MLj/YdLf+rEDyDSRCzeltuyTVGm+/s18gdZ0q+Wmp8VsQ==}
531 | dev: true
532 |
533 | /chalk/2.4.2:
534 | resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
535 | engines: {node: '>=4'}
536 | dependencies:
537 | ansi-styles: 3.2.1
538 | escape-string-regexp: 1.0.5
539 | supports-color: 5.5.0
540 | dev: true
541 |
542 | /chalk/4.1.2:
543 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
544 | engines: {node: '>=10'}
545 | dependencies:
546 | ansi-styles: 4.3.0
547 | supports-color: 7.2.0
548 |
549 | /color-convert/1.9.3:
550 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
551 | dependencies:
552 | color-name: 1.1.3
553 | dev: true
554 |
555 | /color-convert/2.0.1:
556 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
557 | engines: {node: '>=7.0.0'}
558 | dependencies:
559 | color-name: 1.1.4
560 |
561 | /color-name/1.1.3:
562 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
563 | dev: true
564 |
565 | /color-name/1.1.4:
566 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
567 |
568 | /convert-source-map/1.9.0:
569 | resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
570 | dev: true
571 |
572 | /css-what/5.1.0:
573 | resolution: {integrity: sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==}
574 | engines: {node: '>= 6'}
575 |
576 | /cssesc/3.0.0:
577 | resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
578 | engines: {node: '>=4'}
579 | hasBin: true
580 |
581 | /csstype/3.1.1:
582 | resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==}
583 |
584 | /debug/4.3.4:
585 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
586 | engines: {node: '>=6.0'}
587 | peerDependencies:
588 | supports-color: '*'
589 | peerDependenciesMeta:
590 | supports-color:
591 | optional: true
592 | dependencies:
593 | ms: 2.1.2
594 | dev: true
595 |
596 | /deep-object-diff/1.1.7:
597 | resolution: {integrity: sha512-QkgBca0mL08P6HiOjoqvmm6xOAl2W6CT2+34Ljhg0OeFan8cwlcdq8jrLKsBBuUFAZLsN5b6y491KdKEoSo9lg==}
598 |
599 | /deepmerge/4.2.2:
600 | resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==}
601 | engines: {node: '>=0.10.0'}
602 |
603 | /electron-to-chromium/1.4.284:
604 | resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==}
605 | dev: true
606 |
607 | /esbuild-android-64/0.15.12:
608 | resolution: {integrity: sha512-MJKXwvPY9g0rGps0+U65HlTsM1wUs9lbjt5CU19RESqycGFDRijMDQsh68MtbzkqWSRdEtiKS1mtPzKneaAI0Q==}
609 | engines: {node: '>=12'}
610 | cpu: [x64]
611 | os: [android]
612 | requiresBuild: true
613 | dev: true
614 | optional: true
615 |
616 | /esbuild-android-arm64/0.15.12:
617 | resolution: {integrity: sha512-Hc9SEcZbIMhhLcvhr1DH+lrrec9SFTiRzfJ7EGSBZiiw994gfkVV6vG0sLWqQQ6DD7V4+OggB+Hn0IRUdDUqvA==}
618 | engines: {node: '>=12'}
619 | cpu: [arm64]
620 | os: [android]
621 | requiresBuild: true
622 | dev: true
623 | optional: true
624 |
625 | /esbuild-darwin-64/0.15.12:
626 | resolution: {integrity: sha512-qkmqrTVYPFiePt5qFjP8w/S+GIUMbt6k8qmiPraECUWfPptaPJUGkCKrWEfYFRWB7bY23FV95rhvPyh/KARP8Q==}
627 | engines: {node: '>=12'}
628 | cpu: [x64]
629 | os: [darwin]
630 | requiresBuild: true
631 | dev: true
632 | optional: true
633 |
634 | /esbuild-darwin-arm64/0.15.12:
635 | resolution: {integrity: sha512-z4zPX02tQ41kcXMyN3c/GfZpIjKoI/BzHrdKUwhC/Ki5BAhWv59A9M8H+iqaRbwpzYrYidTybBwiZAIWCLJAkw==}
636 | engines: {node: '>=12'}
637 | cpu: [arm64]
638 | os: [darwin]
639 | requiresBuild: true
640 | dev: true
641 | optional: true
642 |
643 | /esbuild-freebsd-64/0.15.12:
644 | resolution: {integrity: sha512-XFL7gKMCKXLDiAiBjhLG0XECliXaRLTZh6hsyzqUqPUf/PY4C6EJDTKIeqqPKXaVJ8+fzNek88285krSz1QECw==}
645 | engines: {node: '>=12'}
646 | cpu: [x64]
647 | os: [freebsd]
648 | requiresBuild: true
649 | dev: true
650 | optional: true
651 |
652 | /esbuild-freebsd-arm64/0.15.12:
653 | resolution: {integrity: sha512-jwEIu5UCUk6TjiG1X+KQnCGISI+ILnXzIzt9yDVrhjug2fkYzlLbl0K43q96Q3KB66v6N1UFF0r5Ks4Xo7i72g==}
654 | engines: {node: '>=12'}
655 | cpu: [arm64]
656 | os: [freebsd]
657 | requiresBuild: true
658 | dev: true
659 | optional: true
660 |
661 | /esbuild-linux-32/0.15.12:
662 | resolution: {integrity: sha512-uSQuSEyF1kVzGzuIr4XM+v7TPKxHjBnLcwv2yPyCz8riV8VUCnO/C4BF3w5dHiVpCd5Z1cebBtZJNlC4anWpwA==}
663 | engines: {node: '>=12'}
664 | cpu: [ia32]
665 | os: [linux]
666 | requiresBuild: true
667 | dev: true
668 | optional: true
669 |
670 | /esbuild-linux-64/0.15.12:
671 | resolution: {integrity: sha512-QcgCKb7zfJxqT9o5z9ZUeGH1k8N6iX1Y7VNsEi5F9+HzN1OIx7ESxtQXDN9jbeUSPiRH1n9cw6gFT3H4qbdvcA==}
672 | engines: {node: '>=12'}
673 | cpu: [x64]
674 | os: [linux]
675 | requiresBuild: true
676 | dev: true
677 | optional: true
678 |
679 | /esbuild-linux-arm/0.15.12:
680 | resolution: {integrity: sha512-Wf7T0aNylGcLu7hBnzMvsTfEXdEdJY/hY3u36Vla21aY66xR0MS5I1Hw8nVquXjTN0A6fk/vnr32tkC/C2lb0A==}
681 | engines: {node: '>=12'}
682 | cpu: [arm]
683 | os: [linux]
684 | requiresBuild: true
685 | dev: true
686 | optional: true
687 |
688 | /esbuild-linux-arm64/0.15.12:
689 | resolution: {integrity: sha512-HtNq5xm8fUpZKwWKS2/YGwSfTF+339L4aIA8yphNKYJckd5hVdhfdl6GM2P3HwLSCORS++++7++//ApEwXEuAQ==}
690 | engines: {node: '>=12'}
691 | cpu: [arm64]
692 | os: [linux]
693 | requiresBuild: true
694 | dev: true
695 | optional: true
696 |
697 | /esbuild-linux-mips64le/0.15.12:
698 | resolution: {integrity: sha512-Qol3+AvivngUZkTVFgLpb0H6DT+N5/zM3V1YgTkryPYFeUvuT5JFNDR3ZiS6LxhyF8EE+fiNtzwlPqMDqVcc6A==}
699 | engines: {node: '>=12'}
700 | cpu: [mips64el]
701 | os: [linux]
702 | requiresBuild: true
703 | dev: true
704 | optional: true
705 |
706 | /esbuild-linux-ppc64le/0.15.12:
707 | resolution: {integrity: sha512-4D8qUCo+CFKaR0cGXtGyVsOI7w7k93Qxb3KFXWr75An0DHamYzq8lt7TNZKoOq/Gh8c40/aKaxvcZnTgQ0TJNg==}
708 | engines: {node: '>=12'}
709 | cpu: [ppc64]
710 | os: [linux]
711 | requiresBuild: true
712 | dev: true
713 | optional: true
714 |
715 | /esbuild-linux-riscv64/0.15.12:
716 | resolution: {integrity: sha512-G9w6NcuuCI6TUUxe6ka0enjZHDnSVK8bO+1qDhMOCtl7Tr78CcZilJj8SGLN00zO5iIlwNRZKHjdMpfFgNn1VA==}
717 | engines: {node: '>=12'}
718 | cpu: [riscv64]
719 | os: [linux]
720 | requiresBuild: true
721 | dev: true
722 | optional: true
723 |
724 | /esbuild-linux-s390x/0.15.12:
725 | resolution: {integrity: sha512-Lt6BDnuXbXeqSlVuuUM5z18GkJAZf3ERskGZbAWjrQoi9xbEIsj/hEzVnSAFLtkfLuy2DE4RwTcX02tZFunXww==}
726 | engines: {node: '>=12'}
727 | cpu: [s390x]
728 | os: [linux]
729 | requiresBuild: true
730 | dev: true
731 | optional: true
732 |
733 | /esbuild-netbsd-64/0.15.12:
734 | resolution: {integrity: sha512-jlUxCiHO1dsqoURZDQts+HK100o0hXfi4t54MNRMCAqKGAV33JCVvMplLAa2FwviSojT/5ZG5HUfG3gstwAG8w==}
735 | engines: {node: '>=12'}
736 | cpu: [x64]
737 | os: [netbsd]
738 | requiresBuild: true
739 | dev: true
740 | optional: true
741 |
742 | /esbuild-openbsd-64/0.15.12:
743 | resolution: {integrity: sha512-1o1uAfRTMIWNOmpf8v7iudND0L6zRBYSH45sofCZywrcf7NcZA+c7aFsS1YryU+yN7aRppTqdUK1PgbZVaB1Dw==}
744 | engines: {node: '>=12'}
745 | cpu: [x64]
746 | os: [openbsd]
747 | requiresBuild: true
748 | dev: true
749 | optional: true
750 |
751 | /esbuild-sunos-64/0.15.12:
752 | resolution: {integrity: sha512-nkl251DpoWoBO9Eq9aFdoIt2yYmp4I3kvQjba3jFKlMXuqQ9A4q+JaqdkCouG3DHgAGnzshzaGu6xofGcXyPXg==}
753 | engines: {node: '>=12'}
754 | cpu: [x64]
755 | os: [sunos]
756 | requiresBuild: true
757 | dev: true
758 | optional: true
759 |
760 | /esbuild-windows-32/0.15.12:
761 | resolution: {integrity: sha512-WlGeBZHgPC00O08luIp5B2SP4cNCp/PcS+3Pcg31kdcJPopHxLkdCXtadLU9J82LCfw4TVls21A6lilQ9mzHrw==}
762 | engines: {node: '>=12'}
763 | cpu: [ia32]
764 | os: [win32]
765 | requiresBuild: true
766 | dev: true
767 | optional: true
768 |
769 | /esbuild-windows-64/0.15.12:
770 | resolution: {integrity: sha512-VActO3WnWZSN//xjSfbiGOSyC+wkZtI8I4KlgrTo5oHJM6z3MZZBCuFaZHd8hzf/W9KPhF0lY8OqlmWC9HO5AA==}
771 | engines: {node: '>=12'}
772 | cpu: [x64]
773 | os: [win32]
774 | requiresBuild: true
775 | dev: true
776 | optional: true
777 |
778 | /esbuild-windows-arm64/0.15.12:
779 | resolution: {integrity: sha512-Of3MIacva1OK/m4zCNIvBfz8VVROBmQT+gRX6pFTLPngFYcj6TFH/12VveAqq1k9VB2l28EoVMNMUCcmsfwyuA==}
780 | engines: {node: '>=12'}
781 | cpu: [arm64]
782 | os: [win32]
783 | requiresBuild: true
784 | dev: true
785 | optional: true
786 |
787 | /esbuild/0.11.23:
788 | resolution: {integrity: sha512-iaiZZ9vUF5wJV8ob1tl+5aJTrwDczlvGP0JoMmnpC2B0ppiMCu8n8gmy5ZTGl5bcG081XBVn+U+jP+mPFm5T5Q==}
789 | hasBin: true
790 | requiresBuild: true
791 | dev: true
792 |
793 | /esbuild/0.15.12:
794 | resolution: {integrity: sha512-PcT+/wyDqJQsRVhaE9uX/Oq4XLrFh0ce/bs2TJh4CSaw9xuvI+xFrH2nAYOADbhQjUgAhNWC5LKoUsakm4dxng==}
795 | engines: {node: '>=12'}
796 | hasBin: true
797 | requiresBuild: true
798 | optionalDependencies:
799 | '@esbuild/android-arm': 0.15.12
800 | '@esbuild/linux-loong64': 0.15.12
801 | esbuild-android-64: 0.15.12
802 | esbuild-android-arm64: 0.15.12
803 | esbuild-darwin-64: 0.15.12
804 | esbuild-darwin-arm64: 0.15.12
805 | esbuild-freebsd-64: 0.15.12
806 | esbuild-freebsd-arm64: 0.15.12
807 | esbuild-linux-32: 0.15.12
808 | esbuild-linux-64: 0.15.12
809 | esbuild-linux-arm: 0.15.12
810 | esbuild-linux-arm64: 0.15.12
811 | esbuild-linux-mips64le: 0.15.12
812 | esbuild-linux-ppc64le: 0.15.12
813 | esbuild-linux-riscv64: 0.15.12
814 | esbuild-linux-s390x: 0.15.12
815 | esbuild-netbsd-64: 0.15.12
816 | esbuild-openbsd-64: 0.15.12
817 | esbuild-sunos-64: 0.15.12
818 | esbuild-windows-32: 0.15.12
819 | esbuild-windows-64: 0.15.12
820 | esbuild-windows-arm64: 0.15.12
821 | dev: true
822 |
823 | /escalade/3.1.1:
824 | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
825 | engines: {node: '>=6'}
826 | dev: true
827 |
828 | /escape-string-regexp/1.0.5:
829 | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
830 | engines: {node: '>=0.8.0'}
831 | dev: true
832 |
833 | /eval/0.1.6:
834 | resolution: {integrity: sha512-o0XUw+5OGkXw4pJZzQoXUk+H87DHuC+7ZE//oSrRGtatTmr12oTnLfg6QOq9DyTt0c/p4TwzgmkKrBzWTSizyQ==}
835 | engines: {node: '>= 0.8'}
836 | dependencies:
837 | require-like: 0.1.2
838 | dev: true
839 |
840 | /find-up/5.0.0:
841 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
842 | engines: {node: '>=10'}
843 | dependencies:
844 | locate-path: 6.0.0
845 | path-exists: 4.0.0
846 | dev: true
847 |
848 | /fsevents/2.3.2:
849 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
850 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
851 | os: [darwin]
852 | requiresBuild: true
853 | dev: true
854 | optional: true
855 |
856 | /function-bind/1.1.1:
857 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
858 | dev: true
859 |
860 | /gensync/1.0.0-beta.2:
861 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
862 | engines: {node: '>=6.9.0'}
863 | dev: true
864 |
865 | /globals/11.12.0:
866 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
867 | engines: {node: '>=4'}
868 | dev: true
869 |
870 | /has-flag/3.0.0:
871 | resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
872 | engines: {node: '>=4'}
873 | dev: true
874 |
875 | /has-flag/4.0.0:
876 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
877 | engines: {node: '>=8'}
878 |
879 | /has/1.0.3:
880 | resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
881 | engines: {node: '>= 0.4.0'}
882 | dependencies:
883 | function-bind: 1.1.1
884 | dev: true
885 |
886 | /is-core-module/2.11.0:
887 | resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==}
888 | dependencies:
889 | has: 1.0.3
890 | dev: true
891 |
892 | /javascript-stringify/2.1.0:
893 | resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==}
894 | dev: true
895 |
896 | /js-tokens/4.0.0:
897 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
898 |
899 | /jsesc/2.5.2:
900 | resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
901 | engines: {node: '>=4'}
902 | hasBin: true
903 | dev: true
904 |
905 | /json5/2.2.1:
906 | resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==}
907 | engines: {node: '>=6'}
908 | hasBin: true
909 | dev: true
910 |
911 | /lilconfig/2.0.6:
912 | resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==}
913 | engines: {node: '>=10'}
914 | dev: true
915 |
916 | /locate-path/6.0.0:
917 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
918 | engines: {node: '>=10'}
919 | dependencies:
920 | p-locate: 5.0.0
921 | dev: true
922 |
923 | /lodash/4.17.21:
924 | resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
925 | dev: true
926 |
927 | /loose-envify/1.4.0:
928 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
929 | hasBin: true
930 | dependencies:
931 | js-tokens: 4.0.0
932 | dev: false
933 |
934 | /magic-string/0.26.7:
935 | resolution: {integrity: sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==}
936 | engines: {node: '>=12'}
937 | dependencies:
938 | sourcemap-codec: 1.4.8
939 | dev: true
940 |
941 | /media-query-parser/2.0.2:
942 | resolution: {integrity: sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==}
943 | dependencies:
944 | '@babel/runtime': 7.20.0
945 |
946 | /ms/2.1.2:
947 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
948 | dev: true
949 |
950 | /nanoid/3.3.4:
951 | resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
952 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
953 | hasBin: true
954 | dev: true
955 |
956 | /node-releases/2.0.6:
957 | resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==}
958 | dev: true
959 |
960 | /outdent/0.8.0:
961 | resolution: {integrity: sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==}
962 |
963 | /p-limit/3.1.0:
964 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
965 | engines: {node: '>=10'}
966 | dependencies:
967 | yocto-queue: 0.1.0
968 | dev: true
969 |
970 | /p-locate/5.0.0:
971 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
972 | engines: {node: '>=10'}
973 | dependencies:
974 | p-limit: 3.1.0
975 | dev: true
976 |
977 | /path-exists/4.0.0:
978 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
979 | engines: {node: '>=8'}
980 | dev: true
981 |
982 | /path-parse/1.0.7:
983 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
984 | dev: true
985 |
986 | /picocolors/1.0.0:
987 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
988 | dev: true
989 |
990 | /postcss-load-config/3.1.4_postcss@8.4.18:
991 | resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
992 | engines: {node: '>= 10'}
993 | peerDependencies:
994 | postcss: '>=8.0.9'
995 | ts-node: '>=9.0.0'
996 | peerDependenciesMeta:
997 | postcss:
998 | optional: true
999 | ts-node:
1000 | optional: true
1001 | dependencies:
1002 | lilconfig: 2.0.6
1003 | postcss: 8.4.18
1004 | yaml: 1.10.2
1005 | dev: true
1006 |
1007 | /postcss/8.4.18:
1008 | resolution: {integrity: sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==}
1009 | engines: {node: ^10 || ^12 || >=14}
1010 | dependencies:
1011 | nanoid: 3.3.4
1012 | picocolors: 1.0.0
1013 | source-map-js: 1.0.2
1014 | dev: true
1015 |
1016 | /react-dom/18.2.0_react@18.2.0:
1017 | resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
1018 | peerDependencies:
1019 | react: ^18.2.0
1020 | dependencies:
1021 | loose-envify: 1.4.0
1022 | react: 18.2.0
1023 | scheduler: 0.23.0
1024 | dev: false
1025 |
1026 | /react-refresh/0.14.0:
1027 | resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==}
1028 | engines: {node: '>=0.10.0'}
1029 | dev: true
1030 |
1031 | /react/18.2.0:
1032 | resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
1033 | engines: {node: '>=0.10.0'}
1034 | dependencies:
1035 | loose-envify: 1.4.0
1036 | dev: false
1037 |
1038 | /regenerator-runtime/0.13.10:
1039 | resolution: {integrity: sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==}
1040 |
1041 | /require-like/0.1.2:
1042 | resolution: {integrity: sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==}
1043 | dev: true
1044 |
1045 | /resolve/1.22.1:
1046 | resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
1047 | hasBin: true
1048 | dependencies:
1049 | is-core-module: 2.11.0
1050 | path-parse: 1.0.7
1051 | supports-preserve-symlinks-flag: 1.0.0
1052 | dev: true
1053 |
1054 | /rollup/2.79.1:
1055 | resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==}
1056 | engines: {node: '>=10.0.0'}
1057 | hasBin: true
1058 | optionalDependencies:
1059 | fsevents: 2.3.2
1060 | dev: true
1061 |
1062 | /scheduler/0.23.0:
1063 | resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
1064 | dependencies:
1065 | loose-envify: 1.4.0
1066 | dev: false
1067 |
1068 | /semver/6.3.0:
1069 | resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
1070 | hasBin: true
1071 | dev: true
1072 |
1073 | /source-map-js/1.0.2:
1074 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
1075 | engines: {node: '>=0.10.0'}
1076 | dev: true
1077 |
1078 | /sourcemap-codec/1.4.8:
1079 | resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
1080 | dev: true
1081 |
1082 | /supports-color/5.5.0:
1083 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
1084 | engines: {node: '>=4'}
1085 | dependencies:
1086 | has-flag: 3.0.0
1087 | dev: true
1088 |
1089 | /supports-color/7.2.0:
1090 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
1091 | engines: {node: '>=8'}
1092 | dependencies:
1093 | has-flag: 4.0.0
1094 |
1095 | /supports-preserve-symlinks-flag/1.0.0:
1096 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
1097 | engines: {node: '>= 0.4'}
1098 | dev: true
1099 |
1100 | /to-fast-properties/2.0.0:
1101 | resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
1102 | engines: {node: '>=4'}
1103 | dev: true
1104 |
1105 | /update-browserslist-db/1.0.10_browserslist@4.21.4:
1106 | resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==}
1107 | hasBin: true
1108 | peerDependencies:
1109 | browserslist: '>= 4.21.0'
1110 | dependencies:
1111 | browserslist: 4.21.4
1112 | escalade: 3.1.1
1113 | picocolors: 1.0.0
1114 | dev: true
1115 |
1116 | /vite/3.2.2:
1117 | resolution: {integrity: sha512-pLrhatFFOWO9kS19bQ658CnRYzv0WLbsPih6R+iFeEEhDOuYgYCX2rztUViMz/uy/V8cLCJvLFeiOK7RJEzHcw==}
1118 | engines: {node: ^14.18.0 || >=16.0.0}
1119 | hasBin: true
1120 | peerDependencies:
1121 | less: '*'
1122 | sass: '*'
1123 | stylus: '*'
1124 | sugarss: '*'
1125 | terser: ^5.4.0
1126 | peerDependenciesMeta:
1127 | less:
1128 | optional: true
1129 | sass:
1130 | optional: true
1131 | stylus:
1132 | optional: true
1133 | sugarss:
1134 | optional: true
1135 | terser:
1136 | optional: true
1137 | dependencies:
1138 | esbuild: 0.15.12
1139 | postcss: 8.4.18
1140 | resolve: 1.22.1
1141 | rollup: 2.79.1
1142 | optionalDependencies:
1143 | fsevents: 2.3.2
1144 | dev: true
1145 |
1146 | /yaml/1.10.2:
1147 | resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
1148 | engines: {node: '>= 6'}
1149 | dev: true
1150 |
1151 | /yocto-queue/0.1.0:
1152 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
1153 | engines: {node: '>=10'}
1154 | dev: true
1155 |
--------------------------------------------------------------------------------
/examples/react/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { useRef } from 'react';
2 | import { createBoxWithAtomsProp } from '@dessert-box/react';
3 | import { themeClass, atoms } from './atoms.css';
4 | import Box from './Box';
5 | import Text from './Text/Text';
6 | import Button from './Button/Button';
7 | import { StyledText, StyledLink } from './styled.css';
8 |
9 | const BoxWithAtomsProp = createBoxWithAtomsProp({ atoms });
10 |
11 | const AsBoxButton = (
12 | props: React.ComponentProps & React.ComponentProps,
13 | ) => ;
14 |
15 | export const App = () => {
16 | const ref = useRef(null);
17 |
18 | return (
19 |
20 | Styled text
21 | Link
22 |
23 | Hello
24 |
25 |
31 | With atoms
32 |
33 |
34 | No props box
35 | header 1 text
36 | header 2 text
37 | paragraph text
38 |
39 |
42 |
43 |
46 |
47 |
53 | With atoms + className
54 |
55 |
56 | Without atoms or className
57 |
58 |
65 | With atoms as a prop
66 |
67 |
68 | );
69 | };
70 |
--------------------------------------------------------------------------------
/examples/react/src/Box.tsx:
--------------------------------------------------------------------------------
1 | import { createBox } from '@dessert-box/react';
2 | import { atoms } from './atoms.css';
3 |
4 | export const Box = createBox({ atoms });
5 |
6 | export default Box;
7 |
--------------------------------------------------------------------------------
/examples/react/src/Button/Button.css.ts:
--------------------------------------------------------------------------------
1 | import { recipe } from '@vanilla-extract/recipes';
2 | import { atoms } from '../atoms.css';
3 |
4 | export const buttonRecipe = recipe({
5 | variants: {
6 | kind: {
7 | primary: atoms({ background: 'blue50' }),
8 | secondary: atoms({ background: 'yellow' }),
9 | },
10 | size: {
11 | md: atoms({ fontSize: 'large' }),
12 | lg: atoms({ fontSize: 'extraLarge' }),
13 | },
14 | },
15 | });
16 |
17 | export type ButtonVariants = Parameters[0];
18 |
--------------------------------------------------------------------------------
/examples/react/src/Button/Button.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { buttonRecipe, ButtonVariants } from './Button.css';
3 | import { Box } from '../Box';
4 |
5 | type Props = {
6 | children: React.ReactNode;
7 | } & ButtonVariants;
8 |
9 | export const Button = ({
10 | children,
11 | size = 'md',
12 | kind = 'secondary',
13 | }: Props) => {
14 | return (
15 |
16 | {children}
17 |
18 | );
19 | };
20 |
21 | export default Button;
22 |
--------------------------------------------------------------------------------
/examples/react/src/Text/Text.css.ts:
--------------------------------------------------------------------------------
1 | import { recipe } from '@vanilla-extract/recipes';
2 | import { atoms } from '../atoms.css';
3 |
4 | export const textRecipe = recipe({
5 | variants: {
6 | kind: {
7 | h1: atoms({
8 | fontSize: 'extraLarge',
9 | fontWeight: '600',
10 | }),
11 | h2: atoms({
12 | fontSize: 'large',
13 | fontWeight: '400',
14 | }),
15 | p: atoms({
16 | fontSize: 'medium',
17 | }),
18 | },
19 | },
20 | });
21 |
22 | export type TextVariants = Parameters[0];
23 |
--------------------------------------------------------------------------------
/examples/react/src/Text/Text.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { textRecipe, TextVariants } from './Text.css';
3 | import { Box } from '../Box';
4 |
5 | type Props = {
6 | children: React.ReactNode;
7 | } & TextVariants;
8 |
9 | const Text = ({ kind, children }: Props) => {
10 | return {children};
11 | };
12 |
13 | export default Text;
14 |
--------------------------------------------------------------------------------
/examples/react/src/atoms.css.ts:
--------------------------------------------------------------------------------
1 | import { createTheme } from '@vanilla-extract/css';
2 | import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles';
3 |
4 | export const [themeClass, vars] = createTheme({
5 | color: {
6 | blue50: '#eff6ff',
7 | blue100: '#dbeafe',
8 | blue200: '#bfdbfe',
9 | yellow: '#aaff00',
10 | },
11 | font: {
12 | body: 'arial',
13 | },
14 | fontSize: {
15 | small: '12px',
16 | medium: '16px',
17 | large: '24px',
18 | extraLarge: '32px',
19 | },
20 | fontWeight: {
21 | '400': '400',
22 | '600': '600',
23 | },
24 | space: {
25 | none: '0',
26 | small: '4px',
27 | medium: '8px',
28 | large: '16px',
29 | extraLarge: '32px',
30 | },
31 | });
32 |
33 | const layoutStyles = defineProperties({
34 | conditions: {
35 | mobile: {},
36 | tablet: { '@media': 'screen and (min-width: 768px)' },
37 | desktop: { '@media': 'screen and (min-width: 1024px)' },
38 | },
39 | defaultCondition: 'mobile',
40 | properties: {
41 | display: ['none', 'block', 'flex'],
42 | flexDirection: ['row', 'column'],
43 | paddingTop: vars.space,
44 | paddingBottom: vars.space,
45 | paddingLeft: vars.space,
46 | paddingRight: vars.space,
47 | margin: vars.space,
48 | width: ['16px', '100%'],
49 | fontSize: vars.fontSize,
50 | fontWeight: vars.fontWeight,
51 | // etc.
52 | },
53 | shorthands: {
54 | padding: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'],
55 | paddingX: ['paddingLeft', 'paddingRight'],
56 | paddingY: ['paddingTop', 'paddingBottom'],
57 | },
58 | });
59 |
60 | const colorStyles = defineProperties({
61 | properties: {
62 | color: vars.color,
63 | background: vars.color,
64 | // etc.
65 | },
66 | });
67 |
68 | export const atoms = createSprinkles(layoutStyles, colorStyles);
69 |
--------------------------------------------------------------------------------
/examples/react/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createRoot } from 'react-dom/client';
3 |
4 | import { App } from './App';
5 |
6 | const root = createRoot(document.getElementById('root')!);
7 | root.render(
8 |
9 |
10 | ,
11 | );
12 |
--------------------------------------------------------------------------------
/examples/react/src/styled.css.ts:
--------------------------------------------------------------------------------
1 | import { styled } from '@dessert-box/react';
2 |
3 | export const StyledText = styled('div', {
4 | backgroundColor: 'red',
5 | color: 'white',
6 | });
7 |
8 | export const StyledLink = styled('a', {
9 | textDecoration: 'none',
10 | });
11 |
--------------------------------------------------------------------------------
/examples/react/vite.config.ts:
--------------------------------------------------------------------------------
1 | import react from '@vitejs/plugin-react';
2 | import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
3 | import { defineConfig } from 'vite';
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [react(), vanillaExtractPlugin()],
8 | });
9 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | transform: {
3 | '\\.tsx?$': ['babel-jest', { configFile: './babel-jest.config.js' }],
4 | },
5 | testMatch: ['**/?(*.)+(test).[jt]s?(x)'],
6 | testTimeout: 10000,
7 | };
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dessert-box",
3 | "version": "0.0.0",
4 | "author": "Victor Tortolero ",
5 | "license": "MIT",
6 | "private": true,
7 | "scripts": {
8 | "dev": "preconstruct dev",
9 | "watch": "preconstruct watch",
10 | "build": "preconstruct build",
11 | "release": "pnpm build && npm publish",
12 | "test": "jest",
13 | "format": "prettier --write .",
14 | "lint": "prettier --check .",
15 | "postinstall": "pnpm dev"
16 | },
17 | "preconstruct": {
18 | "packages": [
19 | "packages/*"
20 | ]
21 | },
22 | "devDependencies": {
23 | "@babel/core": "^7.15.5",
24 | "@babel/preset-env": "^7.15.6",
25 | "@babel/preset-react": "^7.14.5",
26 | "@babel/preset-typescript": "^7.15.0",
27 | "@preconstruct/cli": "^2.1.4",
28 | "@types/jest": "^27.0.1",
29 | "@vanilla-extract/babel-plugin": "^1.1.0",
30 | "babel-jest": "^27.2.1",
31 | "jest": "^27.2.1",
32 | "prettier": "2.4.1",
33 | "tsup": "^6.7.0",
34 | "typescript": "^4.2.4"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/packages/core/README.md:
--------------------------------------------------------------------------------
1 | # 🍰 Dessert Box
2 |
3 | A library to easily consume your design tokens from a React component, meant to be used with [vanilla-extract][vanilla-extract].
4 |
5 | This library will make consuming your [sprinkles][sprinkles] from a react component a breeze. It provides a zero-CSS-runtime `` component (similar to the one in [Braid](https://seek-oss.github.io/braid-design-system/components/Box) or [Chakra](https://chakra-ui.com/docs/layout/box)).
6 |
7 | [Try it on CodeSandbox!](https://codesandbox.io/s/dessert-box-demo-wxgy8?file=/src/App.tsx)
8 |
9 | It works by consuming `atoms` created with [`vanilla-extract`][vanilla-extract]) and [`sprinkles`][sprinkles]. Shout out to the team at Seek for making these awesome libraries!
10 |
11 | 1. Step 1, create your Box with your `atoms` created with sprinkles:
12 |
13 | ```tsx
14 | // Box.tsx
15 | import { createBox } from '@dessert-box/react';
16 | import { atoms } from './sprinkles.css';
17 |
18 | const { Box } = createBox({
19 | atoms,
20 | // optional: pass your CSS reset className here
21 | // useful if you want to scope your reset to your Box element
22 | defaultClassName: 'resetClassName',
23 | });
24 |
25 | export default Box;
26 | ```
27 |
28 | 2. Step 2, import it enjoy the sweetness:
29 |
30 | ```tsx
31 | // OtherFileOrComponent.tsx
32 | import Box from './Box';
33 |
34 | const MyComponent = () => {
35 | return What a sweet treat!;
36 | };
37 | ```
38 |
39 | **Wondering why using a Box component may be a good idea? or what is a Box component? Check the [FAQ](#FAQ).**
40 |
41 | > Wondering how to use `variants` with this library? Check out the [variants](#variants) section.
42 |
43 | 
44 |
45 | - [🍰 Dessert Box](#-dessert-box)
46 | - [Usage](#usage)
47 | - [Variants](#variants)
48 | - [API](#api)
49 | - [createBox(options: { atoms: AtomsFn, defaultClassName?: string })](#createboxoptions--atoms-atomsfn-defaultclassname-string-)
50 | - [createBoxWithAtomsProp(options: { atoms: AtomsFn, defaultClassName?: string })](#createboxwithatomspropoptions--atoms-atomsfn-defaultclassname-string-)
51 | - [Running the example app](#running-the-example-app)
52 | - [How does it work?](#how-does-it-work)
53 | - [Thanks](#thanks)
54 | - [FAQ](#faq)
55 |
56 | [Try it on CodeSandbox!](https://codesandbox.io/s/dessert-box-demo-wxgy8?file=/src/App.tsx)
57 |
58 | ## Usage
59 |
60 | Install the package:
61 |
62 | ```
63 | $ npm install @dessert-box/react
64 | ```
65 |
66 | Configure [vanilla-extract](https://github.com/seek-oss/vanilla-extract) and [`sprinkles`](https://github.com/seek-oss/vanilla-extract/tree/master/packages/sprinkles) and have your atoms ready:
67 |
68 | ```js
69 | // atoms.css.ts
70 | import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles';
71 |
72 | const space = {
73 | none: 0,
74 | small: 4,
75 | medium: 8,
76 | large: 16,
77 | };
78 |
79 | const colors = {
80 | primary: 'blue',
81 | // ...
82 | };
83 |
84 | const atomicStyles = defineProperties({
85 | conditions: {
86 | mobile: {},
87 | tablet: { '@media': 'screen and (min-width: 768px)' },
88 | desktop: { '@media': 'screen and (min-width: 1024px)' },
89 | },
90 | properties: {
91 | padding: space,
92 | backgroundColor: colors,
93 | // ...
94 | },
95 | // ...
96 | });
97 |
98 | export const atoms = createSprinkles(atomicStyles);
99 | ```
100 |
101 | > Check `sprinkles` [docs](https://github.com/seek-oss/vanilla-extract/tree/3360bdfc9220024e7ffa49b3b198b72743d4e264/packages/sprinkles#setup) for more context into how to create these atoms.
102 |
103 | Now let's create our `` using these atoms:
104 |
105 | ```tsx
106 | // Box.ts
107 | import { createBox } from '@dessert-box/react';
108 | import { atoms } from './sprinkles.css';
109 |
110 | const { Box } = createBox({ atoms });
111 |
112 | export default Box;
113 | ```
114 |
115 | ```tsx
116 | // otherFile.tsx
117 | import Box from './Box';
118 |
119 | const App = () => {
120 | return Hello;
121 | };
122 | ```
123 |
124 | Notice we can pass every property, shorthand, or condition we can normally pass to our `atomsFn` function. For example, we could leverage the conditions for responsive design we have here:
125 |
126 | ```jsx
127 |
128 | ```
129 |
130 | If you need to render a tag different than a `div`, you can use the `as` prop:
131 |
132 | ```jsx
133 |
134 | Link to example
135 |
136 | ```
137 |
138 | [Try it on CodeSandbox!](https://codesandbox.io/s/dessert-box-demo-wxgy8?file=/src/App.tsx)
139 |
140 | ### Variants
141 |
142 | The official [@vanilla-extract/recipes][recipes] package has an excelent API for dealing with variants, this can be combined with our `Box` component to create [variant-based components](https://ped.ro/blog/variant-driven-components):
143 |
144 | NOTE: (Assuming you already have created your `Box` component following the example above).
145 |
146 | 1. First define your recipe using the `recipe` function:
147 |
148 | ```tsx
149 | // Button.css.ts
150 | import { recipe } from '@vanilla-extract/recipes';
151 | import { atoms } from '../atoms.css';
152 |
153 | export const buttonRecipe = recipe({
154 | variants: {
155 | kind: {
156 | primary: atoms({ background: 'blue50' }),
157 | secondary: atoms({ background: 'yellow' }),
158 | },
159 | size: {
160 | md: atoms({ fontSize: 'large' }),
161 | lg: atoms({ fontSize: 'extraLarge' }),
162 | },
163 | },
164 | });
165 |
166 | export type ButtonVariants = Parameters[0];
167 | ```
168 |
169 | 2. Then use the `recipes` function to create variants and apply them to your `Box`:
170 |
171 | ```tsx
172 | // Button.tsx
173 | import { Box } from './Box';
174 | import { buttonRecipe, ButtonVariants } from './Button.css';
175 |
176 | type Props = {
177 | children: React.ReactNode;
178 | } & ButtonVariants;
179 |
180 | export const Button = ({
181 | children,
182 | size = 'md',
183 | kind = 'secondary',
184 | }: Props) => {
185 | return (
186 |
187 | {children}
188 |
189 | );
190 | };
191 |
192 | export default Button;
193 | ```
194 |
195 | For more context, refer to [@vanilla-extract/recipe][recipes] or feel free [to open an issue in this project](https://github.com/TheMightyPenguin/dessert-box/issues/new) if the integration is not working as you'd expect!
196 |
197 | ## API
198 |
199 | ### createBox(options: { atoms: AtomsFn, defaultClassName?: string })
200 |
201 | Creates a `` component that takes atoms at the root level.
202 |
203 | ```jsx
204 | import { createBox } from '@dessert-box/react';
205 | import { atoms } from './atoms.css';
206 |
207 | const Box = createBox({ atoms });
208 |
209 | ;
210 | ```
211 |
212 | ### createBoxWithAtomsProp(options: { atoms: AtomsFn, defaultClassName?: string })
213 |
214 | Creates a `` component that takes atoms as a prop called `atoms`.
215 |
216 | ```jsx
217 | import { createBoxWithAtomsProp } from '@dessert-box/react';
218 | import { atoms } from './atoms.css';
219 |
220 | const Box = createBoxWithAtomsProp({ atoms });
221 |
222 | ;
223 | ```
224 |
225 | ## Running the example app
226 |
227 | Run `npm install` then `npm run build` in the root folder (the one with this README file).
228 |
229 | Then move into the example folder `cd example` and run `npm install` and `npm start`.
230 |
231 | ## How does it work?
232 |
233 | This works by depending on build-time generated CSS by [sprinkles](https://github.com/seek-oss/vanilla-extract/tree/3360bdfc9220024e7ffa49b3b198b72743d4e264/packages/sprinkles), and then using the `atomsFn` function to lookup classNames in runtime. So it does have a runtime footprint, but should be pretty minimal. I'm still experimenting to see if it's possible to remove that, but other approaches may lead to other constraints or similar runtime.
234 |
235 | ## Thanks
236 |
237 | - Thanks to the team at Seek for [vanilla-extract](https://github.com/seek-oss/vanilla-extract) and [`sprinkles`](https://github.com/seek-oss/vanilla-extract/tree/master/packages/sprinkles), this would not be possible without these great libs and the technical feats they accomplish.
238 |
239 | ## FAQ
240 |
241 | - What is a Box component?
242 |
243 | > It's a generic element that allows you to prototype fast and takes a variety of styling props (think of exposing a lot of CSS attributes as props on a component).
244 |
245 | - Why should I use a Box component?
246 |
247 | > There are many versions and flavors of a Box component, some are more [flexible](https://chakra-ui.com/docs/layout/box), while others are more [restrictive](https://seek-oss.github.io/braid-design-system/components/Box). The Box in this library falls into the latter category (restrictive), and it's more geared towards being the a lower level API of your Design System (or serving as inspiration for it).
248 |
249 | This Box component is meant to be used as a primitive for consuming design tokens, giving you a nice balance between flexibility and constraints. You can use it as an lower level API to implement your other components (Buttons, Card, Layout components, ...), and also as a prototyping and general usage component:
250 |
251 | - As a prototyping tool, it allows you to use all of your design tokens to generate new designs and evaluate if you need to iterate on your foundations, or to validate if they work for your use cases.
252 | - For general usage you can still have the guarantee that users of your system won't do anything impossible (e.g.: using a value that is not part of the design tokens) but still have a productive experience working on UI.
253 |
254 | [sprinkles]: https://github.com/seek-oss/vanilla-extract/tree/master/packages/sprinkles
255 | [vanilla-extract]: https://github.com/seek-oss/vanilla-extract
256 | [recipes]: https://github.com/seek-oss/vanilla-extract#recipes-api
257 |
--------------------------------------------------------------------------------
/packages/core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@dessert-box/core",
3 | "version": "0.2.0",
4 | "description": "",
5 | "author": "Victor Tortolero ",
6 | "main": "dist/dessert-box-core.cjs.js",
7 | "module": "dist/dessert-box-core.esm.js",
8 | "types": "dist/dessert-box-core.cjs.d.ts",
9 | "sideEffects": false,
10 | "license": "MIT",
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/TheMightyPenguin/dessert-box.git",
14 | "directory": "packages/core"
15 | },
16 | "keywords": []
17 | }
18 |
--------------------------------------------------------------------------------
/packages/core/src/index.tsx:
--------------------------------------------------------------------------------
1 | export interface AtomsFnBase {
2 | (...args: any): string;
3 | properties: Set;
4 | }
5 |
6 | export function composeClassNames(...classNames: Array) {
7 | const classes = classNames
8 | .filter((className) => {
9 | return Boolean(className) && className !== ' ';
10 | })
11 | .map((className) => {
12 | return className?.toString().trim();
13 | }) as Array;
14 | return classes.length === 0 ? undefined : classes.join(' ');
15 | }
16 |
17 | export function extractAtomsFromProps(
18 | props: any,
19 | atomsFn: AtomsFn,
20 | ) {
21 | let hasAtomProps = false;
22 | let atomProps: Record = {};
23 | let otherProps: Record = {};
24 | let customProps: Record = {};
25 |
26 | for (const key in props) {
27 | if (key[0] === '_' && key[1] === '_') {
28 | const actualKey = key.substring(2);
29 | customProps[actualKey] = props[key];
30 | } else if (atomsFn.properties.has(key)) {
31 | hasAtomProps = true;
32 | atomProps[key] = props[key];
33 | } else {
34 | otherProps[key] = props[key];
35 | }
36 | }
37 |
38 | return { hasAtomProps, atomProps, otherProps, customProps };
39 | }
40 |
--------------------------------------------------------------------------------
/packages/react/README.md:
--------------------------------------------------------------------------------
1 | # 🍰 Dessert Box
2 |
3 | A library to easily consume your design tokens from a React component, meant to be used with [vanilla-extract][vanilla-extract].
4 |
5 | This library will make consuming your [sprinkles][sprinkles] from a react component a breeze. It provides a zero-CSS-runtime `` component (similar to the one in [Braid](https://seek-oss.github.io/braid-design-system/components/Box) or [Chakra](https://chakra-ui.com/docs/layout/box)).
6 |
7 | [Try it on CodeSandbox!](https://codesandbox.io/s/dessert-box-demo-wxgy8?file=/src/App.tsx)
8 |
9 | It works by consuming `atoms` created with [`vanilla-extract`][vanilla-extract]) and [`sprinkles`][sprinkles]. Shout out to the team at Seek for making these awesome libraries!
10 |
11 | 1. Step 1, create your Box with your `atoms` created with sprinkles:
12 |
13 | ```tsx
14 | // Box.tsx
15 | import { createBox } from '@dessert-box/react';
16 | import { atoms } from './sprinkles.css';
17 |
18 | const { Box } = createBox({
19 | atoms,
20 | // optional: pass your CSS reset className here
21 | // useful if you want to scope your reset to your Box element
22 | defaultClassName: 'resetClassName',
23 | });
24 |
25 | export default Box;
26 | ```
27 |
28 | 2. Step 2, import it enjoy the sweetness:
29 |
30 | ```tsx
31 | // OtherFileOrComponent.tsx
32 | import Box from './Box';
33 |
34 | const MyComponent = () => {
35 | return What a sweet treat!;
36 | };
37 | ```
38 |
39 | **Wondering why using a Box component may be a good idea? or what is a Box component? Check the [FAQ](#FAQ).**
40 |
41 | > Wondering how to use `variants` with this library? Check out the [variants](#variants) section.
42 |
43 | 
44 |
45 | - [🍰 Dessert Box](#-dessert-box)
46 | - [Usage](#usage)
47 | - [Variants](#variants)
48 | - [API](#api)
49 | - [createBox(options: { atoms: AtomsFn, defaultClassName?: string })](#createboxoptions--atoms-atomsfn-defaultclassname-string-)
50 | - [createBoxWithAtomsProp(options: { atoms: AtomsFn, defaultClassName?: string })](#createboxwithatomspropoptions--atoms-atomsfn-defaultclassname-string-)
51 | - [Running the example app](#running-the-example-app)
52 | - [How does it work?](#how-does-it-work)
53 | - [Thanks](#thanks)
54 | - [FAQ](#faq)
55 |
56 | [Try it on CodeSandbox!](https://codesandbox.io/s/dessert-box-demo-wxgy8?file=/src/App.tsx)
57 |
58 | ## Usage
59 |
60 | Install the package:
61 |
62 | ```
63 | $ npm install @dessert-box/react
64 | ```
65 |
66 | Configure [vanilla-extract](https://github.com/seek-oss/vanilla-extract) and [`sprinkles`](https://github.com/seek-oss/vanilla-extract/tree/master/packages/sprinkles) and have your atoms ready:
67 |
68 | ```js
69 | // atoms.css.ts
70 | import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles';
71 |
72 | const space = {
73 | none: 0,
74 | small: 4,
75 | medium: 8,
76 | large: 16,
77 | };
78 |
79 | const colors = {
80 | primary: 'blue',
81 | // ...
82 | };
83 |
84 | const atomicStyles = defineProperties({
85 | conditions: {
86 | mobile: {},
87 | tablet: { '@media': 'screen and (min-width: 768px)' },
88 | desktop: { '@media': 'screen and (min-width: 1024px)' },
89 | },
90 | properties: {
91 | padding: space,
92 | backgroundColor: colors,
93 | // ...
94 | },
95 | // ...
96 | });
97 |
98 | export const atoms = createSprinkles(atomicStyles);
99 | ```
100 |
101 | > Check `sprinkles` [docs](https://github.com/seek-oss/vanilla-extract/tree/3360bdfc9220024e7ffa49b3b198b72743d4e264/packages/sprinkles#setup) for more context into how to create these atoms.
102 |
103 | Now let's create our `` using these atoms:
104 |
105 | ```tsx
106 | // Box.ts
107 | import { createBox } from '@dessert-box/react';
108 | import { atoms } from './sprinkles.css';
109 |
110 | const { Box } = createBox({ atoms });
111 |
112 | export default Box;
113 | ```
114 |
115 | ```tsx
116 | // otherFile.tsx
117 | import Box from './Box';
118 |
119 | const App = () => {
120 | return Hello;
121 | };
122 | ```
123 |
124 | Notice we can pass every property, shorthand, or condition we can normally pass to our `atomsFn` function. For example, we could leverage the conditions for responsive design we have here:
125 |
126 | ```jsx
127 |
128 | ```
129 |
130 | If you need to render a tag different than a `div`, you can use the `as` prop:
131 |
132 | ```jsx
133 |
134 | Link to example
135 |
136 | ```
137 |
138 | [Try it on CodeSandbox!](https://codesandbox.io/s/dessert-box-demo-wxgy8?file=/src/App.tsx)
139 |
140 | ### Variants
141 |
142 | The official [@vanilla-extract/recipes][recipes] package has an excelent API for dealing with variants, this can be combined with our `Box` component to create [variant-based components](https://ped.ro/blog/variant-driven-components):
143 |
144 | NOTE: (Assuming you already have created your `Box` component following the example above).
145 |
146 | 1. First define your recipe using the `recipe` function:
147 |
148 | ```tsx
149 | // Button.css.ts
150 | import { recipe } from '@vanilla-extract/recipes';
151 | import { atoms } from '../atoms.css';
152 |
153 | export const buttonRecipe = recipe({
154 | variants: {
155 | kind: {
156 | primary: atoms({ background: 'blue50' }),
157 | secondary: atoms({ background: 'yellow' }),
158 | },
159 | size: {
160 | md: atoms({ fontSize: 'large' }),
161 | lg: atoms({ fontSize: 'extraLarge' }),
162 | },
163 | },
164 | });
165 |
166 | export type ButtonVariants = Parameters[0];
167 | ```
168 |
169 | 2. Then use the `recipes` function to create variants and apply them to your `Box`:
170 |
171 | ```tsx
172 | // Button.tsx
173 | import { Box } from './Box';
174 | import { buttonRecipe, ButtonVariants } from './Button.css';
175 |
176 | type Props = {
177 | children: React.ReactNode;
178 | } & ButtonVariants;
179 |
180 | export const Button = ({
181 | children,
182 | size = 'md',
183 | kind = 'secondary',
184 | }: Props) => {
185 | return (
186 |
187 | {children}
188 |
189 | );
190 | };
191 |
192 | export default Button;
193 | ```
194 |
195 | For more context, refer to [@vanilla-extract/recipe][recipes] or feel free [to open an issue in this project](https://github.com/TheMightyPenguin/dessert-box/issues/new) if the integration is not working as you'd expect!
196 |
197 | ## API
198 |
199 | ### createBox(options: { atoms: AtomsFn, defaultClassName?: string })
200 |
201 | Creates a `` component that takes atoms at the root level.
202 |
203 | ```jsx
204 | import { createBox } from '@dessert-box/react';
205 | import { atoms } from './atoms.css';
206 |
207 | const Box = createBox({ atoms });
208 |
209 | ;
210 | ```
211 |
212 | ### createBoxWithAtomsProp(options: { atoms: AtomsFn, defaultClassName?: string })
213 |
214 | Creates a `` component that takes atoms as a prop called `atoms`.
215 |
216 | ```jsx
217 | import { createBoxWithAtomsProp } from '@dessert-box/react';
218 | import { atoms } from './atoms.css';
219 |
220 | const Box = createBoxWithAtomsProp({ atoms });
221 |
222 | ;
223 | ```
224 |
225 | ## Running the example app
226 |
227 | Run `npm install` then `npm run build` in the root folder (the one with this README file).
228 |
229 | Then move into the example folder `cd example` and run `npm install` and `npm start`.
230 |
231 | ## How does it work?
232 |
233 | This works by depending on build-time generated CSS by [sprinkles](https://github.com/seek-oss/vanilla-extract/tree/3360bdfc9220024e7ffa49b3b198b72743d4e264/packages/sprinkles), and then using the `atomsFn` function to lookup classNames in runtime. So it does have a runtime footprint, but should be pretty minimal. I'm still experimenting to see if it's possible to remove that, but other approaches may lead to other constraints or similar runtime.
234 |
235 | ## Thanks
236 |
237 | - Thanks to the team at Seek for [vanilla-extract](https://github.com/seek-oss/vanilla-extract) and [`sprinkles`](https://github.com/seek-oss/vanilla-extract/tree/master/packages/sprinkles), this would not be possible without these great libs and the technical feats they accomplish.
238 |
239 | ## FAQ
240 |
241 | - What is a Box component?
242 |
243 | > It's a generic element that allows you to prototype fast and takes a variety of styling props (think of exposing a lot of CSS attributes as props on a component).
244 |
245 | - Why should I use a Box component?
246 |
247 | > There are many versions and flavors of a Box component, some are more [flexible](https://chakra-ui.com/docs/layout/box), while others are more [restrictive](https://seek-oss.github.io/braid-design-system/components/Box). The Box in this library falls into the latter category (restrictive), and it's more geared towards being the a lower level API of your Design System (or serving as inspiration for it).
248 |
249 | This Box component is meant to be used as a primitive for consuming design tokens, giving you a nice balance between flexibility and constraints. You can use it as an lower level API to implement your other components (Buttons, Card, Layout components, ...), and also as a prototyping and general usage component:
250 |
251 | - As a prototyping tool, it allows you to use all of your design tokens to generate new designs and evaluate if you need to iterate on your foundations, or to validate if they work for your use cases.
252 | - For general usage you can still have the guarantee that users of your system won't do anything impossible (e.g.: using a value that is not part of the design tokens) but still have a productive experience working on UI.
253 |
254 | [sprinkles]: https://github.com/seek-oss/vanilla-extract/tree/master/packages/sprinkles
255 | [vanilla-extract]: https://github.com/seek-oss/vanilla-extract
256 | [recipes]: https://github.com/seek-oss/vanilla-extract#recipes-api
257 |
--------------------------------------------------------------------------------
/packages/react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@dessert-box/react",
3 | "version": "0.7.5",
4 | "description": "",
5 | "author": "Victor Tortolero ",
6 | "main": "dist/dessert-box-react.cjs.js",
7 | "module": "dist/dessert-box-react.esm.js",
8 | "types": "dist/dessert-box-react.cjs.d.ts",
9 | "exports": {
10 | "./package.json": "./package.json",
11 | ".": {
12 | "module": "./dist/dessert-box-react.esm.js",
13 | "default": "./dist/dessert-box-react.cjs.js"
14 | },
15 | "./styledRuntime": {
16 | "module": "./styledRuntime/dist/dessert-box-react-styledRuntime.esm.js",
17 | "default": "./styledRuntime/dist/dessert-box-react-styledRuntime.cjs.js"
18 | }
19 | },
20 | "files": [
21 | "/dist",
22 | "/styledRuntime"
23 | ],
24 | "preconstruct": {
25 | "entrypoints": [
26 | "index.ts",
27 | "styledRuntime.ts"
28 | ]
29 | },
30 | "sideEffects": false,
31 | "license": "MIT",
32 | "repository": {
33 | "type": "git",
34 | "url": "https://github.com/TheMightyPenguin/dessert-box.git",
35 | "directory": "packages/react"
36 | },
37 | "keywords": [],
38 | "devDependencies": {
39 | "@types/react": "^17.0.4",
40 | "@vanilla-extract/css": "^1.11.0",
41 | "react": ">=16.8.0"
42 | },
43 | "peerDependencies": {
44 | "@vanilla-extract/css": ">=1.11.0",
45 | "react": ">=16.8.0"
46 | },
47 | "dependencies": {
48 | "@dessert-box/core": "workspace:0.2.0"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/packages/react/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: 5.4
2 |
3 | specifiers:
4 | '@dessert-box/core': ^0.2.0
5 | '@types/react': ^17.0.4
6 | react: '>=16.8.0'
7 |
8 | dependencies:
9 | '@dessert-box/core': 0.2.0
10 |
11 | devDependencies:
12 | '@types/react': 17.0.52
13 | react: 18.2.0
14 |
15 | packages:
16 |
17 | /@dessert-box/core/0.2.0:
18 | resolution: {integrity: sha512-Vqaec6i0cvS1r54kU6CfOQECi6dPWzz6DVVxJABOxqPmVk8fOSy6pIKsK0YyPFGRpZK/FXkJ1YhURUOW1OxOVQ==}
19 | dev: false
20 |
21 | /@types/prop-types/15.7.5:
22 | resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
23 | dev: true
24 |
25 | /@types/react/17.0.52:
26 | resolution: {integrity: sha512-vwk8QqVODi0VaZZpDXQCmEmiOuyjEFPY7Ttaw5vjM112LOq37yz1CDJGrRJwA1fYEq4Iitd5rnjd1yWAc/bT+A==}
27 | dependencies:
28 | '@types/prop-types': 15.7.5
29 | '@types/scheduler': 0.16.2
30 | csstype: 3.1.1
31 | dev: true
32 |
33 | /@types/scheduler/0.16.2:
34 | resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
35 | dev: true
36 |
37 | /csstype/3.1.1:
38 | resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==}
39 | dev: true
40 |
41 | /js-tokens/4.0.0:
42 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
43 | dev: true
44 |
45 | /loose-envify/1.4.0:
46 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
47 | hasBin: true
48 | dependencies:
49 | js-tokens: 4.0.0
50 | dev: true
51 |
52 | /react/18.2.0:
53 | resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
54 | engines: {node: '>=0.10.0'}
55 | dependencies:
56 | loose-envify: 1.4.0
57 | dev: true
58 |
--------------------------------------------------------------------------------
/packages/react/src/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AtomsFnBase,
3 | composeClassNames,
4 | extractAtomsFromProps,
5 | } from '@dessert-box/core';
6 | import React, {
7 | createElement,
8 | ForwardedRef,
9 | forwardRef,
10 | ReactElement,
11 | } from 'react';
12 | import type { CreateBoxParams } from './types';
13 |
14 | export { styled } from './styled';
15 |
16 | // adapted from https://github.com/kripod/react-polymorphic-box
17 | type AsProp = {
18 | as?: TType;
19 | };
20 | type BaseBoxProps = AsProp &
21 | Omit, keyof AsProp>;
22 |
23 | type PolymorphicComponentProps = Props &
24 | BaseBoxProps;
25 |
26 | type PolymorphicComponent<
27 | Props,
28 | DefaultType extends React.ElementType = 'div',
29 | > = (
30 | props: PolymorphicComponentProps,
31 | ) => React.ReactElement | null;
32 | //
33 |
34 | type OverrideTokens = {
35 | [K in keyof T as K extends string ? `__${K}` : number]:
36 | | Extract
37 | | {};
38 | };
39 |
40 | type Tokens = Parameters[0];
41 | type BoxProps<
42 | AtomsFn extends AtomsFnBase,
43 | TType extends React.ElementType,
44 | > = PolymorphicComponentProps<
45 | TType,
46 | Tokens & OverrideTokens>
47 | >;
48 |
49 | const defaultElement = 'div';
50 |
51 | export function createBox({
52 | atoms: atomsFn,
53 | defaultClassName,
54 | }: CreateBoxParams) {
55 | const Box: (
56 | props: BoxProps,
57 | ) => null | ReactElement> = forwardRef(
58 | (
59 | { className, style, as, ...props }: BoxProps,
60 | ref: ForwardedRef, TType>>,
61 | ) => {
62 | const Element = as || defaultElement;
63 | const { atomProps, customProps, otherProps } = extractAtomsFromProps(
64 | props,
65 | atomsFn,
66 | );
67 |
68 | return createElement(Element, {
69 | ref,
70 | style: { ...style, ...customProps },
71 | ...otherProps,
72 | className: composeClassNames(
73 | className,
74 | atomsFn(atomProps),
75 | defaultClassName,
76 | ),
77 | });
78 | },
79 | );
80 |
81 | (Box as any).displayName = 'DessertBox';
82 |
83 | return Box;
84 | }
85 |
86 | type BoxWithAtomsProps<
87 | AtomsFn extends AtomsFnBase,
88 | TType extends React.ElementType,
89 | > = PolymorphicComponentProps<
90 | TType,
91 | { atoms?: Tokens & OverrideTokens> }
92 | >;
93 |
94 | export function createBoxWithAtomsProp({
95 | atoms: atomsFn,
96 | defaultClassName,
97 | }: CreateBoxParams) {
98 | const Box: (
99 | props: BoxWithAtomsProps,
100 | ) => null | ReactElement = forwardRef(
101 | (
102 | {
103 | className,
104 | style,
105 | atoms,
106 | as,
107 | ...props
108 | }: BoxWithAtomsProps,
109 | ref: ForwardedRef<
110 | PolymorphicComponent, TType>
111 | >,
112 | ) => {
113 | const Element = as || defaultElement;
114 |
115 | return createElement(Element, {
116 | ref,
117 | ...props,
118 | className: composeClassNames(
119 | className,
120 | atomsFn(atoms),
121 | defaultClassName,
122 | ),
123 | });
124 | },
125 | );
126 |
127 | (Box as any).displayName = 'DessertBox';
128 |
129 | return Box;
130 | }
131 |
--------------------------------------------------------------------------------
/packages/react/src/styled.ts:
--------------------------------------------------------------------------------
1 | import { addFunctionSerializer } from '@vanilla-extract/css/functionSerializer';
2 | import { ComplexStyleRule, style } from '@vanilla-extract/css';
3 | import { styledRuntime } from './styledRuntime';
4 |
5 | export function styled(
6 | el: T,
7 | rules: ComplexStyleRule,
8 | ) {
9 | const className = style(rules);
10 | const args = [el, className] as const;
11 |
12 | const Component = styledRuntime(el, className);
13 |
14 | addFunctionSerializer(Component, {
15 | importPath: '@dessert-box/react/styledRuntime',
16 | importName: 'styledRuntime',
17 | // TODO: Fix this type, was complaining about string not being assignable to Serializable from VE lib
18 | args: args as any,
19 | });
20 |
21 | return Component;
22 | }
23 |
--------------------------------------------------------------------------------
/packages/react/src/styledRuntime.ts:
--------------------------------------------------------------------------------
1 | import { createElement } from 'react';
2 |
3 | export function styledRuntime(
4 | el: T,
5 | className: string,
6 | ) {
7 | const Component = function Component(props: React.ComponentProps) {
8 | return createElement(el, {
9 | ...props,
10 | className: [props.className, className].filter(Boolean).join(' '),
11 | });
12 | };
13 |
14 | Component.displayName = `DBStyled(${el})`;
15 |
16 | return Component;
17 | }
18 |
--------------------------------------------------------------------------------
/packages/react/src/types.ts:
--------------------------------------------------------------------------------
1 | export type CreateBoxParams = {
2 | atoms: AtomsFn;
3 | defaultClassName?: string;
4 | };
5 |
--------------------------------------------------------------------------------
/packages/react/styledRuntime/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "dist/dessert-box-react-styledRuntime.cjs.js",
3 | "module": "dist/dessert-box-react-styledRuntime.esm.js"
4 | }
5 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - "packages/*"
3 | - "examples/*"
4 |
--------------------------------------------------------------------------------
/tests/core/core.test.ts:
--------------------------------------------------------------------------------
1 | import { extractAtomsFromProps, composeClassNames } from '@dessert-box/core';
2 |
3 | describe('@dessert-box/core', () => {
4 | describe('composeClassNames', () => {
5 | it('should not include falsy values', () => {
6 | // @ts-ignore
7 | expect(composeClassNames('hello', false, undefined, '', 0, 'world')).toBe(
8 | 'hello world',
9 | );
10 | });
11 |
12 | it('should skip empty strings', () => {
13 | expect(composeClassNames('hello', ' ', ' ', 'world')).toBe('hello world');
14 | });
15 |
16 | it('should strip whitespaces', () => {
17 | expect(composeClassNames(' hello ', ' world ')).toBe('hello world');
18 | });
19 | });
20 |
21 | describe('extractAtomsFromProps', () => {
22 | function createMockAtoms() {
23 | const atoms = () => 'mock';
24 | atoms.properties = new Set(['padding', 'color']);
25 | return atoms;
26 | }
27 |
28 | it('hasAtomProps should be true if it has valid atoms', () => {
29 | const atoms = createMockAtoms();
30 | const onClick = () => {};
31 | const { hasAtomProps } = extractAtomsFromProps(
32 | { padding: 'small', onClick },
33 | atoms,
34 | );
35 | expect(hasAtomProps).toBeTruthy();
36 | });
37 |
38 | it('hasAtomProps should be false if it does not have valid atoms', () => {
39 | const atoms = createMockAtoms();
40 | const onClick = () => {};
41 | const { hasAtomProps } = extractAtomsFromProps({ onClick }, atoms);
42 | expect(hasAtomProps).toBeFalsy();
43 | });
44 |
45 | it('atomProps should contain atoms', () => {
46 | const atoms = createMockAtoms();
47 | const onClick = () => {};
48 | const { atomProps } = extractAtomsFromProps(
49 | { padding: 'small', onClick, color: 'red' },
50 | atoms,
51 | );
52 | expect(atomProps).toEqual({
53 | padding: 'small',
54 | color: 'red',
55 | });
56 | });
57 |
58 | it('otherProps should contain the non-atoms props', () => {
59 | const atoms = createMockAtoms();
60 | const onClick = () => {};
61 | const { otherProps } = extractAtomsFromProps(
62 | { padding: 'small', onClick, color: 'red' },
63 | atoms,
64 | );
65 | expect(otherProps).toEqual({ onClick });
66 | });
67 |
68 | it('customProps should contain props prefixed with "__"', () => {
69 | const atoms = createMockAtoms();
70 | const { customProps } = extractAtomsFromProps(
71 | { padding: 'small', color: 'red', __width: '42px' },
72 | atoms,
73 | );
74 | expect(customProps).toEqual({ _width: '42px' });
75 | });
76 | });
77 | });
78 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "lib": ["DOM", "ESNext"],
6 | "jsx": "preserve",
7 | "strict": true,
8 | "esModuleInterop": true,
9 | "skipLibCheck": true,
10 | "forceConsistentCasingInFileNames": true,
11 | "isolatedModules": true
12 | },
13 | "exclude": ["examples"]
14 | }
15 |
--------------------------------------------------------------------------------