@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.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,
@@ -34,6 +35,9 @@ __export(index_exports, {
34
35
  createSymbolDialog: () => createSymbolDialog,
35
36
  defaultMenus: () => defaultMenus,
36
37
  defaultToolbarGroups: () => defaultToolbarGroups,
38
+ equationGallery: () => equationGallery,
39
+ equationPanel: () => equationPanel,
40
+ equationPreviewSvg: () => equationPreviewSvg,
37
41
  installScrollbars: () => installScrollbars,
38
42
  marginPresetPicker: () => marginPresetPicker,
39
43
  mountMenubar: () => mountMenubar,
@@ -97,12 +101,12 @@ function placeFloating(el5, anchor) {
97
101
  }
98
102
  function rovingGrid(cells) {
99
103
  let cur = [0, 0];
100
- const at = (r, c) => cells[r]?.[c];
101
- const focusCell = (r, c) => {
104
+ const at = (r, c2) => cells[r]?.[c2];
105
+ const focusCell = (r, c2) => {
102
106
  const rows = cells.length;
103
107
  if (rows === 0) return;
104
108
  const nr = Math.min(rows - 1, Math.max(0, r));
105
- const nc = Math.min(cells[nr].length - 1, Math.max(0, c));
109
+ const nc = Math.min(cells[nr].length - 1, Math.max(0, c2));
106
110
  const prev = at(cur[0], cur[1]);
107
111
  if (prev) prev.tabIndex = -1;
108
112
  const next = at(nr, nc);
@@ -112,9 +116,9 @@ function rovingGrid(cells) {
112
116
  cur = [nr, nc];
113
117
  };
114
118
  cells.forEach(
115
- (row, r) => row.forEach((cell, c) => {
119
+ (row, r) => row.forEach((cell, c2) => {
116
120
  cell.setAttribute("role", "gridcell");
117
- cell.tabIndex = r === 0 && c === 0 ? 0 : -1;
121
+ cell.tabIndex = r === 0 && c2 === 0 ? 0 : -1;
118
122
  cell.addEventListener("keydown", (e) => {
119
123
  const delta = {
120
124
  ArrowRight: [0, 1],
@@ -127,10 +131,10 @@ function rovingGrid(cells) {
127
131
  const d = delta[e.key];
128
132
  if (!d) return;
129
133
  e.preventDefault();
130
- focusCell(r + d[0], c + d[1]);
134
+ focusCell(r + d[0], c2 + d[1]);
131
135
  });
132
136
  cell.addEventListener("focus", () => {
133
- cur = [r, c];
137
+ cur = [r, c2];
134
138
  });
135
139
  })
136
140
  );
@@ -460,9 +464,9 @@ function openColorPicker({
460
464
  panel.remove();
461
465
  anchor.focus();
462
466
  };
463
- const pick = (c) => {
464
- if (c && !COLOR_PALETTE.some((row) => row.includes(c))) remember(c);
465
- onPick(c);
467
+ const pick = (c2) => {
468
+ if (c2 && !COLOR_PALETTE.some((row) => row.includes(c2))) remember(c2);
469
+ onPick(c2);
466
470
  close();
467
471
  };
468
472
  if (clearLabel !== void 0) {
@@ -506,15 +510,15 @@ function openColorPicker({
506
510
  );
507
511
  const customRow2 = document.createElement("div");
508
512
  customRow2.className = "bb-cpk-row";
509
- for (const c of customColors) {
513
+ for (const c2 of customColors) {
510
514
  const sw = document.createElement("button");
511
515
  sw.type = "button";
512
516
  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));
517
+ sw.style.background = c2;
518
+ sw.title = c2;
519
+ sw.setAttribute("aria-label", c2);
520
+ if (c2.toUpperCase() === value?.toUpperCase()) sw.classList.add("on");
521
+ sw.addEventListener("click", () => pick(c2));
518
522
  customRow2.append(sw);
519
523
  }
520
524
  const plus = document.createElement("button");
@@ -598,8 +602,8 @@ function colorButton(o) {
598
602
  anchor: el5,
599
603
  value: o.value(),
600
604
  clearLabel: o.clearLabel,
601
- onPick: (c) => {
602
- o.onPick(c);
605
+ onPick: (c2) => {
606
+ o.onPick(c2);
603
607
  sync();
604
608
  }
605
609
  });
@@ -710,7 +714,7 @@ var STYLE3 = `
710
714
  .bb-split-bar{flex:1;height:3px;border-radius:2px;background:var(--bb-ui-border,#d9d9d4)}
711
715
  `;
712
716
  function defaultToolbarGroups(commands) {
713
- const names = [...commands].map((c) => c.name);
717
+ const names = [...commands].map((c2) => c2.name);
714
718
  const aligns = names.filter((n) => n.startsWith("align-"));
715
719
  const rest = names.filter((n) => !n.startsWith("align-"));
716
720
  return [rest, aligns].filter((g2) => g2.length > 0);
@@ -960,7 +964,7 @@ function mountToolbar(host, editor, options = {}) {
960
964
  el5.disabled = cmd.isEnabled ? !cmd.isEnabled(state) : false;
961
965
  }
962
966
  for (const { spec, el: el5 } of selects) el5.value = spec.value(state);
963
- for (const c of colors) c.sync();
967
+ for (const c2 of colors) c2.sync();
964
968
  for (const { spec, cards } of splits) {
965
969
  const selected = spec.value(state);
966
970
  for (const card of cards)
@@ -970,7 +974,7 @@ function mountToolbar(host, editor, options = {}) {
970
974
  );
971
975
  }
972
976
  };
973
- const off = editor.onChange((c) => refresh(c.state));
977
+ const off = editor.onChange((c2) => refresh(c2.state));
974
978
  try {
975
979
  refresh(editor.state);
976
980
  } catch {
@@ -1214,7 +1218,7 @@ function showMenu(entries, at, options = {}) {
1214
1218
  return handle;
1215
1219
  }
1216
1220
  function defaultMenus(commands) {
1217
- const names = [...commands].map((c) => c.name);
1221
+ const names = [...commands].map((c2) => c2.name);
1218
1222
  const marks = ["bold", "italic", "underline", "strike"].filter(
1219
1223
  (n) => commands.has(n)
1220
1224
  );
@@ -1328,10 +1332,10 @@ function mountMenubar(host, editor, options = {}) {
1328
1332
  function refresh(state) {
1329
1333
  latest = state;
1330
1334
  if (openIdx < 0) return;
1331
- for (const c of checks) c.el.textContent = c.active(state) ? "\u2713" : "";
1335
+ for (const c2 of checks) c2.el.textContent = c2.active(state) ? "\u2713" : "";
1332
1336
  for (const e of enables) e.el.disabled = !e.enabled(state);
1333
1337
  }
1334
- const off = editor.onChange((c) => refresh(c.state));
1338
+ const off = editor.onChange((c2) => refresh(c2.state));
1335
1339
  try {
1336
1340
  latest = editor.state;
1337
1341
  } catch {
@@ -1659,13 +1663,13 @@ function showLinkPanel(opts) {
1659
1663
  row.appendChild(icon);
1660
1664
  const label = document.createElement("span");
1661
1665
  label.className = "bb-linkpanel-href";
1662
- label.textContent = internal.label ?? "V\u1ECB tr\xED kh\xF4ng c\xF2n trong t\xE0i li\u1EC7u";
1666
+ label.textContent = internal.label ?? "This place is no longer in the document";
1663
1667
  label.title = internal.label ?? existing.href;
1664
1668
  if (!internal.label) label.classList.add("bb-linkpanel-stale");
1665
1669
  row.appendChild(label);
1666
1670
  if (internal.label) {
1667
1671
  row.appendChild(
1668
- iconBtn(ICONS.goTo, "\u0110i t\u1EDBi v\u1ECB tr\xED n\xE0y", () => {
1672
+ iconBtn(ICONS.goTo, "Go to this place", () => {
1669
1673
  closeCurrent2();
1670
1674
  internal.onGo();
1671
1675
  })
@@ -1879,8 +1883,8 @@ function openCellProperties({
1879
1883
  label: "Fill",
1880
1884
  clearLabel: "No fill",
1881
1885
  value: () => background,
1882
- onPick: (c) => {
1883
- background = c;
1886
+ onPick: (c2) => {
1887
+ background = c2;
1884
1888
  }
1885
1889
  });
1886
1890
  fill.append(fillBtn.el);
@@ -1933,8 +1937,8 @@ function openCellProperties({
1933
1937
  title: "Border colour",
1934
1938
  label: "Colour",
1935
1939
  value: () => penColor,
1936
- onPick: (c) => {
1937
- if (c) penColor = c;
1940
+ onPick: (c2) => {
1941
+ if (c2) penColor = c2;
1938
1942
  }
1939
1943
  });
1940
1944
  penRow.append(widthSel, styleSel, penBtn.el);
@@ -1998,8 +2002,396 @@ function openCellProperties({
1998
2002
  dialog.open();
1999
2003
  }
2000
2004
 
2001
- // packages/ui/src/lib/table-grid.ts
2005
+ // packages/ui/src/lib/equation-gallery.ts
2006
+ var import_bapbong_contracts2 = require("@shadow-garden/bapbong-contracts");
2007
+ var c = (s) => [...s].map((ch) => ({ t: "chr", ch }));
2008
+ var sup = (base, exp) => ({
2009
+ t: "scr",
2010
+ base,
2011
+ sub: [],
2012
+ sup: c(exp)
2013
+ });
2014
+ var subsup = (base, lo, hi) => ({
2015
+ t: "scr",
2016
+ base,
2017
+ sub: c(lo),
2018
+ sup: c(hi)
2019
+ });
2020
+ var BUILT_IN_EQUATIONS = [
2021
+ {
2022
+ name: "Area of a circle",
2023
+ ast: [...c("\u{1D434} = \u{1D70B}"), sup(c("\u{1D45F}"), "2")]
2024
+ },
2025
+ {
2026
+ name: "Pythagorean theorem",
2027
+ ast: [
2028
+ sup(c("\u{1D44E}"), "2"),
2029
+ ...c(" + "),
2030
+ sup(c("\u{1D44F}"), "2"),
2031
+ ...c(" = "),
2032
+ sup(c("\u{1D450}"), "2")
2033
+ ]
2034
+ },
2035
+ {
2036
+ name: "Quadratic formula",
2037
+ ast: [
2038
+ ...c("\u{1D465} = "),
2039
+ {
2040
+ t: "frac",
2041
+ num: [
2042
+ ...c("\u2212\u{1D44F} \xB1 "),
2043
+ {
2044
+ t: "rad",
2045
+ deg: [],
2046
+ body: [sup(c("\u{1D44F}"), "2"), ...c(" \u2212 4\u{1D44E}\u{1D450}")]
2047
+ }
2048
+ ],
2049
+ den: c("2\u{1D44E}")
2050
+ }
2051
+ ]
2052
+ },
2053
+ {
2054
+ name: "Law of cosines",
2055
+ ast: [
2056
+ sup(c("\u{1D44E}"), "2"),
2057
+ ...c(" = "),
2058
+ sup(c("\u{1D44F}"), "2"),
2059
+ ...c(" + "),
2060
+ sup(c("\u{1D450}"), "2"),
2061
+ ...c(" \u2212 2\u{1D44F}\u{1D450} cos \u{1D434}")
2062
+ ]
2063
+ },
2064
+ {
2065
+ name: "Binomial theorem",
2066
+ ast: [
2067
+ // The exponent belongs ON the bracket: a script with an empty base
2068
+ // would render its own empty slot — the dotted placeholder box.
2069
+ {
2070
+ t: "scr",
2071
+ base: [{ t: "fence", l: "(", r: ")", body: c("\u{1D44E} + \u{1D44F}") }],
2072
+ sub: [],
2073
+ sup: c("\u{1D45B}")
2074
+ },
2075
+ ...c(" = "),
2076
+ {
2077
+ t: "big",
2078
+ op: "\u2211",
2079
+ lo: c("\u{1D458} = 0"),
2080
+ hi: c("\u{1D45B}"),
2081
+ body: [
2082
+ subsup(c("\u{1D436}"), "\u{1D45B}", "\u{1D458}"),
2083
+ sup(c("\u{1D44E}"), "\u{1D458}"),
2084
+ { t: "scr", base: c("\u{1D44F}"), sub: [], sup: c("\u{1D45B}\u2212\u{1D458}") }
2085
+ ]
2086
+ }
2087
+ ]
2088
+ }
2089
+ ];
2090
+ var SVG_NS = "http://www.w3.org/2000/svg";
2091
+ function equationPreviewSvg(spec, opts = {}) {
2092
+ const svg = document.createElementNS(SVG_NS, "svg");
2093
+ svg.setAttribute("viewBox", `0 0 ${spec.width} ${spec.height}`);
2094
+ const max = opts.maxWidth ?? spec.width;
2095
+ const scale = Math.min(1, max / Math.max(1, spec.width));
2096
+ svg.setAttribute("width", String(Math.round(spec.width * scale)));
2097
+ svg.setAttribute("height", String(Math.round(spec.height * scale)));
2098
+ svg.setAttribute("aria-hidden", "true");
2099
+ for (const op of spec.ops) svg.append(opElement(op));
2100
+ return svg;
2101
+ }
2102
+ function opElement(op) {
2103
+ if (op.kind === "line") {
2104
+ const el6 = document.createElementNS(SVG_NS, "line");
2105
+ el6.setAttribute("x1", String(op.x1));
2106
+ el6.setAttribute("y1", String(op.y1));
2107
+ el6.setAttribute("x2", String(op.x2));
2108
+ el6.setAttribute("y2", String(op.y2));
2109
+ el6.setAttribute("stroke", op.color);
2110
+ el6.setAttribute("stroke-width", String(Math.max(op.width, 0.75)));
2111
+ return el6;
2112
+ }
2113
+ if (op.kind === "polygon") {
2114
+ const el6 = document.createElementNS(SVG_NS, "polygon");
2115
+ el6.setAttribute("points", op.points.map((p) => `${p.x},${p.y}`).join(" "));
2116
+ el6.setAttribute("fill", op.fill ?? "none");
2117
+ if (op.stroke) {
2118
+ el6.setAttribute("stroke", op.stroke);
2119
+ el6.setAttribute("stroke-width", String(op.strokeWidth ?? 1));
2120
+ }
2121
+ return el6;
2122
+ }
2123
+ const el5 = document.createElementNS(SVG_NS, "text");
2124
+ el5.setAttribute("x", String(op.x));
2125
+ el5.setAttribute("y", String(op.y));
2126
+ el5.setAttribute("font-size", String(op.size));
2127
+ el5.setAttribute("font-family", op.family);
2128
+ el5.setAttribute("fill", op.color);
2129
+ if (op.bold) el5.setAttribute("font-weight", "bold");
2130
+ if (op.italic) el5.setAttribute("font-style", "italic");
2131
+ if (op.vAlign === "top") el5.setAttribute("dominant-baseline", "hanging");
2132
+ if (op.dx) {
2133
+ let x = op.x;
2134
+ for (const [i, ch] of [...op.text].entries()) {
2135
+ const t = document.createElementNS(SVG_NS, "tspan");
2136
+ t.setAttribute("x", String(x));
2137
+ t.textContent = ch;
2138
+ el5.append(t);
2139
+ x += op.dx[i] ?? 0;
2140
+ }
2141
+ } else {
2142
+ el5.textContent = op.text;
2143
+ }
2144
+ return el5;
2145
+ }
2002
2146
  var STYLE9 = `
2147
+ .bb-eqg{display:flex;flex-direction:column;min-width:236px;max-width:300px;user-select:none}
2148
+ .bb-eqg-head{font-size:11px;font-weight:600;opacity:.55;padding:2px 8px 6px}
2149
+ .bb-eqg-list{display:flex;flex-direction:column;max-height:320px;overflow-y:auto}
2150
+ .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}
2151
+ .bb-eqg-item:hover{background:var(--bb-ui-hover,#f1efe8)}
2152
+ .bb-eqg-name{font-size:11px;opacity:.6}
2153
+ /* The preview is the equation TYPESET \u2014 the same display list the canvas
2154
+ paints. The text form is the fallback for a host that cannot lay out. */
2155
+ .bb-eqg-prev{display:flex;align-items:center;min-height:22px;max-width:100%;overflow:hidden}
2156
+ .bb-eqg-prev svg{display:block}
2157
+ .bb-eqg-prev-text{font-family:"Times New Roman",Tinos,serif;font-size:15px;line-height:1.35;white-space:nowrap;text-overflow:ellipsis}
2158
+ .bb-eqg-foot{margin-top:4px;padding-top:5px;border-top:1px solid var(--bb-ui-border,#e3e3e0)}
2159
+ .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}
2160
+ .bb-eqg-new:hover{background:var(--bb-ui-hover,#f1efe8)}
2161
+ .bb-eqg-key{margin-left:auto;opacity:.5;font-size:12px}
2162
+ `;
2163
+ var PREVIEW_PT = 11;
2164
+ var PREVIEW_MAX_W = 264;
2165
+ function equationGallery(options) {
2166
+ injectStyle("bb-ui-eqg-styles", STYLE9);
2167
+ const root = document.createElement("div");
2168
+ root.className = "bb-eqg";
2169
+ const head = document.createElement("div");
2170
+ head.className = "bb-eqg-head";
2171
+ head.textContent = "Built-in";
2172
+ root.append(head);
2173
+ const list = document.createElement("div");
2174
+ list.className = "bb-eqg-list";
2175
+ for (const item of options.items ?? BUILT_IN_EQUATIONS) {
2176
+ const btn = document.createElement("button");
2177
+ btn.type = "button";
2178
+ btn.className = "bb-eqg-item";
2179
+ const prev = document.createElement("div");
2180
+ prev.className = "bb-eqg-prev";
2181
+ const spec = options.layout?.(item.ast, PREVIEW_PT) ?? null;
2182
+ if (spec && spec.ops.length)
2183
+ prev.append(equationPreviewSvg(spec, { maxWidth: PREVIEW_MAX_W }));
2184
+ else {
2185
+ prev.classList.add("bb-eqg-prev-text");
2186
+ prev.textContent = (0, import_bapbong_contracts2.astToLinear)(item.ast);
2187
+ }
2188
+ const name = document.createElement("div");
2189
+ name.className = "bb-eqg-name";
2190
+ name.textContent = item.name;
2191
+ btn.append(prev, name);
2192
+ btn.addEventListener("mousedown", (e) => e.preventDefault());
2193
+ btn.addEventListener("click", () => options.onPick(item.ast));
2194
+ list.append(btn);
2195
+ }
2196
+ root.append(list);
2197
+ const foot = document.createElement("div");
2198
+ foot.className = "bb-eqg-foot";
2199
+ const neu = document.createElement("button");
2200
+ neu.type = "button";
2201
+ neu.className = "bb-eqg-new";
2202
+ const label = document.createElement("span");
2203
+ label.textContent = "Insert new equation";
2204
+ neu.append(label);
2205
+ if (options.newShortcut) {
2206
+ const key = document.createElement("span");
2207
+ key.className = "bb-eqg-key";
2208
+ key.textContent = options.newShortcut;
2209
+ neu.append(key);
2210
+ }
2211
+ neu.addEventListener("mousedown", (e) => e.preventDefault());
2212
+ neu.addEventListener("click", () => options.onNew());
2213
+ foot.append(neu);
2214
+ root.append(foot);
2215
+ return root;
2216
+ }
2217
+
2218
+ // packages/ui/src/lib/equation-panel.ts
2219
+ var import_bapbong_contracts3 = require("@shadow-garden/bapbong-contracts");
2220
+ var SHORTHAND = /* @__PURE__ */ new Map();
2221
+ for (const [name, ch] of Object.entries(import_bapbong_contracts3.MATH_AUTOCORRECT))
2222
+ if (!SHORTHAND.has(ch)) SHORTHAND.set(ch, `\\${name}`);
2223
+ var PREVIEW_PT2 = 10;
2224
+ var STYLE10 = `
2225
+ .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}
2226
+ .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)}
2227
+ .bb-eqp.is-collapsed .bb-eqp-tabs{border-bottom:0}
2228
+ .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}
2229
+ .bb-eqp-tab:hover{background:var(--bb-ui-hover,#f1efe8)}
2230
+ .bb-eqp-tab[aria-selected="true"]{opacity:1;background:var(--bb-ui-sel,#e6f1fb);color:var(--bb-ui-sel-fg,#0c447c)}
2231
+ .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}
2232
+ .bb-eqp-fold:hover{background:var(--bb-ui-hover,#f1efe8);opacity:.9}
2233
+ .bb-eqp-body{padding:8px}
2234
+ .bb-eqp.is-collapsed .bb-eqp-body{display:none}
2235
+ .bb-eqp-set{width:100%;height:30px;margin-bottom:7px;font:inherit;font-size:13px}
2236
+ .bb-eqp-grid{display:grid;grid-template-columns:repeat(10,1fr);gap:1px;max-height:190px;overflow-y:auto}
2237
+ .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}
2238
+ .bb-eqp-sym:hover{background:var(--bb-ui-hover,#f1efe8)}
2239
+ .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}
2240
+ .bb-eqp-hint-g{font-family:"Cambria Math","Times New Roman",Tinos,serif;font-size:15px}
2241
+ .bb-eqp-hint-k{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
2242
+ .bb-eqp-scroll{max-height:230px;overflow-y:auto}
2243
+ .bb-eqp-group{font-size:11px;font-weight:600;opacity:.5;padding:6px 2px 3px}
2244
+ .bb-eqp-row{display:grid;grid-template-columns:repeat(4,1fr);gap:3px}
2245
+ .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}
2246
+ .bb-eqp-st:hover{background:var(--bb-ui-hover,#f1efe8)}
2247
+ .bb-eqp-st-name{font-size:10px;opacity:.6;text-align:center;line-height:1.25}
2248
+ .bb-eqp-st svg{display:block}
2249
+ `;
2250
+ 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>';
2251
+ 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>';
2252
+ function equationPanel(options) {
2253
+ injectStyle("bb-ui-eqp-styles", STYLE10);
2254
+ const root = document.createElement("div");
2255
+ root.className = "bb-eqp";
2256
+ root.setAttribute("role", "group");
2257
+ root.setAttribute("aria-label", "Equation palette");
2258
+ root.addEventListener("mousedown", (e) => e.preventDefault());
2259
+ const tabs = document.createElement("div");
2260
+ tabs.className = "bb-eqp-tabs";
2261
+ tabs.setAttribute("role", "tablist");
2262
+ const body = document.createElement("div");
2263
+ body.className = "bb-eqp-body";
2264
+ let collapsed = false;
2265
+ let current3 = "symbols";
2266
+ const tabEls = {};
2267
+ const mkTab = (id, label) => {
2268
+ const b = document.createElement("button");
2269
+ b.type = "button";
2270
+ b.className = "bb-eqp-tab";
2271
+ b.textContent = label;
2272
+ b.setAttribute("role", "tab");
2273
+ b.addEventListener("click", () => {
2274
+ current3 = id;
2275
+ if (collapsed) setCollapsed(false);
2276
+ render();
2277
+ });
2278
+ tabEls[id] = b;
2279
+ tabs.append(b);
2280
+ };
2281
+ mkTab("symbols", "Symbols");
2282
+ mkTab("structures", "Structures");
2283
+ const fold = document.createElement("button");
2284
+ fold.type = "button";
2285
+ fold.className = "bb-eqp-fold";
2286
+ fold.addEventListener("click", () => setCollapsed(!collapsed));
2287
+ tabs.append(fold);
2288
+ root.append(tabs, body);
2289
+ function setCollapsed(next) {
2290
+ collapsed = next;
2291
+ root.classList.toggle("is-collapsed", collapsed);
2292
+ fold.innerHTML = collapsed ? CHEVRON_DOWN : CHEVRON_UP;
2293
+ fold.setAttribute(
2294
+ "aria-label",
2295
+ collapsed ? "Show palette" : "Hide palette"
2296
+ );
2297
+ fold.setAttribute("aria-expanded", String(!collapsed));
2298
+ }
2299
+ function symbolsBody() {
2300
+ const set = document.createElement("select");
2301
+ set.className = "bb-eqp-set";
2302
+ set.setAttribute("aria-label", "Symbol set");
2303
+ for (const [i, s] of import_bapbong_contracts3.MATH_SYMBOL_SETS.entries()) {
2304
+ const o = document.createElement("option");
2305
+ o.value = String(i);
2306
+ o.textContent = s.name;
2307
+ set.append(o);
2308
+ }
2309
+ set.value = String(setIndex);
2310
+ const grid = document.createElement("div");
2311
+ grid.className = "bb-eqp-grid";
2312
+ const hint = document.createElement("div");
2313
+ hint.className = "bb-eqp-hint";
2314
+ const hintG = document.createElement("span");
2315
+ hintG.className = "bb-eqp-hint-g";
2316
+ const hintK = document.createElement("span");
2317
+ hintK.className = "bb-eqp-hint-k";
2318
+ hint.append(hintG, hintK);
2319
+ const fill = () => {
2320
+ grid.replaceChildren();
2321
+ const chars = import_bapbong_contracts3.MATH_SYMBOL_SETS[setIndex]?.chars ?? "";
2322
+ for (const ch of chars) {
2323
+ const b = document.createElement("button");
2324
+ b.type = "button";
2325
+ b.className = "bb-eqp-sym";
2326
+ b.textContent = ch;
2327
+ const key = SHORTHAND.get(ch);
2328
+ b.title = key ? `${ch} ${key}` : ch;
2329
+ b.addEventListener("mouseenter", () => {
2330
+ hintG.textContent = ch;
2331
+ hintK.textContent = key ?? "";
2332
+ });
2333
+ b.addEventListener("click", () => options.onSymbol(ch));
2334
+ grid.append(b);
2335
+ }
2336
+ };
2337
+ set.addEventListener("change", () => {
2338
+ setIndex = Number(set.value) || 0;
2339
+ fill();
2340
+ });
2341
+ fill();
2342
+ body.replaceChildren(set, grid, hint);
2343
+ }
2344
+ function structuresBody() {
2345
+ const scroll = document.createElement("div");
2346
+ scroll.className = "bb-eqp-scroll";
2347
+ for (const group of (0, import_bapbong_contracts3.eqStructureGroups)()) {
2348
+ const h = document.createElement("div");
2349
+ h.className = "bb-eqp-group";
2350
+ h.textContent = group.name;
2351
+ const row = document.createElement("div");
2352
+ row.className = "bb-eqp-row";
2353
+ for (const item of group.items) {
2354
+ const b = document.createElement("button");
2355
+ b.type = "button";
2356
+ b.className = "bb-eqp-st";
2357
+ b.title = `${group.name} \u2014 ${item.name}`;
2358
+ const spec = options.layout?.([item.node], PREVIEW_PT2) ?? null;
2359
+ if (spec && spec.ops.length)
2360
+ b.append(equationPreviewSvg(spec, { maxWidth: 60 }));
2361
+ const name = document.createElement("span");
2362
+ name.className = "bb-eqp-st-name";
2363
+ name.textContent = item.name;
2364
+ b.append(name);
2365
+ b.addEventListener("click", () => options.onStructure(item));
2366
+ row.append(b);
2367
+ }
2368
+ scroll.append(h, row);
2369
+ }
2370
+ body.replaceChildren(scroll);
2371
+ }
2372
+ let setIndex = 0;
2373
+ function render() {
2374
+ for (const [id, el5] of Object.entries(tabEls))
2375
+ el5.setAttribute("aria-selected", String(id === current3));
2376
+ if (current3 === "symbols") symbolsBody();
2377
+ else structuresBody();
2378
+ }
2379
+ setCollapsed(false);
2380
+ render();
2381
+ return {
2382
+ el: root,
2383
+ setCollapsed,
2384
+ get collapsed() {
2385
+ return collapsed;
2386
+ },
2387
+ destroy() {
2388
+ root.remove();
2389
+ }
2390
+ };
2391
+ }
2392
+
2393
+ // packages/ui/src/lib/table-grid.ts
2394
+ var STYLE11 = `
2003
2395
  .bb-grid{display:flex;flex-direction:column;gap:6px;user-select:none}
2004
2396
  .bb-grid-cells{display:grid;gap:2px}
2005
2397
  .bb-grid-cell{width:15px;height:15px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:2px;background:var(--bb-ui-bg,#fff);cursor:pointer;padding:0}
@@ -2007,7 +2399,7 @@ var STYLE9 = `
2007
2399
  .bb-grid-label{font-size:12px;text-align:center;opacity:.7}
2008
2400
  `;
2009
2401
  function tableGridPicker(options) {
2010
- injectStyle("bb-ui-grid-styles", STYLE9);
2402
+ injectStyle("bb-ui-grid-styles", STYLE11);
2011
2403
  const maxRows = options.maxRows ?? 8;
2012
2404
  const maxCols = options.maxCols ?? 10;
2013
2405
  const root = document.createElement("div");
@@ -2019,22 +2411,22 @@ function tableGridPicker(options) {
2019
2411
  label.className = "bb-grid-label";
2020
2412
  label.textContent = "0 \xD7 0";
2021
2413
  const cells = [];
2022
- const highlight2 = (r, c) => {
2414
+ const highlight2 = (r, c2) => {
2023
2415
  for (let i = 0; i < cells.length; i++) {
2024
2416
  const row = Math.floor(i / maxCols);
2025
2417
  const col = i % maxCols;
2026
- cells[i].classList.toggle("on", row <= r && col <= c);
2418
+ cells[i].classList.toggle("on", row <= r && col <= c2);
2027
2419
  }
2028
- label.textContent = `${r + 1} \xD7 ${c + 1}`;
2420
+ label.textContent = `${r + 1} \xD7 ${c2 + 1}`;
2029
2421
  };
2030
2422
  for (let r = 0; r < maxRows; r++) {
2031
- for (let c = 0; c < maxCols; c++) {
2423
+ for (let c2 = 0; c2 < maxCols; c2++) {
2032
2424
  const cell = document.createElement("button");
2033
2425
  cell.type = "button";
2034
2426
  cell.className = "bb-grid-cell";
2035
2427
  cell.addEventListener("mousedown", (e) => e.preventDefault());
2036
- cell.addEventListener("mouseenter", () => highlight2(r, c));
2037
- cell.addEventListener("click", () => options.onPick(r + 1, c + 1));
2428
+ cell.addEventListener("mouseenter", () => highlight2(r, c2));
2429
+ cell.addEventListener("click", () => options.onPick(r + 1, c2 + 1));
2038
2430
  cells.push(cell);
2039
2431
  cellsEl.appendChild(cell);
2040
2432
  }
@@ -2050,7 +2442,7 @@ var cmToPx = (cm) => Math.round(cm * PX_PER_CM);
2050
2442
  function fmtCm(cm) {
2051
2443
  return `${Number(cm.toFixed(3))} cm`;
2052
2444
  }
2053
- var STYLE10 = `
2445
+ var STYLE12 = `
2054
2446
  .bb-ps{display:flex;flex-direction:column;min-width:250px;max-height:min(70vh,460px);overflow-y:auto}
2055
2447
  .bb-ps,.bb-ps *{box-sizing:border-box}
2056
2448
  .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 +2472,9 @@ var STYLE10 = `
2080
2472
  .bb-ps-tile:hover,.bb-ps-tile:focus{background:var(--bb-ui-hover,#f1efe8);outline:none}
2081
2473
  .bb-ps-tile[aria-checked="true"]{background:var(--bb-ui-active-bg,#e6f1fb)}
2082
2474
  `;
2083
- var SVG_NS = "http://www.w3.org/2000/svg";
2475
+ var SVG_NS2 = "http://www.w3.org/2000/svg";
2084
2476
  function svgEl(name, attrs) {
2085
- const el5 = document.createElementNS(SVG_NS, name);
2477
+ const el5 = document.createElementNS(SVG_NS2, name);
2086
2478
  for (const [k, v] of Object.entries(attrs)) el5.setAttribute(k, String(v));
2087
2479
  return el5;
2088
2480
  }
@@ -2176,7 +2568,7 @@ function customRow(icon, title, description, onPick) {
2176
2568
  return presetRow(icon, title, captionLine(description), false, onPick);
2177
2569
  }
2178
2570
  function pageSizePicker(options) {
2179
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2571
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2180
2572
  const root = document.createElement("div");
2181
2573
  root.className = "bb-ps";
2182
2574
  root.setAttribute("role", "menu");
@@ -2205,7 +2597,7 @@ function pageSizePicker(options) {
2205
2597
  return root;
2206
2598
  }
2207
2599
  function orientationPicker(options) {
2208
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2600
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2209
2601
  const root = document.createElement("div");
2210
2602
  root.className = "bb-ps";
2211
2603
  root.setAttribute("role", "menu");
@@ -2228,7 +2620,7 @@ function orientationPicker(options) {
2228
2620
  return root;
2229
2621
  }
2230
2622
  function marginPresetPicker(options) {
2231
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2623
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2232
2624
  const root = document.createElement("div");
2233
2625
  root.className = "bb-ps";
2234
2626
  root.setAttribute("role", "menu");
@@ -2303,7 +2695,7 @@ function readPx(input, fallbackPx) {
2303
2695
  return Number.isFinite(n) && n > 0 ? cmToPx(n) : fallbackPx;
2304
2696
  }
2305
2697
  function openPageSizeDialog(options) {
2306
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2698
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2307
2699
  const dialog = new Dialog({ title: "Paper size", modal: true });
2308
2700
  const form = document.createElement("form");
2309
2701
  form.className = "bb-pd";
@@ -2330,7 +2722,7 @@ function openPageSizeDialog(options) {
2330
2722
  width.input.select();
2331
2723
  }
2332
2724
  function openMarginsDialog(options) {
2333
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2725
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2334
2726
  const dialog = new Dialog({ title: "Margins", modal: true });
2335
2727
  const form = document.createElement("form");
2336
2728
  form.className = "bb-pd";
@@ -2387,7 +2779,7 @@ var PGNUM_FORMATS = [
2387
2779
  ["upperLetter", "A, B, C, D\u2026", "A"]
2388
2780
  ];
2389
2781
  function pageNumberPicker(options) {
2390
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2782
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2391
2783
  const root = document.createElement("div");
2392
2784
  root.className = "bb-ps";
2393
2785
  root.setAttribute("role", "menu");
@@ -2488,7 +2880,7 @@ function pageNumberPicker(options) {
2488
2880
  return root;
2489
2881
  }
2490
2882
  function sectionPaperPanel(options) {
2491
- injectStyle("bb-ui-pagesetup-styles", STYLE10);
2883
+ injectStyle("bb-ui-pagesetup-styles", STYLE12);
2492
2884
  const root = document.createElement("div");
2493
2885
  root.className = "bb-ps";
2494
2886
  root.setAttribute("role", "menu");
@@ -2557,7 +2949,7 @@ function sectionPaperPanel(options) {
2557
2949
  }
2558
2950
 
2559
2951
  // packages/ui/src/lib/section-chip.ts
2560
- var STYLE11 = `
2952
+ var STYLE13 = `
2561
2953
  .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
2954
  .bb-secchip *{box-sizing:border-box}
2563
2955
  .bb-secchip-title{padding:0 7px;font-size:11px;font-weight:600;opacity:.8}
@@ -2570,7 +2962,7 @@ var STYLE11 = `
2570
2962
  .bb-secchip-x:hover{background:var(--bb-ui-hover,#f1efe8);opacity:1}
2571
2963
  `;
2572
2964
  function createSectionChip(options) {
2573
- injectStyle("bb-ui-section-chip-styles", STYLE11);
2965
+ injectStyle("bb-ui-section-chip-styles", STYLE13);
2574
2966
  const el5 = document.createElement("div");
2575
2967
  el5.className = "bb-secchip";
2576
2968
  const title = document.createElement("span");
@@ -2627,7 +3019,7 @@ var halfToPt = (hp) => hp / 2;
2627
3019
  var ptToHalf = (pt) => Math.round(pt * 2);
2628
3020
  var SCALE_PRESETS = [200, 150, 100, 90, 80, 66, 50, 33];
2629
3021
  var SUPERSUB_SCALE = 0.66;
2630
- var STYLE12 = `
3022
+ var STYLE14 = `
2631
3023
  .bb-fd{display:flex;flex-direction:column;gap:15px;min-width:396px;max-width:430px;color:var(--bb-ui-fg,#2c2c2a)}
2632
3024
  .bb-fd *{box-sizing:border-box}
2633
3025
  /* A segmented control, not a "tab joined to its pane": that pattern needs the
@@ -2709,7 +3101,7 @@ function openFontDialog({
2709
3101
  sizes,
2710
3102
  onApply
2711
3103
  }) {
2712
- injectStyle("bb-font-dialog", STYLE12);
3104
+ injectStyle("bb-font-dialog", STYLE14);
2713
3105
  const dialog = new Dialog({ title: "Font", modal: true });
2714
3106
  const root = el("div", "bb-fd");
2715
3107
  const tabs = el("div", "bb-fd-tabs");
@@ -2773,8 +3165,8 @@ function openFontDialog({
2773
3165
  label: "Text color",
2774
3166
  clearLabel: "Automatic",
2775
3167
  value: () => color,
2776
- onPick: (c) => {
2777
- color = c;
3168
+ onPick: (c2) => {
3169
+ color = c2;
2778
3170
  paint();
2779
3171
  }
2780
3172
  });
@@ -2783,8 +3175,8 @@ function openFontDialog({
2783
3175
  label: "Highlight",
2784
3176
  clearLabel: "No highlight",
2785
3177
  value: () => highlight2,
2786
- onPick: (c) => {
2787
- highlight2 = c;
3178
+ onPick: (c2) => {
3179
+ highlight2 = c2;
2788
3180
  paint();
2789
3181
  }
2790
3182
  });
@@ -2909,8 +3301,8 @@ function openFontDialog({
2909
3301
  s.transform = scale === 100 ? "none" : `scaleX(${scale / 100})`;
2910
3302
  s.verticalAlign = supCb.checked ? "super" : subCb.checked ? "sub" : `${positionPt}pt`;
2911
3303
  }
2912
- for (const c of [familySel, sizeSel, scaleSel])
2913
- c.addEventListener("change", paint);
3304
+ for (const c2 of [familySel, sizeSel, scaleSel])
3305
+ c2.addEventListener("change", paint);
2914
3306
  for (const i of [spacingInput, positionInput])
2915
3307
  i.addEventListener("input", paint);
2916
3308
  const foot = el("div", "bb-fd-foot");
@@ -2950,7 +3342,7 @@ function openFontDialog({
2950
3342
  }
2951
3343
 
2952
3344
  // packages/ui/src/lib/symbol-sets.ts
2953
- var import_bapbong_contracts2 = require("@shadow-garden/bapbong-contracts");
3345
+ var import_bapbong_contracts4 = require("@shadow-garden/bapbong-contracts");
2954
3346
  var g = (id, label, short, pairs) => ({
2955
3347
  id,
2956
3348
  label,
@@ -3286,7 +3678,7 @@ var SYMBOL_GROUPS = [
3286
3678
  ])
3287
3679
  ];
3288
3680
  function autoCorrectHint(char) {
3289
- return import_bapbong_contracts2.AUTOCORRECT_RULES.find((r) => r.to === char)?.seq ?? "";
3681
+ return import_bapbong_contracts4.AUTOCORRECT_RULES.find((r) => r.to === char)?.seq ?? "";
3290
3682
  }
3291
3683
  var SPECIAL_CHARACTERS = [
3292
3684
  { char: "\u2014", name: "Em dash", hint: "" },
@@ -3331,7 +3723,7 @@ function parseCodePoint(input) {
3331
3723
  }
3332
3724
  var RECENT_MAX = 16;
3333
3725
  function pushRecent(recent, char, max = RECENT_MAX) {
3334
- return [char, ...recent.filter((c) => c !== char)].slice(0, max);
3726
+ return [char, ...recent.filter((c2) => c2 !== char)].slice(0, max);
3335
3727
  }
3336
3728
  function searchSymbols(query) {
3337
3729
  const q = query.trim().toLowerCase();
@@ -3351,7 +3743,7 @@ function searchSymbols(query) {
3351
3743
  }
3352
3744
 
3353
3745
  // packages/ui/src/lib/symbol-dialog.ts
3354
- var STYLE13 = `
3746
+ var STYLE15 = `
3355
3747
  .bb-sd{display:flex;flex-direction:column;gap:12px;width:412px;max-width:100%;color:var(--bb-ui-fg,#2c2c2a)}
3356
3748
  .bb-sd *{box-sizing:border-box}
3357
3749
  .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 +3804,7 @@ function glyphFor(char) {
3412
3804
  return char;
3413
3805
  }
3414
3806
  function createSymbolDialog(options) {
3415
- injectStyle("bb-symbol-dialog", STYLE13);
3807
+ injectStyle("bb-symbol-dialog", STYLE15);
3416
3808
  let recent = [...options.recent ?? []].slice(0, RECENT_MAX);
3417
3809
  let selected = null;
3418
3810
  const root = el2("div", "bb-sd");
@@ -3601,9 +3993,9 @@ function createSymbolDialog(options) {
3601
3993
  function renderRecent() {
3602
3994
  fillGrid(
3603
3995
  recentGrid,
3604
- recent.map((c) => ({
3605
- char: c,
3606
- name: SYMBOL_NAMES.get(c) ?? "Character"
3996
+ recent.map((c2) => ({
3997
+ char: c2,
3998
+ name: SYMBOL_NAMES.get(c2) ?? "Character"
3607
3999
  })),
3608
4000
  RECENT_COLS,
3609
4001
  "Nothing yet \u2014 inserted symbols appear here."
@@ -3647,7 +4039,7 @@ function createSymbolDialog(options) {
3647
4039
  code.removeAttribute("aria-invalid");
3648
4040
  const cell = Array.from(
3649
4041
  grid.querySelectorAll(".bb-sd-cell")
3650
- ).find((c) => c.textContent === glyphFor(ch));
4042
+ ).find((c2) => c2.textContent === glyphFor(ch));
3651
4043
  select2(ch, cell ?? null);
3652
4044
  } else {
3653
4045
  code.setAttribute("aria-invalid", code.value.trim() ? "true" : "false");
@@ -3690,7 +4082,7 @@ function createSymbolDialog(options) {
3690
4082
  }
3691
4083
 
3692
4084
  // packages/ui/src/lib/symbol-popover.ts
3693
- var STYLE14 = `
4085
+ var STYLE16 = `
3694
4086
  .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
4087
  .bb-spk *{box-sizing:border-box}
3696
4088
  .bb-spk::backdrop{background:transparent}
@@ -3723,7 +4115,7 @@ function el3(tag, cls, text) {
3723
4115
  return n;
3724
4116
  }
3725
4117
  function openSymbolPopover(options) {
3726
- injectStyle("bb-ui-symbol-popover", STYLE14);
4118
+ injectStyle("bb-ui-symbol-popover", STYLE16);
3727
4119
  const { anchor } = options;
3728
4120
  let recent = [...options.recent ?? []].slice(0, RECENT_MAX);
3729
4121
  let groupId = SYMBOL_GROUPS[0].id;
@@ -3754,16 +4146,16 @@ function openSymbolPopover(options) {
3754
4146
  const chips = el3("div", "bb-spk-chips");
3755
4147
  const chipEls = /* @__PURE__ */ new Map();
3756
4148
  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", () => {
4149
+ const c2 = el3("button", "bb-spk-chip", grp.short);
4150
+ c2.type = "button";
4151
+ c2.title = grp.label;
4152
+ c2.addEventListener("click", () => {
3761
4153
  groupId = grp.id;
3762
4154
  search.value = "";
3763
4155
  render();
3764
4156
  });
3765
- chips.append(c);
3766
- chipEls.set(grp.id, c);
4157
+ chips.append(c2);
4158
+ chipEls.set(grp.id, c2);
3767
4159
  }
3768
4160
  const grid = el3("div", "bb-spk-grid");
3769
4161
  grid.setAttribute("role", "grid");
@@ -3834,9 +4226,9 @@ function openSymbolPopover(options) {
3834
4226
  };
3835
4227
  const renderRecent = () => fill(
3836
4228
  recentGrid,
3837
- recent.slice(0, RECENT_ROW).map((c) => ({
3838
- char: c,
3839
- name: SYMBOL_NAMES.get(c) ?? "Character"
4229
+ recent.slice(0, RECENT_ROW).map((c2) => ({
4230
+ char: c2,
4231
+ name: SYMBOL_NAMES.get(c2) ?? "Character"
3840
4232
  })),
3841
4233
  "Nothing yet."
3842
4234
  );
@@ -3844,8 +4236,8 @@ function openSymbolPopover(options) {
3844
4236
  const q = search.value.trim();
3845
4237
  const byCode = q ? parseCodePoint(q) : null;
3846
4238
  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));
4239
+ for (const [id, c2] of chipEls)
4240
+ c2.setAttribute("aria-pressed", String(!q && id === groupId));
3849
4241
  fill(grid, entries, "No match.");
3850
4242
  const first = grid.querySelector(".bb-spk-cell");
3851
4243
  if (q && first && entries[0]) select2(entries[0].char, first);
@@ -3884,8 +4276,8 @@ function openSymbolPopover(options) {
3884
4276
  }
3885
4277
 
3886
4278
  // packages/ui/src/lib/shortcuts-dialog.ts
3887
- var import_bapbong_contracts3 = require("@shadow-garden/bapbong-contracts");
3888
- var STYLE15 = `
4279
+ var import_bapbong_contracts5 = require("@shadow-garden/bapbong-contracts");
4280
+ var STYLE17 = `
3889
4281
  .bb-ks{display:flex;flex-direction:column;gap:10px;width:600px;max-width:100%;color:var(--bb-ui-fg,#2c2c2a);font-size:12px}
3890
4282
  .bb-ks *{box-sizing:border-box}
3891
4283
  .bb-ks-top{display:flex;gap:8px;align-items:center}
@@ -3943,7 +4335,7 @@ function highlight(text, q) {
3943
4335
  return out;
3944
4336
  }
3945
4337
  function openKeyboardShortcutsDialog(options) {
3946
- injectStyle("bb-ui-shortcuts-dialog", STYLE15);
4338
+ injectStyle("bb-ui-shortcuts-dialog", STYLE17);
3947
4339
  const dialog = new Dialog({
3948
4340
  title: options.title ?? "Keyboard shortcuts",
3949
4341
  modal: true,
@@ -3970,19 +4362,19 @@ function openKeyboardShortcutsDialog(options) {
3970
4362
  let sortKey = "title";
3971
4363
  let sortAsc = true;
3972
4364
  const ths = /* @__PURE__ */ new Map();
3973
- for (const c of columns) {
4365
+ for (const c2 of columns) {
3974
4366
  const th = el4("th");
3975
- th.append(el4("span", void 0, c.label));
4367
+ th.append(el4("span", void 0, c2.label));
3976
4368
  th.addEventListener("click", () => {
3977
- if (sortKey === c.key) sortAsc = !sortAsc;
4369
+ if (sortKey === c2.key) sortAsc = !sortAsc;
3978
4370
  else {
3979
- sortKey = c.key;
4371
+ sortKey = c2.key;
3980
4372
  sortAsc = true;
3981
4373
  }
3982
4374
  render();
3983
4375
  });
3984
4376
  headRow.append(th);
3985
- ths.set(c.key, th);
4377
+ ths.set(c2.key, th);
3986
4378
  }
3987
4379
  thead.append(headRow);
3988
4380
  const tbody = el4("tbody");
@@ -4002,7 +4394,7 @@ function openKeyboardShortcutsDialog(options) {
4002
4394
  const rows = [];
4003
4395
  for (const src of options.sources)
4004
4396
  rows.push(
4005
- ...(0, import_bapbong_contracts3.keybindingRows)(src.keybindings, (c) => src.commands.get(c)?.title)
4397
+ ...(0, import_bapbong_contracts5.keybindingRows)(src.keybindings, (c2) => src.commands.get(c2)?.title)
4006
4398
  );
4007
4399
  return rows;
4008
4400
  };
@@ -4010,13 +4402,13 @@ function openKeyboardShortcutsDialog(options) {
4010
4402
  const td = el4("td");
4011
4403
  keys.forEach((k, i) => {
4012
4404
  if (i > 0) td.append(el4("span", "or", "or"));
4013
- for (const part of (0, import_bapbong_contracts3.formatKey)(k, IS_MAC))
4405
+ for (const part of (0, import_bapbong_contracts5.formatKey)(k, IS_MAC))
4014
4406
  td.append(el4("kbd", void 0, part));
4015
4407
  });
4016
4408
  return td;
4017
4409
  };
4018
4410
  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;
4411
+ const val = (r) => sortKey === "title" ? r.title : sortKey === "keys" ? r.keys.map((k) => (0, import_bapbong_contracts5.formatKey)(k, IS_MAC).join("")).join(" ") : sortKey === "when" ? r.when ?? "" : r.source;
4020
4412
  const sorted = [...rows].sort(
4021
4413
  (a, b) => val(a).localeCompare(val(b), void 0, { sensitivity: "base" })
4022
4414
  );
@@ -4025,7 +4417,7 @@ function openKeyboardShortcutsDialog(options) {
4025
4417
  const render = () => {
4026
4418
  const q = search.value.trim().toLowerCase();
4027
4419
  const rows = allRows();
4028
- const shown = sortRows((0, import_bapbong_contracts3.filterKeybindingRows)(rows, q, IS_MAC));
4420
+ const shown = sortRows((0, import_bapbong_contracts5.filterKeybindingRows)(rows, q, IS_MAC));
4029
4421
  for (const [key, th] of ths) {
4030
4422
  if (key === sortKey)
4031
4423
  th.setAttribute("aria-sort", sortAsc ? "ascending" : "descending");
@@ -4059,7 +4451,7 @@ function openKeyboardShortcutsDialog(options) {
4059
4451
  tbody.append(tr);
4060
4452
  }
4061
4453
  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`;
4454
+ footL.textContent = `Sorted by ${columns.find((c2) => c2.key === sortKey)?.label.toLowerCase()} \xB7 click a header to sort`;
4063
4455
  };
4064
4456
  search.addEventListener("input", render);
4065
4457
  dialog.onClose(() => dialog.destroy());
@@ -4069,7 +4461,7 @@ function openKeyboardShortcutsDialog(options) {
4069
4461
  }
4070
4462
 
4071
4463
  // packages/ui/src/lib/scrollbars.ts
4072
- var STYLE16 = `
4464
+ var STYLE18 = `
4073
4465
  @property --bb-scroll-thumb-now {
4074
4466
  syntax: '<color>';
4075
4467
  /* MUST inherit: the thumb pseudo-element never matches .bb-scrolling
@@ -4101,7 +4493,7 @@ var STYLE16 = `
4101
4493
  var installed = null;
4102
4494
  function installScrollbars(root = document) {
4103
4495
  if (installed) return installed;
4104
- injectStyle("bb-ui-scrollbars", STYLE16);
4496
+ injectStyle("bb-ui-scrollbars", STYLE18);
4105
4497
  const quiet = /* @__PURE__ */ new WeakMap();
4106
4498
  const onScroll = (ev) => {
4107
4499
  const el5 = ev.target instanceof HTMLElement ? ev.target : root.documentElement;
@@ -4121,6 +4513,7 @@ function installScrollbars(root = document) {
4121
4513
  }
4122
4514
  // Annotate the CommonJS export names for ESM import in node:
4123
4515
  0 && (module.exports = {
4516
+ BUILT_IN_EQUATIONS,
4124
4517
  COLOR_PALETTE,
4125
4518
  Dialog,
4126
4519
  RECENT_MAX,
@@ -4135,6 +4528,9 @@ function installScrollbars(root = document) {
4135
4528
  createSymbolDialog,
4136
4529
  defaultMenus,
4137
4530
  defaultToolbarGroups,
4531
+ equationGallery,
4532
+ equationPanel,
4533
+ equationPreviewSvg,
4138
4534
  installScrollbars,
4139
4535
  marginPresetPicker,
4140
4536
  mountMenubar,