@timmo001/groundwork-tokens 0.9.27 → 0.9.29

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/page.ts +48 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timmo001/groundwork-tokens",
3
- "version": "0.9.27",
3
+ "version": "0.9.29",
4
4
  "description": "Groundwork's design tokens: the theme schema, the OKLCH solver and every theme as CSS and JSON",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
package/src/page.ts CHANGED
@@ -15,6 +15,7 @@ import glazing from "../themes/glazing.json" with { type: "json" };
15
15
  import slate from "../themes/slate.json" with { type: "json" };
16
16
  import snag from "../themes/snag.json" with { type: "json" };
17
17
  import survey from "../themes/survey.json" with { type: "json" };
18
+ import type { ThemeStore } from "./runtime.ts";
18
19
  import type { Theme } from "./schema.ts";
19
20
  // Only for `document.modelContext`'s type; the tools themselves load lazily
20
21
  import type {} from "./webmcp.ts";
@@ -99,6 +100,13 @@ export interface PageThemeOptions {
99
100
  * entry, on the page with their CSS.
100
101
  */
101
102
  readonly tones?: Readonly<Record<string, string>>;
103
+ /**
104
+ * Where the visitor's own theme is kept beyond this browser, such as an
105
+ * app's host or a profile. Its theme replaces the local one on load, and
106
+ * importing or resetting writes through to it. Local storage still caches
107
+ * the CSS, so the theme applies before the first paint.
108
+ */
109
+ readonly store?: ThemeStore;
102
110
  }
103
111
 
104
112
  export interface PageTheme {
@@ -273,7 +281,7 @@ export const pageTheme = (options: PageThemeOptions): PageTheme => {
273
281
  };
274
282
 
275
283
  /** Solves a document under the custom id, applies it and keeps it. */
276
- const applyCustom = async (document: Theme, text: string) => {
284
+ const applyCustom = async (document: Theme, text: string, keep = true) => {
277
285
  const { appTonesCss, runtimeTheme } = await import("./runtime.ts");
278
286
  const runtime = runtimeTheme(document, customThemeId);
279
287
 
@@ -290,6 +298,8 @@ export const pageTheme = (options: PageThemeOptions): PageTheme => {
290
298
  savePicks();
291
299
  commit(resolve(state.mode, document.name));
292
300
 
301
+ if (keep) await options.store?.save(text).catch(() => undefined);
302
+
293
303
  return runtime.checks
294
304
  .filter((result) => !result.passes)
295
305
  .map(
@@ -361,6 +371,7 @@ export const pageTheme = (options: PageThemeOptions): PageTheme => {
361
371
 
362
372
  picks = { light: fallback("light"), dark: fallback("dark") };
363
373
  commit(resolve(defaultMode, null));
374
+ void options.store?.clear().catch(() => undefined);
364
375
  },
365
376
  subscribe: (listener) => {
366
377
  listeners.add(listener);
@@ -373,6 +384,42 @@ export const pageTheme = (options: PageThemeOptions): PageTheme => {
373
384
 
374
385
  commit(state);
375
386
 
387
+ // The store's theme wins over this browser's: another client may have
388
+ // changed or dropped it
389
+ if (options.store !== undefined) {
390
+ void options.store
391
+ .load()
392
+ .then(async (text) => {
393
+ if (text === read(stored.document)) return;
394
+
395
+ if (text === null) {
396
+ setStyle(null);
397
+
398
+ for (const key of [stored.document, stored.css, stored.name]) {
399
+ write(key, null);
400
+ }
401
+
402
+ picks = {
403
+ light:
404
+ picks.light === customThemeId ? fallback("light") : picks.light,
405
+ dark: picks.dark === customThemeId ? fallback("dark") : picks.dark,
406
+ };
407
+ savePicks();
408
+ commit(resolve(state.mode, null));
409
+
410
+ return;
411
+ }
412
+
413
+ const { Result } = await import("effect");
414
+ const parsed = await readTheme(text);
415
+
416
+ if (Result.isSuccess(parsed)) {
417
+ await applyCustom(parsed.success, text, false);
418
+ }
419
+ })
420
+ .catch(() => undefined);
421
+ }
422
+
376
423
  if (document.modelContext !== undefined) {
377
424
  void import("./webmcp.ts").then(
378
425
  async ({ coreThemes, registerThemeTools }) => {