@ai-ecoverse/slicc-spectrum 1.45.0 → 1.46.1

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
@@ -8667,7 +8667,10 @@ var ModelElement = class extends i2 {
8667
8667
  return [];
8668
8668
  }
8669
8669
  focusOn(...selectors) {
8670
- const focus = () => selectors.map((selector) => this.renderRoot.querySelector(selector)).find(Boolean)?.focus();
8670
+ this.focusWith({}, ...selectors);
8671
+ }
8672
+ focusWith(options, ...selectors) {
8673
+ const focus = () => selectors.map((selector) => this.renderRoot.querySelector(selector)).find(Boolean)?.focus(options);
8671
8674
  if (this.hasUpdated) focus();
8672
8675
  else void this.updateComplete.then(focus);
8673
8676
  }
@@ -11737,6 +11740,44 @@ function installProperties(document2, text2 = swc_default) {
11737
11740
  return style;
11738
11741
  }
11739
11742
 
11743
+ // src/app/tabs.ts
11744
+ var following = "SLICC runs in another tab. This tab shows it and sends your actions there.";
11745
+ var connecting = "Connecting to the tab running SLICC\u2026";
11746
+ var alone = "SLICC is open in another tab.";
11747
+ function tabsBanner(state2) {
11748
+ if (!state2 || state2.role === "alone") return null;
11749
+ if (state2.skew === "newer")
11750
+ return {
11751
+ kind: "skew",
11752
+ skew: "newer",
11753
+ text: "Another tab runs a newer SLICC. Reload this tab.",
11754
+ reload: true
11755
+ };
11756
+ if (state2.skew === "older")
11757
+ return {
11758
+ kind: "skew",
11759
+ skew: "older",
11760
+ text: "Another tab runs an older SLICC. Reload the other SLICC tab.",
11761
+ reload: false
11762
+ };
11763
+ if (state2.stalled)
11764
+ return {
11765
+ kind: "stalled",
11766
+ skew: null,
11767
+ text: "Chrome paused the tab running SLICC. Switch to it to continue.",
11768
+ reload: false
11769
+ };
11770
+ return null;
11771
+ }
11772
+ function tabsLight(state2) {
11773
+ if (!state2 || state2.role === "owner" || state2.role === "alone") return null;
11774
+ const banner = tabsBanner(state2);
11775
+ if (banner) return { variant: "notice", text: "Another tab", tooltip: banner.text };
11776
+ if (state2.role === "connecting")
11777
+ return { variant: "info", text: "Connecting", tooltip: connecting };
11778
+ return { variant: "neutral", text: "Another tab", tooltip: following };
11779
+ }
11780
+
11740
11781
  // src/app/terminals.ts
