1
0

add initial marp implementation with sample content and build configuration

This commit is contained in:
2025-09-13 18:13:22 +02:00
parent dcacc9b409
commit e5f219507f
10319 changed files with 1402023 additions and 0 deletions

21
node_modules/@marp-team/marpit-svg-polyfill/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Marp team (marp-team@marp.app)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

132
node_modules/@marp-team/marpit-svg-polyfill/README.md generated vendored Normal file
View File

@@ -0,0 +1,132 @@
# @marp-team/marpit-svg-polyfill
[![CircleCI](https://img.shields.io/circleci/project/github/marp-team/marpit-svg-polyfill/main.svg?style=flat-square&logo=circleci)](https://circleci.com/gh/marp-team/marpit-svg-polyfill/)
[![Codecov](https://img.shields.io/codecov/c/github/marp-team/marpit-svg-polyfill/main.svg?style=flat-square&logo=codecov)](https://codecov.io/gh/marp-team/marpit-svg-polyfill)
[![npm](https://img.shields.io/npm/v/@marp-team/marpit-svg-polyfill.svg?style=flat-square&logo=npm)](https://www.npmjs.com/package/@marp-team/marpit-svg-polyfill)
[![LICENSE](https://img.shields.io/github/license/marp-team/marpit-svg-polyfill.svg?style=flat-square)](./LICENSE)
The polyfill for [the inline SVG slide][inline-svg] rendered by [Marpit].
[marpit]: https://github.com/marp-team/marpit
[inline-svg]: https://marpit.marp.app/inline-svg
### Supported browser
- [WebKit](#webkit) based browser: Safari and iOS browsers (including iOS Chrome, iOS Firefox, iOS Edge, and so on...)
## Usage
```html
<!-- Generated HTML by Marpit's inline SVG mode -->
<div class="marpit">
<svg viewBox="0 0 1280 720" data-marpit-svg="">
<foreignObject width="1280" height="720">
<section>...</section>
</foreignObject>
</svg>
</div>
<!-- After than, use polyfill through jsDelivr CDN -->
<script src="https://cdn.jsdelivr.net/npm/@marp-team/marpit-svg-polyfill/lib/polyfill.browser.js"></script>
```
## Why need?
### WebKit
[Marpit]'s [inline SVG slide][inline-svg] has a lot of advantages: No requires JavaScript, gives better performance for scaling, and has predicatable DOM structure.
But unfortunately, WebKit browser has not scaled the wrapped HTML correctly. It is caused from a long standing [bug 23113](https://bugs.webkit.org/show_bug.cgi?id=23113), and it does not resolved in the last 15 years.
![](https://raw.githubusercontent.com/marp-team/marpit-svg-polyfill/main/docs/webkit-bug.png)
> **Note**
> A brand-new SVG engine for WebKit called as [**"Layer-based SVG engine (LBSE)"**](https://blogs.igalia.com/nzimmermann/posts/2021-10-29-layer-based-svg-engine/) is currently under development, and it will finally bring glitch-free scaling without JS. (See also: [Status of the new SVG engine in WebKit](https://wpewebkit.org/blog/05-new-svg-engine.html))
>
> You can test LBSE in [Safari Technology Preview](https://developer.apple.com/safari/technology-preview/) by following these steps:
>
> 1. Install Safari Technology Preview
> 1. Run `defaults write com.apple.SafariTechnologyPreview IncludeInternalDebugMenu 1` in terminal
> 1. Open Safari Technology Preview
> 1. Turn on **"Layer-based SVG engine (LBSE)"** from "Debug" menu → "WebKit Internal Features"
> 1. Restart app
>
> marpit-svg-polyfill v2.1.0 and later will try to detect whether or not enabled LBSE, and does not apply polyfill if LBSE was available.
## Solutions
### For Webkit
#### Scaling
We try to simulate scaling and centering by applying `transform` / `transform-origin` style to Marpit `<section>` elements.
```html
<svg viewBox="0 0 1280 960">
<foreignObject width="1280" height="960">
<section style="transform-origin:0 0;transform:matrix(......);">
...
</section>
</foreignObject>
</svg>
```
marpit-svg-polyfill uses the result of `getScreenCTM()` method, so the polyfill will sacrifice "zero-JS slide", the key feature of inline SVG.
#### Repainting
WebKit browser would not trigger repainting even if modified the contents of slide. It becomes a problem when supporting the live preview feature in Marp tools.
Fortunately, [a genius already resolved this problem only in CSS!](https://stackoverflow.com/a/21947628) `transform:translateZ(0)` would trigger re-painting immidiately when modified contents.
#### Animation GIF
People like to put GIF animation in the slide. However, GIF in polyfilled slides have glitches. GIF updates only a cropped part somewhere.
Applying `transform:translateZ(0.0001px)` to each `<section>` elements within SVG is a magic to resolve that. 🪄
> **Warning**
> This style brings slightly blurred contents too. Our polyfill prefers to render animated contents correctly.
<!--
## Advanced
### Apply polyfill manually
You may pick out the logic of polyfill if you required. When called a picked function, it applies polyfill forcibly without browser detection.
```javascript
import { webkit } from '@marp-team/marpit-svg-polyfill'
const observer = () => {
// Apply polyfill for webkit forcibly
webkit()
window.requestAnimationFrame(observer)
}
document.addEventListener('DOMContentLoaded', observer)
```
#### Use case in Blink browsers
We have confirmed a similar rendering bug to WebKit in a few Blink based browsers. (e.g. Chrome 66, Electron 3.x. refs: [marp-team/marpit#35](https://github.com/marp-team/marpit/pull/35), [marp-team/marp-cli#15](https://github.com/marp-team/marp-cli/pull/15))
We are not applied polyfill for Blink browsers because [they are working toward to resolve this.](https://bugs.chromium.org/p/chromium/issues/detail?id=467484) But you may apply `webkit()` manually if you required.
-->
## Contributing
We are following [the contributing guideline of marp-team projects](https://github.com/marp-team/.github/blob/master/CONTRIBUTING.md). Please read these guidelines this before starting work in this repository.
## Author
Managed by [@marp-team](https://github.com/marp-team).
- <img src="https://github.com/yhatt.png" width="16" height="16"/> Yuki Hattori ([@yhatt](https://github.com/yhatt))
## License
This module releases under the [MIT License](LICENSE).

View File

@@ -0,0 +1 @@
!function(){"use strict";let t;const e="marpitSVGPolyfill:setZoomFactor,",n=Symbol(),o=Symbol();const r=()=>{const e="Apple Computer, Inc."===navigator.vendor,n=e?[l]:[],o={then:n=>(e?(async()=>{if(void 0===t){const e=document.createElement("canvas");e.width=10,e.height=10;const n=e.getContext("2d"),o=new Image(10,10),r=new Promise((t=>{o.addEventListener("load",(()=>t()))}));o.crossOrigin="anonymous",o.src="data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2210%22%20height%3D%2210%22%20viewBox%3D%220%200%201%201%22%3E%3CforeignObject%20width%3D%221%22%20height%3D%221%22%20requiredExtensions%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml%22%3E%3Cdiv%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml%22%20style%3D%22width%3A%201px%3B%20height%3A%201px%3B%20background%3A%20red%3B%20position%3A%20relative%22%3E%3C%2Fdiv%3E%3C%2FforeignObject%3E%3C%2Fsvg%3E",await r,n.drawImage(o,0,0),t=n.getImageData(5,5,1,1).data[3]<128}return t})().then((t=>{null==n||n(t?[l]:[])})):null==n||n([]),o)};return Object.assign(n,o)};let i,a;function l(t){const n="object"==typeof t&&t.target||document,r="object"==typeof t?t.zoom:t;window[o]||(Object.defineProperty(window,o,{configurable:!0,value:!0}),document.body.style.zoom=1.0001,document.body.offsetHeight,document.body.style.zoom=1,window.addEventListener("message",(({data:t,origin:n})=>{if(n===window.origin)try{if(t&&"string"==typeof t&&t.startsWith(e)){const[,e]=t.split(","),n=Number.parseFloat(e);Number.isNaN(n)||(a=n)}}catch(t){console.error(t)}})));let l=!1;Array.from(n.querySelectorAll("svg[data-marpit-svg]"),(t=>{var e,n,o,s;t.style.transform||(t.style.transform="translateZ(0)");const c=r||a||t.currentScale||1;i!==c&&(i=c,l=c);const d=t.getBoundingClientRect(),{length:g}=t.children;for(let r=0;r<g;r+=1){const i=t.children[r];if(i.getScreenCTM){const t=i.getScreenCTM();if(t){const r=null!==(n=null===(e=i.x)||void 0===e?void 0:e.baseVal.value)&&void 0!==n?n:0,a=null!==(s=null===(o=i.y)||void 0===o?void 0:o.baseVal.value)&&void 0!==s?s:0,l=i.children.length;for(let e=0;e<l;e+=1){const n=i.children[e];if("SECTION"===n.tagName){const{style:e}=n;e.transformOrigin||(e.transformOrigin=`${-r}px ${-a}px`),e.transform=`scale(${c}) matrix(${t.a}, ${t.b}, ${t.c}, ${t.d}, ${t.e-d.left}, ${t.f-d.top}) translateZ(0.0001px)`;break}}}}}})),!1!==l&&Array.from(n.querySelectorAll("iframe"),(({contentWindow:t})=>{null==t||t.postMessage(`${e}${l}`,"null"===window.origin?"*":window.origin)}))}i=1,a=void 0,function(t=document){if(t[n])return t[n];let e=!0;const o=()=>{e=!1,delete t[n]};Object.defineProperty(t,n,{configurable:!0,value:o});let i=[],a=!1;(async()=>{try{i=await r()}finally{a=!0}})();const l=()=>{for(const e of i)e({target:t});a&&0===i.length||e&&window.requestAnimationFrame(l)};l()}()}();

View File

@@ -0,0 +1 @@
"use strict";let e;Object.defineProperty(exports,"__esModule",{value:!0});const t="marpitSVGPolyfill:setZoomFactor,",o=Symbol(),n=Symbol();function r(e=document){if(e[o])return e[o];let t=!0;const n=()=>{t=!1,delete e[o]};Object.defineProperty(e,o,{configurable:!0,value:n});let r=[],l=!1;(async()=>{try{r=await i()}finally{l=!0}})();const s=()=>{for(const t of r)t({target:e});l&&0===r.length||t&&window.requestAnimationFrame(s)};return s(),n}const i=()=>{const t="Apple Computer, Inc."===navigator.vendor,o=t?[a]:[],n={then:o=>(t?(async()=>{if(void 0===e){const t=document.createElement("canvas");t.width=10,t.height=10;const o=t.getContext("2d"),n=new Image(10,10),r=new Promise((e=>{n.addEventListener("load",(()=>e()))}));n.crossOrigin="anonymous",n.src="data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2210%22%20height%3D%2210%22%20viewBox%3D%220%200%201%201%22%3E%3CforeignObject%20width%3D%221%22%20height%3D%221%22%20requiredExtensions%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml%22%3E%3Cdiv%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml%22%20style%3D%22width%3A%201px%3B%20height%3A%201px%3B%20background%3A%20red%3B%20position%3A%20relative%22%3E%3C%2Fdiv%3E%3C%2FforeignObject%3E%3C%2Fsvg%3E",await r,o.drawImage(n,0,0),e=o.getImageData(5,5,1,1).data[3]<128}return e})().then((e=>{null==o||o(e?[a]:[])})):null==o||o([]),n)};return Object.assign(o,n)};let l,s;function a(e){const o="object"==typeof e&&e.target||document,r="object"==typeof e?e.zoom:e;window[n]||(Object.defineProperty(window,n,{configurable:!0,value:!0}),document.body.style.zoom=1.0001,document.body.offsetHeight,document.body.style.zoom=1,window.addEventListener("message",(({data:e,origin:o})=>{if(o===window.origin)try{if(e&&"string"==typeof e&&e.startsWith(t)){const[,t]=e.split(","),o=Number.parseFloat(t);Number.isNaN(o)||(s=o)}}catch(e){console.error(e)}})));let i=!1;Array.from(o.querySelectorAll("svg[data-marpit-svg]"),(e=>{var t,o,n,a;e.style.transform||(e.style.transform="translateZ(0)");const c=r||s||e.currentScale||1;l!==c&&(l=c,i=c);const d=e.getBoundingClientRect(),{length:g}=e.children;for(let r=0;r<g;r+=1){const i=e.children[r];if(i.getScreenCTM){const e=i.getScreenCTM();if(e){const r=null!==(o=null===(t=i.x)||void 0===t?void 0:t.baseVal.value)&&void 0!==o?o:0,l=null!==(a=null===(n=i.y)||void 0===n?void 0:n.baseVal.value)&&void 0!==a?a:0,s=i.children.length;for(let t=0;t<s;t+=1){const o=i.children[t];if("SECTION"===o.tagName){const{style:t}=o;t.transformOrigin||(t.transformOrigin=`${-r}px ${-l}px`),t.transform=`scale(${c}) matrix(${e.a}, ${e.b}, ${e.c}, ${e.d}, ${e.e-d.left}, ${e.f-d.top}) translateZ(0.0001px)`;break}}}}}})),!1!==i&&Array.from(o.querySelectorAll("iframe"),(({contentWindow:e})=>{null==e||e.postMessage(`${t}${i}`,"null"===window.origin?"*":window.origin)}))}l=1,s=void 0,exports.default=r,exports.observe=r,exports.polyfills=i,exports.webkit=a;

View File

@@ -0,0 +1 @@
let t;const e="marpitSVGPolyfill:setZoomFactor,",n=Symbol(),o=Symbol();function r(t=document){if(t[n])return t[n];let e=!0;const o=()=>{e=!1,delete t[n]};Object.defineProperty(t,n,{configurable:!0,value:o});let r=[],a=!1;(async()=>{try{r=await i()}finally{a=!0}})();const l=()=>{for(const e of r)e({target:t});a&&0===r.length||e&&window.requestAnimationFrame(l)};return l(),o}const i=()=>{const e="Apple Computer, Inc."===navigator.vendor,n=e?[s]:[],o={then:n=>(e?(async()=>{if(void 0===t){const e=document.createElement("canvas");e.width=10,e.height=10;const n=e.getContext("2d"),o=new Image(10,10),r=new Promise((t=>{o.addEventListener("load",(()=>t()))}));o.crossOrigin="anonymous",o.src="data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2210%22%20height%3D%2210%22%20viewBox%3D%220%200%201%201%22%3E%3CforeignObject%20width%3D%221%22%20height%3D%221%22%20requiredExtensions%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml%22%3E%3Cdiv%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml%22%20style%3D%22width%3A%201px%3B%20height%3A%201px%3B%20background%3A%20red%3B%20position%3A%20relative%22%3E%3C%2Fdiv%3E%3C%2FforeignObject%3E%3C%2Fsvg%3E",await r,n.drawImage(o,0,0),t=n.getImageData(5,5,1,1).data[3]<128}return t})().then((t=>{null==n||n(t?[s]:[])})):null==n||n([]),o)};return Object.assign(n,o)};let a,l;function s(t){const n="object"==typeof t&&t.target||document,r="object"==typeof t?t.zoom:t;window[o]||(Object.defineProperty(window,o,{configurable:!0,value:!0}),document.body.style.zoom=1.0001,document.body.offsetHeight,document.body.style.zoom=1,window.addEventListener("message",(({data:t,origin:n})=>{if(n===window.origin)try{if(t&&"string"==typeof t&&t.startsWith(e)){const[,e]=t.split(","),n=Number.parseFloat(e);Number.isNaN(n)||(l=n)}}catch(t){console.error(t)}})));let i=!1;Array.from(n.querySelectorAll("svg[data-marpit-svg]"),(t=>{var e,n,o,s;t.style.transform||(t.style.transform="translateZ(0)");const c=r||l||t.currentScale||1;a!==c&&(a=c,i=c);const d=t.getBoundingClientRect(),{length:g}=t.children;for(let r=0;r<g;r+=1){const i=t.children[r];if(i.getScreenCTM){const t=i.getScreenCTM();if(t){const r=null!==(n=null===(e=i.x)||void 0===e?void 0:e.baseVal.value)&&void 0!==n?n:0,a=null!==(s=null===(o=i.y)||void 0===o?void 0:o.baseVal.value)&&void 0!==s?s:0,l=i.children.length;for(let e=0;e<l;e+=1){const n=i.children[e];if("SECTION"===n.tagName){const{style:e}=n;e.transformOrigin||(e.transformOrigin=`${-r}px ${-a}px`),e.transform=`scale(${c}) matrix(${t.a}, ${t.b}, ${t.c}, ${t.d}, ${t.e-d.left}, ${t.f-d.top}) translateZ(0.0001px)`;break}}}}}})),!1!==i&&Array.from(n.querySelectorAll("iframe"),(({contentWindow:t})=>{null==t||t.postMessage(`${e}${i}`,"null"===window.origin?"*":window.origin)}))}a=1,l=void 0;export{r as default,r as observe,i as polyfills,s as webkit};

View File

@@ -0,0 +1,115 @@
{
"name": "@marp-team/marpit-svg-polyfill",
"version": "2.1.0",
"description": "Polyfill for inline SVG slides rendered by Marpit",
"license": "MIT",
"author": {
"name": "Marp team",
"url": "https://github.com/marp-team"
},
"contributors": [
{
"name": "Yuki Hattori",
"url": "https://github.com/yhatt"
}
],
"repository": {
"type": "git",
"url": "https://github.com/marp-team/marpit-svg-polyfill"
},
"main": "lib/polyfill.js",
"module": "lib/polyfill.mjs",
"types": "types/entry.d.ts",
"files": [
"lib/",
"types/"
],
"engines": {
"node": ">=10"
},
"jest": {
"collectCoverageFrom": [
"src/**/*.{j,t}s"
],
"coveragePathIgnorePatterns": [
"/node_modules/",
".*\\.d\\.ts"
],
"coverageThreshold": {
"global": {
"lines": 95
}
},
"preset": "ts-jest",
"restoreMocks": true,
"testEnvironment": "jest-environment-jsdom",
"testEnvironmentOptions": {
"resources": "usable"
},
"testMatch": [
"<rootDir>/test/**/!(@(.|_))*.[jt]s"
]
},
"prettier": {
"semi": false,
"singleQuote": true
},
"scripts": {
"build": "yarn -s clean && rollup -c",
"check:audit": "yarn audit",
"check:format": "yarn -s format -c",
"check:ts": "tsc --noEmit",
"clean": "rimraf lib",
"format": "prettier \"**/*.{css,js,json,md,scss,ts,yaml,yml}\"",
"format:write": "yarn -s format --write",
"lint:js": "eslint --ext .js,.mjs,.ts --report-unused-disable-directives --cache .",
"prepack": "npm-run-all --parallel check:* lint:* test:coverage --parallel build types",
"preversion": "run-p check:* lint:* test:coverage",
"test": "jest",
"test:coverage": "jest --coverage",
"types": "rimraf types && tsc --declaration --emitDeclarationOnly --outDir types",
"version": "curl https://raw.githubusercontent.com/marp-team/actions/v1/lib/scripts/version.js | node && git add -A CHANGELOG.md",
"watch": "rollup -w -c"
},
"devDependencies": {
"@babel/eslint-parser": "^7.19.1",
"@babel/plugin-syntax-import-assertions": "^7.20.0",
"@marp-team/marpit": "^2.4.2",
"@rollup/plugin-commonjs": "^24.0.1",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-typescript": "^11.0.0",
"@tsconfig/node10": "^1.0.9",
"@types/jest": "^29.4.0",
"@types/node": "^18.11.19",
"@typescript-eslint/eslint-plugin": "^5.50.0",
"@typescript-eslint/parser": "^5.50.0",
"canvas": "^2.11.0",
"eslint": "^8.33.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jest": "^27.2.1",
"jest": "^29.4.1",
"jest-environment-jsdom": "^29.4.1",
"jest-junit": "^15.0.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.8.3",
"rimraf": "^4.1.2",
"rollup": "^3.14.0",
"rollup-plugin-terser": "^7.0.2",
"ts-jest": "29.0.5",
"tslib": "^2.5.0",
"typescript": "^4.9.5"
},
"peerDependencies": {
"@marp-team/marpit": ">=0.5.0"
},
"peerDependenciesMeta": {
"@marp-team/marpit": {
"optional": true
}
},
"publishConfig": {
"access": "public"
}
}

View File

@@ -0,0 +1 @@
export { PolyfillOption, observe as default, observe, polyfills, webkit, } from './polyfill';

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,42 @@
type PolyfillsRawArray = Array<(opts: PolyfillOption) => void>;
type PolyfillsArray = PolyfillsRawArray & PromiseLike<PolyfillsRawArray>;
export type PolyfillOption = {
/** The parent node to observe. It's useful for observing Marpit slides inside shadow DOM. */
target?: ParentNode;
};
export declare const observerSymbol: unique symbol;
export declare const zoomFactorRecieverSymbol: unique symbol;
/**
* Start observing DOM to apply polyfills.
*
* @param target The parent node to observe. It's useful for observing Marpit
* slides inside shadow DOM. Default is `document`.
* @returns A function for stopping and cleaning up observation.
*/
export declare function observe(target?: ParentNode): () => void;
/**
* Returns an array of polyfill functions that must call for the current browser
* environment.
*
* Including polyfills in the returned array are simply determined by the kind of
* browser. If you want detailed polyfills that were passed accurate feature
* detections, call asyncronous version by `polyfills().then()` or
* `await polyfills()`.
*
* ```js
* import { polyfills } from '@marp-team/marpit-svg-polyfill'
*
* polyfills().then((polyfills) => {
* for (const polyfill of polyfills) polyfill()
* })
* ```
*
* @returns A thenable array including polyfill functions
*/
export declare const polyfills: () => PolyfillsArray;
export declare const _resetCachedZoomFactor: () => void;
export declare function webkit(opts?: number | (PolyfillOption & {
/** A zoom factor applied in the current view. You have to specify manually because there is not a reliable way to get the actual zoom factor in the browser. */
zoom?: number;
})): void;
export {};

View File

@@ -0,0 +1 @@
export declare const isRequiredPolyfill: () => Promise<boolean>;