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