11741
11782
  function deepActive(root2) {
11742
11783
  const active = root2.activeElement;
@@ -19917,6 +19958,33 @@ var SliccApp = class extends ThemedElement {
19917
19958
  flex-direction: column;
19918
19959
  height: 100%;
19919
19960
  }
19961
+ .shell[data-alone] header > :not(.brand),
19962
+ .shell[data-alone] main,
19963
+ .shell[data-alone] .rail.bottom {
19964
+ display: none;
19965
+ }
19966
+ .alone {
19967
+ display: flex;
19968
+ flex: 1;
19969
+ align-items: center;
19970
+ justify-content: center;
19971
+ padding: var(--swc-spacing-400);
19972
+ text-align: center;
19973
+ font-size: var(--swc-font-size-300);
19974
+ color: var(--swc-neutral-subdued-content-color-default);
19975
+ }
19976
+ .alone p {
19977
+ margin: 0;
19978
+ }
19979
+ header .tabs {
19980
+ display: inline-flex;
19981
+ align-self: center;
19982
+ padding-inline: var(--swc-spacing-75);
19983
+ border-radius: var(--swc-corner-radius-small-default);
19984
+ }
19985
+ header .tabs:focus-visible {
19986
+ outline: var(--swc-focus-indicator-thickness) solid var(--swc-focus-indicator-color);
19987
+ }
19920
19988
  main {
19921
19989
  display: grid;
19922
19990
  grid-template-columns: auto minmax(0, 1fr) auto;
@@ -20097,7 +20165,8 @@ var SliccApp = class extends ThemedElement {
20097
20165
  model.browser.on("tabs", update),
20098
20166
  this.dips.on("change", update),
20099
20167
  ...model.updates ? [model.updates.on("items", update)] : [],
20100
- ...model.network ? [model.network.on("network", update)] : []
20168
+ ...model.network ? [model.network.on("network", update)] : [],
20169
+ ...model.tabs ? [model.tabs.on("tabs", update)] : []
20101
20170
  ];
20102
20171
  }
20103
20172
  connectedCallback() {
@@ -20481,6 +20550,15 @@ var SliccApp = class extends ThemedElement {
20481
20550
  </swc-action-button>
20482
20551
  <swc-tooltip for="updates" placement="bottom">${text2}</swc-tooltip>`;
20483
20552
  }
20553
+ #tabsIndicator() {
20554
+ const state2 = this.model?.tabs?.state();
20555
+ const light = tabsLight(state2);
20556
+ if (!state2 || !light) return A;
20557
+ return b`<span id="tabs" class="tabs" tabindex="0" role="img" data-tabs data-role=${state2.role} ?data-stalled=${state2.stalled} data-skew=${state2.skew ?? A} aria-label=${`${light.text}. ${light.tooltip}`}>
20558
+ <swc-status-light size="s" variant=${light.variant}>${this.screen === "phone" ? A : light.text}</swc-status-light>
20559
+ </span>
20560
+ <swc-tooltip for="tabs" placement="bottom">${light.tooltip}</swc-tooltip>`;
20561
+ }
20484
20562
  #networkIndicator() {
20485
20563
  const port = this.model?.network;
20486
20564
  if (!port || !this.#offers("network")) return A;
@@ -20499,8 +20577,9 @@ var SliccApp = class extends ThemedElement {
20499
20577
  const color = this.color;
20500
20578
  const cones = (this.model?.agent.list() ?? []).filter((agent) => agent.kind === "cone");
20501
20579
  const rails = this.#rails();
20580
+ const lonely = this.model?.tabs?.state().role === "alone";
20502
20581
  return b`<div class=${`swc-theme swc-theme--sizeM swc-theme--${color}`}><sp-theme system="spectrum-two" color=${color} scale="medium">
20503
- <div class="shell">
20582
+ <div class="shell" ?data-alone=${lonely}>
20504
20583
  <header>
20505
20584
  <span class="brand">slicc</span>
20506
20585
  ${this.#offers("chat") ? i17(
@@ -20514,6 +20593,7 @@ var SliccApp = class extends ThemedElement {
20514
20593
  ) : A}
20515
20594
  <span class="spacer"></span>
20516
20595
  <div class="status" role="status"><slot name="status"></slot></div>
20596
+ ${this.#tabsIndicator()}
20517
20597
  ${this.#updatesIndicator()}
20518
20598
  ${this.#networkIndicator()}
20519
20599
  ${this.#offers("chat") ? b`<slicc-tray .model=${this.model} ?compact=${this.screen === "phone"}></slicc-tray>` : A}
@@ -20539,6 +20619,7 @@ var SliccApp = class extends ThemedElement {
20539
20619
  ) : A}
20540
20620
  ${this.#headerButton("theme", color === "dark" ? "Switch to light theme" : "Switch to dark theme", b`<swc-icon-contrast slot="icon"></swc-icon-contrast>`, () => this.toggleColor())}
20541
20621
  </header>
20622
+ ${lonely ? b`<div class="alone" role="status" data-tabs="alone"><p>${alone}</p></div>` : A}
20542
20623
  <main>
20543
20624
  ${rails.left}
20544
20625
  <slicc-dock empty-text="All panels are closed. Open one from a rail or View." @layout-change=${this.#save}
@@ -21077,7 +21158,7 @@ var SliccBrowser = class extends ModelElement {
21077
21158
  width: 100%;
21078
21159
  height: 100%;
21079
21160
  object-fit: cover;
21080
- object-position: top;
21161
+ object-position: left top;
21081
21162
  }
21082
21163
  .meta {
21083
21164
  display: flex;
@@ -21388,7 +21469,6 @@ var SliccBrowser = class extends ModelElement {
21388
21469
  focus() {
21389
21470
  void this.updateComplete.then(
21390
21471
  () => this.focusOn(
21391
- '[data-action="stop-agent"]',
21392
21472
  '[data-action="all-tabs"]',
21393
21473
  '.window[aria-current="true"]',
21394
21474
  ".window",
@@ -21645,9 +21725,11 @@ var SliccBrowser = class extends ModelElement {
21645
21725
  ${wide ? this.#list(tabs, tab) : A}
21646
21726
  <section class="detail" aria-label=${tab.title}>
21647
21727
  <div class="bar">
21648
- <swc-action-button size="s" quiet data-action="all-tabs" @click=${() => {
21728
+ <swc-action-button size="s" quiet data-action="all-tabs" @click=${(event2) => {
21649
21729
  this.#show(null);
21650
- void this.updateComplete.then(() => this.focusOn(".window"));
21730
+ void this.updateComplete.then(
21731
+ () => this.focusWith({ focusVisible: event2.detail === 0 }, ".window")
21732
+ );
21651
21733
  }}><swc-icon-chevron-left slot="icon"></swc-icon-chevron-left>All tabs (${tabs.length})</swc-action-button>
21652
21734
  ${wide ? A : this.#picker(tabs, tab)}
21653
21735
  </div>
@@ -22496,6 +22578,7 @@ var SliccChat = class extends ThemedElement {
22496
22578
  if (!this.agent) this.#refresh(true);
22497
22579
  }),
22498
22580
  model.agent.on("agents", () => this.requestUpdate()),
22581
+ ...model.tabs ? [model.tabs.on("tabs", () => this.requestUpdate())] : [],
22499
22582
  model.agent.on("messages", (agentId) => {
22500
22583
  if (agentId === this.#id()) this.#refresh(this.#sent(agentId));
22501
22584
  }),
@@ -22687,7 +22770,7 @@ var SliccChat = class extends ThemedElement {
22687
22770
  this.#items(messages, agent),
22688
22771
  ([key2]) => key2,
22689
22772
  ([, item2]) => item2
22690
- )}</swc-conversation-thread>` : b`<div class="empty">No messages yet. Ask ${agent?.name ?? "the agent"} something.</div>`}
22773
+ )}</swc-conversation-thread>` : this.model?.tabs?.state().role === "connecting" ? b`<div class="empty" data-connecting>${connecting}</div>` : b`<div class="empty">No messages yet. Ask ${agent?.name ?? "the agent"} something.</div>`}
22691
22774
  </div>
22692
22775
  </div>
22693
22776
  ${this.model && !agent?.frozen ? b`<slicc-composer .model=${this.model} .agent=${this.agent}></slicc-composer>` : A}
@@ -24988,8 +25071,10 @@ var SliccNotices = class extends ModelElement {
24988
25071
  this.pending = /* @__PURE__ */ new Map();
24989
25072
  this.failures = /* @__PURE__ */ new Map();
24990
25073
  }
24991
- if (!port) return [];
25074
+ const tabs = model.tabs ? [model.tabs.on("tabs", () => this.requestUpdate())] : [];
25075
+ if (!port) return tabs;
24992
25076
  return [
25077
+ ...tabs,
24993
25078
  port.on("notices", (notices) => {
24994
25079
  const ids = new Set(notices.map((notice) => notice.id));
24995
25080
  this.dismissed = new Set([...this.dismissed].filter((id) => ids.has(id)));
@@ -25039,11 +25124,24 @@ var SliccNotices = class extends ModelElement {
25039
25124
  <swc-close-button size="m" data-dismiss accessible-label=${`Dismiss: ${notice.title}`} @click=${() => this.dismiss(notice.id)}></swc-close-button>
25040
25125
  </div>`;
25041
25126
  }
25127
+ #tabs() {
25128
+ const tabs = this.model?.tabs;
25129
+ const banner = tabsBanner(tabs?.state());
25130
+ if (!tabs || !banner) return A;
25131
+ return b`<div class="notice" role="status" data-tabs-notice=${banner.kind} data-skew=${banner.skew ?? A} data-tone="warning">
25132
+ <swc-icon-alert-triangle></swc-icon-alert-triangle>
25133
+ <div class="text">
25134
+ <p>${banner.text}</p>
25135
+ ${banner.reload ? b`<div class="actions"><swc-button size="s" variant="secondary" fill-style="outline" data-action="reload" @click=${() => tabs.reload()}>Reload</swc-button></div>` : A}
25136
+ </div>
25137
+ </div>`;
25138
+ }
25042
25139
  render() {
25043
25140
  const port = this.model?.notices;
25044
25141
  const notices = (port?.list() ?? []).filter((notice) => !this.dismissed.has(notice.id));
25045
- if (!notices.length) return A;
25046
- return b`<div class="notices">${c(
25142
+ const tabs = this.#tabs();
25143
+ if (!notices.length && tabs === A) return A;
25144
+ return b`<div class="notices">${tabs}${c(
25047
25145
  notices,
25048
25146
  (notice) => notice.id,
25049
25147
  (notice) => this.#notice(notice)