@autono/pinbox-toolbar 0.8.0 → 0.9.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/index-DK_kVd2Z.d.ts +240 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{src-D1qn1iet.js → src-ChTPrRo5.js} +567 -6
- package/dist/svelte.d.ts +1 -1
- package/dist/svelte.js +1 -1
- package/dist/toolbar.iife.js +567 -6
- package/dist/vue.d.ts +1 -1
- package/dist/vue.js +1 -1
- package/package.json +2 -2
- package/dist/index-BAoi0bRT.d.ts +0 -2633
|
@@ -287,6 +287,448 @@ function pinsToMarkdown(pins, threads) {
|
|
|
287
287
|
return `${open.map((p) => block(p, threads.get(p.id) ?? [])).join("\n\n")}\n`;
|
|
288
288
|
}
|
|
289
289
|
//#endregion
|
|
290
|
+
//#region src/motion/spring.ts
|
|
291
|
+
/** Bar ⇄ puck morphs and the post-drag settle. */
|
|
292
|
+
const MORPH_SPRING = {
|
|
293
|
+
k: 300,
|
|
294
|
+
c: 30
|
|
295
|
+
};
|
|
296
|
+
/** The morph surface chasing the pointer mid-drag. */
|
|
297
|
+
const FOLLOW_SPRING = {
|
|
298
|
+
k: 600,
|
|
299
|
+
c: 38
|
|
300
|
+
};
|
|
301
|
+
/** Integration substep — small enough that MORPH/FOLLOW stay stable at any dt. */
|
|
302
|
+
const SUBSTEP = 1 / 240;
|
|
303
|
+
/** A property this close to target, moving this slowly, counts as settled. */
|
|
304
|
+
const SETTLE = .5;
|
|
305
|
+
function mkSpring(init) {
|
|
306
|
+
const cur = { ...init };
|
|
307
|
+
const tgt = { ...init };
|
|
308
|
+
const keys = Object.keys(init);
|
|
309
|
+
const vel = {};
|
|
310
|
+
for (const key of keys) vel[key] = 0;
|
|
311
|
+
let cfg = { ...MORPH_SPRING };
|
|
312
|
+
const curN = cur;
|
|
313
|
+
const tgtN = tgt;
|
|
314
|
+
function integrate(h) {
|
|
315
|
+
for (const key of keys) {
|
|
316
|
+
const x = curN[key] ?? 0;
|
|
317
|
+
const v = vel[key] ?? 0;
|
|
318
|
+
const nextV = v + (-cfg.k * (x - (tgtN[key] ?? 0)) - cfg.c * v) * h;
|
|
319
|
+
vel[key] = nextV;
|
|
320
|
+
curN[key] = x + nextV * h;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
cur,
|
|
325
|
+
tgt,
|
|
326
|
+
snap(values) {
|
|
327
|
+
Object.assign(cur, values);
|
|
328
|
+
Object.assign(tgt, values);
|
|
329
|
+
for (const key of Object.keys(vel)) vel[key] = 0;
|
|
330
|
+
},
|
|
331
|
+
to(values, nextCfg) {
|
|
332
|
+
Object.assign(tgt, values);
|
|
333
|
+
if (nextCfg) cfg = { ...nextCfg };
|
|
334
|
+
},
|
|
335
|
+
step(dt) {
|
|
336
|
+
let remaining = dt;
|
|
337
|
+
while (remaining > 1e-6) {
|
|
338
|
+
const h = Math.min(SUBSTEP, remaining);
|
|
339
|
+
remaining -= h;
|
|
340
|
+
integrate(h);
|
|
341
|
+
}
|
|
342
|
+
for (const key of keys) {
|
|
343
|
+
const v = vel[key] ?? 0;
|
|
344
|
+
const gap = (curN[key] ?? 0) - (tgtN[key] ?? 0);
|
|
345
|
+
if (Math.abs(v) > SETTLE || Math.abs(gap) > SETTLE) return false;
|
|
346
|
+
}
|
|
347
|
+
this.snap({ ...tgt });
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
//#endregion
|
|
353
|
+
//#region src/minimize.ts
|
|
354
|
+
const PUCK = 48;
|
|
355
|
+
const MARGIN = 16;
|
|
356
|
+
/** Movement that begins a drag… */
|
|
357
|
+
const DRAG_START = 8;
|
|
358
|
+
/** …but a release under this much TOTAL travel is still a tap. */
|
|
359
|
+
const TAP_MAX = 12;
|
|
360
|
+
/** Spring hold while the surface swap crossfades (ms). */
|
|
361
|
+
const HOLD_MINIMIZE = 90;
|
|
362
|
+
const HOLD_RESTORE = 70;
|
|
363
|
+
/** Arrival: real element fades in first, morph layer fades this much later. */
|
|
364
|
+
const SWAP_FADE = 100;
|
|
365
|
+
/** …and is display:none'd once its own fade has finished. */
|
|
366
|
+
const LAYER_HIDE = 140;
|
|
367
|
+
const BAR_RADIUS = 4;
|
|
368
|
+
/** The carrier icon rides the surface only while it is puck-like (< this width). */
|
|
369
|
+
const CARRIER_MAX_W = 260;
|
|
370
|
+
function createMinimize(host) {
|
|
371
|
+
const { win, bar, ui } = host;
|
|
372
|
+
const main = mkSpring({
|
|
373
|
+
x: 0,
|
|
374
|
+
y: 0,
|
|
375
|
+
w: 0,
|
|
376
|
+
h: 0,
|
|
377
|
+
r: 0
|
|
378
|
+
});
|
|
379
|
+
let mode = "bar";
|
|
380
|
+
let puckPos = null;
|
|
381
|
+
let dock = loadDock();
|
|
382
|
+
let pdown = null;
|
|
383
|
+
let keyboardToggle = false;
|
|
384
|
+
let raf = 0;
|
|
385
|
+
let last = 0;
|
|
386
|
+
let holdTimer = 0;
|
|
387
|
+
let fadeTimer = 0;
|
|
388
|
+
let hideTimer = 0;
|
|
389
|
+
function loadDock() {
|
|
390
|
+
try {
|
|
391
|
+
const raw = host.storage?.getItem(`${host.storagePrefix}:dock`);
|
|
392
|
+
if (raw == null) return null;
|
|
393
|
+
const parsed = JSON.parse(raw);
|
|
394
|
+
if (typeof parsed.x !== "number" || typeof parsed.y !== "number") return null;
|
|
395
|
+
return {
|
|
396
|
+
x: parsed.x,
|
|
397
|
+
y: parsed.y
|
|
398
|
+
};
|
|
399
|
+
} catch {
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
function persist() {
|
|
404
|
+
try {
|
|
405
|
+
if (dock) host.storage?.setItem(`${host.storagePrefix}:dock`, JSON.stringify(dock));
|
|
406
|
+
host.storage?.setItem(`${host.storagePrefix}:minimized`, mode === "bar" ? "0" : "1");
|
|
407
|
+
} catch {}
|
|
408
|
+
}
|
|
409
|
+
function loadMinimized() {
|
|
410
|
+
try {
|
|
411
|
+
const raw = host.storage?.getItem(`${host.storagePrefix}:minimized`);
|
|
412
|
+
return raw == null ? host.initialMinimized : raw === "1";
|
|
413
|
+
} catch {
|
|
414
|
+
return host.initialMinimized;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
const clamp = (v, lo, hi) => Math.min(Math.max(v, lo), hi);
|
|
418
|
+
function clampPos(p) {
|
|
419
|
+
return {
|
|
420
|
+
x: clamp(p.x, MARGIN, win.innerWidth - MARGIN - PUCK),
|
|
421
|
+
y: clamp(p.y, MARGIN, win.innerHeight - MARGIN - PUCK)
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
function defaultDock() {
|
|
425
|
+
const r = bar.getBoundingClientRect();
|
|
426
|
+
return {
|
|
427
|
+
x: r.left + r.width / 2 - PUCK / 2,
|
|
428
|
+
y: r.top + (r.height - PUCK) / 2
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
function placePuck(x, y) {
|
|
432
|
+
puckPos = {
|
|
433
|
+
x,
|
|
434
|
+
y
|
|
435
|
+
};
|
|
436
|
+
ui.puck.style.transform = `translate(${x}px, ${y}px)`;
|
|
437
|
+
}
|
|
438
|
+
function render() {
|
|
439
|
+
const m = main.cur;
|
|
440
|
+
ui.surface.style.width = `${m.w}px`;
|
|
441
|
+
ui.surface.style.height = `${m.h}px`;
|
|
442
|
+
ui.surface.style.borderRadius = `${m.r}px`;
|
|
443
|
+
ui.surface.style.transform = `translate(${m.x}px, ${m.y}px)`;
|
|
444
|
+
ui.carrier.style.transform = `translate(${m.x + m.w / 2 - PUCK / 2}px, ${m.y + m.h / 2 - PUCK / 2}px)`;
|
|
445
|
+
const iconOn = mode === "drag" || mode === "settle" || (mode === "toPuck" || mode === "toBar") && m.w < CARRIER_MAX_W;
|
|
446
|
+
ui.carrier.classList.toggle("show", iconOn);
|
|
447
|
+
}
|
|
448
|
+
function showMorph() {
|
|
449
|
+
win.clearTimeout(hideTimer);
|
|
450
|
+
win.clearTimeout(fadeTimer);
|
|
451
|
+
ui.morphWrap.hidden = false;
|
|
452
|
+
ui.morphWrap.offsetWidth;
|
|
453
|
+
ui.morphWrap.classList.add("on");
|
|
454
|
+
}
|
|
455
|
+
function hideMorph() {
|
|
456
|
+
ui.morphWrap.classList.remove("on");
|
|
457
|
+
ui.carrier.classList.remove("show");
|
|
458
|
+
win.clearTimeout(hideTimer);
|
|
459
|
+
hideTimer = win.setTimeout(() => {
|
|
460
|
+
ui.morphWrap.hidden = true;
|
|
461
|
+
}, LAYER_HIDE);
|
|
462
|
+
}
|
|
463
|
+
function tick(now) {
|
|
464
|
+
const dt = Math.min((now - last) / 1e3, 1 / 30);
|
|
465
|
+
last = now;
|
|
466
|
+
const done = main.step(dt);
|
|
467
|
+
render();
|
|
468
|
+
if (done && mode !== "drag") {
|
|
469
|
+
raf = 0;
|
|
470
|
+
if (mode === "toPuck" || mode === "settle") finishPuck();
|
|
471
|
+
else if (mode === "toBar") finishBar();
|
|
472
|
+
} else raf = win.requestAnimationFrame(tick);
|
|
473
|
+
}
|
|
474
|
+
function ensureLoop() {
|
|
475
|
+
if (raf === 0) {
|
|
476
|
+
last = win.performance.now();
|
|
477
|
+
raf = win.requestAnimationFrame(tick);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
function finishPuck() {
|
|
481
|
+
placePuck(main.cur.x, main.cur.y);
|
|
482
|
+
ui.puck.classList.remove("pb-ghost");
|
|
483
|
+
win.clearTimeout(fadeTimer);
|
|
484
|
+
fadeTimer = win.setTimeout(hideMorph, SWAP_FADE);
|
|
485
|
+
mode = "puck";
|
|
486
|
+
persist();
|
|
487
|
+
host.onSettled(true, keyboardToggle);
|
|
488
|
+
}
|
|
489
|
+
function finishBar() {
|
|
490
|
+
bar.classList.remove("pb-ghost");
|
|
491
|
+
win.clearTimeout(fadeTimer);
|
|
492
|
+
fadeTimer = win.setTimeout(hideMorph, SWAP_FADE);
|
|
493
|
+
mode = "bar";
|
|
494
|
+
persist();
|
|
495
|
+
host.onSettled(false, keyboardToggle);
|
|
496
|
+
}
|
|
497
|
+
function minimize(keyboard = false) {
|
|
498
|
+
if (mode !== "bar") return;
|
|
499
|
+
pdown = null;
|
|
500
|
+
keyboardToggle = keyboard;
|
|
501
|
+
const r = bar.getBoundingClientRect();
|
|
502
|
+
const d = clampPos(dock ?? defaultDock());
|
|
503
|
+
bar.classList.add("pb-ghost");
|
|
504
|
+
if (host.reduced) {
|
|
505
|
+
placePuck(d.x, d.y);
|
|
506
|
+
ui.puck.classList.remove("pb-ghost");
|
|
507
|
+
mode = "puck";
|
|
508
|
+
persist();
|
|
509
|
+
host.onSettled(true, keyboard);
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
main.snap({
|
|
513
|
+
x: r.left,
|
|
514
|
+
y: r.top,
|
|
515
|
+
w: r.width,
|
|
516
|
+
h: r.height,
|
|
517
|
+
r: BAR_RADIUS
|
|
518
|
+
});
|
|
519
|
+
mode = "toPuck";
|
|
520
|
+
render();
|
|
521
|
+
showMorph();
|
|
522
|
+
win.clearTimeout(holdTimer);
|
|
523
|
+
holdTimer = win.setTimeout(() => {
|
|
524
|
+
main.to({
|
|
525
|
+
x: d.x,
|
|
526
|
+
y: d.y,
|
|
527
|
+
w: PUCK,
|
|
528
|
+
h: PUCK,
|
|
529
|
+
r: PUCK / 2
|
|
530
|
+
}, MORPH_SPRING);
|
|
531
|
+
ensureLoop();
|
|
532
|
+
}, HOLD_MINIMIZE);
|
|
533
|
+
}
|
|
534
|
+
function restore(keyboard = false) {
|
|
535
|
+
if (mode !== "puck" || puckPos === null) return;
|
|
536
|
+
pdown = null;
|
|
537
|
+
keyboardToggle = keyboard;
|
|
538
|
+
dock = { ...puckPos };
|
|
539
|
+
ui.puck.classList.add("pb-ghost");
|
|
540
|
+
if (host.reduced) {
|
|
541
|
+
bar.classList.remove("pb-ghost");
|
|
542
|
+
mode = "bar";
|
|
543
|
+
persist();
|
|
544
|
+
host.onSettled(false, keyboard);
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
const r = bar.getBoundingClientRect();
|
|
548
|
+
main.snap({
|
|
549
|
+
x: puckPos.x,
|
|
550
|
+
y: puckPos.y,
|
|
551
|
+
w: PUCK,
|
|
552
|
+
h: PUCK,
|
|
553
|
+
r: PUCK / 2
|
|
554
|
+
});
|
|
555
|
+
mode = "toBar";
|
|
556
|
+
render();
|
|
557
|
+
showMorph();
|
|
558
|
+
win.clearTimeout(holdTimer);
|
|
559
|
+
holdTimer = win.setTimeout(() => {
|
|
560
|
+
main.to({
|
|
561
|
+
x: r.left,
|
|
562
|
+
y: r.top,
|
|
563
|
+
w: r.width,
|
|
564
|
+
h: r.height,
|
|
565
|
+
r: BAR_RADIUS
|
|
566
|
+
}, MORPH_SPRING);
|
|
567
|
+
ensureLoop();
|
|
568
|
+
}, HOLD_RESTORE);
|
|
569
|
+
}
|
|
570
|
+
function onPointerDown(e) {
|
|
571
|
+
if (mode !== "puck" || e.button !== 0) return;
|
|
572
|
+
try {
|
|
573
|
+
ui.puck.setPointerCapture(e.pointerId);
|
|
574
|
+
} catch {}
|
|
575
|
+
if (puckPos === null) return;
|
|
576
|
+
pdown = {
|
|
577
|
+
px: e.clientX,
|
|
578
|
+
py: e.clientY,
|
|
579
|
+
ox: puckPos.x,
|
|
580
|
+
oy: puckPos.y,
|
|
581
|
+
lx: e.clientX,
|
|
582
|
+
ly: e.clientY,
|
|
583
|
+
moved: false
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
function onPointerMove(e) {
|
|
587
|
+
if (pdown === null) return;
|
|
588
|
+
pdown.lx = e.clientX;
|
|
589
|
+
pdown.ly = e.clientY;
|
|
590
|
+
const dx = e.clientX - pdown.px;
|
|
591
|
+
const dy = e.clientY - pdown.py;
|
|
592
|
+
if (!pdown.moved) {
|
|
593
|
+
if (mode !== "puck") {
|
|
594
|
+
pdown = null;
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
if (Math.hypot(dx, dy) < DRAG_START) return;
|
|
598
|
+
pdown.moved = true;
|
|
599
|
+
mode = "drag";
|
|
600
|
+
if (!host.reduced) {
|
|
601
|
+
ui.puck.classList.add("pb-ghost");
|
|
602
|
+
main.snap({
|
|
603
|
+
x: pdown.ox,
|
|
604
|
+
y: pdown.oy,
|
|
605
|
+
w: PUCK,
|
|
606
|
+
h: PUCK,
|
|
607
|
+
r: PUCK / 2
|
|
608
|
+
});
|
|
609
|
+
render();
|
|
610
|
+
showMorph();
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
const next = {
|
|
614
|
+
x: pdown.ox + dx,
|
|
615
|
+
y: pdown.oy + dy
|
|
616
|
+
};
|
|
617
|
+
if (host.reduced) {
|
|
618
|
+
const p = clampPos(next);
|
|
619
|
+
placePuck(p.x, p.y);
|
|
620
|
+
} else {
|
|
621
|
+
main.to({
|
|
622
|
+
...next,
|
|
623
|
+
w: PUCK,
|
|
624
|
+
h: PUCK,
|
|
625
|
+
r: PUCK / 2
|
|
626
|
+
}, FOLLOW_SPRING);
|
|
627
|
+
ensureLoop();
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
function onPointerUp() {
|
|
631
|
+
if (pdown === null) return;
|
|
632
|
+
const total = Math.hypot(pdown.lx - pdown.px, pdown.ly - pdown.py);
|
|
633
|
+
const wasDrag = pdown.moved && total >= TAP_MAX;
|
|
634
|
+
const origin = {
|
|
635
|
+
x: pdown.ox,
|
|
636
|
+
y: pdown.oy
|
|
637
|
+
};
|
|
638
|
+
const startedDrag = pdown.moved;
|
|
639
|
+
pdown = null;
|
|
640
|
+
if (!wasDrag) {
|
|
641
|
+
if (startedDrag && mode === "drag") {
|
|
642
|
+
main.snap({
|
|
643
|
+
x: origin.x,
|
|
644
|
+
y: origin.y,
|
|
645
|
+
w: PUCK,
|
|
646
|
+
h: PUCK,
|
|
647
|
+
r: PUCK / 2
|
|
648
|
+
});
|
|
649
|
+
placePuck(origin.x, origin.y);
|
|
650
|
+
ui.puck.classList.remove("pb-ghost");
|
|
651
|
+
hideMorph();
|
|
652
|
+
mode = "puck";
|
|
653
|
+
}
|
|
654
|
+
restore(false);
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
if (host.reduced) {
|
|
658
|
+
if (puckPos) {
|
|
659
|
+
const p = clampPos(puckPos);
|
|
660
|
+
placePuck(p.x, p.y);
|
|
661
|
+
dock = { ...p };
|
|
662
|
+
}
|
|
663
|
+
mode = "puck";
|
|
664
|
+
persist();
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
const p = clampPos({
|
|
668
|
+
x: main.tgt.x,
|
|
669
|
+
y: main.tgt.y
|
|
670
|
+
});
|
|
671
|
+
main.to({
|
|
672
|
+
...p,
|
|
673
|
+
w: PUCK,
|
|
674
|
+
h: PUCK,
|
|
675
|
+
r: PUCK / 2
|
|
676
|
+
}, MORPH_SPRING);
|
|
677
|
+
mode = "settle";
|
|
678
|
+
ensureLoop();
|
|
679
|
+
}
|
|
680
|
+
/** Keyboard/AT activation is a synthesized click (detail 0) with no pointer events. */
|
|
681
|
+
function onClick(e) {
|
|
682
|
+
if (e.detail === 0) restore(true);
|
|
683
|
+
}
|
|
684
|
+
function onResize() {
|
|
685
|
+
if (mode === "puck" && puckPos !== null) {
|
|
686
|
+
const p = clampPos(puckPos);
|
|
687
|
+
placePuck(p.x, p.y);
|
|
688
|
+
}
|
|
689
|
+
if (dock !== null) dock = clampPos(dock);
|
|
690
|
+
}
|
|
691
|
+
ui.puck.addEventListener("pointerdown", onPointerDown);
|
|
692
|
+
ui.puck.addEventListener("pointermove", onPointerMove);
|
|
693
|
+
ui.puck.addEventListener("pointerup", onPointerUp);
|
|
694
|
+
ui.puck.addEventListener("pointercancel", onPointerUp);
|
|
695
|
+
ui.puck.addEventListener("click", onClick);
|
|
696
|
+
win.addEventListener("resize", onResize);
|
|
697
|
+
return {
|
|
698
|
+
minimized: () => mode !== "bar",
|
|
699
|
+
mode: () => mode,
|
|
700
|
+
minimize,
|
|
701
|
+
restore,
|
|
702
|
+
applyInitial() {
|
|
703
|
+
if (!loadMinimized()) return;
|
|
704
|
+
const apply = () => {
|
|
705
|
+
if (mode !== "bar") return;
|
|
706
|
+
const d = clampPos(dock ?? defaultDock());
|
|
707
|
+
bar.classList.add("pb-ghost");
|
|
708
|
+
placePuck(d.x, d.y);
|
|
709
|
+
ui.puck.classList.remove("pb-ghost");
|
|
710
|
+
mode = "puck";
|
|
711
|
+
host.onSettled(true, false);
|
|
712
|
+
};
|
|
713
|
+
if (host.reduced) apply();
|
|
714
|
+
else win.requestAnimationFrame(apply);
|
|
715
|
+
},
|
|
716
|
+
destroy() {
|
|
717
|
+
ui.puck.removeEventListener("pointerdown", onPointerDown);
|
|
718
|
+
ui.puck.removeEventListener("pointermove", onPointerMove);
|
|
719
|
+
ui.puck.removeEventListener("pointerup", onPointerUp);
|
|
720
|
+
ui.puck.removeEventListener("pointercancel", onPointerUp);
|
|
721
|
+
ui.puck.removeEventListener("click", onClick);
|
|
722
|
+
win.removeEventListener("resize", onResize);
|
|
723
|
+
if (raf !== 0) win.cancelAnimationFrame(raf);
|
|
724
|
+
raf = 0;
|
|
725
|
+
win.clearTimeout(holdTimer);
|
|
726
|
+
win.clearTimeout(fadeTimer);
|
|
727
|
+
win.clearTimeout(hideTimer);
|
|
728
|
+
}
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
//#endregion
|
|
290
732
|
//#region src/screenshot.ts
|
|
291
733
|
const WEBP_QUALITY = .7;
|
|
292
734
|
const PLACEHOLDER_MAX = 32;
|
|
@@ -418,7 +860,8 @@ function initialState() {
|
|
|
418
860
|
activePinId: null,
|
|
419
861
|
inboxOpen: false,
|
|
420
862
|
connection: "connecting",
|
|
421
|
-
queuedIds: /* @__PURE__ */ new Set()
|
|
863
|
+
queuedIds: /* @__PURE__ */ new Set(),
|
|
864
|
+
minimized: false
|
|
422
865
|
};
|
|
423
866
|
}
|
|
424
867
|
function createStore() {
|
|
@@ -1113,6 +1556,7 @@ const INBOX_ICON = "<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\
|
|
|
1113
1556
|
const THEME_ICON = "<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"><path d=\"M8 1.6a6.4 6.4 0 100 12.8A5 5 0 018 1.6z\"/></svg>";
|
|
1114
1557
|
const COPY_ICON = "<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8\" rx=\"1\"/><path d=\"M10.5 3.5v-1a1 1 0 00-1-1h-6a1 1 0 00-1 1v6a1 1 0 001 1h1\"/></svg>";
|
|
1115
1558
|
const IDENT_ICON = "<svg width=\"15\" height=\"15\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"var(--pb-amber)\" stroke-width=\"1.4\"><rect x=\"2.5\" y=\"1.5\" width=\"11\" height=\"7\" rx=\"1\"/><path d=\"M8 8.5v6\"/><circle cx=\"8\" cy=\"14.6\" r=\".9\" fill=\"var(--pb-amber)\" stroke=\"none\"/></svg>";
|
|
1559
|
+
const MIN_ICON = "<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"><path d=\"M6.5 2.5v4h-4\"/><path d=\"M9.5 13.5v-4h4\"/></svg>";
|
|
1116
1560
|
const CONNECTION_LABEL = {
|
|
1117
1561
|
connecting: "PINBOX",
|
|
1118
1562
|
live: "PINBOX",
|
|
@@ -1122,7 +1566,7 @@ const CONNECTION_LABEL = {
|
|
|
1122
1566
|
function createBar(doc, on) {
|
|
1123
1567
|
const root = doc.createElement("div");
|
|
1124
1568
|
root.className = "pb-bar";
|
|
1125
|
-
root.innerHTML = `<div class="armed-ring"></div><div class="ident">${IDENT_ICON}<span class="bl" data-ref="label">PINBOX</span></div><div class="div"></div><button type="button" class="pb-tb" data-ref="pin" title="Pin (P)">${PIN_ICON}PIN</button><button type="button" class="pb-tb" data-ref="inbox" title="Inbox (I)">${INBOX_ICON}<span data-ref="count">0</span></button><div class="div" style="margin:0 3px"></div><button type="button" class="pb-tb sq" data-ref="copy" title="Copy open pins (C)">${COPY_ICON}</button><button type="button" class="pb-tb sq" data-ref="theme" title="Theme (D)">${THEME_ICON}</button><button type="button" class="pb-tb sq" data-ref="help" title="Shortcuts (?)">?</button>`;
|
|
1569
|
+
root.innerHTML = `<div class="armed-ring"></div><div class="ident">${IDENT_ICON}<span class="bl" data-ref="label">PINBOX</span></div><div class="div"></div><button type="button" class="pb-tb" data-ref="pin" title="Pin (P)">${PIN_ICON}PIN</button><button type="button" class="pb-tb" data-ref="inbox" title="Inbox (I)">${INBOX_ICON}<span data-ref="count">0</span></button><div class="div" style="margin:0 3px"></div><button type="button" class="pb-tb sq" data-ref="copy" title="Copy open pins (C)">${COPY_ICON}</button><button type="button" class="pb-tb sq" data-ref="theme" title="Theme (D)">${THEME_ICON}</button><button type="button" class="pb-tb sq" data-ref="help" title="Shortcuts (?)">?</button><button type="button" class="pb-tb sq" data-ref="min" title="Minimize (M)" aria-label="Minimize toolbar">${MIN_ICON}</button>`;
|
|
1126
1570
|
const ref = (name) => root.querySelector(`[data-ref="${name}"]`);
|
|
1127
1571
|
const label = ref("label");
|
|
1128
1572
|
const pinBtn = ref("pin");
|
|
@@ -1133,6 +1577,7 @@ function createBar(doc, on) {
|
|
|
1133
1577
|
ref("copy").addEventListener("click", on.onCopy);
|
|
1134
1578
|
ref("theme").addEventListener("click", on.onTheme);
|
|
1135
1579
|
ref("help").addEventListener("click", on.onHelp);
|
|
1580
|
+
ref("min").addEventListener("click", (e) => on.onMinimize(e.detail === 0));
|
|
1136
1581
|
return {
|
|
1137
1582
|
root,
|
|
1138
1583
|
update(state) {
|
|
@@ -1629,6 +2074,43 @@ function renderPins(layer, state) {
|
|
|
1629
2074
|
if (state.draft) patchNode(ensureNode(layer, "draft", true), state.draft.placedAt, true, chipInner(visible.length + 1, null));
|
|
1630
2075
|
}
|
|
1631
2076
|
//#endregion
|
|
2077
|
+
//#region src/ui/puck.ts
|
|
2078
|
+
/** The bar's ident mark, sized up for the 48px puck face. */
|
|
2079
|
+
const PUCK_ICON = "<svg width=\"17\" height=\"17\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"><rect x=\"2.5\" y=\"1.5\" width=\"11\" height=\"7\" rx=\"1\"/><path d=\"M8 8.5v6\"/><circle cx=\"8\" cy=\"14.6\" r=\".9\" fill=\"currentColor\" stroke=\"none\"/></svg>";
|
|
2080
|
+
function createMinimizeUi(doc) {
|
|
2081
|
+
const puck = doc.createElement("button");
|
|
2082
|
+
puck.type = "button";
|
|
2083
|
+
puck.className = "pb-puck pb-ghost";
|
|
2084
|
+
puck.setAttribute("aria-label", "Restore Pinbox toolbar");
|
|
2085
|
+
puck.innerHTML = `<span class="in">${PUCK_ICON}</span><span class="badge" data-ref="count" hidden>0</span><span class="cdot"></span>`;
|
|
2086
|
+
const morphWrap = doc.createElement("div");
|
|
2087
|
+
morphWrap.className = "pb-morph-wrap";
|
|
2088
|
+
morphWrap.hidden = true;
|
|
2089
|
+
const surface = doc.createElement("div");
|
|
2090
|
+
surface.className = "pb-morph";
|
|
2091
|
+
const carrier = doc.createElement("div");
|
|
2092
|
+
carrier.className = "pb-carrier";
|
|
2093
|
+
carrier.innerHTML = `${PUCK_ICON}<span class="badge" data-ref="count" hidden>0</span>`;
|
|
2094
|
+
morphWrap.appendChild(surface);
|
|
2095
|
+
morphWrap.appendChild(carrier);
|
|
2096
|
+
const badges = [puck.querySelector("[data-ref=\"count\"]"), carrier.querySelector("[data-ref=\"count\"]")];
|
|
2097
|
+
return {
|
|
2098
|
+
puck,
|
|
2099
|
+
morphWrap,
|
|
2100
|
+
surface,
|
|
2101
|
+
carrier,
|
|
2102
|
+
update(state) {
|
|
2103
|
+
const open = String(state.pins.filter((p) => p.status !== "resolved").length);
|
|
2104
|
+
for (const badge of badges) {
|
|
2105
|
+
if (badge.textContent !== open) badge.textContent = open;
|
|
2106
|
+
badge.hidden = open === "0";
|
|
2107
|
+
}
|
|
2108
|
+
const degraded = state.connection === "offline" || state.connection === "incompatible";
|
|
2109
|
+
puck.classList.toggle("degraded", degraded);
|
|
2110
|
+
}
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2113
|
+
//#endregion
|
|
1632
2114
|
//#region src/ui/reticle.ts
|
|
1633
2115
|
function createReticle(doc) {
|
|
1634
2116
|
const crosshair = doc.createElement("div");
|
|
@@ -1684,6 +2166,7 @@ const ROWS = [
|
|
|
1684
2166
|
["Send comment", "⌘ ↵"],
|
|
1685
2167
|
["Mark pin resolved", "R"],
|
|
1686
2168
|
["Copy open pins", "C"],
|
|
2169
|
+
["Minimize toolbar", "M"],
|
|
1687
2170
|
["Cancel", "ESC"]
|
|
1688
2171
|
];
|
|
1689
2172
|
function createShortcutsModal(doc, onClose) {
|
|
@@ -1894,6 +2377,27 @@ button { font: inherit; color: inherit; background: none; border: 0; cursor: poi
|
|
|
1894
2377
|
.pb-item .mm .sdot { width: 5px; height: 5px; border-radius: 999px; }
|
|
1895
2378
|
.pb-empty { padding: 26px 16px; font-size: 12.5px; color: var(--pb-fg3); }
|
|
1896
2379
|
|
|
2380
|
+
/* minimize: floating puck + morph layer (ui/puck.ts, minimize.ts) — v3 design.
|
|
2381
|
+
The morph surface is styled identically to the bar so endpoint handoffs are
|
|
2382
|
+
pixel-invisible. Ghosting keeps layout (getBoundingClientRect still measures
|
|
2383
|
+
morph targets) while dropping the element from paint and the tab order. */
|
|
2384
|
+
.pb-ghost { opacity: 0 !important; pointer-events: none !important; visibility: hidden; transition: opacity 90ms linear, visibility 0s 90ms; }
|
|
2385
|
+
.pb-bar { transition: opacity 90ms linear; }
|
|
2386
|
+
.pb-morph-wrap { position: fixed; inset: 0; z-index: 89; pointer-events: none; opacity: 0; transition: opacity 90ms linear; }
|
|
2387
|
+
.pb-morph-wrap.on { opacity: 1; }
|
|
2388
|
+
.pb-morph { position: absolute; left: 0; top: 0; background: var(--pb-bar); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); border: 1px solid var(--pb-line-2); box-shadow: var(--pb-shadow); will-change: transform, width, height; }
|
|
2389
|
+
.pb-carrier { position: absolute; left: 0; top: 0; width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; color: var(--pb-amber); opacity: 0; transition: opacity 140ms linear; will-change: transform; }
|
|
2390
|
+
.pb-carrier.show { opacity: 1; }
|
|
2391
|
+
/* Above the bar (90) and drawer (85), below the aim layer (100) and modal (120). */
|
|
2392
|
+
.pb-puck { position: fixed; left: 0; top: 0; width: 48px; height: 48px; z-index: 95; border-radius: 999px; background: var(--pb-bar); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); border: 1px solid var(--pb-line-2); box-shadow: var(--pb-shadow); display: flex; align-items: center; justify-content: center; color: var(--pb-amber); cursor: grab; touch-action: none; transition: opacity 90ms linear; }
|
|
2393
|
+
.pb-puck:active { cursor: grabbing; }
|
|
2394
|
+
.pb-puck .in { display: flex; transition: transform 160ms var(--pb-ease); }
|
|
2395
|
+
.pb-puck:hover .in { transform: scale(1.12); }
|
|
2396
|
+
.pb-puck .badge, .pb-carrier .badge { position: absolute; top: -5px; right: -5px; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px; background: var(--pb-amber); color: var(--pb-amber-ink); font-family: var(--pb-font-mono); font-size: 9px; font-weight: 500; display: flex; align-items: center; justify-content: center; }
|
|
2397
|
+
/* The bar says "· OFFLINE" in words; the puck's amber dot is the same signal. */
|
|
2398
|
+
.pb-puck .cdot { position: absolute; bottom: -1px; right: -1px; width: 9px; height: 9px; border-radius: 999px; background: var(--pb-amber); border: 2px solid var(--pb-canvas); display: none; }
|
|
2399
|
+
.pb-puck.degraded .cdot { display: block; }
|
|
2400
|
+
|
|
1897
2401
|
/* shortcuts modal (ui/shortcuts.ts) — prototype lines 226–232 */
|
|
1898
2402
|
.pb-modal { position: fixed; inset: 0; z-index: 120; display: flex; align-items: center; justify-content: center; background: var(--pb-scrim); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); animation: pb-fade 200ms ease-out both; }
|
|
1899
2403
|
.pb-modal .mx { width: 430px; background: var(--pb-elev); border: 1px solid var(--pb-line-2); border-radius: 4px; box-shadow: var(--pb-shadow); animation: pb-in 280ms var(--pb-ease) both; }
|
|
@@ -1949,6 +2453,8 @@ var PinboxToolbarElement = class extends BaseElement {
|
|
|
1949
2453
|
/** Pending viewport-refresh frame, 0 when none is queued. */
|
|
1950
2454
|
#viewportFrame = 0;
|
|
1951
2455
|
#modal = null;
|
|
2456
|
+
#minUi = null;
|
|
2457
|
+
#min = null;
|
|
1952
2458
|
#helpOpen = false;
|
|
1953
2459
|
#pageStyle = null;
|
|
1954
2460
|
#unsubscribe = null;
|
|
@@ -1989,6 +2495,7 @@ var PinboxToolbarElement = class extends BaseElement {
|
|
|
1989
2495
|
document.head.appendChild(style);
|
|
1990
2496
|
this.#pageStyle = style;
|
|
1991
2497
|
if (this.#aim === null) this.#mountAim();
|
|
2498
|
+
if (this.#min === null) this.#mountMinimize();
|
|
1992
2499
|
document.addEventListener("mousemove", this.#onMouseMove);
|
|
1993
2500
|
window.addEventListener("scroll", this.#onViewportChange, { passive: true });
|
|
1994
2501
|
window.addEventListener("resize", this.#onViewportChange);
|
|
@@ -2034,6 +2541,8 @@ var PinboxToolbarElement = class extends BaseElement {
|
|
|
2034
2541
|
this.#viewportFrame = 0;
|
|
2035
2542
|
this.#aim?.destroy();
|
|
2036
2543
|
this.#aim = null;
|
|
2544
|
+
this.#min?.destroy();
|
|
2545
|
+
this.#min = null;
|
|
2037
2546
|
this.#unsubscribe?.();
|
|
2038
2547
|
this.#unsubscribe = null;
|
|
2039
2548
|
this.#pageStyle?.remove();
|
|
@@ -2087,9 +2596,13 @@ var PinboxToolbarElement = class extends BaseElement {
|
|
|
2087
2596
|
onInbox: () => this.store.update({ inboxOpen: !this.store.get().inboxOpen }),
|
|
2088
2597
|
onTheme: () => this.#toggleTheme(),
|
|
2089
2598
|
onHelp: () => this.#toggleHelp(),
|
|
2090
|
-
onCopy: () => this.#copyOpenPins()
|
|
2599
|
+
onCopy: () => this.#copyOpenPins(),
|
|
2600
|
+
onMinimize: (keyboard) => this.minimize(keyboard)
|
|
2091
2601
|
});
|
|
2092
2602
|
shadow.appendChild(this.#bar.root);
|
|
2603
|
+
this.#minUi = createMinimizeUi(document);
|
|
2604
|
+
shadow.appendChild(this.#minUi.morphWrap);
|
|
2605
|
+
shadow.appendChild(this.#minUi.puck);
|
|
2093
2606
|
this.#drawer = createDrawer(document, {
|
|
2094
2607
|
onActivate: (pinId) => this.#activateFromInbox(pinId),
|
|
2095
2608
|
onClose: () => this.store.update({ inboxOpen: false })
|
|
@@ -2100,6 +2613,52 @@ var PinboxToolbarElement = class extends BaseElement {
|
|
|
2100
2613
|
shadow.appendChild(this.#modal.root);
|
|
2101
2614
|
this.#pinsLayer.addEventListener("click", (e) => this.#onChipClick(e));
|
|
2102
2615
|
}
|
|
2616
|
+
/** Same lifetime split as #mountAim: the controller's window listeners and timers die on
|
|
2617
|
+
* disconnect, so it is (re)built on connect and re-applies the persisted resting state. */
|
|
2618
|
+
#mountMinimize() {
|
|
2619
|
+
const ui = this.#minUi;
|
|
2620
|
+
const bar = this.#bar;
|
|
2621
|
+
if (ui === null || bar === null) return;
|
|
2622
|
+
this.#min = createMinimize({
|
|
2623
|
+
win: window,
|
|
2624
|
+
bar: bar.root,
|
|
2625
|
+
ui,
|
|
2626
|
+
storage: globalThis.localStorage ?? null,
|
|
2627
|
+
storagePrefix: `pinbox:${this.config?.endpoint ?? ""}`,
|
|
2628
|
+
reduced: window.matchMedia("(prefers-reduced-motion: reduce)").matches,
|
|
2629
|
+
initialMinimized: this.config?.minimized === true,
|
|
2630
|
+
onSettled: (minimized, keyboard) => this.#onMinimizeSettled(minimized, keyboard)
|
|
2631
|
+
});
|
|
2632
|
+
this.#min.applyInitial();
|
|
2633
|
+
}
|
|
2634
|
+
#onMinimizeSettled(minimized, keyboard) {
|
|
2635
|
+
if (this.store.get().minimized !== minimized) this.store.update({ minimized });
|
|
2636
|
+
this.dispatchEvent(new CustomEvent(minimized ? "pinbox:minimize" : "pinbox:restore", {
|
|
2637
|
+
bubbles: true,
|
|
2638
|
+
composed: true
|
|
2639
|
+
}));
|
|
2640
|
+
if (!keyboard) return;
|
|
2641
|
+
if (minimized) this.#minUi?.puck.focus();
|
|
2642
|
+
else this.#bar?.root.querySelector("[data-ref=\"min\"]")?.focus();
|
|
2643
|
+
}
|
|
2644
|
+
/** Public: collapse the bar to the floating puck. Bar surfaces close first —
|
|
2645
|
+
* the morph must never sweep over an open card, drawer, or armed reticle. */
|
|
2646
|
+
minimize(keyboard = false) {
|
|
2647
|
+
const state = this.store.get();
|
|
2648
|
+
if (state.mode === "placing" || state.activePinId !== null || state.draft !== null) this.#dismiss();
|
|
2649
|
+
if (state.inboxOpen) this.store.update({ inboxOpen: false });
|
|
2650
|
+
this.#setHelp(false);
|
|
2651
|
+
this.#min?.minimize(keyboard);
|
|
2652
|
+
}
|
|
2653
|
+
/** Public: bring the bar back from the puck. */
|
|
2654
|
+
restore(keyboard = false) {
|
|
2655
|
+
this.#min?.restore(keyboard);
|
|
2656
|
+
}
|
|
2657
|
+
/** Bar-surface shortcuts pressed while minimized restore the bar, then run. */
|
|
2658
|
+
#surfaced(run) {
|
|
2659
|
+
if (this.#min?.minimized() === true) this.restore(false);
|
|
2660
|
+
run();
|
|
2661
|
+
}
|
|
2103
2662
|
/**
|
|
2104
2663
|
* Task 8 wiring: WS events mutate the store, connection state renders in the
|
|
2105
2664
|
* bar, card actions hit the hub. The mirror seeds pins so an offline reload
|
|
@@ -2323,14 +2882,15 @@ var PinboxToolbarElement = class extends BaseElement {
|
|
|
2323
2882
|
if (state.inboxOpen) this.store.update({ inboxOpen: false });
|
|
2324
2883
|
if (state.activePinId || state.draft) this.#dismiss();
|
|
2325
2884
|
};
|
|
2326
|
-
/** Prototype keyboard map (v2-command-bar.html lines 701–712). */
|
|
2885
|
+
/** Prototype keyboard map (v2-command-bar.html lines 701–712) + M (v3 minimize). */
|
|
2327
2886
|
#shortcuts = {
|
|
2328
2887
|
escape: () => this.#dismiss(),
|
|
2329
|
-
p: () => this.#togglePlacing(),
|
|
2330
|
-
i: () => this.#toggleInbox(),
|
|
2888
|
+
p: () => this.#surfaced(() => this.#togglePlacing()),
|
|
2889
|
+
i: () => this.#surfaced(() => this.#toggleInbox()),
|
|
2331
2890
|
d: () => this.#toggleTheme(),
|
|
2332
2891
|
r: () => this.#resolveActive(),
|
|
2333
2892
|
c: () => this.#copyOpenPins(),
|
|
2893
|
+
m: () => this.#min?.minimized() === true ? this.restore(true) : this.minimize(true),
|
|
2334
2894
|
"?": () => this.#toggleHelp()
|
|
2335
2895
|
};
|
|
2336
2896
|
#onKeyDown = (e) => {
|
|
@@ -2368,6 +2928,7 @@ var PinboxToolbarElement = class extends BaseElement {
|
|
|
2368
2928
|
if (this.shadowRoot) renderCard(this.shadowRoot, state, this.#cardActions);
|
|
2369
2929
|
this.#drawer?.update(state);
|
|
2370
2930
|
this.#bar?.update(state);
|
|
2931
|
+
this.#minUi?.update(state);
|
|
2371
2932
|
}
|
|
2372
2933
|
};
|
|
2373
2934
|
//#endregion
|
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-
|
|
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-DK_kVd2Z.js";
|
|
2
2
|
import { Action } from "svelte/action";
|
|
3
3
|
//#region src/svelte.d.ts
|
|
4
4
|
/**
|
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-
|
|
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-ChTPrRo5.js";
|
|
2
2
|
//#region src/svelte.ts
|
|
3
3
|
/**
|
|
4
4
|
* `<div use:pinbox={{ endpoint }} />` — creates + configures the element BEFORE insertion
|