@ai-ecoverse/slicc-spectrum 1.23.3 → 1.24.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/slicc-ui.js CHANGED
@@ -19196,11 +19196,58 @@ var bridge = `(() => {
19196
19196
  });
19197
19197
  post({ type: 'slicc-ready' });
19198
19198
  })();`;
19199
- function frameDocument(source, color, name) {
19199
+ function literal(value) {
19200
+ try {
19201
+ return JSON.stringify(value ?? null).replace(/</g, "\\u003c");
19202
+ } catch {
19203
+ return "null";
19204
+ }
19205
+ }
19206
+ function store(state) {
19207
+ return `(() => {
19208
+ let state = ${literal(state)};
19209
+ const tag = Math.random().toString(36).slice(2);
19210
+ const pending = new Map();
19211
+ let next = 0;
19212
+ const call = (method, args) => new Promise((resolve, reject) => {
19213
+ const id = tag + ':' + ++next;
19214
+ pending.set(id, { resolve, reject });
19215
+ try {
19216
+ parent.postMessage({ type: 'slicc-call', id, method, args }, '*');
19217
+ } catch (error) {
19218
+ pending.delete(id);
19219
+ reject(error);
19220
+ }
19221
+ });
19222
+ addEventListener('message', (event) => {
19223
+ if (event.source !== parent) return;
19224
+ const message = event.data || {};
19225
+ const waiting = message.type === 'slicc-result' && pending.get(message.id);
19226
+ if (!waiting) return;
19227
+ pending.delete(message.id);
19228
+ if (typeof message.error === 'string') waiting.reject(new Error(message.error));
19229
+ else waiting.resolve(message.value);
19230
+ });
19231
+ Object.assign(window.slicc, {
19232
+ readFile: (path) => call('readFile', [path]),
19233
+ exists: (path) => call('exists', [path]),
19234
+ getState: () => state,
19235
+ setState(value) {
19236
+ try {
19237
+ state = JSON.parse(JSON.stringify(value === undefined ? null : value));
19238
+ } catch (error) {
19239
+ return Promise.reject(error);
19240
+ }
19241
+ return call('setState', [state]).then(() => undefined);
19242
+ },
19243
+ });
19244
+ })();`;
19245
+ }
19246
+ function frameDocument(source, color, name, state) {
19200
19247
  const scheme = `<style>${sprinkleTokens}${sprinkle_theme_default}</style>`;
19201
19248
  const light = `<script>document.documentElement.classList.toggle('theme-light', ${color === "light"});<\/script>`;
19202
19249
  const script = `<script data-name="${name.replace(/"/g, "&quot;")}">${bridge}<\/script>`;
19203
- const injection = light + scheme + script;
19250
+ const injection = light + scheme + script + (state ? `<script>${store(state.value)}<\/script>` : "");
19204
19251
  const head2 = source.match(/<head\b[^>]*>/i);
19205
19252
  if (!head2 || head2.index === void 0) return injection + source;
19206
19253
  const at = head2.index + head2[0].length;
@@ -19230,6 +19277,12 @@ async function frameFonts(files, base) {
19230
19277
  (font) => Boolean(font.data)
19231
19278
  );
19232
19279
  }
19280
+ var sprinkleMethods = /* @__PURE__ */ new Set([
19281
+ "readFile",
19282
+ "exists",
19283
+ "getState",
19284
+ "setState"
19285
+ ]);
19233
19286
  var grip = w`<svg class="grip" viewBox="0 0 8 14" width="8" height="14" aria-hidden="true">${[2, 7, 12].flatMap((y7) => [2, 6].map((x5) => w`<circle cx=${x5} cy=${y7} r="1.25"></circle>`))}</svg>`;
19234
19287
  var SliccSprinkle = class extends ThemedElement {
19235
19288
  static properties = {
@@ -19329,11 +19382,52 @@ var SliccSprinkle = class extends ThemedElement {
19329
19382
  source.postMessage({ type: "slicc-fonts", fonts }, "*");
19330
19383
  } else if (data.type === "slicc-size" && typeof data.height === "number") {
19331
19384
  this.height = data.height;
19385
+ } else if (data.type === "slicc-call") {
19386
+ await this.#call(source, data);
19387
+ }
19388
+ };
19389
+ async #call(source, data) {
19390
+ const port = this.model?.sprinkles;
19391
+ if (!port?.call || typeof data.method !== "string" || !sprinkleMethods.has(data.method)) return;
19392
+ const method = data.method;
19393
+ const args2 = Array.isArray(data.args) ? data.args : [];
19394
+ if (method === "setState") this.#held.value = args2[0] ?? null;
19395
+ try {
19396
+ const value = await port.call(this.sprinkle, method, args2);
19397
+ source.postMessage({ type: "slicc-result", id: data.id, value }, "*");
19398
+ } catch (error) {
19399
+ const message = error instanceof Error ? error.message : String(error);
19400
+ source.postMessage({ type: "slicc-result", id: data.id, error: message }, "*");
19332
19401
  }
19402
+ }
19403
+ #held = {
19404
+ port: null,
19405
+ id: "",
19406
+ ready: false,
19407
+ value: null
19333
19408
  };
