@dskripchenko/embed 0.0.0-stage → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/LICENSE +21 -0
- package/README.md +127 -2
- package/dist/chunks/attrs-DGIcWUXu.js +1 -0
- package/dist/chunks/runtime-BsSsgPsG.js +1 -0
- package/dist/embed.bundle.js +221 -0
- package/dist/embed.js +6 -0
- package/dist/importmap.json +16 -0
- package/dist/plugins/diagram.js +1 -0
- package/dist/plugins/editor.js +1 -0
- package/dist/plugins/flow.js +1 -0
- package/dist/plugins/markdown.js +1 -0
- package/dist/plugins/media.js +1 -0
- package/dist/plugins/openapi.js +1 -0
- package/dist/vendor/lucide-vue-next.js +1 -0
- package/package.json +70 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# @dskripchenko/embed
|
|
2
|
+
|
|
3
|
+
## 1.0.1 — 2026-10-26
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- `<dsk-editor>`: typing after a slash item chosen with Enter (or a block
|
|
7
|
+
change from the toolbar) goes into the new block, not the previous
|
|
8
|
+
paragraph — the loader's import map and the fat bundle now carry
|
|
9
|
+
`@dskripchenko/wysiwyg` 0.5.2.
|
|
10
|
+
|
|
11
|
+
## 1.0.0 — 2026-10-26
|
|
12
|
+
|
|
13
|
+
First release.
|
|
14
|
+
|
|
15
|
+
- **Loader** `dist/embed.js` (≈ 9 KB gzipped): a classic script that writes
|
|
16
|
+
the import map of the shared runtime — Vue 3.5.44, `@dskripchenko/ui`
|
|
17
|
+
1.16.0, `wysiwyg` 0.5.1, `diagrams` 1.1.0, `openapi` 1.1.1, `flow` 1.0.2,
|
|
18
|
+
pinned — composes with a page's own import map, defines the elements and
|
|
19
|
+
`window.DskEmbed`, and fetches each plugin when its first element appears.
|
|
20
|
+
- **Fat bundle** `dist/embed.bundle.js` (≈ 563 KB gzipped): the same elements
|
|
21
|
+
and API with everything inside, no import map.
|
|
22
|
+
- **Elements**: `<dsk-video>`, `<dsk-audio>`, `<dsk-diagram>`,
|
|
23
|
+
`<dsk-openapi>` (reference, operation, block), `<dsk-flow>` (view with
|
|
24
|
+
`poll-url` / `toggle-url` / `subgraph-url` conventions, or the editor),
|
|
25
|
+
`<dsk-markdown>`, `<dsk-editor>` (form-ready: `name`, `input`, `input` /
|
|
26
|
+
`change` events). Light DOM, attributes ↔ properties, `loading="lazy"`.
|
|
27
|
+
- **Blocks**: a page-wide registry (`DskEmbed.blocks.register`) with the
|
|
28
|
+
live-block contract of the kit and the editor; built-in `mermaid`,
|
|
29
|
+
`openapi`, `flow`, `video`, `audio`; `DskEmbed.renderBlocks(root)` makes
|
|
30
|
+
stored HTML live, idempotently.
|
|
31
|
+
- **Configuration**: theme (`light`, `dark`, `system`, or the page's
|
|
32
|
+
`data-theme`) and locale (`en`, `ru`, or the page's `lang`) for every
|
|
33
|
+
element from one place; one Vue app context for every mount.
|
|
34
|
+
- **Events**: bubbling `dsk:*` DOM events and `DskEmbed.on/once/off/emit`;
|
|
35
|
+
`openapi-target` and `media-target` wire a process to an API reference and
|
|
36
|
+
a video declaratively.
|
|
37
|
+
- The kit's locale is provided app-wide (`provideAppLocale`); the editor's
|
|
38
|
+
toolbar follows it. Video chapters come from the kit (`chapters`,
|
|
39
|
+
`seekToChapter`), with `playChapter()` and `dsk:chapter` /
|
|
40
|
+
`dsk:chapterchange` on top. Flow toggles persist through `persistToggle`
|
|
41
|
+
and report `{ ok }` in `dsk:toggle`. `<dsk-openapi proxy>` sends try-it
|
|
42
|
+
through the host (`proxySend`); a fixed `height` also sizes the
|
|
43
|
+
reference's sticky navigation (`--oa-viewport-h`).
|
|
44
|
+
- The icons the packages import from `lucide-vue-next` (76, now only
|
|
45
|
+
openapi, flow and the editor's toolbar) are served as one file; pages
|
|
46
|
+
with players or markdown alone no longer fetch them.
|
|
47
|
+
- `scripts/mirror.mjs` for self-hosting in the CDN's layout;
|
|
48
|
+
`dist/importmap.json` for pages that write their own map.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Denis Skripchenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,128 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @dskripchenko/embed
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@dskripchenko/embed)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
Video and audio players, Mermaid diagrams, OpenAPI references, process flows,
|
|
7
|
+
live markdown and a WYSIWYG editor — as HTML tags on **any** page: plain HTML,
|
|
8
|
+
a CMS, WordPress, Blade, React. One script from a CDN. The elements share one
|
|
9
|
+
Vue and one UI kit, render each other's blocks, and talk through DOM events.
|
|
10
|
+
|
|
11
|
+
[**English**](docs/en/getting-started.md) · [Русский](docs/ru/getting-started.md) · [Deutsch](docs/de/getting-started.md) · [中文](docs/zh/getting-started.md)
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<head>
|
|
15
|
+
<script src="https://cdn.jsdelivr.net/npm/@dskripchenko/embed@1/dist/embed.js"></script>
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<dsk-flow src="/process.json" poll-url="/process/state" openapi-target="#api" media-target="#tour"></dsk-flow>
|
|
19
|
+
<dsk-video id="tour" src="/tour.mp4">
|
|
20
|
+
<track kind="chapters" src="/tour.chapters.vtt" default>
|
|
21
|
+
</dsk-video>
|
|
22
|
+
<dsk-openapi id="api" src="/openapi.yaml" height="720"></dsk-openapi>
|
|
23
|
+
|
|
24
|
+
<dsk-markdown>
|
|
25
|
+
<script type="text/markdown">
|
|
26
|
+
```mermaid
|
|
27
|
+
sequenceDiagram
|
|
28
|
+
Shop->>Payments: charge
|
|
29
|
+
```
|
|
30
|
+
</script>
|
|
31
|
+
</dsk-markdown>
|
|
32
|
+
|
|
33
|
+
<form method="post"><dsk-editor name="body"></dsk-editor></form>
|
|
34
|
+
</body>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Clicking a process step opens its API operation and plays its chapter of the
|
|
38
|
+
video; the markdown's diagram is live; the editor submits HTML with the form.
|
|
39
|
+
|
|
40
|
+
## Elements
|
|
41
|
+
|
|
42
|
+
| | | Built on |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `<dsk-video>` | player: sources and quality menu, subtitles, chapters, thumbnails, HLS | [`@dskripchenko/ui`](https://github.com/dskripchenko/ui) |
|
|
45
|
+
| `<dsk-audio>` | player, playlist, waveform | `@dskripchenko/ui` |
|
|
46
|
+
| `<dsk-diagram>` | Mermaid → SVG, 11 diagram types, no Vue loaded | [`@dskripchenko/diagrams`](https://github.com/dskripchenko/diagrams) |
|
|
47
|
+
| `<dsk-openapi>` | full reference (several specs), one operation, or a live API block | [`@dskripchenko/openapi`](https://github.com/dskripchenko/openapi) |
|
|
48
|
+
| `<dsk-flow>` | process view with monitoring, toggles and sub-processes over plain HTTP — or the editor | [`@dskripchenko/flow`](https://github.com/dskripchenko/flow) |
|
|
49
|
+
| `<dsk-markdown>` | markdown with live `mermaid` / `openapi` / `flow` / `video` / `audio` blocks | `@dskripchenko/ui` |
|
|
50
|
+
| `<dsk-editor>` | WYSIWYG with the same live blocks; a form field | [`@dskripchenko/wysiwyg`](https://github.com/dskripchenko/wysiwyg) |
|
|
51
|
+
|
|
52
|
+
All of them: attributes ↔ properties, `dsk:*` events, `ready`, `loading="lazy"`,
|
|
53
|
+
light DOM (your CSS applies). → [Elements](docs/en/elements.md)
|
|
54
|
+
|
|
55
|
+
## Working together
|
|
56
|
+
|
|
57
|
+
- **One runtime.** The loader writes an import map pinning Vue, the kit and
|
|
58
|
+
the plugin packages to the exact versions of the release; every element and
|
|
59
|
+
live block renders in one Vue app context — one locale, one theme, one set
|
|
60
|
+
of block renderers.
|
|
61
|
+
- **Blocks.** `DskEmbed.blocks.register('chart', renderer)` — the live-block
|
|
62
|
+
contract of the kit and the editor — makes ```` ```chart ```` live in
|
|
63
|
+
markdown, in the editor and in `DskEmbed.renderBlocks(root)`, which turns
|
|
64
|
+
stored HTML (`<pre><code class="language-…">`) into widgets. → [Blocks](docs/en/blocks.md)
|
|
65
|
+
- **Configuration.** `DskEmbed.configure({ theme: 'light' | 'dark' | 'system', locale: 'en' | 'ru' })`,
|
|
66
|
+
or just the page's `<html data-theme lang>`. → [Configuration and events](docs/en/config-and-events.md)
|
|
67
|
+
- **Events.** `DskEmbed.on('node', …)`, or `addEventListener('dsk:node', …)` on
|
|
68
|
+
any ancestor; React and other hosts use refs and plain listeners. →
|
|
69
|
+
[Frameworks](docs/en/frameworks.md)
|
|
70
|
+
|
|
71
|
+
## Loader or bundle
|
|
72
|
+
|
|
73
|
+
| | gzipped | |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| `dist/embed.js` — the loader | **9.1 KB** | Classic script; elements, API, import map. Everything else on demand. |
|
|
76
|
+
| `dist/embed.bundle.js` — the fat bundle | **563 KB** (2.0 MB) | Everything inside; no import map, no further requests. |
|
|
77
|
+
|
|
78
|
+
What the loader fetches on demand (gzip -9 of the published files; jsDelivr
|
|
79
|
+
serves Brotli, a little smaller):
|
|
80
|
+
|
|
81
|
+
| First element of… | Fetches | |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| any Vue element | Vue runtime 41.5 KB, `@dskripchenko/ui` 102.6 KB (its icons inside) + CSS 30.1 KB | once per page |
|
|
84
|
+
| `<dsk-video>` / `<dsk-audio>` | plugin 3.5 KB; the HLS adapter 14.6 KB only for `.m3u8` | |
|
|
85
|
+
| `<dsk-diagram>` | plugin 0.8 KB, `@dskripchenko/diagrams` 99.7 KB, kit tokens 2.4 KB | no Vue, no kit components |
|
|
86
|
+
| `<dsk-openapi>` | plugin 1.4 KB, `@dskripchenko/openapi` 180.5 KB + CSS 10.5 KB, icons 5.2 KB | |
|
|
87
|
+
| `<dsk-flow>` | plugin 2.5 KB, `@dskripchenko/flow` 79.9 KB + CSS 4.6 KB, icons 5.2 KB; the Mermaid import (2.4 KB + diagrams) only for Mermaid sources and the editor | |
|
|
88
|
+
| `<dsk-markdown>` | plugin 0.5 KB | blocks load their own plugins |
|
|
89
|
+
| `<dsk-editor>` | plugin 1.1 KB, `@dskripchenko/wysiwyg` 18.2 KB + CSS 2.3 KB, icons 5.2 KB | |
|
|
90
|
+
|
|
91
|
+
The icons file (76 icons, one file) is shared: fetched once, by the first of
|
|
92
|
+
openapi, flow and the editor.
|
|
93
|
+
|
|
94
|
+
→ [Getting started](docs/en/getting-started.md): snippets, self-hosting,
|
|
95
|
+
composing with your own import map, CSP, versioning.
|
|
96
|
+
|
|
97
|
+
## Browsers
|
|
98
|
+
|
|
99
|
+
Current Chromium, Safari and Firefox. The loader needs import maps; there is
|
|
100
|
+
no legacy build. Tested in Chromium and WebKit (Playwright): both builds,
|
|
101
|
+
both themes, both languages, desktop and phone.
|
|
102
|
+
|
|
103
|
+
## Known limitations
|
|
104
|
+
|
|
105
|
+
- **The theme is page-wide** (`<html data-theme>`): the kit's themes are
|
|
106
|
+
defined on `:root`, and its menus and dialogs live in `<body>`.
|
|
107
|
+
|
|
108
|
+
## Development
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pnpm install
|
|
112
|
+
pnpm build # dist/ and the size table
|
|
113
|
+
pnpm test # unit tests (vitest, jsdom)
|
|
114
|
+
pnpm lint && pnpm typecheck
|
|
115
|
+
node scripts/fixtures.mjs # media fixtures for the browser check (ffmpeg)
|
|
116
|
+
pnpm check:browser # Chromium + WebKit against a local mirror of the CDN
|
|
117
|
+
node scripts/mirror.mjs <dir> # self-hosting: the runtime in the CDN's layout
|
|
118
|
+
node scripts/demo.mjs <dir> --local # the demo page (examples/demo) for a host site
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The browser check serves `node_modules` the way jsDelivr serves npm
|
|
122
|
+
(`/npm/<pkg>@<version>/…`, exact versions only) from a second origin, so the
|
|
123
|
+
import map, cross-origin module loading and the version pins are exercised
|
|
124
|
+
for real.
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=[{prop:`locale`,type:`string`},{prop:`loading`,type:`enum`,values:[`lazy`,`eager`]}],t=[{prop:`src`,type:`string`},{prop:`loop`,type:`boolean`},{prop:`preload`,type:`enum`,values:[`none`,`metadata`,`auto`]},{prop:`crossorigin`,type:`enum`,values:[``,`anonymous`,`use-credentials`]},{prop:`exclusive`,type:`boolean`},{prop:`resumeKey`,type:`string`},{prop:`rates`,type:`numbers`},{prop:`hotkeys`,type:`boolean`},{prop:`hlsOptions`,type:`json`}];[...e,...t],[...e,...t],[...e],[...e],[...e],[...e],[...e];function n(e){if(typeof e==`number`&&Number.isFinite(e))return String(e);if(typeof e==`string`&&e.trim()!==``)return e.trim().replace(/\s*[:/]\s*/,` / `)}function r(e,t){return typeof e==`number`&&Number.isFinite(e)?`${e}px`:typeof e==`string`&&e.trim()!==``?/^\d+(\.\d+)?$/.test(e.trim())?`${e.trim()}px`:e.trim():t}export{r as n,n as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{computed as e,createApp as t,createVNode as n,defineComponent as r,h as i,render as a,shallowReactive as o,shallowRef as s}from"vue";import{en as c,markdownBlockRenderersKey as l,provideAppLocale as u,provideLocale as d,ru as f}from"@dskripchenko/ui";var p=o({locale:`en`,theme:`light`,renderers:{}}),m=null,h=null,g={};function _(e){if(h)return;h=e,m=t({render:()=>null}),m.config.errorHandler=(e,t,n)=>{console.error(`[dsk-embed] ${n}:`,e)},m.provide(l,g),u(m,()=>y(p.locale));let n=()=>{let t=e.config();p.locale=t.locale,p.theme=t.resolvedTheme},r=()=>{let t=e.blocks.all();for(let e of Object.keys(g))e in t||delete g[e];Object.assign(g,t),p.renderers=t};n(),r(),e.onConfig(n),e.blocks.subscribe(r)}function v(){if(!h)throw Error(`the embed runtime is not set up`);return h}function y(e){return e===`ru`?f:c}var b=r({name:`DskEmbedLocale`,props:{locale:{type:Function,required:!0},content:{type:Function,required:!0}},setup(t){return d(e(()=>y(t.locale()))),()=>t.content()}}),x=r({name:`DskEmbedContent`,props:{content:{type:Function,required:!0}},setup(e){return()=>e.content()}});function S(e,t,r){if(!m)throw Error(`the embed runtime is not set up`);let i=r?n(b,{locale:r,content:t}):n(x,{content:t});return i.appContext=m._context,a(i,e),{unmount(){a(null,e)}}}function C(e,t){let n=o({props:e.props(),source:e.source(),children:e.children(),locale:e.locale()}),r=e.host.onConfig(()=>{n.locale=e.locale()}),i=e.el.hasAttribute(`locale`)||typeof e.props().locale==`string`,a=S(e.container,()=>t(n),i?()=>n.locale:void 0);return{view:n,refresh(){n.props=e.props(),n.source=e.source(),n.children=e.children(),n.locale=e.locale()},unmount(){r(),a.unmount()}}}function w(){let e=s(null);return{ref:e,set:t=>{e.value=t??null}}}var T=/* @__PURE__ */ new Map;function E(e){let t=T.get(e);return t||(t=fetch(e,{credentials:`same-origin`}).then(t=>{if(!t.ok)throw Error(`${e}: HTTP ${t.status}`);return t.text()}),t.catch(()=>T.delete(e)),T.set(e,t)),t}function D(e){return e instanceof Error?e.message:String(e)}var O=i;export{C as a,_ as c,w as i,p as l,E as n,S as o,O as r,v as s,D as t};
|