@shadow-garden/bapbong-ui 0.13.3 → 0.14.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 +1432 -153
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1423 -153
- package/dist/lib/color-picker.d.ts.map +1 -1
- package/dist/lib/dialog.d.ts +24 -0
- package/dist/lib/dialog.d.ts.map +1 -1
- package/dist/lib/internal.d.ts +25 -1
- package/dist/lib/internal.d.ts.map +1 -1
- package/dist/lib/menubar.d.ts +11 -1
- package/dist/lib/menubar.d.ts.map +1 -1
- package/dist/lib/scrollbars.d.ts +4 -0
- package/dist/lib/scrollbars.d.ts.map +1 -0
- package/dist/lib/shortcuts-dialog.d.ts +23 -0
- package/dist/lib/shortcuts-dialog.d.ts.map +1 -0
- package/dist/lib/symbol-dialog.d.ts +34 -0
- package/dist/lib/symbol-dialog.d.ts.map +1 -0
- package/dist/lib/symbol-popover.d.ts +30 -0
- package/dist/lib/symbol-popover.d.ts.map +1 -0
- package/dist/lib/symbol-sets.d.ts +53 -0
- package/dist/lib/symbol-sets.d.ts.map +1 -0
- package/dist/lib/toolbar.d.ts +18 -2
- package/dist/lib/toolbar.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -22,25 +22,38 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
COLOR_PALETTE: () => COLOR_PALETTE,
|
|
24
24
|
Dialog: () => Dialog,
|
|
25
|
+
RECENT_MAX: () => RECENT_MAX,
|
|
26
|
+
SPECIAL_CHARACTERS: () => SPECIAL_CHARACTERS,
|
|
27
|
+
SYMBOL_GROUPS: () => SYMBOL_GROUPS,
|
|
28
|
+
SYMBOL_NAMES: () => SYMBOL_NAMES,
|
|
25
29
|
cmToPx: () => cmToPx,
|
|
30
|
+
codePointLabel: () => codePointLabel,
|
|
26
31
|
colorButton: () => colorButton,
|
|
27
32
|
createFindDialog: () => createFindDialog,
|
|
28
33
|
createSectionChip: () => createSectionChip,
|
|
34
|
+
createSymbolDialog: () => createSymbolDialog,
|
|
29
35
|
defaultMenus: () => defaultMenus,
|
|
30
36
|
defaultToolbarGroups: () => defaultToolbarGroups,
|
|
37
|
+
installScrollbars: () => installScrollbars,
|
|
31
38
|
marginPresetPicker: () => marginPresetPicker,
|
|
32
39
|
mountMenubar: () => mountMenubar,
|
|
33
40
|
mountToolbar: () => mountToolbar,
|
|
34
41
|
openCellProperties: () => openCellProperties,
|
|
35
42
|
openColorPicker: () => openColorPicker,
|
|
36
43
|
openFontDialog: () => openFontDialog,
|
|
44
|
+
openKeyboardShortcutsDialog: () => openKeyboardShortcutsDialog,
|
|
37
45
|
openMarginsDialog: () => openMarginsDialog,
|
|
38
46
|
openPageSizeDialog: () => openPageSizeDialog,
|
|
47
|
+
openSymbolPopover: () => openSymbolPopover,
|
|
39
48
|
orientationPicker: () => orientationPicker,
|
|
40
49
|
pageNumberPicker: () => pageNumberPicker,
|
|
41
50
|
pageSizePicker: () => pageSizePicker,
|
|
51
|
+
panelAnchor: () => panelAnchor,
|
|
52
|
+
parseCodePoint: () => parseCodePoint,
|
|
42
53
|
promptDialog: () => promptDialog,
|
|
54
|
+
pushRecent: () => pushRecent,
|
|
43
55
|
pxToCm: () => pxToCm,
|
|
56
|
+
searchSymbols: () => searchSymbols,
|
|
44
57
|
sectionPaperPanel: () => sectionPaperPanel,
|
|
45
58
|
showContextMenu: () => showContextMenu,
|
|
46
59
|
showLinkPanel: () => showLinkPanel,
|
|
@@ -51,15 +64,25 @@ __export(index_exports, {
|
|
|
51
64
|
module.exports = __toCommonJS(index_exports);
|
|
52
65
|
|
|
53
66
|
// packages/ui/src/lib/internal.ts
|
|
67
|
+
var import_bapbong_contracts = require("@shadow-garden/bapbong-contracts");
|
|
68
|
+
var IS_MAC = typeof navigator !== "undefined" ? /Mac|iP(hone|[oa]d)/.test(navigator.platform) : false;
|
|
69
|
+
function shortcutLabel(command, registries) {
|
|
70
|
+
for (const r of registries) {
|
|
71
|
+
if (!r) continue;
|
|
72
|
+
for (const b of r)
|
|
73
|
+
if (b.command === command) return (0, import_bapbong_contracts.keyLabel)(b.key, IS_MAC);
|
|
74
|
+
}
|
|
75
|
+
return void 0;
|
|
76
|
+
}
|
|
54
77
|
function injectStyle(id, css) {
|
|
55
78
|
if (document.getElementById(id)) return;
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
document.head.appendChild(
|
|
79
|
+
const el5 = document.createElement("style");
|
|
80
|
+
el5.id = id;
|
|
81
|
+
el5.textContent = css;
|
|
82
|
+
document.head.appendChild(el5);
|
|
60
83
|
}
|
|
61
|
-
function placeFloating(
|
|
62
|
-
const r =
|
|
84
|
+
function placeFloating(el5, anchor) {
|
|
85
|
+
const r = el5.getBoundingClientRect();
|
|
63
86
|
const pad = 6;
|
|
64
87
|
const gap = 6;
|
|
65
88
|
const x = Math.max(
|
|
@@ -69,16 +92,75 @@ function placeFloating(el2, anchor) {
|
|
|
69
92
|
const below = anchor.y + anchor.height + gap;
|
|
70
93
|
const above = anchor.y - gap - r.height;
|
|
71
94
|
const y = below + r.height <= window.innerHeight - pad || above < pad ? Math.min(below, window.innerHeight - r.height - pad) : above;
|
|
72
|
-
|
|
73
|
-
|
|
95
|
+
el5.style.left = `${x}px`;
|
|
96
|
+
el5.style.top = `${y}px`;
|
|
97
|
+
}
|
|
98
|
+
function rovingGrid(cells) {
|
|
99
|
+
let cur = [0, 0];
|
|
100
|
+
const at = (r, c) => cells[r]?.[c];
|
|
101
|
+
const focusCell = (r, c) => {
|
|
102
|
+
const rows = cells.length;
|
|
103
|
+
if (rows === 0) return;
|
|
104
|
+
const nr = Math.min(rows - 1, Math.max(0, r));
|
|
105
|
+
const nc = Math.min(cells[nr].length - 1, Math.max(0, c));
|
|
106
|
+
const prev = at(cur[0], cur[1]);
|
|
107
|
+
if (prev) prev.tabIndex = -1;
|
|
108
|
+
const next = at(nr, nc);
|
|
109
|
+
if (!next) return;
|
|
110
|
+
next.tabIndex = 0;
|
|
111
|
+
next.focus();
|
|
112
|
+
cur = [nr, nc];
|
|
113
|
+
};
|
|
114
|
+
cells.forEach(
|
|
115
|
+
(row, r) => row.forEach((cell, c) => {
|
|
116
|
+
cell.setAttribute("role", "gridcell");
|
|
117
|
+
cell.tabIndex = r === 0 && c === 0 ? 0 : -1;
|
|
118
|
+
cell.addEventListener("keydown", (e) => {
|
|
119
|
+
const delta = {
|
|
120
|
+
ArrowRight: [0, 1],
|
|
121
|
+
ArrowLeft: [0, -1],
|
|
122
|
+
ArrowDown: [1, 0],
|
|
123
|
+
ArrowUp: [-1, 0],
|
|
124
|
+
Home: [0, -Infinity],
|
|
125
|
+
End: [0, Infinity]
|
|
126
|
+
};
|
|
127
|
+
const d = delta[e.key];
|
|
128
|
+
if (!d) return;
|
|
129
|
+
e.preventDefault();
|
|
130
|
+
focusCell(r + d[0], c + d[1]);
|
|
131
|
+
});
|
|
132
|
+
cell.addEventListener("focus", () => {
|
|
133
|
+
cur = [r, c];
|
|
134
|
+
});
|
|
135
|
+
})
|
|
136
|
+
);
|
|
137
|
+
return { focusCell };
|
|
74
138
|
}
|
|
75
139
|
|
|
76
140
|
// packages/ui/src/lib/dialog.ts
|
|
141
|
+
function panelAnchor(o) {
|
|
142
|
+
return () => {
|
|
143
|
+
const areaEl = o.area();
|
|
144
|
+
if (!areaEl) return null;
|
|
145
|
+
const a = areaEl.getBoundingClientRect();
|
|
146
|
+
let top = a.top;
|
|
147
|
+
for (const el5 of o.avoid?.() ?? []) {
|
|
148
|
+
if (!el5) continue;
|
|
149
|
+
const b = el5.getBoundingClientRect();
|
|
150
|
+
const overlapsX = b.right > a.left && b.left < a.right;
|
|
151
|
+
const overTop = b.top < a.bottom && b.bottom > top;
|
|
152
|
+
if (overlapsX && overTop) top = Math.max(top, b.bottom);
|
|
153
|
+
}
|
|
154
|
+
if (top >= a.bottom) return null;
|
|
155
|
+
return new DOMRect(a.left, top, a.width, a.bottom - top);
|
|
156
|
+
};
|
|
157
|
+
}
|
|
77
158
|
var STYLE = `
|
|
78
159
|
.bb-dialog{position:fixed;inset:auto;z-index:1100;margin:0;padding:0;border:1px solid var(--bb-ui-pop-border,var(--bb-ui-border,#e3e3e0));border-radius:10px;background:var(--bb-ui-dialog-bg,var(--bb-ui-menu-bg,#fff));-webkit-backdrop-filter:var(--bb-ui-dialog-filter,none);backdrop-filter:var(--bb-ui-dialog-filter,none);color:var(--bb-ui-fg,#2c2c2a);box-shadow:0 12px 40px rgba(0,0,0,.18);font-family:var(--bb-ui-font,system-ui,-apple-system,sans-serif);min-width:280px;max-width:min(92vw,440px)}
|
|
79
160
|
.bb-dialog *{box-sizing:border-box}
|
|
80
161
|
.bb-dialog::backdrop{background:rgba(0,0,0,.28)}
|
|
81
162
|
.bb-dialog-modal{top:50%;left:50%;transform:translate(-50%,-50%)}
|
|
163
|
+
.bb-dialog-wide{max-width:min(92vw,640px)}
|
|
82
164
|
.bb-dialog-float{top:62px;right:24px}
|
|
83
165
|
.bb-dialog-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 10px 9px 12px;border-bottom:1px solid var(--bb-ui-border,#e3e3e0)}
|
|
84
166
|
.bb-dialog-title{font-size:13px;font-weight:600}
|
|
@@ -112,8 +194,8 @@ var Dialog = class {
|
|
|
112
194
|
injectStyle("bb-ui-dialog-styles", STYLE);
|
|
113
195
|
this.modal = options.modal ?? false;
|
|
114
196
|
this.anchor = options.anchor;
|
|
115
|
-
const
|
|
116
|
-
|
|
197
|
+
const el5 = document.createElement("dialog");
|
|
198
|
+
el5.className = `bb-dialog ${this.modal ? "bb-dialog-modal" : "bb-dialog-float"}` + (options.wide ? " bb-dialog-wide" : "") + (options.className ? ` ${options.className}` : "");
|
|
117
199
|
const header = document.createElement("div");
|
|
118
200
|
header.className = "bb-dialog-header";
|
|
119
201
|
this.title = document.createElement("span");
|
|
@@ -128,18 +210,18 @@ var Dialog = class {
|
|
|
128
210
|
header.append(this.title, close);
|
|
129
211
|
this.body = document.createElement("div");
|
|
130
212
|
this.body.className = "bb-dialog-body";
|
|
131
|
-
|
|
132
|
-
document.body.appendChild(
|
|
133
|
-
|
|
213
|
+
el5.append(header, this.body);
|
|
214
|
+
document.body.appendChild(el5);
|
|
215
|
+
el5.addEventListener("close", () => {
|
|
134
216
|
this.detachReposition();
|
|
135
217
|
this.closeListeners.forEach((cb) => cb());
|
|
136
218
|
});
|
|
137
219
|
if (!this.modal) {
|
|
138
|
-
|
|
220
|
+
el5.addEventListener("keydown", (e) => {
|
|
139
221
|
if (e.key === "Escape") this.close();
|
|
140
222
|
});
|
|
141
223
|
}
|
|
142
|
-
this.el =
|
|
224
|
+
this.el = el5;
|
|
143
225
|
}
|
|
144
226
|
attachReposition() {
|
|
145
227
|
window.addEventListener("scroll", this.reposition, true);
|
|
@@ -398,45 +480,24 @@ function openColorPicker({
|
|
|
398
480
|
grid.className = "bb-cpk-grid";
|
|
399
481
|
grid.setAttribute("role", "grid");
|
|
400
482
|
const cells = [];
|
|
401
|
-
COLOR_PALETTE.forEach((row
|
|
483
|
+
COLOR_PALETTE.forEach((row) => {
|
|
402
484
|
const rowCells = [];
|
|
403
|
-
row.forEach((color
|
|
485
|
+
row.forEach((color) => {
|
|
404
486
|
const sw = document.createElement("button");
|
|
405
487
|
sw.type = "button";
|
|
406
488
|
sw.className = "bb-cpk-sw";
|
|
407
489
|
sw.style.background = color;
|
|
408
490
|
sw.title = color;
|
|
409
|
-
sw.setAttribute("role", "gridcell");
|
|
410
491
|
sw.setAttribute("aria-label", color);
|
|
411
|
-
sw.tabIndex = -1;
|
|
412
492
|
if (color.toUpperCase() === value?.toUpperCase()) sw.classList.add("on");
|
|
413
493
|
sw.addEventListener("click", () => pick(color));
|
|
414
|
-
sw.addEventListener("keydown", (e) => onGridKey(e, r2, c));
|
|
415
494
|
grid.append(sw);
|
|
416
495
|
rowCells.push(sw);
|
|
417
496
|
});
|
|
418
497
|
cells.push(rowCells);
|
|
419
498
|
});
|
|
420
499
|
panel.append(grid);
|
|
421
|
-
|
|
422
|
-
const delta = {
|
|
423
|
-
ArrowRight: [0, 1],
|
|
424
|
-
ArrowLeft: [0, -1],
|
|
425
|
-
ArrowDown: [1, 0],
|
|
426
|
-
ArrowUp: [-1, 0]
|
|
427
|
-
};
|
|
428
|
-
const d = delta[e.key];
|
|
429
|
-
if (!d) return;
|
|
430
|
-
e.preventDefault();
|
|
431
|
-
const rows = cells.length;
|
|
432
|
-
const cols = cells[0].length;
|
|
433
|
-
const nr = Math.min(rows - 1, Math.max(0, r2 + d[0]));
|
|
434
|
-
const nc = Math.min(cols - 1, Math.max(0, c + d[1]));
|
|
435
|
-
cells[r2][c].tabIndex = -1;
|
|
436
|
-
const next = cells[nr][nc];
|
|
437
|
-
next.tabIndex = 0;
|
|
438
|
-
next.focus();
|
|
439
|
-
}
|
|
500
|
+
const nav = rovingGrid(cells);
|
|
440
501
|
panel.append(
|
|
441
502
|
Object.assign(document.createElement("div"), {
|
|
442
503
|
className: "bb-cpk-cap",
|
|
@@ -492,36 +553,38 @@ function openColorPicker({
|
|
|
492
553
|
if (outside) close();
|
|
493
554
|
});
|
|
494
555
|
window.addEventListener("scroll", close, true);
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
556
|
+
const onRow = cells.findIndex(
|
|
557
|
+
(row) => row.some((el5) => el5.classList.contains("on"))
|
|
558
|
+
);
|
|
559
|
+
const onCol = onRow >= 0 ? cells[onRow].findIndex((el5) => el5.classList.contains("on")) : 0;
|
|
560
|
+
nav.focusCell(Math.max(0, onRow), Math.max(0, onCol));
|
|
498
561
|
return { close };
|
|
499
562
|
}
|
|
500
563
|
function colorButton(o) {
|
|
501
564
|
injectStyle("bb-ui-colorpicker-styles", STYLE2);
|
|
502
|
-
const
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
565
|
+
const el5 = document.createElement("button");
|
|
566
|
+
el5.type = "button";
|
|
567
|
+
el5.className = `bb-cpk-btn${o.glyph ? " glyphed" : ""}`;
|
|
568
|
+
el5.title = o.title;
|
|
569
|
+
el5.setAttribute("aria-label", o.title);
|
|
570
|
+
el5.setAttribute("aria-haspopup", "dialog");
|
|
508
571
|
let chip;
|
|
509
572
|
if (o.glyph) {
|
|
510
|
-
const
|
|
511
|
-
|
|
512
|
-
|
|
573
|
+
const g2 = document.createElement("span");
|
|
574
|
+
g2.className = "bb-cpk-btn-glyph";
|
|
575
|
+
g2.innerHTML = o.glyph;
|
|
513
576
|
chip = document.createElement("span");
|
|
514
577
|
chip.className = "bb-cpk-btn-bar";
|
|
515
|
-
|
|
578
|
+
el5.append(g2, chip);
|
|
516
579
|
} else {
|
|
517
580
|
chip = document.createElement("span");
|
|
518
581
|
chip.className = "bb-cpk-btn-chip";
|
|
519
|
-
|
|
520
|
-
if (o.label)
|
|
582
|
+
el5.append(chip);
|
|
583
|
+
if (o.label) el5.append(document.createTextNode(o.label));
|
|
521
584
|
const caret = document.createElement("span");
|
|
522
585
|
caret.className = "bb-cpk-btn-caret";
|
|
523
586
|
caret.textContent = "\u25BE";
|
|
524
|
-
|
|
587
|
+
el5.append(caret);
|
|
525
588
|
}
|
|
526
589
|
function sync() {
|
|
527
590
|
const v = o.value();
|
|
@@ -529,10 +592,10 @@ function colorButton(o) {
|
|
|
529
592
|
chip.classList.toggle("none", !v && !o.glyph);
|
|
530
593
|
chip.textContent = !v && !o.glyph ? "\u29B8" : "";
|
|
531
594
|
}
|
|
532
|
-
|
|
533
|
-
|
|
595
|
+
el5.addEventListener("mousedown", (e) => e.preventDefault());
|
|
596
|
+
el5.addEventListener("click", () => {
|
|
534
597
|
openColorPicker({
|
|
535
|
-
anchor:
|
|
598
|
+
anchor: el5,
|
|
536
599
|
value: o.value(),
|
|
537
600
|
clearLabel: o.clearLabel,
|
|
538
601
|
onPick: (c) => {
|
|
@@ -542,7 +605,7 @@ function colorButton(o) {
|
|
|
542
605
|
});
|
|
543
606
|
});
|
|
544
607
|
sync();
|
|
545
|
-
return { el:
|
|
608
|
+
return { el: el5, sync };
|
|
546
609
|
}
|
|
547
610
|
|
|
548
611
|
// packages/ui/src/lib/toolbar.ts
|
|
@@ -650,7 +713,7 @@ function defaultToolbarGroups(commands) {
|
|
|
650
713
|
const names = [...commands].map((c) => c.name);
|
|
651
714
|
const aligns = names.filter((n) => n.startsWith("align-"));
|
|
652
715
|
const rest = names.filter((n) => !n.startsWith("align-"));
|
|
653
|
-
return [rest, aligns].filter((
|
|
716
|
+
return [rest, aligns].filter((g2) => g2.length > 0);
|
|
654
717
|
}
|
|
655
718
|
function mountToolbar(host, editor, options = {}) {
|
|
656
719
|
injectStyle("bb-ui-toolbar-styles", STYLE3);
|
|
@@ -695,6 +758,20 @@ function mountToolbar(host, editor, options = {}) {
|
|
|
695
758
|
selects.push({ spec: entry, el: sel });
|
|
696
759
|
continue;
|
|
697
760
|
}
|
|
761
|
+
if (typeof entry !== "string" && entry.kind === "button") {
|
|
762
|
+
const btn2 = document.createElement("button");
|
|
763
|
+
btn2.type = "button";
|
|
764
|
+
btn2.className = "bb-toolbar-btn";
|
|
765
|
+
btn2.title = entry.title;
|
|
766
|
+
btn2.setAttribute("aria-label", entry.title);
|
|
767
|
+
btn2.setAttribute("aria-haspopup", "dialog");
|
|
768
|
+
if (entry.svg) btn2.innerHTML = entry.svg;
|
|
769
|
+
else btn2.textContent = entry.label ?? entry.title;
|
|
770
|
+
btn2.addEventListener("mousedown", (e) => e.preventDefault());
|
|
771
|
+
btn2.addEventListener("click", () => entry.onClick(btn2));
|
|
772
|
+
groupEl.appendChild(btn2);
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
698
775
|
if (typeof entry !== "string" && entry.kind === "color") {
|
|
699
776
|
const ctl = colorButton({
|
|
700
777
|
title: entry.title,
|
|
@@ -805,6 +882,10 @@ function mountToolbar(host, editor, options = {}) {
|
|
|
805
882
|
btn.type = "button";
|
|
806
883
|
btn.className = "bb-toolbar-btn" + (item.className ? ` ${item.className}` : "");
|
|
807
884
|
btn.title = item.title;
|
|
885
|
+
btn.addEventListener("mouseenter", () => {
|
|
886
|
+
const key = shortcutLabel(entry, [editor.keybindings]);
|
|
887
|
+
btn.title = key ? `${item.title} (${key})` : item.title;
|
|
888
|
+
});
|
|
808
889
|
btn.setAttribute("aria-label", item.title);
|
|
809
890
|
if (item.svg) btn.innerHTML = item.svg;
|
|
810
891
|
else btn.textContent = item.label ?? entry;
|
|
@@ -855,7 +936,7 @@ function mountToolbar(host, editor, options = {}) {
|
|
|
855
936
|
if (fits()) return;
|
|
856
937
|
moreBtn.style.display = "";
|
|
857
938
|
const groupEls = Array.from(root.children).filter(
|
|
858
|
-
(
|
|
939
|
+
(el5) => el5.classList.contains("bb-toolbar-group")
|
|
859
940
|
);
|
|
860
941
|
for (let i = groupEls.length - 1; i >= 0 && !fits(); i--) {
|
|
861
942
|
pop.insertBefore(groupEls[i], pop.firstChild);
|
|
@@ -870,15 +951,15 @@ function mountToolbar(host, editor, options = {}) {
|
|
|
870
951
|
layout();
|
|
871
952
|
const refresh = (state) => {
|
|
872
953
|
latest = state;
|
|
873
|
-
for (const { name, el:
|
|
954
|
+
for (const { name, el: el5 } of buttons) {
|
|
874
955
|
const cmd = editor.commands.get(name);
|
|
875
956
|
if (!cmd) continue;
|
|
876
957
|
const active = cmd.isActive?.(state) ?? false;
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
958
|
+
el5.classList.toggle("is-active", active);
|
|
959
|
+
el5.setAttribute("aria-pressed", String(active));
|
|
960
|
+
el5.disabled = cmd.isEnabled ? !cmd.isEnabled(state) : false;
|
|
880
961
|
}
|
|
881
|
-
for (const { spec, el:
|
|
962
|
+
for (const { spec, el: el5 } of selects) el5.value = spec.value(state);
|
|
882
963
|
for (const c of colors) c.sync();
|
|
883
964
|
for (const { spec, cards } of splits) {
|
|
884
965
|
const selected = spec.value(state);
|
|
@@ -967,19 +1048,18 @@ function makeRow(label, opts) {
|
|
|
967
1048
|
text.className = "bb-menu-label";
|
|
968
1049
|
text.textContent = label;
|
|
969
1050
|
item.append(check, text);
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
}
|
|
1051
|
+
const sc = document.createElement("span");
|
|
1052
|
+
sc.className = "bb-menu-shortcut";
|
|
1053
|
+
sc.textContent = opts.shortcut ?? "";
|
|
1054
|
+
if (!opts.shortcut) sc.hidden = true;
|
|
1055
|
+
item.appendChild(sc);
|
|
976
1056
|
if (opts.hasSub) {
|
|
977
1057
|
const arrow = document.createElement("span");
|
|
978
1058
|
arrow.className = "bb-menu-arrow";
|
|
979
1059
|
arrow.textContent = "\u203A";
|
|
980
1060
|
item.appendChild(arrow);
|
|
981
1061
|
}
|
|
982
|
-
return { item, check };
|
|
1062
|
+
return { item, check, shortcutEl: sc };
|
|
983
1063
|
}
|
|
984
1064
|
function buildMenuEntries(entries, container, ctx) {
|
|
985
1065
|
for (const entry of entries) {
|
|
@@ -1010,10 +1090,11 @@ function buildMenuEntries(entries, container, ctx) {
|
|
|
1010
1090
|
const editor = ctx.editor;
|
|
1011
1091
|
const cmd = editor?.commands.get(entry.command);
|
|
1012
1092
|
if (!editor || !cmd) continue;
|
|
1013
|
-
const { item, check } = makeRow(
|
|
1093
|
+
const { item, check, shortcutEl } = makeRow(
|
|
1014
1094
|
entry.label ?? ctx.labels[entry.command] ?? entry.command,
|
|
1015
|
-
{}
|
|
1095
|
+
{ shortcut: ctx.shortcutOf?.(entry.command) }
|
|
1016
1096
|
);
|
|
1097
|
+
ctx.shortcutRef?.(shortcutEl, entry.command);
|
|
1017
1098
|
item.setAttribute("role", "menuitemcheckbox");
|
|
1018
1099
|
item.addEventListener("click", () => {
|
|
1019
1100
|
const s = ctx.state();
|
|
@@ -1026,9 +1107,10 @@ function buildMenuEntries(entries, container, ctx) {
|
|
|
1026
1107
|
if (cmd.isEnabled) ctx.enable(item, (s) => cmd.isEnabled(s));
|
|
1027
1108
|
container.appendChild(item);
|
|
1028
1109
|
} else {
|
|
1029
|
-
const { item, check } = makeRow(entry.label, {
|
|
1030
|
-
shortcut: entry.shortcut
|
|
1110
|
+
const { item, check, shortcutEl } = makeRow(entry.label, {
|
|
1111
|
+
shortcut: (entry.shortcutOf && ctx.shortcutOf?.(entry.shortcutOf)) ?? entry.shortcut
|
|
1031
1112
|
});
|
|
1113
|
+
if (entry.shortcutOf) ctx.shortcutRef?.(shortcutEl, entry.shortcutOf);
|
|
1032
1114
|
item.setAttribute(
|
|
1033
1115
|
"role",
|
|
1034
1116
|
entry.isActive ? "menuitemcheckbox" : "menuitem"
|
|
@@ -1054,15 +1136,15 @@ function closeCurrentPopup() {
|
|
|
1054
1136
|
function showPopup(content, at, onClose) {
|
|
1055
1137
|
injectStyle("bb-ui-menubar-styles", STYLE4);
|
|
1056
1138
|
closeCurrentPopup();
|
|
1057
|
-
const
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
document.body.appendChild(
|
|
1139
|
+
const el5 = document.createElement("div");
|
|
1140
|
+
el5.className = "bb-menu bb-popup";
|
|
1141
|
+
el5.setAttribute("role", "menu");
|
|
1142
|
+
el5.appendChild(content);
|
|
1143
|
+
document.body.appendChild(el5);
|
|
1062
1144
|
const place = () => {
|
|
1063
|
-
const r =
|
|
1064
|
-
|
|
1065
|
-
|
|
1145
|
+
const r = el5.getBoundingClientRect();
|
|
1146
|
+
el5.style.left = `${Math.max(4, Math.min(at.x, window.innerWidth - r.width - 4))}px`;
|
|
1147
|
+
el5.style.top = `${Math.max(4, Math.min(at.y, window.innerHeight - r.height - 4))}px`;
|
|
1066
1148
|
};
|
|
1067
1149
|
place();
|
|
1068
1150
|
let disposed = false;
|
|
@@ -1072,7 +1154,7 @@ function showPopup(content, at, onClose) {
|
|
|
1072
1154
|
document.removeEventListener("pointerdown", onPointer, true);
|
|
1073
1155
|
document.removeEventListener("keydown", onKey, true);
|
|
1074
1156
|
document.removeEventListener("scroll", onScroll, true);
|
|
1075
|
-
|
|
1157
|
+
el5.remove();
|
|
1076
1158
|
onClose?.();
|
|
1077
1159
|
};
|
|
1078
1160
|
const close = () => {
|
|
@@ -1080,7 +1162,7 @@ function showPopup(content, at, onClose) {
|
|
|
1080
1162
|
dispose();
|
|
1081
1163
|
};
|
|
1082
1164
|
const onPointer = (e) => {
|
|
1083
|
-
if (!
|
|
1165
|
+
if (!el5.contains(e.target)) close();
|
|
1084
1166
|
};
|
|
1085
1167
|
const onKey = (e) => {
|
|
1086
1168
|
if (e.key === "Escape") {
|
|
@@ -1089,13 +1171,13 @@ function showPopup(content, at, onClose) {
|
|
|
1089
1171
|
}
|
|
1090
1172
|
};
|
|
1091
1173
|
const onScroll = (e) => {
|
|
1092
|
-
if (!
|
|
1174
|
+
if (!el5.contains(e.target)) close();
|
|
1093
1175
|
};
|
|
1094
1176
|
document.addEventListener("pointerdown", onPointer, true);
|
|
1095
1177
|
document.addEventListener("keydown", onKey, true);
|
|
1096
1178
|
document.addEventListener("scroll", onScroll, true);
|
|
1097
1179
|
currentPopup = dispose;
|
|
1098
|
-
return { close, el:
|
|
1180
|
+
return { close, el: el5 };
|
|
1099
1181
|
}
|
|
1100
1182
|
function showMenu(entries, at, options = {}) {
|
|
1101
1183
|
const labels = { ...DEFAULT_LABELS, ...options.labels ?? {} };
|
|
@@ -1119,12 +1201,13 @@ function showMenu(entries, at, options = {}) {
|
|
|
1119
1201
|
close: () => handle?.close(),
|
|
1120
1202
|
labels,
|
|
1121
1203
|
editor: options.editor,
|
|
1204
|
+
shortcutOf: (command) => shortcutLabel(command, [options.editor?.keybindings]),
|
|
1122
1205
|
state: stateOf,
|
|
1123
|
-
check: (
|
|
1124
|
-
|
|
1206
|
+
check: (el5, active) => {
|
|
1207
|
+
el5.textContent = evalNow(active, false) ? "\u2713" : "";
|
|
1125
1208
|
},
|
|
1126
|
-
enable: (
|
|
1127
|
-
|
|
1209
|
+
enable: (el5, enabled) => {
|
|
1210
|
+
el5.disabled = !evalNow(enabled, true);
|
|
1128
1211
|
}
|
|
1129
1212
|
});
|
|
1130
1213
|
handle = showPopup(container, at, options.onClose);
|
|
@@ -1168,6 +1251,7 @@ function mountMenubar(host, editor, options = {}) {
|
|
|
1168
1251
|
const open = (idx, focusFirst = false) => {
|
|
1169
1252
|
if (openIdx === idx) return;
|
|
1170
1253
|
close();
|
|
1254
|
+
refreshShortcuts();
|
|
1171
1255
|
const p = panels[idx];
|
|
1172
1256
|
p.dropdown.hidden = false;
|
|
1173
1257
|
p.title.setAttribute("aria-expanded", "true");
|
|
@@ -1176,13 +1260,24 @@ function mountMenubar(host, editor, options = {}) {
|
|
|
1176
1260
|
if (focusFirst)
|
|
1177
1261
|
p.dropdown.querySelector(".bb-menu-item")?.focus();
|
|
1178
1262
|
};
|
|
1263
|
+
const registries = [editor.keybindings, ...options.keybindings ?? []];
|
|
1264
|
+
const shortcutRefs = [];
|
|
1265
|
+
const refreshShortcuts = () => {
|
|
1266
|
+
for (const { el: el5, command } of shortcutRefs) {
|
|
1267
|
+
const label = shortcutLabel(command, registries);
|
|
1268
|
+
el5.textContent = label ?? "";
|
|
1269
|
+
el5.hidden = !label;
|
|
1270
|
+
}
|
|
1271
|
+
};
|
|
1179
1272
|
const buildCtx = {
|
|
1180
1273
|
close: () => close(),
|
|
1181
1274
|
labels,
|
|
1182
1275
|
editor,
|
|
1276
|
+
shortcutOf: (command) => shortcutLabel(command, registries),
|
|
1277
|
+
shortcutRef: (el5, command) => shortcutRefs.push({ el: el5, command }),
|
|
1183
1278
|
state: () => latest,
|
|
1184
|
-
check: (
|
|
1185
|
-
enable: (
|
|
1279
|
+
check: (el5, active) => checks.push({ el: el5, active }),
|
|
1280
|
+
enable: (el5, enabled) => enables.push({ el: el5, enabled })
|
|
1186
1281
|
};
|
|
1187
1282
|
const buildEntries = (entries, container) => buildMenuEntries(entries, container, buildCtx);
|
|
1188
1283
|
menus.forEach((menu, idx) => {
|
|
@@ -1394,15 +1489,15 @@ function closeCurrent() {
|
|
|
1394
1489
|
function showContextMenu(entries, at) {
|
|
1395
1490
|
injectStyle("bb-ui-contextmenu-styles", STYLE6);
|
|
1396
1491
|
closeCurrent();
|
|
1397
|
-
const
|
|
1398
|
-
|
|
1399
|
-
|
|
1492
|
+
const el5 = document.createElement("div");
|
|
1493
|
+
el5.className = "bb-ctx";
|
|
1494
|
+
el5.setAttribute("role", "menu");
|
|
1400
1495
|
for (const entry of entries) {
|
|
1401
1496
|
if (entry === "separator") {
|
|
1402
1497
|
const sep = document.createElement("div");
|
|
1403
1498
|
sep.className = "bb-ctx-sep";
|
|
1404
1499
|
sep.setAttribute("role", "separator");
|
|
1405
|
-
|
|
1500
|
+
el5.appendChild(sep);
|
|
1406
1501
|
continue;
|
|
1407
1502
|
}
|
|
1408
1503
|
const item = document.createElement("button");
|
|
@@ -1425,22 +1520,22 @@ function showContextMenu(entries, at) {
|
|
|
1425
1520
|
closeCurrent();
|
|
1426
1521
|
entry.run();
|
|
1427
1522
|
});
|
|
1428
|
-
|
|
1523
|
+
el5.appendChild(item);
|
|
1429
1524
|
}
|
|
1430
|
-
document.body.appendChild(
|
|
1431
|
-
const r =
|
|
1525
|
+
document.body.appendChild(el5);
|
|
1526
|
+
const r = el5.getBoundingClientRect();
|
|
1432
1527
|
const pad = 4;
|
|
1433
1528
|
const fitsX = (v) => v >= pad && v + r.width <= window.innerWidth - pad;
|
|
1434
1529
|
const fitsY = (v) => v >= pad && v + r.height <= window.innerHeight - pad;
|
|
1435
1530
|
const x = fitsX(at.x) ? at.x : fitsX(at.x - r.width) ? at.x - r.width : Math.max(pad, Math.min(at.x, window.innerWidth - r.width - pad));
|
|
1436
1531
|
const y = fitsY(at.y) ? at.y : fitsY(at.y - r.height) ? at.y - r.height : Math.max(pad, Math.min(at.y, window.innerHeight - r.height - pad));
|
|
1437
|
-
|
|
1438
|
-
|
|
1532
|
+
el5.style.left = `${x}px`;
|
|
1533
|
+
el5.style.top = `${y}px`;
|
|
1439
1534
|
const items = () => Array.from(
|
|
1440
|
-
|
|
1535
|
+
el5.querySelectorAll(".bb-ctx-item:not(:disabled)")
|
|
1441
1536
|
);
|
|
1442
1537
|
const onDown = (e) => {
|
|
1443
|
-
if (!
|
|
1538
|
+
if (!el5.contains(e.target)) closeCurrent();
|
|
1444
1539
|
};
|
|
1445
1540
|
const onKey = (e) => {
|
|
1446
1541
|
if (e.key === "Escape") return closeCurrent();
|
|
@@ -1462,7 +1557,7 @@ function showContextMenu(entries, at) {
|
|
|
1462
1557
|
document.removeEventListener("pointerdown", onDown, true);
|
|
1463
1558
|
document.removeEventListener("keydown", onKey, true);
|
|
1464
1559
|
window.removeEventListener("scroll", onScroll, true);
|
|
1465
|
-
|
|
1560
|
+
el5.remove();
|
|
1466
1561
|
};
|
|
1467
1562
|
items()[0]?.focus();
|
|
1468
1563
|
return { close: closeCurrent };
|
|
@@ -1523,10 +1618,10 @@ function showLinkPanel(opts) {
|
|
|
1523
1618
|
return currentHandle;
|
|
1524
1619
|
}
|
|
1525
1620
|
closeCurrent2();
|
|
1526
|
-
const
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1621
|
+
const el5 = document.createElement("div");
|
|
1622
|
+
el5.className = "bb-linkpanel";
|
|
1623
|
+
el5.setAttribute("role", "dialog");
|
|
1624
|
+
el5.setAttribute("aria-label", "Link");
|
|
1530
1625
|
const iconBtn = (svg, label, onClick) => {
|
|
1531
1626
|
const b = document.createElement("button");
|
|
1532
1627
|
b.type = "button";
|
|
@@ -1553,7 +1648,7 @@ function showLinkPanel(opts) {
|
|
|
1553
1648
|
return { wrap, input };
|
|
1554
1649
|
};
|
|
1555
1650
|
const renderView = (existing) => {
|
|
1556
|
-
|
|
1651
|
+
el5.textContent = "";
|
|
1557
1652
|
const row = document.createElement("div");
|
|
1558
1653
|
row.className = "bb-linkpanel-row";
|
|
1559
1654
|
const internal = opts.internal;
|
|
@@ -1600,11 +1695,11 @@ function showLinkPanel(opts) {
|
|
|
1600
1695
|
})
|
|
1601
1696
|
);
|
|
1602
1697
|
}
|
|
1603
|
-
|
|
1604
|
-
placeFloating(
|
|
1698
|
+
el5.appendChild(row);
|
|
1699
|
+
placeFloating(el5, opts.anchor);
|
|
1605
1700
|
};
|
|
1606
1701
|
const renderForm = (prefill) => {
|
|
1607
|
-
|
|
1702
|
+
el5.textContent = "";
|
|
1608
1703
|
const form = document.createElement("div");
|
|
1609
1704
|
form.className = "bb-linkpanel-form";
|
|
1610
1705
|
const withText = !opts.hasSelection;
|
|
@@ -1645,16 +1740,16 @@ function showLinkPanel(opts) {
|
|
|
1645
1740
|
}
|
|
1646
1741
|
row.appendChild(apply);
|
|
1647
1742
|
form.appendChild(row);
|
|
1648
|
-
|
|
1649
|
-
placeFloating(
|
|
1743
|
+
el5.appendChild(form);
|
|
1744
|
+
placeFloating(el5, opts.anchor);
|
|
1650
1745
|
u.input.focus();
|
|
1651
1746
|
u.input.select();
|
|
1652
1747
|
};
|
|
1653
|
-
document.body.appendChild(
|
|
1748
|
+
document.body.appendChild(el5);
|
|
1654
1749
|
if (opts.existing) renderView(opts.existing);
|
|
1655
1750
|
else renderForm(null);
|
|
1656
1751
|
const onDown = (e) => {
|
|
1657
|
-
if (
|
|
1752
|
+
if (el5.contains(e.target)) return;
|
|
1658
1753
|
if (opts.key) {
|
|
1659
1754
|
cancelPendingClose();
|
|
1660
1755
|
pendingClose = setTimeout(closeCurrent2, 80);
|
|
@@ -1675,7 +1770,7 @@ function showLinkPanel(opts) {
|
|
|
1675
1770
|
document.removeEventListener("pointerdown", onDown, true);
|
|
1676
1771
|
document.removeEventListener("keydown", onKey, true);
|
|
1677
1772
|
window.removeEventListener("scroll", onScroll, true);
|
|
1678
|
-
|
|
1773
|
+
el5.remove();
|
|
1679
1774
|
};
|
|
1680
1775
|
current2 = dispose;
|
|
1681
1776
|
currentKey = opts.key ?? null;
|
|
@@ -1878,8 +1973,8 @@ function openCellProperties({
|
|
|
1878
1973
|
for (const [key, b] of vaBtns) b.classList.toggle("on", vAlign === key);
|
|
1879
1974
|
}
|
|
1880
1975
|
function syncPresets() {
|
|
1881
|
-
for (const { el:
|
|
1882
|
-
|
|
1976
|
+
for (const { el: el5, key } of presetEls)
|
|
1977
|
+
el5.classList.toggle("on", preset === key);
|
|
1883
1978
|
}
|
|
1884
1979
|
syncVAlign();
|
|
1885
1980
|
syncPresets();
|
|
@@ -1924,7 +2019,7 @@ function tableGridPicker(options) {
|
|
|
1924
2019
|
label.className = "bb-grid-label";
|
|
1925
2020
|
label.textContent = "0 \xD7 0";
|
|
1926
2021
|
const cells = [];
|
|
1927
|
-
const
|
|
2022
|
+
const highlight2 = (r, c) => {
|
|
1928
2023
|
for (let i = 0; i < cells.length; i++) {
|
|
1929
2024
|
const row = Math.floor(i / maxCols);
|
|
1930
2025
|
const col = i % maxCols;
|
|
@@ -1938,7 +2033,7 @@ function tableGridPicker(options) {
|
|
|
1938
2033
|
cell.type = "button";
|
|
1939
2034
|
cell.className = "bb-grid-cell";
|
|
1940
2035
|
cell.addEventListener("mousedown", (e) => e.preventDefault());
|
|
1941
|
-
cell.addEventListener("mouseenter", () =>
|
|
2036
|
+
cell.addEventListener("mouseenter", () => highlight2(r, c));
|
|
1942
2037
|
cell.addEventListener("click", () => options.onPick(r + 1, c + 1));
|
|
1943
2038
|
cells.push(cell);
|
|
1944
2039
|
cellsEl.appendChild(cell);
|
|
@@ -1987,9 +2082,9 @@ var STYLE10 = `
|
|
|
1987
2082
|
`;
|
|
1988
2083
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1989
2084
|
function svgEl(name, attrs) {
|
|
1990
|
-
const
|
|
1991
|
-
for (const [k, v] of Object.entries(attrs))
|
|
1992
|
-
return
|
|
2085
|
+
const el5 = document.createElementNS(SVG_NS, name);
|
|
2086
|
+
for (const [k, v] of Object.entries(attrs)) el5.setAttribute(k, String(v));
|
|
2087
|
+
return el5;
|
|
1993
2088
|
}
|
|
1994
2089
|
function pagePreview(ratio) {
|
|
1995
2090
|
const svg = svgEl("svg", { viewBox: "0 0 34 42", class: "bb-ps-icon" });
|
|
@@ -2056,11 +2151,11 @@ function presetRow(icon, name, caption, active, onPick) {
|
|
|
2056
2151
|
return row;
|
|
2057
2152
|
}
|
|
2058
2153
|
function captionLine(text) {
|
|
2059
|
-
const
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
return
|
|
2154
|
+
const el5 = document.createElement("span");
|
|
2155
|
+
el5.className = "bb-ps-dims";
|
|
2156
|
+
el5.style.display = "block";
|
|
2157
|
+
el5.textContent = text;
|
|
2158
|
+
return el5;
|
|
2064
2159
|
}
|
|
2065
2160
|
function customRow(icon, title, description, onPick) {
|
|
2066
2161
|
icon.appendChild(
|
|
@@ -2189,8 +2284,8 @@ function cmField(label, valuePx, min) {
|
|
|
2189
2284
|
return { row, input };
|
|
2190
2285
|
}
|
|
2191
2286
|
function dialogActions() {
|
|
2192
|
-
const
|
|
2193
|
-
|
|
2287
|
+
const el5 = document.createElement("div");
|
|
2288
|
+
el5.className = "bb-pd-actions";
|
|
2194
2289
|
const cancel = document.createElement("button");
|
|
2195
2290
|
cancel.type = "button";
|
|
2196
2291
|
cancel.className = "bb-prompt-btn";
|
|
@@ -2200,8 +2295,8 @@ function dialogActions() {
|
|
|
2200
2295
|
ok.className = "bb-prompt-btn";
|
|
2201
2296
|
ok.dataset["primary"] = "true";
|
|
2202
2297
|
ok.textContent = "OK";
|
|
2203
|
-
|
|
2204
|
-
return { el:
|
|
2298
|
+
el5.append(cancel, ok);
|
|
2299
|
+
return { el: el5, ok, cancel };
|
|
2205
2300
|
}
|
|
2206
2301
|
function readPx(input, fallbackPx) {
|
|
2207
2302
|
const n = Number(input.value);
|
|
@@ -2398,15 +2493,15 @@ function sectionPaperPanel(options) {
|
|
|
2398
2493
|
root.className = "bb-ps";
|
|
2399
2494
|
root.setAttribute("role", "menu");
|
|
2400
2495
|
const group = (text) => {
|
|
2401
|
-
const
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
return
|
|
2496
|
+
const el5 = document.createElement("div");
|
|
2497
|
+
el5.className = "bb-ps-group";
|
|
2498
|
+
el5.textContent = text;
|
|
2499
|
+
return el5;
|
|
2405
2500
|
};
|
|
2406
2501
|
const sep = () => {
|
|
2407
|
-
const
|
|
2408
|
-
|
|
2409
|
-
return
|
|
2502
|
+
const el5 = document.createElement("div");
|
|
2503
|
+
el5.className = "bb-ps-sep";
|
|
2504
|
+
return el5;
|
|
2410
2505
|
};
|
|
2411
2506
|
root.appendChild(group(options.labels?.orientation ?? "Orientation"));
|
|
2412
2507
|
const tiles = document.createElement("div");
|
|
@@ -2476,8 +2571,8 @@ var STYLE11 = `
|
|
|
2476
2571
|
`;
|
|
2477
2572
|
function createSectionChip(options) {
|
|
2478
2573
|
injectStyle("bb-ui-section-chip-styles", STYLE11);
|
|
2479
|
-
const
|
|
2480
|
-
|
|
2574
|
+
const el5 = document.createElement("div");
|
|
2575
|
+
el5.className = "bb-secchip";
|
|
2481
2576
|
const title = document.createElement("span");
|
|
2482
2577
|
title.className = "bb-secchip-title";
|
|
2483
2578
|
title.textContent = options.title;
|
|
@@ -2511,16 +2606,16 @@ function createSectionChip(options) {
|
|
|
2511
2606
|
x.innerHTML = '<svg viewBox="0 0 16 16" width="9" height="9" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M3 3l10 10M13 3 3 13"/></svg>';
|
|
2512
2607
|
x.addEventListener("mousedown", (e) => e.preventDefault());
|
|
2513
2608
|
x.addEventListener("click", () => options.onDelete());
|
|
2514
|
-
|
|
2609
|
+
el5.append(title, divider(), nums.btn, divider(), paper.btn, divider(), x);
|
|
2515
2610
|
return {
|
|
2516
|
-
el:
|
|
2611
|
+
el: el5,
|
|
2517
2612
|
update(data) {
|
|
2518
2613
|
nums.label.textContent = data.pageNumbers;
|
|
2519
2614
|
nums.btn.dataset["muted"] = String(!!data.pageNumbersMuted);
|
|
2520
2615
|
paper.label.textContent = data.paper;
|
|
2521
2616
|
},
|
|
2522
2617
|
destroy() {
|
|
2523
|
-
|
|
2618
|
+
el5.remove();
|
|
2524
2619
|
}
|
|
2525
2620
|
};
|
|
2526
2621
|
}
|
|
@@ -2672,7 +2767,7 @@ function openFontDialog({
|
|
|
2672
2767
|
const italicBtn = mkSeg("I", initial.italic, "font-style:italic");
|
|
2673
2768
|
const underBtn = mkSeg("U", initial.underline, "text-decoration:underline");
|
|
2674
2769
|
let color = initial.color ?? null;
|
|
2675
|
-
let
|
|
2770
|
+
let highlight2 = initial.highlight ?? null;
|
|
2676
2771
|
const colorBtn = colorButton({
|
|
2677
2772
|
title: "Text color",
|
|
2678
2773
|
label: "Text color",
|
|
@@ -2687,9 +2782,9 @@ function openFontDialog({
|
|
|
2687
2782
|
title: "Highlight",
|
|
2688
2783
|
label: "Highlight",
|
|
2689
2784
|
clearLabel: "No highlight",
|
|
2690
|
-
value: () =>
|
|
2785
|
+
value: () => highlight2,
|
|
2691
2786
|
onPick: (c) => {
|
|
2692
|
-
|
|
2787
|
+
highlight2 = c;
|
|
2693
2788
|
paint();
|
|
2694
2789
|
}
|
|
2695
2790
|
});
|
|
@@ -2809,7 +2904,7 @@ function openFontDialog({
|
|
|
2809
2904
|
s.textDecorationStyle = dstrikeCb.checked ? "double" : "solid";
|
|
2810
2905
|
s.fontVariant = smallCapsCb.checked ? "small-caps" : "normal";
|
|
2811
2906
|
s.color = color ?? "inherit";
|
|
2812
|
-
s.background =
|
|
2907
|
+
s.background = highlight2 ?? "transparent";
|
|
2813
2908
|
s.letterSpacing = `${spacingPt}pt`;
|
|
2814
2909
|
s.transform = scale === 100 ? "none" : `scaleX(${scale / 100})`;
|
|
2815
2910
|
s.verticalAlign = supCb.checked ? "super" : subCb.checked ? "sub" : `${positionPt}pt`;
|
|
@@ -2838,7 +2933,7 @@ function openFontDialog({
|
|
|
2838
2933
|
smallCaps: checkedOrMixed(smallCapsCb),
|
|
2839
2934
|
vertAlign: supCb.checked ? "super" : subCb.checked ? "sub" : null,
|
|
2840
2935
|
color,
|
|
2841
|
-
highlight,
|
|
2936
|
+
highlight: highlight2,
|
|
2842
2937
|
scalePercent: scale,
|
|
2843
2938
|
letterSpacingTwips: ptToTwips(spacingPt),
|
|
2844
2939
|
positionHalfPoints: ptToHalf(positionPt)
|
|
@@ -2853,29 +2948,1213 @@ function openFontDialog({
|
|
|
2853
2948
|
paint();
|
|
2854
2949
|
dialog.open();
|
|
2855
2950
|
}
|
|
2951
|
+
|
|
2952
|
+
// packages/ui/src/lib/symbol-sets.ts
|
|
2953
|
+
var import_bapbong_contracts2 = require("@shadow-garden/bapbong-contracts");
|
|
2954
|
+
var g = (id, label, short, pairs) => ({
|
|
2955
|
+
id,
|
|
2956
|
+
label,
|
|
2957
|
+
short,
|
|
2958
|
+
entries: pairs.map(([char, name]) => ({ char, name }))
|
|
2959
|
+
});
|
|
2960
|
+
var SYMBOL_GROUPS = [
|
|
2961
|
+
g("checks", "Checkboxes & ticks", "Checks", [
|
|
2962
|
+
["\u2610", "Ballot box"],
|
|
2963
|
+
["\u2611", "Ballot box with check"],
|
|
2964
|
+
["\u2612", "Ballot box with X"],
|
|
2965
|
+
["\u2713", "Check mark"],
|
|
2966
|
+
["\u2714", "Heavy check mark"],
|
|
2967
|
+
["\u2717", "Ballot X"],
|
|
2968
|
+
["\u2718", "Heavy ballot X"],
|
|
2969
|
+
["\u2715", "Multiplication X"],
|
|
2970
|
+
["\u2716", "Heavy multiplication X"],
|
|
2971
|
+
["\u274F", "Lower right drop-shadowed white square"],
|
|
2972
|
+
["\u2750", "Upper right drop-shadowed white square"],
|
|
2973
|
+
["\u2751", "Lower right shadowed white square"],
|
|
2974
|
+
["\u2752", "Upper right shadowed white square"],
|
|
2975
|
+
["\u25A2", "White square with rounded corners"],
|
|
2976
|
+
["\u25A3", "White square containing black small square"],
|
|
2977
|
+
["\u22A0", "Squared times"],
|
|
2978
|
+
["\u2297", "Circled times"],
|
|
2979
|
+
["\u29BF", "Circled bullet"],
|
|
2980
|
+
["\u25C9", "Fisheye"],
|
|
2981
|
+
["\u25CB", "White circle"],
|
|
2982
|
+
["\u25CF", "Black circle"],
|
|
2983
|
+
["\u25EF", "Large circle"],
|
|
2984
|
+
["\u25FB", "White medium square"],
|
|
2985
|
+
["\u25FC", "Black medium square"]
|
|
2986
|
+
]),
|
|
2987
|
+
g("bullets", "Bullets & shapes", "Bullets", [
|
|
2988
|
+
["\u2022", "Bullet"],
|
|
2989
|
+
["\u25E6", "White bullet"],
|
|
2990
|
+
["\u25AA", "Black small square"],
|
|
2991
|
+
["\u25AB", "White small square"],
|
|
2992
|
+
["\u25A0", "Black square"],
|
|
2993
|
+
["\u25A1", "White square"],
|
|
2994
|
+
["\u25AC", "Black rectangle"],
|
|
2995
|
+
["\u25C6", "Black diamond"],
|
|
2996
|
+
["\u25C7", "White diamond"],
|
|
2997
|
+
["\u25CA", "Lozenge"],
|
|
2998
|
+
["\u2605", "Black star"],
|
|
2999
|
+
["\u2606", "White star"],
|
|
3000
|
+
["\u2726", "Black four pointed star"],
|
|
3001
|
+
["\u2727", "White four pointed star"],
|
|
3002
|
+
["\u25BA", "Black right-pointing pointer"],
|
|
3003
|
+
["\u25B8", "Black right-pointing small triangle"],
|
|
3004
|
+
["\u25B9", "White right-pointing small triangle"],
|
|
3005
|
+
["\u25B2", "Black up-pointing triangle"],
|
|
3006
|
+
["\u25B3", "White up-pointing triangle"],
|
|
3007
|
+
["\u25BC", "Black down-pointing triangle"],
|
|
3008
|
+
["\u25BD", "White down-pointing triangle"],
|
|
3009
|
+
["\u25C4", "Black left-pointing pointer"],
|
|
3010
|
+
["\u2756", "Black diamond minus white X"],
|
|
3011
|
+
["\u273D", "Heavy teardrop-spoked asterisk"],
|
|
3012
|
+
["\u273F", "Black florette"],
|
|
3013
|
+
["\u2740", "White florette"],
|
|
3014
|
+
["\u27A2", "Three-D top-lighted rightwards arrowhead"],
|
|
3015
|
+
["\u27A4", "Black rightwards arrowhead"],
|
|
3016
|
+
["\u27A3", "Three-D bottom-lighted rightwards arrowhead"],
|
|
3017
|
+
["\u2713", "Check mark"]
|
|
3018
|
+
]),
|
|
3019
|
+
g("arrows", "Arrows", "Arrows", [
|
|
3020
|
+
["\u2190", "Leftwards arrow"],
|
|
3021
|
+
["\u2191", "Upwards arrow"],
|
|
3022
|
+
["\u2192", "Rightwards arrow"],
|
|
3023
|
+
["\u2193", "Downwards arrow"],
|
|
3024
|
+
["\u2194", "Left right arrow"],
|
|
3025
|
+
["\u2195", "Up down arrow"],
|
|
3026
|
+
["\u2196", "North west arrow"],
|
|
3027
|
+
["\u2197", "North east arrow"],
|
|
3028
|
+
["\u2198", "South east arrow"],
|
|
3029
|
+
["\u2199", "South west arrow"],
|
|
3030
|
+
["\u21D0", "Leftwards double arrow"],
|
|
3031
|
+
["\u21D1", "Upwards double arrow"],
|
|
3032
|
+
["\u21D2", "Rightwards double arrow"],
|
|
3033
|
+
["\u21D3", "Downwards double arrow"],
|
|
3034
|
+
["\u21D4", "Left right double arrow"],
|
|
3035
|
+
["\u21D5", "Up down double arrow"],
|
|
3036
|
+
["\u21A9", "Leftwards arrow with hook"],
|
|
3037
|
+
["\u21AA", "Rightwards arrow with hook"],
|
|
3038
|
+
["\u21B5", "Downwards arrow with corner leftwards"],
|
|
3039
|
+
["\u21C4", "Rightwards arrow over leftwards arrow"],
|
|
3040
|
+
["\u21C6", "Leftwards arrow over rightwards arrow"],
|
|
3041
|
+
["\u2794", "Heavy wide-headed rightwards arrow"],
|
|
3042
|
+
["\u279C", "Heavy round-tipped rightwards arrow"],
|
|
3043
|
+
["\u279D", "Triangle-headed rightwards arrow"],
|
|
3044
|
+
["\u279E", "Heavy triangle-headed rightwards arrow"],
|
|
3045
|
+
["\u27A1", "Black rightwards arrow"],
|
|
3046
|
+
["\u2B05", "Leftwards black arrow"],
|
|
3047
|
+
["\u2B06", "Upwards black arrow"],
|
|
3048
|
+
["\u2B07", "Downwards black arrow"],
|
|
3049
|
+
["\u21BB", "Clockwise open circle arrow"],
|
|
3050
|
+
["\u21BA", "Anticlockwise open circle arrow"],
|
|
3051
|
+
["\u2934", "Arrow pointing rightwards then curving upwards"],
|
|
3052
|
+
["\u2935", "Arrow pointing rightwards then curving downwards"]
|
|
3053
|
+
]),
|
|
3054
|
+
g("math", "Math", "Math", [
|
|
3055
|
+
["\xB1", "Plus-minus sign"],
|
|
3056
|
+
["\xD7", "Multiplication sign"],
|
|
3057
|
+
["\xF7", "Division sign"],
|
|
3058
|
+
["\u2212", "Minus sign"],
|
|
3059
|
+
["\u2264", "Less-than or equal to"],
|
|
3060
|
+
["\u2265", "Greater-than or equal to"],
|
|
3061
|
+
["\u2260", "Not equal to"],
|
|
3062
|
+
["\u2248", "Almost equal to"],
|
|
3063
|
+
["\u2261", "Identical to"],
|
|
3064
|
+
["\u221E", "Infinity"],
|
|
3065
|
+
["\u221A", "Square root"],
|
|
3066
|
+
["\u2211", "N-ary summation"],
|
|
3067
|
+
["\u220F", "N-ary product"],
|
|
3068
|
+
["\u222B", "Integral"],
|
|
3069
|
+
["\u2202", "Partial differential"],
|
|
3070
|
+
["\u2206", "Increment"],
|
|
3071
|
+
["\u2207", "Nabla"],
|
|
3072
|
+
["\u2208", "Element of"],
|
|
3073
|
+
["\u2209", "Not an element of"],
|
|
3074
|
+
["\u2229", "Intersection"],
|
|
3075
|
+
["\u222A", "Union"],
|
|
3076
|
+
["\u2282", "Subset of"],
|
|
3077
|
+
["\u2283", "Superset of"],
|
|
3078
|
+
["\u2205", "Empty set"],
|
|
3079
|
+
["\u2200", "For all"],
|
|
3080
|
+
["\u2203", "There exists"],
|
|
3081
|
+
["\xAC", "Not sign"],
|
|
3082
|
+
["\u2227", "Logical and"],
|
|
3083
|
+
["\u2228", "Logical or"],
|
|
3084
|
+
["\xB0", "Degree sign"],
|
|
3085
|
+
["\u2032", "Prime"],
|
|
3086
|
+
["\u2033", "Double prime"],
|
|
3087
|
+
["\u2030", "Per mille sign"],
|
|
3088
|
+
["\xB5", "Micro sign"],
|
|
3089
|
+
["\u03C0", "Greek small letter pi"],
|
|
3090
|
+
["\u221D", "Proportional to"],
|
|
3091
|
+
["\u2220", "Angle"],
|
|
3092
|
+
["\u22A5", "Up tack"],
|
|
3093
|
+
["\u2225", "Parallel to"],
|
|
3094
|
+
["\xB9", "Superscript one"],
|
|
3095
|
+
["\xB2", "Superscript two"],
|
|
3096
|
+
["\xB3", "Superscript three"],
|
|
3097
|
+
["\xBD", "Vulgar fraction one half"],
|
|
3098
|
+
["\u2153", "Vulgar fraction one third"],
|
|
3099
|
+
["\xBC", "Vulgar fraction one quarter"],
|
|
3100
|
+
["\xBE", "Vulgar fraction three quarters"]
|
|
3101
|
+
]),
|
|
3102
|
+
g("currency", "Currency", "Currency", [
|
|
3103
|
+
["\u20AB", "Dong sign"],
|
|
3104
|
+
["$", "Dollar sign"],
|
|
3105
|
+
["\u20AC", "Euro sign"],
|
|
3106
|
+
["\xA3", "Pound sign"],
|
|
3107
|
+
["\xA5", "Yen sign"],
|
|
3108
|
+
["\u20A9", "Won sign"],
|
|
3109
|
+
["\u20B9", "Indian rupee sign"],
|
|
3110
|
+
["\u20BD", "Ruble sign"],
|
|
3111
|
+
["\u0E3F", "Thai currency symbol baht"],
|
|
3112
|
+
["\u20B1", "Peso sign"],
|
|
3113
|
+
["\xA2", "Cent sign"],
|
|
3114
|
+
["\xA4", "Currency sign"],
|
|
3115
|
+
["\u20BF", "Bitcoin sign"]
|
|
3116
|
+
]),
|
|
3117
|
+
g("punct", "Punctuation & typography", "Punct.", [
|
|
3118
|
+
["\u2013", "En dash"],
|
|
3119
|
+
["\u2014", "Em dash"],
|
|
3120
|
+
["\u2026", "Horizontal ellipsis"],
|
|
3121
|
+
["\u2018", "Left single quotation mark"],
|
|
3122
|
+
["\u2019", "Right single quotation mark"],
|
|
3123
|
+
["\u201C", "Left double quotation mark"],
|
|
3124
|
+
["\u201D", "Right double quotation mark"],
|
|
3125
|
+
["\u201A", "Single low-9 quotation mark"],
|
|
3126
|
+
["\u201E", "Double low-9 quotation mark"],
|
|
3127
|
+
["\xAB", "Left-pointing double angle quotation mark"],
|
|
3128
|
+
["\xBB", "Right-pointing double angle quotation mark"],
|
|
3129
|
+
["\u2039", "Single left-pointing angle quotation mark"],
|
|
3130
|
+
["\u203A", "Single right-pointing angle quotation mark"],
|
|
3131
|
+
["\xA7", "Section sign"],
|
|
3132
|
+
["\xB6", "Pilcrow sign"],
|
|
3133
|
+
["\u2020", "Dagger"],
|
|
3134
|
+
["\u2021", "Double dagger"],
|
|
3135
|
+
["\u2022", "Bullet"],
|
|
3136
|
+
["\xB7", "Middle dot"],
|
|
3137
|
+
["\u2116", "Numero sign"],
|
|
3138
|
+
["\xA9", "Copyright sign"],
|
|
3139
|
+
["\xAE", "Registered sign"],
|
|
3140
|
+
["\u2122", "Trade mark sign"],
|
|
3141
|
+
["\u2120", "Service mark"],
|
|
3142
|
+
["\xA1", "Inverted exclamation mark"],
|
|
3143
|
+
["\xBF", "Inverted question mark"],
|
|
3144
|
+
["\u203D", "Interrobang"],
|
|
3145
|
+
["\u02C6", "Modifier letter circumflex accent"],
|
|
3146
|
+
["\u02DC", "Small tilde"],
|
|
3147
|
+
["\xA6", "Broken bar"]
|
|
3148
|
+
]),
|
|
3149
|
+
g("greek", "Greek", "Greek", [
|
|
3150
|
+
["\u03B1", "Alpha"],
|
|
3151
|
+
["\u03B2", "Beta"],
|
|
3152
|
+
["\u03B3", "Gamma"],
|
|
3153
|
+
["\u03B4", "Delta"],
|
|
3154
|
+
["\u03B5", "Epsilon"],
|
|
3155
|
+
["\u03B6", "Zeta"],
|
|
3156
|
+
["\u03B7", "Eta"],
|
|
3157
|
+
["\u03B8", "Theta"],
|
|
3158
|
+
["\u03B9", "Iota"],
|
|
3159
|
+
["\u03BA", "Kappa"],
|
|
3160
|
+
["\u03BB", "Lambda"],
|
|
3161
|
+
["\u03BC", "Mu"],
|
|
3162
|
+
["\u03BD", "Nu"],
|
|
3163
|
+
["\u03BE", "Xi"],
|
|
3164
|
+
["\u03BF", "Omicron"],
|
|
3165
|
+
["\u03C0", "Pi"],
|
|
3166
|
+
["\u03C1", "Rho"],
|
|
3167
|
+
["\u03C3", "Sigma"],
|
|
3168
|
+
["\u03C2", "Final sigma"],
|
|
3169
|
+
["\u03C4", "Tau"],
|
|
3170
|
+
["\u03C5", "Upsilon"],
|
|
3171
|
+
["\u03C6", "Phi"],
|
|
3172
|
+
["\u03C7", "Chi"],
|
|
3173
|
+
["\u03C8", "Psi"],
|
|
3174
|
+
["\u03C9", "Omega"],
|
|
3175
|
+
["\u0391", "Capital alpha"],
|
|
3176
|
+
["\u0392", "Capital beta"],
|
|
3177
|
+
["\u0393", "Capital gamma"],
|
|
3178
|
+
["\u0394", "Capital delta"],
|
|
3179
|
+
["\u0395", "Capital epsilon"],
|
|
3180
|
+
["\u0396", "Capital zeta"],
|
|
3181
|
+
["\u0397", "Capital eta"],
|
|
3182
|
+
["\u0398", "Capital theta"],
|
|
3183
|
+
["\u0399", "Capital iota"],
|
|
3184
|
+
["\u039A", "Capital kappa"],
|
|
3185
|
+
["\u039B", "Capital lambda"],
|
|
3186
|
+
["\u039C", "Capital mu"],
|
|
3187
|
+
["\u039D", "Capital nu"],
|
|
3188
|
+
["\u039E", "Capital xi"],
|
|
3189
|
+
["\u039F", "Capital omicron"],
|
|
3190
|
+
["\u03A0", "Capital pi"],
|
|
3191
|
+
["\u03A1", "Capital rho"],
|
|
3192
|
+
["\u03A3", "Capital sigma"],
|
|
3193
|
+
["\u03A4", "Capital tau"],
|
|
3194
|
+
["\u03A5", "Capital upsilon"],
|
|
3195
|
+
["\u03A6", "Capital phi"],
|
|
3196
|
+
["\u03A7", "Capital chi"],
|
|
3197
|
+
["\u03A8", "Capital psi"],
|
|
3198
|
+
["\u03A9", "Capital omega"]
|
|
3199
|
+
]),
|
|
3200
|
+
g("latin", "Latin (Vietnamese & accents)", "Latin", [
|
|
3201
|
+
["\u0110", "Capital D with stroke"],
|
|
3202
|
+
["\u0111", "Small d with stroke"],
|
|
3203
|
+
["\u0102", "Capital A with breve"],
|
|
3204
|
+
["\u0103", "Small a with breve"],
|
|
3205
|
+
["\xC2", "Capital A with circumflex"],
|
|
3206
|
+
["\xE2", "Small a with circumflex"],
|
|
3207
|
+
["\xCA", "Capital E with circumflex"],
|
|
3208
|
+
["\xEA", "Small e with circumflex"],
|
|
3209
|
+
["\xD4", "Capital O with circumflex"],
|
|
3210
|
+
["\xF4", "Small o with circumflex"],
|
|
3211
|
+
["\u01A0", "Capital O with horn"],
|
|
3212
|
+
["\u01A1", "Small o with horn"],
|
|
3213
|
+
["\u01AF", "Capital U with horn"],
|
|
3214
|
+
["\u01B0", "Small u with horn"],
|
|
3215
|
+
["\xC0", "Capital A with grave"],
|
|
3216
|
+
["\xE0", "Small a with grave"],
|
|
3217
|
+
["\xC1", "Capital A with acute"],
|
|
3218
|
+
["\xE1", "Small a with acute"],
|
|
3219
|
+
["\xC3", "Capital A with tilde"],
|
|
3220
|
+
["\xE3", "Small a with tilde"],
|
|
3221
|
+
["\u1EA2", "Capital A with hook above"],
|
|
3222
|
+
["\u1EA3", "Small a with hook above"],
|
|
3223
|
+
["\u1EA0", "Capital A with dot below"],
|
|
3224
|
+
["\u1EA1", "Small a with dot below"],
|
|
3225
|
+
["\xC8", "Capital E with grave"],
|
|
3226
|
+
["\xE9", "Small e with acute"],
|
|
3227
|
+
["\xCC", "Capital I with grave"],
|
|
3228
|
+
["\xED", "Small i with acute"],
|
|
3229
|
+
["\xD2", "Capital O with grave"],
|
|
3230
|
+
["\xF3", "Small o with acute"],
|
|
3231
|
+
["\xD9", "Capital U with grave"],
|
|
3232
|
+
["\xFA", "Small u with acute"],
|
|
3233
|
+
["\xDD", "Capital Y with acute"],
|
|
3234
|
+
["\u1EF9", "Small y with tilde"],
|
|
3235
|
+
["\xC7", "Capital C with cedilla"],
|
|
3236
|
+
["\xE7", "Small c with cedilla"],
|
|
3237
|
+
["\xD1", "Capital N with tilde"],
|
|
3238
|
+
["\xF1", "Small n with tilde"],
|
|
3239
|
+
["\xD6", "Capital O with diaeresis"],
|
|
3240
|
+
["\xF6", "Small o with diaeresis"],
|
|
3241
|
+
["\xDC", "Capital U with diaeresis"],
|
|
3242
|
+
["\xFC", "Small u with diaeresis"],
|
|
3243
|
+
["\xDF", "Small sharp s"],
|
|
3244
|
+
["\xC6", "Capital AE"],
|
|
3245
|
+
["\xE6", "Small ae"],
|
|
3246
|
+
["\xD8", "Capital O with stroke"],
|
|
3247
|
+
["\xF8", "Small o with stroke"],
|
|
3248
|
+
["\u0152", "Capital ligature OE"],
|
|
3249
|
+
["\u0153", "Small ligature oe"]
|
|
3250
|
+
]),
|
|
3251
|
+
g("misc", "Misc", "Misc", [
|
|
3252
|
+
["\u260E", "Black telephone"],
|
|
3253
|
+
["\u2706", "Telephone location sign"],
|
|
3254
|
+
["\u2709", "Envelope"],
|
|
3255
|
+
["\u2702", "Black scissors"],
|
|
3256
|
+
["\u270E", "Lower right pencil"],
|
|
3257
|
+
["\u270F", "Pencil"],
|
|
3258
|
+
["\u270D", "Writing hand"],
|
|
3259
|
+
["\u263A", "White smiling face"],
|
|
3260
|
+
["\u2639", "White frowning face"],
|
|
3261
|
+
["\u2660", "Black spade suit"],
|
|
3262
|
+
["\u2663", "Black club suit"],
|
|
3263
|
+
["\u2665", "Black heart suit"],
|
|
3264
|
+
["\u2666", "Black diamond suit"],
|
|
3265
|
+
["\u266A", "Eighth note"],
|
|
3266
|
+
["\u266B", "Beamed eighth notes"],
|
|
3267
|
+
["\u2600", "Black sun with rays"],
|
|
3268
|
+
["\u2601", "Cloud"],
|
|
3269
|
+
["\u2602", "Umbrella"],
|
|
3270
|
+
["\u2691", "Black flag"],
|
|
3271
|
+
["\u2690", "White flag"],
|
|
3272
|
+
["\u26A0", "Warning sign"],
|
|
3273
|
+
["\u26D4", "No entry"],
|
|
3274
|
+
["\u2640", "Female sign"],
|
|
3275
|
+
["\u2642", "Male sign"],
|
|
3276
|
+
["\u2318", "Place of interest sign"],
|
|
3277
|
+
["\u2325", "Option key"],
|
|
3278
|
+
["\u21E7", "Upwards white arrow"],
|
|
3279
|
+
["\u23CE", "Return symbol"],
|
|
3280
|
+
["\u232B", "Erase to the left"],
|
|
3281
|
+
["\u23CF", "Eject symbol"],
|
|
3282
|
+
["\u267B", "Black universal recycling symbol"],
|
|
3283
|
+
["\u2708", "Airplane"],
|
|
3284
|
+
["\u2696", "Scales"],
|
|
3285
|
+
["\u2695", "Staff of aesculapius"]
|
|
3286
|
+
])
|
|
3287
|
+
];
|
|
3288
|
+
function autoCorrectHint(char) {
|
|
3289
|
+
return import_bapbong_contracts2.AUTOCORRECT_RULES.find((r) => r.to === char)?.seq ?? "";
|
|
3290
|
+
}
|
|
3291
|
+
var SPECIAL_CHARACTERS = [
|
|
3292
|
+
{ char: "\u2014", name: "Em dash", hint: "" },
|
|
3293
|
+
{ char: "\u2013", name: "En dash", hint: "" },
|
|
3294
|
+
{ char: "\u2011", name: "Nonbreaking hyphen", hint: "" },
|
|
3295
|
+
{ char: "\xAD", name: "Optional hyphen", hint: "" },
|
|
3296
|
+
{ char: "\xA0", name: "Nonbreaking space", hint: "" },
|
|
3297
|
+
{ char: "\u2003", name: "Em space", hint: "" },
|
|
3298
|
+
{ char: "\u2002", name: "En space", hint: "" },
|
|
3299
|
+
{ char: "\u2009", name: "Thin space", hint: "" },
|
|
3300
|
+
{ char: "\xA9", name: "Copyright", hint: autoCorrectHint("\xA9") },
|
|
3301
|
+
{ char: "\xAE", name: "Registered", hint: autoCorrectHint("\xAE") },
|
|
3302
|
+
{ char: "\u2122", name: "Trademark", hint: autoCorrectHint("\u2122") },
|
|
3303
|
+
{ char: "\xA7", name: "Section", hint: "" },
|
|
3304
|
+
{ char: "\xB6", name: "Paragraph", hint: "" },
|
|
3305
|
+
{ char: "\u2026", name: "Ellipsis", hint: autoCorrectHint("\u2026") },
|
|
3306
|
+
{ char: "\u2018", name: "Single opening quote", hint: "" },
|
|
3307
|
+
{ char: "\u2019", name: "Single closing quote", hint: "" },
|
|
3308
|
+
{ char: "\u201C", name: "Double opening quote", hint: "" },
|
|
3309
|
+
{ char: "\u201D", name: "Double closing quote", hint: "" },
|
|
3310
|
+
{ char: "\u20AB", name: "Dong sign", hint: "" },
|
|
3311
|
+
{ char: "\u2116", name: "Numero sign", hint: "" }
|
|
3312
|
+
];
|
|
3313
|
+
var SYMBOL_NAMES = (() => {
|
|
3314
|
+
const m = /* @__PURE__ */ new Map();
|
|
3315
|
+
for (const grp of SYMBOL_GROUPS)
|
|
3316
|
+
for (const e of grp.entries) if (!m.has(e.char)) m.set(e.char, e.name);
|
|
3317
|
+
for (const e of SPECIAL_CHARACTERS) if (!m.has(e.char)) m.set(e.char, e.name);
|
|
3318
|
+
return m;
|
|
3319
|
+
})();
|
|
3320
|
+
function codePointLabel(char) {
|
|
3321
|
+
const cp = char.codePointAt(0) ?? 0;
|
|
3322
|
+
return `U+${cp.toString(16).toUpperCase().padStart(4, "0")}`;
|
|
3323
|
+
}
|
|
3324
|
+
function parseCodePoint(input) {
|
|
3325
|
+
const m = /^\s*(?:u\+|0x)?([0-9a-f]{1,6})\s*$/i.exec(input);
|
|
3326
|
+
if (!m) return null;
|
|
3327
|
+
const cp = parseInt(m[1], 16);
|
|
3328
|
+
if (cp > 1114111 || cp >= 55296 && cp <= 57343) return null;
|
|
3329
|
+
if (cp < 32 || cp >= 127 && cp < 160) return null;
|
|
3330
|
+
return String.fromCodePoint(cp);
|
|
3331
|
+
}
|
|
3332
|
+
var RECENT_MAX = 16;
|
|
3333
|
+
function pushRecent(recent, char, max = RECENT_MAX) {
|
|
3334
|
+
return [char, ...recent.filter((c) => c !== char)].slice(0, max);
|
|
3335
|
+
}
|
|
3336
|
+
function searchSymbols(query) {
|
|
3337
|
+
const q = query.trim().toLowerCase();
|
|
3338
|
+
if (!q) return [];
|
|
3339
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3340
|
+
const ranked = [];
|
|
3341
|
+
for (const grp of SYMBOL_GROUPS) {
|
|
3342
|
+
const groupHit = grp.label.toLowerCase().includes(q);
|
|
3343
|
+
for (const e of grp.entries) {
|
|
3344
|
+
const name = e.name.toLowerCase();
|
|
3345
|
+
if (seen.has(e.char) || !name.includes(q)) continue;
|
|
3346
|
+
seen.add(e.char);
|
|
3347
|
+
ranked.push({ e, rank: groupHit ? 0 : name.startsWith(q) ? 1 : 2 });
|
|
3348
|
+
}
|
|
3349
|
+
}
|
|
3350
|
+
return ranked.sort((a, b) => a.rank - b.rank).map((r) => r.e);
|
|
3351
|
+
}
|
|
3352
|
+
|
|
3353
|
+
// packages/ui/src/lib/symbol-dialog.ts
|
|
3354
|
+
var STYLE13 = `
|
|
3355
|
+
.bb-sd{display:flex;flex-direction:column;gap:12px;width:412px;max-width:100%;color:var(--bb-ui-fg,#2c2c2a)}
|
|
3356
|
+
.bb-sd *{box-sizing:border-box}
|
|
3357
|
+
.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}
|
|
3358
|
+
.bb-sd-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}
|
|
3359
|
+
.bb-sd-tab:last-child{border-right:0}
|
|
3360
|
+
.bb-sd-tab[aria-selected="true"]{background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c);opacity:1}
|
|
3361
|
+
.bb-sd-pane{display:flex;flex-direction:column;gap:12px}
|
|
3362
|
+
.bb-sd-pane[hidden]{display:none}
|
|
3363
|
+
.bb-sd-lbl{font-size:12px;opacity:.7;margin-bottom:5px}
|
|
3364
|
+
.bb-sd-row{display:flex;gap:10px;align-items:flex-end}
|
|
3365
|
+
.bb-sd-ctl::placeholder{color:inherit;opacity:.45}
|
|
3366
|
+
.bb-sd-ctl{width:100%;height:32px;border:0.5px 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));color:inherit;font:inherit;font-size:13px;padding:0 8px}
|
|
3367
|
+
.bb-sd-grid{display:grid;grid-template-columns:repeat(12,1fr);gap:2px;border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:8px;padding:6px;background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));max-height:196px;overflow:auto}
|
|
3368
|
+
.bb-sd-grid.recent{grid-template-columns:repeat(16,1fr);max-height:none;border-color:transparent;padding:0;background:transparent;min-height:26px}
|
|
3369
|
+
.bb-sd-cell{aspect-ratio:1;display:grid;place-items:center;border:0;border-radius:5px;background:transparent;color:inherit;font-size:18px;line-height:1;cursor:pointer;padding:0;font-family:inherit,"Noto Sans Symbols 2"}
|
|
3370
|
+
.bb-sd-grid.recent .bb-sd-cell{border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));font-size:15px}
|
|
3371
|
+
.bb-sd-cell:hover{background:var(--bb-ui-hover,#f1efe8)}
|
|
3372
|
+
.bb-sd-cell:focus{outline:none}
|
|
3373
|
+
.bb-sd-cell[aria-selected="true"]{background:var(--bb-ui-active-bg,#e6f1fb);box-shadow:inset 0 0 0 1.5px var(--bb-ui-active-border,#7fb2ec);color:var(--bb-ui-active-fg,#0c447c)}
|
|
3374
|
+
.bb-sd-empty{grid-column:1/-1;font-size:12px;opacity:.55;padding:6px 2px}
|
|
3375
|
+
.bb-sd-meta{display:grid;grid-template-columns:minmax(0,1fr) 140px;gap:10px;align-items:end}
|
|
3376
|
+
.bb-sd-info{min-width:0;border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:8px;padding:8px 10px;display:flex;gap:12px;align-items:center;min-height:56px}
|
|
3377
|
+
.bb-sd-big{font-size:30px;line-height:1;width:44px;text-align:center;font-family:inherit,"Noto Sans Symbols 2"}
|
|
3378
|
+
.bb-sd-name{font-size:13px}
|
|
3379
|
+
.bb-sd-cp{font-size:11px;opacity:.55;font-family:ui-monospace,Menlo,Consolas,monospace}
|
|
3380
|
+
.bb-sd-code{font-family:ui-monospace,Menlo,Consolas,monospace}
|
|
3381
|
+
.bb-sd-code[aria-invalid="true"]{border-color:#c0392b}
|
|
3382
|
+
.bb-sd-list{border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:8px;max-height:280px;overflow:auto}
|
|
3383
|
+
.bb-sd-list table{width:100%;border-collapse:collapse;font-size:13px}
|
|
3384
|
+
.bb-sd-list td{padding:6px 8px;border-bottom:0.5px solid var(--bb-ui-border,#e3e3e0)}
|
|
3385
|
+
.bb-sd-list tr:last-child td{border-bottom:0}
|
|
3386
|
+
.bb-sd-list tr{cursor:pointer}
|
|
3387
|
+
.bb-sd-list tr:hover td{background:var(--bb-ui-hover,#f1efe8)}
|
|
3388
|
+
.bb-sd-list tr[aria-selected="true"] td{background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c)}
|
|
3389
|
+
.bb-sd-list td.ch{width:36px;text-align:center;font-size:16px;font-family:inherit,"Noto Sans Symbols 2"}
|
|
3390
|
+
.bb-sd-list td.k{width:120px;font-size:11px;opacity:.6;font-family:ui-monospace,Menlo,Consolas,monospace;text-align:right}
|
|
3391
|
+
.bb-sd-foot{display:flex;justify-content:space-between;align-items:center;gap:8px}
|
|
3392
|
+
.bb-sd-hint{font-size:11px;opacity:.55}
|
|
3393
|
+
.bb-sd-btns{display:flex;gap:8px}
|
|
3394
|
+
.bb-sd-btn{height:31px;padding:0 17px;border:0.5px 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));color:inherit;font:inherit;font-size:13px;cursor:pointer}
|
|
3395
|
+
.bb-sd-btn.primary{background:var(--bb-ui-active-bg,#e6f1fb);border-color:var(--bb-ui-active-border,#7fb2ec);color:var(--bb-ui-active-fg,#0c447c)}
|
|
3396
|
+
.bb-sd-btn:disabled{opacity:.5;cursor:default}
|
|
3397
|
+
`;
|
|
3398
|
+
var GRID_COLS = 12;
|
|
3399
|
+
var RECENT_COLS = 16;
|
|
3400
|
+
function el2(tag, cls, text) {
|
|
3401
|
+
const n = document.createElement(tag);
|
|
3402
|
+
if (cls) n.className = cls;
|
|
3403
|
+
if (text !== void 0) n.textContent = text;
|
|
3404
|
+
return n;
|
|
3405
|
+
}
|
|
3406
|
+
function glyphFor(char) {
|
|
3407
|
+
const cp = char.codePointAt(0) ?? 0;
|
|
3408
|
+
if (char === " " || char === "\xA0") return "\u2423";
|
|
3409
|
+
if (cp === 8194 || cp === 8195 || cp === 8201) return "\u2423";
|
|
3410
|
+
if (cp === 173) return "-";
|
|
3411
|
+
if (cp === 8209) return "\u2011";
|
|
3412
|
+
return char;
|
|
3413
|
+
}
|
|
3414
|
+
function createSymbolDialog(options) {
|
|
3415
|
+
injectStyle("bb-symbol-dialog", STYLE13);
|
|
3416
|
+
let recent = [...options.recent ?? []].slice(0, RECENT_MAX);
|
|
3417
|
+
let selected = null;
|
|
3418
|
+
const root = el2("div", "bb-sd");
|
|
3419
|
+
const tabs = el2("div", "bb-sd-tabs");
|
|
3420
|
+
tabs.setAttribute("role", "tablist");
|
|
3421
|
+
const symTab = el2("button", "bb-sd-tab", "Symbols");
|
|
3422
|
+
const spcTab = el2("button", "bb-sd-tab", "Special characters");
|
|
3423
|
+
for (const t of [symTab, spcTab]) {
|
|
3424
|
+
t.type = "button";
|
|
3425
|
+
t.setAttribute("role", "tab");
|
|
3426
|
+
tabs.append(t);
|
|
3427
|
+
}
|
|
3428
|
+
const symPane = el2("div", "bb-sd-pane");
|
|
3429
|
+
const spcPane = el2("div", "bb-sd-pane");
|
|
3430
|
+
const showTab = (special) => {
|
|
3431
|
+
symTab.setAttribute("aria-selected", String(!special));
|
|
3432
|
+
spcTab.setAttribute("aria-selected", String(special));
|
|
3433
|
+
symPane.hidden = special;
|
|
3434
|
+
spcPane.hidden = !special;
|
|
3435
|
+
};
|
|
3436
|
+
symTab.addEventListener("click", () => showTab(false));
|
|
3437
|
+
spcTab.addEventListener("click", () => showTab(true));
|
|
3438
|
+
const recentWrap = el2("div");
|
|
3439
|
+
recentWrap.append(el2("div", "bb-sd-lbl", "Recently used"));
|
|
3440
|
+
const recentGrid = el2("div", "bb-sd-grid recent");
|
|
3441
|
+
recentGrid.setAttribute("role", "grid");
|
|
3442
|
+
recentGrid.setAttribute("aria-label", "Recently used symbols");
|
|
3443
|
+
recentWrap.append(recentGrid);
|
|
3444
|
+
const controls = el2("div", "bb-sd-row");
|
|
3445
|
+
const groupCell = el2("div");
|
|
3446
|
+
groupCell.style.flex = "1";
|
|
3447
|
+
groupCell.append(el2("div", "bb-sd-lbl", "Group"));
|
|
3448
|
+
const groupSel = el2("select", "bb-sd-ctl");
|
|
3449
|
+
groupSel.setAttribute("aria-label", "Group");
|
|
3450
|
+
for (const grp of SYMBOL_GROUPS) {
|
|
3451
|
+
const o = el2("option", void 0, grp.label);
|
|
3452
|
+
o.value = grp.id;
|
|
3453
|
+
groupSel.append(o);
|
|
3454
|
+
}
|
|
3455
|
+
groupCell.append(groupSel);
|
|
3456
|
+
const searchCell = el2("div");
|
|
3457
|
+
searchCell.style.width = "160px";
|
|
3458
|
+
searchCell.append(el2("div", "bb-sd-lbl", "Search name"));
|
|
3459
|
+
const search = el2("input", "bb-sd-ctl");
|
|
3460
|
+
search.type = "search";
|
|
3461
|
+
search.placeholder = "e.g. ballot, arrow";
|
|
3462
|
+
search.setAttribute("aria-label", "Search symbols by name");
|
|
3463
|
+
searchCell.append(search);
|
|
3464
|
+
controls.append(groupCell, searchCell);
|
|
3465
|
+
const grid = el2("div", "bb-sd-grid");
|
|
3466
|
+
grid.setAttribute("role", "grid");
|
|
3467
|
+
grid.setAttribute("aria-label", "Symbols");
|
|
3468
|
+
const meta = el2("div", "bb-sd-meta");
|
|
3469
|
+
const info = el2("div", "bb-sd-info");
|
|
3470
|
+
const big = el2("div", "bb-sd-big", "");
|
|
3471
|
+
const infoText = el2("div");
|
|
3472
|
+
const nameEl = el2("div", "bb-sd-name", "Select a symbol");
|
|
3473
|
+
const cpEl = el2("div", "bb-sd-cp", "");
|
|
3474
|
+
infoText.append(nameEl, cpEl);
|
|
3475
|
+
info.append(big, infoText);
|
|
3476
|
+
const codeCell = el2("div");
|
|
3477
|
+
codeCell.append(el2("div", "bb-sd-lbl", "Character code (hex)"));
|
|
3478
|
+
const code = el2("input", "bb-sd-ctl bb-sd-code");
|
|
3479
|
+
code.placeholder = "e.g. 2611";
|
|
3480
|
+
code.setAttribute("aria-label", "Character code, hexadecimal");
|
|
3481
|
+
code.spellcheck = false;
|
|
3482
|
+
codeCell.append(code);
|
|
3483
|
+
meta.append(info, codeCell);
|
|
3484
|
+
symPane.append(recentWrap, controls, grid, meta);
|
|
3485
|
+
const list = el2("div", "bb-sd-list");
|
|
3486
|
+
const table = el2("table");
|
|
3487
|
+
const tbody = el2("tbody");
|
|
3488
|
+
const rows = [];
|
|
3489
|
+
for (const sc of SPECIAL_CHARACTERS) {
|
|
3490
|
+
const tr = el2("tr");
|
|
3491
|
+
tr.tabIndex = -1;
|
|
3492
|
+
tr.setAttribute("role", "option");
|
|
3493
|
+
const ch = el2("td", "ch", glyphFor(sc.char));
|
|
3494
|
+
const nm = el2("td", void 0, sc.name);
|
|
3495
|
+
const k = el2("td", "k", sc.hint);
|
|
3496
|
+
tr.append(ch, nm, k);
|
|
3497
|
+
tr.addEventListener("click", () => select2(sc.char, tr));
|
|
3498
|
+
tr.addEventListener("dblclick", () => insert(sc.char));
|
|
3499
|
+
tr.addEventListener("keydown", (e) => {
|
|
3500
|
+
const i = rows.indexOf(tr);
|
|
3501
|
+
if (e.key === "ArrowDown" && rows[i + 1]) {
|
|
3502
|
+
e.preventDefault();
|
|
3503
|
+
rows[i + 1].focus();
|
|
3504
|
+
select2(SPECIAL_CHARACTERS[i + 1].char, rows[i + 1]);
|
|
3505
|
+
} else if (e.key === "ArrowUp" && rows[i - 1]) {
|
|
3506
|
+
e.preventDefault();
|
|
3507
|
+
rows[i - 1].focus();
|
|
3508
|
+
select2(SPECIAL_CHARACTERS[i - 1].char, rows[i - 1]);
|
|
3509
|
+
} else if (e.key === "Enter") {
|
|
3510
|
+
e.preventDefault();
|
|
3511
|
+
insert(sc.char);
|
|
3512
|
+
}
|
|
3513
|
+
});
|
|
3514
|
+
tbody.append(tr);
|
|
3515
|
+
rows.push(tr);
|
|
3516
|
+
}
|
|
3517
|
+
table.append(tbody);
|
|
3518
|
+
list.append(table);
|
|
3519
|
+
list.setAttribute("role", "listbox");
|
|
3520
|
+
spcPane.append(list);
|
|
3521
|
+
const foot = el2("div", "bb-sd-foot");
|
|
3522
|
+
const hint = el2(
|
|
3523
|
+
"span",
|
|
3524
|
+
"bb-sd-hint",
|
|
3525
|
+
"Double-click a cell to insert \xB7 Enter inserts the selection"
|
|
3526
|
+
);
|
|
3527
|
+
const btns = el2("div", "bb-sd-btns");
|
|
3528
|
+
const closeBtn = el2("button", "bb-sd-btn", "Close");
|
|
3529
|
+
closeBtn.type = "button";
|
|
3530
|
+
const insertBtn = el2("button", "bb-sd-btn primary", "Insert");
|
|
3531
|
+
insertBtn.type = "button";
|
|
3532
|
+
insertBtn.disabled = true;
|
|
3533
|
+
btns.append(closeBtn, insertBtn);
|
|
3534
|
+
foot.append(hint, btns);
|
|
3535
|
+
root.append(tabs, symPane, spcPane, foot);
|
|
3536
|
+
const dialog = new Dialog({
|
|
3537
|
+
title: "Symbol",
|
|
3538
|
+
modal: false,
|
|
3539
|
+
anchor: options.anchor,
|
|
3540
|
+
className: "bb-symbol-dialog"
|
|
3541
|
+
});
|
|
3542
|
+
dialog.setContent(root);
|
|
3543
|
+
let selectedEl = null;
|
|
3544
|
+
function select2(char, cell) {
|
|
3545
|
+
selected = char;
|
|
3546
|
+
if (selectedEl) selectedEl.removeAttribute("aria-selected");
|
|
3547
|
+
selectedEl = cell ?? null;
|
|
3548
|
+
if (selectedEl) selectedEl.setAttribute("aria-selected", "true");
|
|
3549
|
+
big.textContent = glyphFor(char);
|
|
3550
|
+
nameEl.textContent = SYMBOL_NAMES.get(char) ?? "Character";
|
|
3551
|
+
cpEl.textContent = codePointLabel(char);
|
|
3552
|
+
if (document.activeElement !== code)
|
|
3553
|
+
code.value = codePointLabel(char).slice(2);
|
|
3554
|
+
code.removeAttribute("aria-invalid");
|
|
3555
|
+
insertBtn.disabled = false;
|
|
3556
|
+
}
|
|
3557
|
+
function insert(char) {
|
|
3558
|
+
const active = document.activeElement;
|
|
3559
|
+
options.onInsert(char);
|
|
3560
|
+
recent = pushRecent(recent, char);
|
|
3561
|
+
options.onRecentChange?.([...recent]);
|
|
3562
|
+
renderRecent();
|
|
3563
|
+
if (active instanceof HTMLElement && root.contains(active))
|
|
3564
|
+
queueMicrotask(() => {
|
|
3565
|
+
if (active.isConnected) active.focus();
|
|
3566
|
+
else search.focus();
|
|
3567
|
+
});
|
|
3568
|
+
}
|
|
3569
|
+
function cellFor(e) {
|
|
3570
|
+
const b = el2("button", "bb-sd-cell", glyphFor(e.char));
|
|
3571
|
+
b.type = "button";
|
|
3572
|
+
b.title = `${e.name} \xB7 ${codePointLabel(e.char)}`;
|
|
3573
|
+
b.setAttribute("aria-label", e.name);
|
|
3574
|
+
b.addEventListener("click", () => select2(e.char, b));
|
|
3575
|
+
b.addEventListener("dblclick", () => insert(e.char));
|
|
3576
|
+
b.addEventListener("keydown", (ev) => {
|
|
3577
|
+
if (ev.key === "Enter" || ev.key === " ") {
|
|
3578
|
+
ev.preventDefault();
|
|
3579
|
+
select2(e.char, b);
|
|
3580
|
+
insert(e.char);
|
|
3581
|
+
}
|
|
3582
|
+
});
|
|
3583
|
+
b.addEventListener("focus", () => select2(e.char, b));
|
|
3584
|
+
return b;
|
|
3585
|
+
}
|
|
3586
|
+
function fillGrid(target, entries, cols, empty) {
|
|
3587
|
+
target.replaceChildren();
|
|
3588
|
+
if (entries.length === 0) {
|
|
3589
|
+
target.append(el2("div", "bb-sd-empty", empty));
|
|
3590
|
+
return;
|
|
3591
|
+
}
|
|
3592
|
+
const cells = [];
|
|
3593
|
+
entries.forEach((e, i) => {
|
|
3594
|
+
const b = cellFor(e);
|
|
3595
|
+
target.append(b);
|
|
3596
|
+
if (i % cols === 0) cells.push([]);
|
|
3597
|
+
cells[cells.length - 1].push(b);
|
|
3598
|
+
});
|
|
3599
|
+
rovingGrid(cells);
|
|
3600
|
+
}
|
|
3601
|
+
function renderRecent() {
|
|
3602
|
+
fillGrid(
|
|
3603
|
+
recentGrid,
|
|
3604
|
+
recent.map((c) => ({
|
|
3605
|
+
char: c,
|
|
3606
|
+
name: SYMBOL_NAMES.get(c) ?? "Character"
|
|
3607
|
+
})),
|
|
3608
|
+
RECENT_COLS,
|
|
3609
|
+
"Nothing yet \u2014 inserted symbols appear here."
|
|
3610
|
+
);
|
|
3611
|
+
}
|
|
3612
|
+
function renderGroup() {
|
|
3613
|
+
const q = search.value.trim();
|
|
3614
|
+
const entries = q ? searchSymbols(q) : SYMBOL_GROUPS.find((g2) => g2.id === groupSel.value)?.entries ?? [];
|
|
3615
|
+
fillGrid(grid, entries, GRID_COLS, "No symbol matches that name.");
|
|
3616
|
+
const first = grid.querySelector(".bb-sd-cell");
|
|
3617
|
+
if (q && first && entries[0]) select2(entries[0].char, first);
|
|
3618
|
+
else clearSelection();
|
|
3619
|
+
}
|
|
3620
|
+
function clearSelection() {
|
|
3621
|
+
selected = null;
|
|
3622
|
+
selectedEl?.removeAttribute("aria-selected");
|
|
3623
|
+
selectedEl = null;
|
|
3624
|
+
big.textContent = "";
|
|
3625
|
+
nameEl.textContent = "Select a symbol";
|
|
3626
|
+
cpEl.textContent = "";
|
|
3627
|
+
if (document.activeElement !== code) code.value = "";
|
|
3628
|
+
insertBtn.disabled = true;
|
|
3629
|
+
}
|
|
3630
|
+
groupSel.addEventListener("change", () => {
|
|
3631
|
+
search.value = "";
|
|
3632
|
+
renderGroup();
|
|
3633
|
+
});
|
|
3634
|
+
search.addEventListener("input", renderGroup);
|
|
3635
|
+
search.addEventListener("keydown", (e) => {
|
|
3636
|
+
if (e.key === "Enter" && selected) {
|
|
3637
|
+
e.preventDefault();
|
|
3638
|
+
insert(selected);
|
|
3639
|
+
} else if (e.key === "ArrowDown") {
|
|
3640
|
+
e.preventDefault();
|
|
3641
|
+
grid.querySelector(".bb-sd-cell")?.focus();
|
|
3642
|
+
}
|
|
3643
|
+
});
|
|
3644
|
+
code.addEventListener("input", () => {
|
|
3645
|
+
const ch = parseCodePoint(code.value);
|
|
3646
|
+
if (ch) {
|
|
3647
|
+
code.removeAttribute("aria-invalid");
|
|
3648
|
+
const cell = Array.from(
|
|
3649
|
+
grid.querySelectorAll(".bb-sd-cell")
|
|
3650
|
+
).find((c) => c.textContent === glyphFor(ch));
|
|
3651
|
+
select2(ch, cell ?? null);
|
|
3652
|
+
} else {
|
|
3653
|
+
code.setAttribute("aria-invalid", code.value.trim() ? "true" : "false");
|
|
3654
|
+
insertBtn.disabled = true;
|
|
3655
|
+
selected = null;
|
|
3656
|
+
}
|
|
3657
|
+
});
|
|
3658
|
+
code.addEventListener("keydown", (e) => {
|
|
3659
|
+
if (e.key === "Enter" && selected) {
|
|
3660
|
+
e.preventDefault();
|
|
3661
|
+
insert(selected);
|
|
3662
|
+
}
|
|
3663
|
+
});
|
|
3664
|
+
insertBtn.addEventListener("click", () => {
|
|
3665
|
+
if (selected) insert(selected);
|
|
3666
|
+
});
|
|
3667
|
+
closeBtn.addEventListener("click", () => dialog.close());
|
|
3668
|
+
showTab(false);
|
|
3669
|
+
renderRecent();
|
|
3670
|
+
renderGroup();
|
|
3671
|
+
return {
|
|
3672
|
+
open() {
|
|
3673
|
+
dialog.open();
|
|
3674
|
+
showTab(false);
|
|
3675
|
+
queueMicrotask(() => {
|
|
3676
|
+
search.focus();
|
|
3677
|
+
search.select();
|
|
3678
|
+
});
|
|
3679
|
+
},
|
|
3680
|
+
close() {
|
|
3681
|
+
dialog.close();
|
|
3682
|
+
},
|
|
3683
|
+
destroy() {
|
|
3684
|
+
dialog.destroy();
|
|
3685
|
+
},
|
|
3686
|
+
get isOpen() {
|
|
3687
|
+
return dialog.isOpen;
|
|
3688
|
+
}
|
|
3689
|
+
};
|
|
3690
|
+
}
|
|
3691
|
+
|
|
3692
|
+
// packages/ui/src/lib/symbol-popover.ts
|
|
3693
|
+
var STYLE14 = `
|
|
3694
|
+
.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
|
+
.bb-spk *{box-sizing:border-box}
|
|
3696
|
+
.bb-spk::backdrop{background:transparent}
|
|
3697
|
+
.bb-spk-search{width:100%;height:28px;border:0.5px 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));color:inherit;font:inherit;font-size:12px;padding:0 8px}
|
|
3698
|
+
.bb-spk-search::placeholder{color:inherit;opacity:.45}
|
|
3699
|
+
.bb-spk-lbl{font-size:10.5px;opacity:.65;margin:0 0 4px}
|
|
3700
|
+
.bb-spk-recent{display:grid;grid-template-columns:repeat(8,1fr);gap:3px;min-height:26px}
|
|
3701
|
+
.bb-spk-recent .bb-spk-cell{border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));font-size:14px}
|
|
3702
|
+
.bb-spk-empty{grid-column:1/-1;font-size:11px;opacity:.5;padding:4px 2px}
|
|
3703
|
+
.bb-spk-chips{display:flex;flex-wrap:wrap;gap:3px}
|
|
3704
|
+
.bb-spk-chip{padding:2px 6px;border-radius:10px;border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));color:inherit;font:inherit;font-size:10px;opacity:.8;cursor:pointer}
|
|
3705
|
+
.bb-spk-chip:hover{background:var(--bb-ui-hover,#f1efe8)}
|
|
3706
|
+
.bb-spk-chip[aria-pressed="true"]{background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c);border-color:var(--bb-ui-active-border,#7fb2ec);opacity:1}
|
|
3707
|
+
.bb-spk-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:2px;border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:7px;padding:4px;background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));max-height:150px;overflow:auto}
|
|
3708
|
+
.bb-spk-cell{aspect-ratio:1;display:grid;place-items:center;border:0;border-radius:5px;background:transparent;color:inherit;font-size:16px;line-height:1;padding:0;cursor:pointer;font-family:inherit,"Noto Sans Symbols 2"}
|
|
3709
|
+
.bb-spk-cell:hover{background:var(--bb-ui-hover,#f1efe8)}
|
|
3710
|
+
.bb-spk-cell:focus{outline:none;box-shadow:inset 0 0 0 1.5px var(--bb-ui-active-border,#7fb2ec)}
|
|
3711
|
+
.bb-spk-cell[aria-selected="true"]{background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c)}
|
|
3712
|
+
.bb-spk-foot{display:flex;justify-content:space-between;align-items:center;gap:8px;font-size:11px}
|
|
3713
|
+
.bb-spk-name{opacity:.75;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
3714
|
+
.bb-spk-more{border:0;background:transparent;color:var(--bb-ui-active-fg,#0c447c);font:inherit;font-size:11px;cursor:pointer;padding:2px 4px;border-radius:4px;white-space:nowrap}
|
|
3715
|
+
.bb-spk-more:hover{background:var(--bb-ui-hover,#f1efe8)}
|
|
3716
|
+
`;
|
|
3717
|
+
var COLS = 8;
|
|
3718
|
+
var RECENT_ROW = COLS;
|
|
3719
|
+
function el3(tag, cls, text) {
|
|
3720
|
+
const n = document.createElement(tag);
|
|
3721
|
+
if (cls) n.className = cls;
|
|
3722
|
+
if (text !== void 0) n.textContent = text;
|
|
3723
|
+
return n;
|
|
3724
|
+
}
|
|
3725
|
+
function openSymbolPopover(options) {
|
|
3726
|
+
injectStyle("bb-ui-symbol-popover", STYLE14);
|
|
3727
|
+
const { anchor } = options;
|
|
3728
|
+
let recent = [...options.recent ?? []].slice(0, RECENT_MAX);
|
|
3729
|
+
let groupId = SYMBOL_GROUPS[0].id;
|
|
3730
|
+
let selected = null;
|
|
3731
|
+
const panel = document.createElement("dialog");
|
|
3732
|
+
panel.className = "bb-spk";
|
|
3733
|
+
panel.setAttribute("aria-label", "Insert symbol");
|
|
3734
|
+
let closed = false;
|
|
3735
|
+
const close = () => {
|
|
3736
|
+
if (closed) return;
|
|
3737
|
+
closed = true;
|
|
3738
|
+
window.removeEventListener("scroll", close, true);
|
|
3739
|
+
if (panel.open) panel.close();
|
|
3740
|
+
panel.remove();
|
|
3741
|
+
options.onClose?.();
|
|
3742
|
+
};
|
|
3743
|
+
const search = el3("input", "bb-spk-search");
|
|
3744
|
+
search.type = "search";
|
|
3745
|
+
search.placeholder = "Search name or code (U+2611)";
|
|
3746
|
+
search.setAttribute("aria-label", "Search symbols by name or code");
|
|
3747
|
+
search.spellcheck = false;
|
|
3748
|
+
const recentWrap = el3("div");
|
|
3749
|
+
recentWrap.append(el3("div", "bb-spk-lbl", "Recent"));
|
|
3750
|
+
const recentGrid = el3("div", "bb-spk-recent");
|
|
3751
|
+
recentGrid.setAttribute("role", "grid");
|
|
3752
|
+
recentGrid.setAttribute("aria-label", "Recently used symbols");
|
|
3753
|
+
recentWrap.append(recentGrid);
|
|
3754
|
+
const chips = el3("div", "bb-spk-chips");
|
|
3755
|
+
const chipEls = /* @__PURE__ */ new Map();
|
|
3756
|
+
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", () => {
|
|
3761
|
+
groupId = grp.id;
|
|
3762
|
+
search.value = "";
|
|
3763
|
+
render();
|
|
3764
|
+
});
|
|
3765
|
+
chips.append(c);
|
|
3766
|
+
chipEls.set(grp.id, c);
|
|
3767
|
+
}
|
|
3768
|
+
const grid = el3("div", "bb-spk-grid");
|
|
3769
|
+
grid.setAttribute("role", "grid");
|
|
3770
|
+
grid.setAttribute("aria-label", "Symbols");
|
|
3771
|
+
const foot = el3("div", "bb-spk-foot");
|
|
3772
|
+
const nameEl = el3("span", "bb-spk-name", "");
|
|
3773
|
+
const more = el3("button", "bb-spk-more", "More symbols\u2026");
|
|
3774
|
+
more.type = "button";
|
|
3775
|
+
more.addEventListener("click", () => {
|
|
3776
|
+
close();
|
|
3777
|
+
options.onMore?.();
|
|
3778
|
+
});
|
|
3779
|
+
foot.append(nameEl, more);
|
|
3780
|
+
if (!options.onMore) more.hidden = true;
|
|
3781
|
+
panel.append(search, recentWrap, chips, grid, foot);
|
|
3782
|
+
let selectedEl = null;
|
|
3783
|
+
const select2 = (char, cell) => {
|
|
3784
|
+
selected = char;
|
|
3785
|
+
selectedEl?.removeAttribute("aria-selected");
|
|
3786
|
+
selectedEl = cell;
|
|
3787
|
+
selectedEl?.setAttribute("aria-selected", "true");
|
|
3788
|
+
nameEl.textContent = `${SYMBOL_NAMES.get(char) ?? "Character"} \xB7 ${codePointLabel(char)}`;
|
|
3789
|
+
};
|
|
3790
|
+
const insert = (char) => {
|
|
3791
|
+
const active = document.activeElement;
|
|
3792
|
+
options.onInsert(char);
|
|
3793
|
+
recent = pushRecent(recent, char);
|
|
3794
|
+
options.onRecentChange?.([...recent]);
|
|
3795
|
+
renderRecent();
|
|
3796
|
+
queueMicrotask(() => {
|
|
3797
|
+
if (active instanceof HTMLElement && active.isConnected) active.focus();
|
|
3798
|
+
else search.focus();
|
|
3799
|
+
});
|
|
3800
|
+
};
|
|
3801
|
+
const cellFor = (e) => {
|
|
3802
|
+
const b = el3("button", "bb-spk-cell", e.char);
|
|
3803
|
+
b.type = "button";
|
|
3804
|
+
b.title = `${e.name} \xB7 ${codePointLabel(e.char)}`;
|
|
3805
|
+
b.setAttribute("aria-label", e.name);
|
|
3806
|
+
b.addEventListener("focus", () => select2(e.char, b));
|
|
3807
|
+
b.addEventListener("click", () => {
|
|
3808
|
+
select2(e.char, b);
|
|
3809
|
+
insert(e.char);
|
|
3810
|
+
});
|
|
3811
|
+
b.addEventListener("keydown", (ev) => {
|
|
3812
|
+
if (ev.key === "Enter" || ev.key === " ") {
|
|
3813
|
+
ev.preventDefault();
|
|
3814
|
+
select2(e.char, b);
|
|
3815
|
+
insert(e.char);
|
|
3816
|
+
}
|
|
3817
|
+
});
|
|
3818
|
+
return b;
|
|
3819
|
+
};
|
|
3820
|
+
const fill = (target, entries, empty) => {
|
|
3821
|
+
target.replaceChildren();
|
|
3822
|
+
if (entries.length === 0) {
|
|
3823
|
+
target.append(el3("div", "bb-spk-empty", empty));
|
|
3824
|
+
return;
|
|
3825
|
+
}
|
|
3826
|
+
const cells = [];
|
|
3827
|
+
entries.forEach((e, i) => {
|
|
3828
|
+
const b = cellFor(e);
|
|
3829
|
+
target.append(b);
|
|
3830
|
+
if (i % COLS === 0) cells.push([]);
|
|
3831
|
+
cells[cells.length - 1].push(b);
|
|
3832
|
+
});
|
|
3833
|
+
rovingGrid(cells);
|
|
3834
|
+
};
|
|
3835
|
+
const renderRecent = () => fill(
|
|
3836
|
+
recentGrid,
|
|
3837
|
+
recent.slice(0, RECENT_ROW).map((c) => ({
|
|
3838
|
+
char: c,
|
|
3839
|
+
name: SYMBOL_NAMES.get(c) ?? "Character"
|
|
3840
|
+
})),
|
|
3841
|
+
"Nothing yet."
|
|
3842
|
+
);
|
|
3843
|
+
const render = () => {
|
|
3844
|
+
const q = search.value.trim();
|
|
3845
|
+
const byCode = q ? parseCodePoint(q) : null;
|
|
3846
|
+
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));
|
|
3849
|
+
fill(grid, entries, "No match.");
|
|
3850
|
+
const first = grid.querySelector(".bb-spk-cell");
|
|
3851
|
+
if (q && first && entries[0]) select2(entries[0].char, first);
|
|
3852
|
+
else {
|
|
3853
|
+
selected = null;
|
|
3854
|
+
selectedEl?.removeAttribute("aria-selected");
|
|
3855
|
+
selectedEl = null;
|
|
3856
|
+
nameEl.textContent = "";
|
|
3857
|
+
}
|
|
3858
|
+
};
|
|
3859
|
+
search.addEventListener("input", render);
|
|
3860
|
+
search.addEventListener("keydown", (e) => {
|
|
3861
|
+
if (e.key === "Enter" && selected) {
|
|
3862
|
+
e.preventDefault();
|
|
3863
|
+
insert(selected);
|
|
3864
|
+
} else if (e.key === "ArrowDown") {
|
|
3865
|
+
e.preventDefault();
|
|
3866
|
+
grid.querySelector(".bb-spk-cell")?.focus();
|
|
3867
|
+
}
|
|
3868
|
+
});
|
|
3869
|
+
document.body.append(panel);
|
|
3870
|
+
panel.showModal();
|
|
3871
|
+
const r = anchor.getBoundingClientRect();
|
|
3872
|
+
placeFloating(panel, { x: r.left, y: r.top, height: r.height });
|
|
3873
|
+
panel.addEventListener("close", close);
|
|
3874
|
+
panel.addEventListener("pointerdown", (e) => {
|
|
3875
|
+
const b = panel.getBoundingClientRect();
|
|
3876
|
+
const outside = e.clientX < b.left || e.clientX > b.right || e.clientY < b.top || e.clientY > b.bottom;
|
|
3877
|
+
if (outside) close();
|
|
3878
|
+
});
|
|
3879
|
+
window.addEventListener("scroll", close, true);
|
|
3880
|
+
renderRecent();
|
|
3881
|
+
render();
|
|
3882
|
+
search.focus();
|
|
3883
|
+
return { close };
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3886
|
+
// packages/ui/src/lib/shortcuts-dialog.ts
|
|
3887
|
+
var import_bapbong_contracts3 = require("@shadow-garden/bapbong-contracts");
|
|
3888
|
+
var STYLE15 = `
|
|
3889
|
+
.bb-ks{display:flex;flex-direction:column;gap:10px;width:600px;max-width:100%;color:var(--bb-ui-fg,#2c2c2a);font-size:12px}
|
|
3890
|
+
.bb-ks *{box-sizing:border-box}
|
|
3891
|
+
.bb-ks-top{display:flex;gap:8px;align-items:center}
|
|
3892
|
+
.bb-ks-search{flex:1;height:30px;border:0.5px 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));color:inherit;font:inherit;font-size:12px;padding:0 8px}
|
|
3893
|
+
.bb-ks-search::placeholder{color:inherit;opacity:.45}
|
|
3894
|
+
.bb-ks-count{font-size:11px;opacity:.6;white-space:nowrap}
|
|
3895
|
+
/* No box around the list: a bordered, tinted scroller turns the scrollbar's
|
|
3896
|
+
gutter into a blank column at its edge. Flat on the dialog surface, the
|
|
3897
|
+
rail reads like the app's own (idle-hidden overlay on a plain ground). */
|
|
3898
|
+
.bb-ks-wrap{overflow:auto;max-height:min(60vh,420px);margin:0 -12px;padding:0 12px;scrollbar-gutter:stable}
|
|
3899
|
+
.bb-ks table{width:100%;border-collapse:collapse}
|
|
3900
|
+
.bb-ks th{position:sticky;top:0;z-index:1;text-align:left;font-size:11px;font-weight:600;padding:7px 10px;border-bottom:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));cursor:pointer;user-select:none;white-space:nowrap;background-color:var(--bb-ui-bg,#fff);background-image:linear-gradient(var(--bb-ui-dialog-bg,transparent),var(--bb-ui-dialog-bg,transparent))}
|
|
3901
|
+
/* Opaque surface UNDER the dialog's own tint: a sticky header on the glass
|
|
3902
|
+
alone let the rows scrolling beneath show through it. The dimming goes on
|
|
3903
|
+
the text, not the cell, for the same reason. */
|
|
3904
|
+
.bb-ks th span{opacity:.75}
|
|
3905
|
+
.bb-ks th[aria-sort]{color:var(--bb-ui-active-fg,#0c447c)}
|
|
3906
|
+
.bb-ks th[aria-sort] span{opacity:1}
|
|
3907
|
+
.bb-ks td{padding:7px 10px;border-bottom:0.5px solid var(--bb-ui-border,#e3e3e0);vertical-align:middle}
|
|
3908
|
+
.bb-ks tr:last-child td{border-bottom:0}
|
|
3909
|
+
.bb-ks tbody tr:hover td{background:var(--bb-ui-hover,#f1efe8)}
|
|
3910
|
+
.bb-ks tbody tr:hover td:first-child{border-radius:6px 0 0 6px}
|
|
3911
|
+
.bb-ks tbody tr:hover td:last-child{border-radius:0 6px 6px 0}
|
|
3912
|
+
.bb-ks td.cmd{width:42%}
|
|
3913
|
+
.bb-ks td.cmd small{display:block;font-size:10px;opacity:.5;font-family:ui-monospace,Menlo,Consolas,monospace}
|
|
3914
|
+
.bb-ks kbd{display:inline-block;min-width:20px;padding:1px 6px;margin-right:3px;border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-bottom-width:1.5px;border-radius:5px;background:var(--bb-ui-bg,#fff);font:inherit;font-size:11px;text-align:center}
|
|
3915
|
+
.bb-ks .or{opacity:.5;margin:0 4px 0 1px;font-size:11px}
|
|
3916
|
+
.bb-ks td.when{font-size:11px;opacity:.7;width:24%}
|
|
3917
|
+
.bb-ks td.src{width:12%}
|
|
3918
|
+
.bb-ks-chip{display:inline-block;padding:1px 7px;border-radius:9px;font-size:10px;border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));opacity:.85;white-space:nowrap}
|
|
3919
|
+
.bb-ks-chip.core{background:var(--bb-ui-active-bg,#e6f1fb);border-color:var(--bb-ui-active-border,#7fb2ec);color:var(--bb-ui-active-fg,#0c447c);opacity:1}
|
|
3920
|
+
.bb-ks-empty{padding:16px;text-align:center;font-size:12px;opacity:.55}
|
|
3921
|
+
.bb-ks-foot{display:flex;justify-content:space-between;font-size:11px;opacity:.6}
|
|
3922
|
+
.bb-ks mark{background:transparent;color:inherit;font-weight:600;text-decoration:underline;text-decoration-color:var(--bb-ui-active-border,#7fb2ec);text-underline-offset:2px}
|
|
3923
|
+
`;
|
|
3924
|
+
function el4(tag, cls, text) {
|
|
3925
|
+
const n = document.createElement(tag);
|
|
3926
|
+
if (cls) n.className = cls;
|
|
3927
|
+
if (text !== void 0) n.textContent = text;
|
|
3928
|
+
return n;
|
|
3929
|
+
}
|
|
3930
|
+
function highlight(text, q) {
|
|
3931
|
+
if (!q) return [text];
|
|
3932
|
+
const out = [];
|
|
3933
|
+
const lower = text.toLowerCase();
|
|
3934
|
+
let i = 0;
|
|
3935
|
+
for (; ; ) {
|
|
3936
|
+
const j = lower.indexOf(q, i);
|
|
3937
|
+
if (j < 0) break;
|
|
3938
|
+
if (j > i) out.push(text.slice(i, j));
|
|
3939
|
+
out.push(el4("mark", void 0, text.slice(j, j + q.length)));
|
|
3940
|
+
i = j + q.length;
|
|
3941
|
+
}
|
|
3942
|
+
if (i < text.length) out.push(text.slice(i));
|
|
3943
|
+
return out;
|
|
3944
|
+
}
|
|
3945
|
+
function openKeyboardShortcutsDialog(options) {
|
|
3946
|
+
injectStyle("bb-ui-shortcuts-dialog", STYLE15);
|
|
3947
|
+
const dialog = new Dialog({
|
|
3948
|
+
title: options.title ?? "Keyboard shortcuts",
|
|
3949
|
+
modal: true,
|
|
3950
|
+
wide: true
|
|
3951
|
+
});
|
|
3952
|
+
const root = el4("div", "bb-ks");
|
|
3953
|
+
const top = el4("div", "bb-ks-top");
|
|
3954
|
+
const search = el4("input", "bb-ks-search");
|
|
3955
|
+
search.type = "search";
|
|
3956
|
+
search.placeholder = "Search command, key, when or source\u2026";
|
|
3957
|
+
search.setAttribute("aria-label", "Search shortcuts");
|
|
3958
|
+
const count = el4("span", "bb-ks-count", "");
|
|
3959
|
+
top.append(search, count);
|
|
3960
|
+
const wrap = el4("div", "bb-ks-wrap");
|
|
3961
|
+
const table = el4("table");
|
|
3962
|
+
const thead = el4("thead");
|
|
3963
|
+
const headRow = el4("tr");
|
|
3964
|
+
const columns = [
|
|
3965
|
+
{ key: "title", label: "Command" },
|
|
3966
|
+
{ key: "keys", label: "Keybinding" },
|
|
3967
|
+
{ key: "when", label: "When" },
|
|
3968
|
+
{ key: "source", label: "Source" }
|
|
3969
|
+
];
|
|
3970
|
+
let sortKey = "title";
|
|
3971
|
+
let sortAsc = true;
|
|
3972
|
+
const ths = /* @__PURE__ */ new Map();
|
|
3973
|
+
for (const c of columns) {
|
|
3974
|
+
const th = el4("th");
|
|
3975
|
+
th.append(el4("span", void 0, c.label));
|
|
3976
|
+
th.addEventListener("click", () => {
|
|
3977
|
+
if (sortKey === c.key) sortAsc = !sortAsc;
|
|
3978
|
+
else {
|
|
3979
|
+
sortKey = c.key;
|
|
3980
|
+
sortAsc = true;
|
|
3981
|
+
}
|
|
3982
|
+
render();
|
|
3983
|
+
});
|
|
3984
|
+
headRow.append(th);
|
|
3985
|
+
ths.set(c.key, th);
|
|
3986
|
+
}
|
|
3987
|
+
thead.append(headRow);
|
|
3988
|
+
const tbody = el4("tbody");
|
|
3989
|
+
table.append(thead, tbody);
|
|
3990
|
+
wrap.append(table);
|
|
3991
|
+
const foot = el4("div", "bb-ks-foot");
|
|
3992
|
+
const footL = el4(
|
|
3993
|
+
"span",
|
|
3994
|
+
void 0,
|
|
3995
|
+
"Sorted by command \xB7 click a header to sort"
|
|
3996
|
+
);
|
|
3997
|
+
const footR = el4("span", void 0, "Esc closes");
|
|
3998
|
+
foot.append(footL, footR);
|
|
3999
|
+
root.append(top, wrap, foot);
|
|
4000
|
+
dialog.setContent(root);
|
|
4001
|
+
const allRows = () => {
|
|
4002
|
+
const rows = [];
|
|
4003
|
+
for (const src of options.sources)
|
|
4004
|
+
rows.push(
|
|
4005
|
+
...(0, import_bapbong_contracts3.keybindingRows)(src.keybindings, (c) => src.commands.get(c)?.title)
|
|
4006
|
+
);
|
|
4007
|
+
return rows;
|
|
4008
|
+
};
|
|
4009
|
+
const kbdCell = (keys) => {
|
|
4010
|
+
const td = el4("td");
|
|
4011
|
+
keys.forEach((k, i) => {
|
|
4012
|
+
if (i > 0) td.append(el4("span", "or", "or"));
|
|
4013
|
+
for (const part of (0, import_bapbong_contracts3.formatKey)(k, IS_MAC))
|
|
4014
|
+
td.append(el4("kbd", void 0, part));
|
|
4015
|
+
});
|
|
4016
|
+
return td;
|
|
4017
|
+
};
|
|
4018
|
+
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;
|
|
4020
|
+
const sorted = [...rows].sort(
|
|
4021
|
+
(a, b) => val(a).localeCompare(val(b), void 0, { sensitivity: "base" })
|
|
4022
|
+
);
|
|
4023
|
+
return sortAsc ? sorted : sorted.reverse();
|
|
4024
|
+
};
|
|
4025
|
+
const render = () => {
|
|
4026
|
+
const q = search.value.trim().toLowerCase();
|
|
4027
|
+
const rows = allRows();
|
|
4028
|
+
const shown = sortRows((0, import_bapbong_contracts3.filterKeybindingRows)(rows, q, IS_MAC));
|
|
4029
|
+
for (const [key, th] of ths) {
|
|
4030
|
+
if (key === sortKey)
|
|
4031
|
+
th.setAttribute("aria-sort", sortAsc ? "ascending" : "descending");
|
|
4032
|
+
else th.removeAttribute("aria-sort");
|
|
4033
|
+
}
|
|
4034
|
+
tbody.replaceChildren();
|
|
4035
|
+
if (shown.length === 0) {
|
|
4036
|
+
const tr = el4("tr");
|
|
4037
|
+
const td = el4("td", "bb-ks-empty", "No shortcut matches.");
|
|
4038
|
+
td.colSpan = 4;
|
|
4039
|
+
tr.append(td);
|
|
4040
|
+
tbody.append(tr);
|
|
4041
|
+
}
|
|
4042
|
+
for (const r of shown) {
|
|
4043
|
+
const tr = el4("tr");
|
|
4044
|
+
const cmd = el4("td", "cmd");
|
|
4045
|
+
cmd.append(...highlight(r.title, q));
|
|
4046
|
+
const small = el4("small");
|
|
4047
|
+
small.append(...highlight(r.command, q));
|
|
4048
|
+
cmd.append(small);
|
|
4049
|
+
const when = el4("td", "when");
|
|
4050
|
+
when.append(...highlight(r.when ?? "", q));
|
|
4051
|
+
const src = el4("td", "src");
|
|
4052
|
+
const chip = el4(
|
|
4053
|
+
"span",
|
|
4054
|
+
"bb-ks-chip" + (r.source === "core" ? " core" : "")
|
|
4055
|
+
);
|
|
4056
|
+
chip.append(...highlight(r.source, q));
|
|
4057
|
+
src.append(chip);
|
|
4058
|
+
tr.append(cmd, kbdCell(r.keys), when, src);
|
|
4059
|
+
tbody.append(tr);
|
|
4060
|
+
}
|
|
4061
|
+
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`;
|
|
4063
|
+
};
|
|
4064
|
+
search.addEventListener("input", render);
|
|
4065
|
+
dialog.onClose(() => dialog.destroy());
|
|
4066
|
+
render();
|
|
4067
|
+
dialog.open();
|
|
4068
|
+
search.focus();
|
|
4069
|
+
}
|
|
4070
|
+
|
|
4071
|
+
// packages/ui/src/lib/scrollbars.ts
|
|
4072
|
+
var STYLE16 = `
|
|
4073
|
+
@property --bb-scroll-thumb-now {
|
|
4074
|
+
syntax: '<color>';
|
|
4075
|
+
/* MUST inherit: the thumb pseudo-element never matches .bb-scrolling
|
|
4076
|
+
itself \u2014 it only ever INHERITS the value from its owner. */
|
|
4077
|
+
inherits: true;
|
|
4078
|
+
initial-value: transparent;
|
|
4079
|
+
}
|
|
4080
|
+
* { transition: --bb-scroll-thumb-now 0.35s ease; }
|
|
4081
|
+
.bb-scrolling { --bb-scroll-thumb-now: var(--bb-ui-scroll-thumb, rgba(64,52,28,.28)); }
|
|
4082
|
+
::-webkit-scrollbar { width: 13px; height: 13px; background: transparent; }
|
|
4083
|
+
::-webkit-scrollbar-track { background: transparent; }
|
|
4084
|
+
::-webkit-scrollbar-corner { background: transparent; }
|
|
4085
|
+
::-webkit-scrollbar-thumb {
|
|
4086
|
+
background-color: var(--bb-scroll-thumb-now);
|
|
4087
|
+
background-clip: content-box;
|
|
4088
|
+
border: 3px solid transparent;
|
|
4089
|
+
border-radius: 99px;
|
|
4090
|
+
min-height: 40px; /* a 277-page doc must not shrink the thumb to a dot */
|
|
4091
|
+
}
|
|
4092
|
+
::-webkit-scrollbar-thumb:hover,
|
|
4093
|
+
::-webkit-scrollbar-thumb:active {
|
|
4094
|
+
background-color: var(--bb-ui-scroll-thumb-hover, rgba(64,52,28,.45));
|
|
4095
|
+
}
|
|
4096
|
+
@supports not selector(::-webkit-scrollbar) {
|
|
4097
|
+
/* non-WebKit (Firefox): native thin overlay, same colours */
|
|
4098
|
+
* { scrollbar-width: thin; scrollbar-color: var(--bb-ui-scroll-thumb, rgba(64,52,28,.28)) transparent; }
|
|
4099
|
+
}
|
|
4100
|
+
`;
|
|
4101
|
+
var installed = null;
|
|
4102
|
+
function installScrollbars(root = document) {
|
|
4103
|
+
if (installed) return installed;
|
|
4104
|
+
injectStyle("bb-ui-scrollbars", STYLE16);
|
|
4105
|
+
const quiet = /* @__PURE__ */ new WeakMap();
|
|
4106
|
+
const onScroll = (ev) => {
|
|
4107
|
+
const el5 = ev.target instanceof HTMLElement ? ev.target : root.documentElement;
|
|
4108
|
+
el5.classList.add("bb-scrolling");
|
|
4109
|
+
clearTimeout(quiet.get(el5));
|
|
4110
|
+
quiet.set(
|
|
4111
|
+
el5,
|
|
4112
|
+
window.setTimeout(() => el5.classList.remove("bb-scrolling"), 1e3)
|
|
4113
|
+
);
|
|
4114
|
+
};
|
|
4115
|
+
root.addEventListener("scroll", onScroll, { capture: true, passive: true });
|
|
4116
|
+
installed = () => {
|
|
4117
|
+
root.removeEventListener("scroll", onScroll, { capture: true });
|
|
4118
|
+
installed = null;
|
|
4119
|
+
};
|
|
4120
|
+
return installed;
|
|
4121
|
+
}
|
|
2856
4122
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2857
4123
|
0 && (module.exports = {
|
|
2858
4124
|
COLOR_PALETTE,
|
|
2859
4125
|
Dialog,
|
|
4126
|
+
RECENT_MAX,
|
|
4127
|
+
SPECIAL_CHARACTERS,
|
|
4128
|
+
SYMBOL_GROUPS,
|
|
4129
|
+
SYMBOL_NAMES,
|
|
2860
4130
|
cmToPx,
|
|
4131
|
+
codePointLabel,
|
|
2861
4132
|
colorButton,
|
|
2862
4133
|
createFindDialog,
|
|
2863
4134
|
createSectionChip,
|
|
4135
|
+
createSymbolDialog,
|
|
2864
4136
|
defaultMenus,
|
|
2865
4137
|
defaultToolbarGroups,
|
|
4138
|
+
installScrollbars,
|
|
2866
4139
|
marginPresetPicker,
|
|
2867
4140
|
mountMenubar,
|
|
2868
4141
|
mountToolbar,
|
|
2869
4142
|
openCellProperties,
|
|
2870
4143
|
openColorPicker,
|
|
2871
4144
|
openFontDialog,
|
|
4145
|
+
openKeyboardShortcutsDialog,
|
|
2872
4146
|
openMarginsDialog,
|
|
2873
4147
|
openPageSizeDialog,
|
|
4148
|
+
openSymbolPopover,
|
|
2874
4149
|
orientationPicker,
|
|
2875
4150
|
pageNumberPicker,
|
|
2876
4151
|
pageSizePicker,
|
|
4152
|
+
panelAnchor,
|
|
4153
|
+
parseCodePoint,
|
|
2877
4154
|
promptDialog,
|
|
4155
|
+
pushRecent,
|
|
2878
4156
|
pxToCm,
|
|
4157
|
+
searchSymbols,
|
|
2879
4158
|
sectionPaperPanel,
|
|
2880
4159
|
showContextMenu,
|
|
2881
4160
|
showLinkPanel,
|