@autono/pinbox-toolbar 0.20.0 → 0.21.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.
@@ -150,6 +150,9 @@ declare class PinboxToolbarElement extends BaseElement {
150
150
  restore(keyboard?: boolean): void;
151
151
  }
152
152
  //#endregion
153
+ //#region src/previews.d.ts
154
+ declare function mountPreviewSwitcher(host: HTMLElement, endpoint: string): void;
155
+ //#endregion
153
156
  //#region src/transport/mirror.d.ts
154
157
  interface StorageLike {
155
158
  getItem(key: string): string | null;
@@ -283,4 +286,4 @@ declare const Pinbox: {
283
286
  init(config: PinboxConfig): PinboxToolbarElement;
284
287
  };
285
288
  //#endregion
286
- export { applyHubEvent as _, HubEvent as a, upsertPin as b, WebSocketLike as c, PinboxToolbarElement as d, Draft as f, appendThreadMessage as g, UiStatus as h, ConnectionState as i, HubError as l, ToolbarState as m, PinboxConfig as n, HubTransport as o, Store as p, defineToolbarElement as r, TransportOptions as s, Pinbox as t, StorageLike as u, createStore as v, CaptureResult as x, deriveUiStatus as y };
289
+ export { CaptureResult as S, appendThreadMessage as _, HubEvent as a, deriveUiStatus as b, WebSocketLike as c, mountPreviewSwitcher as d, PinboxToolbarElement as f, UiStatus as g, ToolbarState as h, ConnectionState as i, HubError as l, Store as m, PinboxConfig as n, HubTransport as o, Draft as p, defineToolbarElement as r, TransportOptions as s, Pinbox as t, StorageLike as u, applyHubEvent as v, upsertPin as x, createStore as y };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as applyHubEvent, a as HubEvent, b as upsertPin, c as WebSocketLike, d as PinboxToolbarElement, f as Draft, g as appendThreadMessage, h as UiStatus, i as ConnectionState, l as HubError, m as ToolbarState, n as PinboxConfig, o as HubTransport, p as Store, r as defineToolbarElement, s as TransportOptions, t as Pinbox, u as StorageLike, v as createStore, x as CaptureResult, y as deriveUiStatus } from "./index-xNXeJ2mR.js";
2
- export { type CaptureResult, type ConnectionState, type Draft, HubError, type HubEvent, HubTransport, Pinbox, PinboxConfig, PinboxToolbarElement, type StorageLike, type Store, type ToolbarState, type TransportOptions, type UiStatus, type WebSocketLike, appendThreadMessage, applyHubEvent, createStore, defineToolbarElement, deriveUiStatus, upsertPin };
1
+ import { S as CaptureResult, _ as appendThreadMessage, a as HubEvent, b as deriveUiStatus, c as WebSocketLike, d as mountPreviewSwitcher, f as PinboxToolbarElement, g as UiStatus, h as ToolbarState, i as ConnectionState, l as HubError, m as Store, n as PinboxConfig, o as HubTransport, p as Draft, r as defineToolbarElement, s as TransportOptions, t as Pinbox, u as StorageLike, v as applyHubEvent, x as upsertPin, y as createStore } from "./index-CMSOhoVs.js";
2
+ export { type CaptureResult, type ConnectionState, type Draft, HubError, type HubEvent, HubTransport, Pinbox, PinboxConfig, PinboxToolbarElement, type StorageLike, type Store, type ToolbarState, type TransportOptions, type UiStatus, type WebSocketLike, appendThreadMessage, applyHubEvent, createStore, defineToolbarElement, deriveUiStatus, mountPreviewSwitcher, upsertPin };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as HubError, c as createStore, i as HubTransport, l as deriveUiStatus, n as defineToolbarElement, o as appendThreadMessage, r as PinboxToolbarElement, s as applyHubEvent, t as Pinbox, u as upsertPin } from "./src-DnAkx29T.js";
2
- export { HubError, HubTransport, Pinbox, PinboxToolbarElement, appendThreadMessage, applyHubEvent, createStore, defineToolbarElement, deriveUiStatus, upsertPin };
1
+ import { a as HubTransport, c as applyHubEvent, d as upsertPin, i as PinboxToolbarElement, l as createStore, n as defineToolbarElement, o as HubError, r as mountPreviewSwitcher, s as appendThreadMessage, t as Pinbox, u as deriveUiStatus } from "./src-B134WXZ8.js";
2
+ export { HubError, HubTransport, Pinbox, PinboxToolbarElement, appendThreadMessage, applyHubEvent, createStore, defineToolbarElement, deriveUiStatus, mountPreviewSwitcher, upsertPin };
package/dist/model.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { d as PinboxToolbarElement } from "./index-xNXeJ2mR.js";
1
+ import { f as PinboxToolbarElement } from "./index-CMSOhoVs.js";
2
2
  import { ModelAnchor, ModelAnchor as ModelAnchor$1, Pin } from "@autono/pinbox-core/schema";
3
3
  //#region src/model-target.d.ts
