@glasshome/widget-sdk 1.8.0 → 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 +511 -404
- 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 +214 -134
- package/dist/vite/introspect.d.ts +21 -0
- package/dist/vite/introspect.js +59 -0
- package/package.json +7 -5
- 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). Imports 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,17 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import _ from "
|
|
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";
|
|
8
10
|
//#region src/vite/index.ts
|
|
9
|
-
function
|
|
11
|
+
function S(e) {
|
|
10
12
|
let t = JSON.stringify(e, Object.keys(e).sort());
|
|
11
|
-
return
|
|
13
|
+
return o("sha256").update(t).digest("hex").slice(0, 16);
|
|
12
14
|
}
|
|
13
|
-
var
|
|
14
|
-
async function
|
|
15
|
+
var C = 20;
|
|
16
|
+
async function w(e, t) {
|
|
15
17
|
if (e === void 0) return;
|
|
16
18
|
let n;
|
|
17
19
|
try {
|
|
@@ -31,54 +33,103 @@ async function b(e, t) {
|
|
|
31
33
|
let a = i.error.issues.map((e) => ` examples${e.path.length ? `[${e.path.join("][")}]` : ""}: ${e.message}`).join("\n");
|
|
32
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.`);
|
|
33
35
|
}
|
|
34
|
-
|
|
35
|
-
if (!
|
|
36
|
-
let
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
let n;
|
|
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));
|
|
46
|
+
if (!n) return {
|
|
47
|
+
ok: !1,
|
|
48
|
+
reason: `introspect not found next to ${t}`
|
|
49
|
+
};
|
|
50
|
+
let r = a(process.execPath, [
|
|
51
|
+
"--conditions",
|
|
52
|
+
"browser",
|
|
53
|
+
n,
|
|
54
|
+
e
|
|
55
|
+
], {
|
|
56
|
+
encoding: "utf-8",
|
|
57
|
+
timeout: 3e4
|
|
58
|
+
});
|
|
59
|
+
if (r.error) return {
|
|
60
|
+
ok: !1,
|
|
61
|
+
reason: r.error.message
|
|
62
|
+
};
|
|
63
|
+
if (r.status !== 0) return {
|
|
64
|
+
ok: !1,
|
|
65
|
+
reason: (r.stderr || "").trim().split("\n")[0] || `exit ${r.status}`
|
|
66
|
+
};
|
|
44
67
|
try {
|
|
45
|
-
|
|
46
|
-
|
|
68
|
+
return {
|
|
69
|
+
ok: !0,
|
|
70
|
+
value: JSON.parse(r.stdout)
|
|
71
|
+
};
|
|
47
72
|
} catch {
|
|
48
|
-
return
|
|
73
|
+
return {
|
|
74
|
+
ok: !1,
|
|
75
|
+
reason: "introspect returned unparseable output"
|
|
76
|
+
};
|
|
49
77
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
78
|
+
}
|
|
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;
|
|
57
107
|
if (t.startsWith("{")) try {
|
|
58
108
|
n = JSON.parse(t);
|
|
59
109
|
} catch {
|
|
60
110
|
n = null;
|
|
61
111
|
}
|
|
62
112
|
if (n) {
|
|
63
|
-
if (n.hash !==
|
|
64
|
-
} 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`);
|
|
65
115
|
}
|
|
66
|
-
|
|
67
|
-
hash:
|
|
68
|
-
configVersion:
|
|
116
|
+
p(e.hashFile, `${JSON.stringify({
|
|
117
|
+
hash: a,
|
|
118
|
+
configVersion: o
|
|
69
119
|
})}\n`);
|
|
70
120
|
}
|
|
71
|
-
var
|
|
72
|
-
function
|
|
73
|
-
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;
|
|
74
124
|
}
|
|
75
|
-
function
|
|
76
|
-
|
|
125
|
+
function P() {
|
|
126
|
+
let e = b(import.meta.url);
|
|
127
|
+
return v(h(e), "../../preview");
|
|
77
128
|
}
|
|
78
|
-
function
|
|
79
|
-
return
|
|
129
|
+
function F(e) {
|
|
130
|
+
return r(e);
|
|
80
131
|
}
|
|
81
|
-
function
|
|
132
|
+
function I() {
|
|
82
133
|
return {
|
|
83
134
|
name: "glasshome-widget:sync-layer-guard",
|
|
84
135
|
apply: "build",
|
|
@@ -88,15 +139,38 @@ function O() {
|
|
|
88
139
|
}
|
|
89
140
|
};
|
|
90
141
|
}
|
|
91
|
-
var
|
|
92
|
-
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) {
|
|
93
167
|
try {
|
|
94
|
-
return
|
|
168
|
+
return m(g(process.cwd(), "package.json")).resolve(e);
|
|
95
169
|
} catch {
|
|
96
170
|
return null;
|
|
97
171
|
}
|
|
98
172
|
}
|
|
99
|
-
var
|
|
173
|
+
var H = [
|
|
100
174
|
"--radius",
|
|
101
175
|
"--background",
|
|
102
176
|
"--foreground",
|
|
@@ -106,128 +180,130 @@ var j = [
|
|
|
106
180
|
"--muted",
|
|
107
181
|
"--accent"
|
|
108
182
|
];
|
|
109
|
-
function
|
|
110
|
-
let n =
|
|
111
|
-
if (!
|
|
112
|
-
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");
|
|
113
187
|
for (let e of r.matchAll(/:host[^{]*\{([^}]*)\}/g)) {
|
|
114
|
-
let n = e[1] ?? "", r =
|
|
188
|
+
let n = e[1] ?? "", r = H.find((e) => n.includes(`${e}:`));
|
|
115
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.`);
|
|
116
190
|
}
|
|
117
191
|
}
|
|
118
|
-
function
|
|
119
|
-
let r =
|
|
120
|
-
|
|
121
|
-
let
|
|
122
|
-
if (!
|
|
123
|
-
let
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
...l ? [
|
|
127
|
-
|
|
128
|
-
].filter((e) =>
|
|
129
|
-
|
|
192
|
+
function W(e, t, n) {
|
|
193
|
+
let r = v(e, B);
|
|
194
|
+
c(r, { recursive: !0 });
|
|
195
|
+
let i = V("@glasshome/ui/styles");
|
|
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.");
|
|
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, [
|
|
130
204
|
"@import \"tailwindcss\" source(none);",
|
|
131
205
|
"@import \"tw-animate-css\";",
|
|
132
206
|
"@import \"@glasshome/ui/styles/theme\";",
|
|
133
|
-
...
|
|
207
|
+
...u.map((e) => `@source "${N(e)}";`),
|
|
134
208
|
"@custom-variant dark {",
|
|
135
209
|
" &:is(.dark *) { @slot }",
|
|
136
210
|
" :host(.dark) & { @slot }",
|
|
137
211
|
"}",
|
|
138
212
|
""
|
|
139
213
|
].join("\n"));
|
|
140
|
-
let
|
|
141
|
-
return
|
|
142
|
-
`import "${
|
|
143
|
-
`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)}";`,
|
|
144
218
|
""
|
|
145
|
-
].join("\n")),
|
|
219
|
+
].join("\n")), f;
|
|
146
220
|
}
|
|
147
|
-
function
|
|
148
|
-
let e =
|
|
221
|
+
function G() {
|
|
222
|
+
let e = x();
|
|
149
223
|
for (let t of e) t.apply ??= "build";
|
|
150
224
|
return e;
|
|
151
225
|
}
|
|
152
|
-
function
|
|
226
|
+
function K(e) {
|
|
153
227
|
let t = [];
|
|
154
|
-
if (!
|
|
155
|
-
for (let n of
|
|
156
|
-
let r =
|
|
157
|
-
if (!
|
|
158
|
-
let
|
|
159
|
-
i
|
|
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({
|
|
160
234
|
name: n,
|
|
161
|
-
entry:
|
|
235
|
+
entry: i
|
|
162
236
|
});
|
|
163
237
|
}
|
|
164
238
|
return t;
|
|
165
239
|
}
|
|
166
|
-
function
|
|
167
|
-
let
|
|
168
|
-
if (
|
|
169
|
-
if (!
|
|
170
|
-
let
|
|
171
|
-
if (!
|
|
172
|
-
let
|
|
173
|
-
if (!
|
|
174
|
-
let
|
|
175
|
-
|
|
176
|
-
...
|
|
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,
|
|
177
251
|
bundleUrl: `./${a}.js`,
|
|
178
|
-
...
|
|
252
|
+
...u ? { cssUrl: `./${a}.css` } : {}
|
|
179
253
|
});
|
|
180
254
|
}
|
|
181
|
-
let
|
|
255
|
+
let a = {
|
|
182
256
|
version: 1,
|
|
183
257
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
184
258
|
baseUrl: "./",
|
|
185
|
-
widgets:
|
|
259
|
+
widgets: r
|
|
186
260
|
};
|
|
187
|
-
|
|
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)`);
|
|
188
262
|
}
|
|
189
|
-
async function
|
|
190
|
-
let { build: t } = await import("vite"), n = process.cwd(), r =
|
|
191
|
-
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) {
|
|
192
266
|
console.warn("[glasshome-widgets] No widgets found in", r);
|
|
193
267
|
return;
|
|
194
268
|
}
|
|
195
269
|
if (e?.only) {
|
|
196
270
|
let t = new Set(e.only);
|
|
197
|
-
|
|
271
|
+
a = a.filter((e) => t.has(e.name));
|
|
198
272
|
}
|
|
199
|
-
e?.only || i
|
|
200
|
-
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({
|
|
201
275
|
configFile: !1,
|
|
202
276
|
root: n,
|
|
203
277
|
plugins: [
|
|
204
|
-
...
|
|
278
|
+
...G(),
|
|
205
279
|
...e?.plugins ?? [],
|
|
206
|
-
|
|
280
|
+
I(),
|
|
281
|
+
z()
|
|
207
282
|
],
|
|
208
283
|
...e?.viteConfig,
|
|
209
284
|
build: {
|
|
210
285
|
lib: {
|
|
211
|
-
entry:
|
|
286
|
+
entry: W(n, r.name, r.entry),
|
|
212
287
|
formats: ["es"],
|
|
213
288
|
fileName: r.name,
|
|
214
289
|
cssFileName: r.name
|
|
215
290
|
},
|
|
216
|
-
rollupOptions: { external:
|
|
217
|
-
outDir:
|
|
291
|
+
rollupOptions: { external: F },
|
|
292
|
+
outDir: i,
|
|
218
293
|
emptyOutDir: !1,
|
|
219
294
|
copyPublicDir: !1,
|
|
220
295
|
...e?.viteConfig?.build
|
|
221
296
|
},
|
|
222
297
|
logLevel: "warn"
|
|
223
|
-
}),
|
|
224
|
-
outFile:
|
|
225
|
-
hashFile:
|
|
226
|
-
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")
|
|
227
303
|
});
|
|
228
|
-
|
|
304
|
+
q(r, i);
|
|
229
305
|
}
|
|
230
|
-
function
|
|
306
|
+
function Y(e) {
|
|
231
307
|
let t = e?.entry ?? "src/index.tsx", n = {
|
|
232
308
|
name: "glasshome-widget:build",
|
|
233
309
|
apply: "build",
|
|
@@ -235,12 +311,12 @@ function R(e) {
|
|
|
235
311
|
let e = process.cwd();
|
|
236
312
|
return { build: {
|
|
237
313
|
lib: {
|
|
238
|
-
entry:
|
|
314
|
+
entry: W(e, "index", v(e, t)),
|
|
239
315
|
formats: ["es"],
|
|
240
316
|
fileName: "index",
|
|
241
317
|
cssFileName: "index"
|
|
242
318
|
},
|
|
243
|
-
rollupOptions: { external:
|
|
319
|
+
rollupOptions: { external: F }
|
|
244
320
|
} };
|
|
245
321
|
}
|
|
246
322
|
}, r = {
|
|
@@ -248,19 +324,19 @@ function R(e) {
|
|
|
248
324
|
apply: "serve",
|
|
249
325
|
enforce: "pre",
|
|
250
326
|
config() {
|
|
251
|
-
let e =
|
|
327
|
+
let e = P(), t = process.cwd();
|
|
252
328
|
return { server: { fs: { allow: [
|
|
253
329
|
e,
|
|
254
330
|
t,
|
|
255
|
-
|
|
331
|
+
v(t, "..", "..")
|
|
256
332
|
] } } };
|
|
257
333
|
},
|
|
258
334
|
configureServer(e) {
|
|
259
|
-
let t =
|
|
260
|
-
e.middlewares.use(async (
|
|
261
|
-
if (
|
|
262
|
-
let i =
|
|
263
|
-
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);
|
|
264
340
|
} catch (e) {
|
|
265
341
|
i(e);
|
|
266
342
|
}
|
|
@@ -268,33 +344,37 @@ function R(e) {
|
|
|
268
344
|
});
|
|
269
345
|
},
|
|
270
346
|
resolveId(e) {
|
|
271
|
-
if (e ===
|
|
272
|
-
|
|
347
|
+
if (e === M) {
|
|
348
|
+
let e = P();
|
|
349
|
+
return N(g(e, "host.tsx"));
|
|
350
|
+
}
|
|
351
|
+
if (e === A) return j;
|
|
273
352
|
},
|
|
274
353
|
load(e) {
|
|
275
|
-
if (e ===
|
|
354
|
+
if (e === j) return `export { default } from "${N(v(process.cwd(), t))}";`;
|
|
276
355
|
}
|
|
277
356
|
}, i = {
|
|
278
357
|
name: "glasshome-widget:schema",
|
|
279
358
|
apply: "build",
|
|
280
359
|
async closeBundle() {
|
|
281
|
-
|
|
282
|
-
outFile:
|
|
283
|
-
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"),
|
|
284
363
|
widgetName: "index",
|
|
285
|
-
manifestPath:
|
|
364
|
+
manifestPath: v(process.cwd(), "manifest.json")
|
|
286
365
|
});
|
|
287
366
|
}
|
|
288
367
|
};
|
|
289
368
|
return [
|
|
290
|
-
...
|
|
369
|
+
...G(),
|
|
291
370
|
n,
|
|
292
|
-
|
|
371
|
+
I(),
|
|
372
|
+
z(),
|
|
293
373
|
i,
|
|
294
374
|
r
|
|
295
375
|
];
|
|
296
376
|
}
|
|
297
|
-
function
|
|
377
|
+
function X(e) {
|
|
298
378
|
let t = e?.srcDir ?? "src", n = e?.outDir ?? "dist", r = [];
|
|
299
379
|
return [{
|
|
300
380
|
name: "glasshome-widgets:build",
|
|
@@ -313,7 +393,7 @@ function z(e) {
|
|
|
313
393
|
if (e === "\0glasshome-noop") return "export {}";
|
|
314
394
|
},
|
|
315
395
|
async closeBundle() {
|
|
316
|
-
await
|
|
396
|
+
await J({
|
|
317
397
|
srcDir: t,
|
|
318
398
|
outDir: n,
|
|
319
399
|
plugins: r
|
|
@@ -322,4 +402,4 @@ function z(e) {
|
|
|
322
402
|
}];
|
|
323
403
|
}
|
|
324
404
|
//#endregion
|
|
325
|
-
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 };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a built widget bundle's definition and prints it as JSON.
|
|
3
|
+
*
|
|
4
|
+
* Runs as its own process because a widget bundle cannot be imported by the
|
|
5
|
+
* build: `solid-js/web` resolves to its server build under Node's conditions
|
|
6
|
+
* and throws "Client-only API called on the server side" the moment the module
|
|
7
|
+
* initialises, and forcing browser conditions then needs a DOM for the
|
|
8
|
+
* templates Solid creates at import time. The build spawns this with
|
|
9
|
+
* `--conditions browser` and a DOM in place, so the import succeeds.
|
|
10
|
+
*
|
|
11
|
+
* Until this existed the guard swallowed that import failure and silently did
|
|
12
|
+
* nothing — for every widget, on every build.
|
|
13
|
+
*
|
|
14
|
+
* Usage: bun --conditions browser introspect.js <bundle.js>
|
|
15
|
+
* Prints: { manifest, jsonSchema } on stdout, or exits non-zero with a reason.
|
|
16
|
+
*/
|
|
17
|
+
export interface ExampleConfigIssue {
|
|
18
|
+
index: number;
|
|
19
|
+
label?: string;
|
|
20
|
+
problems: string[];
|
|
21
|
+
}
|