From 0e8e9e22f38576730c73442714c1a611847d9bc7 Mon Sep 17 00:00:00 2001 From: mauroerta Date: Thu, 20 May 2021 14:31:54 +0200 Subject: [PATCH] feat: introucing svelte package and sandbox --- apps/benchmarks/.babelrc | 3 + apps/benchmarks/package.json | 12 +- apps/benchmarks/results/core.md | 16 +-- apps/benchmarks/results/jss.md | 4 +- .../results/morfeo-vs-styled-system.md | 4 +- apps/benchmarks/src/core/completeStyle.js | 2 +- apps/svelte-sandbox/.gitignore | 4 + apps/svelte-sandbox/README.md | 105 ++++++++++++++++ apps/svelte-sandbox/package.json | 27 ++++ apps/svelte-sandbox/public/favicon.png | Bin 0 -> 3127 bytes apps/svelte-sandbox/public/index.html | 18 +++ apps/svelte-sandbox/rollup.config.js | 82 ++++++++++++ .../svelte-sandbox/scripts/setupTypeScript.js | 117 ++++++++++++++++++ apps/svelte-sandbox/src/App.svelte | 11 ++ apps/svelte-sandbox/src/components/Box.svelte | 13 ++ .../src/components/Button.svelte | 10 ++ .../src/components/ToggleTheme.svelte | 20 +++ apps/svelte-sandbox/src/main.js | 11 ++ apps/svelte-sandbox/src/theme.js | 109 ++++++++++++++++ package.json | 4 +- packages/core/src/parsers/components.ts | 2 +- packages/core/src/parsers/createParsers.ts | 2 +- packages/core/src/parsers/index.ts | 2 +- packages/core/src/parsers/parsers.ts | 7 +- packages/core/src/theme/createTheme.ts | 6 +- packages/core/src/theme/index.ts | 2 +- packages/core/src/theme/theme.ts | 6 +- packages/core/tests/theme/theme.test.ts | 12 +- packages/hooks/src/useTheme.ts | 2 +- packages/jss/package.json | 7 +- packages/jss/src/getStyles.ts | 30 ++++- .../src/ThemeProvider.tsx | 4 +- packages/svelte/package.json | 38 ++++++ packages/svelte/src/index.ts | 1 + packages/svelte/src/morfeoAction.ts | 23 ++++ packages/svelte/tests/morfeo.test.ts | 57 +++++++++ packages/svelte/tsconfig.json | 8 ++ tsconfig.base.json | 2 +- 38 files changed, 740 insertions(+), 43 deletions(-) create mode 100644 apps/benchmarks/.babelrc create mode 100644 apps/svelte-sandbox/.gitignore create mode 100644 apps/svelte-sandbox/README.md create mode 100644 apps/svelte-sandbox/package.json create mode 100644 apps/svelte-sandbox/public/favicon.png create mode 100644 apps/svelte-sandbox/public/index.html create mode 100644 apps/svelte-sandbox/rollup.config.js create mode 100644 apps/svelte-sandbox/scripts/setupTypeScript.js create mode 100644 apps/svelte-sandbox/src/App.svelte create mode 100644 apps/svelte-sandbox/src/components/Box.svelte create mode 100644 apps/svelte-sandbox/src/components/Button.svelte create mode 100644 apps/svelte-sandbox/src/components/ToggleTheme.svelte create mode 100644 apps/svelte-sandbox/src/main.js create mode 100644 apps/svelte-sandbox/src/theme.js create mode 100644 packages/svelte/package.json create mode 100644 packages/svelte/src/index.ts create mode 100644 packages/svelte/src/morfeoAction.ts create mode 100644 packages/svelte/tests/morfeo.test.ts create mode 100644 packages/svelte/tsconfig.json diff --git a/apps/benchmarks/.babelrc b/apps/benchmarks/.babelrc new file mode 100644 index 00000000..8aa924d7 --- /dev/null +++ b/apps/benchmarks/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@babel/preset-env"] +} \ No newline at end of file diff --git a/apps/benchmarks/package.json b/apps/benchmarks/package.json index a01acdd3..b31de90a 100755 --- a/apps/benchmarks/package.json +++ b/apps/benchmarks/package.json @@ -7,12 +7,16 @@ "email": "mauro@vlkstudio.com" }, "scripts": { - "morfeo-vs": "node src/morfeo-vs/index.js", - "core": "node src/core/index.js", - "jss": "node src/jss/index.js", - "all": "npm run core && npm run jss && npm run morfeo-vs" + "build": "rimraf build && babel ./src/ --out-dir build/ --ignore ./node_modules", + "morfeo-vs": "node build/morfeo-vs/index.js", + "core": "node build/core/index.js", + "jss": "node build/jss/index.js", + "all": "npm run build && npm run core && npm run jss && npm run morfeo-vs" }, "devDependencies": { + "@babel/cli": "^7.14.3", + "@babel/core": "^7.14.3", + "@babel/preset-env": "^7.14.2", "benchmark": "^2.1.4" }, "dependencies": { diff --git a/apps/benchmarks/results/core.md b/apps/benchmarks/results/core.md index 83f3e36a..c48ca83a 100644 --- a/apps/benchmarks/results/core.md +++ b/apps/benchmarks/results/core.md @@ -8,9 +8,9 @@ } ``` -**regular parsing** 1,560,270 ops/sec ±2.01% (84 runs sampled) +**regular parsing** 1,763,585 ops/sec ±0.77% (91 runs sampled) -**with cache enabled** 2,950,728 ops/sec ±0.88% (89 runs sampled) +**with cache enabled** 3,327,487 ops/sec ±1.13% (95 runs sampled) Fastest is **with cache enabled** @@ -23,9 +23,9 @@ Fastest is **with cache enabled** } ``` -**regular parsing** 822,836 ops/sec ±0.63% (93 runs sampled) +**regular parsing** 822,458 ops/sec ±2.70% (90 runs sampled) -**with cache enabled** 1,763,224 ops/sec ±1.10% (85 runs sampled) +**with cache enabled** 1,703,082 ops/sec ±1.05% (88 runs sampled) Fastest is **with cache enabled** @@ -38,9 +38,9 @@ Fastest is **with cache enabled** } ``` -**regular parsing** 136,781 ops/sec ±1.19% (92 runs sampled) +**regular parsing** 134,212 ops/sec ±1.09% (89 runs sampled) -**with cache enabled** 245,730 ops/sec ±0.96% (92 runs sampled) +**with cache enabled** 238,007 ops/sec ±1.02% (90 runs sampled) Fastest is **with cache enabled** @@ -58,8 +58,8 @@ Fastest is **with cache enabled** } ``` -**regular parsing** 58,332 ops/sec ±1.22% (85 runs sampled) +**regular parsing** 58,249 ops/sec ±1.07% (89 runs sampled) -**with cache enabled** 96,209 ops/sec ±0.86% (91 runs sampled) +**with cache enabled** 94,102 ops/sec ±0.66% (94 runs sampled) Fastest is **with cache enabled** diff --git a/apps/benchmarks/results/jss.md b/apps/benchmarks/results/jss.md index eb91650b..9728001e 100644 --- a/apps/benchmarks/results/jss.md +++ b/apps/benchmarks/results/jss.md @@ -10,8 +10,8 @@ } ``` -**regular parsing** 2,964,522 ops/sec ±0.74% (91 runs sampled) +**regular parsing** 549,704 ops/sec ±1.01% (92 runs sampled) -**jss** 196,230 ops/sec ±2.66% (87 runs sampled) +**jss** 206,599 ops/sec ±2.35% (92 runs sampled) Fastest is **regular parsing** diff --git a/apps/benchmarks/results/morfeo-vs-styled-system.md b/apps/benchmarks/results/morfeo-vs-styled-system.md index 1987df0b..ad75bd57 100644 --- a/apps/benchmarks/results/morfeo-vs-styled-system.md +++ b/apps/benchmarks/results/morfeo-vs-styled-system.md @@ -11,8 +11,8 @@ } ``` -**morfeo** 415,502 ops/sec ±0.98% (94 runs sampled) +**morfeo** 411,153 ops/sec ±1.25% (93 runs sampled) -**styled system** 331,424 ops/sec ±1.17% (89 runs sampled) +**styled system** 279,202 ops/sec ±0.84% (91 runs sampled) Fastest is **morfeo** diff --git a/apps/benchmarks/src/core/completeStyle.js b/apps/benchmarks/src/core/completeStyle.js index 81a32ec6..39fc84d4 100755 --- a/apps/benchmarks/src/core/completeStyle.js +++ b/apps/benchmarks/src/core/completeStyle.js @@ -1,6 +1,6 @@ const Benchmark = require('benchmark'); const { parsers } = require('@morfeo/core'); -const { onCycle, onComplete, onStart, appendInMd } = require('./utils'); +const { onCycle, onComplete, onStart } = require('./utils'); const suite = new Benchmark.Suite(); diff --git a/apps/svelte-sandbox/.gitignore b/apps/svelte-sandbox/.gitignore new file mode 100644 index 00000000..da93220b --- /dev/null +++ b/apps/svelte-sandbox/.gitignore @@ -0,0 +1,4 @@ +/node_modules/ +/public/build/ + +.DS_Store diff --git a/apps/svelte-sandbox/README.md b/apps/svelte-sandbox/README.md new file mode 100644 index 00000000..7b1ba836 --- /dev/null +++ b/apps/svelte-sandbox/README.md @@ -0,0 +1,105 @@ +*Looking for a shareable component template? Go here --> [sveltejs/component-template](https://github.com/sveltejs/component-template)* + +--- + +# svelte app + +This is a project template for [Svelte](https://svelte.dev) apps. It lives at https://github.com/sveltejs/template. + +To create a new project based on this template using [degit](https://github.com/Rich-Harris/degit): + +```bash +npx degit sveltejs/template svelte-app +cd svelte-app +``` + +*Note that you will need to have [Node.js](https://nodejs.org) installed.* + + +## Get started + +Install the dependencies... + +```bash +cd svelte-app +npm install +``` + +...then start [Rollup](https://rollupjs.org): + +```bash +npm run dev +``` + +Navigate to [localhost:5000](http://localhost:5000). You should see your app running. Edit a component file in `src`, save it, and reload the page to see your changes. + +By default, the server will only respond to requests from localhost. To allow connections from other computers, edit the `sirv` commands in package.json to include the option `--host 0.0.0.0`. + +If you're using [Visual Studio Code](https://code.visualstudio.com/) we recommend installing the official extension [Svelte for VS Code](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). If you are using other editors you may need to install a plugin in order to get syntax highlighting and intellisense. + +## Building and running in production mode + +To create an optimised version of the app: + +```bash +npm run build +``` + +You can run the newly built app with `npm run start`. This uses [sirv](https://github.com/lukeed/sirv), which is included in your package.json's `dependencies` so that the app will work when you deploy to platforms like [Heroku](https://heroku.com). + + +## Single-page app mode + +By default, sirv will only respond to requests that match files in `public`. This is to maximise compatibility with static fileservers, allowing you to deploy your app anywhere. + +If you're building a single-page app (SPA) with multiple routes, sirv needs to be able to respond to requests for *any* path. You can make it so by editing the `"start"` command in package.json: + +```js +"start": "sirv public --single" +``` + +## Using TypeScript + +This template comes with a script to set up a TypeScript development environment, you can run it immediately after cloning the template with: + +```bash +node scripts/setupTypeScript.js +``` + +Or remove the script via: + +```bash +rm scripts/setupTypeScript.js +``` + +## Deploying to the web + +### With [Vercel](https://vercel.com) + +Install `vercel` if you haven't already: + +```bash +npm install -g vercel +``` + +Then, from within your project folder: + +```bash +cd public +vercel deploy --name my-project +``` + +### With [surge](https://surge.sh/) + +Install `surge` if you haven't already: + +```bash +npm install -g surge +``` + +Then, from within your project folder: + +```bash +npm run build +surge public my-project.surge.sh +``` diff --git a/apps/svelte-sandbox/package.json b/apps/svelte-sandbox/package.json new file mode 100644 index 00000000..3cfc8836 --- /dev/null +++ b/apps/svelte-sandbox/package.json @@ -0,0 +1,27 @@ +{ + "name": "svelte-app", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "rollup -c", + "dev": "rollup -c -w", + "start": "sirv public --no-clear" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^17.0.0", + "@rollup/plugin-node-resolve": "^11.0.0", + "rollup": "^2.3.4", + "tslib": "^2.2.0", + "rollup-plugin-css-only": "^3.1.0", + "rollup-plugin-livereload": "^2.0.0", + "rollup-plugin-svelte": "^7.0.0", + "rollup-plugin-terser": "^7.0.0", + "svelte": "^3.0.0" + }, + "dependencies": { + "@morfeo/web": "^0.1.0", + "@morfeo/svelte": "^0.1.0", + "rollup-plugin-replace": "^2.2.0", + "sirv-cli": "^1.0.0" + } +} diff --git a/apps/svelte-sandbox/public/favicon.png b/apps/svelte-sandbox/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..7e6f5eb5a2f1f1c882d265cf479de25caa925645 GIT binary patch literal 3127 zcmV-749N3|P)i z7)}s4L53SJCkR}iVi00SFk;`MXX*#X*kkwKs@nFGS}c;=?XFjU|G$3t^5sjIVS2G+ zw)WGF83CpoGXhLGW(1gW%uV|X7>1P6VhCX=Ux)Lb!*DZ%@I3!{Gsf7d?gtIQ%nQiK z3%(LUSkBji;C5Rfgd6$VsF@H`Pk@xtY6t<>FNR-pD}=C~$?)9pdm3XZ36N5PNWYjb z$xd$yNQR9N!dfj-Vd@BwQo^FIIWPPmT&sZyQ$v81(sCBV=PGy{0wltEjB%~h157*t zvbe_!{=I_783x!0t1-r#-d{Y?ae$Q4N_Nd^Ui^@y(%)Gjou6y<3^XJdu{rmUf-Me?)zZ>9OR&6U5H*cK; z$gUlB{g0O4gN0sLSO|Of?hU(l?;h(jA3uH!Z{EBKuV23ouU@^Y6#%v+QG;>e*E}%?wlu-NT4DG zs)z)7WbLr)vGAu(ohrKc^em@OpO&f~6_>E61n_e0_V3@{U3^O;j{`^mNCJUj_>;7v zsMs6Hu3g7+@v+lSo;=yTYFqq}jZmQ-BK8K{C4kqi_i*jBaQE(Au0607V-zKeT;EPg zX(`vrn=L+e74+-Tqeok@_`tDa$G9I|$nTU5H*2V8@y()n*zqM?J1G!-1aX;CfDC9B zTnJ#j_%*n8Qb1)re*Bno7g0RG{Eb;IK14irJYJp$5Z6ac9~b_P?+5t~95~SRG$g?1 znFJ7p$xV&GZ18m~79TGRdfsc-BcX$9yXTR*n)mPD@1~O(_?cT$ZvFPucRmGlq&se0 zKrcUf^k}4hM*biEJOWKzz!qQe;CB_ZtSOO9Owg#lZAc=s65^rb{fZe(TYu_rk!wKkEf}RIt=#Om( zR8mN`DM<^xj~59euMMspBolVN zAPTr8sSDI104orIAdmL$uOXn*6hga1G+0WD0E?UtabxC#VC~vf3|10|phW;yQ3CY8 z2CM=)ErF;xq-YJ5G|um}>*1#E+O_Mu|Nr#qQ&G1P-NMq@f?@*XUcSbV?tX=)ilM-Q zBZP|!Bpv0V;#ojKcpc7$=eqO;#Uy~#?^kNI{vSZfLx&DEt~LTmaKWXcx=joubklI<*Aw z>LtMaQ7DR<1I2LkWvwyu#Rwn~;ezT}_g(@5l3h?W%-a86Y-t#O1PubP+z<%?V5D(U zy57A6{h+{?kOZp7&WKZR+=sznMJ}+Dnpo=C_0%R_x_t~J5T?E_{+))l5v1%52>)d-`iiZyx|5!%M2Fb2dU zW3~MwwpEH9Rhue+k$UIOoo($Ds!NbOyMR36fRHu;*15(YcA7siIZk#%JWz>P!qX1?IUojG&nKR>^gArBt2 zit(ETyZ=@V&7mv_Fi4bABcnwP+jzQuHcfU&BrAV91u-rFvEi7y-KnWsvHH=d2 zgAk(GKm_S8RcTJ>2N3~&Hbwp{Z3NF_Xeh}g4Eke)V&dY{W(3&b1j9t4yK_aYJisZZ{1rcU5- z;eD>K;ndPq&B-8yA_S0F!4ThA&{1{x)H<#?k9a#6Pc6L?V^s0``ynL&D;p(!Nmx`Y zFkHex{4p!Ggm^@DlehW}iHHVi}~u=$&N? z(NEBLQ#UxxAkdW>X9LnqUr#t4Lu0=9L8&o>JsqTtT5|%gb3QA~hr0pED71+iFFr)dZ=Q=E6ng{NE{Z~0)C?deO#?Aj zSDQ$z#TeC2T^|=}6GBo-&$;E{HL3!q3Z-szuf)O=G#zDjin4SSP%o%6+2IT#sLjQa ziyxFFz~LMjWY+_a5H!U6%a<=b7QVP^ z*90a62;bVq{?@)P6^DWd^Yilq4|YTV2Nw!Yu;a1lPI-sxR)rf@Fe5DhDP7FH zZZ%4S*1C30P;|O+jB!1;m|rXT90Sm5*RBbQN`PKu+hDD*S^yE(CdtSfg=z>u$cIj> z + + + + + + Svelte app + + + + + + + + + + + diff --git a/apps/svelte-sandbox/rollup.config.js b/apps/svelte-sandbox/rollup.config.js new file mode 100644 index 00000000..a60d9f61 --- /dev/null +++ b/apps/svelte-sandbox/rollup.config.js @@ -0,0 +1,82 @@ +import svelte from 'rollup-plugin-svelte'; +import commonjs from '@rollup/plugin-commonjs'; +import resolve from '@rollup/plugin-node-resolve'; +import replace from 'rollup-plugin-replace'; +import livereload from 'rollup-plugin-livereload'; +import { terser } from 'rollup-plugin-terser'; +import css from 'rollup-plugin-css-only'; + +const production = !process.env.ROLLUP_WATCH; + +function serve() { + let server; + + function toExit() { + if (server) server.kill(0); + } + + return { + writeBundle() { + if (server) return; + server = require('child_process').spawn( + 'npm', + ['run', 'start', '--', '--dev'], + { + stdio: ['ignore', 'inherit', 'inherit'], + shell: true, + }, + ); + + process.on('SIGTERM', toExit); + process.on('exit', toExit); + }, + }; +} + +export default { + input: 'src/main.js', + output: { + sourcemap: true, + format: 'iife', + name: 'app', + file: 'public/build/bundle.js', + }, + plugins: [ + replace({ 'process.env.NODE_ENV': JSON.stringify('production') }), + svelte({ + compilerOptions: { + // enable run-time checks when not in production + dev: !production, + }, + }), + // we'll extract any component CSS out into + // a separate file - better for performance + css({ output: 'bundle.css' }), + + // If you have external dependencies installed from + // npm, you'll most likely need these plugins. In + // some cases you'll need additional configuration - + // consult the documentation for details: + // https://github.com/rollup/plugins/tree/master/packages/commonjs + resolve({ + browser: true, + dedupe: ['svelte'], + }), + commonjs(), + + // In dev mode, call `npm run start` once + // the bundle has been generated + !production && serve(), + + // Watch the `public` directory and refresh the + // browser on changes when not in production + !production && livereload('public'), + + // If we're building for production (npm run build + // instead of npm run dev), minify + production && terser(), + ], + watch: { + clearScreen: false, + }, +}; diff --git a/apps/svelte-sandbox/scripts/setupTypeScript.js b/apps/svelte-sandbox/scripts/setupTypeScript.js new file mode 100644 index 00000000..1eb6b772 --- /dev/null +++ b/apps/svelte-sandbox/scripts/setupTypeScript.js @@ -0,0 +1,117 @@ +// @ts-check + +/** This script modifies the project to support TS code in .svelte files like: + + + + As well as validating the code for CI. + */ + +/** To work on this script: + rm -rf test-template template && git clone sveltejs/template test-template && node scripts/setupTypeScript.js test-template +*/ + +const fs = require("fs") +const path = require("path") +const { argv } = require("process") + +const projectRoot = argv[2] || path.join(__dirname, "..") + +// Add deps to pkg.json +const packageJSON = JSON.parse(fs.readFileSync(path.join(projectRoot, "package.json"), "utf8")) +packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, { + "svelte-check": "^1.0.0", + "svelte-preprocess": "^4.0.0", + "@rollup/plugin-typescript": "^8.0.0", + "typescript": "^4.0.0", + "tslib": "^2.0.0", + "@tsconfig/svelte": "^1.0.0" +}) + +// Add script for checking +packageJSON.scripts = Object.assign(packageJSON.scripts, { + "validate": "svelte-check" +}) + +// Write the package JSON +fs.writeFileSync(path.join(projectRoot, "package.json"), JSON.stringify(packageJSON, null, " ")) + +// mv src/main.js to main.ts - note, we need to edit rollup.config.js for this too +const beforeMainJSPath = path.join(projectRoot, "src", "main.js") +const afterMainTSPath = path.join(projectRoot, "src", "main.ts") +fs.renameSync(beforeMainJSPath, afterMainTSPath) + +// Switch the app.svelte file to use TS +const appSveltePath = path.join(projectRoot, "src", "App.svelte") +let appFile = fs.readFileSync(appSveltePath, "utf8") +appFile = appFile.replace(" + + + + + + diff --git a/apps/svelte-sandbox/src/components/Box.svelte b/apps/svelte-sandbox/src/components/Box.svelte new file mode 100644 index 00000000..50f8f7e9 --- /dev/null +++ b/apps/svelte-sandbox/src/components/Box.svelte @@ -0,0 +1,13 @@ + + +
+ +
\ No newline at end of file diff --git a/apps/svelte-sandbox/src/components/Button.svelte b/apps/svelte-sandbox/src/components/Button.svelte new file mode 100644 index 00000000..a0c24bd0 --- /dev/null +++ b/apps/svelte-sandbox/src/components/Button.svelte @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/apps/svelte-sandbox/src/components/ToggleTheme.svelte b/apps/svelte-sandbox/src/components/ToggleTheme.svelte new file mode 100644 index 00000000..ce10de43 --- /dev/null +++ b/apps/svelte-sandbox/src/components/ToggleTheme.svelte @@ -0,0 +1,20 @@ + + + \ No newline at end of file diff --git a/apps/svelte-sandbox/src/main.js b/apps/svelte-sandbox/src/main.js new file mode 100644 index 00000000..18453043 --- /dev/null +++ b/apps/svelte-sandbox/src/main.js @@ -0,0 +1,11 @@ +import { theme } from '@morfeo/web'; +import App from './App.svelte'; +import { lightTheme } from './theme'; + +theme.set(lightTheme); + +const app = new App({ + target: document.body, +}); + +export default app; diff --git a/apps/svelte-sandbox/src/theme.js b/apps/svelte-sandbox/src/theme.js new file mode 100644 index 00000000..2075a9a0 --- /dev/null +++ b/apps/svelte-sandbox/src/theme.js @@ -0,0 +1,109 @@ +export const lightTheme = { + colors: { + primary: 'white', + secondary: 'black', + danger: 'red', + }, + radii: { + m: '10px', + round: '50%', + }, + space: { + s: '40px', + m: '100px', + }, + sizes: { + s: '10px', + m: '100px', + xl: '200px', + }, + borderWidths: { + s: '2px', + }, + breakpoints: { + md: '900px', + lg: '1300px', + }, + transitions: { + light: 'all 0.5s', + }, + components: { + Box: { + tag: 'div', + style: {}, + }, + Button: { + tag: 'button', + style: { + transition: 'light', + height: 'm', + width: 'm', + bg: { + md: 'danger', + lg: 'primary', + }, + color: 'secondary', + borderRadius: 'm', + borderWidth: 's', + borderStyle: 'solid', + borderColor: 'primary', + '&:hover': { + bg: 'secondary', + color: 'primary', + }, + }, + props: { + 'aria-label': 'button', + type: 'button', + }, + variants: { + primary: { + props: { + 'aria-label': 'primary button', + }, + style: { + bg: 'secondary', + borderColor: 'primary', + color: 'primary', + '&:hover': { + bg: 'primary', + color: 'secondary', + }, + }, + }, + round: { + style: { borderRadius: 'round' }, + }, + }, + }, + Typography: { + tag: 'p', + style: {}, + variants: { + h1: { + tag: 'h1', + style: { color: 'red' }, + }, + h2: { + tag: 'h1', + style: { color: 'green' }, + }, + h3: { + tag: 'h3', + style: { color: 'blue' }, + }, + code: { + tag: 'pre', + style: { color: 'primary' }, + }, + }, + }, + }, +}; + +export const darkTheme = { + colors: { + primary: 'black', + secondary: 'white', + }, +}; diff --git a/package.json b/package.json index 962464ce..c5a211f8 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,11 @@ "watch": "lerna run watch", "reset": "npm run clean && npm i && lerna bootstrap && npm run build", "init:web-sandbox": "node scripts/bootstrap-app.mjs web-sandbox", + "init:svelte-sandbox": "node scripts/bootstrap-app.mjs svelte-sandbox", "init:native-sandbox": "node scripts/bootstrap-app.mjs native-sandbox", "init:benchmarks": "node scripts/bootstrap-app.mjs benchmarks", "start:web-sandbox": "npm start --prefix apps/web-sandbox", + "start:svelte-sandbox": "npm run dev --prefix apps/svelte-sandbox", "start:benchmarks": "npm run all --prefix apps/benchmarks", "prepare": "husky install", "prettify": "npm run prettify:js && npm run prettify:ts", @@ -19,7 +21,7 @@ "test:watch": "jest --watch --updateSnapshot", "test:coverage": "jest --coverage --updateSnapshot", "test:badges": "npm run test:coverage && jest-coverage-badges output \"./assets/badges\"", - "publish": "npx lerna publish from-package --yes", + "publish": "npm run build && npx lerna publish from-package --yes", "version": "npx lerna version patch --no-push --no-git-tag-version --conventional-commits" }, "dependencies": { diff --git a/packages/core/src/parsers/components.ts b/packages/core/src/parsers/components.ts index b1b5e283..17bd2570 100644 --- a/packages/core/src/parsers/components.ts +++ b/packages/core/src/parsers/components.ts @@ -1,7 +1,7 @@ import { theme } from '../theme'; import { ComponentConfig } from '@morfeo/spec'; import { ParserParams } from '../types'; -import { parsers } from './parsers'; +import parsers from './parsers'; function getVariantStyle( variants: ComponentConfig['variants'], diff --git a/packages/core/src/parsers/createParsers.ts b/packages/core/src/parsers/createParsers.ts index 32d991d1..351b7706 100644 --- a/packages/core/src/parsers/createParsers.ts +++ b/packages/core/src/parsers/createParsers.ts @@ -180,7 +180,7 @@ export function createParsers() { : parsedStyle; } - theme.listen(resetCache); + theme.subscribe(resetCache); const parsers = { get, diff --git a/packages/core/src/parsers/index.ts b/packages/core/src/parsers/index.ts index f6279133..21b2fd24 100644 --- a/packages/core/src/parsers/index.ts +++ b/packages/core/src/parsers/index.ts @@ -1,2 +1,2 @@ -export * from './parsers'; +export { default as parsers } from './parsers'; export * from './baseParser'; diff --git a/packages/core/src/parsers/parsers.ts b/packages/core/src/parsers/parsers.ts index 4698857c..5853afa3 100644 --- a/packages/core/src/parsers/parsers.ts +++ b/packages/core/src/parsers/parsers.ts @@ -12,5 +12,8 @@ declare global { } } -export const parsers: ParserHandler = - globalThis.__MORFEO_PARSERS || createParsers(); +const parsers: ParserHandler = globalThis.__MORFEO_PARSERS || createParsers(); + +Object.freeze(parsers); + +export default parsers; diff --git a/packages/core/src/theme/createTheme.ts b/packages/core/src/theme/createTheme.ts index 4874c984..33805162 100644 --- a/packages/core/src/theme/createTheme.ts +++ b/packages/core/src/theme/createTheme.ts @@ -12,7 +12,7 @@ export function createTheme() { } function getSlice(slice: T) { - return context[slice] || {}; + return get()[slice] || {}; } function getValue( @@ -88,7 +88,7 @@ export function createTheme() { return safeUid; } - function listen(callback: ThemeListener, uid?: string) { + function subscribe(callback: ThemeListener, uid?: string) { const safeUid = getSafeUid(uid); listeners.push([callback, safeUid]); return safeUid; @@ -106,12 +106,12 @@ export function createTheme() { get, set, reset, - listen, cleanUp, getSlice, setSlice, getValue, setValue, + subscribe, isResponsive, resolveMediaQuery, }; diff --git a/packages/core/src/theme/index.ts b/packages/core/src/theme/index.ts index 7b1f54ec..3321864c 100644 --- a/packages/core/src/theme/index.ts +++ b/packages/core/src/theme/index.ts @@ -1 +1 @@ -export * from './theme'; +export { default as theme } from './theme'; diff --git a/packages/core/src/theme/theme.ts b/packages/core/src/theme/theme.ts index 30e56ad0..8d265501 100644 --- a/packages/core/src/theme/theme.ts +++ b/packages/core/src/theme/theme.ts @@ -12,4 +12,8 @@ declare global { } } -export const theme: ThemeHandler = globalThis.__MORFEO_THEME || createTheme(); +const theme: ThemeHandler = globalThis.__MORFEO_THEME || createTheme(); + +Object.freeze(theme); + +export default theme; diff --git a/packages/core/tests/theme/theme.test.ts b/packages/core/tests/theme/theme.test.ts index 259e2419..836c6575 100644 --- a/packages/core/tests/theme/theme.test.ts +++ b/packages/core/tests/theme/theme.test.ts @@ -58,8 +58,8 @@ describe('theme', () => { test('should call all the added listeners each time the theme is updated', () => { const firstListener = jest.fn(); const secondListener = jest.fn(); - theme.listen(firstListener); - theme.listen(secondListener); + theme.subscribe(firstListener); + theme.subscribe(secondListener); theme.setSlice('colors', { primary: 'white' }); theme.setSlice('space', { l: '50px' }); expect(firstListener).toHaveBeenCalledTimes(2); @@ -73,9 +73,9 @@ describe('theme', () => { }); test('should generate a unique id for each listener', () => { - const firstUid = theme.listen(jest.fn(), 'test'); - const secondUid = theme.listen(jest.fn(), 'test'); - const thirdUid = theme.listen(jest.fn()); + const firstUid = theme.subscribe(jest.fn(), 'test'); + const secondUid = theme.subscribe(jest.fn(), 'test'); + const thirdUid = theme.subscribe(jest.fn()); expect(firstUid).toBe('test'); expect(secondUid).toBe('test-0'); @@ -84,7 +84,7 @@ describe('theme', () => { test('should remove the specified listener with the cleanUp method', () => { const listener = jest.fn(); - const uid = theme.listen(listener, 'test'); + const uid = theme.subscribe(listener, 'test'); theme.cleanUp(uid); theme.setValue('colors', 'primary', 'black'); diff --git a/packages/hooks/src/useTheme.ts b/packages/hooks/src/useTheme.ts index 5eceb6ea..c598db7a 100644 --- a/packages/hooks/src/useTheme.ts +++ b/packages/hooks/src/useTheme.ts @@ -9,7 +9,7 @@ export function useTheme() { const [t, setTheme] = useState(theme.get()); useEffect(() => { - const uid = theme.listen(setTheme); + const uid = theme.subscribe(setTheme); return () => { theme.cleanUp(uid); }; diff --git a/packages/jss/package.json b/packages/jss/package.json index f0cf6416..a3d01f9a 100644 --- a/packages/jss/package.json +++ b/packages/jss/package.json @@ -21,10 +21,15 @@ "watch": "tsc -w" }, "dependencies": { - "@morfeo/web": "^0.1.0", "jss": "^10.6.0", "jss-preset-default": "^10.6.0" }, + "peerDependencies": { + "@morfeo/web": "^0.1.0" + }, + "devDependencies": { + "@morfeo/web": "^0.1.0" + }, "publishConfig": { "access": "public" }, diff --git a/packages/jss/src/getStyles.ts b/packages/jss/src/getStyles.ts index 2c5f703e..486ec46e 100644 --- a/packages/jss/src/getStyles.ts +++ b/packages/jss/src/getStyles.ts @@ -1,4 +1,4 @@ -import { parsers, Style, ResolvedStyle } from '@morfeo/web'; +import { parsers, Style, ResolvedStyle, theme } from '@morfeo/web'; import jss, { StyleSheetFactoryOptions } from 'jss'; import './initJSS'; @@ -17,12 +17,34 @@ export function getStyleSheet( return jss.createStyleSheet(parsedStyle as any, options); } -export function getStyles( +export function getRawStyles( styles: Record, options?: StyleSheetFactoryOptions, ) { - const sheet = getStyleSheet(styles, options); + let sheet = getStyleSheet(styles, options); sheet.attach(); - return sheet.classes; + const classes = sheet.classes; + + const uid = theme.subscribe(() => { + sheet.detach(); + sheet = getStyleSheet(styles, { + ...options, + generateId: rule => { + return classes[rule.key]; + }, + }); + sheet.attach(); + }); + + return { classes, sheet, uid }; +} + +export function getStyles( + styles: Record, + options?: StyleSheetFactoryOptions, +) { + const { classes } = getRawStyles(styles, options); + + return classes; } diff --git a/packages/styled-components-web/src/ThemeProvider.tsx b/packages/styled-components-web/src/ThemeProvider.tsx index d91a49f8..f5040b5f 100644 --- a/packages/styled-components-web/src/ThemeProvider.tsx +++ b/packages/styled-components-web/src/ThemeProvider.tsx @@ -1,5 +1,5 @@ import React, { FC, useEffect, useState } from 'react'; -import { theme } from '@morfeo/web'; +import { theme, Theme } from '@morfeo/web'; import { ThemeProvider as StyledProvider } from 'styled-components'; type Props = Omit, 'theme'>; @@ -8,7 +8,7 @@ export const ThemeProvider: FC = ({ children }) => { const [currentTheme, setTheme] = useState(theme.get()); useEffect(() => { - theme.listen(setTheme); + theme.subscribe(setTheme); }, []); return {children}; diff --git a/packages/svelte/package.json b/packages/svelte/package.json new file mode 100644 index 00000000..a8510604 --- /dev/null +++ b/packages/svelte/package.json @@ -0,0 +1,38 @@ +{ + "name": "@morfeo/svelte", + "author": { + "name": "Mauro Erta", + "email": "mauro@vlkstudio.com" + }, + "private": false, + "version": "0.1.0", + "license": "MIT", + "main": "build/index.js", + "module": "build/index.js", + "types": "build/index", + "typings": "build/index", + "keywords": [ + "design", + "system", + "svelte" + ], + "scripts": { + "build": "rimraf build && tsc", + "watch": "tsc -w" + }, + "dependencies": { + "@morfeo/jss": "^0.1.0" + }, + "peerDependencies": { + "@morfeo/web": "^0.1.0" + }, + "devDependencies": { + "@morfeo/web": "^0.1.0" + }, + "publishConfig": { + "access": "public" + }, + "files": [ + "build" + ] +} diff --git a/packages/svelte/src/index.ts b/packages/svelte/src/index.ts new file mode 100644 index 00000000..d05c2dff --- /dev/null +++ b/packages/svelte/src/index.ts @@ -0,0 +1 @@ +export * from './morfeoAction'; diff --git a/packages/svelte/src/morfeoAction.ts b/packages/svelte/src/morfeoAction.ts new file mode 100644 index 00000000..989e436f --- /dev/null +++ b/packages/svelte/src/morfeoAction.ts @@ -0,0 +1,23 @@ +import { getRawStyles } from '@morfeo/jss'; +import { Style, theme } from '@morfeo/web'; + +function getElementName({ componentName, variant }: Style) { + if (componentName && variant) { + return `${componentName}-${variant}`; + } + + return componentName || 'morfeo-element'; +} + +export function morfeo(node: HTMLElement, props: Style = {}) { + const elementName = getElementName(props); + const { classes, uid } = getRawStyles({ [elementName]: props }); + + node.classList.add(classes[elementName]); + + return { + destroy() { + theme.cleanUp(uid); + }, + }; +} diff --git a/packages/svelte/tests/morfeo.test.ts b/packages/svelte/tests/morfeo.test.ts new file mode 100644 index 00000000..b6cdbe16 --- /dev/null +++ b/packages/svelte/tests/morfeo.test.ts @@ -0,0 +1,57 @@ +import { Theme, theme } from '@morfeo/web'; +import { morfeo } from '../src'; + +const THEME: Theme = { + colors: { + primary: '#e3e3e3', + secondary: '#000', + }, + components: { + Box: { + style: { + bg: 'secondary', + }, + }, + }, +} as any; + +describe('morfeo', () => { + beforeAll(() => { + theme.set(THEME); + }); + + test('should add default className to the element', () => { + const element = document.createElement('div'); + morfeo(element, { bg: 'primary' }); + + expect(element.className).toContain('morfeo-element'); + }); + + test('should add custom className if componentName is specified', () => { + const element = document.createElement('div'); + morfeo(element, { componentName: 'Box' }); + + expect(element.className).toContain('Box'); + }); + + test('should add custom className if componentName and variant is specified', () => { + const element = document.createElement('div'); + morfeo(element, { componentName: 'Box', variant: 'primary' }); + + expect(element.className).toContain('Box-primary'); + }); + + test('should not crash if style is not specified', () => { + const element = document.createElement('div'); + morfeo(element); + + expect(element.className).toContain('morfeo-element'); + }); + + test('should return a function that will remove the listener from the theme', () => { + const element = document.createElement('div'); + const { destroy } = morfeo(element); + destroy(); + expect(typeof destroy).toBe('function'); + }); +}); diff --git a/packages/svelte/tsconfig.json b/packages/svelte/tsconfig.json new file mode 100644 index 00000000..9ee04b7b --- /dev/null +++ b/packages/svelte/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./build", + }, + "include": ["./src"], + "exclude": ["./node_modules", "./src/**/*.test.ts", "./src/**/*.spec.ts"] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 2014c898..d3d7f2e9 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -5,7 +5,7 @@ "watch": false, "strict": true, "target": "es6", - "module": "CommonJS", + "module": "ES2015", "allowJs": true, "sourceMap": true, "diagnostics": false,