4
4
  type ModelProjection = (anchor: ModelAnchor$1) => {
@@ -3,6 +3,10 @@
3
3
  interface PinboxPluginOptions {
4
4
  /** Explicit hub base URL. When set, `.pinbox/server.json` discovery is skipped entirely. */
5
5
  hub?: string;
6
+ /** Vite only: show registered local worktree previews. Opt-in, dev-only. */
7
+ previews?: boolean;
8
+ /** Local CLI executable used for preview discovery. Defaults to pinbox on PATH. */
9
+ previewExecutable?: string;
6
10
  /** Directory containing `.pinbox/server.json`. Defaults to `process.cwd()`. */
7
11
  projectRoot?: string;
8
12
  /** Spawn `pinbox serve` when no healthy hub is found. Defaults to true. */
@@ -1,4 +1,4 @@
1
- import { t as PinboxPluginOptions } from "../options-CNqXqkp9.js";
1
+ import { t as PinboxPluginOptions } from "../options-DPsmmgra.js";
2
2
  //#region src/plugins/next.d.ts
3
3
  /**
4
4
  * Structural stand-in for Next's `NextConfig`.
@@ -1,4 +1,4 @@
1
- import { t as PinboxPluginOptions } from "../options-CNqXqkp9.js";
1
+ import { t as PinboxPluginOptions } from "../options-DPsmmgra.js";
2
2
  import { Plugin } from "vite";
3
3
  //#region src/plugins/vite.d.ts
4
4
  /**
@@ -1,4 +1,53 @@
1
1
  import { a as readHubToken, i as ensureHub, n as VIRTUAL_ID, r as resolveOptions, t as RESOLVED_VIRTUAL_ID } from "../options-DSrJgbJh.js";
2
+ import { execFile } from "node:child_process";
3
+ import { createHash } from "node:crypto";
4
+ import { realpathSync } from "node:fs";
5
+ //#region src/plugins/previews.ts
6
+ const PREVIEWS_PATH = "/__pinbox_previews";
7
+ function servePreviews(server, cwd, executable) {
8
+ server.middlewares.use((req, res, next) => {
9
+ const path = req.url?.split("?")[0];
10
+ if (path !== "/__pinbox_previews" && path !== `/__pinbox_previews/identity`) return next();
11
+ res.setHeader("Content-Type", "application/json");
12
+ res.setHeader("Cache-Control", "no-store");
13
+ if (req.method !== "GET" || req.headers["sec-fetch-site"] === "cross-site") {
14
+ res.statusCode = 403;
15
+ res.end(JSON.stringify({
16
+ ok: false,
17
+ error: { message: "same-origin GET required" }
18
+ }));
19
+ return;
20
+ }
21
+ if (path === `/__pinbox_previews/identity`) {
22
+ res.end(JSON.stringify({ id: createHash("sha256").update(realpathSync(cwd)).digest("hex").slice(0, 12) }));
23
+ return;
24
+ }
25
+ execFile(executable, [
26
+ "preview",
27
+ "list",
28
+ "--json"
29
+ ], {
30
+ cwd,
31
+ timeout: 6e3,
32
+ maxBuffer: 1048576
33
+ }, (error, stdout) => {
34
+ if (error) {
35
+ res.statusCode = 503;
36
+ res.end(JSON.stringify({
37
+ ok: false,
38
+ error: { message: "Preview discovery unavailable. Update the Pinbox CLI." }
39
+ }));
40
+ } else try {
41
+ JSON.parse(stdout);
42
+ res.end(stdout);
43
+ } catch {
44
+ res.statusCode = 503;
45
+ res.end("{\"ok\":false}");
46
+ }
47
+ });
48
+ });
49
+ }
50
+ //#endregion
2
51
  //#region src/plugins/snippet.ts
3
52
  /**
4
53
  * Build the module source injected into the dev page.
@@ -24,14 +73,17 @@ import { a as readHubToken, i as ensureHub, n as VIRTUAL_ID, r as resolveOptions
24
73
  * this import was dropped for real. `src/build.test.ts` bundles this exact import with Vite and
25
74
  * asserts `customElements.define` survives, because statting dist/ cannot see that class of break.
26
75
  */
27
- function buildBootstrap(hubUrl, token) {
76
+ function buildBootstrap(hubUrl, token, previews) {
28
77
  const hub = JSON.stringify(hubUrl);
78
+ const tag = JSON.stringify("pinbox-toolbar");
79
+ const tokenLiteral = token === void 0 ? "null" : JSON.stringify(token);
29
80
  return `// pinbox dev toolbar — injected by @autono/pinbox-toolbar (dev only)
30
81
  import "@autono/pinbox-toolbar";
82
+ ${previews ? "import { mountPreviewSwitcher } from \"@autono/pinbox-toolbar\";" : ""}
31
83
 
32
- const TAG = ${JSON.stringify("pinbox-toolbar")};
84
+ const TAG = ${tag};
33
85
  const HUB = ${hub};
34
- const TOKEN = ${token === void 0 ? "null" : JSON.stringify(token)};
86
+ const TOKEN = ${tokenLiteral};
35
87
 
36
88
  function mount() {
37
89
  let el = document.querySelector(TAG);
@@ -44,6 +96,7 @@ function mount() {
44
96
  if (TOKEN === null) el.removeAttribute("token");
45
97
  else el.setAttribute("token", TOKEN);
46
98
  if (created) document.body.appendChild(el);
99
+ ${previews ? `mountPreviewSwitcher(el, ${JSON.stringify(previews)});` : ""}
47
100
  }
48
101
 
49
102
  if (document.readyState === "loading") {
@@ -63,6 +116,8 @@ const PLUGIN_NAME = "pinbox";
63
116
  */
64
117
  function pinbox(options) {
65
118
  const resolved = resolveOptions(options);
119
+ const previews = options?.previews ?? process.env["PINBOX_PREVIEWS"] === "1";
120
+ const previewExecutable = options?.previewExecutable ?? process.env["PINBOX_PREVIEW_EXECUTABLE"] ?? "pinbox";
66
121
  if (resolved.disabled) return { name: PLUGIN_NAME };
67
122
  let hubPromise;
68
123
  function hub() {
@@ -72,7 +127,8 @@ function pinbox(options) {
72
127
  return {
73
128
  name: PLUGIN_NAME,
74
129
  apply: "serve",
75
- async configureServer() {
130
+ async configureServer(server) {
131
+ if (previews) servePreviews(server, resolved.projectRoot, previewExecutable);
76
132
  await hub();
77
133
  },
78
134
  resolveId(id) {
@@ -83,7 +139,7 @@ function pinbox(options) {
83
139
  if (id !== "\0virtual:pinbox-toolbar") return null;
84
140
  const status = await hub();
85
141
  if (status === void 0) return "// pinbox: hub unavailable, toolbar not mounted.\nexport {};\n";
86
- return buildBootstrap(status.url, readHubToken(resolved.projectRoot));
142
+ return buildBootstrap(status.url, readHubToken(resolved.projectRoot), previews ? PREVIEWS_PATH : void 0);
87
143
  },
88
144
  transformIndexHtml: {
89
145
  order: "pre",
package/dist/react.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as PinboxConfig } from "./index-xNXeJ2mR.js";
1
+ import { n as PinboxConfig } from "./index-CMSOhoVs.js";
2
2
  import { ReactElement } from "react";
3
3
  //#region src/react.d.ts
4
4
  /**
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as defineToolbarElement, r as PinboxToolbarElement } from "./src-DnAkx29T.js";
1
+ import { i as PinboxToolbarElement, n as defineToolbarElement } from "./src-B134WXZ8.js";
2
2
  import { createElement, useEffect, useRef } from "react";
3
3
  //#region src/react.ts
4
4
  /**
@@ -793,6 +793,125 @@ function createMinimize(host) {
793
793
  };
794
794
  }
795
795
  //#endregion
796
+ //#region src/reveal-settle.ts
797
+ const pending = /* @__PURE__ */ new WeakMap();
798
+ function cancelRevealSettle(doc) {
799
+ pending.get(doc)?.();
800
+ }
801
+ function settlePinReveal(doc, reveal) {
802
+ cancelRevealSettle(doc);
803
+ const win = doc.defaultView;
804
+ if (!win) return;
805
+ let attempts = 0;
806
+ let timer = 0;
807
+ const events = [
808
+ "wheel",
809
+ "touchstart",
810
+ "pointerdown",
811
+ "keydown"
812
+ ];
813
+ const stop = () => {
814
+ win.clearTimeout(timer);
815
+ for (const event of events) doc.removeEventListener(event, stop, true);
816
+ pending.delete(doc);
817
+ };
818
+ for (const event of events) doc.addEventListener(event, stop, {
819
+ capture: true,
820
+ passive: true
821
+ });
822
+ const tick = () => {
823
+ reveal();
824
+ if (++attempts >= 10) stop();
825
+ else timer = win.setTimeout(tick, 150);
826
+ };
827
+ pending.set(doc, stop);
828
+ timer = win.setTimeout(tick, 150);
829
+ }
830
+ //#endregion
831
+ //#region src/pin-reveal.ts
832
+ /** Query ordering is not a view change; repeated parameter ordering remains intact. */
833
+ function samePinView(win, value) {
834
+ if (!value) return true;
835
+ try {
836
+ const target = new URL(value, win.location.href);
837
+ const current = new URL(win.location.href);
838
+ target.searchParams.sort();
839
+ current.searchParams.sort();
840
+ return target.pathname === current.pathname && target.search === current.search;
841
+ } catch {
842
+ return true;
843
+ }
844
+ }
845
+ function pagePin(pin) {
846
+ return pin.target?.selector === "html" || pin.target?.selector === "body";
847
+ }
848
+ /** Resolve before clipping: an offscreen row is precisely the target we need to scroll. */
849
+ function scrollToPin(doc, pin) {
850
+ if (pin.target?.model || pagePin(pin)) return false;
851
+ const win = doc.defaultView;
852
+ if (!win || !samePinView(win, pin.target?.url) || !pin.target?.selector) return false;
853
+ try {
854
+ const element = doc.querySelector(pin.target.selector);
855
+ if (!element?.getClientRects().length) return false;
856
+ element.scrollIntoView({
857
+ behavior: "instant",
858
+ block: "center",
859
+ inline: "center"
860
+ });
861
+ return true;
862
+ } catch {
863
+ return false;
864
+ }
865
+ }
866
+ const key = (endpoint) => `pinbox:${endpoint}:reveal`;
867
+ /** Returns true when leaving this document. Never navigates to a different origin. */
868
+ function revealPin(doc, pin, endpoint) {
869
+ cancelRevealSettle(doc);
870
+ const win = doc.defaultView;
871
+ if (!win) return false;
872
+ try {
873
+ win.sessionStorage.removeItem(key(endpoint));
874
+ } catch {}
875
+ if (pagePin(pin) || pin.target?.model) return false;
876
+ if (pin.target?.url && !samePinView(win, pin.target.url)) try {
877
+ const target = new URL(pin.target.url, win.location.href);
878
+ if (target.origin !== win.location.origin || !["http:", "https:"].includes(target.protocol)) return false;
879
+ win.sessionStorage.setItem(key(endpoint), JSON.stringify({
880
+ id: pin.id,
881
+ expires: Date.now() + 3e4
882
+ }));
883
+ win.location.assign(target.href);
884
+ return true;
885
+ } catch {
886
+ return false;
887
+ }
888
+ scrollToPin(doc, pin);
889
+ return false;
890
+ }
891
+ /** Called on pin updates and DOM changes: SPA content may arrive after the toolbar. */
892
+ function pendingPinReveal(doc, pins, endpoint) {
893
+ const win = doc.defaultView;
894
+ if (!win) return null;
895
+ try {
896
+ const raw = win.sessionStorage.getItem(key(endpoint));
897
+ if (!raw) return null;
898
+ const pending = JSON.parse(raw);
899
+ if (typeof pending.id !== "string" || !Number.isFinite(pending.expires) || pending.expires < Date.now()) {
900
+ win.sessionStorage.removeItem(key(endpoint));
901
+ return null;
902
+ }
903
+ const pin = pins.find((p) => p.id === pending.id);
904
+ if (!pin || !scrollToPin(doc, pin)) return null;
905
+ win.sessionStorage.removeItem(key(endpoint));
906
+ settlePinReveal(doc, () => {
907
+ scrollToPin(doc, pin);
908
+ });
909
+ return pin.id;
910
+ } catch {
911
+ return null;
912
+ }
913
+ }
914
+ //#endregion
796
915
  //#region src/ui/aim.ts
797
916
  /**
798
917
  * True when aiming has to be done by dragging rather than by pointing.
@@ -2385,20 +2504,6 @@ const chipMemo = /* @__PURE__ */ new WeakMap();
2385
2504
  function nextOrdinal(pins) {
2386
2505
  return Math.max(pins.length, ...pins.map((p) => p.n ?? 0)) + 1;
2387
2506
  }
2388
- /**
2389
- * Does the pin's captured URL still describe the view on screen? Path + search
2390
- * only — hashes are anchors, not views. An absent or unparseable URL never
2391
- * gates: old pins (and CLI pins) keep rendering exactly as before.
2392
- */
2393
- function sameView(win, url) {
2394
- if (url === void 0) return true;
2395
- try {
2396
- const target = new URL(url, win.location.href);
2397
- return target.pathname === win.location.pathname && target.search === win.location.search;
2398
- } catch {
2399
- return true;
2400
- }
2401
- }
2402
2507
  /** A stored (document-space) rect or point, in today's viewport. */
2403
2508
  function toViewport(win, p) {
2404
2509
  return {
@@ -2425,21 +2530,21 @@ function anchorRect(doc, pin) {
2425
2530
  function targetRect(doc, target) {
2426
2531
  if (target?.model) return projectModelTarget(doc, target.model);
2427
2532
  const stored = target?.rect;
2428
- if (stored === void 0) return null;
2429
2533
  const win = doc.defaultView;
2430
- if (win === null) return stored;
2431
- if (!sameView(win, target?.url)) return null;
2534
+ if (win === null) return stored ?? null;
2535
+ if (!samePinView(win, target?.url)) return null;
2432
2536
  const selector = target?.selector;
2433
- if (selector === void 0) return toViewport(win, stored);
2537
+ if (selector === void 0) return stored ? toViewport(win, stored) : null;
2538
+ if (!stored && (selector === "html" || selector === "body")) return null;
2434
2539
  let el;
2435
2540
  try {
2436
2541
  el = doc.querySelector(selector);
2437
2542
  } catch {
2438
- return toViewport(win, stored);
2543
+ return stored ? toViewport(win, stored) : null;
2439
2544
  }
2440
2545
  if (el === null) return null;
2441
2546
  const r = el.getBoundingClientRect();
2442
- if (r.width <= 0 && r.height <= 0) return toViewport(win, stored);
2547
+ if (r.width <= 0 && r.height <= 0) return stored ? toViewport(win, stored) : null;
2443
2548
  return clipToScrollAncestors(win, el, {
2444
2549
  x: r.left,
2445
2550
  y: r.top,
@@ -2753,6 +2858,7 @@ function anchorOf(root, pin, draft) {
2753
2858
  * labels the card without claiming an element that was never captured.
2754
2859
  */
2755
2860
  function labelOf(target) {
2861
+ if (target?.selector === "html" || target?.selector === "body") return "PAGE";
2756
2862
  if (target?.model) return `3D · ${target.model.partId}`;
2757
2863
  return target?.anchor ?? target?.tag?.toUpperCase() ?? "PIN";
2758
2864
  }
@@ -3762,16 +3868,15 @@ var PinboxToolbarElement = class extends BaseElement {
3762
3868
  /** Inbox item click: activate the pin and scroll it into view (prototype line 700). */
3763
3869
  #activateFromInbox(pinId) {
3764
3870
  const pin = this.store.get().pins.find((p) => p.id === pinId);
3871
+ if (!pin) return;
3872
+ this.store.update({
3873
+ inboxOpen: false,
3874
+ activePinId: null,
3875
+ pinsHidden: false
3876
+ });
3877
+ if (revealPin(document, pin, this.config?.endpoint ?? "")) return;
3765
3878
  this.#ensureThread(pinId);
3766
3879
  this.store.update({ activePinId: pinId });
3767
- const rect = pin === void 0 ? null : anchorRect(document, pin);
3768
- if (rect) {
3769
- const y = window.scrollY + rect.y + rect.height / 2;
3770
- window.scrollTo({
3771
- top: Math.max(0, y - window.innerHeight / 2),
3772
- behavior: "smooth"
3773
- });
3774
- }
3775
3880
  }
3776
3881
  /**
3777
3882
  * Nudge a stale pin: re-post the last human message as a new thread message. A watcher that
@@ -3920,6 +4025,16 @@ var PinboxToolbarElement = class extends BaseElement {
3920
4025
  });
3921
4026
  };
3922
4027
  #render(state) {
4028
+ const restored = pendingPinReveal(document, state.pins, this.config?.endpoint ?? "");
4029
+ if (restored) {
4030
+ this.#ensureThread(restored);
4031
+ this.store.update({
4032
+ activePinId: restored,
4033
+ inboxOpen: false,
4034
+ pinsHidden: false
4035
+ });
4036
+ return;
4037
+ }
3923
4038
  const placing = state.mode === "placing";
3924
4039
  this.toggleAttribute("data-placing", placing);
3925
4040
  document.body.classList.toggle(PAGE_PLACING_CLASS, placing);
@@ -3932,6 +4047,184 @@ var PinboxToolbarElement = class extends BaseElement {
3932
4047
  }
3933
4048
  };
3934
4049
  //#endregion
4050
+ //#region src/ui/preview-styles.ts
4051
+ const PREVIEW_STYLES = `
4052
+ .pb-preview-wrap { display:flex; align-items:center; border-left:1px solid var(--pb-line); margin-left:4px; padding-left:4px; }
4053
+ .pb-preview-trigger { max-width:160px; gap:7px; }
4054
+ .pb-preview-trigger .name { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:110px; }
4055
+ .pb-preview-trigger svg { flex-shrink:0; }
4056
+ .pb-preview-menu { position:fixed; margin:0; padding:0; width:304px; max-width:calc(100vw - 24px); max-height:70vh; overflow:auto; background:var(--pb-surface); color:var(--pb-fg1); border:1px solid var(--pb-line-2); border-radius:4px; box-shadow:var(--pb-shadow); font-family:var(--pb-font-body); }
4057
+ .pb-preview-menu::backdrop { background:transparent; }
4058
+ .pb-preview-head { display:flex; align-items:center; justify-content:space-between; padding:10px 12px 8px 16px; border-bottom:1px solid var(--pb-line); }
4059
+ .pb-preview-head span { font:10px var(--pb-font-mono); letter-spacing:.18em; color:var(--pb-fg3); }
4060
+ .pb-preview-list { padding:5px; }
4061
+ .pb-preview-option { display:flex; align-items:center; gap:10px; width:100%; text-align:left; padding:11px 10px; border-radius:2px; color:var(--pb-fg2); }
4062
+ .pb-preview-option:hover, .pb-preview-option:focus-visible { background:var(--pb-hover); outline:1px solid var(--pb-line-2); }
4063
+ .pb-preview-option[aria-checked="true"] { background:var(--pb-amber-soft); color:var(--pb-fg1); }
4064
+ .pb-preview-option:disabled { opacity:.45; cursor:not-allowed; }
4065
+ .pb-preview-option .check { width:14px; flex-shrink:0; color:var(--pb-amber); }
4066
+ .pb-preview-option .copy { display:flex; flex-direction:column; gap:4px; min-width:0; }
4067
+ .pb-preview-option .title { font-size:12px; font-weight:500; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
4068
+ .pb-preview-option .branch { font:10px var(--pb-font-mono); color:var(--pb-fg3); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
4069
+ .pb-preview-foot { border-top:1px solid var(--pb-line); padding:11px 16px; display:flex; flex-direction:column; gap:8px; }
4070
+ .pb-preview-status { font-size:11px; line-height:1.5; color:var(--pb-fg3); }
4071
+ .pb-preview-foot a { font:10px var(--pb-font-mono); letter-spacing:.08em; color:var(--pb-amber); text-decoration:none; }
4072
+ `;
4073
+ //#endregion
4074
+ //#region src/ui/preview-switcher.ts
4075
+ const CHEVRON = icon("<path d=\"m4 6 4 4 4-4\"/>", 14);
4076
+ const REFRESH = icon("<path d=\"M2 8a6 6 0 0 1 10.5-4L14 6M14 2v4h-4M14 8a6 6 0 0 1-10.5 4L2 10M2 14v-4h4\"/>", 14);
4077
+ const BRANCH = "<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.3\"><circle cx=\"4\" cy=\"3\" r=\"1.5\"/><circle cx=\"4\" cy=\"13\" r=\"1.5\"/><circle cx=\"12\" cy=\"4\" r=\"1.5\"/><path d=\"M4 4.5v7M12 5.5v1a3 3 0 0 1-3 3H7a3 3 0 0 0-3 3\"/></svg>";
4078
+ function createPreviewView(doc, root, bar) {
4079
+ const style = doc.createElement("style");
4080
+ style.textContent = PREVIEW_STYLES;
4081
+ root.append(style);
4082
+ const wrap = doc.createElement("div");
4083
+ wrap.dataset["previewSwitcher"] = "";
4084
+ wrap.className = "pb-preview-wrap";
4085
+ wrap.innerHTML = `<button type="button" class="pb-tb pb-preview-trigger" aria-label="Switch preview" aria-haspopup="menu" aria-controls="pb-preview-menu" aria-expanded="false">${BRANCH}<span class="name">PREVIEW</span>${CHEVRON}</button>
4086
+ <div id="pb-preview-menu" class="pb-preview-menu" popover="auto" aria-label="Local previews">
4087
+ <div class="pb-preview-head"><span>LOCAL PREVIEWS</span><button type="button" class="pb-tb sq" aria-label="Refresh previews">${REFRESH}</button></div>
4088
+ <div class="pb-preview-list" role="menu" aria-label="Preview branch or worktree"></div>
4089
+ <div class="pb-preview-foot"><span class="pb-preview-status" role="status">Loading previews…</span><a target="_blank" rel="noopener noreferrer" hidden>OPEN PR ↗</a></div>
4090
+ </div>`;
4091
+ bar.append(wrap);
4092
+ const trigger = wrap.querySelector(".pb-preview-trigger");
4093
+ const panel = wrap.querySelector(".pb-preview-menu");
4094
+ const list = wrap.querySelector(".pb-preview-list");
4095
+ const reload = wrap.querySelector("[aria-label=\"Refresh previews\"]");
4096
+ const status = wrap.querySelector("[role=\"status\"]");
4097
+ const pr = wrap.querySelector("a");
4098
+ wirePopover(trigger, panel, list, doc);
4099
+ return {
4100
+ trigger,
4101
+ list,
4102
+ status,
4103
+ reload,
4104
+ render(choices) {
4105
+ renderOptions(doc, list, choices);
4106
+ const current = choices.find((p) => p.current);
4107
+ trigger.querySelector(".name").textContent = compactLabel(current);
4108
+ trigger.setAttribute("aria-label", `Switch preview: ${current?.label ?? "local previews"}`);
4109
+ trigger.title = current ? `${current.branch} · ${current.commit.slice(0, 8)}` : "Choose a preview";
4110
+ status.textContent = current?.backend || "Local frontend preview";
4111
+ pr.hidden = !current?.pr;
4112
+ if (current?.pr) pr.href = current.pr;
4113
+ }
4114
+ };
4115
+ }
4116
+ function compactLabel(current) {
4117
+ if (!current) return "PREVIEW";
4118
+ return current.label.match(/^PR #\d+/)?.[0] ?? (current.branch === "main" ? "MAIN" : current.branch.replace(/^[^/]+\//, ""));
4119
+ }
4120
+ function renderOptions(doc, list, choices) {
4121
+ list.replaceChildren();
4122
+ for (const item of choices) {
4123
+ const button = doc.createElement("button");
4124
+ button.type = "button";
4125
+ button.className = "pb-preview-option";
4126
+ button.dataset["previewId"] = item.id;
4127
+ button.setAttribute("role", "menuitemradio");
4128
+ button.setAttribute("aria-checked", String(item.current));
4129
+ button.disabled = !item.ready;
4130
+ button.innerHTML = "<span class=\"check\" aria-hidden=\"true\"></span><span class=\"copy\"><span class=\"title\"></span><span class=\"branch\"></span></span>";
4131
+ button.querySelector(".check").textContent = item.current ? "✓" : "";
4132
+ button.querySelector(".title").textContent = item.label;
4133
+ button.querySelector(".branch").textContent = `${item.branch}${item.ready ? "" : " · unavailable"}`;
4134
+ list.append(button);
4135
+ }
4136
+ }
4137
+ function wirePopover(trigger, panel, list, doc) {
4138
+ trigger.addEventListener("click", () => {
4139
+ panel.togglePopover();
4140
+ const rect = trigger.getBoundingClientRect();
4141
+ const width = doc.documentElement.clientWidth;
4142
+ panel.style.left = `${Math.max(12, Math.min(rect.right - 304, width - 316))}px`;
4143
+ panel.style.top = `${rect.top > panel.offsetHeight + 20 ? rect.top - panel.offsetHeight - 10 : rect.bottom + 10}px`;
4144
+ (list.querySelector("button[aria-checked=\"true\"]:not(:disabled)") ?? list.querySelector("button:not(:disabled)"))?.focus();
4145
+ });
4146
+ panel.addEventListener("toggle", () => trigger.setAttribute("aria-expanded", String(panel.matches(":popover-open"))));
4147
+ panel.addEventListener("keydown", (e) => {
4148
+ const buttons = [...list.querySelectorAll("button:not(:disabled)")];
4149
+ const index = buttons.indexOf(panel.getRootNode().activeElement);
4150
+ if ([
4151
+ "ArrowDown",
4152
+ "ArrowUp",
4153
+ "Home",
4154
+ "End"
4155
+ ].includes(e.key)) {
4156
+ e.preventDefault();
4157
+ buttons[e.key === "Home" ? 0 : e.key === "End" ? buttons.length - 1 : (index + (e.key === "ArrowDown" ? 1 : -1) + buttons.length) % buttons.length]?.focus();
4158
+ }
4159
+ if (e.key === "Escape") {
4160
+ panel.hidePopover();
4161
+ trigger.focus();
4162
+ }
4163
+ });
4164
+ }
4165
+ //#endregion
4166
+ //#region src/previews.ts
4167
+ function previewDestination(origin, current) {
4168
+ const target = new URL(origin);
4169
+ const source = new URL(current);
4170
+ if (!["http:", "https:"].includes(target.protocol) || target.username || target.password || target.pathname !== "/" || target.search || target.hash) throw new Error("Invalid preview origin");
4171
+ target.pathname = source.pathname;
4172
+ target.search = source.search;
4173
+ target.hash = source.hash;
4174
+ return target.href;
4175
+ }
4176
+ function mountPreviewSwitcher(host, endpoint) {
4177
+ const root = host.shadowRoot;
4178
+ const bar = root?.querySelector(".pb-bar");
4179
+ if (!root || !bar || root.querySelector("[data-preview-switcher]")) return;
4180
+ const doc = host.ownerDocument;
4181
+ const { trigger, list, status, reload, render } = createPreviewView(doc, root, bar);
4182
+ let choices = [];
4183
+ let busy = false;
4184
+ const load = async () => {
4185
+ const response = await fetch(endpoint, {
4186
+ credentials: "same-origin",
4187
+ cache: "no-store"
4188
+ });
4189
+ const envelope = await response.json();
4190
+ if (!response.ok || !envelope.ok || !Array.isArray(envelope.data)) throw new Error("Preview discovery unavailable");
4191
+ return envelope.data;
4192
+ };
4193
+ async function refresh() {
4194
+ if (busy) return;
4195
+ busy = true;
4196
+ try {
4197
+ choices = await load();
4198
+ render(choices);
4199
+ trigger.disabled = false;
4200
+ } catch {
4201
+ status.textContent = "Preview discovery unavailable";
4202
+ trigger.disabled = false;
4203
+ } finally {
4204
+ busy = false;
4205
+ }
4206
+ }
4207
+ reload.addEventListener("click", () => {
4208
+ refresh();
4209
+ });
4210
+ list.addEventListener("click", async (event) => {
4211
+ const target = event.target.closest("[data-preview-id]");
4212
+ const id = target?.dataset["previewId"];
4213
+ if (!id || target?.disabled) return;
4214
+ trigger.disabled = true;
4215
+ status.textContent = "Checking preview…";
4216
+ try {
4217
+ const destination = (await load()).find((p) => p.id === id);
4218
+ if (!destination?.ready || !destination.url) throw new Error("unavailable");
4219
+ doc.defaultView?.location.assign(previewDestination(destination.url, doc.location.href));
4220
+ } catch {
4221
+ status.textContent = "Preview unavailable. Refresh to try again.";
4222
+ trigger.disabled = false;
4223
+ }
4224
+ });
4225
+ refresh();
4226
+ }
4227
+ //#endregion
3935
4228
  //#region src/index.ts
3936
4229
  /** Register <pinbox-toolbar>; no-op outside a browser or when already defined. */
3937
4230
  function defineToolbarElement() {
@@ -3947,4 +4240,4 @@ const Pinbox = { init(config) {
3947
4240
  } };
3948
4241
  defineToolbarElement();
3949
4242
  //#endregion
3950
- export { HubError as a, createStore as c, HubTransport as i, deriveUiStatus as l, defineToolbarElement as n, appendThreadMessage as o, PinboxToolbarElement as r, applyHubEvent as s, Pinbox as t, upsertPin as u };
4243
+ export { HubTransport as a, applyHubEvent as c, upsertPin as d, PinboxToolbarElement as i, createStore as l, defineToolbarElement as n, HubError as o, mountPreviewSwitcher as r, appendThreadMessage as s, Pinbox as t, deriveUiStatus as u };
package/dist/svelte.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as applyHubEvent, a as HubEvent, b as upsertPin, c as WebSocketLike, d as PinboxToolbarElement, f as Draft, g as appendThreadMessage, h as UiStatus, i as ConnectionState, l as HubError, m as ToolbarState, n as PinboxConfig, o as HubTransport, p as Store, r as defineToolbarElement, s as TransportOptions, t as Pinbox, u as StorageLike, v as createStore, x as CaptureResult, y as deriveUiStatus } from "./index-xNXeJ2mR.js";
1
+ import { S as CaptureResult, _ as appendThreadMessage, a as HubEvent, b as deriveUiStatus, c as WebSocketLike, d as mountPreviewSwitcher, f as PinboxToolbarElement, g as UiStatus, h as ToolbarState, i as ConnectionState, l as HubError, m as Store, n as PinboxConfig, o as HubTransport, p as Draft, r as defineToolbarElement, s as TransportOptions, t as Pinbox, u as StorageLike, v as applyHubEvent, x as upsertPin, y as createStore } from "./index-CMSOhoVs.js";
2
2
  import { Action } from "svelte/action";
3
3
  //#region src/svelte.d.ts
4
4
  /**
@@ -8,4 +8,4 @@ import { Action } from "svelte/action";
8
8
  */
9
9
  declare const pinbox: Action<HTMLElement, PinboxConfig>;
10
10
  //#endregion
11
- export { type CaptureResult, type ConnectionState, type Draft, HubError, type HubEvent, HubTransport, Pinbox, PinboxConfig, PinboxToolbarElement, type StorageLike, type Store, type ToolbarState, type TransportOptions, type UiStatus, type WebSocketLike, appendThreadMessage, applyHubEvent, createStore, defineToolbarElement, deriveUiStatus, pinbox, upsertPin };
11
+ export { type CaptureResult, type ConnectionState, type Draft, HubError, type HubEvent, HubTransport, Pinbox, PinboxConfig, PinboxToolbarElement, type StorageLike, type Store, type ToolbarState, type TransportOptions, type UiStatus, type WebSocketLike, appendThreadMessage, applyHubEvent, createStore, defineToolbarElement, deriveUiStatus, mountPreviewSwitcher, pinbox, upsertPin };
package/dist/svelte.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as HubError, c as createStore, i as HubTransport, l as deriveUiStatus, n as defineToolbarElement, o as appendThreadMessage, r as PinboxToolbarElement, s as applyHubEvent, t as Pinbox, u as upsertPin } from "./src-DnAkx29T.js";
1
+ import { a as HubTransport, c as applyHubEvent, d as upsertPin, i as PinboxToolbarElement, l as createStore, n as defineToolbarElement, o as HubError, r as mountPreviewSwitcher, s as appendThreadMessage, t as Pinbox, u as deriveUiStatus } from "./src-B134WXZ8.js";
2
2
  //#region src/svelte.ts
3
3
  /**
4
4
  * `<div use:pinbox={{ endpoint }} />` — creates + configures the element BEFORE insertion
@@ -15,4 +15,4 @@ const pinbox = (_node, config) => {
15
15
  } };
16
16
  };
17
17
  //#endregion
18
- export { HubError, HubTransport, Pinbox, PinboxToolbarElement, appendThreadMessage, applyHubEvent, createStore, defineToolbarElement, deriveUiStatus, pinbox, upsertPin };
18
+ export { HubError, HubTransport, Pinbox, PinboxToolbarElement, appendThreadMessage, applyHubEvent, createStore, defineToolbarElement, deriveUiStatus, mountPreviewSwitcher, pinbox, upsertPin };
@@ -839,6 +839,125 @@ var Pinbox = (function(exports) {
839
839
  return true;
840
840
  }
841
841
  //#endregion
842
+ //#region src/reveal-settle.ts
843
+ const pending = /* @__PURE__ */ new WeakMap();
844
+ function cancelRevealSettle(doc) {
845
+ pending.get(doc)?.();
846
+ }
847
+ function settlePinReveal(doc, reveal) {
848
+ cancelRevealSettle(doc);
849
+ const win = doc.defaultView;
850
+ if (!win) return;
851
+ let attempts = 0;
852
+ let timer = 0;
853
+ const events = [
854
+ "wheel",
855
+ "touchstart",
856
+ "pointerdown",
857
+ "keydown"
858
+ ];
859
+ const stop = () => {
860
+ win.clearTimeout(timer);
861
+ for (const event of events) doc.removeEventListener(event, stop, true);
862
+ pending.delete(doc);
863
+ };
864
+ for (const event of events) doc.addEventListener(event, stop, {
865
+ capture: true,
866
+ passive: true
867
+ });
868
+ const tick = () => {
869
+ reveal();
870
+ if (++attempts >= 10) stop();
871
+ else timer = win.setTimeout(tick, 150);
872
+ };
873
+ pending.set(doc, stop);
874
+ timer = win.setTimeout(tick, 150);
875
+ }
876
+ //#endregion
877
+ //#region src/pin-reveal.ts
878
+ /** Query ordering is not a view change; repeated parameter ordering remains intact. */
879
+ function samePinView(win, value) {
880
+ if (!value) return true;
881
+ try {
882
+ const target = new URL(value, win.location.href);
883
+ const current = new URL(win.location.href);
884
+ target.searchParams.sort();
885
+ current.searchParams.sort();
886
+ return target.pathname === current.pathname && target.search === current.search;
887
+ } catch {
888
+ return true;
889
+ }
890
+ }
891
+ function pagePin(pin) {
892
+ return pin.target?.selector === "html" || pin.target?.selector === "body";
893
+ }
894
+ /** Resolve before clipping: an offscreen row is precisely the target we need to scroll. */
895
+ function scrollToPin(doc, pin) {
896
+ if (pin.target?.model || pagePin(pin)) return false;
897
+ const win = doc.defaultView;
898
+ if (!win || !samePinView(win, pin.target?.url) || !pin.target?.selector) return false;
899
+ try {
900
+ const element = doc.querySelector(pin.target.selector);
901
+ if (!element?.getClientRects().length) return false;
902
+ element.scrollIntoView({
903
+ behavior: "instant",
904
+ block: "center",
905
+ inline: "center"
906
+ });
907
+ return true;
908
+ } catch {
909
+ return false;
910
+ }
911
+ }
912
+ const key = (endpoint) => `pinbox:${endpoint}:reveal`;
913
+ /** Returns true when leaving this document. Never navigates to a different origin. */
914
+ function revealPin(doc, pin, endpoint) {
915
+ cancelRevealSettle(doc);
916
+ const win = doc.defaultView;
917
+ if (!win) return false;
918
+ try {
919
+ win.sessionStorage.removeItem(key(endpoint));
920
+ } catch {}
921
+ if (pagePin(pin) || pin.target?.model) return false;
922
+ if (pin.target?.url && !samePinView(win, pin.target.url)) try {
923
+ const target = new URL(pin.target.url, win.location.href);
924
+ if (target.origin !== win.location.origin || !["http:", "https:"].includes(target.protocol)) return false;
925
+ win.sessionStorage.setItem(key(endpoint), JSON.stringify({
926
+ id: pin.id,
927
+ expires: Date.now() + 3e4
928
+ }));
929
+ win.location.assign(target.href);
930
+ return true;
931
+ } catch {
932
+ return false;
933
+ }
934
+ scrollToPin(doc, pin);
935
+ return false;
936
+ }
937
+ /** Called on pin updates and DOM changes: SPA content may arrive after the toolbar. */
938
+ function pendingPinReveal(doc, pins, endpoint) {
939
+ const win = doc.defaultView;
940
+ if (!win) return null;
941
+ try {
942
+ const raw = win.sessionStorage.getItem(key(endpoint));
943
+ if (!raw) return null;
944
+ const pending = JSON.parse(raw);
945
+ if (typeof pending.id !== "string" || !Number.isFinite(pending.expires) || pending.expires < Date.now()) {
946
+ win.sessionStorage.removeItem(key(endpoint));
947
+ return null;
948
+ }
949
+ const pin = pins.find((p) => p.id === pending.id);
950
+ if (!pin || !scrollToPin(doc, pin)) return null;
951
+ win.sessionStorage.removeItem(key(endpoint));
952
+ settlePinReveal(doc, () => {
953
+ scrollToPin(doc, pin);
954
+ });
955
+ return pin.id;
956
+ } catch {
957
+ return null;
958
+ }
959
+ }
960
+ //#endregion
842
961
  //#region src/targeting/dom.ts
843
962
  /**
844
963
  * Deepest element under (clientX, clientY) that the caller does not ignore, or null when there is
@@ -2695,20 +2814,6 @@ var Pinbox = (function(exports) {
2695
2814
  function nextOrdinal(pins) {
2696
2815
  return Math.max(pins.length, ...pins.map((p) => p.n ?? 0)) + 1;
2697
2816
  }
2698
- /**
2699
- * Does the pin's captured URL still describe the view on screen? Path + search
2700
- * only — hashes are anchors, not views. An absent or unparseable URL never
2701
- * gates: old pins (and CLI pins) keep rendering exactly as before.
2702
- */
2703
- function sameView(win, url) {
2704
- if (url === void 0) return true;
2705
- try {
2706
- const target = new URL(url, win.location.href);
2707
- return target.pathname === win.location.pathname && target.search === win.location.search;
2708
- } catch {
2709
- return true;
2710
- }
2711
- }
2712
2817
  /** A stored (document-space) rect or point, in today's viewport. */
2713
2818
  function toViewport(win, p) {
2714
2819
  return {
@@ -2735,21 +2840,21 @@ var Pinbox = (function(exports) {
2735
2840
  function targetRect(doc, target) {
2736
2841
  if (target?.model) return projectModelTarget(doc, target.model);
2737
2842
  const stored = target?.rect;
2738
- if (stored === void 0) return null;
2739
2843
  const win = doc.defaultView;
2740
- if (win === null) return stored;
2741
- if (!sameView(win, target?.url)) return null;
2844
+ if (win === null) return stored ?? null;
2845
+ if (!samePinView(win, target?.url)) return null;
2742
2846
  const selector = target?.selector;
2743
- if (selector === void 0) return toViewport(win, stored);
2847
+ if (selector === void 0) return stored ? toViewport(win, stored) : null;
2848
+ if (!stored && (selector === "html" || selector === "body")) return null;
2744
2849
  let el;
2745
2850
  try {
2746
2851
  el = doc.querySelector(selector);
2747
2852
  } catch {
2748
- return toViewport(win, stored);
2853
+ return stored ? toViewport(win, stored) : null;
2749
2854
  }
2750
2855
  if (el === null) return null;
2751
2856
  const r = el.getBoundingClientRect();
2752
- if (r.width <= 0 && r.height <= 0) return toViewport(win, stored);
2857
+ if (r.width <= 0 && r.height <= 0) return stored ? toViewport(win, stored) : null;
2753
2858
  return clipToScrollAncestors(win, el, {
2754
2859
  x: r.left,
2755
2860
  y: r.top,
@@ -3063,6 +3168,7 @@ var Pinbox = (function(exports) {
3063
3168
  * labels the card without claiming an element that was never captured.
3064
3169
  */
3065
3170
  function labelOf(target) {
3171
+ if (target?.selector === "html" || target?.selector === "body") return "PAGE";
3066
3172
  if (target?.model) return `3D · ${target.model.partId}`;
3067
3173
  return target?.anchor ?? target?.tag?.toUpperCase() ?? "PIN";
3068
3174
  }
@@ -4072,16 +4178,15 @@ button { font: inherit; color: inherit; background: none; border: 0; cursor: poi
4072
4178
  /** Inbox item click: activate the pin and scroll it into view (prototype line 700). */
4073
4179
  #activateFromInbox(pinId) {
4074
4180
  const pin = this.store.get().pins.find((p) => p.id === pinId);
4181
+ if (!pin) return;
4182
+ this.store.update({
4183
+ inboxOpen: false,
4184
+ activePinId: null,
4185
+ pinsHidden: false
4186
+ });
4187
+ if (revealPin(document, pin, this.config?.endpoint ?? "")) return;
4075
4188
  this.#ensureThread(pinId);
4076
4189
  this.store.update({ activePinId: pinId });
4077
- const rect = pin === void 0 ? null : anchorRect(document, pin);
4078
- if (rect) {
4079
- const y = window.scrollY + rect.y + rect.height / 2;
4080
- window.scrollTo({
4081
- top: Math.max(0, y - window.innerHeight / 2),
4082
- behavior: "smooth"
4083
- });
4084
- }
4085
4190
  }
4086
4191
  /**
4087
4192
  * Nudge a stale pin: re-post the last human message as a new thread message. A watcher that
@@ -4230,6 +4335,16 @@ button { font: inherit; color: inherit; background: none; border: 0; cursor: poi
4230
4335
  });
4231
4336
  };
4232
4337
  #render(state) {
4338
+ const restored = pendingPinReveal(document, state.pins, this.config?.endpoint ?? "");
4339
+ if (restored) {
4340
+ this.#ensureThread(restored);
4341
+ this.store.update({
4342
+ activePinId: restored,
4343
+ inboxOpen: false,
4344
+ pinsHidden: false
4345
+ });
4346
+ return;
4347
+ }
4233
4348
  const placing = state.mode === "placing";
4234
4349
  this.toggleAttribute("data-placing", placing);
4235
4350
  document.body.classList.toggle(PAGE_PLACING_CLASS, placing);
package/dist/vue.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { d as PinboxToolbarElement, n as PinboxConfig } from "./index-xNXeJ2mR.js";
1
+ import { f as PinboxToolbarElement, n as PinboxConfig } from "./index-CMSOhoVs.js";
2
2
  import { VNode } from "vue";
3
3
  //#region src/vue.d.ts
4
4
  /** The slice of the Vue component instance this wrapper touches. */
package/dist/vue.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as defineToolbarElement, r as PinboxToolbarElement } from "./src-DnAkx29T.js";
1
+ import { i as PinboxToolbarElement, n as defineToolbarElement } from "./src-B134WXZ8.js";
2
2
  import { h } from "vue";
3
3
  //#region src/vue.ts
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autono/pinbox-toolbar",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -75,7 +75,7 @@
75
75
  }
76
76
  },
77
77
  "devDependencies": {
78
- "@autono/pinbox-core": "0.20.0",
78
+ "@autono/pinbox-core": "0.21.0",
79
79
  "@types/react": "^19.2.0",
80
80
  "typescript": "^7.0.0",
81
81
  "tsdown": "^0.22.0",