@glasshome/widget-sdk 1.17.0 → 1.18.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.
@@ -6,27 +6,27 @@ import { createRequire as m } from "node:module";
6
6
  import { dirname as h, join as g, relative as _, resolve as v, sep as y } from "node:path";
7
7
  import { fileURLToPath as b } from "node:url";
8
8
  import ee from "@tailwindcss/vite";
9
- import { spawn as te, spawnSync as x } from "node:child_process";
9
+ import { spawn as te, spawnSync as ne } from "node:child_process";
10
10
  //#region src/vite/introspect-session.ts
11
- var S = 262144e3, C = 3e4, ne = 3e3;
12
- function w(e) {
11
+ var x = 262144e3, S = 3e4, re = 3e3;
12
+ function C(e) {
13
13
  let t = h(b(import.meta.url));
14
14
  return [g(t, `${e}.js`), g(t, `${e}.ts`)].find((e) => s(e)) ?? null;
15
15
  }
16
- function T(e) {
17
- let t = w("introspect");
16
+ function w(e) {
17
+ let t = C("introspect");
18
18
  if (!t) return {
19
19
  ok: !1,
20
20
  reason: "introspect not found next to the sdk"
21
21
  };
22
- let n = x(process.execPath, [
22
+ let n = ne(process.execPath, [
23
23
  "--conditions",
24
24
  "browser",
25
25
  t,
26
26
  e
27
27
  ], {
28
28
  encoding: "utf-8",
29
- timeout: C
29
+ timeout: S
30
30
  });
31
31
  if (n.error) return {
32
32
  ok: !1,
@@ -48,16 +48,16 @@ function T(e) {
48
48
  };
49
49
  }
50
50
  }
51
- function re() {
51
+ function ie() {
52
52
  return {
53
- introspect: async (e) => T(e),
53
+ introspect: async (e) => w(e),
54
54
  dispose: async () => {},
55
55
  childPid: null
56
56
  };
57
57
  }
58
- function ie(e) {
59
- if (process.env.GLASSHOME_WIDGET_NO_WORKER === "1") return re();
60
- let t = e?.rssLimitBytes ?? S, n = e?.timeoutMs ?? C, r = e?.slowMs ?? ne, i = null, a = !1, o = 0, s = Promise.resolve();
58
+ function ae(e) {
59
+ if (process.env.GLASSHOME_WIDGET_NO_WORKER === "1") return ie();
60
+ let t = e?.rssLimitBytes ?? x, n = e?.timeoutMs ?? S, r = e?.slowMs ?? re, i = null, a = !1, o = 0, s = Promise.resolve();
61
61
  function c(e, t) {
62
62
  for (let n of e.pending.values()) n({
63
63
  ok: !1,
@@ -128,7 +128,7 @@ function ie(e) {
128
128
  ok: !1,
129
129
  reason: "introspect session disposed"
130
130
  };
131
- let t = w("introspect-worker");
131
+ let t = C("introspect-worker");
132
132
  if (!t) return {
133
133
  ok: !1,
134
134
  reason: "introspect-worker not found next to the sdk"
@@ -186,20 +186,20 @@ function ie(e) {
186
186
  }
187
187
  //#endregion
188
188
  //#region src/vite/index.ts
189
- var E = 2;
190
- function D(e) {
191
- if (Array.isArray(e)) return `[${e.map(D).join(",")}]`;
189
+ var T = 2;
190
+ function E(e) {
191
+ if (Array.isArray(e)) return `[${e.map(E).join(",")}]`;
192
192
  if (typeof e == "object" && e) {
193
193
  let t = e;
194
- return `{${Object.keys(t).sort().filter((e) => t[e] !== void 0).map((e) => `${JSON.stringify(e)}:${D(t[e])}`).join(",")}}`;
194
+ return `{${Object.keys(t).sort().filter((e) => t[e] !== void 0).map((e) => `${JSON.stringify(e)}:${E(t[e])}`).join(",")}}`;
195
195
  }
196
196
  return JSON.stringify(e) ?? "null";
197
197
  }
198
- function ae(e) {
199
- return o("sha256").update(D(e)).digest("hex").slice(0, 16);
198
+ function oe(e) {
199
+ return o("sha256").update(E(e)).digest("hex").slice(0, 16);
200
200
  }
201
- var oe = 20;
202
- async function O(e, t) {
201
+ var se = 20;
202
+ async function D(e, t) {
203
203
  if (e === void 0) return;
204
204
  let n;
205
205
  try {
@@ -219,7 +219,7 @@ async function O(e, t) {
219
219
  let a = i.error.issues.map((e) => ` examples${e.path.length ? `[${e.path.join("][")}]` : ""}: ${e.message}`).join("\n");
220
220
  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.`);
221
221
  }
222
- function k(e, t) {
222
+ function O(e, t) {
223
223
  if (!e?.length) return;
224
224
  let n = e.map((e) => {
225
225
  let t = e.label ? `"${e.label}"` : `#${e.index}`;
@@ -227,7 +227,7 @@ function k(e, t) {
227
227
  }).join("\n");
228
228
  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.`);
229
229
  }
230
- var se = [
230
+ var ce = [
231
231
  "schema",
232
232
  "defaultConfig",
233
233
  "examples",
@@ -240,20 +240,20 @@ var se = [
240
240
  "minSize",
241
241
  "maxSize"
242
242
  ];
243
- function ce(e, t, n) {
243
+ function le(e, t, n) {
244
244
  let r = l(e, "utf-8"), i = JSON.parse(r), a = {
245
245
  ...t.manifest ?? {},
246
246
  schema: n
247
247
  };
248
- for (let e of se) a[e] !== void 0 && (i[e] = a[e]);
248
+ for (let e of ce) a[e] !== void 0 && (i[e] = a[e]);
249
249
  let o = `${JSON.stringify(i, null, 2)}\n`;
250
250
  o !== r && p(e, o);
251
251
  }
252
- var le = /import\s*(\{[^}]*\}|\*\s*as\s+[\w$]+)\s*from\s*["']@glasshome\/widget-sdk["']/g, ue = /import\(\s*["']@glasshome\/widget-sdk["']\s*\)/;
253
- function A(e) {
252
+ var ue = /import\s*(\{[^}]*\}|\*\s*as\s+[\w$]+)\s*from\s*["']@glasshome\/widget-sdk["']/g, de = /import\(\s*["']@glasshome\/widget-sdk["']\s*\)/;
253
+ function k(e) {
254
254
  let t = /* @__PURE__ */ new Set();
255
- ue.test(e) && t.add("*");
256
- for (let [, n = ""] of e.matchAll(le)) {
255
+ de.test(e) && t.add("*");
256
+ for (let [, n = ""] of e.matchAll(ue)) {
257
257
  if (!n.startsWith("{")) {
258
258
  t.add("*");
259
259
  continue;
@@ -265,27 +265,27 @@ function A(e) {
265
265
  }
266
266
  return t;
267
267
  }
268
- var j = { useDaylight: "sun.sun" };
269
- function M(e, t, n) {
270
- let r = A(e);
271
- for (let [e, a] of Object.entries(j)) {
268
+ var A = { useDaylight: "sun.sun" };
269
+ function j(e, t, n) {
270
+ let r = k(e);
271
+ for (let [e, a] of Object.entries(A)) {
272
272
  if (!r.has(e) && !r.has("*") || i(t, a)) continue;
273
273
  let o = a.split(".")[0];
274
274
  throw Error(`[widget-sdk] "${n}" uses ${e}(), which reads ${a}, but its capabilities grant no read of it.\n Add { "domain": "${o}", "access": "read" } to capabilities, so the homeowner is told before installing.`);
275
275
  }
276
276
  }
277
- async function N(e) {
277
+ async function M(e) {
278
278
  if (!s(e.outFile)) return;
279
- let t = e.session ? await e.session.introspect(e.outFile) : T(e.outFile);
279
+ let t = e.session ? await e.session.introspect(e.outFile) : w(e.outFile);
280
280
  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.
281
281
  This usually means the bundle throws while being imported.`);
282
282
  let n = t.value, r = n.manifest?.name ?? e.widgetName;
283
- await O(n.manifest?.examples, r), k(n.exampleConfigIssues, r);
283
+ await D(n.manifest?.examples, r), O(n.exampleConfigIssues, r);
284
284
  let i = n.jsonSchema, a = e.manifestPath && s(e.manifestPath) ? e.manifestPath : null;
285
- i && a && ce(a, n, i);
285
+ i && a && le(a, n, i);
286
286
  let o = a ? JSON.parse(l(a, "utf-8")).capabilities : n.manifest?.capabilities;
287
- if (M(l(e.outFile, "utf-8"), o ?? [], r), !i) return;
288
- let c = ae(i), u = n.manifest?.configVersion ?? null, d = n.manifest?.name ?? e.widgetName, f = s(e.hashFile) ? l(e.hashFile, "utf-8") : null;
287
+ if (j(l(e.outFile, "utf-8"), o ?? [], r), !i) return;
288
+ let c = oe(i), u = n.manifest?.configVersion ?? null, d = n.manifest?.name ?? e.widgetName, f = s(e.hashFile) ? l(e.hashFile, "utf-8") : null;
289
289
  if (f !== null) {
290
290
  let t = f.trim(), n = null;
291
291
  if (t.startsWith("{")) try {
@@ -293,55 +293,55 @@ async function N(e) {
293
293
  } catch {
294
294
  n = null;
295
295
  }
296
- if (n && n.hashVersion === E) {
296
+ if (n && n.hashVersion === T) {
297
297
  if (n.hash !== c && n.configVersion === u) throw Error(`[widget-sdk] Config schema shape changed for "${d}" without a configVersion bump. Bump configVersion in defineWidget (currently ${u ?? "unset"}) or revert the schema change, then rebuild. Recorded in ${e.hashFile}`);
298
- } else console.warn(`[widget-sdk] Schema shape record for "${d}" was written by an older SDK, so it cannot be compared. Re-recording it under hash format ${E}. This build is not checked for a missing configVersion bump; the next one is. (${e.hashFile})`);
298
+ } else console.warn(`[widget-sdk] Schema shape record for "${d}" was written by an older SDK, so it cannot be compared. Re-recording it under hash format ${T}. This build is not checked for a missing configVersion bump; the next one is. (${e.hashFile})`);
299
299
  }
300
300
  let m = `${JSON.stringify({
301
301
  hash: c,
302
302
  configVersion: u,
303
- hashVersion: E
303
+ hashVersion: T
304
304
  })}\n`;
305
305
  m !== f && p(e.hashFile, m);
306
306
  }
307
- var de = "virtual:glasshome-widget", P = "\0virtual:glasshome-widget", fe = "/@glasshome/preview";
308
- function F(e) {
307
+ var fe = "virtual:glasshome-widget", N = "\0virtual:glasshome-widget", pe = "/@glasshome/preview";
308
+ function P(e) {
309
309
  return y === "\\" ? e.split(y).join("/") : e;
310
310
  }
311
- function I() {
311
+ function F() {
312
312
  let e = b(import.meta.url);
313
313
  return v(h(e), "../../preview");
314
314
  }
315
- function L(e) {
315
+ function I(e) {
316
316
  return r(e);
317
317
  }
318
- var R = /\.(ts|tsx|js|jsx)$/, z = /from\s+["']@glasshome\/sync-layer(\/[^"']*)?["']/;
319
- function B(e, t) {
320
- let n = F(e).split("?")[0] ?? "";
321
- return n.includes("/node_modules/") || !R.test(n) ? !1 : z.test(t);
318
+ var L = /\.(ts|tsx|js|jsx)$/, R = /from\s+["']@glasshome\/sync-layer(\/[^"']*)?["']/;
319
+ function z(e, t) {
320
+ let n = P(e).split("?")[0] ?? "";
321
+ return n.includes("/node_modules/") || !L.test(n) ? !1 : R.test(t);
322
322
  }
323
- function V() {
323
+ function B() {
324
324
  return {
325
325
  name: "glasshome-widget:sync-layer-guard",
326
326
  apply: "build",
327
327
  enforce: "pre",
328
328
  transform(e, t) {
329
- if (B(t, e)) throw Error(`Widgets must not import "@glasshome/sync-layer" directly (imported by ${F(_(process.cwd(), t.split("?")[0] ?? t))}). Import the equivalent hook from "@glasshome/widget-sdk" instead (e.g. useEntity, useEntities, useService).`);
329
+ if (z(t, e)) throw Error(`Widgets must not import "@glasshome/sync-layer" directly (imported by ${P(_(process.cwd(), t.split("?")[0] ?? t))}). Import the equivalent hook from "@glasshome/widget-sdk" instead (e.g. useEntity, useEntities, useService).`);
330
330
  return null;
331
331
  }
332
332
  };
333
333
  }
334
- function H(t, n) {
335
- let r = F(t).split("?")[0] ?? "";
336
- if (r.includes("/node_modules/") || !R.test(r)) return !1;
334
+ function V(t, n) {
335
+ let r = P(t).split("?")[0] ?? "";
336
+ if (r.includes("/node_modules/") || !L.test(r)) return !1;
337
337
  let i = e.find((e) => e.id === "direct-ui-import");
338
338
  return i?.sourcePattern ? new RegExp(i.sourcePattern).test(n) : !1;
339
339
  }
340
- function U(e = /* @__PURE__ */ new Set()) {
340
+ function H(e = /* @__PURE__ */ new Set()) {
341
341
  let t = /* @__PURE__ */ new Set();
342
342
  return {
343
343
  scan(e, n) {
344
- H(e, n) && t.add(F(_(process.cwd(), e.split("?")[0] ?? e)));
344
+ V(e, n) && t.add(P(_(process.cwd(), e.split("?")[0] ?? e)));
345
345
  },
346
346
  take() {
347
347
  let n = [...t].filter((t) => !e.has(t));
@@ -350,8 +350,8 @@ function U(e = /* @__PURE__ */ new Set()) {
350
350
  }
351
351
  };
352
352
  }
353
- function W(n) {
354
- let r = U(n);
353
+ function U(n) {
354
+ let r = H(n);
355
355
  return {
356
356
  name: "glasshome-widget:ui-import-guard",
357
357
  apply: "build",
@@ -367,15 +367,15 @@ function W(n) {
367
367
  }
368
368
  };
369
369
  }
370
- var pe = "node_modules/.cache/glasshome-widgets";
371
- function G(e) {
370
+ var me = "node_modules/.cache/glasshome-widgets";
371
+ function W(e) {
372
372
  try {
373
373
  return m(g(process.cwd(), "package.json")).resolve(e);
374
374
  } catch {
375
375
  return null;
376
376
  }
377
377
  }
378
- var me = [
378
+ var he = [
379
379
  "--radius",
380
380
  "--background",
381
381
  "--foreground",
@@ -385,12 +385,16 @@ var me = [
385
385
  "--muted",
386
386
  "--accent"
387
387
  ];
388
+ function G(e) {
389
+ return e.replace(/(?<=[{;])\s*(--[\w-]+)\s*:\s*var\(\s*\1\s*\)\s*(;|(?=\}))/g, "");
390
+ }
388
391
  function K(e, t) {
389
392
  let n = g(e, `${t}.css`);
390
393
  if (!s(n)) return;
391
- let r = l(n, "utf-8");
392
- for (let e of r.matchAll(/:host[^{]*\{([^}]*)\}/g)) {
393
- let n = e[1] ?? "", r = me.find((e) => n.includes(`${e}:`));
394
+ let r = l(n, "utf-8"), i = G(r);
395
+ i !== r && p(n, i);
396
+ for (let e of i.matchAll(/:host[^{]*\{([^}]*)\}/g)) {
397
+ let n = e[1] ?? "", r = he.find((e) => n.includes(`${e}:`));
394
398
  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.`);
395
399
  }
396
400
  }
@@ -399,11 +403,11 @@ function q(e, t) {
399
403
  return [r, ...u(n, { withFileTypes: !0 }).filter((e) => e.isDirectory()).map((e) => g(n, e.name)).filter((e) => !i.has(e))];
400
404
  }
401
405
  function J(e, t, n, r) {
402
- let i = v(e, pe);
406
+ let i = v(e, me);
403
407
  c(i, { recursive: !0 });
404
- let a = G("@glasshome/ui/styles");
408
+ let a = W("@glasshome/ui/styles");
405
409
  if (!a) 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.");
406
- let o = v(h(a), "../.."), l = G("@glasshome/widget-sdk/tailwind-sources"), u = l ? h(l) : null, d = [
410
+ let o = v(h(a), "../.."), l = W("@glasshome/widget-sdk/tailwind-sources"), u = l ? h(l) : null, d = [
407
411
  g(o, "src"),
408
412
  g(o, "dist"),
409
413
  ...u ? [g(u, "src"), g(u, "dist")] : [],
@@ -413,7 +417,7 @@ function J(e, t, n, r) {
413
417
  "@import \"tailwindcss\" source(none);",
414
418
  "@import \"tw-animate-css\";",
415
419
  "@import \"@glasshome/ui/styles/theme\";",
416
- ...d.map((e) => `@source "${F(e)}";`),
420
+ ...d.map((e) => `@source "${P(e)}";`),
417
421
  "@custom-variant dark {",
418
422
  " &:is(.dark *) { @slot }",
419
423
  " :host(.dark) & { @slot }",
@@ -422,8 +426,8 @@ function J(e, t, n, r) {
422
426
  ].join("\n"));
423
427
  let m = v(i, `${t}.entry.ts`);
424
428
  return p(m, [
425
- `import "${F(f)}";`,
426
- `export { default } from "${F(n)}";`,
429
+ `import "${P(f)}";`,
430
+ `export { default } from "${P(n)}";`,
427
431
  ""
428
432
  ].join("\n")), m;
429
433
  }
@@ -491,8 +495,8 @@ async function $(e) {
491
495
  plugins: [
492
496
  ...X(),
493
497
  ...e?.plugins ?? [],
494
- V(),
495
- W(o)
498
+ B(),
499
+ U(o)
496
500
  ],
497
501
  ...e?.viteConfig,
498
502
  css: {
@@ -506,14 +510,14 @@ async function $(e) {
506
510
  fileName: s.name,
507
511
  cssFileName: s.name
508
512
  },
509
- rollupOptions: { external: L },
513
+ rollupOptions: { external: I },
510
514
  outDir: i,
511
515
  emptyOutDir: !1,
512
516
  copyPublicDir: !1,
513
517
  ...e?.viteConfig?.build
514
518
  },
515
519
  logLevel: "warn"
516
- }), K(i, s.name), await N({
520
+ }), K(i, s.name), await M({
517
521
  outFile: g(i, `${s.name}.js`),
518
522
  hashFile: g(h(s.entry), ".schema-hash"),
519
523
  widgetName: s.name,
@@ -522,7 +526,7 @@ async function $(e) {
522
526
  });
523
527
  Q(r, i);
524
528
  }
525
- function he(e) {
529
+ function ge(e) {
526
530
  let t = e?.entry ?? "src/index.tsx", n = {
527
531
  name: "glasshome-widget:build",
528
532
  apply: "build",
@@ -537,7 +541,7 @@ function he(e) {
537
541
  fileName: "index",
538
542
  cssFileName: "index"
539
543
  },
540
- rollupOptions: { external: L }
544
+ rollupOptions: { external: I }
541
545
  }
542
546
  };
543
547
  }
@@ -546,7 +550,7 @@ function he(e) {
546
550
  apply: "serve",
547
551
  enforce: "pre",
548
552
  config() {
549
- let e = I(), t = process.cwd();
553
+ let e = F(), t = process.cwd();
550
554
  return { server: { fs: { allow: [
551
555
  e,
552
556
  t,
@@ -554,7 +558,7 @@ function he(e) {
554
558
  ] } } };
555
559
  },
556
560
  configureServer(e) {
557
- let t = I(), n = g(t, "preview.html");
561
+ let t = F(), n = g(t, "preview.html");
558
562
  e.middlewares.use(async (t, r, i) => {
559
563
  if (t.url === "/" || t.url === "/index.html") try {
560
564
  let i = l(n, "utf-8");
@@ -566,20 +570,20 @@ function he(e) {
566
570
  });
567
571
  },
568
572
  resolveId(e) {
569
- if (e === fe) {
570
- let e = I();
571
- return F(g(e, "host.tsx"));
573
+ if (e === pe) {
574
+ let e = F();
575
+ return P(g(e, "host.tsx"));
572
576
  }
573
- if (e === de) return P;
577
+ if (e === fe) return N;
574
578
  },
575
579
  load(e) {
576
- if (e === P) return `export { default } from "${F(v(process.cwd(), t))}";`;
580
+ if (e === N) return `export { default } from "${P(v(process.cwd(), t))}";`;
577
581
  }
578
582
  }, i = {
579
583
  name: "glasshome-widget:schema",
580
584
  apply: "build",
581
585
  async closeBundle() {
582
- K(v(process.cwd(), "dist"), "index"), await N({
586
+ K(v(process.cwd(), "dist"), "index"), await M({
583
587
  outFile: v(process.cwd(), "dist", "index.js"),
584
588
  hashFile: v(process.cwd(), ".schema-hash"),
585
589
  widgetName: "index",
@@ -590,13 +594,13 @@ function he(e) {
590
594
  return [
591
595
  ...X(),
592
596
  n,
593
- V(),
594
- W(),
597
+ B(),
598
+ U(),
595
599
  i,
596
600
  r
597
601
  ];
598
602
  }
599
- function ge(e) {
603
+ function _e(e) {
600
604
  let t = e?.srcDir ?? "src", n = e?.outDir ?? "dist", r = [];
601
605
  return [{
602
606
  name: "glasshome-widgets:build",
@@ -624,4 +628,4 @@ function ge(e) {
624
628
  }];
625
629
  }
626
630
  //#endregion
627
- export { j as HOOK_READS, oe as MAX_EXAMPLES, M as assertHookReadsDeclared, $ as buildWidgets, ie as createIntrospectSession, U as createUiImportTracker, Z as discoverWidgets, Q as generateRegistry, he as glasshomeWidget, ge as glasshomeWidgets, T as introspectOnce, B as isDirectSyncLayerImportSource, H as isDirectUiImportSource, L as isWidgetExternal, N as runSchemaGuard, A as sdkImportsOf, q as widgetProjectScanDirs };
631
+ export { A as HOOK_READS, se as MAX_EXAMPLES, j as assertHookReadsDeclared, $ as buildWidgets, ae as createIntrospectSession, H as createUiImportTracker, Z as discoverWidgets, G as dropSelfReferencingVars, Q as generateRegistry, ge as glasshomeWidget, _e as glasshomeWidgets, w as introspectOnce, z as isDirectSyncLayerImportSource, V as isDirectUiImportSource, I as isWidgetExternal, M as runSchemaGuard, k as sdkImportsOf, q as widgetProjectScanDirs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glasshome/widget-sdk",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "SDK for building GlassHome dashboard widgets with SolidJS",
5
5
  "keywords": [
6
6
  "glasshome",
@@ -56,16 +56,16 @@
56
56
  "test": "bun test src && vitest run",
57
57
  "test:dom": "vitest run",
58
58
  "test:dom:watch": "vitest",
59
- "typecheck:test": "tsc --noEmit -p tsconfig.test.json"
59
+ "typecheck:test": "tsc --noEmit -p tsconfig.test.json",
60
+ "check:dead": "fallow dead-code --fail-on-issues"
60
61
  },
61
62
  "peerDependencies": {
62
- "@glasshome/sync-layer": "0.9.0",
63
- "@glasshome/ui": "1.20.0",
63
+ "@glasshome/sync-layer": "0.9.1",
64
+ "@glasshome/ui": "1.21.1",
64
65
  "solid-js": "^1.9.11"
65
66
  },
66
67
  "dependencies": {
67
68
  "@glasshome/widget-contract": "0.3.0",
68
- "@modular-forms/solid": "^0.25.1",
69
69
  "@tailwindcss/vite": "^4.1.13",
70
70
  "clsx": "^2.1.1",
71
71
  "happy-dom": "^20.0.0",
@@ -75,10 +75,11 @@
75
75
  "zod": "^4.1.13"
76
76
  },
77
77
  "devDependencies": {
78
- "@glasshome/ui": "1.20.0",
78
+ "@glasshome/ui": "1.21.1",
79
79
  "@solidjs/testing-library": "^0.8.10",
80
80
  "@types/bun": "^1.4.0",
81
81
  "@types/node": "^25.2.2",
82
+ "fallow": "3.17.0",
82
83
  "typescript": "^7.0.2",
83
84
  "vite": "^8.1.0",
84
85
  "vite-plugin-solid": "^2.11.12",
package/preview/host.tsx CHANGED
@@ -4,7 +4,7 @@ import { render } from "solid-js/web";
4
4
 
5
5
  function PreviewHost() {
6
6
  const [isDark, setIsDark] = createSignal(false);
7
- const [config, setConfig] = createSignal(widget.manifest.defaultConfig || {});
7
+ const [config] = createSignal(widget.manifest.defaultConfig || {});
8
8
 
9
9
  const toggleDark = () => {
10
10
  const next = !isDark();
@@ -86,4 +86,6 @@ function PreviewHost() {
86
86
  );
87
87
  }
88
88
 
89
- render(() => <PreviewHost />, document.getElementById("root")!);
89
+ const root = document.getElementById("root");
90
+ if (!root) throw new Error("preview: #root is missing");
91
+ render(() => <PreviewHost />, root);
@@ -1,7 +0,0 @@
1
- /**
2
- * Variant System - Barrel Export
3
- *
4
- * Built-in variant presets and composition utilities.
5
- */
6
- export { builtInVariants, classicGlass, compactHorizontal, getBuiltInVariant, getBuiltInVariantIds, isBuiltInVariant, minimal, } from "./built-in-variants";
7
- export { applyCssVars, applyLayout, composeVariants, createFlexLayout, extendVariant, mergeVariants, } from "./variant-utils";
@@ -1,105 +0,0 @@
1
- /**
2
- * Variant Composition Utilities
3
- *
4
- * Utilities for creating, merging, extending, and composing widget variants.
5
- * Enables flexible variant system with type safety and composability.
6
- */
7
- import type { FlexLayoutStrategy, LayoutStrategy, WidgetVariantConfig } from "../types";
8
- /**
9
- * Merge two complete variant configurations
10
- *
11
- * Deep merges all properties, with `override` taking precedence.
12
- * Layout strategies are replaced, not merged (since they have different shapes).
13
- *
14
- * @example
15
- * ```tsx
16
- * const customVariant = mergeVariants(classicGlass, {
17
- * styles: {
18
- * cssVars: {
19
- * "--glass-base": "oklch(0.2 0 0 / 0.5)"
20
- * }
21
- * }
22
- * });
23
- * ```
24
- */
25
- export declare function mergeVariants(base: WidgetVariantConfig, override: Partial<WidgetVariantConfig>): WidgetVariantConfig;
26
- /**
27
- * Extend a base variant with partial overrides
28
- *
29
- * Similar to mergeVariants but returns a new variant that references the base
30
- * via the `extends` property. Useful for variant inheritance chains.
31
- *
32
- * @example
33
- * ```tsx
34
- * const darkGlass = extendVariant("classic-glass", {
35
- * id: "dark-glass",
36
- * name: "Dark Glass",
37
- * styles: {
38
- * cssVars: {
39
- * "--glass-base": "oklch(0.2 0 0 / 0.5)"
40
- * }
41
- * }
42
- * });
43
- * ```
44
- */
45
- export declare function extendVariant(baseId: string, override: Partial<WidgetVariantConfig> & {
46
- id: string;
47
- name: string;
48
- }): WidgetVariantConfig;
49
- /**
50
- * Compose multiple variants together (left to right precedence)
51
- *
52
- * Merges multiple variants in sequence, with later variants taking precedence.
53
- * Useful for combining layout + styling + interaction variants.
54
- *
55
- * @example
56
- * ```tsx
57
- * const custom = composeVariants(
58
- * minimal, // Base: minimal styling
59
- * centeredLayout, // Add: centered layout
60
- * largeIcons // Add: large icon sizing
61
- * );
62
- * ```
63
- */
64
- export declare function composeVariants(...variants: WidgetVariantConfig[]): WidgetVariantConfig;
65
- /**
66
- * Apply a layout strategy override to a variant
67
- *
68
- * Convenience function for changing just the layout of a variant.
69
- *
70
- * @example
71
- * ```tsx
72
- * const centered = applyLayout(minimal, {
73
- * type: "flex",
74
- * direction: "column",
75
- * align: "center",
76
- * justify: "center"
77
- * });
78
- * ```
79
- */
80
- export declare function applyLayout(variant: WidgetVariantConfig, layout: LayoutStrategy): WidgetVariantConfig;
81
- /**
82
- * Apply CSS variable overrides to a variant
83
- *
84
- * Convenience function for changing just the CSS variables of a variant.
85
- *
86
- * @example
87
- * ```tsx
88
- * const blueTinted = applyCssVars(classicGlass, {
89
- * "--glass-tone": "oklch(0.62 0.2 260)",
90
- * "--glass-wash": "30%"
91
- * });
92
- * ```
93
- */
94
- export declare function applyCssVars(variant: WidgetVariantConfig, cssVars: Record<`--widget-${string}` | `--glass-${string}`, string | number>): WidgetVariantConfig;
95
- /**
96
- * Create a flex layout strategy
97
- *
98
- * Convenience function for creating common flex layouts.
99
- *
100
- * @example
101
- * ```tsx
102
- * const layout = createFlexLayout("column", "center", "center");
103
- * ```
104
- */
105
- export declare function createFlexLayout(direction?: FlexLayoutStrategy["direction"], align?: FlexLayoutStrategy["align"], justify?: FlexLayoutStrategy["justify"], options?: Partial<FlexLayoutStrategy>): FlexLayoutStrategy;