diff --git a/.gitignore b/.gitignore index 21f8339..64bf9a8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ out .env extension.js extension.js.LICENSE.txt - \ No newline at end of file +local/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..cd38a8b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog + +## Unreleased + +- Fixed presentation2 overflow scaling so long text wraps across the full slide width. +- Fixed native tables in presentation2 to use the slide width, inherit the active theme, render complete borders, and hide their duplicate source outline. +- Fixed presentation2 title detection and hidden-block handling after filtering hidden slide children. +- Added a bounded overflow fallback for presentation2 slides that cannot fit at the minimum scale. +- Kept image and iframe source descendants closed while preserving expanded native media layouts. diff --git a/README.md b/README.md index da8279f..0382595 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,14 @@ Type `{{presentation}}` or `{{slides}}` in a block. Clicking the button will overlay a presentation directly from Roam! Exit the presentation by hitting 'ESC'. +An experimental native-renderer path is available alongside the current +renderer. Use `{{presentation2}}` or `{{slides2}}` to render slide content with +Roam's declarative React APIs while leaving `presentation` and `slides` +unchanged. + + To specify what content is part of the presentation, create a child block for each slide. The text of each child will serve as the slide title. Each child block then in turn renders its children as the slide contents in a bulleted outline. For example, the Playground presentation below uses the following structure: ``` diff --git a/package-lock.json b/package-lock.json index ad856ab..4ee9c23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "reveal.js": "^4.3.0", - "roamjs-components": "^0.82.0" + "roamjs-components": "^0.88.4" } }, "node_modules/@alloc/quick-lru": { @@ -3287,6 +3287,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "peer": true, "engines": { "node": ">= 0.4" }, @@ -3294,74 +3295,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/aws-sdk": { - "version": "2.1234.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1234.0.tgz", - "integrity": "sha512-QFuSeYM8DPiXytspLnWToy4MWJPGYFCgAy4hi+lRd6ueJtCey7MBIgFNHW814uAJzKUDEdJUJZPvDZvtLM1d/Q==", - "dependencies": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.16.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "util": "^0.12.4", - "uuid": "8.0.0", - "xml2js": "0.4.19" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/aws-sdk-plus": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/aws-sdk-plus/-/aws-sdk-plus-0.5.3.tgz", - "integrity": "sha512-C/I1sWXAA5gRh5G4XbqnnVTGfzKimXJVkgBl62rt4SUAjOyakMICvSG/MaS4xzS+6umiVgKH8liWsNmiSueXXA==", - "dependencies": { - "aws-sdk": "^2.1004.0", - "react": "^17.0.2", - "react-dom": "^17.0.2" - } - }, - "node_modules/aws-sdk/node_modules/events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/aws-sdk/node_modules/sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" - }, - "node_modules/aws-sdk/node_modules/uuid": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", - "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/aws-sdk/node_modules/xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "node_modules/aws-sdk/node_modules/xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/axios": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", @@ -3395,7 +3328,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "peer": true }, "node_modules/binary-extensions": { "version": "2.2.0", @@ -3483,16 +3417,6 @@ "node": ">=8" } }, - "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -3532,6 +3456,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "peer": true, "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -4382,6 +4307,7 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "peer": true, "dependencies": { "is-callable": "^1.1.3" } @@ -4457,7 +4383,8 @@ "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "peer": true }, "node_modules/functions-have-names": { "version": "1.2.3", @@ -4489,6 +4416,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "peer": true, "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -4535,6 +4463,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "peer": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -4558,6 +4487,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "peer": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -4599,6 +4529,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "peer": true, "engines": { "node": ">= 0.4" }, @@ -4610,6 +4541,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "peer": true, "engines": { "node": ">= 0.4" }, @@ -4621,6 +4553,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "peer": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -4776,7 +4709,8 @@ "node_modules/ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "peer": true }, "node_modules/immediate": { "version": "3.0.6", @@ -4797,7 +4731,8 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "peer": true }, "node_modules/insect": { "version": "5.8.2", @@ -10959,6 +10894,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "peer": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -11033,6 +10969,7 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "peer": true, "engines": { "node": ">= 0.4" }, @@ -11121,20 +11058,6 @@ "node": ">=8" } }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -11266,6 +11189,7 @@ "version": "1.1.10", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "peer": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -11317,7 +11241,8 @@ "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "peer": true }, "node_modules/isexe": { "version": "2.0.0", @@ -11370,18 +11295,11 @@ "jiti": "bin/jiti.js" } }, - "node_modules/jmespath": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", - "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true }, "node_modules/jsdom": { "version": "20.0.3", @@ -11552,6 +11470,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -11731,6 +11650,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -12337,15 +12257,6 @@ "node": ">=6" } }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -12376,6 +12287,7 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -12400,6 +12312,7 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -12629,13 +12542,13 @@ } }, "node_modules/roamjs-components": { - "version": "0.82.0", - "resolved": "https://registry.npmjs.org/roamjs-components/-/roamjs-components-0.82.0.tgz", - "integrity": "sha512-iyv1nSQ4tHXiO3FsOZWg3Iwe86Or3vdDpNkARjnnaVgnoOamc8xmbhTa4yVtpkDWQxXcL9aAulo9uKlj1O6SBw==", + "version": "0.88.4", + "resolved": "https://registry.npmjs.org/roamjs-components/-/roamjs-components-0.88.4.tgz", + "integrity": "sha512-yMaIvZt6OTLhl87IEKF/IQcIRgeaT56nauYVtgDsjBs85wWUmskx8W++VEjdJaH1QN8pDEz7UOVI1aRCZQw1Rw==", "hasInstallScript": true, + "license": "MIT", "dependencies": { "@samepage/scripts": "^0.74.2", - "aws-sdk-plus": "^0.5.3", "color": "^4.0.1", "date-fns": "^2.27.0", "edn-data": "^1.0.0", @@ -12732,6 +12645,7 @@ "version": "0.20.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -13238,15 +13152,6 @@ "node": ">= 10.0.0" } }, - "node_modules/url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, "node_modules/url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", @@ -13257,11 +13162,6 @@ "requires-port": "^1.0.0" } }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" - }, "node_modules/use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", @@ -13271,18 +13171,6 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -13432,6 +13320,7 @@ "version": "1.1.10", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.10.tgz", "integrity": "sha512-uxoA5vLUfRPdjCuJ1h5LlYdmTLbYfums398v3WLkM+i/Wltl2/XyZpQWKbN++ck5L64SR/grOHqtXCUKmlZPNA==", + "peer": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -16490,65 +16379,8 @@ "available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" - }, - "aws-sdk": { - "version": "2.1234.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1234.0.tgz", - "integrity": "sha512-QFuSeYM8DPiXytspLnWToy4MWJPGYFCgAy4hi+lRd6ueJtCey7MBIgFNHW814uAJzKUDEdJUJZPvDZvtLM1d/Q==", - "requires": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.16.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "util": "^0.12.4", - "uuid": "8.0.0", - "xml2js": "0.4.19" - }, - "dependencies": { - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==" - }, - "sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" - }, - "uuid": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", - "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==" - }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==" - } - } - }, - "aws-sdk-plus": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/aws-sdk-plus/-/aws-sdk-plus-0.5.3.tgz", - "integrity": "sha512-C/I1sWXAA5gRh5G4XbqnnVTGfzKimXJVkgBl62rt4SUAjOyakMICvSG/MaS4xzS+6umiVgKH8liWsNmiSueXXA==", - "requires": { - "aws-sdk": "^2.1004.0", - "react": "^17.0.2", - "react-dom": "^17.0.2" - } + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "peer": true }, "axios": { "version": "0.27.2", @@ -16569,7 +16401,8 @@ "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "peer": true }, "binary-extensions": { "version": "2.2.0", @@ -16636,16 +16469,6 @@ "fill-range": "^7.0.1" } }, - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -16676,6 +16499,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "peer": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -17307,6 +17131,7 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "peer": true, "requires": { "is-callable": "^1.1.3" } @@ -17366,7 +17191,8 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "peer": true }, "functions-have-names": { "version": "1.2.3", @@ -17389,6 +17215,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "peer": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -17423,6 +17250,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "peer": true, "requires": { "get-intrinsic": "^1.1.3" } @@ -17443,6 +17271,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "peer": true, "requires": { "function-bind": "^1.1.1" } @@ -17471,17 +17300,20 @@ "has-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "peer": true }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "peer": true }, "has-tostringtag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "peer": true, "requires": { "has-symbols": "^1.0.2" } @@ -17595,7 +17427,8 @@ "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "peer": true }, "immediate": { "version": "3.0.6", @@ -17616,7 +17449,8 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "peer": true }, "insect": { "version": "5.8.2", @@ -22314,6 +22148,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "peer": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -22366,7 +22201,8 @@ "is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "peer": true }, "is-ci": { "version": "2.0.0", @@ -22418,14 +22254,6 @@ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "peer": true }, - "is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -22514,6 +22342,7 @@ "version": "1.1.10", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "peer": true, "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -22550,7 +22379,8 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "peer": true }, "isexe": { "version": "2.0.0", @@ -22591,15 +22421,11 @@ "integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==", "peer": true }, - "jmespath": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", - "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true }, "jsdom": { "version": "20.0.3", @@ -22745,6 +22571,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -22881,7 +22708,8 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "peer": true }, "object-hash": { "version": "3.0.0", @@ -23285,11 +23113,6 @@ "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "peer": true }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" - }, "querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -23306,6 +23129,7 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "peer": true, "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -23324,6 +23148,7 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "peer": true, "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -23507,12 +23332,11 @@ } }, "roamjs-components": { - "version": "0.82.0", - "resolved": "https://registry.npmjs.org/roamjs-components/-/roamjs-components-0.82.0.tgz", - "integrity": "sha512-iyv1nSQ4tHXiO3FsOZWg3Iwe86Or3vdDpNkARjnnaVgnoOamc8xmbhTa4yVtpkDWQxXcL9aAulo9uKlj1O6SBw==", + "version": "0.88.4", + "resolved": "https://registry.npmjs.org/roamjs-components/-/roamjs-components-0.88.4.tgz", + "integrity": "sha512-yMaIvZt6OTLhl87IEKF/IQcIRgeaT56nauYVtgDsjBs85wWUmskx8W++VEjdJaH1QN8pDEz7UOVI1aRCZQw1Rw==", "requires": { "@samepage/scripts": "^0.74.2", - "aws-sdk-plus": "^0.5.3", "color": "^4.0.1", "date-fns": "^2.27.0", "edn-data": "^1.0.0", @@ -23556,6 +23380,7 @@ "version": "0.20.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "peer": true, "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -23940,22 +23765,6 @@ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "peer": true }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" - } - } - }, "url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", @@ -23973,18 +23782,6 @@ "peer": true, "requires": {} }, - "util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "requires": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -24101,6 +23898,7 @@ "version": "1.1.10", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.10.tgz", "integrity": "sha512-uxoA5vLUfRPdjCuJ1h5LlYdmTLbYfums398v3WLkM+i/Wltl2/XyZpQWKbN++ck5L64SR/grOHqtXCUKmlZPNA==", + "peer": true, "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", diff --git a/package.json b/package.json index 35eb223..32e7616 100644 --- a/package.json +++ b/package.json @@ -5,13 +5,14 @@ "main": "./build/main.js", "scripts": { "start": "samepage dev", + "test": "ts-node --transpile-only --project tsconfig.test.json src/components/nativeSlideUtils.test.ts", "prebuild:roam": "npm install", "build:roam": "samepage build --dry" }, "license": "MIT", "dependencies": { "reveal.js": "^4.3.0", - "roamjs-components": "^0.82.0" + "roamjs-components": "^0.88.4" }, "samepage": { "extends": "node_modules/roamjs-components/package.json" diff --git a/src/components/NativeRoamContent.tsx b/src/components/NativeRoamContent.tsx new file mode 100644 index 0000000..efb8002 --- /dev/null +++ b/src/components/NativeRoamContent.tsx @@ -0,0 +1,90 @@ +import React from "react"; +import type {} from "roamjs-components/types"; + +type BlockContent = { + kind: "block"; + uid: string; + open?: boolean; + zoomPath?: boolean; + zoomStartAfterUid?: string; +}; + +type PageContent = { + kind: "page"; + hideMentions?: boolean; +} & ({ uid: string; title?: never } | { uid?: never; title: string }); + +type StringContent = { + kind: "string"; + string: string; +}; + +type SearchContent = { + kind: "search"; + searchQueryStr: string; + closed?: boolean; + groupByPage?: boolean; + hidePaths?: boolean; + onConfigChange?: (config: { + closed?: boolean; + groupByPage?: boolean; + hidePaths?: boolean; + }) => void; +}; + +export type NativeRoamContentProps = + BlockContent | PageContent | StringContent | SearchContent; + +const getNativeComponents = () => { + const components = window.roamAlphaAPI?.ui.react; + if (!components) { + throw new Error( + "This version of Roam does not expose roamAlphaAPI.ui.react.", + ); + } + return components; +}; + +/** + * One typed entry point for Roam's native React renderers. + * + * Presentation2 currently uses `block` for slide trees and notes, and + * `string` for titles whose presentation directives have been removed. + * `page` and `search` are included here for page-oriented and search-result + * slides without introducing another rendering abstraction later. + */ +const NativeRoamContent = (props: NativeRoamContentProps) => { + const { Block, Page, Search, BlockString } = getNativeComponents(); + + switch (props.kind) { + case "block": + return ( + + ); + case "page": + return props.uid ? ( + + ) : ( + + ); + case "search": + return ( + + ); + case "string": + return ; + } +}; + +export default NativeRoamContent; diff --git a/src/components/Presentation.tsx b/src/components/Presentation.tsx index 0b87a63..490f4a0 100644 --- a/src/components/Presentation.tsx +++ b/src/components/Presentation.tsx @@ -64,9 +64,11 @@ const parseSolo = ({ viewType: "document", children: [], uid: "", + parents: [], heading: 0, open: true, textAlign, + blockViewType: "outline", editTime: new Date(), props: { imageResize: {}, iframe: {} }, }, @@ -588,7 +590,7 @@ const ContentSlide = ({ __html: parseRoamBlocks({ content: bullets, viewType }), }} style={{ - width: isImageLayout ? "50%" : "100%", + width: isSourceLayout && !isCenterLayout ? "50%" : "100%", transformOrigin: "left top", wordBreak: "break-word", display: isCenterLayout ? "none" : "block", @@ -838,7 +840,11 @@ const PresentationContent: React.FunctionComponent<{ }, [revealRef, initialized, startIndex, slides, mappedSlides]); return ( <> -
+
{mappedSlides.map((s: TreeNode & ContentSlideExtras, i) => ( diff --git a/src/components/Presentation2.tsx b/src/components/Presentation2.tsx new file mode 100644 index 0000000..f48b06c --- /dev/null +++ b/src/components/Presentation2.tsx @@ -0,0 +1,712 @@ +import { Button, Dialog, Overlay } from "@blueprintjs/core"; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; +import ReactDOM from "react-dom"; +import Reveal from "reveal.js"; +import BlockErrorBoundary from "roamjs-components/components/BlockErrorBoundary"; +import getUids from "roamjs-components/dom/getUids"; +import getUidsFromButton from "roamjs-components/dom/getUidsFromButton"; +import addStyle from "roamjs-components/dom/addStyle"; +import { TreeNode } from "roamjs-components/types"; +import isControl from "roamjs-components/util/isControl"; +import { + ANIMATE_REGEX, + COLLAPSIBLE_REGEX, + TITLE_REGEX, + TRANSITION_REGEX, + VALID_THEMES, +} from "./Presentation"; +import NativeRoamContent from "./NativeRoamContent"; +import { + collectHiddenUids, + findLargestFittingScale, + getVisibleChildren, + getVisibleLayoutSource, + HIDE_REGEX, + shouldExpandLayoutSource, + shouldUseTitleLayout, +} from "./nativeSlideUtils"; + +const LAYOUTS = [ + "Image Left", + "Image Center", + "Image Right", + "Iframe Left", + "Iframe Center", + "Iframe Right", + "Media Left", + "Media Center", + "Media Right", +]; +const LAYOUT_REGEX = new RegExp( + `(?:\\[\\[{|{\\[\\[|{)layout:(${LAYOUTS.join("|")})(?:\\]\\]}|}\\]\\]|})`, + "is", +); +const STARTS_WITH_IMAGE = /^image /i; +const STARTS_WITH_IFRAME = /^iframe /i; +const STARTS_WITH_MEDIA = /^media /i; +const ENDS_WITH_LEFT = / left$/i; +const ENDS_WITH_CENTER = / center$/i; +const TITLE_SOURCE_REGEX = /^(?:!\[.*\]\(.*\)|{{(?:\[\[)?iframe)/i; + +type PreparedSlide = TreeNode & { + displayText: string; + isTitle: boolean; + layout: string; + collapsible: boolean; + animate: boolean; + transition?: string; + contentChildren: TreeNode[]; + note?: TreeNode; +}; + +type PresentationOptions = { + getSlides: () => TreeNode[]; + theme?: string; + notes?: string; + collapsible?: boolean; + animate?: boolean; + transition?: string; + windowId: string; +}; + +export const prepareSlides = ({ + slides, + showNotes, + globalCollapsible, + globalAnimate, + globalTransition, +}: { + slides: TreeNode[]; + showNotes: boolean; + globalCollapsible: boolean; + globalAnimate: boolean; + globalTransition?: string; +}): PreparedSlide[] => + slides + .filter((slide) => !HIDE_REGEX.test(slide.text)) + .map((slide) => { + let layout = "default"; + let collapsible = globalCollapsible; + let animate = globalAnimate; + let transition = globalTransition; + let isTitle = false; + const displayText = slide.text + .replace(LAYOUT_REGEX, (_, capture: string) => { + layout = capture; + return ""; + }) + .replace(COLLAPSIBLE_REGEX, (_, ignore: string) => { + collapsible = !ignore; + return ""; + }) + .replace(ANIMATE_REGEX, () => { + animate = true; + return ""; + }) + .replace(TRANSITION_REGEX, (_, value: string) => { + transition = value; + return ""; + }) + .replace(TITLE_REGEX, () => { + isTitle = true; + return ""; + }) + .trim(); + const visibleChildren = getVisibleChildren(slide.children); + isTitle = shouldUseTitleLayout({ + forcedTitle: isTitle, + visibleChildren, + }); + const note = showNotes + ? visibleChildren[visibleChildren.length - 1] + : undefined; + const contentChildren = showNotes + ? visibleChildren.slice(0, -1) + : visibleChildren; + + return { + ...slide, + displayText, + isTitle, + layout, + collapsible, + animate, + transition, + contentChildren, + note, + }; + }); + +const escapeAttributeValue = (value: string) => + value.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); + +const getBlockContainer = (element: Element | null) => + element?.closest( + ".roam-block-container, .rm-block-main, [data-block-uid]", + ) || null; + +const NativeCollapsibleNode = ({ node }: { node: TreeNode }) => { + const [expanded, setExpanded] = useState(false); + const children = node.children.filter( + (child) => !HIDE_REGEX.test(child.text), + ); + + return ( +
+
+ {!!children.length && ( + + )} + +
+ {expanded && ( +
+ {children.map((child) => ( + + ))} +
+ )} +
+ ); +}; + +const NativeExpandedSlideTree = ({ + slide, + hiddenUids, +}: { + slide: PreparedSlide; + hiddenUids: string[]; +}) => { + const rootRef = useRef(null); + + useEffect(() => { + const root = rootRef.current; + if (!root) return; + + const applyPresentationVisibility = () => { + const rootUid = escapeAttributeValue(slide.uid); + const rootUidElement = root.querySelector( + `[data-uid="${rootUid}"], [data-block-uid="${rootUid}"]`, + ); + const rootContainer = + getBlockContainer(rootUidElement) || + root.querySelector(".roam-block-container"); + const rootMain = + rootContainer?.querySelector(":scope > .rm-block-main") || + rootContainer?.querySelector(".rm-block-main"); + if (rootMain) rootMain.style.display = "none"; + + hiddenUids.forEach((uid) => { + const escapedUid = escapeAttributeValue(uid); + root + .querySelectorAll( + `[data-uid="${escapedUid}"], [data-block-uid="${escapedUid}"]`, + ) + .forEach((element) => { + const container = getBlockContainer(element); + if (container && container !== rootContainer) { + container.style.display = "none"; + } + }); + }); + + root.querySelectorAll("a").forEach((anchor) => { + anchor.target = "_blank"; + anchor.rel = "noreferrer"; + }); + }; + + applyPresentationVisibility(); + const observer = new MutationObserver(applyPresentationVisibility); + observer.observe(root, { childList: true, subtree: true }); + return () => observer.disconnect(); + }, [slide.uid, hiddenUids.join("|")]); + + return ( +
+ +
+ ); +}; + +const NativeSlideTree = ({ + slide, + hiddenUids, +}: { + slide: PreparedSlide; + hiddenUids: string[]; +}) => { + if (slide.collapsible) { + const hiddenUidSet = new Set(hiddenUids); + const visibleNodes = slide.contentChildren.filter( + (node) => !hiddenUidSet.has(node.uid) && !HIDE_REGEX.test(node.text), + ); + return ( +
+ {visibleNodes.map((node) => ( + + ))} +
+ ); + } + + return ; +}; + +const NativeNotes = ({ note }: { note?: TreeNode }) => + note ? ( + + ) : null; + +const NativeTitleSlide = ({ slide }: { slide: PreparedSlide }) => { + const visibleChildren = slide.contentChildren.filter( + (child) => !HIDE_REGEX.test(child.text), + ); + const props = { + style: { + textAlign: slide.textAlign || "left", + ...(TITLE_SOURCE_REGEX.test(slide.displayText) ? { bottom: 0 } : {}), + }, + ...(slide.animate ? { "data-auto-animate": true } : {}), + ...(slide.transition ? { "data-transition": slide.transition } : {}), + }; + + return ( +
+

+ +

+ {visibleChildren.map((child) => ( +

+ +

+ ))} + +
+ ); +}; + +const NativeContentSlide = ({ slide }: { slide: PreparedSlide }) => { + const isImageLayout = STARTS_WITH_IMAGE.test(slide.layout); + const isIframeLayout = STARTS_WITH_IFRAME.test(slide.layout); + const isMediaLayout = STARTS_WITH_MEDIA.test(slide.layout); + const isSourceLayout = isImageLayout || isIframeLayout || isMediaLayout; + const isLeftLayout = ENDS_WITH_LEFT.test(slide.layout); + const isCenterLayout = ENDS_WITH_CENTER.test(slide.layout); + const source = getVisibleLayoutSource({ + contentChildren: slide.contentChildren, + isSourceLayout, + }); + const hiddenUids = collectHiddenUids(slide.children).concat( + source?.uid || [], + slide.note?.uid || [], + ); + const [imageDialogSrc, setImageDialogSrc] = useState(""); + const onRootClick = useCallback((event: React.MouseEvent) => { + const target = event.target as HTMLElement; + if (target.tagName === "IMG") { + setImageDialogSrc((target as HTMLImageElement).src); + } + }, []); + const sectionProps = { + ...(slide.animate ? { "data-auto-animate": true } : {}), + ...(slide.transition ? { "data-transition": slide.transition } : {}), + }; + + return ( +
+

+ +

+
+
+ +
+ {source && ( +
+ +
+ )} +
+ + setImageDialogSrc("")} + portalClassName="roamjs-presentation-img-dialog" + style={{ paddingBottom: 0 }} + > + + +
+ ); +}; + +const scaleActiveSlide = (slidesElement: HTMLElement) => { + const container = slidesElement.querySelector( + ".present .roamjs-bullets-container", + ); + if (!container) return; + container.style.transform = "none"; + container.style.overflow = "visible"; + const containerHeight = container.offsetHeight; + const containerWidth = container.offsetWidth; + const content = container.firstElementChild as HTMLElement | null; + if (!content || containerHeight <= 0 || containerWidth <= 0) return; + content.style.transform = "none"; + content.style.transformOrigin = "left top"; + content.style.width = `${containerWidth}px`; + + const fitsAtScale = (scale: number) => { + content.style.width = `${containerWidth / scale}px`; + return ( + content.offsetHeight * scale <= containerHeight && + content.scrollWidth * scale <= containerWidth + 2 + ); + }; + + const scale = findLargestFittingScale({ fitsAtScale }); + if (scale === 1) { + content.style.width = "100%"; + return; + } + if (scale === undefined) { + content.style.width = "100%"; + container.style.overflow = "auto"; + return; + } + + content.style.width = `${containerWidth / scale}px`; + content.style.transform = `scale(${scale})`; +}; + +const NativePresentationContent = ({ + slides, + onClose, + showNotes, + globalCollapsible, + globalAnimate, + globalTransition, + startIndex, +}: { + slides: TreeNode[]; + onClose: (index: number) => void; + showNotes: boolean; + globalCollapsible: boolean; + globalAnimate: boolean; + globalTransition?: string; + startIndex: number; +}) => { + const revealRef = useRef(null); + const slidesRef = useRef(null); + const preparedSlides = useMemo( + () => + prepareSlides({ + slides, + showNotes, + globalCollapsible, + globalAnimate, + globalTransition, + }), + [slides, showNotes, globalCollapsible, globalAnimate, globalTransition], + ); + const [initialized, setInitialized] = useState(false); + + const close = useCallback( + (event?: Event) => { + const reveal = revealRef.current; + if (!reveal) return; + reveal.getRevealElement().style.display = "none"; + const currentSlide = preparedSlides[reveal.getState().indexh]; + const actualIndex = currentSlide + ? slides.findIndex((slide) => slide.uid === currentSlide.uid) + : 0; + onClose(Math.max(0, actualIndex)); + event?.stopImmediatePropagation(); + }, + [onClose, preparedSlides, slides], + ); + + useEffect(() => { + if (!slidesRef.current) return; + const deck = new Reveal({ + embedded: true, + slideNumber: "c/t", + width: window.innerWidth * 0.9, + height: window.innerHeight * 0.9, + showNotes, + minScale: 1, + maxScale: 1, + }); + const layoutActiveSlide = () => { + deck.layout(); + requestAnimationFrame(() => { + if (slidesRef.current) scaleActiveSlide(slidesRef.current); + }); + }; + deck.on("ready", layoutActiveSlide); + deck.initialize().then(layoutActiveSlide); + revealRef.current = deck; + const observer = new MutationObserver(layoutActiveSlide); + observer.observe(slidesRef.current, { + attributes: true, + attributeFilter: ["class"], + childList: true, + subtree: true, + }); + setInitialized(true); + return () => { + observer.disconnect(); + deck.off("ready", layoutActiveSlide); + (deck as Reveal & { destroy?: () => void }).destroy?.(); + }; + }, [showNotes]); + + useEffect(() => { + const onKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") { + close(event); + } else if ( + isControl(event) && + event.key === "p" && + !event.shiftKey && + !event.altKey + ) { + revealRef.current.isPrintingPdf = () => true; + const injectedStyle = addStyle(`@media print { + body * { visibility: hidden; } + #roamjs-presentation-container #roamjs-reveal-root * { visibility: visible; } + #roamjs-presentation-container * { + position: absolute; + left: 0; + top: 0; + } +}`); + const onAfterPrint = () => { + injectedStyle.remove(); + window.removeEventListener("afterprint", onAfterPrint); + }; + window.addEventListener("afterprint", onAfterPrint); + window.print(); + event.preventDefault(); + } + }; + document.body.addEventListener("keydown", onKeyDown); + return () => document.body.removeEventListener("keydown", onKeyDown); + }, [close]); + + useEffect(() => { + if (!initialized || startIndex <= 0) return; + const selectedSlide = slides[startIndex]; + const actualIndex = preparedSlides.findIndex( + (slide) => slide.uid === selectedSlide?.uid, + ); + if (actualIndex >= 0) revealRef.current.slide(actualIndex); + }, [initialized, startIndex, slides, preparedSlides]); + + return ( + <> +
+
+ {preparedSlides.map((slide) => + slide.isTitle ? ( + + ) : ( + + ), + )} +
+
+