diff --git a/.gitignore b/.gitignore index d2114b4..4c9d7ee 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ log.txt .stencil/ .idea/ -.vscode/ .sass-cache/ .versions/ node_modules/ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..bf2b964 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "html.customData": ["./vscode-data.json"] +} diff --git a/package.json b/package.json index 437a0b4..c0de967 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,8 @@ "sbb": "stencil build && storybook build --docs", "dev": "NODE_ENV=development npm-run-all -p dev:*", "dev:start": "stencil build --watch --dev --serve", - "dev:storybook": "sleep 6 && storybook dev -p 6006" + "dev:storybook": "sleep 6 && storybook dev -p 6006", + "generate-slangroom-presets-file": "node src/components/dyne-slangroom-preset-loader/utils/generate-preset-json.mjs" }, "devDependencies": { "@chromatic-com/storybook": "^1.5.0", @@ -68,6 +69,8 @@ "@storybook/theming": "^8.1.10", "@tailwindcss/line-clamp": "^0.4.4", "@types/jest": "^29.5.12", + "degit": "^2.8.4", + "glob": "^11.0.0", "jest": "29", "jest-cli": "29", "lit": "^3.1.4", @@ -78,6 +81,7 @@ "stencil-tailwind-plugin": "^1.8.0", "storybook": "^8.1.10", "tailwindcss": "^3.4.4", + "ts-node": "^10.9.2", "typescript": "^5.5.2", "vite": "^5.3.1" }, @@ -89,9 +93,12 @@ "@codemirror/view": "^6.28.2", "@sinclair/typebox": "^0.32.34", "@slangroom/browser": "^1.33.12", + "@types/degit": "^2.8.6", "@types/node": "^20.14.8", "ansi-to-html": "^0.7.2", "codemirror": "^6.0.1", + "effect": "^3.5.7", + "fuse.js": "^7.0.0", "has-ansi": "^6.0.0", "lucide-react": "^0.396.0", "nanoid": "^5.0.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 74a673a..c2c5e69 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: '@slangroom/browser': specifier: ^1.33.12 version: 1.35.0(@capacitor/core@6.1.0)(zenroom@4.32.5) + '@types/degit': + specifier: ^2.8.6 + version: 2.8.6 '@types/node': specifier: ^20.14.8 version: 20.14.10 @@ -35,6 +38,12 @@ importers: codemirror: specifier: ^6.0.1 version: 6.0.1(@lezer/common@1.2.1) + effect: + specifier: ^3.5.7 + version: 3.5.7 + fuse.js: + specifier: ^7.0.0 + version: 7.0.0 has-ansi: specifier: ^6.0.0 version: 6.0.0 @@ -125,22 +134,28 @@ importers: version: 8.2.1(storybook@8.2.1(@babel/preset-env@7.24.7(@babel/core@7.24.7))) '@storybook/test': specifier: ^8.1.10 - version: 8.2.1(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.10))(storybook@8.2.1(@babel/preset-env@7.24.7(@babel/core@7.24.7))) + version: 8.2.1(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)))(storybook@8.2.1(@babel/preset-env@7.24.7(@babel/core@7.24.7))) '@storybook/theming': specifier: ^8.1.10 version: 8.2.1(storybook@8.2.1(@babel/preset-env@7.24.7(@babel/core@7.24.7))) '@tailwindcss/line-clamp': specifier: ^0.4.4 - version: 0.4.4(tailwindcss@3.4.4) + version: 0.4.4(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3))) '@types/jest': specifier: ^29.5.12 version: 29.5.12 + degit: + specifier: ^2.8.4 + version: 2.8.4 + glob: + specifier: ^11.0.0 + version: 11.0.0 jest: specifier: '29' - version: 29.7.0(@types/node@20.14.10) + version: 29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) jest-cli: specifier: '29' - version: 29.7.0(@types/node@20.14.10) + version: 29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) lit: specifier: ^3.1.4 version: 3.1.4 @@ -158,13 +173,16 @@ importers: version: 24.0.0(typescript@5.5.3) stencil-tailwind-plugin: specifier: ^1.8.0 - version: 1.8.0(tailwindcss@3.4.4)(typescript@5.5.3) + version: 1.8.0(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)))(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3))(typescript@5.5.3) storybook: specifier: ^8.1.10 version: 8.2.1(@babel/preset-env@7.24.7(@babel/core@7.24.7)) tailwindcss: specifier: ^3.4.4 - version: 3.4.4 + version: 3.4.4(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@20.14.10)(typescript@5.5.3) typescript: specifier: ^5.5.2 version: 5.5.3 @@ -874,6 +892,10 @@ packages: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + '@esbuild/aix-ppc64@0.21.5': resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} @@ -1114,6 +1136,9 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@lezer/common@1.2.1': resolution: {integrity: sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==} @@ -1650,6 +1675,18 @@ packages: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -1674,6 +1711,9 @@ packages: '@types/cross-spawn@6.0.6': resolution: {integrity: sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==} + '@types/degit@2.8.6': + resolution: {integrity: sha512-y0M7sqzsnHB6cvAeTCBPrCQNQiZe8U4qdzf8uBVmOWYap5MMTN/gB2iEqrIqFiYcsyvP74GnGD5tgsHttielFw==} + '@types/emscripten@1.39.13': resolution: {integrity: sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==} @@ -1794,6 +1834,10 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + acorn-walk@8.3.3: + resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==} + engines: {node: '>=0.4.0'} + acorn@8.12.1: resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} engines: {node: '>=0.4.0'} @@ -1858,6 +1902,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -2297,6 +2344,9 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} @@ -2446,6 +2496,11 @@ packages: resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} engines: {node: '>= 14'} + degit@2.8.4: + resolution: {integrity: sha512-vqYuzmSA5I50J882jd+AbAhQtgK6bdKUJIex1JNfEUPENCgYsxugzKVZlFyMwV4i06MmnV47/Iqi5Io86zf3Ng==} + engines: {node: '>=8.0.0'} + hasBin: true + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -2480,6 +2535,10 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dijkstrajs@1.0.3: resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} @@ -2526,6 +2585,9 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + effect@3.5.7: + resolution: {integrity: sha512-PzEncc0R3ZZhqNTR+fXrSX+anF/4Ai6ftKie1ZrUUWY7WPE7d4KjB6wjpeWoGMOC7xWFPGSkBBUudyJN1mx3+g==} + electron-to-chromium@1.4.825: resolution: {integrity: sha512-OCcF+LwdgFGcsYPYC5keEEFC2XT0gBhrYbeGzHCx7i9qRFbzO/AqTmc/C/1xNhJj+JA7rzlN7mpBuStshh96Cg==} @@ -2849,6 +2911,10 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + fuse.js@7.0.0: + resolution: {integrity: sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==} + engines: {node: '>=10'} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -2918,6 +2984,11 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true + glob@11.0.0: + resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} + engines: {node: 20 || >=22} + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -3278,6 +3349,10 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@4.0.1: + resolution: {integrity: sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==} + engines: {node: 20 || >=22} + java-properties@1.0.2: resolution: {integrity: sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==} engines: {node: '>= 0.6.0'} @@ -3564,6 +3639,10 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.0.0: + resolution: {integrity: sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -3602,6 +3681,9 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} @@ -3691,6 +3773,10 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} + minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -4106,6 +4192,10 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} @@ -5080,6 +5170,20 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -5233,6 +5337,9 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + v8-to-istanbul@9.3.0: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} @@ -5400,6 +5507,10 @@ packages: yauzl@2.10.0: resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -6348,6 +6459,10 @@ snapshots: '@colors/colors@1.5.0': optional: true + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + '@esbuild/aix-ppc64@0.21.5': optional: true @@ -6449,7 +6564,7 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0': + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -6463,7 +6578,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.14.10) + jest-config: 29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -6619,6 +6734,11 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + '@lezer/common@1.2.1': {} '@lezer/highlight@1.2.0': @@ -7264,12 +7384,12 @@ snapshots: react-dom: 18.3.1(react@18.3.1) storybook: 8.2.1(@babel/preset-env@7.24.7(@babel/core@7.24.7)) - '@storybook/test@8.2.1(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.10))(storybook@8.2.1(@babel/preset-env@7.24.7(@babel/core@7.24.7)))': + '@storybook/test@8.2.1(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)))(storybook@8.2.1(@babel/preset-env@7.24.7(@babel/core@7.24.7)))': dependencies: '@storybook/csf': 0.1.11 '@storybook/instrumenter': 8.2.1(storybook@8.2.1(@babel/preset-env@7.24.7(@babel/core@7.24.7))) '@testing-library/dom': 10.1.0 - '@testing-library/jest-dom': 6.4.5(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.10)) + '@testing-library/jest-dom': 6.4.5(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3))) '@testing-library/user-event': 14.5.2(@testing-library/dom@10.1.0) '@vitest/expect': 1.6.0 '@vitest/spy': 1.6.0 @@ -7286,9 +7406,9 @@ snapshots: dependencies: storybook: 8.2.1(@babel/preset-env@7.24.7(@babel/core@7.24.7)) - '@tailwindcss/line-clamp@0.4.4(tailwindcss@3.4.4)': + '@tailwindcss/line-clamp@0.4.4(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)))': dependencies: - tailwindcss: 3.4.4 + tailwindcss: 3.4.4(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) '@testing-library/dom@10.1.0': dependencies: @@ -7301,7 +7421,7 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/jest-dom@6.4.5(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.10))': + '@testing-library/jest-dom@6.4.5(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)))': dependencies: '@adobe/css-tools': 4.4.0 '@babel/runtime': 7.24.7 @@ -7314,7 +7434,7 @@ snapshots: optionalDependencies: '@jest/globals': 29.7.0 '@types/jest': 29.5.12 - jest: 29.7.0(@types/node@20.14.10) + jest: 29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) '@testing-library/user-event@14.5.2(@testing-library/dom@10.1.0)': dependencies: @@ -7324,6 +7444,14 @@ snapshots: '@trysound/sax@0.2.0': {} + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + '@types/aria-query@5.0.4': {} '@types/babel__core@7.20.5': @@ -7360,6 +7488,8 @@ snapshots: dependencies: '@types/node': 20.14.10 + '@types/degit@2.8.6': {} + '@types/emscripten@1.39.13': {} '@types/estree@1.0.5': {} @@ -7498,6 +7628,10 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 + acorn-walk@8.3.3: + dependencies: + acorn: 8.12.1 + acorn@8.12.1: {} agent-base@7.1.1: @@ -7558,6 +7692,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + arg@4.1.3: {} + arg@5.0.2: {} argparse@1.0.10: @@ -8062,13 +8198,13 @@ snapshots: optionalDependencies: typescript: 5.5.3 - create-jest@29.7.0(@types/node@20.14.10): + create-jest@29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.14.10) + jest-config: 29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -8077,6 +8213,8 @@ snapshots: - supports-color - ts-node + create-require@1.1.1: {} + crelt@1.0.6: {} cross-spawn@6.0.5: @@ -8238,6 +8376,8 @@ snapshots: escodegen: 2.1.0 esprima: 4.0.1 + degit@2.8.4: {} + delayed-stream@1.0.0: {} depd@2.0.0: {} @@ -8256,6 +8396,8 @@ snapshots: diff-sequences@29.6.3: {} + diff@4.0.2: {} + dijkstrajs@1.0.3: {} dir-glob@3.0.1: @@ -8300,6 +8442,8 @@ snapshots: ee-first@1.1.1: {} + effect@3.5.7: {} + electron-to-chromium@1.4.825: {} emittery@0.13.1: {} @@ -8736,6 +8880,8 @@ snapshots: functions-have-names@1.2.3: {} + fuse.js@7.0.0: {} + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} @@ -8821,6 +8967,15 @@ snapshots: package-json-from-dist: 1.0.0 path-scurry: 1.11.1 + glob@11.0.0: + dependencies: + foreground-child: 3.2.1 + jackspeak: 4.0.1 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 2.0.0 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -9174,6 +9329,12 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jackspeak@4.0.1: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + java-properties@1.0.2: {} jest-changed-files@29.7.0: @@ -9208,16 +9369,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.14.10): + jest-cli@29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)): dependencies: - '@jest/core': 29.7.0 + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.14.10) + create-jest: 29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.14.10) + jest-config: 29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -9227,7 +9388,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@20.14.10): + jest-config@29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)): dependencies: '@babel/core': 7.24.7 '@jest/test-sequencer': 29.7.0 @@ -9253,6 +9414,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.14.10 + ts-node: 10.9.2(@types/node@20.14.10)(typescript@5.5.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -9472,12 +9634,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.14.10): + jest@29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)): dependencies: - '@jest/core': 29.7.0 + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.14.10) + jest-cli: 29.7.0(@types/node@20.14.10)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -9636,6 +9798,8 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@11.0.0: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -9673,6 +9837,8 @@ snapshots: dependencies: semver: 7.6.2 + make-error@1.3.6: {} + makeerror@1.0.12: dependencies: tmpl: 1.0.5 @@ -9736,6 +9902,10 @@ snapshots: min-indent@1.0.1: {} + minimatch@10.0.1: + dependencies: + brace-expansion: 2.0.1 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -10056,6 +10226,11 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + path-scurry@2.0.0: + dependencies: + lru-cache: 11.0.0 + minipass: 7.1.2 + path-to-regexp@0.1.7: {} path-type@3.0.0: @@ -10176,12 +10351,13 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.4.39 - postcss-load-config@4.0.2(postcss@8.4.39): + postcss-load-config@4.0.2(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)): dependencies: lilconfig: 3.1.2 yaml: 2.4.5 optionalDependencies: postcss: 8.4.39 + ts-node: 10.9.2(@types/node@20.14.10)(typescript@5.5.3) postcss-merge-longhand@5.1.7(postcss@8.4.39): dependencies: @@ -10868,7 +11044,7 @@ snapshots: statuses@2.0.1: {} - stencil-tailwind-plugin@1.8.0(tailwindcss@3.4.4)(typescript@5.5.3): + stencil-tailwind-plugin@1.8.0(tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)))(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3))(typescript@5.5.3): dependencies: autoprefixer: 10.4.19(postcss@8.4.39) chalk: 4.1.2 @@ -10878,8 +11054,8 @@ snapshots: postcss: 8.4.39 postcss-combine-duplicated-selectors: 10.0.3(postcss@8.4.39) postcss-discard-comments: 5.1.2(postcss@8.4.39) - postcss-load-config: 4.0.2(postcss@8.4.39) - tailwindcss: 3.4.4 + postcss-load-config: 4.0.2(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) + tailwindcss: 3.4.4(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) typescript: 5.5.3 transitivePeerDependencies: - ts-node @@ -11062,7 +11238,7 @@ snapshots: picocolors: 1.0.1 stable: 0.1.8 - tailwindcss@3.4.4: + tailwindcss@3.4.4(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -11081,7 +11257,7 @@ snapshots: postcss: 8.4.39 postcss-import: 15.1.0(postcss@8.4.39) postcss-js: 4.0.1(postcss@8.4.39) - postcss-load-config: 4.0.2(postcss@8.4.39) + postcss-load-config: 4.0.2(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)) postcss-nested: 6.0.1(postcss@8.4.39) postcss-selector-parser: 6.1.0 resolve: 1.22.8 @@ -11184,6 +11360,24 @@ snapshots: ts-interface-checker@0.1.13: {} + ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.14.10 + acorn: 8.12.1 + acorn-walk: 8.3.3 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.5.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + tslib@1.14.1: {} tslib@2.6.3: {} @@ -11333,6 +11527,8 @@ snapshots: uuid@9.0.1: {} + v8-compile-cache-lib@3.0.1: {} + v8-to-istanbul@9.3.0: dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -11494,6 +11690,8 @@ snapshots: buffer-crc32: 0.2.13 fd-slicer: 1.1.0 + yn@3.1.1: {} + yocto-queue@0.1.0: {} yocto-queue@1.1.1: {} diff --git a/src/components.d.ts b/src/components.d.ts index 296bd6c..a8e3131 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -7,10 +7,12 @@ import { HTMLStencilElement, JSXBase } from "@stencil/core/internal"; import { Color, Emphasis, Size } from "./components/types"; import { EditorStateConfig } from "@codemirror/state"; -import { SlangroomEditorContent } from "./components/dyne-slangroom-editor/dyne-slangroom-editor"; +import { EditorId, SlangroomEditorContent } from "./components/dyne-slangroom-editor/dyne-slangroom-editor"; +import { SlangroomPreset } from "./components/dyne-slangroom-preset-loader/dyne-slangroom-preset-loader"; export { Color, Emphasis, Size } from "./components/types"; export { EditorStateConfig } from "@codemirror/state"; -export { SlangroomEditorContent } from "./components/dyne-slangroom-editor/dyne-slangroom-editor"; +export { EditorId, SlangroomEditorContent } from "./components/dyne-slangroom-editor/dyne-slangroom-editor"; +export { SlangroomPreset } from "./components/dyne-slangroom-preset-loader/dyne-slangroom-preset-loader"; export namespace Components { interface DyneButton { /** @@ -44,6 +46,19 @@ export namespace Components { "keys": string; "keysLocalStorageKey": string | undefined; "keysMode": 'none' | 'editor' | 'localStorage'; + "setContent": (editor: EditorId, content: string) => Promise; + } + interface DyneSlangroomPreset { + "contract": string; + "data": string; + "description": string; + "getPreset": () => Promise; + "group": string; + "keys": string; + "name": string; + } + interface DyneSlangroomPresetLoader { + "editorId": string; } } declare global { @@ -71,11 +86,25 @@ declare global { prototype: HTMLDyneSlangroomEditorElement; new (): HTMLDyneSlangroomEditorElement; }; + interface HTMLDyneSlangroomPresetElement extends Components.DyneSlangroomPreset, HTMLStencilElement { + } + var HTMLDyneSlangroomPresetElement: { + prototype: HTMLDyneSlangroomPresetElement; + new (): HTMLDyneSlangroomPresetElement; + }; + interface HTMLDyneSlangroomPresetLoaderElement extends Components.DyneSlangroomPresetLoader, HTMLStencilElement { + } + var HTMLDyneSlangroomPresetLoaderElement: { + prototype: HTMLDyneSlangroomPresetLoaderElement; + new (): HTMLDyneSlangroomPresetLoaderElement; + }; interface HTMLElementTagNameMap { "dyne-button": HTMLDyneButtonElement; "dyne-code-editor": HTMLDyneCodeEditorElement; "dyne-inline": HTMLDyneInlineElement; "dyne-slangroom-editor": HTMLDyneSlangroomEditorElement; + "dyne-slangroom-preset": HTMLDyneSlangroomPresetElement; + "dyne-slangroom-preset-loader": HTMLDyneSlangroomPresetLoaderElement; } } declare namespace LocalJSX { @@ -109,11 +138,24 @@ declare namespace LocalJSX { "keysLocalStorageKey"?: string | undefined; "keysMode"?: 'none' | 'editor' | 'localStorage'; } + interface DyneSlangroomPreset { + "contract"?: string; + "data"?: string; + "description"?: string; + "group"?: string; + "keys"?: string; + "name"?: string; + } + interface DyneSlangroomPresetLoader { + "editorId"?: string; + } interface IntrinsicElements { "dyne-button": DyneButton; "dyne-code-editor": DyneCodeEditor; "dyne-inline": DyneInline; "dyne-slangroom-editor": DyneSlangroomEditor; + "dyne-slangroom-preset": DyneSlangroomPreset; + "dyne-slangroom-preset-loader": DyneSlangroomPresetLoader; } } export { LocalJSX as JSX }; @@ -124,6 +166,8 @@ declare module "@stencil/core" { "dyne-code-editor": LocalJSX.DyneCodeEditor & JSXBase.HTMLAttributes; "dyne-inline": LocalJSX.DyneInline & JSXBase.HTMLAttributes; "dyne-slangroom-editor": LocalJSX.DyneSlangroomEditor & JSXBase.HTMLAttributes; + "dyne-slangroom-preset": LocalJSX.DyneSlangroomPreset & JSXBase.HTMLAttributes; + "dyne-slangroom-preset-loader": LocalJSX.DyneSlangroomPresetLoader & JSXBase.HTMLAttributes; } } } diff --git a/src/components/dyne-button/readme.md b/src/components/dyne-button/readme.md index 6850702..b6b51ba 100644 --- a/src/components/dyne-button/readme.md +++ b/src/components/dyne-button/readme.md @@ -19,11 +19,13 @@ ### Used by - [dyne-slangroom-editor](../dyne-slangroom-editor) + - [dyne-slangroom-preset-loader](../dyne-slangroom-preset-loader) ### Graph ```mermaid graph TD; dyne-slangroom-editor --> dyne-button + dyne-slangroom-preset-loader --> dyne-button style dyne-button fill:#f9f,stroke:#333,stroke-width:4px ``` diff --git a/src/components/dyne-button/test/dyne-button.e2e.ts b/src/components/dyne-button/test/dyne-button.e2e.ts index 7b87131..01dbee0 100644 --- a/src/components/dyne-button/test/dyne-button.e2e.ts +++ b/src/components/dyne-button/test/dyne-button.e2e.ts @@ -7,9 +7,7 @@ test.describe('dyne-button', () => { await page.goto('/components/dyne-button/test/dyne-button.e2e.html'); // Rest of test - const component = await page.locator('dyne-button'); + const component = page.locator('dyne-button'); await expect(component).toHaveText(`ciao`); }); }); - - diff --git a/src/components/dyne-code-editor/readme.md b/src/components/dyne-code-editor/readme.md index f49fe05..3dc97c2 100644 --- a/src/components/dyne-code-editor/readme.md +++ b/src/components/dyne-code-editor/readme.md @@ -46,11 +46,13 @@ Type: `Promise` ### Used by - [dyne-slangroom-editor](../dyne-slangroom-editor) + - [dyne-slangroom-preset-loader](../dyne-slangroom-preset-loader) ### Graph ```mermaid graph TD; dyne-slangroom-editor --> dyne-code-editor + dyne-slangroom-preset-loader --> dyne-code-editor style dyne-code-editor fill:#f9f,stroke:#333,stroke-width:4px ``` diff --git a/src/components/dyne-slangroom-editor/dyne-slangroom-editor.tsx b/src/components/dyne-slangroom-editor/dyne-slangroom-editor.tsx index f61757a..b123362 100644 --- a/src/components/dyne-slangroom-editor/dyne-slangroom-editor.tsx +++ b/src/components/dyne-slangroom-editor/dyne-slangroom-editor.tsx @@ -1,4 +1,4 @@ -import { Component, Element, State, Prop, Method, h, Watch } from '@stencil/core'; +import { Component, Element, State, Prop, Method, h, Host } from '@stencil/core'; // import { dracula } from 'thememirror'; import { defaultKeymap } from '@codemirror/commands'; @@ -48,6 +48,16 @@ export class DyneSlangroomEditor { }; } + @Method() + async setContent(editor: EditorId, content: string): Promise { + try { + await this.getEditor(editor).setContent(content); + this.result = undefined; + } catch (e) { + console.warn(e); + } + } + // async componentDidLoad() { @@ -76,7 +86,6 @@ export class DyneSlangroomEditor { data: parseJsonObjectWithFallback(data), keys, }); - this.isExecuting = false; } @@ -140,54 +149,57 @@ export class DyneSlangroomEditor { render() { return ( -
- -
- - <dyne-button size="small" emphasis="high" onClick={() => this.executeContract()}> - Execute contract - </dyne-button> - </div> - </Container> - - <div class="flex sm:flex-col md:flex-row items-stretch gap-4"> - <Container className="md:grow md:w-0 shrink-0 md:basis-2"> - <div class="space-y-4"> - <Section title={EditorId.CONTRACT}> - <dyne-code-editor - name={EditorId.CONTRACT} - content={this.contract} - config={{ extensions: this.keyboardExtension }} - ></dyne-code-editor> - </Section> - - <Section title={EditorId.DATA}> - <dyne-code-editor - name={EditorId.DATA} - content={this.data} - config={{ extensions: [this.keyboardExtension, json()] }} - ></dyne-code-editor> - </Section> - - {this.keysMode == 'editor' && ( - <Section title={EditorId.KEYS}> + <Host> + <div class="space-y-4"> + <Container> + <div class="flex justify-between items-center"> + <Title name="Slangroom" /> + <div class="flex items-center gap-2"> + <slot name="topbar-right"></slot> + <dyne-button size="small" emphasis="high" onClick={() => this.executeContract()}> + Execute contract + </dyne-button> + </div> + </div> + </Container> + + <div class="flex sm:flex-col md:flex-row items-stretch gap-4"> + <Container className="md:grow md:w-0 shrink-0 md:basis-2"> + <div class="space-y-4"> + <Section title={EditorId.CONTRACT}> <dyne-code-editor - name={EditorId.KEYS} - content={this.keys} - config={{ extensions: [this.keyboardExtension, json()] }} + name={EditorId.CONTRACT} + config={{ doc: this.contract, extensions: this.keyboardExtension }} ></dyne-code-editor> </Section> - )} - </div> - </Container> - <Container className="md:grow md:w-0 shrink-0 md:basis-2"> - {this.showEmptyState && <EmptyState />} - {this.isExecuting && <Spinner />} - {this.result && <ResultRenderer result={this.result} />} - </Container> + <Section title={EditorId.DATA}> + <dyne-code-editor + name={EditorId.DATA} + config={{ doc: this.data, extensions: [this.keyboardExtension, json()] }} + ></dyne-code-editor> + </Section> + + {this.keysMode == 'editor' && ( + <Section title={EditorId.KEYS}> + <dyne-code-editor + name={EditorId.KEYS} + config={{ doc: this.keys, extensions: [this.keyboardExtension, json()] }} + ></dyne-code-editor> + </Section> + )} + </div> + </Container> + + <Container className="md:grow md:w-0 shrink-0 md:basis-2"> + {this.showEmptyState && <EmptyState />} + {this.isExecuting && <Spinner />} + {this.value && <ValueRenderer value={this.value} />} + {this.error && <ErrorRenderer error={this.error} />} + </Container> + </div> </div> - </div> + </Host> ); } } @@ -221,19 +233,13 @@ function parseJsonObjectWithFallback(string: string): Record<string, unknown> { // Partials -function ResultRenderer(props: { result: SlangroomResult }) { - const { result } = props; - if (result.success === true) return <ValueRenderer value={result.value} />; - else return <ErrorRenderer error={result.error} />; -} - function ValueRenderer(props: { value: SlangroomValue }) { return ( <Section title="Result"> <dyne-code-editor name={EditorId.RESULT} - content={JSON.stringify(props.value, null, 2)} config={{ + doc: JSON.stringify(props.value, null, 2), extensions: [json()], }} ></dyne-code-editor> @@ -253,9 +259,9 @@ function ErrorRenderer(props: { error: SlangroomError }) { } else { return ( <Section title="Error"> - <pre class="bg-red-50 text-red-800 rounded-lg border border-red-300 divide-red-300 p-4 gap-3 text-sm flex items-center"> + <p class="bg-red-50 text-red-800 rounded-lg border border-red-300 divide-red-300 p-4 gap-3 text-sm flex items-center"> {error} - </pre> + </p> </Section> ); } @@ -264,38 +270,37 @@ function ErrorRenderer(props: { error: SlangroomError }) { } } -// bg-slate-100 -> #F1F5F9 -// text-slate-800 -> #1E293B function AnsiRenderer(props: { text: string; className?: string }) { const { text, className = '' } = props; - const converter = new Convert({ bg: '#F1F5F9', fg: '#1E293B' }); + const converter = new Convert(); return <pre class={className} innerHTML={converter.toHtml(text)}></pre>; } function ZencodeErrorRenderer(props: { error: ZencodeRuntimeError }) { const { error } = props; return ( - <div class="space-y-4"> - <div> - <Title name="trace" className="mb-2" /> - <dyne-code-editor name="trace" content={error.trace.join('\n')}></dyne-code-editor> - </div> - - <div> - <Title name="logs" className="mb-2" /> - <dyne-code-editor name="logs" content={error.logs.join('\n')}></dyne-code-editor> - </div> - - <div> - <Title name="heap" className="mb-2" /> - <dyne-code-editor - name="heap" - content={JSON.stringify(error.heap, null, 2)} - config={{ - extensions: [json()], - }} - ></dyne-code-editor> - </div> + <div> + <Title name="trace" className="mb-1" /> + <dyne-code-editor + config={{ + doc: error.trace.join('\n'), + }} + ></dyne-code-editor> + + <Title name="logs" className="mb-1" /> + <dyne-code-editor + config={{ + doc: error.logs.join('\n'), + }} + ></dyne-code-editor> + + <Title name="heap" className="mb-1" /> + <dyne-code-editor + config={{ + doc: JSON.stringify(error.heap, null, 2), + extensions: [json()], + }} + ></dyne-code-editor> </div> ); } diff --git a/src/components/dyne-slangroom-editor/readme.md b/src/components/dyne-slangroom-editor/readme.md index 1c58d70..26289a4 100644 --- a/src/components/dyne-slangroom-editor/readme.md +++ b/src/components/dyne-slangroom-editor/readme.md @@ -26,6 +26,23 @@ Type: `Promise<SlangroomEditorContent>` +### `setContent(editor: EditorId, content: string) => Promise<void>` + + + +#### Parameters + +| Name | Type | Description | +| --------- | ---------- | ----------- | +| `editor` | `EditorId` | | +| `content` | `string` | | + +#### Returns + +Type: `Promise<void>` + + + ## Dependencies diff --git a/src/components/dyne-slangroom-editor/test/dyne-slangroom-editor.e2e.html b/src/components/dyne-slangroom-editor/test/dyne-slangroom-editor.e2e.html index 1425cdc..98eba59 100644 --- a/src/components/dyne-slangroom-editor/test/dyne-slangroom-editor.e2e.html +++ b/src/components/dyne-slangroom-editor/test/dyne-slangroom-editor.e2e.html @@ -8,6 +8,6 @@ <script src="../../../build/dyne-components.js" nomodule></script> </head> <body> - <dyne-slangroom-editor contract=``></dyne-slangroom-editor> + <dyne-slangroom-editor contract=""></dyne-slangroom-editor> </body> </html> diff --git a/src/components/dyne-slangroom-editor/test/dyne-slangroom-editor.e2e.ts b/src/components/dyne-slangroom-editor/test/dyne-slangroom-editor.e2e.ts index fc9ea6a..ad0153d 100644 --- a/src/components/dyne-slangroom-editor/test/dyne-slangroom-editor.e2e.ts +++ b/src/components/dyne-slangroom-editor/test/dyne-slangroom-editor.e2e.ts @@ -7,7 +7,7 @@ test.describe('dyne-slangroom-editor', () => { await page.goto('/components/dyne-slangroom-editor/test/dyne-slangroom-editor.e2e.html'); // Rest of test - const component = await page.locator('dyne-slangroom-editor'); - await expect(component).toHaveAttribute("contract"); + const component = page.locator('dyne-slangroom-editor'); + await expect(component).toHaveAttribute('contract'); }); }); diff --git a/src/components/dyne-slangroom-preset-loader/dyne-slangroom-preset-loader.scss b/src/components/dyne-slangroom-preset-loader/dyne-slangroom-preset-loader.scss new file mode 100644 index 0000000..5d4e87f --- /dev/null +++ b/src/components/dyne-slangroom-preset-loader/dyne-slangroom-preset-loader.scss @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/src/components/dyne-slangroom-preset-loader/dyne-slangroom-preset-loader.tsx b/src/components/dyne-slangroom-preset-loader/dyne-slangroom-preset-loader.tsx new file mode 100644 index 0000000..d7793c9 --- /dev/null +++ b/src/components/dyne-slangroom-preset-loader/dyne-slangroom-preset-loader.tsx @@ -0,0 +1,208 @@ +import { Component, Host, Prop, State, Element, Watch, h } from '@stencil/core'; +import SlangroomPresets from './utils/slangroom-presets.json'; +import { EditorId } from '../dyne-slangroom-editor/dyne-slangroom-editor'; +import { Array as A, pipe, Effect } from 'effect'; +import Fuse from 'fuse.js'; + +@Component({ + tag: 'dyne-slangroom-preset-loader', + styleUrl: 'dyne-slangroom-preset-loader.scss', + shadow: true, +}) +export class DyneSlangroomPresetLoader { + @Element() el: HTMLElement; + + @Prop({ reflect: true }) editorId: string; + + @State() presets: SlangroomPreset[] = SlangroomPresets; + + @State() filteredPresets: SlangroomPreset[] = this.presets; + @State() searchText = ''; + + get dialog() { + return this.el.shadowRoot?.querySelector('dialog'); + } + + get editor() { + return document.getElementById(this.editorId) as HTMLDyneSlangroomEditorElement; + } + + async componentDidLoad() { + await this.loadPresetsFromElements(); + lockScrollOnDialogOpen(this.dialog!); + } + + // Preset selection + + private onPresetSelect(preset: SlangroomPreset) { + this.loadPresetInEditor(preset); + this.dialog?.close(); + } + + private async loadPresetInEditor(preset: SlangroomPreset) { + await this.editor.setContent(EditorId.CONTRACT, preset.contract); + await this.editor.setContent(EditorId.DATA, preset.data); + await this.editor.setContent(EditorId.KEYS, preset.keys); + } + + // Load presets from dyne-slangroom-preset + + private async loadPresetsFromElements() { + const presets = await this.readPresetsFromElements(); + this.addPresets(presets); + } + + private readPresetsFromElements() { + return pipe( + Effect.succeed(this.el.querySelectorAll('dyne-slangroom-preset')), + Effect.map(presetElementNodeList => Array.from(presetElementNodeList)), + Effect.flatMap(presetElementArray => + pipe( + presetElementArray, + A.map(presetElement => presetElement.getPreset()), + A.map(presetPromise => Effect.promise(() => presetPromise)), + Effect.all, + ), + ), + Effect.runPromise, + ); + } + + private addPresets(presets: SlangroomPreset[]) { + this.presets = [...this.presets, ...presets]; + } + + @Watch('presets') + updatePresetsSearch() { + this.filteredPresets = this.presets; + } + + // Search + + private updateSearchText(e: Event) { + this.searchText = (e.target as any).value; + } + + @Watch('searchText') + filterPresets() { + this.filteredPresets = filterPresetsByText(this.presets, this.searchText); + } + + // Utils + + private setDialogEvents() { + this.dialog?.addEventListener('close', () => unlockScroll()); + this.dialog?.addEventListener('cancel', () => unlockScroll()); + this.dialog?.addEventListener('cancel', () => unlockScroll()); + } + + // + + render() { + return ( + <Host> + <dyne-button size="small" emphasis="m" onClick={() => this.dialog?.showModal()}> + Select preset + </dyne-button> + <dialog class="backdrop:bg-black backdrop:opacity-75 h-screen m-0"> + <div class="sticky top-0 bg-white"> + <div class="flex gap-4 justify-between items-center p-4 border-b "> + <p>Select a Slangroom preset</p> + <dyne-button size="small" emphasis="m" onClick={() => this.dialog?.close()}> + X + </dyne-button> + </div> + <div class="p-4 border-b"> + <input + class="block border w-full p-2 rounded-md hover:bg-slate-100 focus:bg-transparent" + name="search" + value={this.searchText} + placeholder="Search for a topic" + onInput={e => this.updateSearchText(e)} + ></input> + </div> + </div> + <PresetsSelect + presets={this.filteredPresets} + onPresetSelect={this.onPresetSelect.bind(this)} + ></PresetsSelect> + </dialog> + </Host> + ); + } +} + +export type SlangroomPreset = (typeof SlangroomPresets)[number]; + +type PresetsProps = { + onPresetSelect?: (preset: SlangroomPreset) => void; + presets?: SlangroomPreset[]; +}; + +function PresetsSelect(props: PresetsProps) { + const { onPresetSelect = () => {}, presets = [] } = props; + + const groupedPresets = pipe( + presets, + A.groupBy(p => p.group), + ); + + return ( + <div class="p-4 space-y-4"> + {Object.entries(groupedPresets).map(([groupName, groupContent]) => ( + <div> + <p class="uppercase text-xs font-semibold tracking-wide text-slate-600 mb-2"> + {groupName} + </p> + <ul class="space-y-1"> + {Object.entries(groupContent).map(([presetName, presetContent]) => ( + <li> + <button + class="capitalize p-2 w-full text-left rounded-md bg-slate-100 hover:bg-slate-300" + onClick={() => onPresetSelect(presetContent)} + > + {presetContent.meta.title ?? presetName} + </button> + </li> + ))} + </ul> + </div> + ))} + </div> + ); +} + +// + +function filterPresetsByText(presets: SlangroomPreset[], text: string): SlangroomPreset[] { + if (!Boolean(text)) return presets; + const fuse = new Fuse(presets, { + keys: ['name', 'group', 'meta.title'], + threshold: 0.4, + }); + return fuse.search(text).map(result => result.item); +} + +function lockScroll() { + document.body.style.overflow = 'hidden'; +} + +function unlockScroll() { + document.body.style.overflow = ''; +} + +function lockScrollOnDialogOpen(dialog: HTMLDialogElement) { + const observer = new MutationObserver(mutationsList => { + mutationsList + .filter(mutation => mutation.attributeName === 'open') + .forEach(() => { + if (dialog.open) { + lockScroll(); + } else { + unlockScroll(); + } + }); + }); + + observer.observe(dialog, { attributes: true }); +} diff --git a/src/components/dyne-slangroom-preset-loader/readme.md b/src/components/dyne-slangroom-preset-loader/readme.md new file mode 100644 index 0000000..7b48693 --- /dev/null +++ b/src/components/dyne-slangroom-preset-loader/readme.md @@ -0,0 +1,32 @@ +# dyne-slangroom-preset-loader + + + +<!-- Auto Generated Below --> + + +## Properties + +| Property | Attribute | Description | Type | Default | +| ---------- | ----------- | ----------- | -------- | ----------- | +| `editorId` | `editor-id` | | `string` | `undefined` | + + +## Dependencies + +### Depends on + +- [dyne-button](../dyne-button) +- [dyne-code-editor](../dyne-code-editor) + +### Graph +```mermaid +graph TD; + dyne-slangroom-preset-loader --> dyne-button + dyne-slangroom-preset-loader --> dyne-code-editor + style dyne-slangroom-preset-loader fill:#f9f,stroke:#333,stroke-width:4px +``` + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/src/components/dyne-slangroom-preset-loader/test/dyne-slangroom-preset-loader.e2e.html b/src/components/dyne-slangroom-preset-loader/test/dyne-slangroom-preset-loader.e2e.html new file mode 100644 index 0000000..921fe4c --- /dev/null +++ b/src/components/dyne-slangroom-preset-loader/test/dyne-slangroom-preset-loader.e2e.html @@ -0,0 +1,13 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf8" /> + + <!-- Replace with the path to your entrypoint --> + <script src="../../../build/dyne-components.esm.js" type="module"></script> + <script src="../../../build/dyne-components.js" nomodule></script> + </head> + <body> + <dyne-slangroom-preset-loader editor-id="ok"></dyne-slangroom-preset-loader> + </body> +</html> diff --git a/src/components/dyne-slangroom-preset-loader/test/dyne-slangroom-preset-loader.e2e.ts b/src/components/dyne-slangroom-preset-loader/test/dyne-slangroom-preset-loader.e2e.ts new file mode 100644 index 0000000..2bd5ad6 --- /dev/null +++ b/src/components/dyne-slangroom-preset-loader/test/dyne-slangroom-preset-loader.e2e.ts @@ -0,0 +1,13 @@ +import { test } from '@stencil/playwright'; +import { expect } from '@playwright/test'; + +test.describe('dyne-slangroom-preset-loader', () => { + test('renders', async ({ page }) => { + await page.goto( + '/components/dyne-slangroom-preset-loader/test/dyne-slangroom-preset-loader.e2e.html', + ); + + const element = page.locator('dyne-slangroom-preset-loader'); + await expect(element).toHaveAttribute('editor-id'); + }); +}); diff --git a/src/components/dyne-slangroom-preset-loader/utils/generate-preset-json.mjs b/src/components/dyne-slangroom-preset-loader/utils/generate-preset-json.mjs new file mode 100644 index 0000000..421bb0d --- /dev/null +++ b/src/components/dyne-slangroom-preset-loader/utils/generate-preset-json.mjs @@ -0,0 +1,152 @@ +import fs from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import path from 'node:path'; +import { glob } from 'glob'; +import { Array as A, pipe, Record as R, String as S, Option as O } from 'effect'; +import degit from 'degit'; + +// -- Config -- // + +const SLANGROOM_REPO = 'github:dyne/slangroom'; +const SLANGROOM_DIR = 'slangroom'; +const EXAMPLES_DIR = 'examples'; +const PRESETS_FILE = 'slangroom-presets.json'; +const BROWSER_LIB = 'pkg/browser/package.json'; + +// -- Instructions -- // + +await cloneRepo(SLANGROOM_REPO, getTempSlangroomPath()); + +const browserModules = getSlangroomBrowserModules(); +pipe( + await getExamplesFilesPaths(browserModules), + processAndParseExamplesPaths, + serialize, + writePresetFile, +); + +deleteFolder(getTempSlangroomPath()); + +// -- Functions -- // + +/** + * + * @param {string[]} paths + * @returns + */ +function processAndParseExamplesPaths(paths) { + return pipe( + paths, + + A.filter(p => fs.lstatSync(p).isFile()), + A.groupBy(p => path.basename(p).split('.').at(0)), + + R.map((paths, key) => ({ + name: key, + contract: paths.find(S.includes('.slang')), + keys: paths.find(S.includes('.keys.')), + data: paths.find(S.includes('.data.')), + meta: paths.find(S.includes('.meta.')), + })), + + R.map(contractData => ({ + ...contractData, + group: path.dirname(contractData.contract).split('/').at(-1), + })), + + R.map(contractData => ({ + ...contractData, + contract: readFileAsString(contractData.contract), + keys: readFileAsString(contractData.keys), + data: readFileAsString(contractData.data), + meta: JSON.parse(readFileAsString(contractData.meta)), + })), + + R.toEntries, + A.map(A.get(1)), + A.map(O.getOrThrow), + ); +} + +/** @param {string[]} folders */ +function getExamplesFilesPaths(folders = []) { + const f = folders.length === 0 ? '**' : `{${folders.join(',')}}`; + return glob(path.join(getTempSlangroomPath(), EXAMPLES_DIR, f, '*')); +} + +/** @param {string} data */ +function writePresetFile(data) { + return fs.writeFileSync(getPresetFilePath(), data); +} + +function getSlangroomBrowserModules() { + return pipe( + getSlangroomBrowserModulePackageJson(), + packageJson => packageJson.dependencies, + R.toEntries, + A.map(A.get(0)), + A.map(O.map(S.replace('@slangroom/', ''))), + A.map(O.getOrThrow), + ); +} + +/** @typedef {Object.<string, string>} StringRecord */ +/** @returns {{dependencies: StringRecord}} browserLibPackageJson */ +function getSlangroomBrowserModulePackageJson() { + return pipe(getBrowserLibFilePath(), readFileAsString, JSON.parse); +} + +// -- Utils: fs, cloning -- // + +/** + * @param {string} repo + * @param {string} dest + */ +function cloneRepo(repo, dest) { + return new Promise((resolve, reject) => { + const emitter = degit(repo, { + cache: true, + force: true, + verbose: true, + }); + + emitter.clone(dest).then(() => { + resolve(); + }); + }); +} + +/** @param {string} path */ +function readFileAsString(path) { + return fs.readFileSync(path).toString(); +} + +/** @param {string} data */ +function serialize(data) { + return JSON.stringify(data, null, 4); +} + +/** @param {string} dir */ +function deleteFolder(dir) { + fs.rmSync(dir, { recursive: true, force: true }); +} + +// -- Paths -- // + +function cwd() { + const __filename = fileURLToPath(import.meta.url); + const __dirname = path.dirname(__filename); + return __dirname; +} + +function getTempSlangroomPath() { + return path.join(cwd(), SLANGROOM_DIR); +} + +function getPresetFilePath() { + return path.join(cwd(), PRESETS_FILE); +} + +function getBrowserLibFilePath() { + return path.join(getTempSlangroomPath(), BROWSER_LIB); +} diff --git a/src/components/dyne-slangroom-preset-loader/utils/slangroom-presets.json b/src/components/dyne-slangroom-preset-loader/utils/slangroom-presets.json new file mode 100644 index 0000000..172da2a --- /dev/null +++ b/src/components/dyne-slangroom-preset-loader/utils/slangroom-presets.json @@ -0,0 +1,233 @@ +[ + { + "name": "post_with_headers", + "contract": "Rule unknown ignore\nGiven I connect to 'address' and send object 'body' and send headers 'headers' and do post and output into 'result'\nGiven I have a 'string dictionary' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"address\": \"https://dyne.org/slangroom\"\n}\n", + "data": "{\n\t\"body\": {\n\t\t\"hello\": \"world\"\n\t},\n\t\"headers\": {\n\t\t\"Content-Type\": \"application/json\"\n\t}\n}\n", + "meta": { + "title": "http post with header", + "highlight": "2" + }, + "group": "http" + }, + { + "name": "post", + "contract": "Rule unknown ignore\nGiven I connect to 'address' and send object 'body' and do post and output into 'result'\nGiven I have a 'string dictionary' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"address\": \"https://dyne.org/slangroom\"\n}\n", + "data": "{\n\t\"body\": {\n\t\t\"hello\": \"world\"\n\t}\n}\n", + "meta": { + "title": "http post", + "highlight": "2" + }, + "group": "http" + }, + { + "name": "get_with_headers", + "contract": "Rule unknown ignore\nGiven I connect to 'address' and send headers 'headers' and do get and output into 'result'\nGiven I have a 'string dictionary' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"address\": \"https://dyne.org/slangroom\"\n}\n", + "data": "{\n\t\"headers\": {\n\t\t\"Content-Type\": \"application/json\"\n\t}\n}\n", + "meta": { + "title": "http get with headers", + "highlight": "2" + }, + "group": "http" + }, + { + "name": "get", + "contract": "Rule unknown ignore\nGiven I connect to 'address' and do get and output into 'result'\nGiven I have a 'string dictionary' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"secret\": \"foo\"\n}\n", + "data": "{\n\t\"address\": \"https://dyne.org/slangroom\"\n}\n", + "meta": { + "title": "http get", + "highlight": "2" + }, + "group": "http" + }, + { + "name": "set", + "contract": "Rule unknown ignore\n\nGiven I send object 'object' and send path 'path' and send value 'value' and manipulate and set\n\nGiven I have a 'string dictionary' named 'object'\nThen print 'mimmo'\n", + "keys": "{\n\t\"path\": \"root.element\"\n}\n", + "data": "{\n\t\"value\": { \"name\": \"Jhon\" },\n\t\"object\": {\n\t\t\"surname\": \"Doe\"\n\t}\n}\n", + "meta": { + "title": "manipulate and set", + "highlight": "3" + }, + "group": "helpers" + }, + { + "name": "pick", + "contract": "Rule unknown ignore\n\nGiven I send object 'object' and send properties 'properties' and manipulate and pick and output into 'result'\n\nGiven I have a 'string dictionary' named 'result'\nThen print the data\n", + "keys": "{\n\t\"properties\": [\n\t\t\"name\",\n\t\t\"personal_information.email.first\"\n\t]\n}\n", + "data": "{\n\t\"object\": {\n\t\t\"name\": \"Jhon\",\n\t\t\"personal_information\": {\n\t\t\t\"email\": {\n\t\t\t\t\"frist\": \"example@example.org\",\n\t\t\t\t\"second\": \"email@example.org\"\n\t\t\t},\n\t\t\t\"phone\": \"3338957823\"\n\t\t}\n\t}\n}\n", + "meta": { + "title": "manipulate and pick", + "highlight": "3" + }, + "group": "helpers" + }, + { + "name": "omit", + "contract": "Rule unknown ignore\n\nGiven I send object 'object' and send paths 'paths' and manipulate and omit and output into 'result'\n\nGiven I have a 'string dictionary' named 'result'\nThen print the data\n", + "keys": "{\n\t\"path\": [\n\t\t\"names.third\",\n\t\t\"surnames.second\"\n\t]\n}\n", + "data": "{\n\t\"object\": {\n\t\t\"names\": {\n\t\t\t\"first\": \"Bella\",\n\t\t\t\"third\": \"Owen\"\n\t\t},\n\t\t\"surnames\": {\n\t\t\t\"first\": \"Allen\",\n\t\t\t\"second\": \"Briggs\"\n\t\t}\n\t}\n}\n", + "meta": { + "title": "manipulate and omit", + "highlight": "3" + }, + "group": "helpers" + }, + { + "name": "merge", + "contract": "Rule unknown ignore\n\nGiven I send object 'object' and send sources 'sources' and manipulate and merge and output into 'result'\n\nGiven I have a 'string dictionary' named 'result'\nThen print the data\n", + "keys": "{\n\t\"sources\": [\n\t\t{\n\t\t\t\"names\": {\n\t\t\t\t\"second\": \"Jhon\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"surnames\": {\n\t\t\t\t\"third\": \"Doe\"\n\t\t\t}\n\t\t}\n\t]\n}\n", + "data": "{\n\t\"object\": {\n\t\t\"names\": {\n\t\t\t\"first\": \"Bella\",\n\t\t\t\"third\": \"Owen\"\n\t\t},\n\t\t\"surnames\": {\n\t\t\t\"first\": \"Allen\",\n\t\t\t\"second\": \"Briggs\"\n\t\t}\n\t}\n}\n", + "meta": { + "title": "manipulate and merge", + "highlight": "3" + }, + "group": "helpers" + }, + { + "name": "concat", + "contract": "Rule unknown ignore\n\nGiven I send array 'array' and send values 'values' and manipulate and concat and output into 'result'\n\nGiven I have a 'string array' named 'result'\nThen print the data\n", + "keys": "{\n\t\"values\": [\n\t\t\"third\",\n\t\t\"foruth\",\n\t\t\"fifth\"\n\t]\n}\n", + "data": "{\n \"array\": [\n\t\t\"first\",\n\t\t\"second\"\n\t]\n}\n", + "meta": { + "title": "manipulate and concat", + "highlight": "3" + }, + "group": "helpers" + }, + { + "name": "compact", + "contract": "Rule unknown ignore\n\nGiven I send array 'array' and manipulate and compact and output into 'result'\n\nGiven I have a 'string array' named 'result'\nThen print the data\n", + "keys": "{}\n", + "data": "{\n\t\"the_array\": [\n\t\t0,\n\t\t\"c\",\n\t\tfalse,\n\t\t\"d\",\n\t\t\"\"\n\t]\n}\n", + "meta": { + "title": "manipulate and compact", + "highlight": "3" + }, + "group": "helpers" + }, + { + "name": "validate", + "contract": "Rule unknown ignore\n\nGiven I send json_data 'json_data' and send json_schema 'json_schema' and validate json and output into 'result'\n\nGiven I have a 'string dictionary' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"json_schema\": {\n\t\t\"type\": \"object\",\n\t\t\"properties\": {\n\t\t\t\"first_name\": {\n\t\t\t\t\"type\": \"string\"\n\t\t\t},\n\t\t\t\"last_name\": {\n\t\t\t\t\"type\": \"string\"\n\t\t\t}\n\t\t},\n\t\t\"required\": [\n\t\t\t\"first_name\",\n\t\t\t\"last_name\"\n\t\t]\n\t}\n}\n", + "data": "{\n \"json_data\": {\n \"first_name\": \"Jhon\",\n \"last_name\": \"Doe\"\n }\n}\n", + "meta": { + "title": "validate json", + "highlight": "3" + }, + "group": "json-schema" + }, + { + "name": "qr_code", + "contract": "Rule unknown ignore\n\nGiven I send text 'text' and create qr code and output into 'result'\n\nGiven I have a 'string' named 'result'\nThen print the 'result'\n", + "keys": "{}\n", + "data": "{\n \"text\": \"Hello World!\"\n}\n", + "meta": { + "title": "create qr code", + "highlight": "3" + }, + "group": "qrcode" + }, + { + "name": "update_record", + "contract": "Rule unknown ignore\n\nGiven I connect to 'pb_address' and start pb client\nGiven I send my_credentials 'my_credentials' and login\n\nGiven I send update_parameters 'update_parameters' and send record_parameters 'record_parameters' and update record and output into 'result'\n\nGiven I have a 'string dictionary' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"pb_address\": \"http://127.0.0.1:8090\",\n\t\"my_credentials\": {\n\t\t\"email\": \"test@test.eu\",\n\t\t\"password\": \"testtest\"\n\t}\n}\n", + "data": "{\n\t\"update_parameters\": {\n\t\t\"id\": \"q3vijjsacrn32tk\",\n\t\t\"collection\": \"organizations\",\n\t\t\"record\": {\n\t\t\t\"name\": \"new value for name\"\n\t\t}\n\t},\n\t\"record_parameters\": {\n\t\t\"fields\": \"id, name\"\n\t}\n}\n", + "meta": { + "title": "update a record", + "highlight": "6" + }, + "group": "pocketbase" + }, + { + "name": "start_pb", + "contract": "Rule unknown ignore\n\nGiven I connect to 'pb_address' and start pb client and output into 'result'\n# for mobile contracts use instead\n# Given I connect to 'pb_address' and start capacitor pb client and output into 'result'\n\nGiven I have a 'string' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"pb_address\": \"http://127.0.0.1:8090\"\n}\n", + "data": "{}\n", + "meta": { + "title": "start pb client", + "highlight": "3" + }, + "group": "pocketbase" + }, + { + "name": "send_request", + "contract": "Rule unknown ignore\n\nGiven I connect to 'pb_address' and start pb client\n\nGiven I send url 'url' and send send_parameters 'send_parameters' and send request and output into 'result'\n\nGiven I have a 'string dictionary' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"pb_address\": \"http://127.0.0.1:8090\"\n}\n", + "data": "{\n\t\"url\": \"/api/hello/user\",\n\t\"send_parameters\": {}\n}\n", + "meta": { + "title": "send request", + "highlight": "5" + }, + "group": "pocketbase" + }, + { + "name": "pw_reset", + "contract": "Rule unknown ignore\n\nGiven I connect to 'pb_address' and start pb client\nGiven I send my_credentials 'my_credentials' and login\n\nGiven I send email 'email' and ask password reset and output into 'result'\n\nGiven I have a 'string dictionary' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"pb_address\": \"http://127.0.0.1:8090\",\n\t\"my_credentials\": {\n\t\t\"email\": \"test@test.eu\",\n\t\t\"password\": \"testtest\"\n\t}\n}\n", + "data": "{\n\t\"email\": \"test@test.eu\"\n}\n", + "meta": { + "title": "password reset", + "highlight": "6" + }, + "group": "pocketbase" + }, + { + "name": "login", + "contract": "Rule unknown ignore\n\nGiven I connect to 'pb_address' and start pb client\n\nGiven I send my_credentials 'my_credentials' and login and output into 'result'\n\nGiven I have a 'string' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"pb_address\": \"http://127.0.0.1:8090\"\n}\n", + "data": "{\n\t\"my_credentials\": {\n\t\t\"email\": \"test@test.eu\",\n\t\t\"password\": \"testtest\"\n\t}\n}\n", + "meta": { + "title": "login", + "highlight": "5" + }, + "group": "pocketbase" + }, + { + "name": "get_some_records", + "contract": "Rule unknown ignore\n\nGiven I connect to 'pb_address' and start pb client\n\nGiven I send list_parameters 'list_parameters' and get some records and output into 'result'\n\nGiven I have a 'string dictionary' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"pb_address\": \"http://127.0.0.1:8090\"\n}\n", + "data": "{\n\t\"list_parameters\": {\n\t\t\"type\": \"list\",\n\t\t\"pagination\": {\n\t\t\t\"page\": 2,\n\t\t\t\"perPage\": 20\n\t\t},\n\t\t\"collection\": \"organizations\"\n\t}\n}\n", + "meta": { + "title": "get some records", + "highlight": "5" + }, + "group": "pocketbase" + }, + { + "name": "get_one_record", + "contract": "Rule unknown ignore\n\nGiven I connect to 'pb_address' and start pb client\n\nGiven I send show_parameters 'show_parameters' and get one record and output into 'result'\n\nGiven I have a 'string dictionary' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"pb_address\": \"http://127.0.0.1:8090\"\n}\n", + "data": "{\n\t\"show_parameters\": {\n\t\t\"collection\": \"organizations\",\n\t\t\"id\": \"p7viyzsihrn52uj\",\n\t\t\"fields\": \"name\"\n\t}\n}\n", + "meta": { + "title": "get one record", + "highlight": "5" + }, + "group": "pocketbase" + }, + { + "name": "delete_record", + "contract": "Rule unknown ignore\n\nGiven I connect to 'pb_address' and start pb client\nGiven I send my_credentials 'my_credentials' and login\n\nGiven I send delete_parameters 'delete_parameters' and delete record and output into 'result'\n\nGiven I have a 'string' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"pb_address\": \"http://127.0.0.1:8090\",\n\t\"my_credentials\": {\n\t\t\"email\": \"test@test.eu\",\n\t\t\"password\": \"testtest\"\n\t}\n}\n", + "data": "{\n\t\"delete_parameters\": {\n\t\t\"collection\": \"organizations\",\n\t\t\"id\": \"q3vijjsacrn32tk\"\n\t}\n}\n", + "meta": { + "title": "delete a record", + "highlight": "6" + }, + "group": "pocketbase" + }, + { + "name": "create_record", + "contract": "Rule unknown ignore\n\nGiven I connect to 'pb_address' and start pb client\nGiven I send my_credentials 'my_credentials' and login\n\nGiven I send create_parameters 'create_parameters' and send record_parameters 'record_parameters' and create record and output into 'result'\n\nGiven I have a 'string dictionary' named 'result'\nThen print the 'result'\n", + "keys": "{\n\t\"pb_address\": \"http://127.0.0.1:8090\",\n\t\"my_credentials\": {\n\t\t\"email\": \"test@test.eu\",\n\t\t\"password\": \"testtest\"\n\t}\n}\n", + "data": "{\n\t\"create_parameters\": {\n\t\t\"collection\": \"organizations\",\n\t\t\"record\": {\n\t\t\t\"name\": \"Jhon org\"\n\t\t}\n\t},\n\t\"record_parameters\": {\n\t\t\"requestKey\": \"testCreate\"\n\t}\n}\n", + "meta": { + "title": "create a record", + "highlight": "6" + }, + "group": "pocketbase" + } +] \ No newline at end of file diff --git a/src/components/dyne-slangroom-preset/dyne-slangroom-preset.scss b/src/components/dyne-slangroom-preset/dyne-slangroom-preset.scss new file mode 100644 index 0000000..5d4e87f --- /dev/null +++ b/src/components/dyne-slangroom-preset/dyne-slangroom-preset.scss @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/src/components/dyne-slangroom-preset/dyne-slangroom-preset.tsx b/src/components/dyne-slangroom-preset/dyne-slangroom-preset.tsx new file mode 100644 index 0000000..bd947fc --- /dev/null +++ b/src/components/dyne-slangroom-preset/dyne-slangroom-preset.tsx @@ -0,0 +1,32 @@ +import { Component, Host, Prop, Method, h } from '@stencil/core'; +import { SlangroomPreset } from '../dyne-slangroom-preset-loader/dyne-slangroom-preset-loader'; + +@Component({ + tag: 'dyne-slangroom-preset', + styleUrl: 'dyne-slangroom-preset.scss', + shadow: true, +}) +export class DyneSlangroomPreset { + @Prop({ reflect: true }) contract = ''; + @Prop({ reflect: true }) data = ''; + @Prop({ reflect: true }) keys = ''; + @Prop({ reflect: true }) name = ''; + @Prop({ reflect: true }) description = ''; + @Prop({ reflect: true }) group = ''; + + @Method() + async getPreset(): Promise<SlangroomPreset> { + return { + contract: this.contract, + data: this.data, + keys: this.keys, + name: this.name, + group: this.group, + meta: { title: this.name, highlight: '1' }, + }; + } + + render() { + return <Host></Host>; + } +} diff --git a/src/components/dyne-slangroom-preset/readme.md b/src/components/dyne-slangroom-preset/readme.md new file mode 100644 index 0000000..e7bcae9 --- /dev/null +++ b/src/components/dyne-slangroom-preset/readme.md @@ -0,0 +1,22 @@ +# dyne-slangroom-preset + + + +<!-- Auto Generated Below --> + + +## Properties + +| Property | Attribute | Description | Type | Default | +| ------------- | ------------- | ----------- | -------- | ------- | +| `contract` | `contract` | | `string` | `''` | +| `data` | `data` | | `string` | `''` | +| `description` | `description` | | `string` | `''` | +| `group` | `group` | | `string` | `''` | +| `keys` | `keys` | | `string` | `''` | +| `name` | `name` | | `string` | `''` | + + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/src/components/dyne-slangroom-preset/test/dyne-slangroom-preset.e2e.html b/src/components/dyne-slangroom-preset/test/dyne-slangroom-preset.e2e.html new file mode 100644 index 0000000..b9bcb3b --- /dev/null +++ b/src/components/dyne-slangroom-preset/test/dyne-slangroom-preset.e2e.html @@ -0,0 +1,13 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf8" /> + + <!-- Replace with the path to your entrypoint --> + <script src="../../../build/dyne-components.esm.js" type="module"></script> + <script src="../../../build/dyne-components.js" nomodule></script> + </head> + <body> + <dyne-slangroom-preset contract="Rule unkown ignore"></dyne-slangroom-preset> + </body> +</html> diff --git a/src/components/dyne-slangroom-preset/test/dyne-slangroom-preset.e2e.ts b/src/components/dyne-slangroom-preset/test/dyne-slangroom-preset.e2e.ts new file mode 100644 index 0000000..dd66880 --- /dev/null +++ b/src/components/dyne-slangroom-preset/test/dyne-slangroom-preset.e2e.ts @@ -0,0 +1,11 @@ +import { test } from '@stencil/playwright'; +import { expect } from '@playwright/test'; + +test.describe('dyne-slangroom-preset', () => { + test('renders', async ({ page }) => { + await page.goto('/components/dyne-slangroom-preset/test/dyne-slangroom-preset.e2e.html'); + + const element = page.locator('dyne-slangroom-preset'); + await expect(element).toHaveAttribute('contract'); + }); +}); diff --git a/src/index.html b/src/index.html index 1cd6940..17ca522 100644 --- a/src/index.html +++ b/src/index.html @@ -15,13 +15,28 @@ body { background-color: var(--md-sys-color-surface-container); } + + .component-title { + color: white; + font-weight: bolder; + font-size: larger; + margin-bottom: 32px; + } + + .component-container { + padding: 32px; + border: 1px solid gray; + margin-bottom: 32px; + background-color: black; + } </style> </head> <body class="p-8"> - <div class="p-8 bg-slate-900 border border-slate-700 mb-8"> - <h1 class="text-xl pb-8 font-extrabold text-white">Slangroom editor</h1> + <div class="component-container"> + <h1 class="component-title">Slangroom editor</h1> <dyne-slangroom-editor + id="slangroom-editor" contract="Rule unknown ignore Given I connect to 'did_url' and do get and output into 'did' Given I have a 'string dictionary' named 'did' @@ -31,22 +46,31 @@ <h1 class="text-xl pb-8 font-extrabold text-white">Slangroom editor</h1> "foo": "bar", "did_url": "https://did.dyne.org/dids/did:dyne:sandbox.test:pEn78CGNEKvMR7DJQ1yvUVUpAHKzsBz45mQw3zD2js9" }' - ></dyne-slangroom-editor> + > + <dyne-slangroom-preset-loader slot="topbar-right" editor-id="slangroom-editor"> + <dyne-slangroom-preset + group="helpers" + name="Preset Element Test" + contract="Test" + data="Test" + ></dyne-slangroom-preset> + </dyne-slangroom-preset-loader> + </dyne-slangroom-editor> <!-- <dyne-slangroom-editor></dyne-slangroom-editor> --> </div> - <div class="p-8 bg-slate-900 border border-slate-700 mb-8"> - <h1 class="text-xl pb-8 font-extrabold text-white">Code editor</h1> + <div class="component-container"> + <h1 class="component-title">Code editor</h1> <dyne-code-editor></dyne-code-editor> </div> - <div class="p-8 bg-slate-900 border border-slate-700 mb-8"> - <h1 class="text-xl pb-8 font-extrabold text-white">Buttons</h1> + <div class="component-container"> + <h1 class="component-title">Buttons</h1> <div class="grid grid-cols-3 gap-4" id="buttons"></div> </div> - <div class="p-8 bg-slate-900 border border-slate-700 mb-8"> - <h1 class="text-xl pb-8 font-extrabold text-white">Inline</h1> + <div class="component-container"> + <h1 class="component-title">Inline</h1> <dyne-inline> <dyne-button>Click me</dyne-button> <dyne-button>Trust me</dyne-button> diff --git a/stencil.config.ts b/stencil.config.ts index 917b5c4..250663f 100644 --- a/stencil.config.ts +++ b/stencil.config.ts @@ -1,7 +1,11 @@ import { Config } from '@stencil/core'; import { sass } from '@stencil/sass'; import nodePolyfills from 'rollup-plugin-node-polyfills'; -import tailwind, { PluginOpts, setPluginConfigurationDefaults, tailwindHMR } from 'stencil-tailwind-plugin'; +import tailwind, { + PluginOpts, + setPluginConfigurationDefaults, + tailwindHMR, +} from 'stencil-tailwind-plugin'; import tailwindConf from './tailwind.config.ts'; setPluginConfigurationDefaults({ diff --git a/test-results/.last-run.json b/test-results/.last-run.json new file mode 100644 index 0000000..cbcc1fb --- /dev/null +++ b/test-results/.last-run.json @@ -0,0 +1,4 @@ +{ + "status": "passed", + "failedTests": [] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 7d109c4..fb7dd81 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,7 +17,8 @@ "baseUrl": ".", "paths": { "@/*": ["./*"] - } + }, + "resolveJsonModule": true }, "include": ["src"], "exclude": ["node_modules"] diff --git a/vscode-data.json b/vscode-data.json index 88c2803..f066f68 100644 --- a/vscode-data.json +++ b/vscode-data.json @@ -133,6 +133,52 @@ ] } ] + }, + { + "name": "dyne-slangroom-preset", + "description": { + "kind": "markdown", + "value": "" + }, + "attributes": [ + { + "name": "contract", + "description": "" + }, + { + "name": "data", + "description": "" + }, + { + "name": "description", + "description": "" + }, + { + "name": "group", + "description": "" + }, + { + "name": "keys", + "description": "" + }, + { + "name": "name", + "description": "" + } + ] + }, + { + "name": "dyne-slangroom-preset-loader", + "description": { + "kind": "markdown", + "value": "" + }, + "attributes": [ + { + "name": "editor-id", + "description": "" + } + ] } ] } \ No newline at end of file