19409
+ #hold(port, ask, id) {
19410
+ const held = { port, id, ready: false, value: null };
19411
+ this.#held = held;
19412
+ this.#frame = { key: "", doc: "" };
19413
+ const settle = (value) => {
19414
+ held.value = value ?? null;
19415
+ held.ready = true;
19416
+ if (this.#held === held) this.requestUpdate();
19417
+ };
19418
+ ask.call(port, id, "getState", []).then(settle, () => settle(null));
19419
+ }
19420
+ willUpdate(changed) {
19421
+ super.willUpdate(changed);
19422
+ const port = this.model?.sprinkles;
19423
+ if (port?.call && (this.#held.port !== port || this.#held.id !== this.sprinkle))
19424
+ this.#hold(port, port.call, this.sprinkle);
19425
+ }
19334
19426
  #dips = new Dips();
19427
+ #focusLater = false;
19335
19428
  focus() {
19336
- this.focusOn("iframe");
19429
+ if (this.model?.sprinkles.call && !this.#held.ready) this.#focusLater = true;
19430
+ else this.focusOn("iframe");
19337
19431
  }
19338
19432
  subscribe(model) {
19339
19433
  this.#dips = dipsOf(this) ?? this.#dips;
@@ -19358,16 +19452,22 @@ var SliccSprinkle = class extends ThemedElement {
19358
19452
  return this.model?.sprinkles.list().find((candidate) => candidate.id === this.sprinkle);
19359
19453
  }
19360
19454
  #frame = { key: "", doc: "" };
19361
- #document(data) {
19362
- const key2 = `${data.name}
19455
+ #document(data, state) {
19456
+ const key2 = `${!!state}
19457
+ ${data.name}
19363
19458
  ${data.html}`;
19364
19459
  if (this.#frame.key !== key2)
19365
- this.#frame = { key: key2, doc: frameDocument(data.html, this.color, data.name) };
19460
+ this.#frame = { key: key2, doc: frameDocument(data.html, this.color, data.name, state) };
19366
19461
  return this.#frame.doc;
19367
19462
  }
19368
19463
  updated(changed) {
19369
19464
  super.updated(changed);
19370
- this.renderRoot.querySelector("iframe")?.contentWindow?.postMessage({ type: "slicc-theme", color: this.color }, "*");
19465
+ const frame = this.renderRoot.querySelector("iframe");
19466
+ frame?.contentWindow?.postMessage({ type: "slicc-theme", color: this.color }, "*");
19467
+ if (frame && this.#focusLater) {
19468
+ this.#focusLater = false;
19469
+ frame.focus();
19470
+ }
19371
19471
  }
19372
19472
  render() {
19373
19473
  const data = this.#data;
@@ -19379,8 +19479,11 @@ ${data.html}`;
19379
19479
  <sp-action-button size="s" quiet @click=${() => this.#send("show-surface", `sprinkle:${data.id}`)}>Show</sp-action-button>
19380
19480
  </div>`;
19381
19481
  }
19482
+ const bridged = !!this.model?.sprinkles.call;
19483
+ if (bridged && !this.#held.ready) return b``;
19484
+ const state = bridged ? this.#held : void 0;
19382
19485
  const style = `color-scheme:${this.color};${this.inline ? `height:${this.height}px;` : ""}`;
19383
- const frame = b`<iframe title=${data.title} sandbox="allow-scripts" style=${style} .srcdoc=${this.#document(data)}></iframe>`;
19486
+ const frame = b`<iframe title=${data.title} sandbox="allow-scripts" style=${style} .srcdoc=${this.#document(data, state)}></iframe>`;
19384
19487
  if (!this.inline) return frame;
19385
19488
  return b`<div class="handle" draggable="true" title="Drag into the dock or a rail to open as a panel" @dragstart=${this.#drag}>
19386
19489
  ${grip}
@@ -31321,20 +31424,20 @@ function canParticipateWithNode(capture, node) {
31321
31424
  throw new Error("Unexpected path");
31322
31425
  }
31323
31426
  function cloneCapturingGroup(obj, originMap, up, up2) {
31324
- const store = Array.isArray(obj) ? [] : {};
31427
+ const store2 = Array.isArray(obj) ? [] : {};
31325
31428
  for (const [key2, value] of Object.entries(obj)) {
31326
31429
  if (key2 === "parent") {
31327
- store.parent = Array.isArray(up) ? up2 : up;
31430
+ store2.parent = Array.isArray(up) ? up2 : up;
31328
31431
  } else if (value && typeof value === "object") {
31329
- store[key2] = cloneCapturingGroup(value, originMap, store, up);
31432
+ store2[key2] = cloneCapturingGroup(value, originMap, store2, up);
31330
31433
  } else {
31331
31434
  if (key2 === "type" && value === "CapturingGroup") {
31332
- originMap.set(store, originMap.get(obj) ?? obj);
31435
+ originMap.set(store2, originMap.get(obj) ?? obj);
31333
31436
  }
31334
- store[key2] = value;
31437
+ store2[key2] = value;
31335
31438
  }
31336
31439
  }
31337
- return store;
31440
+ return store2;
31338
31441
  }
31339
31442
  function createRecursion(ref) {
31340
31443
  const node = O2(ref);
@@ -64849,8 +64952,8 @@ function buildSoaNodeStore(snapshot) {
64849
64952
  childIdsFlat
64850
64953
  };
64851
64954
  }
64852
- function sweepOpenVisibleCountsSoa(store) {
64853
- const { nodeCount, rootId, flattenEmptyDirectories, depthAndFlags, subtreeNodeCount, visibleSubtreeCount, childStart, childCount, childIdsFlat } = store;
64955
+ function sweepOpenVisibleCountsSoa(store2) {
64956
+ const { nodeCount, rootId, flattenEmptyDirectories, depthAndFlags, subtreeNodeCount, visibleSubtreeCount, childStart, childCount, childIdsFlat } = store2;
64854
64957
  for (let id = nodeCount - 1; id >= 1; id -= 1) {
64855
64958
  if ((depthAndFlags[id] & KIND_MASK) === 0) continue;
64856
64959
  const base = childStart[id];