@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.cjs CHANGED
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // packages/ui/src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ BUILT_IN_EQUATIONS: () => BUILT_IN_EQUATIONS,
23
24
  COLOR_PALETTE: () => COLOR_PALETTE,
24
25
  Dialog: () => Dialog,
25
26
  RECENT_MAX: () => RECENT_MAX,
@@ -32,8 +33,13 @@ __export(index_exports, {
32
33
  createFindDialog: () => createFindDialog,
33
34
  createSectionChip: () => createSectionChip,
34
35
  createSymbolDialog: () => createSymbolDialog,
36
+ createTableStylePanel: () => createTableStylePanel,
35
37
  defaultMenus: () => defaultMenus,
36
38
  defaultToolbarGroups: () => defaultToolbarGroups,
39
+ equationGallery: () => equationGallery,
40
+ equationPanel: () => equationPanel,
41
+ equationPreviewSvg: () => equationPreviewSvg,
42
+ foldPlan: () => foldPlan,
37
43
  installScrollbars: () => installScrollbars,
38
44
  marginPresetPicker: () => marginPresetPicker,
39
45
  mountMenubar: () => mountMenubar,
@@ -74,6 +80,13 @@ function shortcutLabel(command, registries) {
74
80
  }
75
81
  return void 0;
76
82
  }
83
+ var TABS_CSS = `
84
+ .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}
85
+ .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}
86
+ .bb-tab:last-child{border-right:0}
87
+ .bb-tab:hover{background:var(--bb-ui-hover,#f1efe8);opacity:.9}
88
+ .bb-tab[aria-selected="true"]{background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c);opacity:1}
89
+ `;
77
90
  function injectStyle(id, css) {
78
91
  if (document.getElementById(id)) return;
79
92
  const el5 = document.createElement("style");
@@ -97,12 +110,12 @@ function placeFloating(el5, anchor) {
97
110
  }
98
111
  function rovingGrid(cells) {
99
112
  let cur = [0, 0];
100
- const at = (r, c) => cells[r]?.[c];
101
- const focusCell = (r, c) => {
113
+ const at = (r, c2) => cells[r]?.[c2];
114
+ const focusCell = (r, c2) => {
102
115
  const rows = cells.length;
103
116
  if (rows === 0) return;
104
117
  const nr = Math.min(rows - 1, Math.max(0, r));
105
- const nc = Math.min(cells[nr].length - 1, Math.max(0, c));
118
+ const nc = Math.min(cells[nr].length - 1, Math.max(0, c2));
106
119
  const prev = at(cur[0], cur[1]);
107
120
  if (prev) prev.tabIndex = -1;
108
121
  const next = at(nr, nc);
@@ -112,9 +125,9 @@ function rovingGrid(cells) {
112
125
  cur = [nr, nc];
113
126
  };
114
127
  cells.forEach(
115
- (row, r) => row.forEach((cell, c) => {
128
+ (row, r) => row.forEach((cell, c2) => {
116
129
  cell.setAttribute("role", "gridcell");
117
- cell.tabIndex = r === 0 && c === 0 ? 0 : -1;
130
+ cell.tabIndex = r === 0 && c2 === 0 ? 0 : -1;
118
131
  cell.addEventListener("keydown", (e) => {
119
132
  const delta = {
120
133
  ArrowRight: [0, 1],
@@ -127,10 +140,10 @@ function rovingGrid(cells) {
127
140
  const d = delta[e.key];
128
141
  if (!d) return;
129
142
  e.preventDefault();
130
- focusCell(r + d[0], c + d[1]);
143
+ focusCell(r + d[0], c2 + d[1]);
131
144
  });
132
145
  cell.addEventListener("focus", () => {
133
- cur = [r, c];
146
+ cur = [r, c2];
134
147
  });
135
148
  })
136
149
  );
@@ -460,9 +473,9 @@ function openColorPicker({
460
473
  panel.remove();
461
474
  anchor.focus();
462
475
  };
463
- const pick = (c) => {
464
- if (c && !COLOR_PALETTE.some((row) => row.includes(c))) remember(c);
465
- onPick(c);
476
+ const pick = (c2) => {
477
+ if (c2 && !COLOR_PALETTE.some((row) => row.includes(c2))) remember(c2);
478
+ onPick(c2);
466
479
  close();
467
480
  };
468
481
  if (clearLabel !== void 0) {
@@ -506,15 +519,15 @@ function openColorPicker({
506
519
  );
507
520
  const customRow2 = document.createElement("div");
508
521
  customRow2.className = "bb-cpk-row";
509
- for (const c of customColors) {
522
+ for (const c2 of customColors) {
510
523
  const sw = document.createElement("button");
511
524
  sw.type = "button";
512
525
  sw.className = "bb-cpk-sw";
513
- sw.style.background = c;
514
- sw.title = c;
515
- sw.setAttribute("aria-label", c);
516
- if (c.toUpperCase() === value?.toUpperCase()) sw.classList.add("on");
517
- sw.addEventListener("click", () => pick(c));
526
+ sw.style.background = c2;
527
+ sw.title = c2;
528
+ sw.setAttribute("aria-label", c2);
529
+ if (c2.toUpperCase() === value?.toUpperCase()) sw.classList.add("on");
530
+ sw.addEventListener("click", () => pick(c2));
518
531
  customRow2.append(sw);
519
532
  }
520
533
  const plus = document.createElement("button");
@@ -598,8 +611,8 @@ function colorButton(o) {
598
611
  anchor: el5,
599
612
  value: o.value(),
600
613
  clearLabel: o.clearLabel,
601
- onPick: (c) => {
602
- o.onPick(c);
614
+ onPick: (c2) => {
615
+ o.onPick(c2);
603
616
  sync();
604
617
  }
605
618
  });
@@ -683,6 +696,7 @@ var STYLE3 = `
683
696
  .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}
684
697
  .bb-toolbar *{box-sizing:border-box}
685
698
  .bb-toolbar-group{display:flex;gap:2px;flex:none}
699
+ .bb-toolbar-group[hidden]{display:none}
686
700
  .bb-toolbar-group+.bb-toolbar-group{padding-left:10px;border-left:1px solid var(--bb-ui-border,#e3e3e0)}
687
701
  .bb-toolbar-more{margin-left:auto;flex:none}
688
702
  .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)}
@@ -691,6 +705,9 @@ var STYLE3 = `
691
705
  .bb-toolbar-btn:hover{background:var(--bb-ui-hover,#f1efe8)}
692
706
  .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)}
693
707
  .bb-toolbar-btn:disabled{opacity:.38;cursor:default}
708
+ .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)}
709
+ .bb-toolbar-btn.bb-btn-accent:hover{background:var(--bb-ui-active-bg,#e6f1fb);border-color:var(--bb-ui-active-fg,#0c447c)}
710
+ .bb-btn-caret{font-size:9px;opacity:.7;line-height:1}
694
711
  .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}
695
712
  .bb-toolbar-select:hover{background:var(--bb-ui-hover,#f1efe8)}
696
713
  .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}
@@ -710,11 +727,30 @@ var STYLE3 = `
710
727
  .bb-split-bar{flex:1;height:3px;border-radius:2px;background:var(--bb-ui-border,#d9d9d4)}
711
728
  `;
712
729
  function defaultToolbarGroups(commands) {
713
- const names = [...commands].map((c) => c.name);
730
+ const names = [...commands].map((c2) => c2.name);
714
731
  const aligns = names.filter((n) => n.startsWith("align-"));
715
732
  const rest = names.filter((n) => !n.startsWith("align-"));
716
733
  return [rest, aligns].filter((g2) => g2.length > 0);
717
734
  }
735
+ function foldPlan(candidates, avail, moreWidth, gap) {
736
+ const vis = candidates.filter((c2) => !c2.hidden);
737
+ const rowWidth = vis.reduce((sum, c2) => sum + c2.width, 0) + gap * Math.max(0, vis.length - 1);
738
+ const folded = /* @__PURE__ */ new Set();
739
+ if (rowWidth <= avail + 1) return folded;
740
+ const order = [
741
+ ...vis.filter((c2) => !c2.sticky).reverse(),
742
+ ...vis.filter((c2) => c2.sticky).reverse()
743
+ ];
744
+ const fitsRemaining = () => {
745
+ const rem = vis.filter((c2) => !folded.has(c2.idx));
746
+ return rem.reduce((sum, c2) => sum + c2.width, 0) + gap * rem.length + moreWidth <= avail + 1;
747
+ };
748
+ for (const c2 of order) {
749
+ if (fitsRemaining()) break;
750
+ folded.add(c2.idx);
751
+ }
752
+ return folded;
753
+ }
718
754
  function mountToolbar(host, editor, options = {}) {
719
755
  injectStyle("bb-ui-toolbar-styles", STYLE3);
720
756
  const items = { ...DEFAULT_ITEMS, ...options.items ?? {} };
@@ -725,17 +761,25 @@ function mountToolbar(host, editor, options = {}) {
725
761
  root.className = "bb-toolbar";
726
762
  root.setAttribute("role", "toolbar");
727
763
  const buttons = [];
764
+ const groupList = [];
765
+ const conditionalGroups = [];
728
766
  const selects = [];
729
767
  const colors = [];
730
768
  const splits = [];
731
769
  let latest = null;
732
770
  for (const group of groups) {
733
- const entries = group.filter(
771
+ const spec = Array.isArray(group) ? { entries: group } : group;
772
+ const entries = spec.entries.filter(
734
773
  (e) => typeof e !== "string" || editor.commands.has(e)
735
774
  );
736
775
  if (entries.length === 0) continue;
737
776
  const groupEl = document.createElement("div");
738
777
  groupEl.className = "bb-toolbar-group";
778
+ groupList.push({ el: groupEl, sticky: !!spec.sticky, lastWidth: 0 });
779
+ if (spec.visible) {
780
+ conditionalGroups.push({ el: groupEl, visible: spec.visible });
781
+ groupEl.hidden = true;
782
+ }
739
783
  for (const entry of entries) {
740
784
  if (typeof entry !== "string" && entry.kind === "select") {
741
785
  const sel = document.createElement("select");
@@ -761,12 +805,24 @@ function mountToolbar(host, editor, options = {}) {
761
805
  if (typeof entry !== "string" && entry.kind === "button") {
762
806
  const btn2 = document.createElement("button");
763
807
  btn2.type = "button";
764
- btn2.className = "bb-toolbar-btn";
808
+ btn2.className = "bb-toolbar-btn" + (entry.accent ? " bb-btn-accent" : "");
765
809
  btn2.title = entry.title;
766
810
  btn2.setAttribute("aria-label", entry.title);
767
811
  btn2.setAttribute("aria-haspopup", "dialog");
768
812
  if (entry.svg) btn2.innerHTML = entry.svg;
769
813
  else btn2.textContent = entry.label ?? entry.title;
814
+ if (entry.text) {
815
+ const span = document.createElement("span");
816
+ span.textContent = entry.text;
817
+ btn2.appendChild(span);
818
+ }
819
+ if (entry.caret) {
820
+ const caret = document.createElement("span");
821
+ caret.className = "bb-btn-caret";
822
+ caret.setAttribute("aria-hidden", "true");
823
+ caret.textContent = "\u25BE";
824
+ btn2.appendChild(caret);
825
+ }
770
826
  btn2.addEventListener("mousedown", (e) => e.preventDefault());
771
827
  btn2.addEventListener("click", () => entry.onClick(btn2));
772
828
  groupEl.appendChild(btn2);
@@ -927,19 +983,52 @@ function mountToolbar(host, editor, options = {}) {
927
983
  pop.hidden = !pop.hidden;
928
984
  moreBtn.setAttribute("aria-expanded", String(!pop.hidden));
929
985
  });
930
- const fits = () => root.scrollWidth <= root.clientWidth + 1;
986
+ let gapPx = -1;
987
+ let moreW = -1;
988
+ const anchorIn = (container, idx) => {
989
+ for (let j = idx + 1; j < groupList.length; j++)
990
+ if (groupList[j].el.parentElement === container) return groupList[j].el;
991
+ return container === root ? moreBtn : null;
992
+ };
931
993
  const layout = () => {
932
- while (pop.firstChild) root.insertBefore(pop.firstChild, moreBtn);
933
- moreBtn.style.display = "none";
934
- closePop();
935
- wrap.querySelectorAll(".bb-split-pop").forEach((p) => p.hidden = true);
936
- if (fits()) return;
937
- moreBtn.style.display = "";
938
- const groupEls = Array.from(root.children).filter(
939
- (el5) => el5.classList.contains("bb-toolbar-group")
940
- );
941
- for (let i = groupEls.length - 1; i >= 0 && !fits(); i--) {
942
- pop.insertBefore(groupEls[i], pop.firstChild);
994
+ if (gapPx < 0)
995
+ gapPx = Number.parseFloat(getComputedStyle(root).columnGap) || 0;
996
+ if (moreW < 0) {
997
+ moreBtn.style.visibility = "hidden";
998
+ const prev = moreBtn.style.display;
999
+ moreBtn.style.display = "";
1000
+ moreW = moreBtn.offsetWidth;
1001
+ moreBtn.style.display = prev;
1002
+ moreBtn.style.visibility = "";
1003
+ }
1004
+ const avail = root.clientWidth;
1005
+ const candidates = groupList.map((g2, idx) => {
1006
+ const w = g2.el.offsetWidth;
1007
+ if (w > 0) g2.lastWidth = w;
1008
+ return {
1009
+ idx,
1010
+ width: g2.lastWidth,
1011
+ sticky: g2.sticky,
1012
+ hidden: g2.el.hidden
1013
+ };
1014
+ });
1015
+ const folded = foldPlan(candidates, avail, moreW, gapPx);
1016
+ let moved = false;
1017
+ groupList.forEach((g2, idx) => {
1018
+ const inPop = g2.el.parentElement === pop;
1019
+ const should = folded.has(idx);
1020
+ if (inPop === should) return;
1021
+ moved = true;
1022
+ if (should) pop.insertBefore(g2.el, anchorIn(pop, idx));
1023
+ else root.insertBefore(g2.el, anchorIn(root, idx));
1024
+ });
1025
+ const showMore = folded.size > 0;
1026
+ if (moreBtn.style.display !== "none" !== showMore)
1027
+ moreBtn.style.display = showMore ? "" : "none";
1028
+ if (!showMore) closePop();
1029
+ if (moved) {
1030
+ closePop();
1031
+ wrap.querySelectorAll(".bb-split-pop").forEach((p) => p.hidden = true);
943
1032
  }
944
1033
  };
945
1034
  let ro = null;
@@ -951,6 +1040,15 @@ function mountToolbar(host, editor, options = {}) {
951
1040
  layout();
952
1041
  const refresh = (state) => {
953
1042
  latest = state;
1043
+ let visibilityChanged = false;
1044
+ for (const g2 of conditionalGroups) {
1045
+ const show = g2.visible(state);
1046
+ if (show === g2.el.hidden) {
1047
+ g2.el.hidden = !show;
1048
+ visibilityChanged = true;
1049
+ }
1050
+ }
1051
+ if (visibilityChanged) layout();
954
1052
  for (const { name, el: el5 } of buttons) {
955
1053
  const cmd = editor.commands.get(name);
956
1054
  if (!cmd) continue;
@@ -960,7 +1058,7 @@ function mountToolbar(host, editor, options = {}) {
960
1058
  el5.disabled = cmd.isEnabled ? !cmd.isEnabled(state) : false;
961
1059
  }
962
1060
  for (const { spec, el: el5 } of selects) el5.value = spec.value(state);
963
- for (const c of colors) c.sync();
1061
+ for (const c2 of colors) c2.sync();
964
1062
  for (const { spec, cards } of splits) {
965
1063
  const selected = spec.value(state);
966
1064
  for (const card of cards)
@@ -970,7 +1068,7 @@ function mountToolbar(host, editor, options = {}) {
970
1068
  );
971
1069
  }
972
1070
  };
973
- const off = editor.onChange((c) => refresh(c.state));
1071
+ const off = editor.onChange((c2) => refresh(c2.state));
974
1072
  try {
975
1073
  refresh(editor.state);
976
1074
  } catch {
@@ -1214,7 +1312,7 @@ function showMenu(entries, at, options = {}) {
1214
1312
  return handle;
1215
1313
  }
1216
1314
  function defaultMenus(commands) {
1217
- const names = [...commands].map((c) => c.name);
1315
+ const names = [...commands].map((c2) => c2.name);
1218
1316
  const marks = ["bold", "italic", "underline", "strike"].filter(
1219
1317
  (n) => commands.has(n)
1220
1318
  );
@@ -1328,10 +1426,10 @@ function mountMenubar(host, editor, options = {}) {
1328
1426
  function refresh(state) {
1329
1427
  latest = state;
1330
1428
  if (openIdx < 0) return;
1331
- for (const c of checks) c.el.textContent = c.active(state) ? "\u2713" : "";
1429
+ for (const c2 of checks) c2.el.textContent = c2.active(state) ? "\u2713" : "";
1332
1430
  for (const e of enables) e.el.disabled = !e.enabled(state);
1333
1431
  }
1334
- const off = editor.onChange((c) => refresh(c.state));
1432
+ const off = editor.onChange((c2) => refresh(c2.state));
1335
1433
  try {
1336
1434
  latest = editor.state;
1337
1435
  } catch {
@@ -1659,13 +1757,13 @@ function showLinkPanel(opts) {
1659
1757
  row.appendChild(icon);
1660
1758
  const label = document.createElement("span");
1661
1759
  label.className = "bb-linkpanel-href";
1662
- label.textContent = internal.label ?? "V\u1ECB tr\xED kh\xF4ng c\xF2n trong t\xE0i li\u1EC7u";
1760
+ label.textContent = internal.label ?? "This place is no longer in the document";
1663
1761
  label.title = internal.label ?? existing.href;
1664
1762
  if (!internal.label) label.classList.add("bb-linkpanel-stale");
1665
1763
  row.appendChild(label);
1666
1764
  if (internal.label) {
1667
1765
  row.appendChild(
1668
- iconBtn(ICONS.goTo, "\u0110i t\u1EDBi v\u1ECB tr\xED n\xE0y", () => {
1766
+ iconBtn(ICONS.goTo, "Go to this place", () => {
1669
1767
  closeCurrent2();
1670
1768
  internal.onGo();
1671
1769
  })
@@ -1879,8 +1977,8 @@ function openCellProperties({
1879
1977
  label: "Fill",
1880
1978
  clearLabel: "No fill",
1881
1979
  value: () => background,
1882
- onPick: (c) => {
1883
- background = c;
1980
+ onPick: (c2) => {
1981
+ background = c2;
1884
1982
  }
1885
1983
  });
1886
1984
  fill.append(fillBtn.el);
@@ -1933,8 +2031,8 @@ function openCellProperties({
1933
2031
  title: "Border colour",
1934
2032
  label: "Colour",
1935
2033
  value: () => penColor,
1936
- onPick: (c) => {
1937
- if (c) penColor = c;
2034
+ onPick: (c2) => {
2035
+ if (c2) penColor = c2;
1938
2036
  }
1939
2037
  });
1940
2038
  penRow.append(widthSel, styleSel, penBtn.el);
@@ -1998,8 +2096,369 @@ function openCellProperties({
1998
2096
  dialog.open();
1999
2097
  }
2000
2098
 
2001
- // packages/ui/src/lib/table-grid.ts
2099
+ // packages/ui/src/lib/equation-gallery.ts
2100
+ var import_bapbong_contracts2 = require("@shadow-garden/bapbong-contracts");
2101
+ var c = (s) => [...s].map((ch) => ({ t: "chr", ch }));
2102
+ var sup = (base, exp) => ({
2103
+ t: "scr",
2104
+ base,
2105
+ sub: [],
2106
+ sup: c(exp)
2107
+ });
2108
+ var subsup = (base, lo, hi) => ({
2109
+ t: "scr",
2110
+ base,
2111
+ sub: c(lo),
2112
+ sup: c(hi)
2113
+ });
2114
+ var BUILT_IN_EQUATIONS = [
2115
+ {
2116
+ name: "Area of a circle",
2117
+ ast: [...c("\u{1D434} = \u{1D70B}"), sup(c("\u{1D45F}"), "2")]
2118
+ },
2119
+ {
2120
+ name: "Pythagorean theorem",
2121
+ ast: [
2122
+ sup(c("\u{1D44E}"), "2"),
2123
+ ...c(" + "),
2124
+ sup(c("\u{1D44F}"), "2"),
2125
+ ...c(" = "),
2126
+ sup(c("\u{1D450}"), "2")
2127
+ ]
2128
+ },
2129
+ {
2130
+ name: "Quadratic formula",
2131
+ ast: [
2132
+ ...c("\u{1D465} = "),
2133
+ {
2134
+ t: "frac",
2135
+ num: [
2136
+ ...c("\u2212\u{1D44F} \xB1 "),
2137
+ {
2138
+ t: "rad",
2139
+ deg: [],
2140
+ body: [sup(c("\u{1D44F}"), "2"), ...c(" \u2212 4\u{1D44E}\u{1D450}")]
2141
+ }
2142
+ ],
2143
+ den: c("2\u{1D44E}")
2144
+ }
2145
+ ]
2146
+ },
2147
+ {
2148
+ name: "Law of cosines",
2149
+ ast: [
2150
+ sup(c("\u{1D44E}"), "2"),
2151
+ ...c(" = "),
2152
+ sup(c("\u{1D44F}"), "2"),
2153
+ ...c(" + "),
2154
+ sup(c("\u{1D450}"), "2"),
2155
+ ...c(" \u2212 2\u{1D44F}\u{1D450} cos \u{1D434}")
2156
+ ]
2157
+ },
2158
+ {
2159
+ name: "Binomial theorem",
2160
+ ast: [
2161
+ // The exponent belongs ON the bracket: a script with an empty base
2162
+ // would render its own empty slot — the dotted placeholder box.
2163
+ {
2164
+ t: "scr",
2165
+ base: [{ t: "fence", l: "(", r: ")", body: c("\u{1D44E} + \u{1D44F}") }],
2166
+ sub: [],
2167
+ sup: c("\u{1D45B}")
2168
+ },
2169
+ ...c(" = "),
2170
+ {
2171
+ t: "big",
2172
+ op: "\u2211",
2173
+ lo: c("\u{1D458} = 0"),
2174
+ hi: c("\u{1D45B}"),
2175
+ body: [
2176
+ subsup(c("\u{1D436}"), "\u{1D45B}", "\u{1D458}"),
2177
+ sup(c("\u{1D44E}"), "\u{1D458}"),
2178
+ { t: "scr", base: c("\u{1D44F}"), sub: [], sup: c("\u{1D45B}\u2212\u{1D458}") }
2179
+ ]
2180
+ }
2181
+ ]
2182
+ }
2183
+ ];
2184
+ var SVG_NS = "http://www.w3.org/2000/svg";
2185
+ function equationPreviewSvg(spec, opts = {}) {
2186
+ const svg = document.createElementNS(SVG_NS, "svg");
2187
+ svg.setAttribute("viewBox", `0 0 ${spec.width} ${spec.height}`);
2188
+ const max = opts.maxWidth ?? spec.width;
2189
+ const scale = Math.min(1, max / Math.max(1, spec.width));
2190
+ svg.setAttribute("width", String(Math.round(spec.width * scale)));
2191
+ svg.setAttribute("height", String(Math.round(spec.height * scale)));
2192
+ svg.setAttribute("aria-hidden", "true");
2193
+ for (const op of spec.ops) svg.append(opElement(op));
2194
+ return svg;
2195
+ }
2196
+ function opElement(op) {
2197
+ if (op.kind === "line") {
2198
+ const el6 = document.createElementNS(SVG_NS, "line");
2199
+ el6.setAttribute("x1", String(op.x1));
2200
+ el6.setAttribute("y1", String(op.y1));
2201
+ el6.setAttribute("x2", String(op.x2));
2202
+ el6.setAttribute("y2", String(op.y2));
2203
+ el6.setAttribute("stroke", op.color);
2204
+ el6.setAttribute("stroke-width", String(Math.max(op.width, 0.75)));
2205
+ return el6;
2206
+ }
2207
+ if (op.kind === "polygon") {
2208
+ const el6 = document.createElementNS(SVG_NS, "polygon");
2209
+ el6.setAttribute("points", op.points.map((p) => `${p.x},${p.y}`).join(" "));
2210
+ el6.setAttribute("fill", op.fill ?? "none");
2211
+ if (op.stroke) {
2212
+ el6.setAttribute("stroke", op.stroke);
2213
+ el6.setAttribute("stroke-width", String(op.strokeWidth ?? 1));
2214
+ }
2215
+ return el6;
2216
+ }
2217
+ const el5 = document.createElementNS(SVG_NS, "text");
2218
+ el5.setAttribute("x", String(op.x));
2219
+ el5.setAttribute("y", String(op.y));
2220
+ el5.setAttribute("font-size", String(op.size));
2221
+ el5.setAttribute("font-family", op.family);
2222
+ el5.setAttribute("fill", op.color);
2223
+ if (op.bold) el5.setAttribute("font-weight", "bold");
2224
+ if (op.italic) el5.setAttribute("font-style", "italic");
2225
+ if (op.vAlign === "top") el5.setAttribute("dominant-baseline", "hanging");
2226
+ if (op.dx) {
2227
+ let x = op.x;
2228
+ for (const [i, ch] of [...op.text].entries()) {
2229
+ const t = document.createElementNS(SVG_NS, "tspan");
2230
+ t.setAttribute("x", String(x));
2231
+ t.textContent = ch;
2232
+ el5.append(t);
2233
+ x += op.dx[i] ?? 0;
2234
+ }
2235
+ } else {
2236
+ el5.textContent = op.text;
2237
+ }
2238
+ return el5;
2239
+ }
2002
2240
  var STYLE9 = `
2241
+ .bb-eqg{display:flex;flex-direction:column;min-width:236px;max-width:300px;user-select:none}
2242
+ .bb-eqg-head{font-size:11px;font-weight:600;opacity:.55;padding:2px 8px 6px}
2243
+ .bb-eqg-list{display:flex;flex-direction:column;max-height:320px;overflow-y:auto}
2244
+ .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}
2245
+ .bb-eqg-item:hover{background:var(--bb-ui-hover,#f1efe8)}
2246
+ .bb-eqg-name{font-size:11px;opacity:.6}
2247
+ /* The preview is the equation TYPESET \u2014 the same display list the canvas
2248
+ paints. The text form is the fallback for a host that cannot lay out. */
2249
+ .bb-eqg-prev{display:flex;align-items:center;min-height:22px;max-width:100%;overflow:hidden}
2250
+ .bb-eqg-prev svg{display:block}
2251
+ .bb-eqg-prev-text{font-family:"Times New Roman",Tinos,serif;font-size:15px;line-height:1.35;white-space:nowrap;text-overflow:ellipsis}
2252
+ .bb-eqg-foot{margin-top:4px;padding-top:5px;border-top:1px solid var(--bb-ui-border,#e3e3e0)}
2253
+ .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}
2254
+ .bb-eqg-new:hover{background:var(--bb-ui-hover,#f1efe8)}
2255
+ .bb-eqg-key{margin-left:auto;opacity:.5;font-size:12px}
2256
+ `;
2257
+ var PREVIEW_PT = 11;
2258
+ var PREVIEW_MAX_W = 264;
2259
+ function equationGallery(options) {
2260
+ injectStyle("bb-ui-eqg-styles", STYLE9);
2261
+ const root = document.createElement("div");
2262
+ root.className = "bb-eqg";
2263
+ const head = document.createElement("div");
2264
+ head.className = "bb-eqg-head";
2265
+ head.textContent = "Built-in";
2266
+ root.append(head);
2267
+ const list = document.createElement("div");
2268
+ list.className = "bb-eqg-list";
2269
+ for (const item of options.items ?? BUILT_IN_EQUATIONS) {
2270
+ const btn = document.createElement("button");
2271
+ btn.type = "button";
2272
+ btn.className = "bb-eqg-item";
2273
+ const prev = document.createElement("div");
2274
+ prev.className = "bb-eqg-prev";
2275
+ const spec = options.layout?.(item.ast, PREVIEW_PT) ?? null;
2276
+ if (spec && spec.ops.length)
2277
+ prev.append(equationPreviewSvg(spec, { maxWidth: PREVIEW_MAX_W }));
2278
+ else {
2279
+ prev.classList.add("bb-eqg-prev-text");
2280
+ prev.textContent = (0, import_bapbong_contracts2.astToLinear)(item.ast);
2281
+ }
2282
+ const name = document.createElement("div");
2283
+ name.className = "bb-eqg-name";
2284
+ name.textContent = item.name;
2285
+ btn.append(prev, name);
2286
+ btn.addEventListener("mousedown", (e) => e.preventDefault());
2287
+ btn.addEventListener("click", () => options.onPick(item.ast));
2288
+ list.append(btn);
2289
+ }
2290
+ root.append(list);
2291
+ const foot = document.createElement("div");
2292
+ foot.className = "bb-eqg-foot";
2293
+ const neu = document.createElement("button");
2294
+ neu.type = "button";
2295
+ neu.className = "bb-eqg-new";
2296
+ const label = document.createElement("span");
2297
+ label.textContent = "Insert new equation";
2298
+ neu.append(label);
2299
+ if (options.newShortcut) {
2300
+ const key = document.createElement("span");
2301
+ key.className = "bb-eqg-key";
2302
+ key.textContent = options.newShortcut;
2303
+ neu.append(key);
2304
+ }
2305
+ neu.addEventListener("mousedown", (e) => e.preventDefault());
2306
+ neu.addEventListener("click", () => options.onNew());
2307
+ foot.append(neu);
2308
+ root.append(foot);
2309
+ return root;
2310
+ }
2311
+
2312
+ // packages/ui/src/lib/equation-panel.ts
2313
+ var import_bapbong_contracts3 = require("@shadow-garden/bapbong-contracts");
2314
+ var SHORTHAND = /* @__PURE__ */ new Map();
2315
+ for (const [name, ch] of Object.entries(import_bapbong_contracts3.MATH_AUTOCORRECT))
2316
+ if (!SHORTHAND.has(ch)) SHORTHAND.set(ch, `\\${name}`);
2317
+ var PREVIEW_PT2 = 10;
2318
+ var STYLE10 = `
2319
+ .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}
2320
+ .bb-eqp-tabs{display:flex;padding:8px 8px 0}
2321
+ .bb-eqp-body{padding:8px}
2322
+ .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}
2323
+ .bb-eqp-grid{display:grid;grid-template-columns:repeat(10,1fr);gap:1px;max-height:190px;overflow-y:auto}
2324
+ .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}
2325
+ .bb-eqp-sym:hover{background:var(--bb-ui-hover,#f1efe8)}
2326
+ .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}
2327
+ .bb-eqp-hint-g{font-family:"Cambria Math","Times New Roman",Tinos,serif;font-size:15px}
2328
+ .bb-eqp-hint-k{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
2329
+ .bb-eqp-scroll{max-height:230px;overflow-y:auto}
2330
+ .bb-eqp-group{font-size:11px;font-weight:600;opacity:.5;padding:6px 2px 3px}
2331
+ .bb-eqp-row{display:grid;grid-template-columns:repeat(4,1fr);gap:3px}
2332
+ .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}
2333
+ .bb-eqp-st:hover{background:var(--bb-ui-hover,#f1efe8)}
2334
+ .bb-eqp-st-name{font-size:10px;opacity:.6;text-align:center;line-height:1.25}
2335
+ .bb-eqp-st svg{display:block}
2336
+ `;
2337
+ function equationPanel(options) {
2338
+ injectStyle("bb-ui-tabs", TABS_CSS);
2339
+ injectStyle("bb-ui-eqp-styles", STYLE10);
2340
+ const root = document.createElement("div");
2341
+ root.className = "bb-eqp";
2342
+ root.setAttribute("role", "group");
2343
+ root.setAttribute("aria-label", "Equation palette");
2344
+ root.addEventListener("mousedown", (e) => e.preventDefault());
2345
+ const strip = document.createElement("div");
2346
+ strip.className = "bb-eqp-tabs";
2347
+ const tabs = document.createElement("div");
2348
+ tabs.className = "bb-tabs";
2349
+ tabs.setAttribute("role", "tablist");
2350
+ strip.append(tabs);
2351
+ const body = document.createElement("div");
2352
+ body.className = "bb-eqp-body";
2353
+ let current3 = "symbols";
2354
+ const tabEls = {};
2355
+ const mkTab = (id, label) => {
2356
+ const b = document.createElement("button");
2357
+ b.type = "button";
2358
+ b.className = "bb-tab";
2359
+ b.textContent = label;
2360
+ b.setAttribute("role", "tab");
2361
+ b.addEventListener("click", () => {
2362
+ current3 = id;
2363
+ render();
2364
+ });
2365
+ tabEls[id] = b;
2366
+ tabs.append(b);
2367
+ };
2368
+ mkTab("symbols", "Symbols");
2369
+ mkTab("structures", "Structures");
2370
+ root.append(strip, body);
2371
+ function symbolsBody() {
2372
+ const set = document.createElement("select");
2373
+ set.className = "bb-eqp-set";
2374
+ set.setAttribute("aria-label", "Symbol set");
2375
+ for (const [i, s] of import_bapbong_contracts3.MATH_SYMBOL_SETS.entries()) {
2376
+ const o = document.createElement("option");
2377
+ o.value = String(i);
2378
+ o.textContent = s.name;
2379
+ set.append(o);
2380
+ }
2381
+ set.value = String(setIndex);
2382
+ const grid = document.createElement("div");
2383
+ grid.className = "bb-eqp-grid";
2384
+ const hint = document.createElement("div");
2385
+ hint.className = "bb-eqp-hint";
2386
+ const hintG = document.createElement("span");
2387
+ hintG.className = "bb-eqp-hint-g";
2388
+ const hintK = document.createElement("span");
2389
+ hintK.className = "bb-eqp-hint-k";
2390
+ hint.append(hintG, hintK);
2391
+ const fill = () => {
2392
+ grid.replaceChildren();
2393
+ const chars = import_bapbong_contracts3.MATH_SYMBOL_SETS[setIndex]?.chars ?? "";
2394
+ for (const ch of chars) {
2395
+ const b = document.createElement("button");
2396
+ b.type = "button";
2397
+ b.className = "bb-eqp-sym";
2398
+ b.textContent = ch;
2399
+ const key = SHORTHAND.get(ch);
2400
+ b.title = key ? `${ch} ${key}` : ch;
2401
+ b.addEventListener("mouseenter", () => {
2402
+ hintG.textContent = ch;
2403
+ hintK.textContent = key ?? "";
2404
+ });
2405
+ b.addEventListener("click", () => options.onSymbol(ch));
2406
+ grid.append(b);
2407
+ }
2408
+ };
2409
+ set.addEventListener("change", () => {
2410
+ setIndex = Number(set.value) || 0;
2411
+ fill();
2412
+ });
2413
+ fill();
2414
+ body.replaceChildren(set, grid, hint);
2415
+ }
2416
+ function structuresBody() {
2417
+ const scroll = document.createElement("div");
2418
+ scroll.className = "bb-eqp-scroll";
2419
+ for (const group of (0, import_bapbong_contracts3.eqStructureGroups)()) {
2420
+ const h = document.createElement("div");
2421
+ h.className = "bb-eqp-group";
2422
+ h.textContent = group.name;
2423
+ const row = document.createElement("div");
2424
+ row.className = "bb-eqp-row";
2425
+ for (const item of group.items) {
2426
+ const b = document.createElement("button");
2427
+ b.type = "button";
2428
+ b.className = "bb-eqp-st";
2429
+ b.title = `${group.name} \u2014 ${item.name}`;
2430
+ const spec = options.layout?.([item.node], PREVIEW_PT2) ?? null;
2431
+ if (spec && spec.ops.length)
2432
+ b.append(equationPreviewSvg(spec, { maxWidth: 60 }));
2433
+ const name = document.createElement("span");
2434
+ name.className = "bb-eqp-st-name";
2435
+ name.textContent = item.name;
2436
+ b.append(name);
2437
+ b.addEventListener("click", () => options.onStructure(item));
2438
+ row.append(b);
2439
+ }
2440
+ scroll.append(h, row);
2441
+ }
2442
+ body.replaceChildren(scroll);
2443
+ }
2444
+ let setIndex = 0;
2445
+ function render() {
2446
+ for (const [id, el5] of Object.entries(tabEls))
2447
+ el5.setAttribute("aria-selected", String(id === current3));
2448
+ if (current3 === "symbols") symbolsBody();
2449
+ else structuresBody();
2450
+ }
2451
+ render();
2452
+ return {
2453
+ el: root,
2454
+ destroy() {
2455
+ root.remove();
2456
+ }
2457
+ };
2458
+ }
2459
+
2460
+ // packages/ui/src/lib/table-grid.ts
2461
+ var STYLE11 = `
2003
2462
  .bb-grid{display:flex;flex-direction:column;gap:6px;user-select:none}
2004
2463
  .bb-grid-cells{display:grid;gap:2px}
2005
2464
  .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}
@@ -2007,7 +2466,7 @@ var STYLE9 = `
2007
2466
  .bb-grid-label{font-size:12px;text-align:center;opacity:.7}
2008
2467
  `;
2009
2468
  function tableGridPicker(options) {
2010
- injectStyle("bb-ui-grid-styles", STYLE9);
2469
+ injectStyle("bb-ui-grid-styles", STYLE11);
2011
2470
  const maxRows = options.maxRows ?? 8;
2012
2471
  const maxCols = options.maxCols ?? 10;
2013
2472
  const root = document.createElement("div");
@@ -2019,22 +2478,22 @@ function tableGridPicker(options) {
2019
2478
  label.className = "bb-grid-label";
2020
2479
  label.textContent = "0 \xD7 0";
2021
2480
  const cells = [];
2022
- const highlight2 = (r, c) => {
2481
+ const highlight2 = (r, c2) => {
2023
2482
  for (let i = 0; i < cells.length; i++) {
2024
2483
  const row = Math.floor(i / maxCols);
2025
2484
  const col = i % maxCols;
2026
- cells[i].classList.toggle("on", row <= r && col <= c);
2485
+ cells[i].classList.toggle("on", row <= r && col <= c2);
2027
2486
  }
2028
- label.textContent = `${r + 1} \xD7 ${c + 1}`;
2487
+ label.textContent = `${r + 1} \xD7 ${c2 + 1}`;
2029
2488
  };
2030
2489
  for (let r = 0; r < maxRows; r++) {
2031
- for (let c = 0; c < maxCols; c++) {
2490
+ for (let c2 = 0; c2 < maxCols; c2++) {
2032
2491
  const cell = document.createElement("button");
2033
2492
  cell.type = "button";
2034
2493
  cell.className = "bb-grid-cell";
2035
2494
  cell.addEventListener("mousedown", (e) => e.preventDefault());
2036
- cell.addEventListener("mouseenter", () => highlight2(r, c));
2037
- cell.addEventListener("click", () => options.onPick(r + 1, c + 1));
2495
+ cell.addEventListener("mouseenter", () => highlight2(r, c2));
2496
+ cell.addEventListener("click", () => options.onPick(r + 1, c2 + 1));
2038
2497
  cells.push(cell);
2039
2498
  cellsEl.appendChild(cell);
2040
2499
  }
@@ -2043,6 +2502,176 @@ function tableGridPicker(options) {
2043
2502
  return root;
2044
2503
  }
2045
2504
 
2505
+ // packages/ui/src/lib/table-style-panel.ts
2506
+ var import_bapbong_contracts4 = require("@shadow-garden/bapbong-contracts");
2507
+ var GATES = [
2508
+ { key: "firstRow", label: "Header row" },
2509
+ { key: "lastRow", label: "Total row" },
2510
+ { key: "hBand", label: "Banded rows" },
2511
+ { key: "firstCol", label: "First column" },
2512
+ { key: "lastCol", label: "Last column" },
2513
+ { key: "vBand", label: "Banded columns" }
2514
+ ];
2515
+ var THUMB_ROWS = 4;
2516
+ var THUMB_COLS = 5;
2517
+ var STYLE12 = `
2518
+ .bb-tsp{display:flex;gap:16px;width:432px;max-width:100%;color:var(--bb-ui-fg,#2c2c2a)}
2519
+ .bb-tsp *{box-sizing:border-box}
2520
+ .bb-tsp-opts{flex:0 0 128px;display:flex;flex-direction:column;gap:2px}
2521
+ .bb-tsp-lbl{font-size:12px;opacity:.7;margin-bottom:4px}
2522
+ .bb-tsp-chk{display:flex;align-items:center;gap:7px;font-size:13px;padding:3px 0;cursor:pointer}
2523
+ .bb-tsp-chk input{margin:0}
2524
+ .bb-tsp-chk.is-disabled{opacity:.4;cursor:default}
2525
+ .bb-tsp-sep{height:1px;margin:6px 0;background:var(--bb-ui-border,#e3e3e0)}
2526
+ .bb-tsp-main{flex:1;display:flex;flex-direction:column;gap:8px;min-width:0}
2527
+ .bb-tsp-gallery{display:flex;flex-wrap:wrap;gap:6px}
2528
+ .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}
2529
+ .bb-tsp-tile:hover{border-color:var(--bb-ui-fg,#2c2c2a)}
2530
+ .bb-tsp-tile.is-selected{padding:2px;border:2px solid var(--bb-ui-active-fg,#0c447c)}
2531
+ .bb-tsp-thumb{display:grid;grid-template-columns:repeat(${THUMB_COLS},12px);grid-auto-rows:8px;gap:0}
2532
+ .bb-tsp-none{display:flex;align-items:center;justify-content:center;width:60px;height:32px;font-size:11px;opacity:.7;line-height:1.1}
2533
+ .bb-tsp-empty{font-size:13px;opacity:.65;padding:8px 0}
2534
+ `;
2535
+ function edgeCss(side) {
2536
+ if (!side) return "none";
2537
+ return `1px ${side.style === "double" ? "double" : "solid"} ${side.color}`;
2538
+ }
2539
+ function thumbnail(style, look) {
2540
+ const grid = document.createElement("div");
2541
+ grid.className = "bb-tsp-thumb";
2542
+ const t = style.table.borders ?? {};
2543
+ for (let r = 0; r < THUMB_ROWS; r++) {
2544
+ for (let c2 = 0; c2 < THUMB_COLS; c2++) {
2545
+ const layer = (0, import_bapbong_contracts4.cellStyleLayer)(style, look, {
2546
+ row: r,
2547
+ rowCount: THUMB_ROWS,
2548
+ col: c2,
2549
+ colspan: 1,
2550
+ colCount: THUMB_COLS,
2551
+ header: false
2552
+ });
2553
+ const cell = document.createElement("div");
2554
+ const b = layer.borders ?? {};
2555
+ cell.style.borderTop = edgeCss(b.top ?? (r === 0 ? t.top : t.insideH));
2556
+ cell.style.borderBottom = edgeCss(
2557
+ b.bottom ?? (r === THUMB_ROWS - 1 ? t.bottom : void 0)
2558
+ );
2559
+ cell.style.borderLeft = edgeCss(b.left ?? (c2 === 0 ? t.left : t.insideV));
2560
+ cell.style.borderRight = edgeCss(
2561
+ b.right ?? (c2 === THUMB_COLS - 1 ? t.right : void 0)
2562
+ );
2563
+ if (layer.background) cell.style.background = layer.background;
2564
+ grid.appendChild(cell);
2565
+ }
2566
+ }
2567
+ return grid;
2568
+ }
2569
+ function createTableStylePanel(options) {
2570
+ injectStyle("bb-table-style-panel", STYLE12);
2571
+ const root = document.createElement("div");
2572
+ root.className = "bb-tsp";
2573
+ const opts = document.createElement("div");
2574
+ opts.className = "bb-tsp-opts";
2575
+ const optsLbl = document.createElement("div");
2576
+ optsLbl.className = "bb-tsp-lbl";
2577
+ optsLbl.textContent = "Style options";
2578
+ opts.appendChild(optsLbl);
2579
+ const checks = /* @__PURE__ */ new Map();
2580
+ GATES.forEach((g2, i) => {
2581
+ if (i === 3) {
2582
+ const sep = document.createElement("div");
2583
+ sep.className = "bb-tsp-sep";
2584
+ opts.appendChild(sep);
2585
+ }
2586
+ const label = document.createElement("label");
2587
+ label.className = "bb-tsp-chk";
2588
+ const input = document.createElement("input");
2589
+ input.type = "checkbox";
2590
+ input.addEventListener(
2591
+ "change",
2592
+ () => options.onLook({ [g2.key]: input.checked })
2593
+ );
2594
+ label.append(input, document.createTextNode(g2.label));
2595
+ opts.appendChild(label);
2596
+ checks.set(g2.key, input);
2597
+ });
2598
+ const main = document.createElement("div");
2599
+ main.className = "bb-tsp-main";
2600
+ const mainLbl = document.createElement("div");
2601
+ mainLbl.className = "bb-tsp-lbl";
2602
+ mainLbl.textContent = "Table styles";
2603
+ const gallery = document.createElement("div");
2604
+ gallery.className = "bb-tsp-gallery";
2605
+ main.append(mainLbl, gallery);
2606
+ root.append(opts, main);
2607
+ const dialog = new Dialog({
2608
+ title: "Table style",
2609
+ modal: false,
2610
+ anchor: options.anchor
2611
+ });
2612
+ dialog.setContent(root);
2613
+ let drawnKey = "";
2614
+ const draw = () => {
2615
+ const current3 = options.current();
2616
+ const items = options.styles();
2617
+ const key = JSON.stringify([current3, items.map((i) => i.id)]);
2618
+ if (key === drawnKey) return;
2619
+ drawnKey = key;
2620
+ const look = current3?.look ?? null;
2621
+ for (const [gate, input] of checks) {
2622
+ input.checked = look?.[gate] ?? false;
2623
+ input.disabled = !current3;
2624
+ input.closest("label")?.classList.toggle("is-disabled", !current3);
2625
+ }
2626
+ gallery.replaceChildren();
2627
+ if (!current3) {
2628
+ const empty = document.createElement("div");
2629
+ empty.className = "bb-tsp-empty";
2630
+ empty.textContent = "Click inside a table to style it.";
2631
+ gallery.appendChild(empty);
2632
+ return;
2633
+ }
2634
+ const noneTile = document.createElement("button");
2635
+ noneTile.type = "button";
2636
+ noneTile.className = "bb-tsp-tile" + (current3.styleId === null ? " is-selected" : "");
2637
+ noneTile.title = "None";
2638
+ const noneInner = document.createElement("span");
2639
+ noneInner.className = "bb-tsp-none";
2640
+ noneInner.textContent = "None";
2641
+ noneTile.appendChild(noneInner);
2642
+ noneTile.addEventListener("click", () => options.onPick(null));
2643
+ gallery.appendChild(noneTile);
2644
+ for (const item of items) {
2645
+ const tile = document.createElement("button");
2646
+ tile.type = "button";
2647
+ tile.className = "bb-tsp-tile" + (current3.styleId === item.id ? " is-selected" : "");
2648
+ tile.title = item.name;
2649
+ tile.appendChild(thumbnail(item.style, current3.look));
2650
+ tile.addEventListener("click", () => options.onPick(item));
2651
+ gallery.appendChild(tile);
2652
+ }
2653
+ };
2654
+ return {
2655
+ open() {
2656
+ drawnKey = "";
2657
+ draw();
2658
+ dialog.open();
2659
+ },
2660
+ close() {
2661
+ dialog.close();
2662
+ },
2663
+ refresh() {
2664
+ if (dialog.isOpen) draw();
2665
+ },
2666
+ destroy() {
2667
+ dialog.destroy();
2668
+ },
2669
+ get isOpen() {
2670
+ return dialog.isOpen;
2671
+ }
2672
+ };
2673
+ }
2674
+
2046
2675
  // packages/ui/src/lib/page-setup.ts
2047
2676
  var PX_PER_CM = 96 / 2.54;
2048
2677
  var pxToCm = (px) => px / PX_PER_CM;
@@ -2050,7 +2679,7 @@ var cmToPx = (cm) => Math.round(cm * PX_PER_CM);
2050
2679
  function fmtCm(cm) {
2051
2680
  return `${Number(cm.toFixed(3))} cm`;
2052
2681
  }
2053
- var STYLE10 = `
2682
+ var STYLE13 = `
2054
2683
  .bb-ps{display:flex;flex-direction:column;min-width:250px;max-height:min(70vh,460px);overflow-y:auto}
2055
2684
  .bb-ps,.bb-ps *{box-sizing:border-box}
2056
2685
  .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}
@@ -2080,9 +2709,9 @@ var STYLE10 = `
2080
2709
  .bb-ps-tile:hover,.bb-ps-tile:focus{background:var(--bb-ui-hover,#f1efe8);outline:none}
2081
2710
  .bb-ps-tile[aria-checked="true"]{background:var(--bb-ui-active-bg,#e6f1fb)}
2082
2711
  `;
2083
- var SVG_NS = "http://www.w3.org/2000/svg";
2712
+ var SVG_NS2 = "http://www.w3.org/2000/svg";
2084
2713
  function svgEl(name, attrs) {
2085
- const el5 = document.createElementNS(SVG_NS, name);
2714
+ const el5 = document.createElementNS(SVG_NS2, name);
2086
2715
  for (const [k, v] of Object.entries(attrs)) el5.setAttribute(k, String(v));
2087
2716
  return el5;
2088
2717
  }
@@ -2176,7 +2805,7 @@ function customRow(icon, title, description, onPick) {
2176
2805
  return presetRow(icon, title, captionLine(description), false, onPick);
2177
2806
  }
2178
2807
  function pageSizePicker(options) {
2179
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2808
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2180
2809
  const root = document.createElement("div");
2181
2810
  root.className = "bb-ps";
2182
2811
  root.setAttribute("role", "menu");
@@ -2205,7 +2834,7 @@ function pageSizePicker(options) {
2205
2834
  return root;
2206
2835
  }
2207
2836
  function orientationPicker(options) {
2208
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2837
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2209
2838
  const root = document.createElement("div");
2210
2839
  root.className = "bb-ps";
2211
2840
  root.setAttribute("role", "menu");
@@ -2228,7 +2857,7 @@ function orientationPicker(options) {
2228
2857
  return root;
2229
2858
  }
2230
2859
  function marginPresetPicker(options) {
2231
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2860
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2232
2861
  const root = document.createElement("div");
2233
2862
  root.className = "bb-ps";
2234
2863
  root.setAttribute("role", "menu");
@@ -2303,7 +2932,7 @@ function readPx(input, fallbackPx) {
2303
2932
  return Number.isFinite(n) && n > 0 ? cmToPx(n) : fallbackPx;
2304
2933
  }
2305
2934
  function openPageSizeDialog(options) {
2306
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2935
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2307
2936
  const dialog = new Dialog({ title: "Paper size", modal: true });
2308
2937
  const form = document.createElement("form");
2309
2938
  form.className = "bb-pd";
@@ -2330,7 +2959,7 @@ function openPageSizeDialog(options) {
2330
2959
  width.input.select();
2331
2960
  }
2332
2961
  function openMarginsDialog(options) {
2333
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2962
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2334
2963
  const dialog = new Dialog({ title: "Margins", modal: true });
2335
2964
  const form = document.createElement("form");
2336
2965
  form.className = "bb-pd";
@@ -2387,7 +3016,7 @@ var PGNUM_FORMATS = [
2387
3016
  ["upperLetter", "A, B, C, D\u2026", "A"]
2388
3017
  ];
2389
3018
  function pageNumberPicker(options) {
2390
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
3019
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2391
3020
  const root = document.createElement("div");
2392
3021
  root.className = "bb-ps";
2393
3022
  root.setAttribute("role", "menu");
@@ -2488,7 +3117,7 @@ function pageNumberPicker(options) {
2488
3117
  return root;
2489
3118
  }
2490
3119
  function sectionPaperPanel(options) {
2491
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
3120
+ injectStyle("bb-ui-pagesetup-styles", STYLE13);
2492
3121
  const root = document.createElement("div");
2493
3122
  root.className = "bb-ps";
2494
3123
  root.setAttribute("role", "menu");
@@ -2557,7 +3186,7 @@ function sectionPaperPanel(options) {
2557
3186
  }
2558
3187
 
2559
3188
  // packages/ui/src/lib/section-chip.ts
2560
- var STYLE11 = `
3189
+ var STYLE14 = `
2561
3190
  .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)}
2562
3191
  .bb-secchip *{box-sizing:border-box}
2563
3192
  .bb-secchip-title{padding:0 7px;font-size:11px;font-weight:600;opacity:.8}
@@ -2570,7 +3199,7 @@ var STYLE11 = `
2570
3199
  .bb-secchip-x:hover{background:var(--bb-ui-hover,#f1efe8);opacity:1}
2571
3200
  `;
2572
3201
  function createSectionChip(options) {
2573
- injectStyle("bb-ui-section-chip-styles", STYLE11);
3202
+ injectStyle("bb-ui-section-chip-styles", STYLE14);
2574
3203
  const el5 = document.createElement("div");
2575
3204
  el5.className = "bb-secchip";
2576
3205
  const title = document.createElement("span");
@@ -2627,17 +3256,13 @@ var halfToPt = (hp) => hp / 2;
2627
3256
  var ptToHalf = (pt) => Math.round(pt * 2);
2628
3257
  var SCALE_PRESETS = [200, 150, 100, 90, 80, 66, 50, 33];
2629
3258
  var SUPERSUB_SCALE = 0.66;
2630
- var STYLE12 = `
3259
+ var STYLE15 = `
2631
3260
  .bb-fd{display:flex;flex-direction:column;gap:15px;min-width:396px;max-width:430px;color:var(--bb-ui-fg,#2c2c2a)}
2632
3261
  .bb-fd *{box-sizing:border-box}
2633
3262
  /* A segmented control, not a "tab joined to its pane": that pattern needs the
2634
3263
  active tab's background to equal the pane's, and this dialog floats on
2635
3264
  frosted glass whose colour the widget cannot know. Same shape cell-properties
2636
3265
  already uses, so the two dialogs read as one product. */
2637
- .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}
2638
- .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}
2639
- .bb-fd-tab:last-child{border-right:0}
2640
- .bb-fd-tab[aria-selected="true"]{background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c);opacity:1}
2641
3266
  .bb-fd-pane{display:flex;flex-direction:column;gap:13px}
2642
3267
  /* A class-level display beats the UA's [hidden]{display:none}; without this
2643
3268
  both tabs render at once. */
@@ -2709,13 +3334,14 @@ function openFontDialog({
2709
3334
  sizes,
2710
3335
  onApply
2711
3336
  }) {
2712
- injectStyle("bb-font-dialog", STYLE12);
3337
+ injectStyle("bb-ui-tabs", TABS_CSS);
3338
+ injectStyle("bb-font-dialog", STYLE15);
2713
3339
  const dialog = new Dialog({ title: "Font", modal: true });
2714
3340
  const root = el("div", "bb-fd");
2715
- const tabs = el("div", "bb-fd-tabs");
3341
+ const tabs = el("div", "bb-tabs");
2716
3342
  tabs.setAttribute("role", "tablist");
2717
- const fontTab = el("button", "bb-fd-tab", "Font");
2718
- const advTab = el("button", "bb-fd-tab", "Advanced");
3343
+ const fontTab = el("button", "bb-tab", "Font");
3344
+ const advTab = el("button", "bb-tab", "Advanced");
2719
3345
  for (const t of [fontTab, advTab]) {
2720
3346
  t.type = "button";
2721
3347
  t.setAttribute("role", "tab");
@@ -2773,8 +3399,8 @@ function openFontDialog({
2773
3399
  label: "Text color",
2774
3400
  clearLabel: "Automatic",
2775
3401
  value: () => color,
2776
- onPick: (c) => {
2777
- color = c;
3402
+ onPick: (c2) => {
3403
+ color = c2;
2778
3404
  paint();
2779
3405
  }
2780
3406
  });
@@ -2783,8 +3409,8 @@ function openFontDialog({
2783
3409
  label: "Highlight",
2784
3410
  clearLabel: "No highlight",
2785
3411
  value: () => highlight2,
2786
- onPick: (c) => {
2787
- highlight2 = c;
3412
+ onPick: (c2) => {
3413
+ highlight2 = c2;
2788
3414
  paint();
2789
3415
  }
2790
3416
  });
@@ -2909,8 +3535,8 @@ function openFontDialog({
2909
3535
  s.transform = scale === 100 ? "none" : `scaleX(${scale / 100})`;
2910
3536
  s.verticalAlign = supCb.checked ? "super" : subCb.checked ? "sub" : `${positionPt}pt`;
2911
3537
  }
2912
- for (const c of [familySel, sizeSel, scaleSel])
2913
- c.addEventListener("change", paint);
3538
+ for (const c2 of [familySel, sizeSel, scaleSel])
3539
+ c2.addEventListener("change", paint);
2914
3540
  for (const i of [spacingInput, positionInput])
2915
3541
  i.addEventListener("input", paint);
2916
3542
  const foot = el("div", "bb-fd-foot");
@@ -2950,7 +3576,7 @@ function openFontDialog({
2950
3576
  }
2951
3577
 
2952
3578
  // packages/ui/src/lib/symbol-sets.ts
2953
- var import_bapbong_contracts2 = require("@shadow-garden/bapbong-contracts");
3579
+ var import_bapbong_contracts5 = require("@shadow-garden/bapbong-contracts");
2954
3580
  var g = (id, label, short, pairs) => ({
2955
3581
  id,
2956
3582
  label,
@@ -3286,7 +3912,7 @@ var SYMBOL_GROUPS = [
3286
3912
  ])
3287
3913
  ];
3288
3914
  function autoCorrectHint(char) {
3289
- return import_bapbong_contracts2.AUTOCORRECT_RULES.find((r) => r.to === char)?.seq ?? "";
3915
+ return import_bapbong_contracts5.AUTOCORRECT_RULES.find((r) => r.to === char)?.seq ?? "";
3290
3916
  }
3291
3917
  var SPECIAL_CHARACTERS = [
3292
3918
  { char: "\u2014", name: "Em dash", hint: "" },
@@ -3331,7 +3957,7 @@ function parseCodePoint(input) {
3331
3957
  }
3332
3958
  var RECENT_MAX = 16;
3333
3959
  function pushRecent(recent, char, max = RECENT_MAX) {
3334
- return [char, ...recent.filter((c) => c !== char)].slice(0, max);
3960
+ return [char, ...recent.filter((c2) => c2 !== char)].slice(0, max);
3335
3961
  }
3336
3962
  function searchSymbols(query) {
3337
3963
  const q = query.trim().toLowerCase();
@@ -3351,7 +3977,7 @@ function searchSymbols(query) {
3351
3977
  }
3352
3978
 
3353
3979
  // packages/ui/src/lib/symbol-dialog.ts
3354
- var STYLE13 = `
3980
+ var STYLE16 = `
3355
3981
  .bb-sd{display:flex;flex-direction:column;gap:12px;width:412px;max-width:100%;color:var(--bb-ui-fg,#2c2c2a)}
3356
3982
  .bb-sd *{box-sizing:border-box}
3357
3983
  .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}
@@ -3412,7 +4038,7 @@ function glyphFor(char) {
3412
4038
  return char;
3413
4039
  }
3414
4040
  function createSymbolDialog(options) {
3415
- injectStyle("bb-symbol-dialog", STYLE13);
4041
+ injectStyle("bb-symbol-dialog", STYLE16);
3416
4042
  let recent = [...options.recent ?? []].slice(0, RECENT_MAX);
3417
4043
  let selected = null;
3418
4044
  const root = el2("div", "bb-sd");
@@ -3601,9 +4227,9 @@ function createSymbolDialog(options) {
3601
4227
  function renderRecent() {
3602
4228
  fillGrid(
3603
4229
  recentGrid,
3604
- recent.map((c) => ({
3605
- char: c,
3606
- name: SYMBOL_NAMES.get(c) ?? "Character"
4230
+ recent.map((c2) => ({
4231
+ char: c2,
4232
+ name: SYMBOL_NAMES.get(c2) ?? "Character"
3607
4233
  })),
3608
4234
  RECENT_COLS,
3609
4235
  "Nothing yet \u2014 inserted symbols appear here."
@@ -3647,7 +4273,7 @@ function createSymbolDialog(options) {
3647
4273
  code.removeAttribute("aria-invalid");
3648
4274
  const cell = Array.from(
3649
4275
  grid.querySelectorAll(".bb-sd-cell")
3650
- ).find((c) => c.textContent === glyphFor(ch));
4276
+ ).find((c2) => c2.textContent === glyphFor(ch));
3651
4277
  select2(ch, cell ?? null);
3652
4278
  } else {
3653
4279
  code.setAttribute("aria-invalid", code.value.trim() ? "true" : "false");
@@ -3690,7 +4316,7 @@ function createSymbolDialog(options) {
3690
4316
  }
3691
4317
 
3692
4318
  // packages/ui/src/lib/symbol-popover.ts
3693
- var STYLE14 = `
4319
+ var STYLE17 = `
3694
4320
  .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}
3695
4321
  .bb-spk *{box-sizing:border-box}
3696
4322
  .bb-spk::backdrop{background:transparent}
@@ -3723,7 +4349,7 @@ function el3(tag, cls, text) {
3723
4349
  return n;
3724
4350
  }
3725
4351
  function openSymbolPopover(options) {
3726
- injectStyle("bb-ui-symbol-popover", STYLE14);
4352
+ injectStyle("bb-ui-symbol-popover", STYLE17);
3727
4353
  const { anchor } = options;
3728
4354
  let recent = [...options.recent ?? []].slice(0, RECENT_MAX);
3729
4355
  let groupId = SYMBOL_GROUPS[0].id;
@@ -3754,16 +4380,16 @@ function openSymbolPopover(options) {
3754
4380
  const chips = el3("div", "bb-spk-chips");
3755
4381
  const chipEls = /* @__PURE__ */ new Map();
3756
4382
  for (const grp of SYMBOL_GROUPS) {
3757
- const c = el3("button", "bb-spk-chip", grp.short);
3758
- c.type = "button";
3759
- c.title = grp.label;
3760
- c.addEventListener("click", () => {
4383
+ const c2 = el3("button", "bb-spk-chip", grp.short);
4384
+ c2.type = "button";
4385
+ c2.title = grp.label;
4386
+ c2.addEventListener("click", () => {
3761
4387
  groupId = grp.id;
3762
4388
  search.value = "";
3763
4389
  render();
3764
4390
  });
3765
- chips.append(c);
3766
- chipEls.set(grp.id, c);
4391
+ chips.append(c2);
4392
+ chipEls.set(grp.id, c2);
3767
4393
  }
3768
4394
  const grid = el3("div", "bb-spk-grid");
3769
4395
  grid.setAttribute("role", "grid");
@@ -3834,9 +4460,9 @@ function openSymbolPopover(options) {
3834
4460
  };
3835
4461
  const renderRecent = () => fill(
3836
4462
  recentGrid,
3837
- recent.slice(0, RECENT_ROW).map((c) => ({
3838
- char: c,
3839
- name: SYMBOL_NAMES.get(c) ?? "Character"
4463
+ recent.slice(0, RECENT_ROW).map((c2) => ({
4464
+ char: c2,
4465
+ name: SYMBOL_NAMES.get(c2) ?? "Character"
3840
4466
  })),
3841
4467
  "Nothing yet."
3842
4468
  );
@@ -3844,8 +4470,8 @@ function openSymbolPopover(options) {
3844
4470
  const q = search.value.trim();
3845
4471
  const byCode = q ? parseCodePoint(q) : null;
3846
4472
  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 ?? [];
3847
- for (const [id, c] of chipEls)
3848
- c.setAttribute("aria-pressed", String(!q && id === groupId));
4473
+ for (const [id, c2] of chipEls)
4474
+ c2.setAttribute("aria-pressed", String(!q && id === groupId));
3849
4475
  fill(grid, entries, "No match.");
3850
4476
  const first = grid.querySelector(".bb-spk-cell");
3851
4477
  if (q && first && entries[0]) select2(entries[0].char, first);
@@ -3884,8 +4510,8 @@ function openSymbolPopover(options) {
3884
4510
  }
3885
4511
 
3886
4512
  // packages/ui/src/lib/shortcuts-dialog.ts
3887
- var import_bapbong_contracts3 = require("@shadow-garden/bapbong-contracts");
3888
- var STYLE15 = `
4513
+ var import_bapbong_contracts6 = require("@shadow-garden/bapbong-contracts");
4514
+ var STYLE18 = `
3889
4515
  .bb-ks{display:flex;flex-direction:column;gap:10px;width:600px;max-width:100%;color:var(--bb-ui-fg,#2c2c2a);font-size:12px}
3890
4516
  .bb-ks *{box-sizing:border-box}
3891
4517
  .bb-ks-top{display:flex;gap:8px;align-items:center}
@@ -3943,7 +4569,7 @@ function highlight(text, q) {
3943
4569
  return out;
3944
4570
  }
3945
4571
  function openKeyboardShortcutsDialog(options) {
3946
- injectStyle("bb-ui-shortcuts-dialog", STYLE15);
4572
+ injectStyle("bb-ui-shortcuts-dialog", STYLE18);
3947
4573
  const dialog = new Dialog({
3948
4574
  title: options.title ?? "Keyboard shortcuts",
3949
4575
  modal: true,
@@ -3970,19 +4596,19 @@ function openKeyboardShortcutsDialog(options) {
3970
4596
  let sortKey = "title";
3971
4597
  let sortAsc = true;
3972
4598
  const ths = /* @__PURE__ */ new Map();
3973
- for (const c of columns) {
4599
+ for (const c2 of columns) {
3974
4600
  const th = el4("th");
3975
- th.append(el4("span", void 0, c.label));
4601
+ th.append(el4("span", void 0, c2.label));
3976
4602
  th.addEventListener("click", () => {
3977
- if (sortKey === c.key) sortAsc = !sortAsc;
4603
+ if (sortKey === c2.key) sortAsc = !sortAsc;
3978
4604
  else {
3979
- sortKey = c.key;
4605
+ sortKey = c2.key;
3980
4606
  sortAsc = true;
3981
4607
  }
3982
4608
  render();
3983
4609
  });
3984
4610
  headRow.append(th);
3985
- ths.set(c.key, th);
4611
+ ths.set(c2.key, th);
3986
4612
  }
3987
4613
  thead.append(headRow);
3988
4614
  const tbody = el4("tbody");
@@ -4002,7 +4628,7 @@ function openKeyboardShortcutsDialog(options) {
4002
4628
  const rows = [];
4003
4629
  for (const src of options.sources)
4004
4630
  rows.push(
4005
- ...(0, import_bapbong_contracts3.keybindingRows)(src.keybindings, (c) => src.commands.get(c)?.title)
4631
+ ...(0, import_bapbong_contracts6.keybindingRows)(src.keybindings, (c2) => src.commands.get(c2)?.title)
4006
4632
  );
4007
4633
  return rows;
4008
4634
  };
@@ -4010,13 +4636,13 @@ function openKeyboardShortcutsDialog(options) {
4010
4636
  const td = el4("td");
4011
4637
  keys.forEach((k, i) => {
4012
4638
  if (i > 0) td.append(el4("span", "or", "or"));
4013
- for (const part of (0, import_bapbong_contracts3.formatKey)(k, IS_MAC))
4639
+ for (const part of (0, import_bapbong_contracts6.formatKey)(k, IS_MAC))
4014
4640
  td.append(el4("kbd", void 0, part));
4015
4641
  });
4016
4642
  return td;
4017
4643
  };
4018
4644
  const sortRows = (rows) => {
4019
- const val = (r) => sortKey === "title" ? r.title : sortKey === "keys" ? r.keys.map((k) => (0, import_bapbong_contracts3.formatKey)(k, IS_MAC).join("")).join(" ") : sortKey === "when" ? r.when ?? "" : r.source;
4645
+ const val = (r) => sortKey === "title" ? r.title : sortKey === "keys" ? r.keys.map((k) => (0, import_bapbong_contracts6.formatKey)(k, IS_MAC).join("")).join(" ") : sortKey === "when" ? r.when ?? "" : r.source;
4020
4646
  const sorted = [...rows].sort(
4021
4647
  (a, b) => val(a).localeCompare(val(b), void 0, { sensitivity: "base" })
4022
4648
  );
@@ -4025,7 +4651,7 @@ function openKeyboardShortcutsDialog(options) {
4025
4651
  const render = () => {
4026
4652
  const q = search.value.trim().toLowerCase();
4027
4653
  const rows = allRows();
4028
- const shown = sortRows((0, import_bapbong_contracts3.filterKeybindingRows)(rows, q, IS_MAC));
4654
+ const shown = sortRows((0, import_bapbong_contracts6.filterKeybindingRows)(rows, q, IS_MAC));
4029
4655
  for (const [key, th] of ths) {
4030
4656
  if (key === sortKey)
4031
4657
  th.setAttribute("aria-sort", sortAsc ? "ascending" : "descending");
@@ -4059,7 +4685,7 @@ function openKeyboardShortcutsDialog(options) {
4059
4685
  tbody.append(tr);
4060
4686
  }
4061
4687
  count.textContent = shown.length === rows.length ? `${rows.length} shortcuts` : `${shown.length} of ${rows.length}`;
4062
- footL.textContent = `Sorted by ${columns.find((c) => c.key === sortKey)?.label.toLowerCase()} \xB7 click a header to sort`;
4688
+ footL.textContent = `Sorted by ${columns.find((c2) => c2.key === sortKey)?.label.toLowerCase()} \xB7 click a header to sort`;
4063
4689
  };
4064
4690
  search.addEventListener("input", render);
4065
4691
  dialog.onClose(() => dialog.destroy());
@@ -4069,7 +4695,7 @@ function openKeyboardShortcutsDialog(options) {
4069
4695
  }
4070
4696
 
4071
4697
  // packages/ui/src/lib/scrollbars.ts
4072
- var STYLE16 = `
4698
+ var STYLE19 = `
4073
4699
  @property --bb-scroll-thumb-now {
4074
4700
  syntax: '<color>';
4075
4701
  /* MUST inherit: the thumb pseudo-element never matches .bb-scrolling
@@ -4101,7 +4727,7 @@ var STYLE16 = `
4101
4727
  var installed = null;
4102
4728
  function installScrollbars(root = document) {
4103
4729
  if (installed) return installed;
4104
- injectStyle("bb-ui-scrollbars", STYLE16);
4730
+ injectStyle("bb-ui-scrollbars", STYLE19);
4105
4731
  const quiet = /* @__PURE__ */ new WeakMap();
4106
4732
  const onScroll = (ev) => {
4107
4733
  const el5 = ev.target instanceof HTMLElement ? ev.target : root.documentElement;
@@ -4121,6 +4747,7 @@ function installScrollbars(root = document) {
4121
4747
  }
4122
4748
  // Annotate the CommonJS export names for ESM import in node:
4123
4749
  0 && (module.exports = {
4750
+ BUILT_IN_EQUATIONS,
4124
4751
  COLOR_PALETTE,
4125
4752
  Dialog,
4126
4753
  RECENT_MAX,
@@ -4133,8 +4760,13 @@ function installScrollbars(root = document) {
4133
4760
  createFindDialog,
4134
4761
  createSectionChip,
4135
4762
  createSymbolDialog,
4763
+ createTableStylePanel,
4136
4764
  defaultMenus,
4137
4765
  defaultToolbarGroups,
4766
+ equationGallery,
4767
+ equationPanel,
4768
+ equationPreviewSvg,
4769
+ foldPlan,
4138
4770
  installScrollbars,
4139
4771
  marginPresetPicker,
4140
4772
  mountMenubar,