@kitlangton/knobs 0.4.0-next.10 → 0.4.0-next.12

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/ui.js CHANGED
@@ -3043,13 +3043,17 @@ var css2 = `
3043
3043
  .knobs-tree-row[aria-expanded="true"]>.knobs-tree-caret{transform:rotate(90deg)}
3044
3044
  .knobs-tree-row:not([aria-expanded])>.knobs-tree-caret{visibility:hidden}
3045
3045
  .knobs-tree-icon{flex:none;display:flex;align-items:center;justify-content:center;width:14px;margin-right:6px;color:var(--_k-fg-3);font-size:calc(var(--_k-font-size) - 1px)}
3046
- .knobs-tree-label{position:relative;flex:1;min-width:0;overflow:hidden;font-weight:var(--_k-weight)}
3046
+ /* The label wins the room: it keeps its width while the detail (which only takes what's left)
3047
+ fades out at its end, and gives way only once the detail is gone. Each fades where it's cut. */
3048
+ .knobs-tree-label{position:relative;flex:0 1 auto;min-width:0;overflow:hidden;font-weight:var(--_k-weight)}
3049
+ .knobs-tree-row[data-editing]>.knobs-tree-label{flex-grow:1}
3047
3050
  .knobs-tree-row[data-ancestor] .knobs-tree-label{color:var(--_k-fg-2)}
3048
3051
  .knobs-tree-label .knobs-tree-mark{color:var(--_k-accent)}
3049
3052
  .knobs-tree-row[data-off~="visible"] :is(.knobs-tree-label,.knobs-tree-icon){opacity:.45}
3050
3053
  .knobs-tree-row[data-off~="locked"] .knobs-tree-label{color:var(--_k-fg-2)}
3051
- .knobs-tree-detail{flex:none;margin-left:6px;color:var(--_k-fg-3);font-variant-numeric:tabular-nums}
3052
- .knobs-tree-tools{flex:none;display:flex;align-items:center;gap:1px;margin-left:4px}
3054
+ .knobs-tree-detail{flex:1 1 0;min-width:0;overflow:hidden;padding-left:6px;text-align:right;color:var(--_k-fg-3);font-variant-numeric:tabular-nums}
3055
+ .knobs-tree-row[data-editing]>.knobs-tree-detail{flex-grow:0;visibility:hidden}
3056
+ .knobs-tree-tools{flex:none;display:flex;align-items:center;gap:1px;margin-left:auto;padding-left:4px}
3053
3057
  .knobs-ui .knobs-tree-toggle{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:calc(var(--_k-radius) * 999);color:var(--_k-fg-3);cursor:pointer;opacity:0;transition:opacity .12s,color .12s,background .12s}
3054
3058
  .knobs-ui .knobs-tree-toggle svg{width:12px;height:12px}
3055
3059
  .knobs-tree-row:is(:hover,[data-active],[aria-selected="true"]) .knobs-tree-toggle,.knobs-ui .knobs-tree-toggle[aria-pressed="false"]{opacity:1}
@@ -10047,7 +10051,7 @@ function tree(container, options) {
10047
10051
  text.className = "knobs-tree-text";
10048
10052
  label.append(text);
10049
10053
  const detail = doc.createElement("span");
10050
- detail.className = "knobs-tree-detail";
10054
+ detail.className = "knobs-tree-detail knobs-scroll-fade-x";
10051
10055
  const tools = doc.createElement("span");
10052
10056
  tools.className = "knobs-tree-tools";
10053
10057
  el.append(caret, icon, label, detail, tools);
@@ -19773,6 +19777,976 @@ function bento(container, options) {
19773
19777
  }
19774
19778
  };
19775
19779
  }
19780
+ // src/ui/canvas.ts
19781
+ init_glide();
19782
+ init_motion();
19783
+
19784
+ // src/ui/canvas-css.ts
19785
+ var canvasCss = `
19786
+ .knobs-ui.knobs-canvas{--_kc-radius:var(--k-ui-canvas-radius,var(--_k-radius-panel));--_kc-fade:var(--k-ui-canvas-fade,16px);
19787
+ position:relative;width:100%;height:100%;overflow:hidden;outline:none;background:var(--k-ui-canvas-bg,var(--_k-bg-page));contain:strict;
19788
+ touch-action:none;overscroll-behavior:none;user-select:none;-webkit-user-select:none;cursor:default;
19789
+ font:var(--_k-weight) var(--_k-font-size)/1.35 var(--_k-font);color:var(--_k-fg);letter-spacing:normal;text-align:left}
19790
+ :where(.knobs-canvas-stage,.knobs-canvas-stage *,.knobs-canvas-zoom,.knobs-canvas-zoom *){box-sizing:border-box}
19791
+ /* No hard edges: what slides out of view fades over the last few px. */
19792
+ .knobs-canvas-stage{position:absolute;inset:0;overflow:hidden;
19793
+ -webkit-mask-image:linear-gradient(to right,transparent,#000 var(--_kc-fade),#000 calc(100% - var(--_kc-fade)),transparent),linear-gradient(to bottom,transparent,#000 var(--_kc-fade),#000 calc(100% - var(--_kc-fade)),transparent);
19794
+ -webkit-mask-composite:source-in;mask-image:linear-gradient(to right,transparent,#000 var(--_kc-fade),#000 calc(100% - var(--_kc-fade)),transparent),linear-gradient(to bottom,transparent,#000 var(--_kc-fade),#000 calc(100% - var(--_kc-fade)),transparent);mask-composite:intersect}
19795
+ .knobs-canvas-dots{position:absolute;left:-128px;top:-128px;right:-128px;bottom:-128px;pointer-events:none;will-change:transform;
19796
+ background-image:radial-gradient(circle,var(--k-ui-canvas-dot,color-mix(in srgb,var(--_k-fg) 22%,transparent)) 1px,transparent 1.25px)}
19797
+ .knobs-canvas-world{position:absolute;left:0;top:0;width:0;height:0;transform-origin:0 0}
19798
+ .knobs-canvas[data-moving] .knobs-canvas-world{will-change:transform}
19799
+ .knobs-canvas:is([data-panning],[data-space]) .knobs-canvas-world{pointer-events:none}
19800
+ .knobs-canvas[data-space]{cursor:grab}
19801
+ .knobs-canvas[data-grabbing]{cursor:grabbing}
19802
+ .knobs-canvas-tile{position:absolute;left:0;top:0;display:flex;flex-direction:column;width:max-content;transform-origin:50% 50%}
19803
+ .knobs-canvas-title{flex:none;contain:inline-size;height:24px;padding:0 2px 8px;overflow:hidden;white-space:nowrap;color:var(--_k-fg-2);
19804
+ font-size:var(--_k-type-small,12px);line-height:16px;-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 16px),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 16px),transparent)}
19805
+ .knobs-canvas-card{position:relative;flex:none;padding:var(--k-ui-canvas-pad,16px);border-radius:var(--_kc-radius);background:var(--k-ui-canvas-card,var(--_k-bg));
19806
+ overflow:hidden;user-select:text;-webkit-user-select:text}
19807
+ .knobs-canvas-card::after{content:"";position:absolute;inset:0;border-radius:inherit;box-shadow:inset 0 0 0 1px var(--_k-border);pointer-events:none}
19808
+ /* The readout: how far, and the way back to the whole set or 100%. */
19809
+ .knobs-canvas-zoom{position:absolute;right:10px;bottom:10px;z-index:1;display:flex;align-items:center;gap:2px;height:28px;padding:0 4px;border-radius:999px;
19810
+ background:var(--_k-bg);box-shadow:inset 0 0 0 1px var(--_k-border);color:var(--_k-fg-2);font-size:var(--_k-type-small,12px);
19811
+ font-variant-numeric:tabular-nums;font-feature-settings:"tnum";white-space:nowrap}
19812
+ :where(.knobs-ui) .knobs-canvas-btn{all:revert;box-sizing:border-box;font:inherit;letter-spacing:inherit;margin:0;border:0;outline:none;box-shadow:none;
19813
+ display:inline-flex;align-items:center;justify-content:center;height:20px;min-width:20px;padding:0 6px;border-radius:999px;background:transparent;color:inherit;cursor:default;
19814
+ transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
19815
+ :where(.knobs-ui) .knobs-canvas-btn:is(:hover,:focus-visible){background:var(--_k-fill-hover);color:var(--_k-fg);transition-duration:0ms}
19816
+ :where(.knobs-ui) .knobs-canvas-btn:focus-visible{box-shadow:0 0 0 1.5px var(--_k-accent)}
19817
+ .knobs-canvas-pct{min-width:46px}
19818
+ .knobs-canvas-btn svg{width:13px;height:13px}
19819
+ `;
19820
+
19821
+ // src/ui/canvas-model.ts
19822
+ var clamp3 = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
19823
+ function packRows(sizes, opts) {
19824
+ const { gap, width } = opts;
19825
+ const x0 = opts.x ?? 0;
19826
+ let x = 0;
19827
+ let y = opts.y ?? 0;
19828
+ let rowH = 0;
19829
+ return sizes.map((s) => {
19830
+ if (x > 0 && x + s.w > width) {
19831
+ x = 0;
19832
+ y += rowH + gap;
19833
+ rowH = 0;
19834
+ }
19835
+ const r = { x: Math.round(x0 + x), y: Math.round(y), w: s.w, h: s.h };
19836
+ x += s.w + gap;
19837
+ rowH = Math.max(rowH, s.h);
19838
+ return r;
19839
+ });
19840
+ }
19841
+ function rowWidth(sizes, gap, aspect) {
19842
+ let widest = 0;
19843
+ let total = 0;
19844
+ for (const s of sizes) {
19845
+ widest = Math.max(widest, s.w);
19846
+ total += s.w + gap;
19847
+ }
19848
+ if (!sizes.length)
19849
+ return 0;
19850
+ const a = Number.isFinite(aspect) && aspect > 0 ? aspect : 16 / 10;
19851
+ const shape = (width) => {
19852
+ const b = boundsOf(packRows(sizes, { gap, width }));
19853
+ return b.w / Math.max(1, b.h);
19854
+ };
19855
+ let lo = widest;
19856
+ let hi = Math.max(widest, total);
19857
+ for (let i = 0;i < 24 && hi - lo > 1; i++) {
19858
+ const mid = (lo + hi) / 2;
19859
+ if (shape(mid) < a)
19860
+ lo = mid;
19861
+ else
19862
+ hi = mid;
19863
+ }
19864
+ return Math.abs(Math.log(shape(lo) / a)) <= Math.abs(Math.log(shape(hi) / a)) ? lo : hi;
19865
+ }
19866
+ function layoutCanvas(items, opts) {
19867
+ const placed = items.flatMap((it) => it.x !== undefined && it.y !== undefined ? [{ x: it.x, y: it.y, w: it.w, h: it.h }] : []);
19868
+ const free = items.filter((it) => it.x === undefined || it.y === undefined);
19869
+ const width = opts.width ?? rowWidth(free, opts.gap, opts.aspect ?? 16 / 10);
19870
+ const under = boundsOf(placed);
19871
+ const packed = packRows(free, {
19872
+ gap: opts.gap,
19873
+ width,
19874
+ x: under ? under.x : 0,
19875
+ y: under ? under.y + under.h + opts.gap * 2 : 0
19876
+ });
19877
+ let i = 0;
19878
+ const rects = items.map((it) => it.x !== undefined && it.y !== undefined ? { x: it.x, y: it.y, w: it.w, h: it.h } : packed[i++]);
19879
+ return { rects, width };
19880
+ }
19881
+ function boundsOf(rects) {
19882
+ if (!rects.length)
19883
+ return null;
19884
+ let x0 = Number.POSITIVE_INFINITY;
19885
+ let y0 = Number.POSITIVE_INFINITY;
19886
+ let x1 = Number.NEGATIVE_INFINITY;
19887
+ let y1 = Number.NEGATIVE_INFINITY;
19888
+ for (const r of rects) {
19889
+ x0 = Math.min(x0, r.x);
19890
+ y0 = Math.min(y0, r.y);
19891
+ x1 = Math.max(x1, r.x + r.w);
19892
+ y1 = Math.max(y1, r.y + r.h);
19893
+ }
19894
+ return { x: x0, y: y0, w: x1 - x0, h: y1 - y0 };
19895
+ }
19896
+ function zoomAround(v, scale, at, min = 0, max = Number.POSITIVE_INFINITY) {
19897
+ const s = clamp3(scale, min, max);
19898
+ const k = s / v.scale;
19899
+ return { x: at.x - (at.x - v.x) * k, y: at.y - (at.y - v.y) * k, scale: s };
19900
+ }
19901
+ function pinchView(v, from, to, ratio, min = 0, max = Number.POSITIVE_INFINITY) {
19902
+ const z = zoomAround(v, v.scale * ratio, from, min, max);
19903
+ return { x: z.x + to.x - from.x, y: z.y + to.y - from.y, scale: z.scale };
19904
+ }
19905
+ var WHEEL_ZOOM_MAX = 1.25;
19906
+ function wheelZoom(deltaY, pinch) {
19907
+ const f = Math.exp(-deltaY * (pinch ? 0.01 : 0.0025));
19908
+ return clamp3(f, 1 / WHEEL_ZOOM_MAX, WHEEL_ZOOM_MAX);
19909
+ }
19910
+ function fitView(r, w, h, opts = {}) {
19911
+ const pad = opts.pad ?? 0;
19912
+ const room = (n) => Math.max(1, n - pad * 2);
19913
+ const raw = Math.min(room(w) / Math.max(1, r.w), room(h) / Math.max(1, r.h));
19914
+ const scale = clamp3(raw, opts.min ?? 0, opts.max ?? Number.POSITIVE_INFINITY);
19915
+ return {
19916
+ x: w / 2 - (r.x + r.w / 2) * scale,
19917
+ y: h / 2 - (r.y + r.h / 2) * scale,
19918
+ scale
19919
+ };
19920
+ }
19921
+ function viewPath(from, to) {
19922
+ const k = to.scale / from.scale;
19923
+ if (!Number.isFinite(k) || Math.abs(Math.log(k)) < 0.0001)
19924
+ return (t) => ({
19925
+ x: from.x + (to.x - from.x) * t,
19926
+ y: from.y + (to.y - from.y) * t,
19927
+ scale: from.scale + (to.scale - from.scale) * t
19928
+ });
19929
+ const fx = (to.x - k * from.x) / (1 - k);
19930
+ const fy = (to.y - k * from.y) / (1 - k);
19931
+ const wx = (fx - from.x) / from.scale;
19932
+ const wy = (fy - from.y) / from.scale;
19933
+ return (t) => {
19934
+ if (t >= 1)
19935
+ return to;
19936
+ const scale = from.scale * k ** t;
19937
+ return { x: fx - wx * scale, y: fy - wy * scale, scale };
19938
+ };
19939
+ }
19940
+ var snapView = (v, dpr) => {
19941
+ const d = dpr > 0 ? dpr : 1;
19942
+ return { x: Math.round(v.x * d) / d, y: Math.round(v.y * d) / d, scale: v.scale };
19943
+ };
19944
+ var smooth = (a, b, x) => {
19945
+ const t = clamp3((x - a) / (b - a), 0, 1);
19946
+ return t * t * (3 - 2 * t);
19947
+ };
19948
+ function dotGrid(scale, step = 24) {
19949
+ const size = step * scale;
19950
+ const alpha = smooth(7, 14, size) * (1 - smooth(72, 128, size));
19951
+ return { size, alpha };
19952
+ }
19953
+ function keyAction(e) {
19954
+ if (e.altKey)
19955
+ return null;
19956
+ switch (e.key) {
19957
+ case "0":
19958
+ return "fit";
19959
+ case "1":
19960
+ return "actual";
19961
+ case "=":
19962
+ case "+":
19963
+ return "in";
19964
+ case "-":
19965
+ case "_":
19966
+ return "out";
19967
+ default:
19968
+ return null;
19969
+ }
19970
+ }
19971
+ var KEY_ZOOM = 1.5;
19972
+ function releaseVelocity(samples, now, window2 = 80) {
19973
+ const last = samples.at(-1);
19974
+ if (!last || now - last.t > 60)
19975
+ return { x: 0, y: 0 };
19976
+ let first = last;
19977
+ for (let i = samples.length - 1;i >= 0; i--) {
19978
+ if (last.t - samples[i].t > window2)
19979
+ break;
19980
+ first = samples[i];
19981
+ }
19982
+ const dt = (last.t - first.t) / 1000;
19983
+ if (dt <= 0)
19984
+ return { x: 0, y: 0 };
19985
+ return { x: (last.x - first.x) / dt, y: (last.y - first.y) / dt };
19986
+ }
19987
+ var COAST_TAU = -1 / (1000 * Math.log(0.998));
19988
+
19989
+ // src/ui/canvas.ts
19990
+ init_look();
19991
+ var FIT = springMotion(SPRINGS.smooth);
19992
+ var KEY2 = springMotion(SPRINGS.default);
19993
+ var LAYOUT3 = springMotion(SPRINGS.calm);
19994
+ var FOCUS_MAX = 2;
19995
+ var MAX_FLING = 8000;
19996
+ var SETTLE_MS = 200;
19997
+ var INTERACTIVE = "a,button,input,select,textarea,label,summary,[contenteditable],[role=button],[role=slider],[role=switch],[role=checkbox],[role=tab],[role=option],[role=textbox]";
19998
+ var ICON_FIT = svg('<path d="M2.5 6V3.5a1 1 0 0 1 1-1H6M10 2.5h2.5a1 1 0 0 1 1 1V6M13.5 10v2.5a1 1 0 0 1-1 1H10M6 13.5H3.5a1 1 0 0 1-1-1V10"/>');
19999
+ var injectCanvasStyles = (doc) => {
20000
+ if (doc.querySelector("style[data-knobs-canvas]"))
20001
+ return;
20002
+ const style = doc.createElement("style");
20003
+ style.dataset.knobsCanvas = "";
20004
+ style.textContent = aliased(canvasCss);
20005
+ doc.head.append(style);
20006
+ };
20007
+ function canvas(container, options) {
20008
+ const doc = container.ownerDocument;
20009
+ const win = doc.defaultView;
20010
+ const gap = options.gap ?? 48;
20011
+ const pad = options.padding ?? 48;
20012
+ const minZoom = options.minZoom ?? 0.05;
20013
+ const maxZoom = options.maxZoom ?? 8;
20014
+ let items = options.items;
20015
+ const root = doc.createElement("div");
20016
+ root.className = "knobs-canvas";
20017
+ root.tabIndex = 0;
20018
+ root.setAttribute("role", "region");
20019
+ root.setAttribute("aria-roledescription", "canvas");
20020
+ root.setAttribute("aria-label", options.label ?? "Canvas");
20021
+ applyLook2(root, options);
20022
+ injectCanvasStyles(doc);
20023
+ const stage = doc.createElement("div");
20024
+ stage.className = "knobs-canvas-stage";
20025
+ const dots = doc.createElement("div");
20026
+ dots.className = "knobs-canvas-dots";
20027
+ const world = doc.createElement("div");
20028
+ world.className = "knobs-canvas-world";
20029
+ stage.append(dots, world);
20030
+ root.append(stage);
20031
+ let pct = null;
20032
+ if (options.readout !== false) {
20033
+ const bar = doc.createElement("div");
20034
+ bar.className = "knobs-canvas-zoom";
20035
+ const fitBtn = doc.createElement("button");
20036
+ fitBtn.type = "button";
20037
+ fitBtn.className = "knobs-canvas-btn";
20038
+ fitBtn.innerHTML = ICON_FIT;
20039
+ fitBtn.title = "Fit (0)";
20040
+ fitBtn.setAttribute("aria-label", "Fit");
20041
+ fitBtn.addEventListener("click", () => api.fit());
20042
+ pct = doc.createElement("button");
20043
+ pct.type = "button";
20044
+ pct.className = "knobs-canvas-btn knobs-canvas-pct";
20045
+ pct.title = "100% (1)";
20046
+ pct.setAttribute("aria-label", "Zoom to 100%");
20047
+ pct.addEventListener("click", () => api.zoomTo(1));
20048
+ bar.append(fitBtn, pct);
20049
+ bar.addEventListener("dblclick", (e) => e.stopPropagation());
20050
+ root.append(bar);
20051
+ }
20052
+ container.append(root);
20053
+ const motionQuery = win.matchMedia?.("(prefers-reduced-motion: reduce)");
20054
+ const reduced = () => motionQuery?.matches ?? reducedMotion(win);
20055
+ let view = { x: 0, y: 0, scale: 1 };
20056
+ let vw = 0;
20057
+ let vh = 0;
20058
+ let pristine = true;
20059
+ let rowW;
20060
+ let rects = new Map;
20061
+ let jump = null;
20062
+ let coast = null;
20063
+ let frames = 0;
20064
+ const times = [];
20065
+ const tiles = new Map;
20066
+ let drawnView = "";
20067
+ let drawnDots = "";
20068
+ let drawnPct = "";
20069
+ const drawView = () => {
20070
+ const v = view;
20071
+ const key = `${v.x}|${v.y}|${v.scale}`;
20072
+ if (key === drawnView)
20073
+ return;
20074
+ drawnView = key;
20075
+ world.style.transform = `translate(${v.x}px,${v.y}px) scale(${v.scale})`;
20076
+ const g = dotGrid(v.scale);
20077
+ if (g.alpha <= 0.001) {
20078
+ if (drawnDots !== "off")
20079
+ dots.style.visibility = "hidden";
20080
+ drawnDots = "off";
20081
+ } else {
20082
+ const ox = ((v.x + 128 - g.size / 2) % g.size + g.size) % g.size;
20083
+ const oy = ((v.y + 128 - g.size / 2) % g.size + g.size) % g.size;
20084
+ const size = `${g.size}px ${g.size}px`;
20085
+ const a = String(Math.round(g.alpha * 1000) / 1000);
20086
+ if (drawnDots === "off")
20087
+ dots.style.visibility = "";
20088
+ if (dots.style.backgroundSize !== size)
20089
+ dots.style.backgroundSize = size;
20090
+ if (dots.style.opacity !== a)
20091
+ dots.style.opacity = a;
20092
+ dots.style.transform = `translate(${ox}px,${oy}px)`;
20093
+ drawnDots = "on";
20094
+ }
20095
+ if (pct) {
20096
+ const label = `${Math.round(v.scale * 100)}%`;
20097
+ if (label !== drawnPct)
20098
+ pct.textContent = drawnPct = label;
20099
+ }
20100
+ options.onView?.(v);
20101
+ };
20102
+ let settleTimer = 0;
20103
+ let held = false;
20104
+ let layerScale = 0;
20105
+ const settle = () => {
20106
+ settleTimer = 0;
20107
+ if (held)
20108
+ return;
20109
+ if (loop.running) {
20110
+ settleTimer = win.setTimeout(settle, SETTLE_MS);
20111
+ return;
20112
+ }
20113
+ view = snapView(view, win.devicePixelRatio || 1);
20114
+ if (Math.abs(view.scale / layerScale - 1) > 0.000001) {
20115
+ delete root.dataset.moving;
20116
+ layerScale = 0;
20117
+ }
20118
+ drawView();
20119
+ };
20120
+ const moved = () => {
20121
+ if (!layerScale) {
20122
+ root.dataset.moving = "";
20123
+ layerScale = view.scale;
20124
+ }
20125
+ win.clearTimeout(settleTimer);
20126
+ settleTimer = win.setTimeout(settle, SETTLE_MS);
20127
+ };
20128
+ const setView = (v) => {
20129
+ view = v;
20130
+ moved();
20131
+ drawView();
20132
+ };
20133
+ const drawTile = (t) => {
20134
+ const key = `${t.x.x}|${t.y.x}`;
20135
+ if (key === t.drawn)
20136
+ return;
20137
+ t.drawn = key;
20138
+ t.el.style.translate = `${t.x.x}px ${t.y.x}px`;
20139
+ };
20140
+ const sizeCard = (t) => {
20141
+ const { w, h } = t.item;
20142
+ t.card.style.width = w === undefined ? "" : `${w}px`;
20143
+ t.card.style.height = h === undefined ? "" : `${h}px`;
20144
+ };
20145
+ const setTitle = (t) => {
20146
+ const text = t.item.title;
20147
+ if (text && !t.title) {
20148
+ t.title = doc.createElement("div");
20149
+ t.title.className = "knobs-canvas-title";
20150
+ t.el.prepend(t.title);
20151
+ }
20152
+ if (t.title) {
20153
+ if (text)
20154
+ t.title.textContent = text;
20155
+ else {
20156
+ t.title.remove();
20157
+ t.title = null;
20158
+ }
20159
+ }
20160
+ };
20161
+ const mount = (it, enter) => {
20162
+ const el = doc.createElement("div");
20163
+ el.className = "knobs-canvas-tile";
20164
+ el.dataset.id = it.id;
20165
+ const card = doc.createElement("div");
20166
+ card.className = "knobs-canvas-card";
20167
+ el.append(card);
20168
+ const t = {
20169
+ id: it.id,
20170
+ item: it,
20171
+ el,
20172
+ title: null,
20173
+ card,
20174
+ cleanup: undefined,
20175
+ x: new Spring(0, LAYOUT3.omega, LAYOUT3.zeta, 0.05),
20176
+ y: new Spring(0, LAYOUT3.omega, LAYOUT3.zeta, 0.05),
20177
+ w: 0,
20178
+ h: 0,
20179
+ placed: false,
20180
+ leaving: false,
20181
+ gone: false,
20182
+ drawn: ""
20183
+ };
20184
+ setTitle(t);
20185
+ sizeCard(t);
20186
+ world.append(el);
20187
+ t.cleanup = it.render(card) || undefined;
20188
+ tiles.set(it.id, t);
20189
+ ro.observe(el);
20190
+ if (enter) {
20191
+ const r = reduced();
20192
+ el.animate(r ? [{ opacity: 0 }, { opacity: 1 }] : [
20193
+ { opacity: 0, scale: 0.96, filter: "blur(3px)" },
20194
+ { opacity: 1, scale: 1, filter: "blur(0px)" }
20195
+ ], { duration: r ? 160 : 260, easing: "cubic-bezier(.2,.8,.2,1)" });
20196
+ }
20197
+ return t;
20198
+ };
20199
+ const unmount = (t) => {
20200
+ if (t.gone)
20201
+ return;
20202
+ t.gone = true;
20203
+ ro.unobserve(t.el);
20204
+ t.cleanup?.();
20205
+ t.el.remove();
20206
+ if (tiles.get(t.id) === t)
20207
+ tiles.delete(t.id);
20208
+ };
20209
+ const leave = (t) => {
20210
+ t.leaving = true;
20211
+ tiles.delete(t.id);
20212
+ t.el.style.pointerEvents = "none";
20213
+ const r = reduced();
20214
+ const a = t.el.animate(r ? [{ opacity: 1 }, { opacity: 0 }] : [
20215
+ { opacity: 1, scale: 1, filter: "blur(0px)" },
20216
+ { opacity: 0, scale: 0.96, filter: "blur(3px)" }
20217
+ ], { duration: r ? 160 : 200, easing: "cubic-bezier(.4,0,1,1)", fill: "forwards" });
20218
+ a.onfinish = () => {
20219
+ leaving.delete(t);
20220
+ unmount(t);
20221
+ };
20222
+ leaving.add(t);
20223
+ };
20224
+ const leaving = new Set;
20225
+ const measure = () => {
20226
+ for (const t of tiles.values()) {
20227
+ t.w = t.el.offsetWidth;
20228
+ t.h = t.el.offsetHeight;
20229
+ }
20230
+ };
20231
+ const fitTarget = () => {
20232
+ const b = boundsOf([...rects.values()]);
20233
+ if (!b || !vw || !vh)
20234
+ return null;
20235
+ return fitView(b, vw, vh, { pad, min: minZoom, max: Math.min(maxZoom, 1) });
20236
+ };
20237
+ const relayout = (glide) => {
20238
+ const live = items.map((it) => tiles.get(it.id)).filter(Boolean);
20239
+ const sizes = live.map((t) => ({ x: t.item.x, y: t.item.y, w: t.w, h: t.h }));
20240
+ if (pristine)
20241
+ rowW = options.width;
20242
+ const out = layoutCanvas(sizes, {
20243
+ gap,
20244
+ width: rowW,
20245
+ aspect: vw && vh ? vw / vh : undefined
20246
+ });
20247
+ rowW = out.width;
20248
+ const next = new Map;
20249
+ const animate = glide && !pristine && !reduced();
20250
+ let moving = false;
20251
+ live.forEach((t, i) => {
20252
+ const r = out.rects[i];
20253
+ next.set(t.id, r);
20254
+ if (!animate || !t.placed) {
20255
+ t.x.snap(r.x);
20256
+ t.y.snap(r.y);
20257
+ } else {
20258
+ tune(t.x, LAYOUT3).set(r.x);
20259
+ tune(t.y, LAYOUT3).set(r.y);
20260
+ moving ||= !t.x.resting || !t.y.resting;
20261
+ }
20262
+ t.placed = true;
20263
+ drawTile(t);
20264
+ });
20265
+ rects = next;
20266
+ if (pristine) {
20267
+ const f = fitTarget();
20268
+ if (f) {
20269
+ view = snapView(f, win.devicePixelRatio || 1);
20270
+ drawView();
20271
+ }
20272
+ }
20273
+ if (moving)
20274
+ loop.wake();
20275
+ };
20276
+ let relayoutQueued = 0;
20277
+ const ro = new win.ResizeObserver((entries) => {
20278
+ let changed = false;
20279
+ for (const e of entries) {
20280
+ const t = tiles.get(e.target.dataset.id ?? "");
20281
+ if (!t || t.el !== e.target)
20282
+ continue;
20283
+ const w = t.el.offsetWidth;
20284
+ const h = t.el.offsetHeight;
20285
+ if (w !== t.w || h !== t.h) {
20286
+ t.w = w;
20287
+ t.h = h;
20288
+ changed = true;
20289
+ }
20290
+ }
20291
+ if (changed && !relayoutQueued)
20292
+ relayoutQueued = win.requestAnimationFrame(() => {
20293
+ relayoutQueued = 0;
20294
+ relayout(true);
20295
+ });
20296
+ });
20297
+ const rootRo = new win.ResizeObserver(() => {
20298
+ const w = root.clientWidth;
20299
+ const h = root.clientHeight;
20300
+ if (w === vw && h === vh)
20301
+ return;
20302
+ const was = { w: vw, h: vh };
20303
+ vw = w;
20304
+ vh = h;
20305
+ if (pristine)
20306
+ return relayout(false);
20307
+ if (was.w && was.h) {
20308
+ const dx = (w - was.w) / 2;
20309
+ const dy = (h - was.h) / 2;
20310
+ if (jump)
20311
+ startJump({ x: jump.to.x + dx, y: jump.to.y + dy, scale: jump.to.scale }, jump.t.omega === FIT.omega ? FIT : KEY2);
20312
+ view = { x: view.x + dx, y: view.y + dy, scale: view.scale };
20313
+ drawView();
20314
+ }
20315
+ });
20316
+ const frame = (dt) => {
20317
+ const t0 = performance.now();
20318
+ frames++;
20319
+ let moving = false;
20320
+ if (jump) {
20321
+ jump.t.step(dt);
20322
+ if (jump.t.resting) {
20323
+ view = jump.to;
20324
+ jump = null;
20325
+ } else {
20326
+ view = jump.path(Math.min(1, jump.t.x));
20327
+ moving = true;
20328
+ }
20329
+ moved();
20330
+ }
20331
+ if (coast) {
20332
+ const decay = Math.exp(-dt / COAST_TAU);
20333
+ const travel = COAST_TAU * (1 - decay);
20334
+ let v = {
20335
+ x: view.x + coast.vx * travel,
20336
+ y: view.y + coast.vy * travel,
20337
+ scale: view.scale
20338
+ };
20339
+ if (coast.vs)
20340
+ v = zoomAround(v, v.scale * Math.exp(coast.vs * travel), coast.at, minZoom, maxZoom);
20341
+ view = v;
20342
+ coast.vx *= decay;
20343
+ coast.vy *= decay;
20344
+ coast.vs *= decay;
20345
+ if (Math.hypot(coast.vx, coast.vy) < 10 && Math.abs(coast.vs) < 0.02)
20346
+ coast = null;
20347
+ else
20348
+ moving = true;
20349
+ moved();
20350
+ }
20351
+ drawView();
20352
+ for (const t of tiles.values())
20353
+ if (!t.x.resting || !t.y.resting) {
20354
+ t.x.step(dt);
20355
+ t.y.step(dt);
20356
+ drawTile(t);
20357
+ moving = true;
20358
+ }
20359
+ times.push(performance.now() - t0);
20360
+ if (times.length > 600)
20361
+ times.splice(0, times.length - 600);
20362
+ return moving;
20363
+ };
20364
+ const loop = frameLoop(win, frame);
20365
+ const pathLength = (a, b) => Math.abs(Math.log(b.scale / a.scale)) + Math.hypot(b.x - a.x, b.y - a.y) / Math.max(1, vw, vh);
20366
+ const startJump = (to, m) => {
20367
+ pristine = false;
20368
+ coast = null;
20369
+ if (reduced()) {
20370
+ jump = null;
20371
+ setView(to);
20372
+ return;
20373
+ }
20374
+ let v = 0;
20375
+ if (jump) {
20376
+ const len = pathLength(view, to);
20377
+ if (len > 0.000001)
20378
+ v = clamp3(jump.t.v * pathLength(jump.from, jump.to) / len, 0, 40);
20379
+ }
20380
+ const t = new Spring(0, m.omega, m.zeta, 0.0005).set(1);
20381
+ t.v = v;
20382
+ jump = { from: view, to, path: viewPath(view, to), t };
20383
+ moved();
20384
+ loop.wake();
20385
+ };
20386
+ const target = () => jump?.to ?? view;
20387
+ const centre = () => ({ x: vw / 2, y: vh / 2 });
20388
+ const grab = () => {
20389
+ pristine = false;
20390
+ jump = null;
20391
+ coast = null;
20392
+ };
20393
+ const local = (e) => {
20394
+ const r = root.getBoundingClientRect();
20395
+ return { x: e.clientX - r.left, y: e.clientY - r.top };
20396
+ };
20397
+ let pointer = null;
20398
+ let pinching = false;
20399
+ const onWheel = (e) => {
20400
+ e.preventDefault();
20401
+ const k = e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? vh : 1;
20402
+ if (e.ctrlKey || e.metaKey) {
20403
+ if (pinching)
20404
+ return;
20405
+ const dy = e.deltaY * k;
20406
+ const at = local(e);
20407
+ grab();
20408
+ setView(zoomAround(view, view.scale * wheelZoom(dy, e.ctrlKey), at, minZoom, maxZoom));
20409
+ return;
20410
+ }
20411
+ let dx = e.deltaX * k;
20412
+ let dy = e.deltaY * k;
20413
+ if (e.shiftKey && !dx) {
20414
+ dx = dy;
20415
+ dy = 0;
20416
+ }
20417
+ grab();
20418
+ setView({ x: view.x - dx, y: view.y - dy, scale: view.scale });
20419
+ };
20420
+ let gestureScale = 1;
20421
+ const onGesture = (e) => {
20422
+ e.preventDefault();
20423
+ const g = e;
20424
+ if (e.type === "gesturestart") {
20425
+ gestureScale = 1;
20426
+ pinching = true;
20427
+ grab();
20428
+ return;
20429
+ }
20430
+ if (e.type === "gestureend") {
20431
+ pinching = false;
20432
+ return;
20433
+ }
20434
+ const at = g.clientX !== undefined ? local(g) : centre();
20435
+ setView(zoomAround(view, view.scale * g.scale / gestureScale, at, minZoom, maxZoom));
20436
+ gestureScale = g.scale;
20437
+ };
20438
+ let drag = null;
20439
+ const touches = new Map;
20440
+ let pinch = null;
20441
+ let space = false;
20442
+ let spaceDragged = false;
20443
+ let hovering = false;
20444
+ let pressed = null;
20445
+ const capped = (v) => {
20446
+ const speed = Math.hypot(v.x, v.y);
20447
+ return speed > MAX_FLING ? { x: v.x / speed * MAX_FLING, y: v.y / speed * MAX_FLING } : v;
20448
+ };
20449
+ const onBackground = (target) => {
20450
+ const el = target;
20451
+ return !el?.closest?.(".knobs-canvas-card,.knobs-canvas-zoom");
20452
+ };
20453
+ const beginDrag = (e, grabbing) => {
20454
+ grab();
20455
+ held = true;
20456
+ drag = { id: e.pointerId, last: local(e), samples: [] };
20457
+ root.dataset.panning = "";
20458
+ if (space)
20459
+ spaceDragged = true;
20460
+ if (grabbing)
20461
+ root.dataset.grabbing = "";
20462
+ try {
20463
+ root.setPointerCapture(e.pointerId);
20464
+ } catch {}
20465
+ moved();
20466
+ };
20467
+ const endDrag = (coastOn) => {
20468
+ const d = drag;
20469
+ drag = null;
20470
+ held = false;
20471
+ delete root.dataset.panning;
20472
+ delete root.dataset.grabbing;
20473
+ if (!d)
20474
+ return;
20475
+ const v = coastOn ? capped(releaseVelocity(d.samples, performance.now())) : { x: 0, y: 0 };
20476
+ if (Math.hypot(v.x, v.y) > 60) {
20477
+ coast = { vx: v.x, vy: v.y, vs: 0, at: centre() };
20478
+ loop.wake();
20479
+ }
20480
+ moved();
20481
+ };
20482
+ const spread = () => {
20483
+ const [a, b] = [...touches.values()];
20484
+ return a && b ? { d: Math.hypot(a.x - b.x, a.y - b.y), mid: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 } } : null;
20485
+ };
20486
+ const onPointerDown = (e) => {
20487
+ pristine = false;
20488
+ if (e.isPrimary)
20489
+ pressed = e.target;
20490
+ if (e.pointerType === "touch") {
20491
+ touches.set(e.pointerId, local(e));
20492
+ if (touches.size === 2) {
20493
+ if (drag)
20494
+ endDrag(false);
20495
+ const s = spread();
20496
+ grab();
20497
+ held = true;
20498
+ pinch = { d: s.d, mid: s.mid, samples: [] };
20499
+ root.dataset.panning = "";
20500
+ for (const id of touches.keys())
20501
+ try {
20502
+ root.setPointerCapture(id);
20503
+ } catch {}
20504
+ e.preventDefault();
20505
+ e.stopPropagation();
20506
+ return;
20507
+ }
20508
+ if (touches.size === 1 && onBackground(e.target))
20509
+ beginDrag(e, false);
20510
+ return;
20511
+ }
20512
+ const middle = e.button === 1;
20513
+ if (!middle && e.button !== 0)
20514
+ return;
20515
+ if (!middle && !space && !onBackground(e.target))
20516
+ return;
20517
+ e.preventDefault();
20518
+ if (!middle && onBackground(e.target))
20519
+ root.focus({ preventScroll: true });
20520
+ beginDrag(e, middle || space);
20521
+ };
20522
+ const onPointerMove = (e) => {
20523
+ if (e.pointerType !== "touch")
20524
+ pointer = local(e);
20525
+ if (touches.has(e.pointerId))
20526
+ touches.set(e.pointerId, local(e));
20527
+ if (pinch) {
20528
+ const s = spread();
20529
+ if (!s)
20530
+ return;
20531
+ const v = pinchView(view, pinch.mid, s.mid, s.d / Math.max(1, pinch.d), minZoom, maxZoom);
20532
+ pinch.d = s.d;
20533
+ pinch.mid = s.mid;
20534
+ pinch.samples.push({ x: s.mid.x, y: s.mid.y, t: performance.now(), s: Math.log(v.scale) });
20535
+ if (pinch.samples.length > 12)
20536
+ pinch.samples.shift();
20537
+ setView(v);
20538
+ return;
20539
+ }
20540
+ if (!drag || drag.id !== e.pointerId)
20541
+ return;
20542
+ const p = local(e);
20543
+ const dx = p.x - drag.last.x;
20544
+ const dy = p.y - drag.last.y;
20545
+ drag.last = p;
20546
+ drag.samples.push({ x: p.x, y: p.y, t: performance.now() });
20547
+ if (drag.samples.length > 12)
20548
+ drag.samples.shift();
20549
+ setView({ x: view.x + dx, y: view.y + dy, scale: view.scale });
20550
+ };
20551
+ const onPointerUp = (e) => {
20552
+ if (touches.delete(e.pointerId) && pinch) {
20553
+ if (touches.size < 2) {
20554
+ const p = pinch;
20555
+ pinch = null;
20556
+ held = false;
20557
+ delete root.dataset.panning;
20558
+ const now = performance.now();
20559
+ const v = capped(releaseVelocity(p.samples, now));
20560
+ const first = p.samples.find((s) => now - s.t <= 80) ?? p.samples[0];
20561
+ const last = p.samples.at(-1);
20562
+ const dt = first && last ? (last.t - first.t) / 1000 : 0;
20563
+ const vs = dt > 0 && now - last.t < 60 ? clamp3((last.s - first.s) / dt, -4, 4) : 0;
20564
+ if (Math.hypot(v.x, v.y) > 60 || Math.abs(vs) > 0.3) {
20565
+ coast = { vx: v.x, vy: v.y, vs, at: p.mid };
20566
+ loop.wake();
20567
+ }
20568
+ moved();
20569
+ }
20570
+ return;
20571
+ }
20572
+ if (drag && drag.id === e.pointerId)
20573
+ endDrag(e.type === "pointerup");
20574
+ };
20575
+ const onDblClick = (e) => {
20576
+ if (space)
20577
+ return;
20578
+ const el = e.target === root && pressed && root.contains(pressed) ? pressed : e.target;
20579
+ const tileEl = el.closest?.(".knobs-canvas-tile");
20580
+ if (tileEl) {
20581
+ const card = el.closest(".knobs-canvas-card");
20582
+ if (card && (el.closest(INTERACTIVE) || isTypingTarget(el)))
20583
+ return;
20584
+ const id = tileEl.dataset.id;
20585
+ const f = focusTarget(id);
20586
+ if (!f)
20587
+ return;
20588
+ const t = target();
20589
+ const there = Math.abs(t.scale / f.scale - 1) < 0.02 && Math.abs(t.x - f.x) < 4 && Math.abs(t.y - f.y) < 4;
20590
+ if (there)
20591
+ api.fit();
20592
+ else
20593
+ startJump(f, FIT);
20594
+ return;
20595
+ }
20596
+ if (onBackground(el))
20597
+ api.fit();
20598
+ };
20599
+ const keyAnchor = () => hovering && pointer ? pointer : centre();
20600
+ const onKey = (e) => {
20601
+ if (isTypingTarget(e.target))
20602
+ return;
20603
+ const a = keyAction(e);
20604
+ if (!a || a === "actual" && (e.metaKey || e.ctrlKey))
20605
+ return;
20606
+ e.preventDefault();
20607
+ e.stopPropagation();
20608
+ if (a === "fit")
20609
+ return api.fit();
20610
+ const from = target();
20611
+ const scale = a === "actual" ? 1 : a === "in" ? from.scale * KEY_ZOOM : from.scale / KEY_ZOOM;
20612
+ startJump(zoomAround(from, scale, keyAnchor(), minZoom, maxZoom), KEY2);
20613
+ };
20614
+ const spaceOwner = (e) => e.key === " " && !e.metaKey && !e.ctrlKey && !e.altKey && !isTypingTarget(e.target) && (hovering || root.contains(doc.activeElement));
20615
+ const onControl = () => {
20616
+ const el = doc.activeElement;
20617
+ return !!el && el !== root && root.contains(el) && !!el.closest(INTERACTIVE);
20618
+ };
20619
+ const onDocKeyDown = (e) => {
20620
+ if (!spaceOwner(e))
20621
+ return;
20622
+ if (!onControl())
20623
+ e.preventDefault();
20624
+ if (space)
20625
+ return;
20626
+ space = true;
20627
+ spaceDragged = false;
20628
+ root.dataset.space = "";
20629
+ };
20630
+ const endSpace = () => {
20631
+ space = false;
20632
+ delete root.dataset.space;
20633
+ if (!drag)
20634
+ delete root.dataset.grabbing;
20635
+ };
20636
+ const onDocKeyUp = (e) => {
20637
+ if (e.key !== " " || !space)
20638
+ return;
20639
+ if (spaceDragged || !onControl())
20640
+ e.preventDefault();
20641
+ endSpace();
20642
+ };
20643
+ root.addEventListener("wheel", onWheel, { passive: false });
20644
+ root.addEventListener("gesturestart", onGesture);
20645
+ root.addEventListener("gesturechange", onGesture);
20646
+ root.addEventListener("gestureend", onGesture);
20647
+ root.addEventListener("pointerdown", onPointerDown, { capture: true });
20648
+ root.addEventListener("pointermove", onPointerMove);
20649
+ root.addEventListener("pointerup", onPointerUp);
20650
+ root.addEventListener("pointercancel", onPointerUp);
20651
+ root.addEventListener("pointerenter", () => hovering = true);
20652
+ root.addEventListener("pointerleave", () => {
20653
+ hovering = false;
20654
+ });
20655
+ root.addEventListener("auxclick", (e) => e.button === 1 && e.preventDefault());
20656
+ root.addEventListener("dblclick", onDblClick);
20657
+ root.addEventListener("keydown", onKey);
20658
+ doc.addEventListener("keydown", onDocKeyDown, { capture: true });
20659
+ doc.addEventListener("keyup", onDocKeyUp, { capture: true });
20660
+ win.addEventListener("blur", endSpace);
20661
+ root.addEventListener("knobs-restyle", () => {
20662
+ measure();
20663
+ relayout(true);
20664
+ });
20665
+ const focusTarget = (id) => {
20666
+ const r = rects.get(id);
20667
+ if (!r || !vw || !vh)
20668
+ return null;
20669
+ return fitView(r, vw, vh, { pad, min: minZoom, max: Math.min(maxZoom, FOCUS_MAX) });
20670
+ };
20671
+ for (const it of items)
20672
+ mount(it, false);
20673
+ vw = root.clientWidth;
20674
+ vh = root.clientHeight;
20675
+ measure();
20676
+ relayout(false);
20677
+ rootRo.observe(root);
20678
+ drawView();
20679
+ const api = {
20680
+ element: root,
20681
+ get view() {
20682
+ return view;
20683
+ },
20684
+ get rects() {
20685
+ return rects;
20686
+ },
20687
+ fit() {
20688
+ const f = fitTarget();
20689
+ if (f)
20690
+ startJump(f, FIT);
20691
+ },
20692
+ focus(id) {
20693
+ const f = focusTarget(id);
20694
+ if (f)
20695
+ startJump(f, FIT);
20696
+ },
20697
+ zoomTo(scale, at) {
20698
+ const from = target();
20699
+ startJump(zoomAround(from, scale, at ?? centre(), minZoom, maxZoom), KEY2);
20700
+ },
20701
+ update(next) {
20702
+ const ids = new Set(next.map((it) => it.id));
20703
+ for (const t of [...tiles.values()])
20704
+ if (!ids.has(t.id))
20705
+ leave(t);
20706
+ for (const it of next) {
20707
+ const t = tiles.get(it.id);
20708
+ if (!t) {
20709
+ mount(it, true);
20710
+ continue;
20711
+ }
20712
+ if (t.item.render !== it.render) {
20713
+ t.cleanup?.();
20714
+ t.card.replaceChildren();
20715
+ t.cleanup = it.render(t.card) || undefined;
20716
+ }
20717
+ t.item = it;
20718
+ setTitle(t);
20719
+ sizeCard(t);
20720
+ }
20721
+ items = next;
20722
+ measure();
20723
+ relayout(true);
20724
+ },
20725
+ get moving() {
20726
+ return loop.running;
20727
+ },
20728
+ stats() {
20729
+ const s = [...times].sort((a, b) => a - b);
20730
+ const q = (p) => Math.round((s[Math.floor(p * (s.length - 1))] ?? 0) * 1000) / 1000;
20731
+ return { frames, p50: q(0.5), p95: q(0.95), max: q(1) };
20732
+ },
20733
+ dispose() {
20734
+ loop.stop();
20735
+ ro.disconnect();
20736
+ rootRo.disconnect();
20737
+ win.clearTimeout(settleTimer);
20738
+ if (relayoutQueued)
20739
+ win.cancelAnimationFrame(relayoutQueued);
20740
+ doc.removeEventListener("keydown", onDocKeyDown, { capture: true });
20741
+ doc.removeEventListener("keyup", onDocKeyUp, { capture: true });
20742
+ win.removeEventListener("blur", endSpace);
20743
+ for (const t of [...tiles.values(), ...leaving])
20744
+ unmount(t);
20745
+ root.remove();
20746
+ }
20747
+ };
20748
+ return api;
20749
+ }
19776
20750
  // node_modules/@kitlangton/rolling-number/dist/chunk-vm1v7ncb.js
19777
20751
  var z = new Map;
19778
20752
  var le = /[\u0590-\u08ff\u200e\u200f\u202a-\u202e\u2066-\u2069\ufb1d-\ufeff]/u;
@@ -25479,6 +26453,8 @@ export {
25479
26453
  bento,
25480
26454
  neighbour as bentoNeighbour,
25481
26455
  windowOf as bentoWindow,
26456
+ canvas,
26457
+ boundsOf as canvasBounds,
25482
26458
  claimsDigit,
25483
26459
  clampView,
25484
26460
  codeDiff,
@@ -25506,6 +26482,7 @@ export {
25506
26482
  diffStatus,
25507
26483
  diffTree,
25508
26484
  digitPick,
26485
+ dotGrid,
25509
26486
  drag as dragDivider,
25510
26487
  dropTarget,
25511
26488
  facts,
@@ -25513,6 +26490,7 @@ export {
25513
26490
  fileKey,
25514
26491
  filesUnder,
25515
26492
  fitRect,
26493
+ fitView,
25516
26494
  flatten,
25517
26495
  flattenActivity,
25518
26496
  followView,
@@ -25533,6 +26511,7 @@ export {
25533
26511
  keepSelection as keepActivitySelection,
25534
26512
  keepFile,
25535
26513
  keepPick,
26514
+ layoutCanvas,
25536
26515
  letterbox,
25537
26516
  magnet,
25538
26517
  marks,
@@ -25552,6 +26531,7 @@ export {
25552
26531
  normalizeWalkthrough,
25553
26532
  optionPicker,
25554
26533
  overlayLook,
26534
+ packRows,
25555
26535
  pageHints,
25556
26536
  parseLayout,
25557
26537
  parsePatch,
@@ -25606,6 +26586,7 @@ export {
25606
26586
  tree,
25607
26587
  typeahead,
25608
26588
  validMove,
26589
+ viewPath,
25609
26590
  virtualWindow,
25610
26591
  walkthrough,
25611
26592
  walkthroughProgress,
@@ -25614,5 +26595,6 @@ export {
25614
26595
  wipeKey,
25615
26596
  wipeX,
25616
26597
  zoomAbout,
26598
+ zoomAround,
25617
26599
  zoomView
25618
26600
  };