@dvina/widget-kit 0.0.0-stage → 0.0.33

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dvina
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.
@@ -0,0 +1,2 @@
1
+ /** A React widget's source as a browser module (JSX and TypeScript compiled away, imports left as they are). */
2
+ export declare function compileReactWidget(source: string): Promise<{ code: string } | { error: string }>;
@@ -0,0 +1,18 @@
1
+ // src/runtime/compile.ts
2
+ async function compileReactWidget(source) {
3
+ try {
4
+ const { transform } = await import("sucrase");
5
+ const { code } = transform(source, {
6
+ transforms: ["jsx", "typescript"],
7
+ jsxRuntime: "automatic",
8
+ production: true,
9
+ filePath: "widget.tsx"
10
+ });
11
+ return { code };
12
+ } catch (error) {
13
+ return { error: error instanceof Error ? error.message : String(error) };
14
+ }
15
+ }
16
+ export {
17
+ compileReactWidget
18
+ };
@@ -0,0 +1,9 @@
1
+ export type WidgetKind = "html" | "react";
2
+ /** The meta a composed page declares itself with: `<meta name="dvina-widget" content="html|react">`. */
3
+ export declare const WIDGET_PAGE_META: string;
4
+ /** A saved widget as a page of its own: the kit's tokens, stylesheet and script inlined with its code. */
5
+ export declare function composeWidgetPage(input: { kind: WidgetKind; title: string; code: string }): Promise<string>;
6
+ /** Whether a file is a composed widget page, and which kind; null for anything else. */
7
+ export declare function widgetPageKind(page: string): WidgetKind | null;
8
+ /** The widget's own code from a composed page; the text itself for anything else. */
9
+ export declare function widgetSource(page: string): string;
@@ -0,0 +1,82 @@
1
+ // src/runtime/compose.ts
2
+ import {
3
+ kitCss,
4
+ kitReactScript,
5
+ kitScript,
6
+ reactLoaderScript,
7
+ tailwindCss,
8
+ tailwindScript,
9
+ tokensCss
10
+ } from "./index.js";
11
+
12
+ // src/runtime/compile.ts
13
+ async function compileReactWidget(source) {
14
+ try {
15
+ const { transform } = await import("sucrase");
16
+ const { code } = transform(source, {
17
+ transforms: ["jsx", "typescript"],
18
+ jsxRuntime: "automatic",
19
+ production: true,
20
+ filePath: "widget.tsx"
21
+ });
22
+ return { code };
23
+ } catch (error) {
24
+ return { error: error instanceof Error ? error.message : String(error) };
25
+ }
26
+ }
27
+
28
+ // src/runtime/compose.ts
29
+ var WIDGET_PAGE_META = "dvina-widget";
30
+ var START = "<!-- dvina:widget -->";
31
+ var END = "<!-- /dvina:widget -->";
32
+ var escapeHtml = (text) => text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
33
+ var inScript = (text) => text.replace(/<\/(script|style)/gi, "<\\/$1").replace(/<!--/g, "<\\!--");
34
+ var literal = (value) => JSON.stringify(value).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
35
+ function head(kind, title, extra = "") {
36
+ return [
37
+ '<meta charset="utf-8" />',
38
+ '<meta name="viewport" content="width=device-width, initial-scale=1" />',
39
+ `<meta name="${WIDGET_PAGE_META}" content="${kind}" />`,
40
+ `<title>${escapeHtml(title)}</title>`,
41
+ `<style id="dvina-tokens">${inScript(tokensCss)}</style>`,
42
+ `<style id="dvina-kit">${inScript(kitCss)}</style>`,
43
+ `<script id="dvina-kit-script">${inScript(kitScript)}</script>`,
44
+ extra
45
+ ].join("");
46
+ }
47
+ async function composeWidgetPage(input) {
48
+ const title = input.title.trim() || "Widget";
49
+ if (input.kind === "html") {
50
+ return `<!doctype html><html lang="en"><head>${head("html", title)}</head><body>${START}
51
+ ${input.code}
52
+ ${END}</body></html>`;
53
+ }
54
+ const compiled = await compileReactWidget(input.code);
55
+ if ("error" in compiled) throw new Error(`The React widget does not compile: ${compiled.error}`);
56
+ const react = [
57
+ `<style type="text/tailwindcss" id="dvina-tailwind">${inScript(tailwindCss)}</style>`,
58
+ `<script id="dvina-tailwind-script">${inScript(tailwindScript)}</script>`,
59
+ `<script id="dvina-react-loader">${inScript(reactLoaderScript)}</script>`
60
+ ].join("");
61
+ const mount = `var root=document.getElementById("root");window.__dvinaMountReact(root,${literal(compiled.code)},{text:${literal(kitReactScript)}}).catch(function(error){root.textContent=String(error&&error.message||error);});`;
62
+ return `<!doctype html><html lang="en"><head>${head("react", title, react)}</head><body><div id="root"></div><script type="text/plain" id="dvina-widget-source">${START}
63
+ ${inScript(input.code)}
64
+ ${END}</script><script>${mount}</script></body></html>`;
65
+ }
66
+ function widgetPageKind(page) {
67
+ const match = new RegExp(`<meta name="${WIDGET_PAGE_META}" content="(html|react)"`).exec(page.slice(0, 4096));
68
+ return match ? match[1] : null;
69
+ }
70
+ function widgetSource(page) {
71
+ const start = page.indexOf(START);
72
+ const end = page.lastIndexOf(END);
73
+ if (widgetPageKind(page) === null || start < 0 || end < start) return page;
74
+ const code = page.slice(start + START.length, end).replace(/^\n/, "").replace(/\n$/, "");
75
+ return widgetPageKind(page) === "react" ? code.replace(/<\\\/(script|style)/gi, "</$1").replace(/<\\!--/g, "<!--") : code;
76
+ }
77
+ export {
78
+ WIDGET_PAGE_META,
79
+ composeWidgetPage,
80
+ widgetPageKind,
81
+ widgetSource
82
+ };
@@ -0,0 +1,14 @@
1
+ /** The kit's tokens (`--dv-*`), light and dark, in their layer: inlined first wherever the kit is used. */
2
+ export declare const tokensCss: string;
3
+ /** The kit's stylesheet: fonts, bare elements, classes and the SVG kit; no tokens (tokensCss). */
4
+ export declare const kitCss: string;
5
+ /** The kit's script, an IIFE: icons, slider fills, SVG arrow heads, `window.Dvina` (chart themes, formatters). */
6
+ export declare const kitScript: string;
7
+ /** The React components as an IIFE that reads `window.React` and sets `window.DvinaKit`. */
8
+ export declare const kitReactScript: string;
9
+ /** React mode's loader, an IIFE: React from its pinned CDN, the kit's components, then the widget module mounted. */
10
+ export declare const reactLoaderScript: string;
11
+ /** Tailwind's theme over the kit's tokens, as text for a text/tailwindcss style; React artifacts only. */
12
+ export declare const tailwindCss: string;
13
+ /** Tailwind v4's browser build (pinned), which compiles that theme and the classes it finds in the page. */
14
+ export declare const tailwindScript: string;