@glasshome/widget-sdk 1.8.1 → 1.9.0
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/dist/deprecations.js +16 -0
- package/dist/framework/config/index.d.ts +34 -1
- package/dist/framework/core/Widget.d.ts +2 -2
- package/dist/framework/dialogs/validate-config.d.ts +8 -0
- package/dist/framework/hooks/index.d.ts +2 -1
- package/dist/framework/hooks/use-widget-context.d.ts +8 -9
- package/dist/framework/hooks/use-widget-dimensions.d.ts +14 -0
- package/dist/framework/index.d.ts +1 -1
- package/dist/host/index.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +507 -401
- package/dist/tokens-CFl0mCx4.js +33 -0
- package/dist/ui.d.ts +17 -0
- package/dist/vite/index.d.ts +8 -12
- package/dist/vite/index.js +187 -138
- package/dist/vite/introspect.d.ts +4 -10
- package/dist/vite/introspect.js +34 -12
- package/package.json +3 -2
- package/dist/tokens-Bdfb1xYe.js +0 -33
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createContext as e, useContext as t } from "solid-js";
|
|
2
|
+
//#region src/framework/hooks/use-widget-context.ts
|
|
3
|
+
var n = e();
|
|
4
|
+
function r() {
|
|
5
|
+
let e = t(n);
|
|
6
|
+
if (!e) throw Error("useWidgetContext must be used within a Widget component");
|
|
7
|
+
return e;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/framework/theming/tokens.css?raw
|
|
11
|
+
var i = "/* Authoritative SDK CSS contract. Injected once on first Widget mount\n * via framework/theming/tokens.ts.\n *\n * All widget-internal visual scale is driven from CSS custom properties +\n * container queries on the `.glasshome-widget` shell (`container-type: size`).\n * No JS classifier, no size tier enum.\n */\n\n:root {\n --tone-success: oklch(0.70 0.18 145);\n --tone-warning: oklch(0.80 0.17 75);\n --tone-danger: oklch(0.64 0.22 27);\n --tone-info: oklch(0.66 0.20 245);\n --tone-neutral: oklch(0.65 0.02 250);\n --tone-accent: oklch(0.74 0.18 60);\n\n --widget-grad-strength: 1;\n --widget-glow-default: 0.4;\n --widget-border-highlight: oklch(0.98 0 0 / 0.4);\n}\n\n.dark {\n --tone-success: oklch(0.74 0.18 145);\n --tone-warning: oklch(0.82 0.17 75);\n --tone-danger: oklch(0.68 0.22 27);\n --tone-info: oklch(0.70 0.20 245);\n --tone-neutral: oklch(0.69 0.02 250);\n --tone-accent: oklch(0.78 0.18 60);\n\n --widget-grad-strength: 1.1;\n --widget-glow-default: 0.5;\n --widget-border-highlight: oklch(1 0 0 / 0.08);\n}\n\n@property --widget-color {\n syntax: \"<color>\";\n inherits: true;\n initial-value: oklch(0.65 0.02 250);\n}\n\n/* === Widget shell ===\n * Fluid scale tokens — tied to the shell's own container box (cqb=height, cqi=width).\n * Icon/pad/gap track HEIGHT (cqb) not the shortest side: two widgets of equal\n * height match regardless of width (a 2×2 and a 4×2 get the same icon). cqmin\n * starved portrait tiles by pinning the icon to the narrow width. Tune\n * multipliers / clamps to adjust density. */\n.glasshome-widget {\n --widget-color: var(--tone-neutral);\n --widget-glow-strength: var(--widget-glow-default);\n\n --widget-icon-box: clamp(44px, 25cqb, 58px);\n --widget-icon-glyph: clamp(24px, 14cqb, 33px);\n --widget-pad: clamp(8px, 3.5cqb, 22px);\n --widget-gap: clamp(6px, 2cqb, 14px);\n --widget-title-size: clamp(12px, 2cqi, 18px);\n --widget-subtitle: clamp(12px, 2.5cqi, 20px);\n --widget-status-size: clamp(14px, 5cqi, 36px);\n --widget-value-size: clamp(18px, 7cqi, 48px);\n --widget-badge-size: clamp(11px, 1.6cqi, 14px);\n}\n\n/* Shell material. Two channels, both host/variant-driven:\n * - `--widget-backdrop`: the live backdrop filter (the shared glass recipe is\n * blur + saturate, matching ui's CARD_BLUR). Default none — a variant opts\n * in (classic-glass), and a performant-blur host disables it via override\n * sheet when it paints a precomputed frost instead.\n * - `--glass-frost`: one full background layer (image + position / size +\n * repeat) composited at the BOTTOM, under the accent gradient — the same\n * frost slot ui's `.glass` formula ends its background list with. Unset →\n * none. A performant-blur host sets it per shell with the viewport-aligned\n * slice of its pre-blurred bitmap. */\n.glasshome-widget {\n background:\n var(--widget-gradient,\n linear-gradient(135deg,\n color-mix(in oklch, var(--widget-color) calc(22% * var(--widget-grad-strength)), transparent),\n color-mix(in oklch, var(--widget-color-to, var(--widget-color)) calc(11% * var(--widget-grad-strength)), transparent)\n )\n ),\n var(--glass-frost, none);\n backdrop-filter: var(--widget-backdrop, none);\n -webkit-backdrop-filter: var(--widget-backdrop, none);\n box-shadow: inset 0 1px 0 var(--widget-border-highlight);\n}\n\n/* === Slot: content layout === */\n/* Default: column. Flip to row only on wide-and-short widgets (matches the\n * old contentLayout heuristic: aspect > 1 AND height < 150px). */\n.glasshome-widget-content {\n position: relative;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n width: 100%;\n height: 100%;\n padding: var(--widget-pad);\n gap: var(--widget-gap);\n overflow: hidden;\n}\n@container widget (min-aspect-ratio: 1) and (max-height: 149px) {\n .glasshome-widget-content {\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n }\n}\n\n/* === Compact 1×1 ===\n * Small in BOTH axes → stack the tile: icon on top, label + status centered\n * under it. Icon stays moderate (not a hero) so the text keeps room. Wide\n * tiles (2×1) fail the width test and keep the row layout above. Placed after\n * the row-flip so it wins. */\n@container widget (max-width: 189px) and (max-height: 189px) {\n .glasshome-widget-content {\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n gap: clamp(4px, 2.5cqmin, 8px);\n }\n .glasshome-widget-content > * { align-items: center; text-align: center; }\n .glasshome-widget-icon {\n --widget-icon-box: clamp(36px, 30cqmin, 56px);\n --widget-icon-glyph: clamp(20px, 17cqmin, 32px);\n }\n .glasshome-widget-title { font-size: clamp(11px, 6cqmin, 14px); max-width: 100%; }\n .glasshome-widget-status,\n .glasshome-widget-value { font-size: clamp(13px, 7cqmin, 17px); }\n .glasshome-widget-content [class*=\"ml-auto\"] { margin-left: 0 !important; }\n}\n.glasshome-widget-content [class*=\"ml-auto\"] {\n position: relative;\n z-index: 30;\n}\n\n/* === Slot: icon === */\n.glasshome-widget-icon {\n width: var(--widget-icon-box);\n height: var(--widget-icon-box);\n border-radius: var(--radius-sm, 12px);\n background: var(--widget-icon-color, var(--widget-color));\n box-shadow: 0 0 calc(var(--widget-glow-strength) * 30px)\n color-mix(in oklch, var(--widget-icon-color, var(--widget-color)) 50%, transparent);\n color: oklch(from var(--widget-icon-color, var(--widget-color)) calc(0.52 + sign(0.5 - l) * 0.43) calc(c * 0.2) h);\n}\n.glasshome-widget-icon-glyph {\n font-size: var(--widget-icon-glyph);\n line-height: 1;\n}\n.glasshome-widget-icon-stack {\n position: absolute;\n width: 102%;\n height: 102%;\n border-radius: var(--radius-sm, 12px);\n}\n.glasshome-widget-icon-stack-2 { bottom: -14%; right: -10%; opacity: 0.45; z-index: -2; }\n.glasshome-widget-icon-stack-3 { bottom: -28%; right: -20%; opacity: 0.20; z-index: -3; }\n\n/* === Slot: text === */\n.glasshome-widget-title {\n font-size: var(--widget-title-size);\n line-height: 1.2;\n color: color-mix(in oklch, var(--color-foreground, currentColor) 60%, transparent);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.glasshome-widget-subtitle {\n font-size: var(--widget-subtitle);\n color: color-mix(in oklch, var(--color-foreground, currentColor) 60%, transparent);\n}\n.glasshome-widget-status {\n font-size: var(--widget-status-size);\n font-weight: 700;\n color: var(--color-foreground, currentColor);\n line-height: 1.1;\n}\n.glasshome-widget-value {\n font-size: var(--widget-value-size);\n font-weight: 700;\n color: var(--color-foreground, currentColor);\n line-height: 1.05;\n}\n.glasshome-widget-badge {\n font-size: var(--widget-badge-size);\n font-weight: 500;\n padding: 0.125rem 0.5rem;\n border-radius: 9999px;\n background: color-mix(in oklch, var(--color-foreground, currentColor) 20%, transparent);\n color: var(--color-foreground, currentColor);\n}\n\n.glasshome-widget-loading {\n background: color-mix(in oklch, var(--widget-color) 20%, transparent);\n}\n\n/* === Slider fill ===\n * Value flows in via --widget-fill-value (0-100). Vertical orientation auto-\n * detected via container query. */\n.glasshome-widget-slider-fill {\n --widget-fill-value: 0;\n background: color-mix(in oklch, var(--widget-icon-color, var(--widget-color)) 30%, transparent);\n box-shadow: 0 0 calc(var(--widget-glow-strength) * 40px)\n color-mix(in oklch, var(--widget-icon-color, var(--widget-color)) 40%, transparent);\n clip-path: inset(0 calc((100 - var(--widget-fill-value)) * 1%) 0 0);\n}\n@container widget (max-aspect-ratio: 1) {\n .glasshome-widget-slider-fill {\n clip-path: inset(calc((100 - var(--widget-fill-value)) * 1%) 0 0 0);\n }\n}\n", a = !1, o, s = /* @__PURE__ */ new WeakSet();
|
|
12
|
+
function c() {
|
|
13
|
+
return o || (o = new CSSStyleSheet(), o.replaceSync(i.replace(/:root\b/g, ":host").replace(/^\.dark\b/gm, ":host(.dark)"))), o;
|
|
14
|
+
}
|
|
15
|
+
function l(e) {
|
|
16
|
+
if (typeof ShadowRoot < "u" && e instanceof ShadowRoot) {
|
|
17
|
+
if (s.has(e)) return;
|
|
18
|
+
let t = c();
|
|
19
|
+
e.adoptedStyleSheets.includes(t) || (e.adoptedStyleSheets = [...e.adoptedStyleSheets, t]), s.add(e);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (a) return;
|
|
23
|
+
let t = e ?? (typeof document > "u" ? void 0 : document);
|
|
24
|
+
if (!t) return;
|
|
25
|
+
if (t.head.querySelector?.("style[data-glasshome-tokens]")) {
|
|
26
|
+
a = !0;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
let n = t.createElement("style");
|
|
30
|
+
n.setAttribute("data-glasshome-tokens", ""), n.textContent = i, t.head.appendChild(n), a = !0;
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { n, r, l as t };
|
package/dist/ui.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host UI primitives, re-exported so the SDK is the single gated door.
|
|
3
|
+
*
|
|
4
|
+
* The host serves `@glasshome/ui/solid` through its import map with no compat
|
|
5
|
+
* check of its own, so a widget importing it directly is exposed to ui drift
|
|
6
|
+
* across the Hub auto-update boundary. Routed through here, the same
|
|
7
|
+
* primitives sit behind `sdkVersion` — the one contract `checkSdkCompat`
|
|
8
|
+
* enforces (same model as the sync-layer hooks).
|
|
9
|
+
*
|
|
10
|
+
* The set is exactly what shipped widgets use; extending it is an additive
|
|
11
|
+
* SDK minor. Direct `@glasshome/ui` imports keep working but are deprecated
|
|
12
|
+
* (`direct-ui-import` in the registry), removed in 2.0.0.
|
|
13
|
+
*
|
|
14
|
+
* `@glasshome/ui/solid` is a vite external of this package: these re-exports
|
|
15
|
+
* resolve to the host-provided singleton at runtime, never a bundled copy.
|
|
16
|
+
*/
|
|
17
|
+
export { Badge, Button, type Color, ColorSlider, ColorWheel, Input, Label, parseColor, ResponsiveDialog, ResponsiveDialogContent, ResponsiveDialogDescription, ResponsiveDialogHeader, ResponsiveDialogTitle, SchemaForm, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Slider, Switch, } from "@glasshome/ui/solid";
|
package/dist/vite/index.d.ts
CHANGED
|
@@ -11,18 +11,6 @@ export interface GlasshomeWidgetOptions {
|
|
|
11
11
|
* author decide which states matter rather than discovering the loss never.
|
|
12
12
|
*/
|
|
13
13
|
export declare const MAX_EXAMPLES = 20;
|
|
14
|
-
/**
|
|
15
|
-
* Configuration-drift guard (D-11). Reads the built bundle, derives the JSON
|
|
16
|
-
* Schema from its configSchema, and compares against the recorded
|
|
17
|
-
* `.schema-hash`. A shape change without a configVersion bump fails the build:
|
|
18
|
-
* tsc cannot catch this class of break because the old persisted config still
|
|
19
|
-
* parses, only its meaning shifts. Legacy plain-hash records (written by
|
|
20
|
-
* pre-1.7 builds) cannot prove a missing bump, so they only warn, then upgrade
|
|
21
|
-
* to the JSON record format.
|
|
22
|
-
*
|
|
23
|
-
* When `manifestPath` is given (single-widget projects), the generated JSON
|
|
24
|
-
* Schema is also written into `manifest.json` as `schema`.
|
|
25
|
-
*/
|
|
26
14
|
export declare function runSchemaGuard(args: {
|
|
27
15
|
outFile: string;
|
|
28
16
|
hashFile: string;
|
|
@@ -37,6 +25,14 @@ export declare function runSchemaGuard(args: {
|
|
|
37
25
|
* must be bundled, because leaving it external is a runtime 404.
|
|
38
26
|
*/
|
|
39
27
|
export declare function isWidgetExternal(id: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* True when a widget source file imports `@glasshome/ui` directly. The regex is
|
|
30
|
+
* the registry's `sourcePattern` for `direct-ui-import`, so the build warning and
|
|
31
|
+
* the widget-cli lint can never disagree on what counts as a direct import.
|
|
32
|
+
* node_modules is excluded: dependencies and the SDK's own generated entries in
|
|
33
|
+
* BUILD_CACHE_DIR (the theme `@import`) are the SDK's business, not the widget's.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isDirectUiImportSource(id: string, code: string): boolean;
|
|
40
36
|
interface DiscoveredWidget {
|
|
41
37
|
name: string;
|
|
42
38
|
entry: string;
|
package/dist/vite/index.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
1
|
+
import { deprecations as e, formatDeprecation as t } from "../deprecations.js";
|
|
2
|
+
import { formatSchemaError as n, isHostProvidedModule as r, widgetManifestSchema as i } from "@glasshome/widget-contract";
|
|
3
|
+
import { spawnSync as a } from "node:child_process";
|
|
4
|
+
import { createHash as o } from "node:crypto";
|
|
5
|
+
import { existsSync as s, mkdirSync as c, readFileSync as l, readdirSync as u, rmSync as d, statSync as f, writeFileSync as p } from "node:fs";
|
|
6
|
+
import { createRequire as m } from "node:module";
|
|
7
|
+
import { dirname as h, join as g, relative as _, resolve as v, sep as y } from "node:path";
|
|
8
|
+
import { fileURLToPath as b } from "node:url";
|
|
9
|
+
import x from "@tailwindcss/vite";
|
|
9
10
|
//#region src/vite/index.ts
|
|
10
|
-
function
|
|
11
|
+
function S(e) {
|
|
11
12
|
let t = JSON.stringify(e, Object.keys(e).sort());
|
|
12
|
-
return
|
|
13
|
+
return o("sha256").update(t).digest("hex").slice(0, 16);
|
|
13
14
|
}
|
|
14
|
-
var
|
|
15
|
-
async function
|
|
15
|
+
var C = 20;
|
|
16
|
+
async function w(e, t) {
|
|
16
17
|
if (e === void 0) return;
|
|
17
18
|
let n;
|
|
18
19
|
try {
|
|
@@ -32,13 +33,21 @@ async function x(e, t) {
|
|
|
32
33
|
let a = i.error.issues.map((e) => ` examples${e.path.length ? `[${e.path.join("][")}]` : ""}: ${e.message}`).join("\n");
|
|
33
34
|
throw Error(`[widget-sdk] Invalid \`examples\` for "${t}":\n${a}\nEach example needs a \`config\` object and a \`size\` of whole positive tiles, and at most 20 are rendered.`);
|
|
34
35
|
}
|
|
35
|
-
function
|
|
36
|
-
|
|
36
|
+
function T(e, t) {
|
|
37
|
+
if (!e?.length) return;
|
|
38
|
+
let n = e.map((e) => {
|
|
39
|
+
let t = e.label ? `"${e.label}"` : `#${e.index}`;
|
|
40
|
+
return [` examples[${e.index}] ${t}:`, ...e.problems.map((e) => ` ${e}`)].join("\n");
|
|
41
|
+
}).join("\n");
|
|
42
|
+
throw Error(`[widget-sdk] Example config rejected by "${t}"'s own configSchema:\n${n}\nEach example's \`config\` must be a config the widget would actually accept, or its preview renders empty.`);
|
|
43
|
+
}
|
|
44
|
+
function E(e) {
|
|
45
|
+
let t = h(b(import.meta.url)), n = [g(t, "introspect.js"), g(t, "introspect.ts")].find((e) => s(e));
|
|
37
46
|
if (!n) return {
|
|
38
47
|
ok: !1,
|
|
39
48
|
reason: `introspect not found next to ${t}`
|
|
40
49
|
};
|
|
41
|
-
let
|
|
50
|
+
let r = a(process.execPath, [
|
|
42
51
|
"--conditions",
|
|
43
52
|
"browser",
|
|
44
53
|
n,
|
|
@@ -47,18 +56,18 @@ function S(e) {
|
|
|
47
56
|
encoding: "utf-8",
|
|
48
57
|
timeout: 3e4
|
|
49
58
|
});
|
|
50
|
-
if (
|
|
59
|
+
if (r.error) return {
|
|
51
60
|
ok: !1,
|
|
52
|
-
reason:
|
|
61
|
+
reason: r.error.message
|
|
53
62
|
};
|
|
54
|
-
if (
|
|
63
|
+
if (r.status !== 0) return {
|
|
55
64
|
ok: !1,
|
|
56
|
-
reason: (
|
|
65
|
+
reason: (r.stderr || "").trim().split("\n")[0] || `exit ${r.status}`
|
|
57
66
|
};
|
|
58
67
|
try {
|
|
59
68
|
return {
|
|
60
69
|
ok: !0,
|
|
61
|
-
value: JSON.parse(
|
|
70
|
+
value: JSON.parse(r.stdout)
|
|
62
71
|
};
|
|
63
72
|
} catch {
|
|
64
73
|
return {
|
|
@@ -67,49 +76,60 @@ function S(e) {
|
|
|
67
76
|
};
|
|
68
77
|
}
|
|
69
78
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
let
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (
|
|
87
|
-
|
|
79
|
+
var D = [
|
|
80
|
+
"schema",
|
|
81
|
+
"defaultConfig",
|
|
82
|
+
"examples",
|
|
83
|
+
"configVersion"
|
|
84
|
+
];
|
|
85
|
+
function O(e, t, n) {
|
|
86
|
+
let r = l(e, "utf-8"), i = JSON.parse(r), a = {
|
|
87
|
+
...t.manifest ?? {},
|
|
88
|
+
schema: n
|
|
89
|
+
};
|
|
90
|
+
for (let e of D) a[e] !== void 0 && (i[e] = a[e]);
|
|
91
|
+
let o = `${JSON.stringify(i, null, 2)}\n`;
|
|
92
|
+
o !== r && p(e, o);
|
|
93
|
+
}
|
|
94
|
+
async function k(e) {
|
|
95
|
+
if (!s(e.outFile)) return;
|
|
96
|
+
let t = E(e.outFile);
|
|
97
|
+
if (!t.ok) throw Error(`[widget-sdk] Could not read "${e.widgetName}" to check it: ${t.reason}\n Its examples and config schema could not be validated, so the build cannot continue.
|
|
98
|
+
This usually means the bundle throws while being imported.`);
|
|
99
|
+
let n = t.value, r = n.manifest?.name ?? e.widgetName;
|
|
100
|
+
await w(n.manifest?.examples, r), T(n.exampleConfigIssues, r);
|
|
101
|
+
let i = n.jsonSchema;
|
|
102
|
+
if (!i) return;
|
|
103
|
+
e.manifestPath && s(e.manifestPath) && O(e.manifestPath, n, i);
|
|
104
|
+
let a = S(i), o = n.manifest?.configVersion ?? null, c = n.manifest?.name ?? e.widgetName;
|
|
105
|
+
if (s(e.hashFile)) {
|
|
106
|
+
let t = l(e.hashFile, "utf-8").trim(), n = null;
|
|
88
107
|
if (t.startsWith("{")) try {
|
|
89
108
|
n = JSON.parse(t);
|
|
90
109
|
} catch {
|
|
91
110
|
n = null;
|
|
92
111
|
}
|
|
93
112
|
if (n) {
|
|
94
|
-
if (n.hash !==
|
|
95
|
-
} else t !==
|
|
113
|
+
if (n.hash !== a && n.configVersion === o) throw Error(`[widget-sdk] Config schema shape changed for "${c}" without a configVersion bump. Bump configVersion in defineWidget (currently ${o ?? "unset"}) or revert the schema change, then rebuild. Recorded in ${e.hashFile}`);
|
|
114
|
+
} else t !== a && console.warn(`[widget-sdk] Schema shape changed for "${c}" — verify configVersion was bumped`);
|
|
96
115
|
}
|
|
97
|
-
|
|
98
|
-
hash:
|
|
116
|
+
p(e.hashFile, `${JSON.stringify({
|
|
117
|
+
hash: a,
|
|
99
118
|
configVersion: o
|
|
100
119
|
})}\n`);
|
|
101
120
|
}
|
|
102
|
-
var
|
|
103
|
-
function
|
|
104
|
-
return
|
|
121
|
+
var A = "virtual:glasshome-widget", j = "\0virtual:glasshome-widget", M = "/@glasshome/preview";
|
|
122
|
+
function N(e) {
|
|
123
|
+
return y === "\\" ? e.split(y).join("/") : e;
|
|
105
124
|
}
|
|
106
|
-
function
|
|
107
|
-
|
|
125
|
+
function P() {
|
|
126
|
+
let e = b(import.meta.url);
|
|
127
|
+
return v(h(e), "../../preview");
|
|
108
128
|
}
|
|
109
|
-
function
|
|
110
|
-
return
|
|
129
|
+
function F(e) {
|
|
130
|
+
return r(e);
|
|
111
131
|
}
|
|
112
|
-
function
|
|
132
|
+
function I() {
|
|
113
133
|
return {
|
|
114
134
|
name: "glasshome-widget:sync-layer-guard",
|
|
115
135
|
apply: "build",
|
|
@@ -119,15 +139,38 @@ function A() {
|
|
|
119
139
|
}
|
|
120
140
|
};
|
|
121
141
|
}
|
|
122
|
-
var
|
|
123
|
-
function
|
|
142
|
+
var L = /\.(ts|tsx|js|jsx)$/;
|
|
143
|
+
function R(t, n) {
|
|
144
|
+
let r = N(t).split("?")[0] ?? "";
|
|
145
|
+
if (r.includes("/node_modules/") || !L.test(r)) return !1;
|
|
146
|
+
let i = e.find((e) => e.id === "direct-ui-import");
|
|
147
|
+
return i?.sourcePattern ? new RegExp(i.sourcePattern).test(n) : !1;
|
|
148
|
+
}
|
|
149
|
+
function z() {
|
|
150
|
+
let n = /* @__PURE__ */ new Set();
|
|
151
|
+
return {
|
|
152
|
+
name: "glasshome-widget:ui-import-guard",
|
|
153
|
+
apply: "build",
|
|
154
|
+
enforce: "pre",
|
|
155
|
+
transform(e, t) {
|
|
156
|
+
return R(t, e) && n.add(N(_(process.cwd(), t.split("?")[0] ?? t))), null;
|
|
157
|
+
},
|
|
158
|
+
buildEnd() {
|
|
159
|
+
if (n.size === 0) return;
|
|
160
|
+
let r = e.find((e) => e.id === "direct-ui-import"), i = r ? t(r) : "[@glasshome/widget-sdk] Direct @glasshome/ui imports are deprecated; import the same export from \"@glasshome/widget-sdk\".", a = [...n].map((e) => ` ${e}`).join("\n");
|
|
161
|
+
console.warn(`${i}\n Direct @glasshome/ui import(s) in:\n${a}`);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
var B = "node_modules/.cache/glasshome-widgets";
|
|
166
|
+
function V(e) {
|
|
124
167
|
try {
|
|
125
|
-
return
|
|
168
|
+
return m(g(process.cwd(), "package.json")).resolve(e);
|
|
126
169
|
} catch {
|
|
127
170
|
return null;
|
|
128
171
|
}
|
|
129
172
|
}
|
|
130
|
-
var
|
|
173
|
+
var H = [
|
|
131
174
|
"--radius",
|
|
132
175
|
"--background",
|
|
133
176
|
"--foreground",
|
|
@@ -137,128 +180,130 @@ var N = [
|
|
|
137
180
|
"--muted",
|
|
138
181
|
"--accent"
|
|
139
182
|
];
|
|
140
|
-
function
|
|
141
|
-
let n =
|
|
142
|
-
if (!
|
|
143
|
-
let r =
|
|
183
|
+
function U(e, t) {
|
|
184
|
+
let n = g(e, `${t}.css`);
|
|
185
|
+
if (!s(n)) return;
|
|
186
|
+
let r = l(n, "utf-8");
|
|
144
187
|
for (let e of r.matchAll(/:host[^{]*\{([^}]*)\}/g)) {
|
|
145
|
-
let n = e[1] ?? "", r =
|
|
188
|
+
let n = e[1] ?? "", r = H.find((e) => n.includes(`${e}:`));
|
|
146
189
|
if (r) throw Error(`[glasshome-widget] "${t}.css" defines theme variable "${r}" on :host. Theme variables must inherit from the document so widgets follow the household theme — never re-scope them into the widget's shadow root.`);
|
|
147
190
|
}
|
|
148
191
|
}
|
|
149
|
-
function
|
|
150
|
-
let r =
|
|
151
|
-
|
|
152
|
-
let i =
|
|
192
|
+
function W(e, t, n) {
|
|
193
|
+
let r = v(e, B);
|
|
194
|
+
c(r, { recursive: !0 });
|
|
195
|
+
let i = V("@glasshome/ui/styles");
|
|
153
196
|
if (!i) throw Error("[widget-sdk] @glasshome/ui is required to build widgets (it provides the theme every GlassHome widget ships with). Add it to your widget's dependencies.");
|
|
154
|
-
let
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
...l ? [
|
|
158
|
-
|
|
159
|
-
].filter((e) =>
|
|
160
|
-
d
|
|
197
|
+
let a = v(h(i), "../.."), o = V("@glasshome/widget-sdk/tailwind-sources"), l = o ? h(o) : null, u = [
|
|
198
|
+
g(a, "src"),
|
|
199
|
+
g(a, "dist"),
|
|
200
|
+
...l ? [g(l, "src"), g(l, "dist")] : [],
|
|
201
|
+
h(n)
|
|
202
|
+
].filter((e) => s(e)), d = v(r, `${t}.tailwind.css`);
|
|
203
|
+
p(d, [
|
|
161
204
|
"@import \"tailwindcss\" source(none);",
|
|
162
205
|
"@import \"tw-animate-css\";",
|
|
163
206
|
"@import \"@glasshome/ui/styles/theme\";",
|
|
164
|
-
...u.map((e) => `@source "${
|
|
207
|
+
...u.map((e) => `@source "${N(e)}";`),
|
|
165
208
|
"@custom-variant dark {",
|
|
166
209
|
" &:is(.dark *) { @slot }",
|
|
167
210
|
" :host(.dark) & { @slot }",
|
|
168
211
|
"}",
|
|
169
212
|
""
|
|
170
213
|
].join("\n"));
|
|
171
|
-
let
|
|
172
|
-
return
|
|
173
|
-
`import "${
|
|
174
|
-
`export { default } from "${
|
|
214
|
+
let f = v(r, `${t}.entry.ts`);
|
|
215
|
+
return p(f, [
|
|
216
|
+
`import "${N(d)}";`,
|
|
217
|
+
`export { default } from "${N(n)}";`,
|
|
175
218
|
""
|
|
176
|
-
].join("\n")),
|
|
219
|
+
].join("\n")), f;
|
|
177
220
|
}
|
|
178
|
-
function
|
|
179
|
-
let e =
|
|
221
|
+
function G() {
|
|
222
|
+
let e = x();
|
|
180
223
|
for (let t of e) t.apply ??= "build";
|
|
181
224
|
return e;
|
|
182
225
|
}
|
|
183
|
-
function
|
|
226
|
+
function K(e) {
|
|
184
227
|
let t = [];
|
|
185
|
-
if (!
|
|
186
|
-
for (let n of
|
|
187
|
-
let r =
|
|
188
|
-
if (!
|
|
189
|
-
let i =
|
|
190
|
-
|
|
228
|
+
if (!s(e)) return t;
|
|
229
|
+
for (let n of u(e)) {
|
|
230
|
+
let r = v(e, n);
|
|
231
|
+
if (!f(r).isDirectory()) continue;
|
|
232
|
+
let i = v(r, "index.tsx"), a = v(r, "manifest.json");
|
|
233
|
+
s(i) && s(a) && t.push({
|
|
191
234
|
name: n,
|
|
192
235
|
entry: i
|
|
193
236
|
});
|
|
194
237
|
}
|
|
195
238
|
return t;
|
|
196
239
|
}
|
|
197
|
-
function
|
|
198
|
-
let
|
|
199
|
-
if (
|
|
200
|
-
if (!
|
|
201
|
-
let
|
|
202
|
-
if (!
|
|
203
|
-
let
|
|
204
|
-
if (!
|
|
205
|
-
let
|
|
206
|
-
|
|
207
|
-
...
|
|
208
|
-
bundleUrl: `./${
|
|
209
|
-
...
|
|
240
|
+
function q(e, t) {
|
|
241
|
+
let r = [];
|
|
242
|
+
if (s(e)) for (let a of u(e)) {
|
|
243
|
+
if (!f(g(e, a)).isDirectory()) continue;
|
|
244
|
+
let o = g(e, a, "manifest.json");
|
|
245
|
+
if (!s(o)) continue;
|
|
246
|
+
let c = i.safeParse(JSON.parse(l(o, "utf-8")));
|
|
247
|
+
if (!c.success) throw Error(`[registry] Invalid manifest for "${a}": ${n(c.error)}`);
|
|
248
|
+
let u = s(g(t, `${a}.css`));
|
|
249
|
+
r.push({
|
|
250
|
+
...c.data,
|
|
251
|
+
bundleUrl: `./${a}.js`,
|
|
252
|
+
...u ? { cssUrl: `./${a}.css` } : {}
|
|
210
253
|
});
|
|
211
254
|
}
|
|
212
|
-
let
|
|
255
|
+
let a = {
|
|
213
256
|
version: 1,
|
|
214
257
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
215
258
|
baseUrl: "./",
|
|
216
|
-
widgets:
|
|
259
|
+
widgets: r
|
|
217
260
|
};
|
|
218
|
-
|
|
261
|
+
s(t) || c(t, { recursive: !0 }), p(g(t, "registry.json"), JSON.stringify(a, null, 2)), console.log(`[registry] Generated registry.json with ${r.length} widget(s)`);
|
|
219
262
|
}
|
|
220
|
-
async function
|
|
221
|
-
let { build: t } = await import("vite"), n = process.cwd(), r =
|
|
222
|
-
if (
|
|
263
|
+
async function J(e) {
|
|
264
|
+
let { build: t } = await import("vite"), n = process.cwd(), r = v(n, e?.srcDir ?? "src"), i = v(n, e?.outDir ?? "dist"), a = K(r);
|
|
265
|
+
if (a.length === 0) {
|
|
223
266
|
console.warn("[glasshome-widgets] No widgets found in", r);
|
|
224
267
|
return;
|
|
225
268
|
}
|
|
226
269
|
if (e?.only) {
|
|
227
270
|
let t = new Set(e.only);
|
|
228
|
-
|
|
271
|
+
a = a.filter((e) => t.has(e.name));
|
|
229
272
|
}
|
|
230
|
-
e?.only ||
|
|
231
|
-
for (let r of
|
|
273
|
+
e?.only || s(i) && d(i, { recursive: !0 }), s(i) || c(i, { recursive: !0 });
|
|
274
|
+
for (let r of a) await t({
|
|
232
275
|
configFile: !1,
|
|
233
276
|
root: n,
|
|
234
277
|
plugins: [
|
|
235
|
-
...
|
|
278
|
+
...G(),
|
|
236
279
|
...e?.plugins ?? [],
|
|
237
|
-
|
|
280
|
+
I(),
|
|
281
|
+
z()
|
|
238
282
|
],
|
|
239
283
|
...e?.viteConfig,
|
|
240
284
|
build: {
|
|
241
285
|
lib: {
|
|
242
|
-
entry:
|
|
286
|
+
entry: W(n, r.name, r.entry),
|
|
243
287
|
formats: ["es"],
|
|
244
288
|
fileName: r.name,
|
|
245
289
|
cssFileName: r.name
|
|
246
290
|
},
|
|
247
|
-
rollupOptions: { external:
|
|
291
|
+
rollupOptions: { external: F },
|
|
248
292
|
outDir: i,
|
|
249
293
|
emptyOutDir: !1,
|
|
250
294
|
copyPublicDir: !1,
|
|
251
295
|
...e?.viteConfig?.build
|
|
252
296
|
},
|
|
253
297
|
logLevel: "warn"
|
|
254
|
-
}),
|
|
255
|
-
outFile:
|
|
256
|
-
hashFile:
|
|
257
|
-
widgetName: r.name
|
|
298
|
+
}), U(i, r.name), await k({
|
|
299
|
+
outFile: g(i, `${r.name}.js`),
|
|
300
|
+
hashFile: g(h(r.entry), ".schema-hash"),
|
|
301
|
+
widgetName: r.name,
|
|
302
|
+
manifestPath: g(h(r.entry), "manifest.json")
|
|
258
303
|
});
|
|
259
|
-
|
|
304
|
+
q(r, i);
|
|
260
305
|
}
|
|
261
|
-
function
|
|
306
|
+
function Y(e) {
|
|
262
307
|
let t = e?.entry ?? "src/index.tsx", n = {
|
|
263
308
|
name: "glasshome-widget:build",
|
|
264
309
|
apply: "build",
|
|
@@ -266,12 +311,12 @@ function B(e) {
|
|
|
266
311
|
let e = process.cwd();
|
|
267
312
|
return { build: {
|
|
268
313
|
lib: {
|
|
269
|
-
entry:
|
|
314
|
+
entry: W(e, "index", v(e, t)),
|
|
270
315
|
formats: ["es"],
|
|
271
316
|
fileName: "index",
|
|
272
317
|
cssFileName: "index"
|
|
273
318
|
},
|
|
274
|
-
rollupOptions: { external:
|
|
319
|
+
rollupOptions: { external: F }
|
|
275
320
|
} };
|
|
276
321
|
}
|
|
277
322
|
}, r = {
|
|
@@ -279,19 +324,19 @@ function B(e) {
|
|
|
279
324
|
apply: "serve",
|
|
280
325
|
enforce: "pre",
|
|
281
326
|
config() {
|
|
282
|
-
let e =
|
|
327
|
+
let e = P(), t = process.cwd();
|
|
283
328
|
return { server: { fs: { allow: [
|
|
284
329
|
e,
|
|
285
330
|
t,
|
|
286
|
-
|
|
331
|
+
v(t, "..", "..")
|
|
287
332
|
] } } };
|
|
288
333
|
},
|
|
289
334
|
configureServer(e) {
|
|
290
|
-
let t =
|
|
291
|
-
e.middlewares.use(async (
|
|
292
|
-
if (
|
|
293
|
-
let i =
|
|
294
|
-
i = await e.transformIndexHtml(
|
|
335
|
+
let t = P(), n = g(t, "preview.html");
|
|
336
|
+
e.middlewares.use(async (t, r, i) => {
|
|
337
|
+
if (t.url === "/" || t.url === "/index.html") try {
|
|
338
|
+
let i = l(n, "utf-8");
|
|
339
|
+
i = await e.transformIndexHtml(t.url, i), r.setHeader("Content-Type", "text/html"), r.statusCode = 200, r.end(i);
|
|
295
340
|
} catch (e) {
|
|
296
341
|
i(e);
|
|
297
342
|
}
|
|
@@ -299,33 +344,37 @@ function B(e) {
|
|
|
299
344
|
});
|
|
300
345
|
},
|
|
301
346
|
resolveId(e) {
|
|
302
|
-
if (e ===
|
|
303
|
-
|
|
347
|
+
if (e === M) {
|
|
348
|
+
let e = P();
|
|
349
|
+
return N(g(e, "host.tsx"));
|
|
350
|
+
}
|
|
351
|
+
if (e === A) return j;
|
|
304
352
|
},
|
|
305
353
|
load(e) {
|
|
306
|
-
if (e ===
|
|
354
|
+
if (e === j) return `export { default } from "${N(v(process.cwd(), t))}";`;
|
|
307
355
|
}
|
|
308
356
|
}, i = {
|
|
309
357
|
name: "glasshome-widget:schema",
|
|
310
358
|
apply: "build",
|
|
311
359
|
async closeBundle() {
|
|
312
|
-
|
|
313
|
-
outFile:
|
|
314
|
-
hashFile:
|
|
360
|
+
U(v(process.cwd(), "dist"), "index"), await k({
|
|
361
|
+
outFile: v(process.cwd(), "dist", "index.js"),
|
|
362
|
+
hashFile: v(process.cwd(), ".schema-hash"),
|
|
315
363
|
widgetName: "index",
|
|
316
|
-
manifestPath:
|
|
364
|
+
manifestPath: v(process.cwd(), "manifest.json")
|
|
317
365
|
});
|
|
318
366
|
}
|
|
319
367
|
};
|
|
320
368
|
return [
|
|
321
|
-
...
|
|
369
|
+
...G(),
|
|
322
370
|
n,
|
|
323
|
-
|
|
371
|
+
I(),
|
|
372
|
+
z(),
|
|
324
373
|
i,
|
|
325
374
|
r
|
|
326
375
|
];
|
|
327
376
|
}
|
|
328
|
-
function
|
|
377
|
+
function X(e) {
|
|
329
378
|
let t = e?.srcDir ?? "src", n = e?.outDir ?? "dist", r = [];
|
|
330
379
|
return [{
|
|
331
380
|
name: "glasshome-widgets:build",
|
|
@@ -344,7 +393,7 @@ function V(e) {
|
|
|
344
393
|
if (e === "\0glasshome-noop") return "export {}";
|
|
345
394
|
},
|
|
346
395
|
async closeBundle() {
|
|
347
|
-
await
|
|
396
|
+
await J({
|
|
348
397
|
srcDir: t,
|
|
349
398
|
outDir: n,
|
|
350
399
|
plugins: r
|
|
@@ -353,4 +402,4 @@ function V(e) {
|
|
|
353
402
|
}];
|
|
354
403
|
}
|
|
355
404
|
//#endregion
|
|
356
|
-
export {
|
|
405
|
+
export { C as MAX_EXAMPLES, J as buildWidgets, K as discoverWidgets, q as generateRegistry, Y as glasshomeWidget, X as glasshomeWidgets, R as isDirectUiImportSource, F as isWidgetExternal, k as runSchemaGuard };
|
|
@@ -14,14 +14,8 @@
|
|
|
14
14
|
* Usage: bun --conditions browser introspect.js <bundle.js>
|
|
15
15
|
* Prints: { manifest, jsonSchema } on stdout, or exits non-zero with a reason.
|
|
16
16
|
*/
|
|
17
|
-
interface
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
examples?: unknown;
|
|
22
|
-
} | null;
|
|
23
|
-
/** JSON Schema derived from the widget's configSchema, when it has one. */
|
|
24
|
-
jsonSchema: object | null;
|
|
17
|
+
export interface ExampleConfigIssue {
|
|
18
|
+
index: number;
|
|
19
|
+
label?: string;
|
|
20
|
+
problems: string[];
|
|
25
21
|
}
|
|
26
|
-
declare function installDom(): Promise<void>;
|
|
27
|
-
declare function main(): Promise<void>;
|