@shadow-garden/bapbong-ui 0.15.0 → 0.17.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.js CHANGED
@@ -9,6 +9,13 @@ function shortcutLabel(command, registries) {
9
9
  }
10
10
  return void 0;
11
11
  }
12
+ var TABS_CSS = `
13
+ .bb-tabs{display:inline-flex;align-self:flex-start;border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;overflow:hidden}
14
+ .bb-tab{height:30px;padding:0 18px;border:0;border-right:0.5px solid var(--bb-ui-border,#e3e3e0);background:transparent;color:inherit;opacity:.65;font:inherit;font-size:13px;cursor:pointer}
15
+ .bb-tab:last-child{border-right:0}
16
+ .bb-tab:hover{background:var(--bb-ui-hover,#f1efe8);opacity:.9}
17
+ .bb-tab[aria-selected="true"]{background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c);opacity:1}
18
+ `;
12
19
  function injectStyle(id, css) {
13
20
  if (document.getElementById(id)) return;
14
21
  const el5 = document.createElement("style");
@@ -32,12 +39,12 @@ function placeFloating(el5, anchor) {
32
39
  }
33
40
  function rovingGrid(cells) {
34
41
  let cur = [0, 0];
35
- const at = (r, c) => cells[r]?.[c];
36
- const focusCell = (r, c) => {
42
+ const at = (r, c2) => cells[r]?.[c2];
43
+ const focusCell = (r, c2) => {
37
44
  const rows = cells.length;
38
45
  if (rows === 0) return;
39
46
  const nr = Math.min(rows - 1, Math.max(0, r));
40
- const nc = Math.min(cells[nr].length - 1, Math.max(0, c));
47
+ const nc = Math.min(cells[nr].length - 1, Math.max(0, c2));
41
48
  const prev = at(cur[0], cur[1]);
42
49
  if (prev) prev.tabIndex = -1;
43
50
  const next = at(nr, nc);
@@ -47,9 +54,9 @@ function rovingGrid(cells) {
47
54
  cur = [nr, nc];
48
55
  };
49
56
  cells.forEach(
50
- (row, r) => row.forEach((cell, c) => {
57
+ (row, r) => row.forEach((cell, c2) => {
51
58
  cell.setAttribute("role", "gridcell");
52
- cell.tabIndex = r === 0 && c === 0 ? 0 : -1;
59
+ cell.tabIndex = r === 0 && c2 === 0 ? 0 : -1;
53
60
  cell.addEventListener("keydown", (e) => {
54
61
  const delta = {
55
62
  ArrowRight: [0, 1],
@@ -62,10 +69,10 @@ function rovingGrid(cells) {
62
69
  const d = delta[e.key];
63
70
  if (!d) return;
64
71
  e.preventDefault();
65
- focusCell(r + d[0], c + d[1]);
72
+ focusCell(r + d[0], c2 + d[1]);
66
73
  });
67
74
  cell.addEventListener("focus", () => {
68
- cur = [r, c];
75
+ cur = [r, c2];
69
76
  });
70
77
  })
71
78
  );
@@ -395,9 +402,9 @@ function openColorPicker({
395
402
  panel.remove();
396
403
  anchor.focus();
397
404
  };
398
- const pick = (c) => {
399
- if (c && !COLOR_PALETTE.some((row) => row.includes(c))) remember(c);
400
- onPick(c);
405
+ const pick = (c2) => {
406
+ if (c2 && !COLOR_PALETTE.some((row) => row.includes(c2))) remember(c2);
407
+ onPick(c2);
401
408
  close();
402
409
  };
403
410
  if (clearLabel !== void 0) {
@@ -441,15 +448,15 @@ function openColorPicker({
441
448
  );
442
449
  const customRow2 = document.createElement("div");
443
450
  customRow2.className = "bb-cpk-row";
444
- for (const c of customColors) {
451
+ for (const c2 of customColors) {
445
452
  const sw = document.createElement("button");
446
453
  sw.type = "button";
447
454
  sw.className = "bb-cpk-sw";
448
- sw.style.background = c;
449
- sw.title = c;
450
- sw.setAttribute("aria-label", c);
451
- if (c.toUpperCase() === value?.toUpperCase()) sw.classList.add("on");
452
- sw.addEventListener("click", () => pick(c));
455
+ sw.style.background = c2;
456
+ sw.title = c2;
457
+ sw.setAttribute("aria-label", c2);
458
+ if (c2.toUpperCase() === value?.toUpperCase()) sw.classList.add("on");
459
+ sw.addEventListener("click", () => pick(c2));
453
460
  customRow2.append(sw);
454
461
  }
455
462
  const plus = document.createElement("button");
@@ -533,8 +540,8 @@ function colorButton(o) {
533
540
  anchor: el5,
534
541
  value: o.value(),
535
542
  clearLabel: o.clearLabel,
536
- onPick: (c) => {
537
- o.onPick(c);
543
+ onPick: (c2) => {
544
+ o.onPick(c2);
538
545
  sync();
539
546
  }
540
547
  });
@@ -618,6 +625,7 @@ var STYLE3 = `
618
625
  .bb-toolbar{display:flex;gap:10px;align-items:center;flex-wrap:nowrap;overflow:hidden;padding:6px 8px;font-family:var(--bb-ui-font,system-ui,-apple-system,sans-serif);color:var(--bb-ui-fg,#2c2c2a);background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));border-bottom:1px solid var(--bb-ui-border,#e3e3e0);box-sizing:border-box}
619
626
  .bb-toolbar *{box-sizing:border-box}
620
627
  .bb-toolbar-group{display:flex;gap:2px;flex:none}
628
+ .bb-toolbar-group[hidden]{display:none}
621
629
  .bb-toolbar-group+.bb-toolbar-group{padding-left:10px;border-left:1px solid var(--bb-ui-border,#e3e3e0)}
622
630
  .bb-toolbar-more{margin-left:auto;flex:none}
623
631
  .bb-toolbar-pop{position:absolute;z-index:1200;top:100%;left:0;right:0;margin-top:4px;display:flex;flex-wrap:wrap;gap:10px;row-gap:6px;align-items:center;padding:6px 8px;background:var(--bb-ui-menu-bg,#fff);-webkit-backdrop-filter:var(--bb-ui-pop-filter,none);backdrop-filter:var(--bb-ui-pop-filter,none);border:1px solid var(--bb-ui-pop-border,var(--bb-ui-border,#e3e3e0));border-radius:10px;box-shadow:0 8px 28px rgba(0,0,0,.16);font-family:var(--bb-ui-font,system-ui,-apple-system,sans-serif);color:var(--bb-ui-fg,#2c2c2a)}
@@ -626,6 +634,9 @@ var STYLE3 = `
626
634
  .bb-toolbar-btn:hover{background:var(--bb-ui-hover,#f1efe8)}
627
635
  .bb-toolbar-btn.is-active{background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c);border-color:var(--bb-ui-active-border,#b5d4f4)}
628
636
  .bb-toolbar-btn:disabled{opacity:.38;cursor:default}
637
+ .bb-toolbar-btn.bb-btn-accent{gap:5px;padding:0 9px;font-size:12.5px;white-space:nowrap;background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c);border-color:var(--bb-ui-active-border,#b5d4f4)}
638
+ .bb-toolbar-btn.bb-btn-accent:hover{background:var(--bb-ui-active-bg,#e6f1fb);border-color:var(--bb-ui-active-fg,#0c447c)}
639
+ .bb-btn-caret{font-size:9px;opacity:.7;line-height:1}
629
640
  .bb-toolbar-select{height:30px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#e3e3e0));border-radius:6px;background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));color:inherit;font-family:inherit;font-size:13px;padding:0 6px;cursor:pointer}
630
641
  .bb-toolbar-select:hover{background:var(--bb-ui-hover,#f1efe8)}
631
642
  .bb-i-bold{font-weight:700}.bb-i-italic{font-style:italic}.bb-i-underline{text-decoration:underline}.bb-i-strike{text-decoration:line-through}
@@ -645,11 +656,30 @@ var STYLE3 = `
645
656
  .bb-split-bar{flex:1;height:3px;border-radius:2px;background:var(--bb-ui-border,#d9d9d4)}
646
657
  `;
647
658
  function defaultToolbarGroups(commands) {
648
- const names = [...commands].map((c) => c.name);
659
+ const names = [...commands].map((c2) => c2.name);
649
660
  const aligns = names.filter((n) => n.startsWith("align-"));
650
661
  const rest = names.filter((n) => !n.startsWith("align-"));
651
662
  return [rest, aligns].filter((g2) => g2.length > 0);
652
663
  }
664
+ function foldPlan(candidates, avail, moreWidth, gap) {
665
+ const vis = candidates.filter((c2) => !c2.hidden);
666
+ const rowWidth = vis.reduce((sum, c2) => sum + c2.width, 0) + gap * Math.max(0, vis.length - 1);
667
+ const folded = /* @__PURE__ */ new Set();
668
+ if (rowWidth <= avail + 1) return folded;
669
+ const order = [
670
+ ...vis.filter((c2) => !c2.sticky).reverse(),
671
+ ...vis.filter((c2) => c2.sticky).reverse()
672
+ ];
673
+ const fitsRemaining = () => {
674
+ const rem = vis.filter((c2) => !folded.has(c2.idx));
675
+ return rem.reduce((sum, c2) => sum + c2.width, 0) + gap * rem.length + moreWidth <= avail + 1;
676
+ };
677
+ for (const c2 of order) {
678
+ if (fitsRemaining()) break;
679
+ folded.add(c2.idx);
680
+ }
681
+ return folded;
682
+ }
653
683
  function mountToolbar(host, editor, options = {}) {
654
684
  injectStyle("bb-ui-toolbar-styles", STYLE3);
655
685
  const items = { ...DEFAULT_ITEMS, ...options.items ?? {} };
@@ -660,17 +690,25 @@ function mountToolbar(host, editor, options = {}) {
660
690
  root.className = "bb-toolbar";
661
691
  root.setAttribute("role", "toolbar");
662
692
  const buttons = [];
693
+ const groupList = [];
694
+ const conditionalGroups = [];
663
695
  const selects = [];
664
696
  const colors = [];
665
697
  const splits = [];
666
698
  let latest = null;
667
699
  for (const group of groups) {
668
- const entries = group.filter(
700
+ const spec = Array.isArray(group) ? { entries: group } : group;
701
+ const entries = spec.entries.filter(
669
702
  (e) => typeof e !== "string" || editor.commands.has(e)
670
703
  );
671
704
  if (entries.length === 0) continue;
672
705
  const groupEl = document.createElement("div");
673
706
  groupEl.className = "bb-toolbar-group";
707
+ groupList.push({ el: groupEl, sticky: !!spec.sticky, lastWidth: 0 });
708
+ if (spec.visible) {
709
+ conditionalGroups.push({ el: groupEl, visible: spec.visible });
710
+ groupEl.hidden = true;
711
+ }
674
712
  for (const entry of entries) {
675
713
  if (typeof entry !== "string" && entry.kind === "select") {
676
714
  const sel = document.createElement("select");
@@ -696,12 +734,24 @@ function mountToolbar(host, editor, options = {}) {
696
734
  if (typeof entry !== "string" && entry.kind === "button") {
697
735
  const btn2 = document.createElement("button");
698
736
  btn2.type = "button";
699
- btn2.className = "bb-toolbar-btn";
737
+ btn2.className = "bb-toolbar-btn" + (entry.accent ? " bb-btn-accent" : "");
700
738
  btn2.title = entry.title;
701
739
  btn2.setAttribute("aria-label", entry.title);
702
740
  btn2.setAttribute("aria-haspopup", "dialog");
703
741
  if (entry.svg) btn2.innerHTML = entry.svg;
704
742
  else btn2.textContent = entry.label ?? entry.title;
743
+ if (entry.text) {
744
+ const span = document.createElement("span");
745
+ span.textContent = entry.text;
746
+ btn2.appendChild(span);
747
+ }
748
+ if (entry.caret) {
749
+ const caret = document.createElement("span");
750
+ caret.className = "bb-btn-caret";
751
+ caret.setAttribute("aria-hidden", "true");
752
+ caret.textContent = "\u25BE";
753
+ btn2.appendChild(caret);
754
+ }
705
755
  btn2.addEventListener("mousedown", (e) => e.preventDefault());
706
756
  btn2.addEventListener("click", () => entry.onClick(btn2));
707
757
  groupEl.appendChild(btn2);
@@ -862,19 +912,52 @@ function mountToolbar(host, editor, options = {}) {
862
912
  pop.hidden = !pop.hidden;
863
913
  moreBtn.setAttribute("aria-expanded", String(!pop.hidden));
864
914
  });
865
- const fits = () => root.scrollWidth <= root.clientWidth + 1;
915
+ let gapPx = -1;
916
+ let moreW = -1;
917
+ const anchorIn = (container, idx) => {
918
+ for (let j = idx + 1; j < groupList.length; j++)
919
+ if (groupList[j].el.parentElement === container) return groupList[j].el;
920
+ return container === root ? moreBtn : null;
921
+ };
866
922
  const layout = () => {
867
- while (pop.firstChild) root.insertBefore(pop.firstChild, moreBtn);
868
- moreBtn.style.display = "none";
869
- closePop();
870
- wrap.querySelectorAll(".bb-split-pop").forEach((p) => p.hidden = true);
871
- if (fits()) return;
872
- moreBtn.style.display = "";
873
- const groupEls = Array.from(root.children).filter(
874
- (el5) => el5.classList.contains("bb-toolbar-group")
875
- );
876
- for (let i = groupEls.length - 1; i >= 0 && !fits(); i--) {
877
- pop.insertBefore(groupEls[i], pop.firstChild);
923
+ if (gapPx < 0)
924
+ gapPx = Number.parseFloat(getComputedStyle(root).columnGap) || 0;
925
+ if (moreW < 0) {
926
+ moreBtn.style.visibility = "hidden";
927
+ const prev = moreBtn.style.display;
928
+ moreBtn.style.display = "";
929
+ moreW = moreBtn.offsetWidth;
930
+ moreBtn.style.display = prev;
931
+ moreBtn.style.visibility = "";
932
+ }
933
+ const avail = root.clientWidth;
934
+ const candidates = groupList.map((g2, idx) => {
935
+ const w = g2.el.offsetWidth;
936
+ if (w > 0) g2.lastWidth = w;
937
+ return {
938
+ idx,
939
+ width: g2.lastWidth,
940
+ sticky: g2.sticky,
941
+ hidden: g2.el.hidden
942
+ };
943
+ });
944
+ const folded = foldPlan(candidates, avail, moreW, gapPx);
945
+ let moved = false;
946
+ groupList.forEach((g2, idx) => {
947
+ const inPop = g2.el.parentElement === pop;
948
+ const should = folded.has(idx);
949
+ if (inPop === should) return;
950
+ moved = true;
951
+ if (should) pop.insertBefore(g2.el, anchorIn(pop, idx));
952
+ else root.insertBefore(g2.el, anchorIn(root, idx));
953
+ });
954
+ const showMore = folded.size > 0;
955
+ if (moreBtn.style.display !== "none" !== showMore)
956
+ moreBtn.style.display = showMore ? "" : "none";
957
+ if (!showMore) closePop();
958
+ if (moved) {
959
+ closePop();
960
+ wrap.querySelectorAll(".bb-split-pop").forEach((p) => p.hidden = true);
878
961
  }
879
962
  };
880
963
  let ro = null;
@@ -886,6 +969,15 @@ function mountToolbar(host, editor, options = {}) {
886
969
  layout();
887
970
  const refresh = (state) => {
888
971
  latest = state;
972
+ let visibilityChanged = false;
973
+ for (const g2 of conditionalGroups) {
974
+ const show = g2.visible(state);
975
+ if (show === g2.el.hidden) {
976
+ g2.el.hidden = !show;
977
+ visibilityChanged = true;
978
+ }
979
+ }
980
+ if (visibilityChanged) layout();
889
981
  for (const { name, el: el5 } of buttons) {
890
982
  const cmd = editor.commands.get(name);
891
983
  if (!cmd) continue;
@@ -895,7 +987,7 @@ function mountToolbar(host, editor, options = {}) {
895
987
  el5.disabled = cmd.isEnabled ? !cmd.isEnabled(state) : false;
896
988
  }
897
989
  for (const { spec, el: el5 } of selects) el5.value = spec.value(state);
898
- for (const c of colors) c.sync();
990
+ for (const c2 of colors) c2.sync();
899
991
  for (const { spec, cards } of splits) {
900
992
  const selected = spec.value(state);
901
993
  for (const card of cards)
@@ -905,7 +997,7 @@ function mountToolbar(host, editor, options = {}) {
905
997
  );
906
998
  }
907
999
  };
908
- const off = editor.onChange((c) => refresh(c.state));
1000
+ const off = editor.onChange((c2) => refresh(c2.state));
909
1001
  try {
910
1002
  refresh(editor.state);
911
1003
  } catch {
@@ -1149,7 +1241,7 @@ function showMenu(entries, at, options = {}) {
1149
1241
  return handle;
1150
1242
  }
1151
1243
  function defaultMenus(commands) {
1152
- const names = [...commands].map((c) => c.name);
1244
+ const names = [...commands].map((c2) => c2.name);
1153
1245
  const marks = ["bold", "italic", "underline", "strike"].filter(
1154
1246
  (n) => commands.has(n)
1155
1247
  );
@@ -1263,10 +1355,10 @@ function mountMenubar(host, editor, options = {}) {
1263
1355
  function refresh(state) {
1264
1356
  latest = state;
1265
1357
  if (openIdx < 0) return;
1266
- for (const c of checks) c.el.textContent = c.active(state) ? "\u2713" : "";
1358
+ for (const c2 of checks) c2.el.textContent = c2.active(state) ? "\u2713" : "";
1267
1359
  for (const e of enables) e.el.disabled = !e.enabled(state);
1268
1360
  }
1269
- const off = editor.onChange((c) => refresh(c.state));
1361
+ const off = editor.onChange((c2) => refresh(c2.state));
1270
1362
  try {
1271
1363
  latest = editor.state;
1272
1364
  } catch {
@@ -1594,13 +1686,13 @@ function showLinkPanel(opts) {
1594
1686
  row.appendChild(icon);
1595
1687
  const label = document.createElement("span");
1596
1688
  label.className = "bb-linkpanel-href";
1597
- label.textContent = internal.label ?? "V\u1ECB tr\xED kh\xF4ng c\xF2n trong t\xE0i li\u1EC7u";
1689
+ label.textContent = internal.label ?? "This place is no longer in the document";
1598
1690
  label.title = internal.label ?? existing.href;
1599
1691
  if (!internal.label) label.classList.add("bb-linkpanel-stale");
1600
1692
  row.appendChild(label);
1601
1693
  if (internal.label) {
1602
1694
  row.appendChild(
1603
- iconBtn(ICONS.goTo, "\u0110i t\u1EDBi v\u1ECB tr\xED n\xE0y", () => {
1695
+ iconBtn(ICONS.goTo, "Go to this place", () => {
1604
1696
  closeCurrent2();
1605
1697
  internal.onGo();
1606
1698
  })
@@ -1814,8 +1906,8 @@ function openCellProperties({
1814
1906
  label: "Fill",
1815
1907
  clearLabel: "No fill",
1816
1908
  value: () => background,
1817
- onPick: (c) => {
1818
- background = c;
1909
+ onPick: (c2) => {
1910
+ background = c2;
1819
1911
  }
1820
1912
  });
1821
1913
  fill.append(fillBtn.el);
@@ -1868,8 +1960,8 @@ function openCellProperties({
1868
1960
  title: "Border colour",
1869
1961
  label: "Colour",
1870
1962
  value: () => penColor,
1871
- onPick: (c) => {
1872
- if (c) penColor = c;
1963
+ onPick: (c2) => {
1964
+ if (c2) penColor = c2;
1873
1965
  }
1874
1966
  });
1875
1967
  penRow.append(widthSel, styleSel, penBtn.el);
@@ -1933,8 +2025,373 @@ function openCellProperties({
1933
2025
  dialog.open();
1934
2026
  }
1935
2027
 
1936
- // packages/ui/src/lib/table-grid.ts
2028
+ // packages/ui/src/lib/equation-gallery.ts
2029
+ import { astToLinear } from "@shadow-garden/bapbong-contracts";
2030
+ var c = (s) => [...s].map((ch) => ({ t: "chr", ch }));
2031
+ var sup = (base, exp) => ({
2032
+ t: "scr",
2033
+ base,
2034
+ sub: [],
2035
+ sup: c(exp)
2036
+ });
2037
+ var subsup = (base, lo, hi) => ({
2038
+ t: "scr",
2039
+ base,
2040
+ sub: c(lo),
2041
+ sup: c(hi)
2042
+ });
2043
+ var BUILT_IN_EQUATIONS = [
2044
+ {
2045
+ name: "Area of a circle",
2046
+ ast: [...c("\u{1D434} = \u{1D70B}"), sup(c("\u{1D45F}"), "2")]
2047
+ },
2048
+ {
2049
+ name: "Pythagorean theorem",
2050
+ ast: [
2051
+ sup(c("\u{1D44E}"), "2"),
2052
+ ...c(" + "),
2053
+ sup(c("\u{1D44F}"), "2"),
2054
+ ...c(" = "),
2055
+ sup(c("\u{1D450}"), "2")
2056
+ ]
2057
+ },
2058
+ {
2059
+ name: "Quadratic formula",
2060
+ ast: [
2061
+ ...c("\u{1D465} = "),
2062
+ {
2063
+ t: "frac",
2064
+ num: [
2065
+ ...c("\u2212\u{1D44F} \xB1 "),
2066
+ {
2067
+ t: "rad",
2068
+ deg: [],
2069
+ body: [sup(c("\u{1D44F}"), "2"), ...c(" \u2212 4\u{1D44E}\u{1D450}")]
2070
+ }
2071
+ ],
2072
+ den: c("2\u{1D44E}")
2073
+ }
2074
+ ]
2075
+ },
2076
+ {
2077
+ name: "Law of cosines",
2078
+ ast: [
2079
+ sup(c("\u{1D44E}"), "2"),
2080
+ ...c(" = "),
2081
+ sup(c("\u{1D44F}"), "2"),
2082
+ ...c(" + "),
2083
+ sup(c("\u{1D450}"), "2"),
2084
+ ...c(" \u2212 2\u{1D44F}\u{1D450} cos \u{1D434}")
2085
+ ]
2086
+ },
2087
+ {
2088
+ name: "Binomial theorem",
2089
+ ast: [
2090
+ // The exponent belongs ON the bracket: a script with an empty base
2091
+ // would render its own empty slot — the dotted placeholder box.
2092
+ {
2093
+ t: "scr",
2094
+ base: [{ t: "fence", l: "(", r: ")", body: c("\u{1D44E} + \u{1D44F}") }],
2095
+ sub: [],
2096
+ sup: c("\u{1D45B}")
2097
+ },
2098
+ ...c(" = "),
2099
+ {
2100
+ t: "big",
2101
+ op: "\u2211",
2102
+ lo: c("\u{1D458} = 0"),
2103
+ hi: c("\u{1D45B}"),
2104
+ body: [
2105
+ subsup(c("\u{1D436}"), "\u{1D45B}", "\u{1D458}"),
2106
+ sup(c("\u{1D44E}"), "\u{1D458}"),
2107
+ { t: "scr", base: c("\u{1D44F}"), sub: [], sup: c("\u{1D45B}\u2212\u{1D458}") }
2108
+ ]
2109
+ }
2110
+ ]
2111
+ }
2112
+ ];
2113
+ var SVG_NS = "http://www.w3.org/2000/svg";
2114
+ function equationPreviewSvg(spec, opts = {}) {
2115
+ const svg = document.createElementNS(SVG_NS, "svg");
2116
+ svg.setAttribute("viewBox", `0 0 ${spec.width} ${spec.height}`);
2117
+ const max = opts.maxWidth ?? spec.width;
2118
+ const scale = Math.min(1, max / Math.max(1, spec.width));
2119
+ svg.setAttribute("width", String(Math.round(spec.width * scale)));
2120
+ svg.setAttribute("height", String(Math.round(spec.height * scale)));
2121
+ svg.setAttribute("aria-hidden", "true");
2122
+ for (const op of spec.ops) svg.append(opElement(op));
2123
+ return svg;
2124
+ }
2125
+ function opElement(op) {
2126
+ if (op.kind === "line") {
2127
+ const el6 = document.createElementNS(SVG_NS, "line");
2128
+ el6.setAttribute("x1", String(op.x1));
2129
+ el6.setAttribute("y1", String(op.y1));
2130
+ el6.setAttribute("x2", String(op.x2));
2131
+ el6.setAttribute("y2", String(op.y2));
2132
+ el6.setAttribute("stroke", op.color);
2133
+ el6.setAttribute("stroke-width", String(Math.max(op.width, 0.75)));
2134
+ return el6;
2135
+ }
2136
+ if (op.kind === "polygon") {
2137
+ const el6 = document.createElementNS(SVG_NS, "polygon");
2138
+ el6.setAttribute("points", op.points.map((p) => `${p.x},${p.y}`).join(" "));
2139
+ el6.setAttribute("fill", op.fill ?? "none");
2140
+ if (op.stroke) {
2141
+ el6.setAttribute("stroke", op.stroke);
2142
+ el6.setAttribute("stroke-width", String(op.strokeWidth ?? 1));
2143
+ }
2144
+ return el6;
2145
+ }
2146
+ const el5 = document.createElementNS(SVG_NS, "text");
2147
+ el5.setAttribute("x", String(op.x));
2148
+ el5.setAttribute("y", String(op.y));
2149
+ el5.setAttribute("font-size", String(op.size));
2150
+ el5.setAttribute("font-family", op.family);
2151
+ el5.setAttribute("fill", op.color);
2152
+ if (op.bold) el5.setAttribute("font-weight", "bold");
2153
+ if (op.italic) el5.setAttribute("font-style", "italic");
2154
+ if (op.vAlign === "top") el5.setAttribute("dominant-baseline", "hanging");
2155
+ if (op.dx) {
2156
+ let x = op.x;
2157
+ for (const [i, ch] of [...op.text].entries()) {
2158
+ const t = document.createElementNS(SVG_NS, "tspan");
2159
+ t.setAttribute("x", String(x));
2160
+ t.textContent = ch;
2161
+ el5.append(t);
2162
+ x += op.dx[i] ?? 0;
2163
+ }
2164
+ } else {
2165
+ el5.textContent = op.text;
2166
+ }
2167
+ return el5;
2168
+ }
1937
2169
  var STYLE9 = `
2170
+ .bb-eqg{display:flex;flex-direction:column;min-width:236px;max-width:300px;user-select:none}
2171
+ .bb-eqg-head{font-size:11px;font-weight:600;opacity:.55;padding:2px 8px 6px}
2172
+ .bb-eqg-list{display:flex;flex-direction:column;max-height:320px;overflow-y:auto}
2173
+ .bb-eqg-item{display:flex;flex-direction:column;gap:3px;align-items:flex-start;width:100%;padding:7px 9px;border:0;border-radius:6px;background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}
2174
+ .bb-eqg-item:hover{background:var(--bb-ui-hover,#f1efe8)}
2175
+ .bb-eqg-name{font-size:11px;opacity:.6}
2176
+ /* The preview is the equation TYPESET \u2014 the same display list the canvas
2177
+ paints. The text form is the fallback for a host that cannot lay out. */
2178
+ .bb-eqg-prev{display:flex;align-items:center;min-height:22px;max-width:100%;overflow:hidden}
2179
+ .bb-eqg-prev svg{display:block}
2180
+ .bb-eqg-prev-text{font-family:"Times New Roman",Tinos,serif;font-size:15px;line-height:1.35;white-space:nowrap;text-overflow:ellipsis}
2181
+ .bb-eqg-foot{margin-top:4px;padding-top:5px;border-top:1px solid var(--bb-ui-border,#e3e3e0)}
2182
+ .bb-eqg-new{display:flex;align-items:center;gap:8px;width:100%;height:30px;padding:0 9px;border:0;border-radius:6px;background:transparent;color:inherit;font:inherit;font-size:13px;text-align:left;cursor:pointer}
2183
+ .bb-eqg-new:hover{background:var(--bb-ui-hover,#f1efe8)}
2184
+ .bb-eqg-key{margin-left:auto;opacity:.5;font-size:12px}
2185
+ `;
2186
+ var PREVIEW_PT = 11;
2187
+ var PREVIEW_MAX_W = 264;
2188
+ function equationGallery(options) {
2189
+ injectStyle("bb-ui-eqg-styles", STYLE9);
2190
+ const root = document.createElement("div");
2191
+ root.className = "bb-eqg";
2192
+ const head = document.createElement("div");
2193
+ head.className = "bb-eqg-head";
2194
+ head.textContent = "Built-in";
2195
+ root.append(head);
2196
+ const list = document.createElement("div");
2197
+ list.className = "bb-eqg-list";
2198
+ for (const item of options.items ?? BUILT_IN_EQUATIONS) {
2199
+ const btn = document.createElement("button");
2200
+ btn.type = "button";
2201
+ btn.className = "bb-eqg-item";
2202
+ const prev = document.createElement("div");
2203
+ prev.className = "bb-eqg-prev";
2204
+ const spec = options.layout?.(item.ast, PREVIEW_PT) ?? null;
2205
+ if (spec && spec.ops.length)
2206
+ prev.append(equationPreviewSvg(spec, { maxWidth: PREVIEW_MAX_W }));
2207
+ else {
2208
+ prev.classList.add("bb-eqg-prev-text");
2209
+ prev.textContent = astToLinear(item.ast);
2210
+ }
2211
+ const name = document.createElement("div");
2212
+ name.className = "bb-eqg-name";
2213
+ name.textContent = item.name;
2214
+ btn.append(prev, name);
2215
+ btn.addEventListener("mousedown", (e) => e.preventDefault());
2216
+ btn.addEventListener("click", () => options.onPick(item.ast));
2217
+ list.append(btn);
2218
+ }
2219
+ root.append(list);
2220
+ const foot = document.createElement("div");
2221
+ foot.className = "bb-eqg-foot";
2222
+ const neu = document.createElement("button");
2223
+ neu.type = "button";
2224
+ neu.className = "bb-eqg-new";
2225
+ const label = document.createElement("span");
2226
+ label.textContent = "Insert new equation";
2227
+ neu.append(label);
2228
+ if (options.newShortcut) {
2229
+ const key = document.createElement("span");
2230
+ key.className = "bb-eqg-key";
2231
+ key.textContent = options.newShortcut;
2232
+ neu.append(key);
2233
+ }
2234
+ neu.addEventListener("mousedown", (e) => e.preventDefault());
2235
+ neu.addEventListener("click", () => options.onNew());
2236
+ foot.append(neu);
2237
+ root.append(foot);
2238
+ return root;
2239
+ }
2240
+
2241
+ // packages/ui/src/lib/equation-panel.ts
2242
+ import {
2243
+ eqStructureGroups,
2244
+ MATH_AUTOCORRECT,
2245
+ MATH_SYMBOL_SETS
2246
+ } from "@shadow-garden/bapbong-contracts";
2247
+ var SHORTHAND = /* @__PURE__ */ new Map();
2248
+ for (const [name, ch] of Object.entries(MATH_AUTOCORRECT))
2249
+ if (!SHORTHAND.has(ch)) SHORTHAND.set(ch, `\\${name}`);
2250
+ var PREVIEW_PT2 = 10;
2251
+ var STYLE10 = `
2252
+ .bb-eqp{width:352px;display:flex;flex-direction:column;background:var(--bb-ui-menu-bg,#fff);-webkit-backdrop-filter:var(--bb-ui-pop-filter,none);backdrop-filter:var(--bb-ui-pop-filter,none);border:1px solid var(--bb-ui-pop-border,var(--bb-ui-border,#e3e3e0));border-radius:10px;box-shadow:0 8px 28px rgba(0,0,0,.14);user-select:none;overflow:hidden}
2253
+ .bb-eqp-tabs{display:flex;padding:8px 8px 0}
2254
+ .bb-eqp-body{padding:8px}
2255
+ .bb-eqp-set{width:100%;height:30px;margin-bottom:7px;border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;background:var(--bb-ui-control-bg,#fff);color:inherit;font:inherit;font-size:13px;padding:0 8px}
2256
+ .bb-eqp-grid{display:grid;grid-template-columns:repeat(10,1fr);gap:1px;max-height:190px;overflow-y:auto}
2257
+ .bb-eqp-sym{padding:5px 0;border:0;border-radius:5px;background:transparent;color:inherit;font-family:"Cambria Math","Times New Roman",Tinos,serif;font-size:16px;line-height:1.2;cursor:pointer}
2258
+ .bb-eqp-sym:hover{background:var(--bb-ui-hover,#f1efe8)}
2259
+ .bb-eqp-hint{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:22px;margin-top:7px;padding-top:6px;border-top:0.5px solid var(--bb-ui-border,#e3e3e0);font-size:12px;opacity:.6}
2260
+ .bb-eqp-hint-g{font-family:"Cambria Math","Times New Roman",Tinos,serif;font-size:15px}
2261
+ .bb-eqp-hint-k{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
2262
+ .bb-eqp-scroll{max-height:230px;overflow-y:auto}
2263
+ .bb-eqp-group{font-size:11px;font-weight:600;opacity:.5;padding:6px 2px 3px}
2264
+ .bb-eqp-row{display:grid;grid-template-columns:repeat(4,1fr);gap:3px}
2265
+ .bb-eqp-st{display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:3px;min-height:52px;padding:6px 2px;border:0;border-radius:6px;background:transparent;color:inherit;font:inherit;cursor:pointer}
2266
+ .bb-eqp-st:hover{background:var(--bb-ui-hover,#f1efe8)}
2267
+ .bb-eqp-st-name{font-size:10px;opacity:.6;text-align:center;line-height:1.25}
2268
+ .bb-eqp-st svg{display:block}
2269
+ `;
2270
+ function equationPanel(options) {
2271
+ injectStyle("bb-ui-tabs", TABS_CSS);
2272
+ injectStyle("bb-ui-eqp-styles", STYLE10);
2273
+ const root = document.createElement("div");
2274
+ root.className = "bb-eqp";
2275
+ root.setAttribute("role", "group");
2276
+ root.setAttribute("aria-label", "Equation palette");
2277
+ root.addEventListener("mousedown", (e) => e.preventDefault());
2278
+ const strip = document.createElement("div");
2279
+ strip.className = "bb-eqp-tabs";
2280
+ const tabs = document.createElement("div");
2281
+ tabs.className = "bb-tabs";
2282
+ tabs.setAttribute("role", "tablist");
2283
+ strip.append(tabs);
2284
+ const body = document.createElement("div");
2285
+ body.className = "bb-eqp-body";
2286
+ let current3 = "symbols";
2287
+ const tabEls = {};
2288
+ const mkTab = (id, label) => {
2289
+ const b = document.createElement("button");
2290
+ b.type = "button";
2291
+ b.className = "bb-tab";
2292
+ b.textContent = label;
2293
+ b.setAttribute("role", "tab");
2294
+ b.addEventListener("click", () => {
2295
+ current3 = id;
2296
+ render();
2297
+ });
2298
+ tabEls[id] = b;
2299
+ tabs.append(b);
2300
+ };
2301
+ mkTab("symbols", "Symbols");
2302
+ mkTab("structures", "Structures");
2303
+ root.append(strip, body);
2304
+ function symbolsBody() {
2305
+ const set = document.createElement("select");
2306
+ set.className = "bb-eqp-set";
2307
+ set.setAttribute("aria-label", "Symbol set");
2308
+ for (const [i, s] of MATH_SYMBOL_SETS.entries()) {
2309
+ const o = document.createElement("option");
2310
+ o.value = String(i);
2311
+ o.textContent = s.name;
2312
+ set.append(o);
2313
+ }
2314
+ set.value = String(setIndex);
2315
+ const grid = document.createElement("div");
2316
+ grid.className = "bb-eqp-grid";
2317
+ const hint = document.createElement("div");
2318
+ hint.className = "bb-eqp-hint";
2319
+ const hintG = document.createElement("span");
2320
+ hintG.className = "bb-eqp-hint-g";
2321
+ const hintK = document.createElement("span");
2322
+ hintK.className = "bb-eqp-hint-k";
2323
+ hint.append(hintG, hintK);
2324
+ const fill = () => {
2325
+ grid.replaceChildren();
2326
+ const chars = MATH_SYMBOL_SETS[setIndex]?.chars ?? "";
2327
+ for (const ch of chars) {
2328
+ const b = document.createElement("button");
2329
+ b.type = "button";
2330
+ b.className = "bb-eqp-sym";
2331
+ b.textContent = ch;
2332
+ const key = SHORTHAND.get(ch);
2333
+ b.title = key ? `${ch} ${key}` : ch;
2334
+ b.addEventListener("mouseenter", () => {
2335
+ hintG.textContent = ch;
2336
+ hintK.textContent = key ?? "";
2337
+ });
2338
+ b.addEventListener("click", () => options.onSymbol(ch));
2339
+ grid.append(b);
2340
+ }
2341
+ };
2342
+ set.addEventListener("change", () => {
2343
+ setIndex = Number(set.value) || 0;
2344
+ fill();
2345
+ });
2346
+ fill();
2347
+ body.replaceChildren(set, grid, hint);
2348
+ }
2349
+ function structuresBody() {
2350
+ const scroll = document.createElement("div");
2351
+ scroll.className = "bb-eqp-scroll";
2352
+ for (const group of eqStructureGroups()) {
2353
+ const h = document.createElement("div");
2354
+ h.className = "bb-eqp-group";
2355
+ h.textContent = group.name;
2356
+ const row = document.createElement("div");
2357
+ row.className = "bb-eqp-row";
2358
+ for (const item of group.items) {
2359
+ const b = document.createElement("button");
2360
+ b.type = "button";
2361
+ b.className = "bb-eqp-st";
2362
+ b.title = `${group.name} \u2014 ${item.name}`;
2363
+ const spec = options.layout?.([item.node], PREVIEW_PT2) ?? null;
2364
+ if (spec && spec.ops.length)
2365
+ b.append(equationPreviewSvg(spec, { maxWidth: 60 }));
2366
+ const name = document.createElement("span");
2367
+ name.className = "bb-eqp-st-name";
2368
+ name.textContent = item.name;
2369
+ b.append(name);
2370
+ b.addEventListener("click", () => options.onStructure(item));
2371
+ row.append(b);
2372
+ }
2373
+ scroll.append(h, row);
2374
+ }
2375
+ body.replaceChildren(scroll);
2376
+ }
2377
+ let setIndex = 0;
2378
+ function render() {
2379
+ for (const [id, el5] of Object.entries(tabEls))
2380
+ el5.setAttribute("aria-selected", String(id === current3));
2381
+ if (current3 === "symbols") symbolsBody();
2382
+ else structuresBody();
2383
+ }
2384
+ render();
2385
+ return {
2386
+ el: root,
2387
+ destroy() {
2388
+ root.remove();
2389
+ }
2390
+ };
2391
+ }
2392
+
2393
+ // packages/ui/src/lib/table-grid.ts
2394
+ var STYLE11 = `
1938
2395
  .bb-grid{display:flex;flex-direction:column;gap:6px;user-select:none}
1939
2396
  .bb-grid-cells{display:grid;gap:2px}
1940
2397
  .bb-grid-cell{width:15px;height:15px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:2px;background:var(--bb-ui-bg,#fff);cursor:pointer;padding:0}
@@ -1942,7 +2399,7 @@ var STYLE9 = `
1942
2399
  .bb-grid-label{font-size:12px;text-align:center;opacity:.7}
1943
2400
  `;
1944
2401
  function tableGridPicker(options) {
1945
- injectStyle("bb-ui-grid-styles", STYLE9);
2402
+ injectStyle("bb-ui-grid-styles", STYLE11);
1946
2403
  const maxRows = options.maxRows ?? 8;
1947
2404
  const maxCols = options.maxCols ?? 10;
1948
2405
  const root = document.createElement("div");
@@ -1954,22 +2411,22 @@ function tableGridPicker(options) {
1954
2411
  label.className = "bb-grid-label";
1955
2412
  label.textContent = "0 \xD7 0";
1956
2413
  const cells = [];
1957
- const highlight2 = (r, c) => {
2414
+ const highlight2 = (r, c2) => {
1958
2415
  for (let i = 0; i < cells.length; i++) {
1959
2416
  const row = Math.floor(i / maxCols);
1960
2417
  const col = i % maxCols;
1961
- cells[i].classList.toggle("on", row <= r && col <= c);
2418
+ cells[i].classList.toggle("on", row <= r && col <= c2);
1962
2419
  }
1963
- label.textContent = `${r + 1} \xD7 ${c + 1}`;
2420
+ label.textContent = `${r + 1} \xD7 ${c2 + 1}`;
1964
2421
  };
1965
2422
  for (let r = 0; r < maxRows; r++) {
1966
- for (let c = 0; c < maxCols; c++) {
2423
+ for (let c2 = 0; c2 < maxCols; c2++) {
1967
2424
  const cell = document.createElement("button");
1968
2425
  cell.type = "button";
1969
2426
  cell.className = "bb-grid-cell";
1970
2427
  cell.addEventListener("mousedown", (e) => e.preventDefault());
1971
- cell.addEventListener("mouseenter", () => highlight2(r, c));
1972
- cell.addEventListener("click", () => options.onPick(r + 1, c + 1));
2428
+ cell.addEventListener("mouseenter", () => highlight2(r, c2));
2429
+ cell.addEventListener("click", () => options.onPick(r + 1, c2 + 1));
1973
2430
  cells.push(cell);
1974
2431
  cellsEl.appendChild(cell);
1975
2432
  }
@@ -1978,6 +2435,178 @@ function tableGridPicker(options) {
1978
2435
  return root;
1979
2436
  }
1980
2437
 
2438
+ // packages/ui/src/lib/table-style-panel.ts
2439
+ import {
2440
+ cellStyleLayer
2441
+ } from "@shadow-garden/bapbong-contracts";
2442
+ var GATES = [
2443
+ { key: "firstRow", label: "Header row" },
2444
+ { key: "lastRow", label: "Total row" },
2445
+ { key: "hBand", label: "Banded rows" },
2446
+ { key: "firstCol", label: "First column" },
2447
+ { key: "lastCol", label: "Last column" },
2448
+ { key: "vBand", label: "Banded columns" }
2449
+ ];
2450
+ var THUMB_ROWS = 4;
2451
+ var THUMB_COLS = 5;
2452
+ var STYLE12 = `
2453
+ .bb-tsp{display:flex;gap:16px;width:432px;max-width:100%;color:var(--bb-ui-fg,#2c2c2a)}
2454
+ .bb-tsp *{box-sizing:border-box}
2455
+ .bb-tsp-opts{flex:0 0 128px;display:flex;flex-direction:column;gap:2px}
2456
+ .bb-tsp-lbl{font-size:12px;opacity:.7;margin-bottom:4px}
2457
+ .bb-tsp-chk{display:flex;align-items:center;gap:7px;font-size:13px;padding:3px 0;cursor:pointer}
2458
+ .bb-tsp-chk input{margin:0}
2459
+ .bb-tsp-chk.is-disabled{opacity:.4;cursor:default}
2460
+ .bb-tsp-sep{height:1px;margin:6px 0;background:var(--bb-ui-border,#e3e3e0)}
2461
+ .bb-tsp-main{flex:1;display:flex;flex-direction:column;gap:8px;min-width:0}
2462
+ .bb-tsp-gallery{display:flex;flex-wrap:wrap;gap:6px}
2463
+ .bb-tsp-tile{padding:3px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));cursor:pointer;line-height:0}
2464
+ .bb-tsp-tile:hover{border-color:var(--bb-ui-fg,#2c2c2a)}
2465
+ .bb-tsp-tile.is-selected{padding:2px;border:2px solid var(--bb-ui-active-fg,#0c447c)}
2466
+ .bb-tsp-thumb{display:grid;grid-template-columns:repeat(${THUMB_COLS},12px);grid-auto-rows:8px;gap:0}
2467
+ .bb-tsp-none{display:flex;align-items:center;justify-content:center;width:60px;height:32px;font-size:11px;opacity:.7;line-height:1.1}
2468
+ .bb-tsp-empty{font-size:13px;opacity:.65;padding:8px 0}
2469
+ `;
2470
+ function edgeCss(side) {
2471
+ if (!side) return "none";
2472
+ return `1px ${side.style === "double" ? "double" : "solid"} ${side.color}`;
2473
+ }
2474
+ function thumbnail(style, look) {
2475
+ const grid = document.createElement("div");
2476
+ grid.className = "bb-tsp-thumb";
2477
+ const t = style.table.borders ?? {};
2478
+ for (let r = 0; r < THUMB_ROWS; r++) {
2479
+ for (let c2 = 0; c2 < THUMB_COLS; c2++) {
2480
+ const layer = cellStyleLayer(style, look, {
2481
+ row: r,
2482
+ rowCount: THUMB_ROWS,
2483
+ col: c2,
2484
+ colspan: 1,
2485
+ colCount: THUMB_COLS,
2486
+ header: false
2487
+ });
2488
+ const cell = document.createElement("div");
2489
+ const b = layer.borders ?? {};
2490
+ cell.style.borderTop = edgeCss(b.top ?? (r === 0 ? t.top : t.insideH));
2491
+ cell.style.borderBottom = edgeCss(
2492
+ b.bottom ?? (r === THUMB_ROWS - 1 ? t.bottom : void 0)
2493
+ );
2494
+ cell.style.borderLeft = edgeCss(b.left ?? (c2 === 0 ? t.left : t.insideV));
2495
+ cell.style.borderRight = edgeCss(
2496
+ b.right ?? (c2 === THUMB_COLS - 1 ? t.right : void 0)
2497
+ );
2498
+ if (layer.background) cell.style.background = layer.background;
2499
+ grid.appendChild(cell);
2500
+ }
2501
+ }
2502
+ return grid;
2503
+ }
2504
+ function createTableStylePanel(options) {
2505
+ injectStyle("bb-table-style-panel", STYLE12);
2506
+ const root = document.createElement("div");
2507
+ root.className = "bb-tsp";
2508
+ const opts = document.createElement("div");
2509
+ opts.className = "bb-tsp-opts";
2510
+ const optsLbl = document.createElement("div");
2511
+ optsLbl.className = "bb-tsp-lbl";
2512
+ optsLbl.textContent = "Style options";
2513
+ opts.appendChild(optsLbl);
2514
+ const checks = /* @__PURE__ */ new Map();
2515
+ GATES.forEach((g2, i) => {
2516
+ if (i === 3) {
2517
+ const sep = document.createElement("div");
2518
+ sep.className = "bb-tsp-sep";
2519
+ opts.appendChild(sep);
2520
+ }
2521
+ const label = document.createElement("label");
2522
+ label.className = "bb-tsp-chk";
2523
+ const input = document.createElement("input");
2524
+ input.type = "checkbox";
2525
+ input.addEventListener(
2526
+ "change",
2527
+ () => options.onLook({ [g2.key]: input.checked })
2528
+ );
2529
+ label.append(input, document.createTextNode(g2.label));
2530
+ opts.appendChild(label);
2531
+ checks.set(g2.key, input);
2532
+ });
2533
+ const main = document.createElement("div");
2534
+ main.className = "bb-tsp-main";
2535
+ const mainLbl = document.createElement("div");
2536
+ mainLbl.className = "bb-tsp-lbl";
2537
+ mainLbl.textContent = "Table styles";
2538
+ const gallery = document.createElement("div");
2539
+ gallery.className = "bb-tsp-gallery";
2540
+ main.append(mainLbl, gallery);
2541
+ root.append(opts, main);
2542
+ const dialog = new Dialog({
2543
+ title: "Table style",
2544
+ modal: false,
2545
+ anchor: options.anchor
2546
+ });
2547
+ dialog.setContent(root);
2548
+ let drawnKey = "";
2549
+ const draw = () => {
2550
+ const current3 = options.current();
2551
+ const items = options.styles();
2552
+ const key = JSON.stringify([current3, items.map((i) => i.id)]);
2553
+ if (key === drawnKey) return;
2554
+ drawnKey = key;
2555
+ const look = current3?.look ?? null;
2556
+ for (const [gate, input] of checks) {
2557
+ input.checked = look?.[gate] ?? false;
2558
+ input.disabled = !current3;
2559
+ input.closest("label")?.classList.toggle("is-disabled", !current3);
2560
+ }
2561
+ gallery.replaceChildren();
2562
+ if (!current3) {
2563
+ const empty = document.createElement("div");
2564
+ empty.className = "bb-tsp-empty";
2565
+ empty.textContent = "Click inside a table to style it.";
2566
+ gallery.appendChild(empty);
2567
+ return;
2568
+ }
2569
+ const noneTile = document.createElement("button");
2570
+ noneTile.type = "button";
2571
+ noneTile.className = "bb-tsp-tile" + (current3.styleId === null ? " is-selected" : "");
2572
+ noneTile.title = "None";
2573
+ const noneInner = document.createElement("span");
2574
+ noneInner.className = "bb-tsp-none";
2575
+ noneInner.textContent = "None";
2576
+ noneTile.appendChild(noneInner);
2577
+ noneTile.addEventListener("click", () => options.onPick(null));
2578
+ gallery.appendChild(noneTile);
2579
+ for (const item of items) {
2580
+ const tile = document.createElement("button");
2581
+ tile.type = "button";
2582
+ tile.className = "bb-tsp-tile" + (current3.styleId === item.id ? " is-selected" : "");
2583
+ tile.title = item.name;
2584
+ tile.appendChild(thumbnail(item.style, current3.look));
2585
+ tile.addEventListener("click", () => options.onPick(item));
2586
+ gallery.appendChild(tile);
2587
+ }
2588
+ };
2589
+ return {
2590
+ open() {
2591
+ drawnKey = "";
2592
+ draw();
2593
+ dialog.open();
2594
+ },
2595
+ close() {
2596
+ dialog.close();
2597
+ },
2598
+ refresh() {
2599
+ if (dialog.isOpen) draw();
2600
+ },
2601
+ destroy() {
2602
+ dialog.destroy();
2603
+ },
2604
+ get isOpen() {
2605
+ return dialog.isOpen;
2606
+ }
2607
+ };
2608
+ }
2609
+
1981
2610
  // packages/ui/src/lib/page-setup.ts
1982
2611
  var PX_PER_CM = 96 / 2.54;
1983
2612
  var pxToCm = (px) => px / PX_PER_CM;
@@ -1985,7 +2614,7 @@ var cmToPx = (cm) => Math.round(cm * PX_PER_CM);
1985
2614
  function fmtCm(cm) {
1986
2615
  return `${Number(cm.toFixed(3))} cm`;
1987
2616
  }
1988
- var STYLE10 = `
2617
+ var STYLE13 = `
1989
2618
  .bb-ps{display:flex;flex-direction:column;min-width:250px;max-height:min(70vh,460px);overflow-y:auto}
1990
2619
  .bb-ps,.bb-ps *{box-sizing:border-box}
1991
2620
  .bb-ps-row{display:flex;align-items:center;gap:11px;width:100%;padding:7px 10px;border:0;border-radius:6px;background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}
@@ -2015,9 +2644,9 @@ var STYLE10 = `
2015
2644
  .bb-ps-tile:hover,.bb-ps-tile:focus{background:var(--bb-ui-hover,#f1efe8);outline:none}
2016
2645
  .bb-ps-tile[aria-checked="true"]{background:var(--bb-ui-active-bg,#e6f1fb)}
2017
2646
  `;
2018
- var SVG_NS = "http://www.w3.org/2000/svg";
2647
+ var SVG_NS2 = "http://www.w3.org/2000/svg";
2019
2648
  function svgEl(name, attrs) {
2020
- const el5 = document.createElementNS(SVG_NS, name);
2649
+ const el5 = document.createElementNS(SVG_NS2, name);
2021
2650
  for (const [k, v] of Object.entries(attrs)) el5.setAttribute(k, String(v));
2022
2651
  return el5;
2023
2652
  }
@@ -2111,7 +2740,7 @@ function customRow(icon, title, description, onPick) {
2111
2740
  return presetRow(icon, title, captionLine(description), false, onPick);
2112
2741
  }
2113
2742
  function pageSizePicker(options) {
2114
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2743
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2115
2744
  const root = document.createElement("div");
2116
2745
  root.className = "bb-ps";
2117
2746
  root.setAttribute("role", "menu");
@@ -2140,7 +2769,7 @@ function pageSizePicker(options) {
2140
2769
  return root;
2141
2770
  }
2142
2771
  function orientationPicker(options) {
2143
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2772
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2144
2773
  const root = document.createElement("div");
2145
2774
  root.className = "bb-ps";
2146
2775
  root.setAttribute("role", "menu");
@@ -2163,7 +2792,7 @@ function orientationPicker(options) {
2163
2792
  return root;
2164
2793
  }
2165
2794
  function marginPresetPicker(options) {
2166
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2795
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2167
2796
  const root = document.createElement("div");
2168
2797
  root.className = "bb-ps";
2169
2798
  root.setAttribute("role", "menu");
@@ -2238,7 +2867,7 @@ function readPx(input, fallbackPx) {
2238
2867
  return Number.isFinite(n) && n > 0 ? cmToPx(n) : fallbackPx;
2239
2868
  }
2240
2869
  function openPageSizeDialog(options) {
2241
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2870
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2242
2871
  const dialog = new Dialog({ title: "Paper size", modal: true });
2243
2872
  const form = document.createElement("form");
2244
2873
  form.className = "bb-pd";
@@ -2265,7 +2894,7 @@ function openPageSizeDialog(options) {
2265
2894
  width.input.select();
2266
2895
  }
2267
2896
  function openMarginsDialog(options) {
2268
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2897
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2269
2898
  const dialog = new Dialog({ title: "Margins", modal: true });
2270
2899
  const form = document.createElement("form");
2271
2900
  form.className = "bb-pd";
@@ -2322,7 +2951,7 @@ var PGNUM_FORMATS = [
2322
2951
  ["upperLetter", "A, B, C, D\u2026", "A"]
2323
2952
  ];
2324
2953
  function pageNumberPicker(options) {
2325
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2954
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2326
2955
  const root = document.createElement("div");
2327
2956
  root.className = "bb-ps";
2328
2957
  root.setAttribute("role", "menu");
@@ -2423,7 +3052,7 @@ function pageNumberPicker(options) {
2423
3052
  return root;
2424
3053
  }
2425
3054
  function sectionPaperPanel(options) {
2426
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
3055
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2427
3056
  const root = document.createElement("div");
2428
3057
  root.className = "bb-ps";
2429
3058
  root.setAttribute("role", "menu");
@@ -2492,7 +3121,7 @@ function sectionPaperPanel(options) {
2492
3121
  }
2493
3122
 
2494
3123
  // packages/ui/src/lib/section-chip.ts
2495
- var STYLE11 = `
3124
+ var STYLE14 = `
2496
3125
  .bb-secchip{position:absolute;z-index:8;display:inline-flex;align-items:center;transform:translate(-50%,-50%);white-space:nowrap;background:var(--bb-ui-menu-bg,#fff);-webkit-backdrop-filter:var(--bb-ui-pop-filter,none);backdrop-filter:var(--bb-ui-pop-filter,none);border:1px solid var(--bb-ui-pop-border,var(--bb-ui-border,#e3e3e0));border-radius:10px;padding:1px 2px;box-shadow:0 2px 10px rgba(0,0,0,.12);font-family:var(--bb-ui-font,system-ui,-apple-system,sans-serif);font-size:11px;color:var(--bb-ui-fg,#2c2c2a)}
2497
3126
  .bb-secchip *{box-sizing:border-box}
2498
3127
  .bb-secchip-title{padding:0 7px;font-size:11px;font-weight:600;opacity:.8}
@@ -2505,7 +3134,7 @@ var STYLE11 = `
2505
3134
  .bb-secchip-x:hover{background:var(--bb-ui-hover,#f1efe8);opacity:1}
2506
3135
  `;
2507
3136
  function createSectionChip(options) {
2508
- injectStyle("bb-ui-section-chip-styles", STYLE11);
3137
+ injectStyle("bb-ui-section-chip-styles", STYLE14);
2509
3138
  const el5 = document.createElement("div");
2510
3139
  el5.className = "bb-secchip";
2511
3140
  const title = document.createElement("span");
@@ -2562,17 +3191,13 @@ var halfToPt = (hp) => hp / 2;
2562
3191
  var ptToHalf = (pt) => Math.round(pt * 2);
2563
3192
  var SCALE_PRESETS = [200, 150, 100, 90, 80, 66, 50, 33];
2564
3193
  var SUPERSUB_SCALE = 0.66;
2565
- var STYLE12 = `
3194
+ var STYLE15 = `
2566
3195
  .bb-fd{display:flex;flex-direction:column;gap:15px;min-width:396px;max-width:430px;color:var(--bb-ui-fg,#2c2c2a)}
2567
3196
  .bb-fd *{box-sizing:border-box}
2568
3197
  /* A segmented control, not a "tab joined to its pane": that pattern needs the
2569
3198
  active tab's background to equal the pane's, and this dialog floats on
2570
3199
  frosted glass whose colour the widget cannot know. Same shape cell-properties
2571
3200
  already uses, so the two dialogs read as one product. */
2572
- .bb-fd-tabs{display:inline-flex;border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;overflow:hidden;align-self:flex-start}
2573
- .bb-fd-tab{height:30px;padding:0 18px;border:0;border-right:0.5px solid var(--bb-ui-border,#e3e3e0);background:transparent;color:inherit;opacity:.65;font:inherit;font-size:13px;cursor:pointer}
2574
- .bb-fd-tab:last-child{border-right:0}
2575
- .bb-fd-tab[aria-selected="true"]{background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c);opacity:1}
2576
3201
  .bb-fd-pane{display:flex;flex-direction:column;gap:13px}
2577
3202
  /* A class-level display beats the UA's [hidden]{display:none}; without this
2578
3203
  both tabs render at once. */
@@ -2644,13 +3269,14 @@ function openFontDialog({
2644
3269
  sizes,
2645
3270
  onApply
2646
3271
  }) {
2647
- injectStyle("bb-font-dialog", STYLE12);
3272
+ injectStyle("bb-ui-tabs", TABS_CSS);
3273
+ injectStyle("bb-font-dialog", STYLE15);
2648
3274
  const dialog = new Dialog({ title: "Font", modal: true });
2649
3275
  const root = el("div", "bb-fd");
2650
- const tabs = el("div", "bb-fd-tabs");
3276
+ const tabs = el("div", "bb-tabs");
2651
3277
  tabs.setAttribute("role", "tablist");
2652
- const fontTab = el("button", "bb-fd-tab", "Font");
2653
- const advTab = el("button", "bb-fd-tab", "Advanced");
3278
+ const fontTab = el("button", "bb-tab", "Font");
3279
+ const advTab = el("button", "bb-tab", "Advanced");
2654
3280
  for (const t of [fontTab, advTab]) {
2655
3281
  t.type = "button";
2656
3282
  t.setAttribute("role", "tab");
@@ -2708,8 +3334,8 @@ function openFontDialog({
2708
3334
  label: "Text color",
2709
3335
  clearLabel: "Automatic",
2710
3336
  value: () => color,
2711
- onPick: (c) => {
2712
- color = c;
3337
+ onPick: (c2) => {
3338
+ color = c2;
2713
3339
  paint();
2714
3340
  }
2715
3341
  });
@@ -2718,8 +3344,8 @@ function openFontDialog({
2718
3344
  label: "Highlight",
2719
3345
  clearLabel: "No highlight",
2720
3346
  value: () => highlight2,
2721
- onPick: (c) => {
2722
- highlight2 = c;
3347
+ onPick: (c2) => {
3348
+ highlight2 = c2;
2723
3349
  paint();
2724
3350
  }
2725
3351
  });
@@ -2844,8 +3470,8 @@ function openFontDialog({
2844
3470
  s.transform = scale === 100 ? "none" : `scaleX(${scale / 100})`;
2845
3471
  s.verticalAlign = supCb.checked ? "super" : subCb.checked ? "sub" : `${positionPt}pt`;
2846
3472
  }
2847
- for (const c of [familySel, sizeSel, scaleSel])
2848
- c.addEventListener("change", paint);
3473
+ for (const c2 of [familySel, sizeSel, scaleSel])
3474
+ c2.addEventListener("change", paint);
2849
3475
  for (const i of [spacingInput, positionInput])
2850
3476
  i.addEventListener("input", paint);
2851
3477
  const foot = el("div", "bb-fd-foot");
@@ -3266,7 +3892,7 @@ function parseCodePoint(input) {
3266
3892
  }
3267
3893
  var RECENT_MAX = 16;
3268
3894
  function pushRecent(recent, char, max = RECENT_MAX) {
3269
- return [char, ...recent.filter((c) => c !== char)].slice(0, max);
3895
+ return [char, ...recent.filter((c2) => c2 !== char)].slice(0, max);
3270
3896
  }
3271
3897
  function searchSymbols(query) {
3272
3898
  const q = query.trim().toLowerCase();
@@ -3286,7 +3912,7 @@ function searchSymbols(query) {
3286
3912
  }
3287
3913
 
3288
3914
  // packages/ui/src/lib/symbol-dialog.ts
3289
- var STYLE13 = `
3915
+ var STYLE16 = `
3290
3916
  .bb-sd{display:flex;flex-direction:column;gap:12px;width:412px;max-width:100%;color:var(--bb-ui-fg,#2c2c2a)}
3291
3917
  .bb-sd *{box-sizing:border-box}
3292
3918
  .bb-sd-tabs{display:inline-flex;border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;overflow:hidden;align-self:flex-start}
@@ -3347,7 +3973,7 @@ function glyphFor(char) {
3347
3973
  return char;
3348
3974
  }
3349
3975
  function createSymbolDialog(options) {
3350
- injectStyle("bb-symbol-dialog", STYLE13);
3976
+ injectStyle("bb-symbol-dialog", STYLE16);
3351
3977
  let recent = [...options.recent ?? []].slice(0, RECENT_MAX);
3352
3978
  let selected = null;
3353
3979
  const root = el2("div", "bb-sd");
@@ -3536,9 +4162,9 @@ function createSymbolDialog(options) {
3536
4162
  function renderRecent() {
3537
4163
  fillGrid(
3538
4164
  recentGrid,
3539
- recent.map((c) => ({
3540
- char: c,
3541
- name: SYMBOL_NAMES.get(c) ?? "Character"
4165
+ recent.map((c2) => ({
4166
+ char: c2,
4167
+ name: SYMBOL_NAMES.get(c2) ?? "Character"
3542
4168
  })),
3543
4169
  RECENT_COLS,
3544
4170
  "Nothing yet \u2014 inserted symbols appear here."
@@ -3582,7 +4208,7 @@ function createSymbolDialog(options) {
3582
4208
  code.removeAttribute("aria-invalid");
3583
4209
  const cell = Array.from(
3584
4210
  grid.querySelectorAll(".bb-sd-cell")
3585
- ).find((c) => c.textContent === glyphFor(ch));
4211
+ ).find((c2) => c2.textContent === glyphFor(ch));
3586
4212
  select2(ch, cell ?? null);
3587
4213
  } else {
3588
4214
  code.setAttribute("aria-invalid", code.value.trim() ? "true" : "false");
@@ -3625,7 +4251,7 @@ function createSymbolDialog(options) {
3625
4251
  }
3626
4252
 
3627
4253
  // packages/ui/src/lib/symbol-popover.ts
3628
- var STYLE14 = `
4254
+ var STYLE17 = `
3629
4255
  .bb-spk{position:fixed;margin:0;max-width:none;max-height:none;z-index:1300;width:276px;padding:10px;background:var(--bb-ui-menu-bg,#fff);-webkit-backdrop-filter:var(--bb-ui-pop-filter,none);backdrop-filter:var(--bb-ui-pop-filter,none);color:var(--bb-ui-fg,#2c2c2a);border:1px solid var(--bb-ui-pop-border,var(--bb-ui-border,#e3e3e0));border-radius:10px;box-shadow:0 8px 28px rgba(0,0,0,.16);font-family:var(--bb-ui-font,system-ui,-apple-system,sans-serif);font-size:12px;box-sizing:border-box;display:flex;flex-direction:column;gap:8px}
3630
4256
  .bb-spk *{box-sizing:border-box}
3631
4257
  .bb-spk::backdrop{background:transparent}
@@ -3658,7 +4284,7 @@ function el3(tag, cls, text) {
3658
4284
  return n;
3659
4285
  }
3660
4286
  function openSymbolPopover(options) {
3661
- injectStyle("bb-ui-symbol-popover", STYLE14);
4287
+ injectStyle("bb-ui-symbol-popover", STYLE17);
3662
4288
  const { anchor } = options;
3663
4289
  let recent = [...options.recent ?? []].slice(0, RECENT_MAX);
3664
4290
  let groupId = SYMBOL_GROUPS[0].id;
@@ -3689,16 +4315,16 @@ function openSymbolPopover(options) {
3689
4315
  const chips = el3("div", "bb-spk-chips");
3690
4316
  const chipEls = /* @__PURE__ */ new Map();
3691
4317
  for (const grp of SYMBOL_GROUPS) {
3692
- const c = el3("button", "bb-spk-chip", grp.short);
3693
- c.type = "button";
3694
- c.title = grp.label;
3695
- c.addEventListener("click", () => {
4318
+ const c2 = el3("button", "bb-spk-chip", grp.short);
4319
+ c2.type = "button";
4320
+ c2.title = grp.label;
4321
+ c2.addEventListener("click", () => {
3696
4322
  groupId = grp.id;
3697
4323
  search.value = "";
3698
4324
  render();
3699
4325
  });
3700
- chips.append(c);
3701
- chipEls.set(grp.id, c);
4326
+ chips.append(c2);
4327
+ chipEls.set(grp.id, c2);
3702
4328
  }
3703
4329
  const grid = el3("div", "bb-spk-grid");
3704
4330
  grid.setAttribute("role", "grid");
@@ -3769,9 +4395,9 @@ function openSymbolPopover(options) {
3769
4395
  };
3770
4396
  const renderRecent = () => fill(
3771
4397
  recentGrid,
3772
- recent.slice(0, RECENT_ROW).map((c) => ({
3773
- char: c,
3774
- name: SYMBOL_NAMES.get(c) ?? "Character"
4398
+ recent.slice(0, RECENT_ROW).map((c2) => ({
4399
+ char: c2,
4400
+ name: SYMBOL_NAMES.get(c2) ?? "Character"
3775
4401
  })),
3776
4402
  "Nothing yet."
3777
4403
  );
@@ -3779,8 +4405,8 @@ function openSymbolPopover(options) {
3779
4405
  const q = search.value.trim();
3780
4406
  const byCode = q ? parseCodePoint(q) : null;
3781
4407
  const entries = q ? byCode && !searchSymbols(q).length ? [{ char: byCode, name: SYMBOL_NAMES.get(byCode) ?? "Character" }] : searchSymbols(q) : SYMBOL_GROUPS.find((g2) => g2.id === groupId)?.entries ?? [];
3782
- for (const [id, c] of chipEls)
3783
- c.setAttribute("aria-pressed", String(!q && id === groupId));
4408
+ for (const [id, c2] of chipEls)
4409
+ c2.setAttribute("aria-pressed", String(!q && id === groupId));
3784
4410
  fill(grid, entries, "No match.");
3785
4411
  const first = grid.querySelector(".bb-spk-cell");
3786
4412
  if (q && first && entries[0]) select2(entries[0].char, first);
@@ -3824,7 +4450,7 @@ import {
3824
4450
  formatKey,
3825
4451
  keybindingRows
3826
4452
  } from "@shadow-garden/bapbong-contracts";
3827
- var STYLE15 = `
4453
+ var STYLE18 = `
3828
4454
  .bb-ks{display:flex;flex-direction:column;gap:10px;width:600px;max-width:100%;color:var(--bb-ui-fg,#2c2c2a);font-size:12px}
3829
4455
  .bb-ks *{box-sizing:border-box}
3830
4456
  .bb-ks-top{display:flex;gap:8px;align-items:center}
@@ -3882,7 +4508,7 @@ function highlight(text, q) {
3882
4508
  return out;
3883
4509
  }
3884
4510
  function openKeyboardShortcutsDialog(options) {
3885
- injectStyle("bb-ui-shortcuts-dialog", STYLE15);
4511
+ injectStyle("bb-ui-shortcuts-dialog", STYLE18);
3886
4512
  const dialog = new Dialog({
3887
4513
  title: options.title ?? "Keyboard shortcuts",
3888
4514
  modal: true,
@@ -3909,19 +4535,19 @@ function openKeyboardShortcutsDialog(options) {
3909
4535
  let sortKey = "title";
3910
4536
  let sortAsc = true;
3911
4537
  const ths = /* @__PURE__ */ new Map();
3912
- for (const c of columns) {
4538
+ for (const c2 of columns) {
3913
4539
  const th = el4("th");
3914
- th.append(el4("span", void 0, c.label));
4540
+ th.append(el4("span", void 0, c2.label));
3915
4541
  th.addEventListener("click", () => {
3916
- if (sortKey === c.key) sortAsc = !sortAsc;
4542
+ if (sortKey === c2.key) sortAsc = !sortAsc;
3917
4543
  else {
3918
- sortKey = c.key;
4544
+ sortKey = c2.key;
3919
4545
  sortAsc = true;
3920
4546
  }
3921
4547
  render();
3922
4548
  });
3923
4549
  headRow.append(th);
3924
- ths.set(c.key, th);
4550
+ ths.set(c2.key, th);
3925
4551
  }
3926
4552
  thead.append(headRow);
3927
4553
  const tbody = el4("tbody");
@@ -3941,7 +4567,7 @@ function openKeyboardShortcutsDialog(options) {
3941
4567
  const rows = [];
3942
4568
  for (const src of options.sources)
3943
4569
  rows.push(
3944
- ...keybindingRows(src.keybindings, (c) => src.commands.get(c)?.title)
4570
+ ...keybindingRows(src.keybindings, (c2) => src.commands.get(c2)?.title)
3945
4571
  );
3946
4572
  return rows;
3947
4573
  };
@@ -3998,7 +4624,7 @@ function openKeyboardShortcutsDialog(options) {
3998
4624
  tbody.append(tr);
3999
4625
  }
4000
4626
  count.textContent = shown.length === rows.length ? `${rows.length} shortcuts` : `${shown.length} of ${rows.length}`;
4001
- footL.textContent = `Sorted by ${columns.find((c) => c.key === sortKey)?.label.toLowerCase()} \xB7 click a header to sort`;
4627
+ footL.textContent = `Sorted by ${columns.find((c2) => c2.key === sortKey)?.label.toLowerCase()} \xB7 click a header to sort`;
4002
4628
  };
4003
4629
  search.addEventListener("input", render);
4004
4630
  dialog.onClose(() => dialog.destroy());
@@ -4008,7 +4634,7 @@ function openKeyboardShortcutsDialog(options) {
4008
4634
  }
4009
4635
 
4010
4636
  // packages/ui/src/lib/scrollbars.ts
4011
- var STYLE16 = `
4637
+ var STYLE19 = `
4012
4638
  @property --bb-scroll-thumb-now {
4013
4639
  syntax: '<color>';
4014
4640
  /* MUST inherit: the thumb pseudo-element never matches .bb-scrolling
@@ -4040,7 +4666,7 @@ var STYLE16 = `
4040
4666
  var installed = null;
4041
4667
  function installScrollbars(root = document) {
4042
4668
  if (installed) return installed;
4043
- injectStyle("bb-ui-scrollbars", STYLE16);
4669
+ injectStyle("bb-ui-scrollbars", STYLE19);
4044
4670
  const quiet = /* @__PURE__ */ new WeakMap();
4045
4671
  const onScroll = (ev) => {
4046
4672
  const el5 = ev.target instanceof HTMLElement ? ev.target : root.documentElement;
@@ -4059,6 +4685,7 @@ function installScrollbars(root = document) {
4059
4685
  return installed;
4060
4686
  }
4061
4687
  export {
4688
+ BUILT_IN_EQUATIONS,
4062
4689
  COLOR_PALETTE,
4063
4690
  Dialog,
4064
4691
  RECENT_MAX,
@@ -4071,8 +4698,13 @@ export {
4071
4698
  createFindDialog,
4072
4699
  createSectionChip,
4073
4700
  createSymbolDialog,
4701
+ createTableStylePanel,
4074
4702
  defaultMenus,
4075
4703
  defaultToolbarGroups,
4704
+ equationGallery,
4705
+ equationPanel,
4706
+ equationPreviewSvg,
4707
+ foldPlan,
4076
4708
  installScrollbars,
4077
4709
  marginPresetPicker,
4078
4710
  mountMenubar,