@shadow-garden/bapbong-ui 0.15.0 → 0.16.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
@@ -32,12 +32,12 @@ function placeFloating(el5, anchor) {
32
32
  }
33
33
  function rovingGrid(cells) {
34
34
  let cur = [0, 0];
35
- const at = (r, c) => cells[r]?.[c];
36
- const focusCell = (r, c) => {
35
+ const at = (r, c2) => cells[r]?.[c2];
36
+ const focusCell = (r, c2) => {
37
37
  const rows = cells.length;
38
38
  if (rows === 0) return;
39
39
  const nr = Math.min(rows - 1, Math.max(0, r));
40
- const nc = Math.min(cells[nr].length - 1, Math.max(0, c));
40
+ const nc = Math.min(cells[nr].length - 1, Math.max(0, c2));
41
41
  const prev = at(cur[0], cur[1]);
42
42
  if (prev) prev.tabIndex = -1;
43
43
  const next = at(nr, nc);
@@ -47,9 +47,9 @@ function rovingGrid(cells) {
47
47
  cur = [nr, nc];
48
48
  };
49
49
  cells.forEach(
50
- (row, r) => row.forEach((cell, c) => {
50
+ (row, r) => row.forEach((cell, c2) => {
51
51
  cell.setAttribute("role", "gridcell");
52
- cell.tabIndex = r === 0 && c === 0 ? 0 : -1;
52
+ cell.tabIndex = r === 0 && c2 === 0 ? 0 : -1;
53
53
  cell.addEventListener("keydown", (e) => {
54
54
  const delta = {
55
55
  ArrowRight: [0, 1],
@@ -62,10 +62,10 @@ function rovingGrid(cells) {
62
62
  const d = delta[e.key];
63
63
  if (!d) return;
64
64
  e.preventDefault();
65
- focusCell(r + d[0], c + d[1]);
65
+ focusCell(r + d[0], c2 + d[1]);
66
66
  });
67
67
  cell.addEventListener("focus", () => {
68
- cur = [r, c];
68
+ cur = [r, c2];
69
69
  });
70
70
  })
71
71
  );
@@ -395,9 +395,9 @@ function openColorPicker({
395
395
  panel.remove();
396
396
  anchor.focus();
397
397
  };
398
- const pick = (c) => {
399
- if (c && !COLOR_PALETTE.some((row) => row.includes(c))) remember(c);
400
- onPick(c);
398
+ const pick = (c2) => {
399
+ if (c2 && !COLOR_PALETTE.some((row) => row.includes(c2))) remember(c2);
400
+ onPick(c2);
401
401
  close();
402
402
  };
403
403
  if (clearLabel !== void 0) {
@@ -441,15 +441,15 @@ function openColorPicker({
441
441
  );
442
442
  const customRow2 = document.createElement("div");
443
443
  customRow2.className = "bb-cpk-row";
444
- for (const c of customColors) {
444
+ for (const c2 of customColors) {
445
445
  const sw = document.createElement("button");
446
446
  sw.type = "button";
447
447
  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));
448
+ sw.style.background = c2;
449
+ sw.title = c2;
450
+ sw.setAttribute("aria-label", c2);
451
+ if (c2.toUpperCase() === value?.toUpperCase()) sw.classList.add("on");
452
+ sw.addEventListener("click", () => pick(c2));
453
453
  customRow2.append(sw);
454
454
  }
455
455
  const plus = document.createElement("button");
@@ -533,8 +533,8 @@ function colorButton(o) {
533
533
  anchor: el5,
534
534
  value: o.value(),
535
535
  clearLabel: o.clearLabel,
536
- onPick: (c) => {
537
- o.onPick(c);
536
+ onPick: (c2) => {
537
+ o.onPick(c2);
538
538
  sync();
539
539
  }
540
540
  });
@@ -645,7 +645,7 @@ var STYLE3 = `
645
645
  .bb-split-bar{flex:1;height:3px;border-radius:2px;background:var(--bb-ui-border,#d9d9d4)}
646
646
  `;
647
647
  function defaultToolbarGroups(commands) {
648
- const names = [...commands].map((c) => c.name);
648
+ const names = [...commands].map((c2) => c2.name);
649
649
  const aligns = names.filter((n) => n.startsWith("align-"));
650
650
  const rest = names.filter((n) => !n.startsWith("align-"));
651
651
  return [rest, aligns].filter((g2) => g2.length > 0);
@@ -895,7 +895,7 @@ function mountToolbar(host, editor, options = {}) {
895
895
  el5.disabled = cmd.isEnabled ? !cmd.isEnabled(state) : false;
896
896
  }
897
897
  for (const { spec, el: el5 } of selects) el5.value = spec.value(state);
898
- for (const c of colors) c.sync();
898
+ for (const c2 of colors) c2.sync();
899
899
  for (const { spec, cards } of splits) {
900
900
  const selected = spec.value(state);
901
901
  for (const card of cards)
@@ -905,7 +905,7 @@ function mountToolbar(host, editor, options = {}) {
905
905
  );
906
906
  }
907
907
  };
908
- const off = editor.onChange((c) => refresh(c.state));
908
+ const off = editor.onChange((c2) => refresh(c2.state));
909
909
  try {
910
910
  refresh(editor.state);
911
911
  } catch {
@@ -1149,7 +1149,7 @@ function showMenu(entries, at, options = {}) {
1149
1149
  return handle;
1150
1150
  }
1151
1151
  function defaultMenus(commands) {
1152
- const names = [...commands].map((c) => c.name);
1152
+ const names = [...commands].map((c2) => c2.name);
1153
1153
  const marks = ["bold", "italic", "underline", "strike"].filter(
1154
1154
  (n) => commands.has(n)
1155
1155
  );
@@ -1263,10 +1263,10 @@ function mountMenubar(host, editor, options = {}) {
1263
1263
  function refresh(state) {
1264
1264
  latest = state;
1265
1265
  if (openIdx < 0) return;
1266
- for (const c of checks) c.el.textContent = c.active(state) ? "\u2713" : "";
1266
+ for (const c2 of checks) c2.el.textContent = c2.active(state) ? "\u2713" : "";
1267
1267
  for (const e of enables) e.el.disabled = !e.enabled(state);
1268
1268
  }
1269
- const off = editor.onChange((c) => refresh(c.state));
1269
+ const off = editor.onChange((c2) => refresh(c2.state));
1270
1270
  try {
1271
1271
  latest = editor.state;
1272
1272
  } catch {
@@ -1594,13 +1594,13 @@ function showLinkPanel(opts) {
1594
1594
  row.appendChild(icon);
1595
1595
  const label = document.createElement("span");
1596
1596
  label.className = "bb-linkpanel-href";
1597
- label.textContent = internal.label ?? "V\u1ECB tr\xED kh\xF4ng c\xF2n trong t\xE0i li\u1EC7u";
1597
+ label.textContent = internal.label ?? "This place is no longer in the document";
1598
1598
  label.title = internal.label ?? existing.href;
1599
1599
  if (!internal.label) label.classList.add("bb-linkpanel-stale");
1600
1600
  row.appendChild(label);
1601
1601
  if (internal.label) {
1602
1602
  row.appendChild(
1603
- iconBtn(ICONS.goTo, "\u0110i t\u1EDBi v\u1ECB tr\xED n\xE0y", () => {
1603
+ iconBtn(ICONS.goTo, "Go to this place", () => {
1604
1604
  closeCurrent2();
1605
1605
  internal.onGo();
1606
1606
  })
@@ -1814,8 +1814,8 @@ function openCellProperties({
1814
1814
  label: "Fill",
1815
1815
  clearLabel: "No fill",
1816
1816
  value: () => background,
1817
- onPick: (c) => {
1818
- background = c;
1817
+ onPick: (c2) => {
1818
+ background = c2;
1819
1819
  }
1820
1820
  });
1821
1821
  fill.append(fillBtn.el);
@@ -1868,8 +1868,8 @@ function openCellProperties({
1868
1868
  title: "Border colour",
1869
1869
  label: "Colour",
1870
1870
  value: () => penColor,
1871
- onPick: (c) => {
1872
- if (c) penColor = c;
1871
+ onPick: (c2) => {
1872
+ if (c2) penColor = c2;
1873
1873
  }
1874
1874
  });
1875
1875
  penRow.append(widthSel, styleSel, penBtn.el);
@@ -1933,8 +1933,400 @@ function openCellProperties({
1933
1933
  dialog.open();
1934
1934
  }
1935
1935
 
1936
- // packages/ui/src/lib/table-grid.ts
1936
+ // packages/ui/src/lib/equation-gallery.ts
1937
+ import { astToLinear } from "@shadow-garden/bapbong-contracts";
1938
+ var c = (s) => [...s].map((ch) => ({ t: "chr", ch }));
1939
+ var sup = (base, exp) => ({
1940
+ t: "scr",
1941
+ base,
1942
+ sub: [],
1943
+ sup: c(exp)
1944
+ });
1945
+ var subsup = (base, lo, hi) => ({
1946
+ t: "scr",
1947
+ base,
1948
+ sub: c(lo),
1949
+ sup: c(hi)
1950
+ });
1951
+ var BUILT_IN_EQUATIONS = [
1952
+ {
1953
+ name: "Area of a circle",
1954
+ ast: [...c("\u{1D434} = \u{1D70B}"), sup(c("\u{1D45F}"), "2")]
1955
+ },
1956
+ {
1957
+ name: "Pythagorean theorem",
1958
+ ast: [
1959
+ sup(c("\u{1D44E}"), "2"),
1960
+ ...c(" + "),
1961
+ sup(c("\u{1D44F}"), "2"),
1962
+ ...c(" = "),
1963
+ sup(c("\u{1D450}"), "2")
1964
+ ]
1965
+ },
1966
+ {
1967
+ name: "Quadratic formula",
1968
+ ast: [
1969
+ ...c("\u{1D465} = "),
1970
+ {
1971
+ t: "frac",
1972
+ num: [
1973
+ ...c("\u2212\u{1D44F} \xB1 "),
1974
+ {
1975
+ t: "rad",
1976
+ deg: [],
1977
+ body: [sup(c("\u{1D44F}"), "2"), ...c(" \u2212 4\u{1D44E}\u{1D450}")]
1978
+ }
1979
+ ],
1980
+ den: c("2\u{1D44E}")
1981
+ }
1982
+ ]
1983
+ },
1984
+ {
1985
+ name: "Law of cosines",
1986
+ ast: [
1987
+ sup(c("\u{1D44E}"), "2"),
1988
+ ...c(" = "),
1989
+ sup(c("\u{1D44F}"), "2"),
1990
+ ...c(" + "),
1991
+ sup(c("\u{1D450}"), "2"),
1992
+ ...c(" \u2212 2\u{1D44F}\u{1D450} cos \u{1D434}")
1993
+ ]
1994
+ },
1995
+ {
1996
+ name: "Binomial theorem",
1997
+ ast: [
1998
+ // The exponent belongs ON the bracket: a script with an empty base
1999
+ // would render its own empty slot — the dotted placeholder box.
2000
+ {
2001
+ t: "scr",
2002
+ base: [{ t: "fence", l: "(", r: ")", body: c("\u{1D44E} + \u{1D44F}") }],
2003
+ sub: [],
2004
+ sup: c("\u{1D45B}")
2005
+ },
2006
+ ...c(" = "),
2007
+ {
2008
+ t: "big",
2009
+ op: "\u2211",
2010
+ lo: c("\u{1D458} = 0"),
2011
+ hi: c("\u{1D45B}"),
2012
+ body: [
2013
+ subsup(c("\u{1D436}"), "\u{1D45B}", "\u{1D458}"),
2014
+ sup(c("\u{1D44E}"), "\u{1D458}"),
2015
+ { t: "scr", base: c("\u{1D44F}"), sub: [], sup: c("\u{1D45B}\u2212\u{1D458}") }
2016
+ ]
2017
+ }
2018
+ ]
2019
+ }
2020
+ ];
2021
+ var SVG_NS = "http://www.w3.org/2000/svg";
2022
+ function equationPreviewSvg(spec, opts = {}) {
2023
+ const svg = document.createElementNS(SVG_NS, "svg");
2024
+ svg.setAttribute("viewBox", `0 0 ${spec.width} ${spec.height}`);
2025
+ const max = opts.maxWidth ?? spec.width;
2026
+ const scale = Math.min(1, max / Math.max(1, spec.width));
2027
+ svg.setAttribute("width", String(Math.round(spec.width * scale)));
2028
+ svg.setAttribute("height", String(Math.round(spec.height * scale)));
2029
+ svg.setAttribute("aria-hidden", "true");
2030
+ for (const op of spec.ops) svg.append(opElement(op));
2031
+ return svg;
2032
+ }
2033
+ function opElement(op) {
2034
+ if (op.kind === "line") {
2035
+ const el6 = document.createElementNS(SVG_NS, "line");
2036
+ el6.setAttribute("x1", String(op.x1));
2037
+ el6.setAttribute("y1", String(op.y1));
2038
+ el6.setAttribute("x2", String(op.x2));
2039
+ el6.setAttribute("y2", String(op.y2));
2040
+ el6.setAttribute("stroke", op.color);
2041
+ el6.setAttribute("stroke-width", String(Math.max(op.width, 0.75)));
2042
+ return el6;
2043
+ }
2044
+ if (op.kind === "polygon") {
2045
+ const el6 = document.createElementNS(SVG_NS, "polygon");
2046
+ el6.setAttribute("points", op.points.map((p) => `${p.x},${p.y}`).join(" "));
2047
+ el6.setAttribute("fill", op.fill ?? "none");
2048
+ if (op.stroke) {
2049
+ el6.setAttribute("stroke", op.stroke);
2050
+ el6.setAttribute("stroke-width", String(op.strokeWidth ?? 1));
2051
+ }
2052
+ return el6;
2053
+ }
2054
+ const el5 = document.createElementNS(SVG_NS, "text");
2055
+ el5.setAttribute("x", String(op.x));
2056
+ el5.setAttribute("y", String(op.y));
2057
+ el5.setAttribute("font-size", String(op.size));
2058
+ el5.setAttribute("font-family", op.family);
2059
+ el5.setAttribute("fill", op.color);
2060
+ if (op.bold) el5.setAttribute("font-weight", "bold");
2061
+ if (op.italic) el5.setAttribute("font-style", "italic");
2062
+ if (op.vAlign === "top") el5.setAttribute("dominant-baseline", "hanging");
2063
+ if (op.dx) {
2064
+ let x = op.x;
2065
+ for (const [i, ch] of [...op.text].entries()) {
2066
+ const t = document.createElementNS(SVG_NS, "tspan");
2067
+ t.setAttribute("x", String(x));
2068
+ t.textContent = ch;
2069
+ el5.append(t);
2070
+ x += op.dx[i] ?? 0;
2071
+ }
2072
+ } else {
2073
+ el5.textContent = op.text;
2074
+ }
2075
+ return el5;
2076
+ }
1937
2077
  var STYLE9 = `
2078
+ .bb-eqg{display:flex;flex-direction:column;min-width:236px;max-width:300px;user-select:none}
2079
+ .bb-eqg-head{font-size:11px;font-weight:600;opacity:.55;padding:2px 8px 6px}
2080
+ .bb-eqg-list{display:flex;flex-direction:column;max-height:320px;overflow-y:auto}
2081
+ .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}
2082
+ .bb-eqg-item:hover{background:var(--bb-ui-hover,#f1efe8)}
2083
+ .bb-eqg-name{font-size:11px;opacity:.6}
2084
+ /* The preview is the equation TYPESET \u2014 the same display list the canvas
2085
+ paints. The text form is the fallback for a host that cannot lay out. */
2086
+ .bb-eqg-prev{display:flex;align-items:center;min-height:22px;max-width:100%;overflow:hidden}
2087
+ .bb-eqg-prev svg{display:block}
2088
+ .bb-eqg-prev-text{font-family:"Times New Roman",Tinos,serif;font-size:15px;line-height:1.35;white-space:nowrap;text-overflow:ellipsis}
2089
+ .bb-eqg-foot{margin-top:4px;padding-top:5px;border-top:1px solid var(--bb-ui-border,#e3e3e0)}
2090
+ .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}
2091
+ .bb-eqg-new:hover{background:var(--bb-ui-hover,#f1efe8)}
2092
+ .bb-eqg-key{margin-left:auto;opacity:.5;font-size:12px}
2093
+ `;
2094
+ var PREVIEW_PT = 11;
2095
+ var PREVIEW_MAX_W = 264;
2096
+ function equationGallery(options) {
2097
+ injectStyle("bb-ui-eqg-styles", STYLE9);
2098
+ const root = document.createElement("div");
2099
+ root.className = "bb-eqg";
2100
+ const head = document.createElement("div");
2101
+ head.className = "bb-eqg-head";
2102
+ head.textContent = "Built-in";
2103
+ root.append(head);
2104
+ const list = document.createElement("div");
2105
+ list.className = "bb-eqg-list";
2106
+ for (const item of options.items ?? BUILT_IN_EQUATIONS) {
2107
+ const btn = document.createElement("button");
2108
+ btn.type = "button";
2109
+ btn.className = "bb-eqg-item";
2110
+ const prev = document.createElement("div");
2111
+ prev.className = "bb-eqg-prev";
2112
+ const spec = options.layout?.(item.ast, PREVIEW_PT) ?? null;
2113
+ if (spec && spec.ops.length)
2114
+ prev.append(equationPreviewSvg(spec, { maxWidth: PREVIEW_MAX_W }));
2115
+ else {
2116
+ prev.classList.add("bb-eqg-prev-text");
2117
+ prev.textContent = astToLinear(item.ast);
2118
+ }
2119
+ const name = document.createElement("div");
2120
+ name.className = "bb-eqg-name";
2121
+ name.textContent = item.name;
2122
+ btn.append(prev, name);
2123
+ btn.addEventListener("mousedown", (e) => e.preventDefault());
2124
+ btn.addEventListener("click", () => options.onPick(item.ast));
2125
+ list.append(btn);
2126
+ }
2127
+ root.append(list);
2128
+ const foot = document.createElement("div");
2129
+ foot.className = "bb-eqg-foot";
2130
+ const neu = document.createElement("button");
2131
+ neu.type = "button";
2132
+ neu.className = "bb-eqg-new";
2133
+ const label = document.createElement("span");
2134
+ label.textContent = "Insert new equation";
2135
+ neu.append(label);
2136
+ if (options.newShortcut) {
2137
+ const key = document.createElement("span");
2138
+ key.className = "bb-eqg-key";
2139
+ key.textContent = options.newShortcut;
2140
+ neu.append(key);
2141
+ }
2142
+ neu.addEventListener("mousedown", (e) => e.preventDefault());
2143
+ neu.addEventListener("click", () => options.onNew());
2144
+ foot.append(neu);
2145
+ root.append(foot);
2146
+ return root;
2147
+ }
2148
+
2149
+ // packages/ui/src/lib/equation-panel.ts
2150
+ import {
2151
+ eqStructureGroups,
2152
+ MATH_AUTOCORRECT,
2153
+ MATH_SYMBOL_SETS
2154
+ } from "@shadow-garden/bapbong-contracts";
2155
+ var SHORTHAND = /* @__PURE__ */ new Map();
2156
+ for (const [name, ch] of Object.entries(MATH_AUTOCORRECT))
2157
+ if (!SHORTHAND.has(ch)) SHORTHAND.set(ch, `\\${name}`);
2158
+ var PREVIEW_PT2 = 10;
2159
+ var STYLE10 = `
2160
+ .bb-eqp{width:352px;display:flex;flex-direction:column;background:var(--bb-ui-bg,#fff);border:0.5px solid var(--bb-ui-border,#e3e3e0);border-radius:10px;box-shadow:0 4px 16px rgba(0,0,0,.13);user-select:none;overflow:hidden}
2161
+ .bb-eqp-tabs{display:flex;align-items:flex-end;gap:2px;padding:5px 5px 0;border-bottom:0.5px solid var(--bb-ui-border,#e3e3e0)}
2162
+ .bb-eqp.is-collapsed .bb-eqp-tabs{border-bottom:0}
2163
+ .bb-eqp-tab{padding:6px 11px;border:0;border-radius:6px 6px 0 0;background:transparent;color:inherit;font:inherit;font-size:13px;opacity:.65;cursor:pointer}
2164
+ .bb-eqp-tab:hover{background:var(--bb-ui-hover,#f1efe8)}
2165
+ .bb-eqp-tab[aria-selected="true"]{opacity:1;background:var(--bb-ui-sel,#e6f1fb);color:var(--bb-ui-sel-fg,#0c447c)}
2166
+ .bb-eqp-fold{margin-left:auto;margin-bottom:5px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;padding:0;border:0;border-radius:6px;background:transparent;color:inherit;opacity:.5;cursor:pointer}
2167
+ .bb-eqp-fold:hover{background:var(--bb-ui-hover,#f1efe8);opacity:.9}
2168
+ .bb-eqp-body{padding:8px}
2169
+ .bb-eqp.is-collapsed .bb-eqp-body{display:none}
2170
+ .bb-eqp-set{width:100%;height:30px;margin-bottom:7px;font:inherit;font-size:13px}
2171
+ .bb-eqp-grid{display:grid;grid-template-columns:repeat(10,1fr);gap:1px;max-height:190px;overflow-y:auto}
2172
+ .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}
2173
+ .bb-eqp-sym:hover{background:var(--bb-ui-hover,#f1efe8)}
2174
+ .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}
2175
+ .bb-eqp-hint-g{font-family:"Cambria Math","Times New Roman",Tinos,serif;font-size:15px}
2176
+ .bb-eqp-hint-k{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
2177
+ .bb-eqp-scroll{max-height:230px;overflow-y:auto}
2178
+ .bb-eqp-group{font-size:11px;font-weight:600;opacity:.5;padding:6px 2px 3px}
2179
+ .bb-eqp-row{display:grid;grid-template-columns:repeat(4,1fr);gap:3px}
2180
+ .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}
2181
+ .bb-eqp-st:hover{background:var(--bb-ui-hover,#f1efe8)}
2182
+ .bb-eqp-st-name{font-size:10px;opacity:.6;text-align:center;line-height:1.25}
2183
+ .bb-eqp-st svg{display:block}
2184
+ `;
2185
+ var CHEVRON_UP = '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 15l6-6 6 6"/></svg>';
2186
+ var CHEVRON_DOWN = '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 9l6 6 6-6"/></svg>';
2187
+ function equationPanel(options) {
2188
+ injectStyle("bb-ui-eqp-styles", STYLE10);
2189
+ const root = document.createElement("div");
2190
+ root.className = "bb-eqp";
2191
+ root.setAttribute("role", "group");
2192
+ root.setAttribute("aria-label", "Equation palette");
2193
+ root.addEventListener("mousedown", (e) => e.preventDefault());
2194
+ const tabs = document.createElement("div");
2195
+ tabs.className = "bb-eqp-tabs";
2196
+ tabs.setAttribute("role", "tablist");
2197
+ const body = document.createElement("div");
2198
+ body.className = "bb-eqp-body";
2199
+ let collapsed = false;
2200
+ let current3 = "symbols";
2201
+ const tabEls = {};
2202
+ const mkTab = (id, label) => {
2203
+ const b = document.createElement("button");
2204
+ b.type = "button";
2205
+ b.className = "bb-eqp-tab";
2206
+ b.textContent = label;
2207
+ b.setAttribute("role", "tab");
2208
+ b.addEventListener("click", () => {
2209
+ current3 = id;
2210
+ if (collapsed) setCollapsed(false);
2211
+ render();
2212
+ });
2213
+ tabEls[id] = b;
2214
+ tabs.append(b);
2215
+ };
2216
+ mkTab("symbols", "Symbols");
2217
+ mkTab("structures", "Structures");
2218
+ const fold = document.createElement("button");
2219
+ fold.type = "button";
2220
+ fold.className = "bb-eqp-fold";
2221
+ fold.addEventListener("click", () => setCollapsed(!collapsed));
2222
+ tabs.append(fold);
2223
+ root.append(tabs, body);
2224
+ function setCollapsed(next) {
2225
+ collapsed = next;
2226
+ root.classList.toggle("is-collapsed", collapsed);
2227
+ fold.innerHTML = collapsed ? CHEVRON_DOWN : CHEVRON_UP;
2228
+ fold.setAttribute(
2229
+ "aria-label",
2230
+ collapsed ? "Show palette" : "Hide palette"
2231
+ );
2232
+ fold.setAttribute("aria-expanded", String(!collapsed));
2233
+ }
2234
+ function symbolsBody() {
2235
+ const set = document.createElement("select");
2236
+ set.className = "bb-eqp-set";
2237
+ set.setAttribute("aria-label", "Symbol set");
2238
+ for (const [i, s] of MATH_SYMBOL_SETS.entries()) {
2239
+ const o = document.createElement("option");
2240
+ o.value = String(i);
2241
+ o.textContent = s.name;
2242
+ set.append(o);
2243
+ }
2244
+ set.value = String(setIndex);
2245
+ const grid = document.createElement("div");
2246
+ grid.className = "bb-eqp-grid";
2247
+ const hint = document.createElement("div");
2248
+ hint.className = "bb-eqp-hint";
2249
+ const hintG = document.createElement("span");
2250
+ hintG.className = "bb-eqp-hint-g";
2251
+ const hintK = document.createElement("span");
2252
+ hintK.className = "bb-eqp-hint-k";
2253
+ hint.append(hintG, hintK);
2254
+ const fill = () => {
2255
+ grid.replaceChildren();
2256
+ const chars = MATH_SYMBOL_SETS[setIndex]?.chars ?? "";
2257
+ for (const ch of chars) {
2258
+ const b = document.createElement("button");
2259
+ b.type = "button";
2260
+ b.className = "bb-eqp-sym";
2261
+ b.textContent = ch;
2262
+ const key = SHORTHAND.get(ch);
2263
+ b.title = key ? `${ch} ${key}` : ch;
2264
+ b.addEventListener("mouseenter", () => {
2265
+ hintG.textContent = ch;
2266
+ hintK.textContent = key ?? "";
2267
+ });
2268
+ b.addEventListener("click", () => options.onSymbol(ch));
2269
+ grid.append(b);
2270
+ }
2271
+ };
2272
+ set.addEventListener("change", () => {
2273
+ setIndex = Number(set.value) || 0;
2274
+ fill();
2275
+ });
2276
+ fill();
2277
+ body.replaceChildren(set, grid, hint);
2278
+ }
2279
+ function structuresBody() {
2280
+ const scroll = document.createElement("div");
2281
+ scroll.className = "bb-eqp-scroll";
2282
+ for (const group of eqStructureGroups()) {
2283
+ const h = document.createElement("div");
2284
+ h.className = "bb-eqp-group";
2285
+ h.textContent = group.name;
2286
+ const row = document.createElement("div");
2287
+ row.className = "bb-eqp-row";
2288
+ for (const item of group.items) {
2289
+ const b = document.createElement("button");
2290
+ b.type = "button";
2291
+ b.className = "bb-eqp-st";
2292
+ b.title = `${group.name} \u2014 ${item.name}`;
2293
+ const spec = options.layout?.([item.node], PREVIEW_PT2) ?? null;
2294
+ if (spec && spec.ops.length)
2295
+ b.append(equationPreviewSvg(spec, { maxWidth: 60 }));
2296
+ const name = document.createElement("span");
2297
+ name.className = "bb-eqp-st-name";
2298
+ name.textContent = item.name;
2299
+ b.append(name);
2300
+ b.addEventListener("click", () => options.onStructure(item));
2301
+ row.append(b);
2302
+ }
2303
+ scroll.append(h, row);
2304
+ }
2305
+ body.replaceChildren(scroll);
2306
+ }
2307
+ let setIndex = 0;
2308
+ function render() {
2309
+ for (const [id, el5] of Object.entries(tabEls))
2310
+ el5.setAttribute("aria-selected", String(id === current3));
2311
+ if (current3 === "symbols") symbolsBody();
2312
+ else structuresBody();
2313
+ }
2314
+ setCollapsed(false);
2315
+ render();
2316
+ return {
2317
+ el: root,
2318
+ setCollapsed,
2319
+ get collapsed() {
2320
+ return collapsed;
2321
+ },
2322
+ destroy() {
2323
+ root.remove();
2324
+ }
2325
+ };
2326
+ }
2327
+
2328
+ // packages/ui/src/lib/table-grid.ts
2329
+ var STYLE11 = `
1938
2330
  .bb-grid{display:flex;flex-direction:column;gap:6px;user-select:none}
1939
2331
  .bb-grid-cells{display:grid;gap:2px}
1940
2332
  .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 +2334,7 @@ var STYLE9 = `
1942
2334
  .bb-grid-label{font-size:12px;text-align:center;opacity:.7}
1943
2335
  `;
1944
2336
  function tableGridPicker(options) {
1945
- injectStyle("bb-ui-grid-styles", STYLE9);
2337
+ injectStyle("bb-ui-grid-styles", STYLE11);
1946
2338
  const maxRows = options.maxRows ?? 8;
1947
2339
  const maxCols = options.maxCols ?? 10;
1948
2340
  const root = document.createElement("div");
@@ -1954,22 +2346,22 @@ function tableGridPicker(options) {
1954
2346
  label.className = "bb-grid-label";
1955
2347
  label.textContent = "0 \xD7 0";
1956
2348
  const cells = [];
1957
- const highlight2 = (r, c) => {
2349
+ const highlight2 = (r, c2) => {
1958
2350
  for (let i = 0; i < cells.length; i++) {
1959
2351
  const row = Math.floor(i / maxCols);
1960
2352
  const col = i % maxCols;
1961
- cells[i].classList.toggle("on", row <= r && col <= c);
2353
+ cells[i].classList.toggle("on", row <= r && col <= c2);
1962
2354
  }
1963
- label.textContent = `${r + 1} \xD7 ${c + 1}`;
2355
+ label.textContent = `${r + 1} \xD7 ${c2 + 1}`;
1964
2356
  };
1965
2357
  for (let r = 0; r < maxRows; r++) {
1966
- for (let c = 0; c < maxCols; c++) {
2358
+ for (let c2 = 0; c2 < maxCols; c2++) {
1967
2359
  const cell = document.createElement("button");
1968
2360
  cell.type = "button";
1969
2361
  cell.className = "bb-grid-cell";
1970
2362
  cell.addEventListener("mousedown", (e) => e.preventDefault());
1971
- cell.addEventListener("mouseenter", () => highlight2(r, c));
1972
- cell.addEventListener("click", () => options.onPick(r + 1, c + 1));
2363
+ cell.addEventListener("mouseenter", () => highlight2(r, c2));
2364
+ cell.addEventListener("click", () => options.onPick(r + 1, c2 + 1));
1973
2365
  cells.push(cell);
1974
2366
  cellsEl.appendChild(cell);
1975
2367
  }
@@ -1985,7 +2377,7 @@ var cmToPx = (cm) => Math.round(cm * PX_PER_CM);
1985
2377
  function fmtCm(cm) {
1986
2378
  return `${Number(cm.toFixed(3))} cm`;
1987
2379
  }
1988
- var STYLE10 = `
2380
+ var STYLE12 = `
1989
2381
  .bb-ps{display:flex;flex-direction:column;min-width:250px;max-height:min(70vh,460px);overflow-y:auto}
1990
2382
  .bb-ps,.bb-ps *{box-sizing:border-box}
1991
2383
  .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 +2407,9 @@ var STYLE10 = `
2015
2407
  .bb-ps-tile:hover,.bb-ps-tile:focus{background:var(--bb-ui-hover,#f1efe8);outline:none}
2016
2408
  .bb-ps-tile[aria-checked="true"]{background:var(--bb-ui-active-bg,#e6f1fb)}
2017
2409
  `;
2018
- var SVG_NS = "http://www.w3.org/2000/svg";
2410
+ var SVG_NS2 = "http://www.w3.org/2000/svg";
2019
2411
  function svgEl(name, attrs) {
2020
- const el5 = document.createElementNS(SVG_NS, name);
2412
+ const el5 = document.createElementNS(SVG_NS2, name);
2021
2413
  for (const [k, v] of Object.entries(attrs)) el5.setAttribute(k, String(v));
2022
2414
  return el5;
2023
2415
  }
@@ -2111,7 +2503,7 @@ function customRow(icon, title, description, onPick) {
2111
2503
  return presetRow(icon, title, captionLine(description), false, onPick);
2112
2504
  }
2113
2505
  function pageSizePicker(options) {
2114
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2506
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2115
2507
  const root = document.createElement("div");
2116
2508
  root.className = "bb-ps";
2117
2509
  root.setAttribute("role", "menu");
@@ -2140,7 +2532,7 @@ function pageSizePicker(options) {
2140
2532
  return root;
2141
2533
  }
2142
2534
  function orientationPicker(options) {
2143
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2535
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2144
2536
  const root = document.createElement("div");
2145
2537
  root.className = "bb-ps";
2146
2538
  root.setAttribute("role", "menu");
@@ -2163,7 +2555,7 @@ function orientationPicker(options) {
2163
2555
  return root;
2164
2556
  }
2165
2557
  function marginPresetPicker(options) {
2166
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2558
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2167
2559
  const root = document.createElement("div");
2168
2560
  root.className = "bb-ps";
2169
2561
  root.setAttribute("role", "menu");
@@ -2238,7 +2630,7 @@ function readPx(input, fallbackPx) {
2238
2630
  return Number.isFinite(n) && n > 0 ? cmToPx(n) : fallbackPx;
2239
2631
  }
2240
2632
  function openPageSizeDialog(options) {
2241
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2633
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2242
2634
  const dialog = new Dialog({ title: "Paper size", modal: true });
2243
2635
  const form = document.createElement("form");
2244
2636
  form.className = "bb-pd";
@@ -2265,7 +2657,7 @@ function openPageSizeDialog(options) {
2265
2657
  width.input.select();
2266
2658
  }
2267
2659
  function openMarginsDialog(options) {
2268
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2660
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2269
2661
  const dialog = new Dialog({ title: "Margins", modal: true });
2270
2662
  const form = document.createElement("form");
2271
2663
  form.className = "bb-pd";
@@ -2322,7 +2714,7 @@ var PGNUM_FORMATS = [
2322
2714
  ["upperLetter", "A, B, C, D\u2026", "A"]
2323
2715
  ];
2324
2716
  function pageNumberPicker(options) {
2325
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2717
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2326
2718
  const root = document.createElement("div");
2327
2719
  root.className = "bb-ps";
2328
2720
  root.setAttribute("role", "menu");
@@ -2423,7 +2815,7 @@ function pageNumberPicker(options) {
2423
2815
  return root;
2424
2816
  }
2425
2817
  function sectionPaperPanel(options) {
2426
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2818
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2427
2819
  const root = document.createElement("div");
2428
2820
  root.className = "bb-ps";
2429
2821
  root.setAttribute("role", "menu");
@@ -2492,7 +2884,7 @@ function sectionPaperPanel(options) {
2492
2884
  }
2493
2885
 
2494
2886
  // packages/ui/src/lib/section-chip.ts
2495
- var STYLE11 = `
2887
+ var STYLE13 = `
2496
2888
  .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
2889
  .bb-secchip *{box-sizing:border-box}
2498
2890
  .bb-secchip-title{padding:0 7px;font-size:11px;font-weight:600;opacity:.8}
@@ -2505,7 +2897,7 @@ var STYLE11 = `
2505
2897
  .bb-secchip-x:hover{background:var(--bb-ui-hover,#f1efe8);opacity:1}
2506
2898
  `;
2507
2899
  function createSectionChip(options) {
2508
- injectStyle("bb-ui-section-chip-styles", STYLE11);
2900
+ injectStyle("bb-ui-section-chip-styles", STYLE13);
2509
2901
  const el5 = document.createElement("div");
2510
2902
  el5.className = "bb-secchip";
2511
2903
  const title = document.createElement("span");
@@ -2562,7 +2954,7 @@ var halfToPt = (hp) => hp / 2;
2562
2954
  var ptToHalf = (pt) => Math.round(pt * 2);
2563
2955
  var SCALE_PRESETS = [200, 150, 100, 90, 80, 66, 50, 33];
2564
2956
  var SUPERSUB_SCALE = 0.66;
2565
- var STYLE12 = `
2957
+ var STYLE14 = `
2566
2958
  .bb-fd{display:flex;flex-direction:column;gap:15px;min-width:396px;max-width:430px;color:var(--bb-ui-fg,#2c2c2a)}
2567
2959
  .bb-fd *{box-sizing:border-box}
2568
2960
  /* A segmented control, not a "tab joined to its pane": that pattern needs the
@@ -2644,7 +3036,7 @@ function openFontDialog({
2644
3036
  sizes,
2645
3037
  onApply
2646
3038
  }) {
2647
- injectStyle("bb-font-dialog", STYLE12);
3039
+ injectStyle("bb-font-dialog", STYLE14);
2648
3040
  const dialog = new Dialog({ title: "Font", modal: true });
2649
3041
  const root = el("div", "bb-fd");
2650
3042
  const tabs = el("div", "bb-fd-tabs");
@@ -2708,8 +3100,8 @@ function openFontDialog({
2708
3100
  label: "Text color",
2709
3101
  clearLabel: "Automatic",
2710
3102
  value: () => color,
2711
- onPick: (c) => {
2712
- color = c;
3103
+ onPick: (c2) => {
3104
+ color = c2;
2713
3105
  paint();
2714
3106
  }
2715
3107
  });
@@ -2718,8 +3110,8 @@ function openFontDialog({
2718
3110
  label: "Highlight",
2719
3111
  clearLabel: "No highlight",
2720
3112
  value: () => highlight2,
2721
- onPick: (c) => {
2722
- highlight2 = c;
3113
+ onPick: (c2) => {
3114
+ highlight2 = c2;
2723
3115
  paint();
2724
3116
  }
2725
3117
  });
@@ -2844,8 +3236,8 @@ function openFontDialog({
2844
3236
  s.transform = scale === 100 ? "none" : `scaleX(${scale / 100})`;
2845
3237
  s.verticalAlign = supCb.checked ? "super" : subCb.checked ? "sub" : `${positionPt}pt`;
2846
3238
  }
2847
- for (const c of [familySel, sizeSel, scaleSel])
2848
- c.addEventListener("change", paint);
3239
+ for (const c2 of [familySel, sizeSel, scaleSel])
3240
+ c2.addEventListener("change", paint);
2849
3241
  for (const i of [spacingInput, positionInput])
2850
3242
  i.addEventListener("input", paint);
2851
3243
  const foot = el("div", "bb-fd-foot");
@@ -3266,7 +3658,7 @@ function parseCodePoint(input) {
3266
3658
  }
3267
3659
  var RECENT_MAX = 16;
3268
3660
  function pushRecent(recent, char, max = RECENT_MAX) {
3269
- return [char, ...recent.filter((c) => c !== char)].slice(0, max);
3661
+ return [char, ...recent.filter((c2) => c2 !== char)].slice(0, max);
3270
3662
  }
3271
3663
  function searchSymbols(query) {
3272
3664
  const q = query.trim().toLowerCase();
@@ -3286,7 +3678,7 @@ function searchSymbols(query) {
3286
3678
  }
3287
3679
 
3288
3680
  // packages/ui/src/lib/symbol-dialog.ts
3289
- var STYLE13 = `
3681
+ var STYLE15 = `
3290
3682
  .bb-sd{display:flex;flex-direction:column;gap:12px;width:412px;max-width:100%;color:var(--bb-ui-fg,#2c2c2a)}
3291
3683
  .bb-sd *{box-sizing:border-box}
3292
3684
  .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 +3739,7 @@ function glyphFor(char) {
3347
3739
  return char;
3348
3740
  }
3349
3741
  function createSymbolDialog(options) {
3350
- injectStyle("bb-symbol-dialog", STYLE13);
3742
+ injectStyle("bb-symbol-dialog", STYLE15);
3351
3743
  let recent = [...options.recent ?? []].slice(0, RECENT_MAX);
3352
3744
  let selected = null;
3353
3745
  const root = el2("div", "bb-sd");
@@ -3536,9 +3928,9 @@ function createSymbolDialog(options) {
3536
3928
  function renderRecent() {
3537
3929
  fillGrid(
3538
3930
  recentGrid,
3539
- recent.map((c) => ({
3540
- char: c,
3541
- name: SYMBOL_NAMES.get(c) ?? "Character"
3931
+ recent.map((c2) => ({
3932
+ char: c2,
3933
+ name: SYMBOL_NAMES.get(c2) ?? "Character"
3542
3934
  })),
3543
3935
  RECENT_COLS,
3544
3936
  "Nothing yet \u2014 inserted symbols appear here."
@@ -3582,7 +3974,7 @@ function createSymbolDialog(options) {
3582
3974
  code.removeAttribute("aria-invalid");
3583
3975
  const cell = Array.from(
3584
3976
  grid.querySelectorAll(".bb-sd-cell")
3585
- ).find((c) => c.textContent === glyphFor(ch));
3977
+ ).find((c2) => c2.textContent === glyphFor(ch));
3586
3978
  select2(ch, cell ?? null);
3587
3979
  } else {
3588
3980
  code.setAttribute("aria-invalid", code.value.trim() ? "true" : "false");
@@ -3625,7 +4017,7 @@ function createSymbolDialog(options) {
3625
4017
  }
3626
4018
 
3627
4019
  // packages/ui/src/lib/symbol-popover.ts
3628
- var STYLE14 = `
4020
+ var STYLE16 = `
3629
4021
  .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
4022
  .bb-spk *{box-sizing:border-box}
3631
4023
  .bb-spk::backdrop{background:transparent}
@@ -3658,7 +4050,7 @@ function el3(tag, cls, text) {
3658
4050
  return n;
3659
4051
  }
3660
4052
  function openSymbolPopover(options) {
3661
- injectStyle("bb-ui-symbol-popover", STYLE14);
4053
+ injectStyle("bb-ui-symbol-popover", STYLE16);
3662
4054
  const { anchor } = options;
3663
4055
  let recent = [...options.recent ?? []].slice(0, RECENT_MAX);
3664
4056
  let groupId = SYMBOL_GROUPS[0].id;
@@ -3689,16 +4081,16 @@ function openSymbolPopover(options) {
3689
4081
  const chips = el3("div", "bb-spk-chips");
3690
4082
  const chipEls = /* @__PURE__ */ new Map();
3691
4083
  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", () => {
4084
+ const c2 = el3("button", "bb-spk-chip", grp.short);
4085
+ c2.type = "button";
4086
+ c2.title = grp.label;
4087
+ c2.addEventListener("click", () => {
3696
4088
  groupId = grp.id;
3697
4089
  search.value = "";
3698
4090
  render();
3699
4091
  });
3700
- chips.append(c);
3701
- chipEls.set(grp.id, c);
4092
+ chips.append(c2);
4093
+ chipEls.set(grp.id, c2);
3702
4094
  }
3703
4095
  const grid = el3("div", "bb-spk-grid");
3704
4096
  grid.setAttribute("role", "grid");
@@ -3769,9 +4161,9 @@ function openSymbolPopover(options) {
3769
4161
  };
3770
4162
  const renderRecent = () => fill(
3771
4163
  recentGrid,
3772
- recent.slice(0, RECENT_ROW).map((c) => ({
3773
- char: c,
3774
- name: SYMBOL_NAMES.get(c) ?? "Character"
4164
+ recent.slice(0, RECENT_ROW).map((c2) => ({
4165
+ char: c2,
4166
+ name: SYMBOL_NAMES.get(c2) ?? "Character"
3775
4167
  })),
3776
4168
  "Nothing yet."
3777
4169
  );
@@ -3779,8 +4171,8 @@ function openSymbolPopover(options) {
3779
4171
  const q = search.value.trim();
3780
4172
  const byCode = q ? parseCodePoint(q) : null;
3781
4173
  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));
4174
+ for (const [id, c2] of chipEls)
4175
+ c2.setAttribute("aria-pressed", String(!q && id === groupId));
3784
4176
  fill(grid, entries, "No match.");
3785
4177
  const first = grid.querySelector(".bb-spk-cell");
3786
4178
  if (q && first && entries[0]) select2(entries[0].char, first);
@@ -3824,7 +4216,7 @@ import {
3824
4216
  formatKey,
3825
4217
  keybindingRows
3826
4218
  } from "@shadow-garden/bapbong-contracts";
3827
- var STYLE15 = `
4219
+ var STYLE17 = `
3828
4220
  .bb-ks{display:flex;flex-direction:column;gap:10px;width:600px;max-width:100%;color:var(--bb-ui-fg,#2c2c2a);font-size:12px}
3829
4221
  .bb-ks *{box-sizing:border-box}
3830
4222
  .bb-ks-top{display:flex;gap:8px;align-items:center}
@@ -3882,7 +4274,7 @@ function highlight(text, q) {
3882
4274
  return out;
3883
4275
  }
3884
4276
  function openKeyboardShortcutsDialog(options) {
3885
- injectStyle("bb-ui-shortcuts-dialog", STYLE15);
4277
+ injectStyle("bb-ui-shortcuts-dialog", STYLE17);
3886
4278
  const dialog = new Dialog({
3887
4279
  title: options.title ?? "Keyboard shortcuts",
3888
4280
  modal: true,
@@ -3909,19 +4301,19 @@ function openKeyboardShortcutsDialog(options) {
3909
4301
  let sortKey = "title";
3910
4302
  let sortAsc = true;
3911
4303
  const ths = /* @__PURE__ */ new Map();
3912
- for (const c of columns) {
4304
+ for (const c2 of columns) {
3913
4305
  const th = el4("th");
3914
- th.append(el4("span", void 0, c.label));
4306
+ th.append(el4("span", void 0, c2.label));
3915
4307
  th.addEventListener("click", () => {
3916
- if (sortKey === c.key) sortAsc = !sortAsc;
4308
+ if (sortKey === c2.key) sortAsc = !sortAsc;
3917
4309
  else {
3918
- sortKey = c.key;
4310
+ sortKey = c2.key;
3919
4311
  sortAsc = true;
3920
4312
  }
3921
4313
  render();
3922
4314
  });
3923
4315
  headRow.append(th);
3924
- ths.set(c.key, th);
4316
+ ths.set(c2.key, th);
3925
4317
  }
3926
4318
  thead.append(headRow);
3927
4319
  const tbody = el4("tbody");
@@ -3941,7 +4333,7 @@ function openKeyboardShortcutsDialog(options) {
3941
4333
  const rows = [];
3942
4334
  for (const src of options.sources)
3943
4335
  rows.push(
3944
- ...keybindingRows(src.keybindings, (c) => src.commands.get(c)?.title)
4336
+ ...keybindingRows(src.keybindings, (c2) => src.commands.get(c2)?.title)
3945
4337
  );
3946
4338
  return rows;
3947
4339
  };
@@ -3998,7 +4390,7 @@ function openKeyboardShortcutsDialog(options) {
3998
4390
  tbody.append(tr);
3999
4391
  }
4000
4392
  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`;
4393
+ footL.textContent = `Sorted by ${columns.find((c2) => c2.key === sortKey)?.label.toLowerCase()} \xB7 click a header to sort`;
4002
4394
  };
4003
4395
  search.addEventListener("input", render);
4004
4396
  dialog.onClose(() => dialog.destroy());
@@ -4008,7 +4400,7 @@ function openKeyboardShortcutsDialog(options) {
4008
4400
  }
4009
4401
 
4010
4402
  // packages/ui/src/lib/scrollbars.ts
4011
- var STYLE16 = `
4403
+ var STYLE18 = `
4012
4404
  @property --bb-scroll-thumb-now {
4013
4405
  syntax: '<color>';
4014
4406
  /* MUST inherit: the thumb pseudo-element never matches .bb-scrolling
@@ -4040,7 +4432,7 @@ var STYLE16 = `
4040
4432
  var installed = null;
4041
4433
  function installScrollbars(root = document) {
4042
4434
  if (installed) return installed;
4043
- injectStyle("bb-ui-scrollbars", STYLE16);
4435
+ injectStyle("bb-ui-scrollbars", STYLE18);
4044
4436
  const quiet = /* @__PURE__ */ new WeakMap();
4045
4437
  const onScroll = (ev) => {
4046
4438
  const el5 = ev.target instanceof HTMLElement ? ev.target : root.documentElement;
@@ -4059,6 +4451,7 @@ function installScrollbars(root = document) {
4059
4451
  return installed;
4060
4452
  }
4061
4453
  export {
4454
+ BUILT_IN_EQUATIONS,
4062
4455
  COLOR_PALETTE,
4063
4456
  Dialog,
4064
4457
  RECENT_MAX,
@@ -4073,6 +4466,9 @@ export {
4073
4466
  createSymbolDialog,
4074
4467
  defaultMenus,
4075
4468
  defaultToolbarGroups,
4469
+ equationGallery,
4470
+ equationPanel,
4471
+ equationPreviewSvg,
4076
4472
  installScrollbars,
4077
4473
  marginPresetPicker,
4078
4474
  mountMenubar,