@shadow-garden/bapbong-ui 0.7.0 → 0.8.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 +841 -273
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +837 -273
- package/dist/lib/cell-properties.d.ts +1 -1
- package/dist/lib/cell-properties.d.ts.map +1 -1
- package/dist/lib/color-picker.d.ts +51 -0
- package/dist/lib/color-picker.d.ts.map +1 -0
- package/dist/lib/font-dialog.d.ts +15 -0
- package/dist/lib/font-dialog.d.ts.map +1 -0
- package/dist/lib/internal.d.ts +12 -0
- package/dist/lib/internal.d.ts.map +1 -1
- package/dist/lib/link-panel.d.ts.map +1 -1
- package/dist/lib/menubar.d.ts.map +1 -1
- package/dist/lib/toolbar.d.ts +7 -6
- package/dist/lib/toolbar.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -20,8 +20,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// packages/ui/src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
COLOR_PALETTE: () => COLOR_PALETTE,
|
|
23
24
|
Dialog: () => Dialog,
|
|
24
25
|
cmToPx: () => cmToPx,
|
|
26
|
+
colorButton: () => colorButton,
|
|
25
27
|
createFindDialog: () => createFindDialog,
|
|
26
28
|
defaultMenus: () => defaultMenus,
|
|
27
29
|
defaultToolbarGroups: () => defaultToolbarGroups,
|
|
@@ -29,6 +31,8 @@ __export(index_exports, {
|
|
|
29
31
|
mountMenubar: () => mountMenubar,
|
|
30
32
|
mountToolbar: () => mountToolbar,
|
|
31
33
|
openCellProperties: () => openCellProperties,
|
|
34
|
+
openColorPicker: () => openColorPicker,
|
|
35
|
+
openFontDialog: () => openFontDialog,
|
|
32
36
|
openMarginsDialog: () => openMarginsDialog,
|
|
33
37
|
openPageSizeDialog: () => openPageSizeDialog,
|
|
34
38
|
orientationPicker: () => orientationPicker,
|
|
@@ -44,10 +48,24 @@ module.exports = __toCommonJS(index_exports);
|
|
|
44
48
|
// packages/ui/src/lib/internal.ts
|
|
45
49
|
function injectStyle(id, css) {
|
|
46
50
|
if (document.getElementById(id)) return;
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
document.head.appendChild(
|
|
51
|
+
const el2 = document.createElement("style");
|
|
52
|
+
el2.id = id;
|
|
53
|
+
el2.textContent = css;
|
|
54
|
+
document.head.appendChild(el2);
|
|
55
|
+
}
|
|
56
|
+
function placeFloating(el2, anchor) {
|
|
57
|
+
const r = el2.getBoundingClientRect();
|
|
58
|
+
const pad = 6;
|
|
59
|
+
const gap = 6;
|
|
60
|
+
const x = Math.max(
|
|
61
|
+
pad,
|
|
62
|
+
Math.min(anchor.x, window.innerWidth - r.width - pad)
|
|
63
|
+
);
|
|
64
|
+
const below = anchor.y + anchor.height + gap;
|
|
65
|
+
const above = anchor.y - gap - r.height;
|
|
66
|
+
const y = below + r.height <= window.innerHeight - pad || above < pad ? Math.min(below, window.innerHeight - r.height - pad) : above;
|
|
67
|
+
el2.style.left = `${x}px`;
|
|
68
|
+
el2.style.top = `${y}px`;
|
|
51
69
|
}
|
|
52
70
|
|
|
53
71
|
// packages/ui/src/lib/dialog.ts
|
|
@@ -63,9 +81,9 @@ var STYLE = `
|
|
|
63
81
|
.bb-dialog-close:hover{opacity:1;background:var(--bb-ui-hover,#f1efe8)}
|
|
64
82
|
.bb-dialog-body{padding:12px}
|
|
65
83
|
.bb-prompt{display:flex;flex-direction:column;gap:10px;min-width:280px}
|
|
66
|
-
.bb-prompt-input{height:30px;padding:0 9px;border:1px solid var(--bb-ui-border,#d8d6cf);border-radius:6px;font:inherit;font-size:13px}
|
|
84
|
+
.bb-prompt-input{height:30px;padding:0 9px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;font:inherit;font-size:13px}
|
|
67
85
|
.bb-prompt-actions{display:flex;justify-content:flex-end;gap:8px}
|
|
68
|
-
.bb-prompt-btn{height:30px;padding:0 14px;border:1px solid var(--bb-ui-border,#d8d6cf);border-radius:6px;background:var(--bb-ui-bg,#fff);color:inherit;font:inherit;font-size:13px;cursor:pointer}
|
|
86
|
+
.bb-prompt-btn{height:30px;padding:0 14px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));color:inherit;font:inherit;font-size:13px;cursor:pointer}
|
|
69
87
|
.bb-prompt-btn[data-primary]{background:var(--bb-ui-active-bg,#e6f1fb);border-color:var(--bb-ui-active-border,#b5d4f4);color:var(--bb-ui-active-fg,#0c447c)}
|
|
70
88
|
.bb-prompt-btn:hover{filter:brightness(.97)}
|
|
71
89
|
`;
|
|
@@ -89,8 +107,8 @@ var Dialog = class {
|
|
|
89
107
|
injectStyle("bb-ui-dialog-styles", STYLE);
|
|
90
108
|
this.modal = options.modal ?? false;
|
|
91
109
|
this.anchor = options.anchor;
|
|
92
|
-
const
|
|
93
|
-
|
|
110
|
+
const el2 = document.createElement("dialog");
|
|
111
|
+
el2.className = `bb-dialog ${this.modal ? "bb-dialog-modal" : "bb-dialog-float"}` + (options.className ? ` ${options.className}` : "");
|
|
94
112
|
const header = document.createElement("div");
|
|
95
113
|
header.className = "bb-dialog-header";
|
|
96
114
|
this.title = document.createElement("span");
|
|
@@ -105,18 +123,18 @@ var Dialog = class {
|
|
|
105
123
|
header.append(this.title, close);
|
|
106
124
|
this.body = document.createElement("div");
|
|
107
125
|
this.body.className = "bb-dialog-body";
|
|
108
|
-
|
|
109
|
-
document.body.appendChild(
|
|
110
|
-
|
|
126
|
+
el2.append(header, this.body);
|
|
127
|
+
document.body.appendChild(el2);
|
|
128
|
+
el2.addEventListener("close", () => {
|
|
111
129
|
this.detachReposition();
|
|
112
130
|
this.closeListeners.forEach((cb) => cb());
|
|
113
131
|
});
|
|
114
132
|
if (!this.modal) {
|
|
115
|
-
|
|
133
|
+
el2.addEventListener("keydown", (e) => {
|
|
116
134
|
if (e.key === "Escape") this.close();
|
|
117
135
|
});
|
|
118
136
|
}
|
|
119
|
-
this.el =
|
|
137
|
+
this.el = el2;
|
|
120
138
|
}
|
|
121
139
|
attachReposition() {
|
|
122
140
|
window.addEventListener("scroll", this.reposition, true);
|
|
@@ -201,6 +219,327 @@ function promptDialog(options) {
|
|
|
201
219
|
});
|
|
202
220
|
}
|
|
203
221
|
|
|
222
|
+
// packages/ui/src/lib/color-picker.ts
|
|
223
|
+
var COLOR_PALETTE = [
|
|
224
|
+
[
|
|
225
|
+
"#000000",
|
|
226
|
+
"#434343",
|
|
227
|
+
"#666666",
|
|
228
|
+
"#999999",
|
|
229
|
+
"#B7B7B7",
|
|
230
|
+
"#CCCCCC",
|
|
231
|
+
"#D9D9D9",
|
|
232
|
+
"#EFEFEF",
|
|
233
|
+
"#F3F3F3",
|
|
234
|
+
"#FFFFFF"
|
|
235
|
+
],
|
|
236
|
+
[
|
|
237
|
+
"#980000",
|
|
238
|
+
"#FF0000",
|
|
239
|
+
"#FF9900",
|
|
240
|
+
"#FFFF00",
|
|
241
|
+
"#00FF00",
|
|
242
|
+
"#00FFFF",
|
|
243
|
+
"#4A86E8",
|
|
244
|
+
"#0000FF",
|
|
245
|
+
"#9900FF",
|
|
246
|
+
"#FF00FF"
|
|
247
|
+
],
|
|
248
|
+
[
|
|
249
|
+
"#E6B8AF",
|
|
250
|
+
"#F4CCCC",
|
|
251
|
+
"#FCE5CD",
|
|
252
|
+
"#FFF2CC",
|
|
253
|
+
"#D9EAD3",
|
|
254
|
+
"#D0E0E3",
|
|
255
|
+
"#C9DAF8",
|
|
256
|
+
"#CFE2F3",
|
|
257
|
+
"#D9D2E9",
|
|
258
|
+
"#EAD1DC"
|
|
259
|
+
],
|
|
260
|
+
[
|
|
261
|
+
"#DD7E6B",
|
|
262
|
+
"#EA9999",
|
|
263
|
+
"#F9CB9C",
|
|
264
|
+
"#FFE599",
|
|
265
|
+
"#B6D7A8",
|
|
266
|
+
"#A2C4C9",
|
|
267
|
+
"#A4C2F4",
|
|
268
|
+
"#9FC5E8",
|
|
269
|
+
"#B4A7D6",
|
|
270
|
+
"#D5A6BD"
|
|
271
|
+
],
|
|
272
|
+
[
|
|
273
|
+
"#CC4125",
|
|
274
|
+
"#E06666",
|
|
275
|
+
"#F6B26B",
|
|
276
|
+
"#FFD966",
|
|
277
|
+
"#93C47D",
|
|
278
|
+
"#76A5AF",
|
|
279
|
+
"#6D9EEB",
|
|
280
|
+
"#6FA8DC",
|
|
281
|
+
"#8E7CC3",
|
|
282
|
+
"#C27BA0"
|
|
283
|
+
],
|
|
284
|
+
[
|
|
285
|
+
"#A61C00",
|
|
286
|
+
"#CC0000",
|
|
287
|
+
"#E69138",
|
|
288
|
+
"#F1C232",
|
|
289
|
+
"#6AA84F",
|
|
290
|
+
"#45818E",
|
|
291
|
+
"#3C78D8",
|
|
292
|
+
"#3D85C6",
|
|
293
|
+
"#674EA7",
|
|
294
|
+
"#A64D79"
|
|
295
|
+
],
|
|
296
|
+
[
|
|
297
|
+
"#85200C",
|
|
298
|
+
"#990000",
|
|
299
|
+
"#B45F06",
|
|
300
|
+
"#BF9000",
|
|
301
|
+
"#38761D",
|
|
302
|
+
"#134F5C",
|
|
303
|
+
"#1155CC",
|
|
304
|
+
"#0B5394",
|
|
305
|
+
"#351C75",
|
|
306
|
+
"#741B47"
|
|
307
|
+
],
|
|
308
|
+
[
|
|
309
|
+
"#5B0F00",
|
|
310
|
+
"#660000",
|
|
311
|
+
"#783F04",
|
|
312
|
+
"#7F6000",
|
|
313
|
+
"#274E13",
|
|
314
|
+
"#0C343D",
|
|
315
|
+
"#1C4587",
|
|
316
|
+
"#073763",
|
|
317
|
+
"#20124D",
|
|
318
|
+
"#4C1130"
|
|
319
|
+
]
|
|
320
|
+
];
|
|
321
|
+
var customColors = [];
|
|
322
|
+
var MAX_CUSTOM = 8;
|
|
323
|
+
function remember(color) {
|
|
324
|
+
const at = customColors.indexOf(color);
|
|
325
|
+
if (at !== -1) customColors.splice(at, 1);
|
|
326
|
+
customColors.unshift(color);
|
|
327
|
+
if (customColors.length > MAX_CUSTOM) customColors.length = MAX_CUSTOM;
|
|
328
|
+
}
|
|
329
|
+
var isHex = (v) => /^#[0-9a-fA-F]{6}$/.test(v);
|
|
330
|
+
var STYLE2 = `
|
|
331
|
+
.bb-cpk{position:fixed;margin:0;max-width:none;max-height:none;z-index:1300;padding:11px;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);box-sizing:border-box}
|
|
332
|
+
.bb-cpk *{box-sizing:border-box}
|
|
333
|
+
.bb-cpk-grid{display:grid;grid-template-columns:repeat(10,20px);gap:5px}
|
|
334
|
+
.bb-cpk-sw{width:20px;height:20px;padding:0;border-radius:50%;border:1px solid rgba(128,128,128,.35);cursor:pointer}
|
|
335
|
+
.bb-cpk-sw:focus-visible{outline:none}
|
|
336
|
+
.bb-cpk-sw.on,.bb-cpk-sw:focus-visible{box-shadow:0 0 0 2px var(--bb-ui-menu-bg,#fff),0 0 0 4px var(--bb-ui-active-fg,#0c447c)}
|
|
337
|
+
.bb-cpk-cap{font-size:11px;letter-spacing:.04em;opacity:.6;margin:13px 0 7px}
|
|
338
|
+
.bb-cpk-row{display:flex;gap:6px;align-items:center;flex-wrap:wrap}
|
|
339
|
+
.bb-cpk-none{width:100%;display:flex;align-items:center;gap:8px;height:28px;padding:0 7px;margin-bottom:10px;border:0;border-radius:6px;background:transparent;color:inherit;font:inherit;font-size:13px;text-align:left;cursor:pointer}
|
|
340
|
+
.bb-cpk-none:hover,.bb-cpk-none:focus-visible{background:var(--bb-ui-hover,#f1efe8);outline:none}
|
|
341
|
+
.bb-cpk-none-chip{width:18px;height:18px;border-radius:50%;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));display:flex;align-items:center;justify-content:center;font-size:12px;opacity:.6;flex:none}
|
|
342
|
+
.bb-cpk-plus{width:20px;height:20px;padding:0;border-radius:50%;border:1px dashed var(--bb-ui-border,#d8d6cf);background:transparent;color:inherit;font:inherit;font-size:13px;line-height:1;cursor:pointer;opacity:.75;position:relative;overflow:hidden}
|
|
343
|
+
.bb-cpk-plus input{position:absolute;inset:0;opacity:0;cursor:pointer;border:0;padding:0}
|
|
344
|
+
.bb-cpk-hex{height:26px;width:96px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));color:inherit;font:inherit;font-size:12px;padding:0 7px;font-family:var(--bb-ui-mono,ui-monospace,monospace)}
|
|
345
|
+
|
|
346
|
+
.bb-cpk-btn{min-width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;gap:5px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));color:inherit;font:inherit;font-size:13px;padding:0 7px;cursor:pointer}
|
|
347
|
+
.bb-cpk-btn-chip{width:14px;height:14px;border-radius:50%;border:1px solid rgba(128,128,128,.4);flex:none}
|
|
348
|
+
.bb-cpk-btn-chip.none{background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));display:flex;align-items:center;justify-content:center;font-size:10px;opacity:.6}
|
|
349
|
+
.bb-cpk-btn-caret{opacity:.5;font-size:10px}
|
|
350
|
+
/* Toolbar shape: a glyph with the colour as a bar beneath it. */
|
|
351
|
+
.bb-cpk-btn.glyphed{flex-direction:column;gap:1px;min-width:30px;padding:0 6px;border-color:transparent;background:transparent}
|
|
352
|
+
.bb-cpk-btn.glyphed:hover{background:var(--bb-ui-hover,#f1efe8)}
|
|
353
|
+
.bb-cpk-btn-glyph{font-size:13px;line-height:1}
|
|
354
|
+
.bb-cpk-btn-bar{width:16px;height:4px;border-radius:1px;border:0.5px solid rgba(128,128,128,.35)}
|
|
355
|
+
.bb-cpk::backdrop{background:transparent}
|
|
356
|
+
`;
|
|
357
|
+
function openColorPicker({
|
|
358
|
+
anchor,
|
|
359
|
+
value,
|
|
360
|
+
clearLabel,
|
|
361
|
+
onPick
|
|
362
|
+
}) {
|
|
363
|
+
injectStyle("bb-ui-colorpicker-styles", STYLE2);
|
|
364
|
+
const panel = document.createElement("dialog");
|
|
365
|
+
panel.className = "bb-cpk";
|
|
366
|
+
panel.setAttribute("aria-label", "Colour");
|
|
367
|
+
let closed = false;
|
|
368
|
+
const close = () => {
|
|
369
|
+
if (closed) return;
|
|
370
|
+
closed = true;
|
|
371
|
+
window.removeEventListener("scroll", close, true);
|
|
372
|
+
if (panel.open) panel.close();
|
|
373
|
+
panel.remove();
|
|
374
|
+
anchor.focus();
|
|
375
|
+
};
|
|
376
|
+
const pick = (c) => {
|
|
377
|
+
if (c && !COLOR_PALETTE.some((row) => row.includes(c))) remember(c);
|
|
378
|
+
onPick(c);
|
|
379
|
+
close();
|
|
380
|
+
};
|
|
381
|
+
if (clearLabel !== void 0) {
|
|
382
|
+
const none = document.createElement("button");
|
|
383
|
+
none.type = "button";
|
|
384
|
+
none.className = "bb-cpk-none";
|
|
385
|
+
const chip = document.createElement("span");
|
|
386
|
+
chip.className = "bb-cpk-none-chip";
|
|
387
|
+
chip.textContent = "\u29B8";
|
|
388
|
+
none.append(chip, document.createTextNode(clearLabel));
|
|
389
|
+
none.addEventListener("click", () => pick(null));
|
|
390
|
+
panel.append(none);
|
|
391
|
+
}
|
|
392
|
+
const grid = document.createElement("div");
|
|
393
|
+
grid.className = "bb-cpk-grid";
|
|
394
|
+
grid.setAttribute("role", "grid");
|
|
395
|
+
const cells = [];
|
|
396
|
+
COLOR_PALETTE.forEach((row, r2) => {
|
|
397
|
+
const rowCells = [];
|
|
398
|
+
row.forEach((color, c) => {
|
|
399
|
+
const sw = document.createElement("button");
|
|
400
|
+
sw.type = "button";
|
|
401
|
+
sw.className = "bb-cpk-sw";
|
|
402
|
+
sw.style.background = color;
|
|
403
|
+
sw.title = color;
|
|
404
|
+
sw.setAttribute("role", "gridcell");
|
|
405
|
+
sw.setAttribute("aria-label", color);
|
|
406
|
+
sw.tabIndex = -1;
|
|
407
|
+
if (color.toUpperCase() === value?.toUpperCase()) sw.classList.add("on");
|
|
408
|
+
sw.addEventListener("click", () => pick(color));
|
|
409
|
+
sw.addEventListener("keydown", (e) => onGridKey(e, r2, c));
|
|
410
|
+
grid.append(sw);
|
|
411
|
+
rowCells.push(sw);
|
|
412
|
+
});
|
|
413
|
+
cells.push(rowCells);
|
|
414
|
+
});
|
|
415
|
+
panel.append(grid);
|
|
416
|
+
function onGridKey(e, r2, c) {
|
|
417
|
+
const delta = {
|
|
418
|
+
ArrowRight: [0, 1],
|
|
419
|
+
ArrowLeft: [0, -1],
|
|
420
|
+
ArrowDown: [1, 0],
|
|
421
|
+
ArrowUp: [-1, 0]
|
|
422
|
+
};
|
|
423
|
+
const d = delta[e.key];
|
|
424
|
+
if (!d) return;
|
|
425
|
+
e.preventDefault();
|
|
426
|
+
const rows = cells.length;
|
|
427
|
+
const cols = cells[0].length;
|
|
428
|
+
const nr = Math.min(rows - 1, Math.max(0, r2 + d[0]));
|
|
429
|
+
const nc = Math.min(cols - 1, Math.max(0, c + d[1]));
|
|
430
|
+
cells[r2][c].tabIndex = -1;
|
|
431
|
+
const next = cells[nr][nc];
|
|
432
|
+
next.tabIndex = 0;
|
|
433
|
+
next.focus();
|
|
434
|
+
}
|
|
435
|
+
panel.append(
|
|
436
|
+
Object.assign(document.createElement("div"), {
|
|
437
|
+
className: "bb-cpk-cap",
|
|
438
|
+
textContent: "CUSTOM"
|
|
439
|
+
})
|
|
440
|
+
);
|
|
441
|
+
const customRow2 = document.createElement("div");
|
|
442
|
+
customRow2.className = "bb-cpk-row";
|
|
443
|
+
for (const c of customColors) {
|
|
444
|
+
const sw = document.createElement("button");
|
|
445
|
+
sw.type = "button";
|
|
446
|
+
sw.className = "bb-cpk-sw";
|
|
447
|
+
sw.style.background = c;
|
|
448
|
+
sw.title = c;
|
|
449
|
+
sw.setAttribute("aria-label", c);
|
|
450
|
+
if (c.toUpperCase() === value?.toUpperCase()) sw.classList.add("on");
|
|
451
|
+
sw.addEventListener("click", () => pick(c));
|
|
452
|
+
customRow2.append(sw);
|
|
453
|
+
}
|
|
454
|
+
const plus = document.createElement("button");
|
|
455
|
+
plus.type = "button";
|
|
456
|
+
plus.className = "bb-cpk-plus";
|
|
457
|
+
plus.title = "Custom colour";
|
|
458
|
+
plus.append(document.createTextNode("+"));
|
|
459
|
+
const native = document.createElement("input");
|
|
460
|
+
native.type = "color";
|
|
461
|
+
native.value = value && isHex(value) ? value : "#000000";
|
|
462
|
+
native.addEventListener("input", () => pick(native.value.toUpperCase()));
|
|
463
|
+
plus.append(native);
|
|
464
|
+
customRow2.append(plus);
|
|
465
|
+
const hex = document.createElement("input");
|
|
466
|
+
hex.type = "text";
|
|
467
|
+
hex.className = "bb-cpk-hex";
|
|
468
|
+
hex.placeholder = "#RRGGBB";
|
|
469
|
+
hex.spellcheck = false;
|
|
470
|
+
hex.value = value ?? "";
|
|
471
|
+
hex.addEventListener("keydown", (e) => {
|
|
472
|
+
if (e.key !== "Enter") return;
|
|
473
|
+
e.preventDefault();
|
|
474
|
+
const v = hex.value.trim();
|
|
475
|
+
if (isHex(v)) pick(v.toUpperCase());
|
|
476
|
+
});
|
|
477
|
+
customRow2.append(hex);
|
|
478
|
+
panel.append(customRow2);
|
|
479
|
+
document.body.append(panel);
|
|
480
|
+
panel.showModal();
|
|
481
|
+
const r = anchor.getBoundingClientRect();
|
|
482
|
+
placeFloating(panel, { x: r.left, y: r.top, height: r.height });
|
|
483
|
+
panel.addEventListener("close", close);
|
|
484
|
+
panel.addEventListener("pointerdown", (e) => {
|
|
485
|
+
const b = panel.getBoundingClientRect();
|
|
486
|
+
const outside = e.clientX < b.left || e.clientX > b.right || e.clientY < b.top || e.clientY > b.bottom;
|
|
487
|
+
if (outside) close();
|
|
488
|
+
});
|
|
489
|
+
window.addEventListener("scroll", close, true);
|
|
490
|
+
const start = cells.flat().find((el2) => el2.classList.contains("on")) ?? cells[0][0];
|
|
491
|
+
start.tabIndex = 0;
|
|
492
|
+
start.focus();
|
|
493
|
+
return { close };
|
|
494
|
+
}
|
|
495
|
+
function colorButton(o) {
|
|
496
|
+
injectStyle("bb-ui-colorpicker-styles", STYLE2);
|
|
497
|
+
const el2 = document.createElement("button");
|
|
498
|
+
el2.type = "button";
|
|
499
|
+
el2.className = `bb-cpk-btn${o.glyph ? " glyphed" : ""}`;
|
|
500
|
+
el2.title = o.title;
|
|
501
|
+
el2.setAttribute("aria-label", o.title);
|
|
502
|
+
el2.setAttribute("aria-haspopup", "dialog");
|
|
503
|
+
let chip;
|
|
504
|
+
if (o.glyph) {
|
|
505
|
+
const g = document.createElement("span");
|
|
506
|
+
g.className = "bb-cpk-btn-glyph";
|
|
507
|
+
g.innerHTML = o.glyph;
|
|
508
|
+
chip = document.createElement("span");
|
|
509
|
+
chip.className = "bb-cpk-btn-bar";
|
|
510
|
+
el2.append(g, chip);
|
|
511
|
+
} else {
|
|
512
|
+
chip = document.createElement("span");
|
|
513
|
+
chip.className = "bb-cpk-btn-chip";
|
|
514
|
+
el2.append(chip);
|
|
515
|
+
if (o.label) el2.append(document.createTextNode(o.label));
|
|
516
|
+
const caret = document.createElement("span");
|
|
517
|
+
caret.className = "bb-cpk-btn-caret";
|
|
518
|
+
caret.textContent = "\u25BE";
|
|
519
|
+
el2.append(caret);
|
|
520
|
+
}
|
|
521
|
+
function sync() {
|
|
522
|
+
const v = o.value();
|
|
523
|
+
chip.style.background = v ?? "transparent";
|
|
524
|
+
chip.classList.toggle("none", !v && !o.glyph);
|
|
525
|
+
chip.textContent = !v && !o.glyph ? "\u29B8" : "";
|
|
526
|
+
}
|
|
527
|
+
el2.addEventListener("mousedown", (e) => e.preventDefault());
|
|
528
|
+
el2.addEventListener("click", () => {
|
|
529
|
+
openColorPicker({
|
|
530
|
+
anchor: el2,
|
|
531
|
+
value: o.value(),
|
|
532
|
+
clearLabel: o.clearLabel,
|
|
533
|
+
onPick: (c) => {
|
|
534
|
+
o.onPick(c);
|
|
535
|
+
sync();
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
sync();
|
|
540
|
+
return { el: el2, sync };
|
|
541
|
+
}
|
|
542
|
+
|
|
204
543
|
// packages/ui/src/lib/toolbar.ts
|
|
205
544
|
var alignSvg = (spans) => `<svg width="15" height="15" viewBox="0 0 16 16" aria-hidden="true"><g stroke="currentColor" stroke-width="1.6" stroke-linecap="round">` + spans.map(
|
|
206
545
|
([x1, x2], i) => `<line x1="${x1}" y1="${4 + i * 4}" x2="${x2}" y2="${4 + i * 4}"/>`
|
|
@@ -271,9 +610,9 @@ var DEFAULT_ITEMS = {
|
|
|
271
610
|
svg: '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M6 4h8M6 8h8M6 12h8"/><text x="0.5" y="5.6" font-size="5.5" fill="currentColor" stroke="none">1</text><text x="0.5" y="9.6" font-size="5.5" fill="currentColor" stroke="none">2</text><text x="0.5" y="13.6" font-size="5.5" fill="currentColor" stroke="none">3</text></svg>'
|
|
272
611
|
}
|
|
273
612
|
};
|
|
274
|
-
var
|
|
613
|
+
var STYLE3 = `
|
|
275
614
|
.bb-toolbar-wrap{position:relative}
|
|
276
|
-
.bb-toolbar{display:flex;gap:10px;align-items:center;flex-wrap:nowrap;overflow:hidden;padding:6px 8px;font-family:var(--bb-ui-font,system-ui,-apple-system,sans-serif);color:var(--bb-ui-fg,#2c2c2a);background:var(--bb-ui-bg,#fff);border-bottom:1px solid var(--bb-ui-border,#e3e3e0);box-sizing:border-box}
|
|
615
|
+
.bb-toolbar{display:flex;gap:10px;align-items:center;flex-wrap:nowrap;overflow:hidden;padding:6px 8px;font-family:var(--bb-ui-font,system-ui,-apple-system,sans-serif);color:var(--bb-ui-fg,#2c2c2a);background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));border-bottom:1px solid var(--bb-ui-border,#e3e3e0);box-sizing:border-box}
|
|
277
616
|
.bb-toolbar *{box-sizing:border-box}
|
|
278
617
|
.bb-toolbar-group{display:flex;gap:2px;flex:none}
|
|
279
618
|
.bb-toolbar-group+.bb-toolbar-group{padding-left:10px;border-left:1px solid var(--bb-ui-border,#e3e3e0)}
|
|
@@ -284,16 +623,8 @@ var STYLE2 = `
|
|
|
284
623
|
.bb-toolbar-btn:hover{background:var(--bb-ui-hover,#f1efe8)}
|
|
285
624
|
.bb-toolbar-btn.is-active{background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c);border-color:var(--bb-ui-active-border,#b5d4f4)}
|
|
286
625
|
.bb-toolbar-btn:disabled{opacity:.38;cursor:default}
|
|
287
|
-
.bb-toolbar-select{height:30px;border:1px solid var(--bb-ui-border,#e3e3e0);border-radius:6px;background:var(--bb-ui-bg,#fff);color:inherit;font-family:inherit;font-size:13px;padding:0 6px;cursor:pointer}
|
|
626
|
+
.bb-toolbar-select{height:30px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#e3e3e0));border-radius:6px;background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));color:inherit;font-family:inherit;font-size:13px;padding:0 6px;cursor:pointer}
|
|
288
627
|
.bb-toolbar-select:hover{background:var(--bb-ui-hover,#f1efe8)}
|
|
289
|
-
.bb-toolbar-color{position:relative}
|
|
290
|
-
.bb-toolbar-color .bb-color-glyph{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;line-height:1;font-size:13px}
|
|
291
|
-
.bb-toolbar-color .bb-color-bar{width:16px;height:3px;border-radius:1px;background:currentColor}
|
|
292
|
-
.bb-color-pop{position:absolute;z-index:1200;display:grid;grid-template-columns:repeat(8,16px);gap:4px;padding:8px;background:var(--bb-ui-menu-bg,#fff);-webkit-backdrop-filter:var(--bb-ui-pop-filter,none);backdrop-filter:var(--bb-ui-pop-filter,none);border:1px solid var(--bb-ui-pop-border,var(--bb-ui-border,#e3e3e0));border-radius:8px;box-shadow:0 8px 28px rgba(0,0,0,.16)}
|
|
293
|
-
.bb-color-pop[hidden]{display:none}
|
|
294
|
-
.bb-color-swatch{width:16px;height:16px;padding:0;border:1px solid rgba(0,0,0,.18);border-radius:3px;cursor:pointer}
|
|
295
|
-
.bb-color-none{grid-column:1/-1;font:inherit;font-size:12px;padding:3px 0;border:1px solid var(--bb-ui-border,#e3e3e0);border-radius:5px;background:var(--bb-ui-bg,#fff);cursor:pointer}
|
|
296
|
-
.bb-color-none:hover{background:var(--bb-ui-hover,#f1efe8)}
|
|
297
628
|
.bb-i-bold{font-weight:700}.bb-i-italic{font-style:italic}.bb-i-underline{text-decoration:underline}.bb-i-strike{text-decoration:line-through}
|
|
298
629
|
.bb-toolbar-split{display:flex;align-items:center;gap:0}
|
|
299
630
|
.bb-toolbar-split .bb-toolbar-btn{min-width:26px;padding:0 5px}
|
|
@@ -301,7 +632,7 @@ var STYLE2 = `
|
|
|
301
632
|
.bb-split-arrow svg{display:block}
|
|
302
633
|
.bb-split-pop{position:absolute;z-index:1200;display:grid;grid-template-columns:repeat(3,auto);gap:8px;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);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)}
|
|
303
634
|
.bb-split-pop[hidden]{display:none}
|
|
304
|
-
.bb-split-card{display:flex;flex-direction:column;gap:6px;width:76px;padding:9px 8px;border:1px solid var(--bb-ui-border,#e3e3e0);border-radius:6px;background:transparent;cursor:pointer;font-family:inherit}
|
|
635
|
+
.bb-split-card{display:flex;flex-direction:column;gap:6px;width:76px;padding:9px 8px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#e3e3e0));border-radius:6px;background:transparent;cursor:pointer;font-family:inherit}
|
|
305
636
|
.bb-split-card:hover{background:var(--bb-ui-hover,#f1efe8)}
|
|
306
637
|
.bb-split-card.is-selected{background:var(--bb-ui-active-bg,#e6f1fb);border-color:var(--bb-ui-active-border,#b5d4f4)}
|
|
307
638
|
.bb-split-row{display:flex;align-items:center;gap:4px}
|
|
@@ -317,7 +648,7 @@ function defaultToolbarGroups(commands) {
|
|
|
317
648
|
return [rest, aligns].filter((g) => g.length > 0);
|
|
318
649
|
}
|
|
319
650
|
function mountToolbar(host, editor, options = {}) {
|
|
320
|
-
injectStyle("bb-ui-toolbar-styles",
|
|
651
|
+
injectStyle("bb-ui-toolbar-styles", STYLE3);
|
|
321
652
|
const items = { ...DEFAULT_ITEMS, ...options.items ?? {} };
|
|
322
653
|
const groups = options.groups ?? defaultToolbarGroups(editor.commands);
|
|
323
654
|
const wrap = document.createElement("div");
|
|
@@ -360,77 +691,20 @@ function mountToolbar(host, editor, options = {}) {
|
|
|
360
691
|
continue;
|
|
361
692
|
}
|
|
362
693
|
if (typeof entry !== "string" && entry.kind === "color") {
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const bar = document.createElement("span");
|
|
374
|
-
bar.className = "bb-color-bar";
|
|
375
|
-
glyph.appendChild(bar);
|
|
376
|
-
btn2.appendChild(glyph);
|
|
377
|
-
const pop2 = document.createElement("div");
|
|
378
|
-
pop2.className = "bb-color-pop";
|
|
379
|
-
pop2.hidden = true;
|
|
380
|
-
const pick = (color) => {
|
|
381
|
-
entry.onSelect(color);
|
|
382
|
-
pop2.hidden = true;
|
|
383
|
-
editor.focus();
|
|
384
|
-
};
|
|
385
|
-
for (const c of entry.swatches) {
|
|
386
|
-
const sw = document.createElement("button");
|
|
387
|
-
sw.type = "button";
|
|
388
|
-
sw.className = "bb-color-swatch";
|
|
389
|
-
sw.style.background = c;
|
|
390
|
-
sw.title = c;
|
|
391
|
-
sw.addEventListener("mousedown", (e) => e.preventDefault());
|
|
392
|
-
sw.addEventListener("click", () => pick(c));
|
|
393
|
-
pop2.appendChild(sw);
|
|
394
|
-
}
|
|
395
|
-
if (entry.allowNone) {
|
|
396
|
-
const none = document.createElement("button");
|
|
397
|
-
none.type = "button";
|
|
398
|
-
none.className = "bb-color-none";
|
|
399
|
-
none.textContent = "None";
|
|
400
|
-
none.addEventListener("mousedown", (e) => e.preventDefault());
|
|
401
|
-
none.addEventListener("click", () => pick(null));
|
|
402
|
-
pop2.appendChild(none);
|
|
403
|
-
}
|
|
404
|
-
btn2.addEventListener("mousedown", (e) => e.preventDefault());
|
|
405
|
-
btn2.addEventListener("click", () => {
|
|
406
|
-
const open = pop2.hidden;
|
|
407
|
-
wrap.querySelectorAll(".bb-color-pop,.bb-split-pop").forEach((p) => p.hidden = true);
|
|
408
|
-
pop2.hidden = !open;
|
|
409
|
-
if (!pop2.hidden) {
|
|
410
|
-
const wrapRect = wrap.getBoundingClientRect();
|
|
411
|
-
const btnRect = btn2.getBoundingClientRect();
|
|
412
|
-
pop2.style.top = `${btnRect.bottom - wrapRect.top + 4}px`;
|
|
413
|
-
const left = Math.max(
|
|
414
|
-
0,
|
|
415
|
-
Math.min(
|
|
416
|
-
btnRect.left - wrapRect.left,
|
|
417
|
-
wrap.clientWidth - pop2.offsetWidth - 4
|
|
418
|
-
)
|
|
419
|
-
);
|
|
420
|
-
pop2.style.left = `${left}px`;
|
|
421
|
-
const onDoc = (ev) => {
|
|
422
|
-
if (!colorWrap.contains(ev.target) && !pop2.contains(ev.target)) {
|
|
423
|
-
pop2.hidden = true;
|
|
424
|
-
document.removeEventListener("pointerdown", onDoc, true);
|
|
425
|
-
}
|
|
426
|
-
};
|
|
427
|
-
document.addEventListener("pointerdown", onDoc, true);
|
|
694
|
+
const ctl = colorButton({
|
|
695
|
+
title: entry.title,
|
|
696
|
+
glyph: entry.glyph,
|
|
697
|
+
clearLabel: entry.clearLabel,
|
|
698
|
+
// `latest`, not `editor.state`: the toolbar mounts before any
|
|
699
|
+
// document exists, and reading state then throws.
|
|
700
|
+
value: () => latest ? entry.value(latest) : null,
|
|
701
|
+
onPick: (color) => {
|
|
702
|
+
entry.onSelect(color);
|
|
703
|
+
editor.focus();
|
|
428
704
|
}
|
|
429
705
|
});
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
groupEl.appendChild(colorWrap);
|
|
433
|
-
colors.push({ spec: entry, bar });
|
|
706
|
+
groupEl.appendChild(ctl.el);
|
|
707
|
+
colors.push(ctl);
|
|
434
708
|
continue;
|
|
435
709
|
}
|
|
436
710
|
if (typeof entry !== "string" && entry.kind === "split") {
|
|
@@ -492,7 +766,7 @@ function mountToolbar(host, editor, options = {}) {
|
|
|
492
766
|
arrow.addEventListener("mousedown", (e) => e.preventDefault());
|
|
493
767
|
arrow.addEventListener("click", () => {
|
|
494
768
|
const open = pop2.hidden;
|
|
495
|
-
wrap.querySelectorAll(".bb-split-pop
|
|
769
|
+
wrap.querySelectorAll(".bb-split-pop").forEach((p) => p.hidden = true);
|
|
496
770
|
pop2.hidden = !open;
|
|
497
771
|
if (!pop2.hidden) {
|
|
498
772
|
const wrapRect = wrap.getBoundingClientRect();
|
|
@@ -572,11 +846,11 @@ function mountToolbar(host, editor, options = {}) {
|
|
|
572
846
|
while (pop.firstChild) root.insertBefore(pop.firstChild, moreBtn);
|
|
573
847
|
moreBtn.style.display = "none";
|
|
574
848
|
closePop();
|
|
575
|
-
wrap.querySelectorAll(".bb-
|
|
849
|
+
wrap.querySelectorAll(".bb-split-pop").forEach((p) => p.hidden = true);
|
|
576
850
|
if (fits()) return;
|
|
577
851
|
moreBtn.style.display = "";
|
|
578
852
|
const groupEls = Array.from(root.children).filter(
|
|
579
|
-
(
|
|
853
|
+
(el2) => el2.classList.contains("bb-toolbar-group")
|
|
580
854
|
);
|
|
581
855
|
for (let i = groupEls.length - 1; i >= 0 && !fits(); i--) {
|
|
582
856
|
pop.insertBefore(groupEls[i], pop.firstChild);
|
|
@@ -591,17 +865,16 @@ function mountToolbar(host, editor, options = {}) {
|
|
|
591
865
|
layout();
|
|
592
866
|
const refresh = (state) => {
|
|
593
867
|
latest = state;
|
|
594
|
-
for (const { name, el } of buttons) {
|
|
868
|
+
for (const { name, el: el2 } of buttons) {
|
|
595
869
|
const cmd = editor.commands.get(name);
|
|
596
870
|
if (!cmd) continue;
|
|
597
871
|
const active = cmd.isActive?.(state) ?? false;
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
872
|
+
el2.classList.toggle("is-active", active);
|
|
873
|
+
el2.setAttribute("aria-pressed", String(active));
|
|
874
|
+
el2.disabled = cmd.isEnabled ? !cmd.isEnabled(state) : false;
|
|
601
875
|
}
|
|
602
|
-
for (const { spec, el } of selects)
|
|
603
|
-
for (const
|
|
604
|
-
bar.style.background = spec.value(state) ?? "";
|
|
876
|
+
for (const { spec, el: el2 } of selects) el2.value = spec.value(state);
|
|
877
|
+
for (const c of colors) c.sync();
|
|
605
878
|
for (const { spec, cards } of splits) {
|
|
606
879
|
const selected = spec.value(state);
|
|
607
880
|
for (const card of cards)
|
|
@@ -635,6 +908,8 @@ var DEFAULT_LABELS = {
|
|
|
635
908
|
strike: "Strikethrough",
|
|
636
909
|
superscript: "Superscript",
|
|
637
910
|
subscript: "Subscript",
|
|
911
|
+
"small-caps": "Small caps",
|
|
912
|
+
"double-strike": "Double strikethrough",
|
|
638
913
|
"align-left": "Align left",
|
|
639
914
|
"align-center": "Center",
|
|
640
915
|
"align-right": "Align right",
|
|
@@ -651,8 +926,8 @@ var DEFAULT_LABELS = {
|
|
|
651
926
|
redo: "Redo",
|
|
652
927
|
"page-break": "Page break"
|
|
653
928
|
};
|
|
654
|
-
var
|
|
655
|
-
.bb-menubar{display:flex;gap:2px;align-items:center;padding:2px 6px;font-family:var(--bb-ui-font,system-ui,-apple-system,sans-serif);color:var(--bb-ui-fg,#2c2c2a);background:var(--bb-ui-bg,#fff);border-bottom:1px solid var(--bb-ui-border,#e3e3e0);box-sizing:border-box}
|
|
929
|
+
var STYLE4 = `
|
|
930
|
+
.bb-menubar{display:flex;gap:2px;align-items:center;padding:2px 6px;font-family:var(--bb-ui-font,system-ui,-apple-system,sans-serif);color:var(--bb-ui-fg,#2c2c2a);background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));border-bottom:1px solid var(--bb-ui-border,#e3e3e0);box-sizing:border-box}
|
|
656
931
|
.bb-menubar *{box-sizing:border-box}
|
|
657
932
|
.bb-menubar-menu{position:relative}
|
|
658
933
|
.bb-menubar-title{height:28px;padding:0 10px;border:0;border-radius:6px;background:transparent;color:inherit;font:inherit;font-size:13px;cursor:pointer}
|
|
@@ -689,7 +964,7 @@ function defaultMenus(commands) {
|
|
|
689
964
|
return entries.length ? [{ label: "Format", entries }] : [];
|
|
690
965
|
}
|
|
691
966
|
function mountMenubar(host, editor, options = {}) {
|
|
692
|
-
injectStyle("bb-ui-menubar-styles",
|
|
967
|
+
injectStyle("bb-ui-menubar-styles", STYLE4);
|
|
693
968
|
const labels = { ...DEFAULT_LABELS, ...options.labels ?? {} };
|
|
694
969
|
const menus = options.menus ?? defaultMenus(editor.commands);
|
|
695
970
|
const vertical = options.orientation === "vertical";
|
|
@@ -885,18 +1160,18 @@ var DEFAULT_LABELS2 = {
|
|
|
885
1160
|
replaceOne: "Replace",
|
|
886
1161
|
replaceAll: "Replace all"
|
|
887
1162
|
};
|
|
888
|
-
var
|
|
1163
|
+
var STYLE5 = `
|
|
889
1164
|
.bb-find{display:flex;flex-direction:column;gap:8px;min-width:300px}
|
|
890
1165
|
.bb-find *{box-sizing:border-box}
|
|
891
1166
|
.bb-find-row{display:flex;gap:6px;align-items:center}
|
|
892
|
-
.bb-find-input{flex:1 1 auto;height:30px;padding:0 9px;border:1px solid var(--bb-ui-border,#d8d6cf);border-radius:6px;font:inherit;font-size:13px;background:var(--bb-ui-bg,#fff);color:inherit}
|
|
1167
|
+
.bb-find-input{flex:1 1 auto;height:30px;padding:0 9px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;font:inherit;font-size:13px;background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));color:inherit}
|
|
893
1168
|
.bb-find-count{min-width:44px;text-align:center;font-size:12px;opacity:.65;font-variant-numeric:tabular-nums}
|
|
894
|
-
.bb-find-btn{height:30px;min-width:30px;padding:0 10px;border:1px solid var(--bb-ui-border,#d8d6cf);border-radius:6px;background:var(--bb-ui-bg,#fff);color:inherit;font:inherit;font-size:13px;cursor:pointer}
|
|
1169
|
+
.bb-find-btn{height:30px;min-width:30px;padding:0 10px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));color:inherit;font:inherit;font-size:13px;cursor:pointer}
|
|
895
1170
|
.bb-find-btn:hover:not(:disabled){background:var(--bb-ui-hover,#f1efe8)}
|
|
896
1171
|
.bb-find-btn:disabled{opacity:.4;cursor:default}
|
|
897
1172
|
`;
|
|
898
1173
|
function createFindDialog(handle, options = {}) {
|
|
899
|
-
injectStyle("bb-ui-find-styles",
|
|
1174
|
+
injectStyle("bb-ui-find-styles", STYLE5);
|
|
900
1175
|
const find = typeof handle === "function" ? new Proxy({}, {
|
|
901
1176
|
get: (_t, prop) => handle()[prop]
|
|
902
1177
|
}) : handle;
|
|
@@ -997,7 +1272,7 @@ function createFindDialog(handle, options = {}) {
|
|
|
997
1272
|
}
|
|
998
1273
|
|
|
999
1274
|
// packages/ui/src/lib/context-menu.ts
|
|
1000
|
-
var
|
|
1275
|
+
var STYLE6 = `
|
|
1001
1276
|
.bb-ctx{position:fixed;z-index:1200;min-width:208px;padding:4px;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:8px;box-shadow:0 8px 28px rgba(0,0,0,.16);font-family:var(--bb-ui-font,system-ui,-apple-system,sans-serif)}
|
|
1002
1277
|
.bb-ctx *{box-sizing:border-box}
|
|
1003
1278
|
.bb-ctx-item{display:flex;align-items:center;gap:16px;width:100%;height:30px;padding:0 10px;border:0;border-radius:5px;background:transparent;color:inherit;font:inherit;font-size:13px;text-align:left;white-space:nowrap;cursor:pointer}
|
|
@@ -1016,17 +1291,17 @@ function closeCurrent() {
|
|
|
1016
1291
|
}
|
|
1017
1292
|
}
|
|
1018
1293
|
function showContextMenu(entries, at) {
|
|
1019
|
-
injectStyle("bb-ui-contextmenu-styles",
|
|
1294
|
+
injectStyle("bb-ui-contextmenu-styles", STYLE6);
|
|
1020
1295
|
closeCurrent();
|
|
1021
|
-
const
|
|
1022
|
-
|
|
1023
|
-
|
|
1296
|
+
const el2 = document.createElement("div");
|
|
1297
|
+
el2.className = "bb-ctx";
|
|
1298
|
+
el2.setAttribute("role", "menu");
|
|
1024
1299
|
for (const entry of entries) {
|
|
1025
1300
|
if (entry === "separator") {
|
|
1026
1301
|
const sep = document.createElement("div");
|
|
1027
1302
|
sep.className = "bb-ctx-sep";
|
|
1028
1303
|
sep.setAttribute("role", "separator");
|
|
1029
|
-
|
|
1304
|
+
el2.appendChild(sep);
|
|
1030
1305
|
continue;
|
|
1031
1306
|
}
|
|
1032
1307
|
const item = document.createElement("button");
|
|
@@ -1049,22 +1324,22 @@ function showContextMenu(entries, at) {
|
|
|
1049
1324
|
closeCurrent();
|
|
1050
1325
|
entry.run();
|
|
1051
1326
|
});
|
|
1052
|
-
|
|
1327
|
+
el2.appendChild(item);
|
|
1053
1328
|
}
|
|
1054
|
-
document.body.appendChild(
|
|
1055
|
-
const r =
|
|
1329
|
+
document.body.appendChild(el2);
|
|
1330
|
+
const r = el2.getBoundingClientRect();
|
|
1056
1331
|
const pad = 4;
|
|
1057
1332
|
const fitsX = (v) => v >= pad && v + r.width <= window.innerWidth - pad;
|
|
1058
1333
|
const fitsY = (v) => v >= pad && v + r.height <= window.innerHeight - pad;
|
|
1059
1334
|
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));
|
|
1060
1335
|
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));
|
|
1061
|
-
|
|
1062
|
-
|
|
1336
|
+
el2.style.left = `${x}px`;
|
|
1337
|
+
el2.style.top = `${y}px`;
|
|
1063
1338
|
const items = () => Array.from(
|
|
1064
|
-
|
|
1339
|
+
el2.querySelectorAll(".bb-ctx-item:not(:disabled)")
|
|
1065
1340
|
);
|
|
1066
1341
|
const onDown = (e) => {
|
|
1067
|
-
if (!
|
|
1342
|
+
if (!el2.contains(e.target)) closeCurrent();
|
|
1068
1343
|
};
|
|
1069
1344
|
const onKey = (e) => {
|
|
1070
1345
|
if (e.key === "Escape") return closeCurrent();
|
|
@@ -1086,19 +1361,19 @@ function showContextMenu(entries, at) {
|
|
|
1086
1361
|
document.removeEventListener("pointerdown", onDown, true);
|
|
1087
1362
|
document.removeEventListener("keydown", onKey, true);
|
|
1088
1363
|
window.removeEventListener("scroll", onScroll, true);
|
|
1089
|
-
|
|
1364
|
+
el2.remove();
|
|
1090
1365
|
};
|
|
1091
1366
|
items()[0]?.focus();
|
|
1092
1367
|
return { close: closeCurrent };
|
|
1093
1368
|
}
|
|
1094
1369
|
|
|
1095
1370
|
// packages/ui/src/lib/link-panel.ts
|
|
1096
|
-
var
|
|
1371
|
+
var STYLE7 = `
|
|
1097
1372
|
.bb-linkpanel{position:fixed;z-index:1200;width:300px;padding:8px;background:var(--bb-ui-menu-bg,#fff);-webkit-backdrop-filter:var(--bb-ui-pop-filter,none);backdrop-filter:var(--bb-ui-pop-filter,none);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);box-sizing:border-box}
|
|
1098
1373
|
.bb-linkpanel *{box-sizing:border-box}
|
|
1099
1374
|
.bb-linkpanel-row{display:flex;align-items:center;gap:8px}
|
|
1100
1375
|
.bb-linkpanel-form{display:flex;flex-direction:column;gap:8px}
|
|
1101
|
-
.bb-linkpanel-field{display:flex;align-items:center;gap:7px;border:1px solid var(--bb-ui-border,#e3e3e0);border-radius:7px;padding:0 9px;background:var(--bb-ui-bg,#fff)}
|
|
1376
|
+
.bb-linkpanel-field{display:flex;align-items:center;gap:7px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#e3e3e0));border-radius:7px;padding:0 9px;background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff))}
|
|
1102
1377
|
.bb-linkpanel-field:focus-within{border-color:var(--bb-ui-accent,#d85a30)}
|
|
1103
1378
|
.bb-linkpanel-field svg{flex:none;opacity:.55}
|
|
1104
1379
|
.bb-linkpanel-input{flex:1;min-width:0;height:30px;border:0;background:transparent;color:inherit;font:inherit;font-size:13px;outline:none}
|
|
@@ -1140,31 +1415,17 @@ function closeCurrent2() {
|
|
|
1140
1415
|
dispose();
|
|
1141
1416
|
}
|
|
1142
1417
|
}
|
|
1143
|
-
function place(el, anchor) {
|
|
1144
|
-
const r = el.getBoundingClientRect();
|
|
1145
|
-
const pad = 6;
|
|
1146
|
-
const gap = 6;
|
|
1147
|
-
const x = Math.max(
|
|
1148
|
-
pad,
|
|
1149
|
-
Math.min(anchor.x, window.innerWidth - r.width - pad)
|
|
1150
|
-
);
|
|
1151
|
-
const below = anchor.y + anchor.height + gap;
|
|
1152
|
-
const above = anchor.y - gap - r.height;
|
|
1153
|
-
const y = below + r.height <= window.innerHeight - pad || above < pad ? Math.min(below, window.innerHeight - r.height - pad) : above;
|
|
1154
|
-
el.style.left = `${x}px`;
|
|
1155
|
-
el.style.top = `${y}px`;
|
|
1156
|
-
}
|
|
1157
1418
|
function showLinkPanel(opts) {
|
|
1158
|
-
injectStyle("bb-ui-linkpanel-styles",
|
|
1419
|
+
injectStyle("bb-ui-linkpanel-styles", STYLE7);
|
|
1159
1420
|
if (opts.key && current2 && currentKey === opts.key && currentHandle) {
|
|
1160
1421
|
cancelPendingClose();
|
|
1161
1422
|
return currentHandle;
|
|
1162
1423
|
}
|
|
1163
1424
|
closeCurrent2();
|
|
1164
|
-
const
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1425
|
+
const el2 = document.createElement("div");
|
|
1426
|
+
el2.className = "bb-linkpanel";
|
|
1427
|
+
el2.setAttribute("role", "dialog");
|
|
1428
|
+
el2.setAttribute("aria-label", "Link");
|
|
1168
1429
|
const iconBtn = (svg, label, onClick) => {
|
|
1169
1430
|
const b = document.createElement("button");
|
|
1170
1431
|
b.type = "button";
|
|
@@ -1191,7 +1452,7 @@ function showLinkPanel(opts) {
|
|
|
1191
1452
|
return { wrap, input };
|
|
1192
1453
|
};
|
|
1193
1454
|
const renderView = (existing) => {
|
|
1194
|
-
|
|
1455
|
+
el2.textContent = "";
|
|
1195
1456
|
const row = document.createElement("div");
|
|
1196
1457
|
row.className = "bb-linkpanel-row";
|
|
1197
1458
|
const internal = opts.internal;
|
|
@@ -1238,11 +1499,11 @@ function showLinkPanel(opts) {
|
|
|
1238
1499
|
})
|
|
1239
1500
|
);
|
|
1240
1501
|
}
|
|
1241
|
-
|
|
1242
|
-
|
|
1502
|
+
el2.appendChild(row);
|
|
1503
|
+
placeFloating(el2, opts.anchor);
|
|
1243
1504
|
};
|
|
1244
1505
|
const renderForm = (prefill) => {
|
|
1245
|
-
|
|
1506
|
+
el2.textContent = "";
|
|
1246
1507
|
const form = document.createElement("div");
|
|
1247
1508
|
form.className = "bb-linkpanel-form";
|
|
1248
1509
|
const withText = !opts.hasSelection;
|
|
@@ -1283,16 +1544,16 @@ function showLinkPanel(opts) {
|
|
|
1283
1544
|
}
|
|
1284
1545
|
row.appendChild(apply);
|
|
1285
1546
|
form.appendChild(row);
|
|
1286
|
-
|
|
1287
|
-
|
|
1547
|
+
el2.appendChild(form);
|
|
1548
|
+
placeFloating(el2, opts.anchor);
|
|
1288
1549
|
u.input.focus();
|
|
1289
1550
|
u.input.select();
|
|
1290
1551
|
};
|
|
1291
|
-
document.body.appendChild(
|
|
1552
|
+
document.body.appendChild(el2);
|
|
1292
1553
|
if (opts.existing) renderView(opts.existing);
|
|
1293
1554
|
else renderForm(null);
|
|
1294
1555
|
const onDown = (e) => {
|
|
1295
|
-
if (
|
|
1556
|
+
if (el2.contains(e.target)) return;
|
|
1296
1557
|
if (opts.key) {
|
|
1297
1558
|
cancelPendingClose();
|
|
1298
1559
|
pendingClose = setTimeout(closeCurrent2, 80);
|
|
@@ -1313,7 +1574,7 @@ function showLinkPanel(opts) {
|
|
|
1313
1574
|
document.removeEventListener("pointerdown", onDown, true);
|
|
1314
1575
|
document.removeEventListener("keydown", onKey, true);
|
|
1315
1576
|
window.removeEventListener("scroll", onScroll, true);
|
|
1316
|
-
|
|
1577
|
+
el2.remove();
|
|
1317
1578
|
};
|
|
1318
1579
|
current2 = dispose;
|
|
1319
1580
|
currentKey = opts.key ?? null;
|
|
@@ -1328,8 +1589,6 @@ function showLinkPanel(opts) {
|
|
|
1328
1589
|
}
|
|
1329
1590
|
|
|
1330
1591
|
// packages/ui/src/lib/cell-properties.ts
|
|
1331
|
-
var FILL_PRESETS = ["#FCEBEB", "#FAEEDA", "#EAF3DE", "#E6F1FB", "#EEEDFE", "#FBEAF0", "#E1F5EE", "#F1EFE8", "#D3D1C7"];
|
|
1332
|
-
var PEN_COLORS = ["#000000", "#5F5E5A", "#B0B0B0", "#E24B4A", "#185FA5", "#1D9E75", "#BA7517"];
|
|
1333
1592
|
var PT_WIDTHS = [0.5, 0.75, 1, 1.5, 2.25, 3];
|
|
1334
1593
|
var STYLES = [
|
|
1335
1594
|
{ key: "solid", label: "Solid" },
|
|
@@ -1343,43 +1602,53 @@ var VALIGNS = [
|
|
|
1343
1602
|
{ key: "bottom", label: "Bottom" }
|
|
1344
1603
|
];
|
|
1345
1604
|
var PRESETS = [
|
|
1346
|
-
{
|
|
1605
|
+
{
|
|
1606
|
+
key: "all",
|
|
1607
|
+
label: "All borders",
|
|
1608
|
+
sides: [1, 1, 1, 1, 1, 1],
|
|
1609
|
+
inside: false
|
|
1610
|
+
},
|
|
1347
1611
|
{ key: "none", label: "No border", sides: [0, 0, 0, 0, 0, 0], inside: false },
|
|
1348
|
-
{
|
|
1612
|
+
{
|
|
1613
|
+
key: "outside",
|
|
1614
|
+
label: "Outside",
|
|
1615
|
+
sides: [1, 1, 1, 1, 0, 0],
|
|
1616
|
+
inside: false
|
|
1617
|
+
},
|
|
1349
1618
|
{ key: "inside", label: "Inside", sides: [0, 0, 0, 0, 1, 1], inside: true },
|
|
1350
1619
|
{ key: "top", label: "Top", sides: [1, 0, 0, 0, 0, 0], inside: false },
|
|
1351
1620
|
{ key: "bottom", label: "Bottom", sides: [0, 0, 1, 0, 0, 0], inside: false },
|
|
1352
1621
|
{ key: "left", label: "Left", sides: [0, 0, 0, 1, 0, 0], inside: false },
|
|
1353
1622
|
{ key: "right", label: "Right", sides: [0, 1, 0, 0, 0, 0], inside: false },
|
|
1354
|
-
{
|
|
1355
|
-
|
|
1623
|
+
{
|
|
1624
|
+
key: "insideH",
|
|
1625
|
+
label: "Inside horizontal",
|
|
1626
|
+
sides: [0, 0, 0, 0, 1, 0],
|
|
1627
|
+
inside: true
|
|
1628
|
+
},
|
|
1629
|
+
{
|
|
1630
|
+
key: "insideV",
|
|
1631
|
+
label: "Inside vertical",
|
|
1632
|
+
sides: [0, 0, 0, 0, 0, 1],
|
|
1633
|
+
inside: true
|
|
1634
|
+
}
|
|
1356
1635
|
];
|
|
1357
|
-
var
|
|
1636
|
+
var STYLE8 = `
|
|
1358
1637
|
.bb-cp{display:flex;flex-direction:column;gap:16px;min-width:320px;color:var(--bb-ui-fg,#2c2c2a)}
|
|
1359
1638
|
.bb-cp *{box-sizing:border-box}
|
|
1360
1639
|
.bb-cp-label{font-size:12px;opacity:.7;margin-bottom:8px}
|
|
1361
|
-
.bb-cp-
|
|
1362
|
-
.bb-cp-swatch{width:26px;height:26px;border-radius:6px;border:0.5px solid var(--bb-ui-border,#d8d6cf);padding:0;cursor:pointer}
|
|
1363
|
-
.bb-cp-swatch.on{box-shadow:0 0 0 2px var(--bb-ui-active-fg,#0c447c)}
|
|
1364
|
-
.bb-cp-none{display:flex;align-items:center;justify-content:center;background:var(--bb-ui-bg,#fff);font-size:15px;color:#b4b2a9}
|
|
1365
|
-
.bb-cp-hexrow{display:flex;align-items:center;gap:8px;margin-top:10px}
|
|
1366
|
-
.bb-cp-hexpreview{width:26px;height:26px;border-radius:6px;border:0.5px solid var(--bb-ui-border,#d8d6cf);flex:none}
|
|
1367
|
-
.bb-cp-hex{height:30px;width:120px;font-size:13px;padding:0 8px;border:0.5px solid var(--bb-ui-border,#d8d6cf);border-radius:6px;background:var(--bb-ui-bg,#fff);color:inherit}
|
|
1368
|
-
.bb-cp-seg{display:inline-flex;border:0.5px solid var(--bb-ui-border,#d8d6cf);border-radius:6px;overflow:hidden}
|
|
1640
|
+
.bb-cp-seg{display:inline-flex;border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;overflow:hidden}
|
|
1369
1641
|
.bb-cp-segbtn{height:32px;padding:0 16px;border:0;border-right:0.5px solid var(--bb-ui-border,#e3e3e0);background:transparent;color:inherit;font:inherit;font-size:13px;cursor:pointer}
|
|
1370
1642
|
.bb-cp-segbtn:last-child{border-right:0}
|
|
1371
1643
|
.bb-cp-segbtn.on{background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c)}
|
|
1372
1644
|
.bb-cp-presets{display:grid;grid-template-columns:repeat(5,1fr);gap:6px;margin-bottom:12px}
|
|
1373
|
-
.bb-cp-preset{display:flex;align-items:center;justify-content:center;height:32px;border:0.5px solid var(--bb-ui-border,#d8d6cf);border-radius:6px;background:var(--bb-ui-bg,#fff);cursor:pointer;padding:0}
|
|
1645
|
+
.bb-cp-preset{display:flex;align-items:center;justify-content:center;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));cursor:pointer;padding:0}
|
|
1374
1646
|
.bb-cp-preset.on{border-color:var(--bb-ui-active-border,#7fb2ec);background:var(--bb-ui-active-bg,#e6f1fb)}
|
|
1375
1647
|
.bb-cp-preset:disabled{opacity:.35;cursor:default}
|
|
1376
1648
|
.bb-cp-penrow{display:flex;gap:10px;margin-bottom:10px}
|
|
1377
|
-
.bb-cp-select{flex:1;height:32px;border:0.5px solid var(--bb-ui-border,#d8d6cf);border-radius:6px;background:var(--bb-ui-bg,#fff);color:inherit;font:inherit;font-size:13px;padding:0 8px}
|
|
1378
|
-
.bb-cp-colors{display:flex;gap:7px}
|
|
1379
|
-
.bb-cp-color{width:24px;height:24px;border-radius:6px;border:0.5px solid var(--bb-ui-border,#d8d6cf);padding:0;cursor:pointer}
|
|
1380
|
-
.bb-cp-color.on{box-shadow:0 0 0 2px var(--bb-ui-active-fg,#0c447c)}
|
|
1649
|
+
.bb-cp-select{flex:1;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}
|
|
1381
1650
|
.bb-cp-footer{display:flex;justify-content:flex-end;gap:8px;margin-top:2px}
|
|
1382
|
-
.bb-cp-btn{height:32px;padding:0 16px;border:0.5px solid var(--bb-ui-border,#d8d6cf);border-radius:6px;background:var(--bb-ui-bg,#fff);color:inherit;font:inherit;font-size:13px;cursor:pointer}
|
|
1651
|
+
.bb-cp-btn{height:32px;padding:0 16px;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}
|
|
1383
1652
|
.bb-cp-primary{background:var(--bb-ui-active-bg,#e6f1fb);border-color:var(--bb-ui-active-border,#b5d4f4);color:var(--bb-ui-active-fg,#0c447c)}
|
|
1384
1653
|
`;
|
|
1385
1654
|
var ACTIVE = "#378ADD";
|
|
@@ -1394,8 +1663,12 @@ var section = (label) => {
|
|
|
1394
1663
|
sec.appendChild(l);
|
|
1395
1664
|
return sec;
|
|
1396
1665
|
};
|
|
1397
|
-
function openCellProperties({
|
|
1398
|
-
|
|
1666
|
+
function openCellProperties({
|
|
1667
|
+
initial,
|
|
1668
|
+
singleCell,
|
|
1669
|
+
onApply
|
|
1670
|
+
}) {
|
|
1671
|
+
injectStyle("bb-ui-cellprops-styles", STYLE8);
|
|
1399
1672
|
let background = initial.background;
|
|
1400
1673
|
let vAlign = initial.vAlign;
|
|
1401
1674
|
let penWidthPt = 1;
|
|
@@ -1405,48 +1678,16 @@ function openCellProperties({ initial, singleCell, onApply }) {
|
|
|
1405
1678
|
const root = document.createElement("div");
|
|
1406
1679
|
root.className = "bb-cp";
|
|
1407
1680
|
const fill = section("Fill");
|
|
1408
|
-
const
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
});
|
|
1416
|
-
swatches.appendChild(el);
|
|
1417
|
-
swatchEls.push({ el, color });
|
|
1418
|
-
};
|
|
1419
|
-
const none = document.createElement("button");
|
|
1420
|
-
none.type = "button";
|
|
1421
|
-
none.className = "bb-cp-swatch bb-cp-none";
|
|
1422
|
-
none.title = "No fill";
|
|
1423
|
-
none.textContent = "\u29B8";
|
|
1424
|
-
addSwatch(none, null);
|
|
1425
|
-
for (const color of FILL_PRESETS) {
|
|
1426
|
-
const sw = document.createElement("button");
|
|
1427
|
-
sw.type = "button";
|
|
1428
|
-
sw.className = "bb-cp-swatch";
|
|
1429
|
-
sw.style.background = color;
|
|
1430
|
-
sw.title = color;
|
|
1431
|
-
addSwatch(sw, color);
|
|
1432
|
-
}
|
|
1433
|
-
const hexRow = document.createElement("div");
|
|
1434
|
-
hexRow.className = "bb-cp-hexrow";
|
|
1435
|
-
const hexPreview = document.createElement("span");
|
|
1436
|
-
hexPreview.className = "bb-cp-hexpreview";
|
|
1437
|
-
const hex = document.createElement("input");
|
|
1438
|
-
hex.type = "text";
|
|
1439
|
-
hex.className = "bb-cp-hex";
|
|
1440
|
-
hex.placeholder = "#RRGGBB";
|
|
1441
|
-
hex.addEventListener("input", () => {
|
|
1442
|
-
const v = hex.value.trim();
|
|
1443
|
-
if (/^#[0-9a-fA-F]{6}$/.test(v)) {
|
|
1444
|
-
background = v;
|
|
1445
|
-
syncFill();
|
|
1681
|
+
const fillBtn = colorButton({
|
|
1682
|
+
title: "Cell fill",
|
|
1683
|
+
label: "Fill",
|
|
1684
|
+
clearLabel: "No fill",
|
|
1685
|
+
value: () => background,
|
|
1686
|
+
onPick: (c) => {
|
|
1687
|
+
background = c;
|
|
1446
1688
|
}
|
|
1447
1689
|
});
|
|
1448
|
-
|
|
1449
|
-
fill.append(swatches, hexRow);
|
|
1690
|
+
fill.append(fillBtn.el);
|
|
1450
1691
|
const valign = section("Vertical alignment");
|
|
1451
1692
|
const seg = document.createElement("div");
|
|
1452
1693
|
seg.className = "bb-cp-seg";
|
|
@@ -1476,7 +1717,10 @@ function openCellProperties({ initial, singleCell, onApply }) {
|
|
|
1476
1717
|
if (pt === penWidthPt) o.selected = true;
|
|
1477
1718
|
widthSel.appendChild(o);
|
|
1478
1719
|
}
|
|
1479
|
-
widthSel.addEventListener(
|
|
1720
|
+
widthSel.addEventListener(
|
|
1721
|
+
"change",
|
|
1722
|
+
() => penWidthPt = Number(widthSel.value)
|
|
1723
|
+
);
|
|
1480
1724
|
const styleSel = document.createElement("select");
|
|
1481
1725
|
styleSel.className = "bb-cp-select";
|
|
1482
1726
|
for (const { key, label } of STYLES) {
|
|
@@ -1485,24 +1729,19 @@ function openCellProperties({ initial, singleCell, onApply }) {
|
|
|
1485
1729
|
o.textContent = label;
|
|
1486
1730
|
styleSel.appendChild(o);
|
|
1487
1731
|
}
|
|
1488
|
-
styleSel.addEventListener(
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
const
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
c
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
syncColors();
|
|
1502
|
-
});
|
|
1503
|
-
colors.appendChild(c);
|
|
1504
|
-
colorEls.push({ el: c, color });
|
|
1505
|
-
}
|
|
1732
|
+
styleSel.addEventListener(
|
|
1733
|
+
"change",
|
|
1734
|
+
() => penStyle = styleSel.value
|
|
1735
|
+
);
|
|
1736
|
+
const penBtn = colorButton({
|
|
1737
|
+
title: "Border colour",
|
|
1738
|
+
label: "Colour",
|
|
1739
|
+
value: () => penColor,
|
|
1740
|
+
onPick: (c) => {
|
|
1741
|
+
if (c) penColor = c;
|
|
1742
|
+
}
|
|
1743
|
+
});
|
|
1744
|
+
penRow.append(widthSel, styleSel, penBtn.el);
|
|
1506
1745
|
const grid = document.createElement("div");
|
|
1507
1746
|
grid.className = "bb-cp-presets";
|
|
1508
1747
|
const presetEls = [];
|
|
@@ -1521,7 +1760,7 @@ function openCellProperties({ initial, singleCell, onApply }) {
|
|
|
1521
1760
|
grid.appendChild(btn);
|
|
1522
1761
|
presetEls.push({ el: btn, key: p.key });
|
|
1523
1762
|
}
|
|
1524
|
-
borders.append(grid, penRow
|
|
1763
|
+
borders.append(grid, penRow);
|
|
1525
1764
|
const footer = document.createElement("div");
|
|
1526
1765
|
footer.className = "bb-cp-footer";
|
|
1527
1766
|
const cancel = document.createElement("button");
|
|
@@ -1534,23 +1773,14 @@ function openCellProperties({ initial, singleCell, onApply }) {
|
|
|
1534
1773
|
apply.textContent = "Apply";
|
|
1535
1774
|
footer.append(cancel, apply);
|
|
1536
1775
|
root.append(fill, valign, borders, footer);
|
|
1537
|
-
function syncFill() {
|
|
1538
|
-
for (const { el, color } of swatchEls) el.classList.toggle("on", color === background);
|
|
1539
|
-
hexPreview.style.background = background ?? "transparent";
|
|
1540
|
-
if (document.activeElement !== hex) hex.value = background ?? "";
|
|
1541
|
-
}
|
|
1542
1776
|
function syncVAlign() {
|
|
1543
1777
|
for (const [key, b] of vaBtns) b.classList.toggle("on", vAlign === key);
|
|
1544
1778
|
}
|
|
1545
|
-
function syncColors() {
|
|
1546
|
-
for (const { el, color } of colorEls) el.classList.toggle("on", color === penColor);
|
|
1547
|
-
}
|
|
1548
1779
|
function syncPresets() {
|
|
1549
|
-
for (const { el, key } of presetEls)
|
|
1780
|
+
for (const { el: el2, key } of presetEls)
|
|
1781
|
+
el2.classList.toggle("on", preset === key);
|
|
1550
1782
|
}
|
|
1551
|
-
syncFill();
|
|
1552
1783
|
syncVAlign();
|
|
1553
|
-
syncColors();
|
|
1554
1784
|
syncPresets();
|
|
1555
1785
|
const dialog = new Dialog({ title: "Cell properties", modal: true });
|
|
1556
1786
|
dialog.setContent(root);
|
|
@@ -1559,7 +1789,12 @@ function openCellProperties({ initial, singleCell, onApply }) {
|
|
|
1559
1789
|
apply.addEventListener("click", () => {
|
|
1560
1790
|
const result = { background, vAlign };
|
|
1561
1791
|
if (preset) {
|
|
1562
|
-
result.border = {
|
|
1792
|
+
result.border = {
|
|
1793
|
+
preset,
|
|
1794
|
+
width: penWidthPt * 96 / 72,
|
|
1795
|
+
style: penStyle,
|
|
1796
|
+
color: penColor
|
|
1797
|
+
};
|
|
1563
1798
|
}
|
|
1564
1799
|
onApply(result);
|
|
1565
1800
|
dialog.close();
|
|
@@ -1568,15 +1803,15 @@ function openCellProperties({ initial, singleCell, onApply }) {
|
|
|
1568
1803
|
}
|
|
1569
1804
|
|
|
1570
1805
|
// packages/ui/src/lib/table-grid.ts
|
|
1571
|
-
var
|
|
1806
|
+
var STYLE9 = `
|
|
1572
1807
|
.bb-grid{display:flex;flex-direction:column;gap:6px;user-select:none}
|
|
1573
1808
|
.bb-grid-cells{display:grid;gap:2px}
|
|
1574
|
-
.bb-grid-cell{width:15px;height:15px;border:1px solid var(--bb-ui-border,#d8d6cf);border-radius:2px;background:var(--bb-ui-bg,#fff);cursor:pointer;padding:0}
|
|
1809
|
+
.bb-grid-cell{width:15px;height:15px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:2px;background:var(--bb-ui-bg,#fff);cursor:pointer;padding:0}
|
|
1575
1810
|
.bb-grid-cell.on{background:var(--bb-ui-active-bg,#e6f1fb);border-color:var(--bb-ui-active-border,#7fb2ec)}
|
|
1576
1811
|
.bb-grid-label{font-size:12px;text-align:center;opacity:.7}
|
|
1577
1812
|
`;
|
|
1578
1813
|
function tableGridPicker(options) {
|
|
1579
|
-
injectStyle("bb-ui-grid-styles",
|
|
1814
|
+
injectStyle("bb-ui-grid-styles", STYLE9);
|
|
1580
1815
|
const maxRows = options.maxRows ?? 8;
|
|
1581
1816
|
const maxCols = options.maxCols ?? 10;
|
|
1582
1817
|
const root = document.createElement("div");
|
|
@@ -1619,7 +1854,7 @@ var cmToPx = (cm) => Math.round(cm * PX_PER_CM);
|
|
|
1619
1854
|
function fmtCm(cm) {
|
|
1620
1855
|
return `${Number(cm.toFixed(3))} cm`;
|
|
1621
1856
|
}
|
|
1622
|
-
var
|
|
1857
|
+
var STYLE10 = `
|
|
1623
1858
|
.bb-ps{display:flex;flex-direction:column;min-width:250px;max-height:min(70vh,460px);overflow-y:auto}
|
|
1624
1859
|
.bb-ps-row{display:flex;align-items:center;gap:11px;width:100%;padding:7px 10px;border:0;border-radius:6px;background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}
|
|
1625
1860
|
.bb-ps-row:hover,.bb-ps-row:focus{background:var(--bb-ui-hover,#f1efe8);outline:none}
|
|
@@ -1634,15 +1869,15 @@ var STYLE9 = `
|
|
|
1634
1869
|
.bb-pd-fields{display:grid;gap:10px 18px}
|
|
1635
1870
|
.bb-pd-field{display:flex;align-items:center;gap:8px}
|
|
1636
1871
|
.bb-pd-label{flex:0 0 74px;font-size:13px}
|
|
1637
|
-
.bb-pd-input{flex:1 1 auto;min-width:0;width:100%;height:30px;padding:0 8px;border:1px solid var(--bb-ui-border,#d8d6cf);border-radius:6px;background:var(--bb-ui-bg,#fff);color:inherit;font:inherit;font-size:13px}
|
|
1872
|
+
.bb-pd-input{flex:1 1 auto;min-width:0;width:100%;height:30px;padding:0 8px;border:1px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));color:inherit;font:inherit;font-size:13px}
|
|
1638
1873
|
.bb-pd-input:focus{outline:2px solid var(--bb-ui-active-border,#7fb2ec);outline-offset:-1px}
|
|
1639
1874
|
.bb-pd-actions{display:flex;justify-content:flex-end;gap:8px}
|
|
1640
1875
|
`;
|
|
1641
1876
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1642
1877
|
function svgEl(name, attrs) {
|
|
1643
|
-
const
|
|
1644
|
-
for (const [k, v] of Object.entries(attrs))
|
|
1645
|
-
return
|
|
1878
|
+
const el2 = document.createElementNS(SVG_NS, name);
|
|
1879
|
+
for (const [k, v] of Object.entries(attrs)) el2.setAttribute(k, String(v));
|
|
1880
|
+
return el2;
|
|
1646
1881
|
}
|
|
1647
1882
|
function pagePreview(ratio) {
|
|
1648
1883
|
const svg = svgEl("svg", { viewBox: "0 0 34 42", class: "bb-ps-icon" });
|
|
@@ -1709,11 +1944,11 @@ function presetRow(icon, name, caption, active, onPick) {
|
|
|
1709
1944
|
return row;
|
|
1710
1945
|
}
|
|
1711
1946
|
function captionLine(text) {
|
|
1712
|
-
const
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
return
|
|
1947
|
+
const el2 = document.createElement("span");
|
|
1948
|
+
el2.className = "bb-ps-dims";
|
|
1949
|
+
el2.style.display = "block";
|
|
1950
|
+
el2.textContent = text;
|
|
1951
|
+
return el2;
|
|
1717
1952
|
}
|
|
1718
1953
|
function customRow(icon, title, description, onPick) {
|
|
1719
1954
|
icon.appendChild(
|
|
@@ -1734,7 +1969,7 @@ function customRow(icon, title, description, onPick) {
|
|
|
1734
1969
|
return presetRow(icon, title, captionLine(description), false, onPick);
|
|
1735
1970
|
}
|
|
1736
1971
|
function pageSizePicker(options) {
|
|
1737
|
-
injectStyle("bb-ui-pagesetup-styles",
|
|
1972
|
+
injectStyle("bb-ui-pagesetup-styles", STYLE10);
|
|
1738
1973
|
const root = document.createElement("div");
|
|
1739
1974
|
root.className = "bb-ps";
|
|
1740
1975
|
root.setAttribute("role", "menu");
|
|
@@ -1763,7 +1998,7 @@ function pageSizePicker(options) {
|
|
|
1763
1998
|
return root;
|
|
1764
1999
|
}
|
|
1765
2000
|
function orientationPicker(options) {
|
|
1766
|
-
injectStyle("bb-ui-pagesetup-styles",
|
|
2001
|
+
injectStyle("bb-ui-pagesetup-styles", STYLE10);
|
|
1767
2002
|
const root = document.createElement("div");
|
|
1768
2003
|
root.className = "bb-ps";
|
|
1769
2004
|
root.setAttribute("role", "menu");
|
|
@@ -1786,7 +2021,7 @@ function orientationPicker(options) {
|
|
|
1786
2021
|
return root;
|
|
1787
2022
|
}
|
|
1788
2023
|
function marginPresetPicker(options) {
|
|
1789
|
-
injectStyle("bb-ui-pagesetup-styles",
|
|
2024
|
+
injectStyle("bb-ui-pagesetup-styles", STYLE10);
|
|
1790
2025
|
const root = document.createElement("div");
|
|
1791
2026
|
root.className = "bb-ps";
|
|
1792
2027
|
root.setAttribute("role", "menu");
|
|
@@ -1842,8 +2077,8 @@ function cmField(label, valuePx, min) {
|
|
|
1842
2077
|
return { row, input };
|
|
1843
2078
|
}
|
|
1844
2079
|
function dialogActions() {
|
|
1845
|
-
const
|
|
1846
|
-
|
|
2080
|
+
const el2 = document.createElement("div");
|
|
2081
|
+
el2.className = "bb-pd-actions";
|
|
1847
2082
|
const cancel = document.createElement("button");
|
|
1848
2083
|
cancel.type = "button";
|
|
1849
2084
|
cancel.className = "bb-prompt-btn";
|
|
@@ -1853,15 +2088,15 @@ function dialogActions() {
|
|
|
1853
2088
|
ok.className = "bb-prompt-btn";
|
|
1854
2089
|
ok.dataset["primary"] = "true";
|
|
1855
2090
|
ok.textContent = "OK";
|
|
1856
|
-
|
|
1857
|
-
return { el, ok, cancel };
|
|
2091
|
+
el2.append(cancel, ok);
|
|
2092
|
+
return { el: el2, ok, cancel };
|
|
1858
2093
|
}
|
|
1859
2094
|
function readPx(input, fallbackPx) {
|
|
1860
2095
|
const n = Number(input.value);
|
|
1861
2096
|
return Number.isFinite(n) && n > 0 ? cmToPx(n) : fallbackPx;
|
|
1862
2097
|
}
|
|
1863
2098
|
function openPageSizeDialog(options) {
|
|
1864
|
-
injectStyle("bb-ui-pagesetup-styles",
|
|
2099
|
+
injectStyle("bb-ui-pagesetup-styles", STYLE10);
|
|
1865
2100
|
const dialog = new Dialog({ title: "Paper size", modal: true });
|
|
1866
2101
|
const form = document.createElement("form");
|
|
1867
2102
|
form.className = "bb-pd";
|
|
@@ -1888,7 +2123,7 @@ function openPageSizeDialog(options) {
|
|
|
1888
2123
|
width.input.select();
|
|
1889
2124
|
}
|
|
1890
2125
|
function openMarginsDialog(options) {
|
|
1891
|
-
injectStyle("bb-ui-pagesetup-styles",
|
|
2126
|
+
injectStyle("bb-ui-pagesetup-styles", STYLE10);
|
|
1892
2127
|
const dialog = new Dialog({ title: "Margins", modal: true });
|
|
1893
2128
|
const form = document.createElement("form");
|
|
1894
2129
|
form.className = "bb-pd";
|
|
@@ -1923,10 +2158,341 @@ function openMarginsDialog(options) {
|
|
|
1923
2158
|
top.input.focus();
|
|
1924
2159
|
top.input.select();
|
|
1925
2160
|
}
|
|
2161
|
+
|
|
2162
|
+
// packages/ui/src/lib/font-dialog.ts
|
|
2163
|
+
var twipsToPt = (tw) => tw / 20;
|
|
2164
|
+
var ptToTwips = (pt) => Math.round(pt * 20);
|
|
2165
|
+
var halfToPt = (hp) => hp / 2;
|
|
2166
|
+
var ptToHalf = (pt) => Math.round(pt * 2);
|
|
2167
|
+
var SCALE_PRESETS = [200, 150, 100, 90, 80, 66, 50, 33];
|
|
2168
|
+
var SUPERSUB_SCALE = 0.66;
|
|
2169
|
+
var STYLE11 = `
|
|
2170
|
+
.bb-fd{display:flex;flex-direction:column;gap:15px;min-width:396px;max-width:430px;color:var(--bb-ui-fg,#2c2c2a)}
|
|
2171
|
+
.bb-fd *{box-sizing:border-box}
|
|
2172
|
+
/* A segmented control, not a "tab joined to its pane": that pattern needs the
|
|
2173
|
+
active tab's background to equal the pane's, and this dialog floats on
|
|
2174
|
+
frosted glass whose colour the widget cannot know. Same shape cell-properties
|
|
2175
|
+
already uses, so the two dialogs read as one product. */
|
|
2176
|
+
.bb-fd-tabs{display:inline-flex;border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;overflow:hidden;align-self:flex-start}
|
|
2177
|
+
.bb-fd-tab{height:30px;padding:0 18px;border:0;border-right:0.5px solid var(--bb-ui-border,#e3e3e0);background:transparent;color:inherit;opacity:.65;font:inherit;font-size:13px;cursor:pointer}
|
|
2178
|
+
.bb-fd-tab:last-child{border-right:0}
|
|
2179
|
+
.bb-fd-tab[aria-selected="true"]{background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c);opacity:1}
|
|
2180
|
+
.bb-fd-pane{display:flex;flex-direction:column;gap:13px}
|
|
2181
|
+
/* A class-level display beats the UA's [hidden]{display:none}; without this
|
|
2182
|
+
both tabs render at once. */
|
|
2183
|
+
.bb-fd-pane[hidden]{display:none}
|
|
2184
|
+
.bb-fd-lbl{font-size:12px;opacity:.7;margin-bottom:5px}
|
|
2185
|
+
.bb-fd-sec{font-size:12px;opacity:.7;margin-bottom:9px}
|
|
2186
|
+
.bb-fd-grid{display:grid;gap:10px}
|
|
2187
|
+
.bb-fd-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}
|
|
2188
|
+
.bb-fd-row{display:grid;grid-template-columns:96px 1fr 88px;gap:10px;align-items:center;margin-bottom:10px}
|
|
2189
|
+
.bb-fd-row label{font-size:13px}
|
|
2190
|
+
.bb-fd-state{font-size:12px;color:var(--bb-ui-active-fg,#0c447c)}
|
|
2191
|
+
.bb-fd-state.off{color:inherit;opacity:.5}
|
|
2192
|
+
.bb-fd-seg{display:inline-flex;border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:6px;overflow:hidden;height:32px}
|
|
2193
|
+
.bb-fd-segbtn{width:40px;border:0;border-right:0.5px solid var(--bb-ui-border,#e3e3e0);background:transparent;color:inherit;font:inherit;font-size:13px;cursor:pointer}
|
|
2194
|
+
.bb-fd-segbtn:last-child{border-right:0}
|
|
2195
|
+
.bb-fd-segbtn[aria-pressed="true"]{background:var(--bb-ui-active-bg,#e6f1fb);color:var(--bb-ui-active-fg,#0c447c)}
|
|
2196
|
+
.bb-fd-segbtn[aria-pressed="mixed"]{background:repeating-linear-gradient(135deg,transparent 0 4px,var(--bb-ui-active-bg,#e6f1fb) 4px 8px)}
|
|
2197
|
+
.bb-fd-swatch-custom{background:conic-gradient(#c0392b,#ba7517,#1d9e75,#185fa5,#7f77dd,#c0392b)}
|
|
2198
|
+
.bb-fd-swatch-custom::-webkit-color-swatch-wrapper{padding:0}
|
|
2199
|
+
.bb-fd-swatch-custom::-webkit-color-swatch{border:0;border-radius:5px;opacity:0}
|
|
2200
|
+
.bb-fd-eff{display:grid;grid-template-columns:1fr 1fr;gap:8px 14px}
|
|
2201
|
+
.bb-fd-cb{display:flex;align-items:center;gap:7px;font-size:13px;cursor:pointer}
|
|
2202
|
+
.bb-fd-prev{border:0.5px solid var(--bb-ui-control-border,var(--bb-ui-border,#d8d6cf));border-radius:8px;background:var(--bb-ui-control-bg,var(--bb-ui-bg,#fff));padding:13px 14px;overflow:hidden}
|
|
2203
|
+
.bb-fd-prev-cap{font-size:11px;opacity:.55;margin-bottom:9px;text-align:center}
|
|
2204
|
+
/* The surrounding sentence stays at a fixed size and weight \u2014 it is the ruler
|
|
2205
|
+
the sample is read against, so it must not move when the sample does. */
|
|
2206
|
+
.bb-fd-prev-line{font-size:15px;line-height:2;text-align:center}
|
|
2207
|
+
.bb-fd-prev-txt{display:inline-block}
|
|
2208
|
+
.bb-fd-dim{opacity:.4}
|
|
2209
|
+
.bb-fd-note{font-size:11px;opacity:.55;margin-top:5px}
|
|
2210
|
+
.bb-fd-foot{display:flex;justify-content:flex-end;gap:8px}
|
|
2211
|
+
.bb-fd-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}
|
|
2212
|
+
.bb-fd-btn.primary{background:var(--bb-ui-active-bg,#e6f1fb);border-color:var(--bb-ui-active-border,#7fb2ec);color:var(--bb-ui-active-fg,#0c447c)}
|
|
2213
|
+
`;
|
|
2214
|
+
function el(tag, cls, text) {
|
|
2215
|
+
const n = document.createElement(tag);
|
|
2216
|
+
if (cls) n.className = cls;
|
|
2217
|
+
if (text) n.textContent = text;
|
|
2218
|
+
return n;
|
|
2219
|
+
}
|
|
2220
|
+
function select(options, value) {
|
|
2221
|
+
const s = el("select", "bb-fd-ctl");
|
|
2222
|
+
for (const [v, label] of options) {
|
|
2223
|
+
const o = document.createElement("option");
|
|
2224
|
+
o.value = v;
|
|
2225
|
+
o.textContent = label;
|
|
2226
|
+
s.append(o);
|
|
2227
|
+
}
|
|
2228
|
+
s.value = value;
|
|
2229
|
+
return s;
|
|
2230
|
+
}
|
|
2231
|
+
function checkbox(label, on) {
|
|
2232
|
+
const wrap = el("label", "bb-fd-cb");
|
|
2233
|
+
const input = document.createElement("input");
|
|
2234
|
+
input.type = "checkbox";
|
|
2235
|
+
input.checked = on === true;
|
|
2236
|
+
input.indeterminate = on === void 0;
|
|
2237
|
+
input.addEventListener("change", () => {
|
|
2238
|
+
input.indeterminate = false;
|
|
2239
|
+
});
|
|
2240
|
+
wrap.append(input, document.createTextNode(label));
|
|
2241
|
+
input.wrap = wrap;
|
|
2242
|
+
return input;
|
|
2243
|
+
}
|
|
2244
|
+
var wrapOf = (i) => i.wrap ?? i;
|
|
2245
|
+
function openFontDialog({
|
|
2246
|
+
initial,
|
|
2247
|
+
families,
|
|
2248
|
+
sizes,
|
|
2249
|
+
onApply
|
|
2250
|
+
}) {
|
|
2251
|
+
injectStyle("bb-font-dialog", STYLE11);
|
|
2252
|
+
const dialog = new Dialog({ title: "Font", modal: true });
|
|
2253
|
+
const root = el("div", "bb-fd");
|
|
2254
|
+
const tabs = el("div", "bb-fd-tabs");
|
|
2255
|
+
tabs.setAttribute("role", "tablist");
|
|
2256
|
+
const fontTab = el("button", "bb-fd-tab", "Font");
|
|
2257
|
+
const advTab = el("button", "bb-fd-tab", "Advanced");
|
|
2258
|
+
for (const t of [fontTab, advTab]) {
|
|
2259
|
+
t.type = "button";
|
|
2260
|
+
t.setAttribute("role", "tab");
|
|
2261
|
+
tabs.append(t);
|
|
2262
|
+
}
|
|
2263
|
+
const fontPane = el("div", "bb-fd-pane");
|
|
2264
|
+
const advPane = el("div", "bb-fd-pane");
|
|
2265
|
+
const showTab = (advanced) => {
|
|
2266
|
+
fontTab.setAttribute("aria-selected", String(!advanced));
|
|
2267
|
+
advTab.setAttribute("aria-selected", String(advanced));
|
|
2268
|
+
fontPane.hidden = advanced;
|
|
2269
|
+
advPane.hidden = !advanced;
|
|
2270
|
+
};
|
|
2271
|
+
fontTab.addEventListener("click", () => showTab(false));
|
|
2272
|
+
advTab.addEventListener("click", () => showTab(true));
|
|
2273
|
+
const famList = families.includes(initial.family ?? "") ? families : initial.family ? [initial.family, ...families] : families;
|
|
2274
|
+
const familySel = select(
|
|
2275
|
+
[["", "Font"], ...famList.map((f) => [f, f])],
|
|
2276
|
+
initial.family ?? ""
|
|
2277
|
+
);
|
|
2278
|
+
const sizeSel = select(
|
|
2279
|
+
[["", "Size"], ...sizes.map((n) => [String(n), String(n)])],
|
|
2280
|
+
initial.sizePt == null ? "" : String(initial.sizePt)
|
|
2281
|
+
);
|
|
2282
|
+
const topGrid = el("div", "bb-fd-grid");
|
|
2283
|
+
topGrid.style.gridTemplateColumns = "1fr 100px";
|
|
2284
|
+
const famCell = el("div");
|
|
2285
|
+
famCell.append(el("div", "bb-fd-lbl", "Font"), familySel);
|
|
2286
|
+
const sizeCell = el("div");
|
|
2287
|
+
sizeCell.append(el("div", "bb-fd-lbl", "Size"), sizeSel);
|
|
2288
|
+
topGrid.append(famCell, sizeCell);
|
|
2289
|
+
const seg = el("div", "bb-fd-seg");
|
|
2290
|
+
const mkSeg = (text, on, style) => {
|
|
2291
|
+
const b = el("button", "bb-fd-segbtn", text);
|
|
2292
|
+
b.type = "button";
|
|
2293
|
+
b.setAttribute("aria-pressed", on === void 0 ? "mixed" : String(on));
|
|
2294
|
+
if (style) b.setAttribute("style", style);
|
|
2295
|
+
b.addEventListener("click", () => {
|
|
2296
|
+
b.setAttribute(
|
|
2297
|
+
"aria-pressed",
|
|
2298
|
+
b.getAttribute("aria-pressed") === "true" ? "false" : "true"
|
|
2299
|
+
);
|
|
2300
|
+
paint();
|
|
2301
|
+
});
|
|
2302
|
+
seg.append(b);
|
|
2303
|
+
return b;
|
|
2304
|
+
};
|
|
2305
|
+
const boldBtn = mkSeg("B", initial.bold, "font-weight:600");
|
|
2306
|
+
const italicBtn = mkSeg("I", initial.italic, "font-style:italic");
|
|
2307
|
+
const underBtn = mkSeg("U", initial.underline, "text-decoration:underline");
|
|
2308
|
+
let color = initial.color ?? null;
|
|
2309
|
+
let highlight = initial.highlight ?? null;
|
|
2310
|
+
const colorBtn = colorButton({
|
|
2311
|
+
title: "Text color",
|
|
2312
|
+
label: "Text color",
|
|
2313
|
+
clearLabel: "Automatic",
|
|
2314
|
+
value: () => color,
|
|
2315
|
+
onPick: (c) => {
|
|
2316
|
+
color = c;
|
|
2317
|
+
paint();
|
|
2318
|
+
}
|
|
2319
|
+
});
|
|
2320
|
+
const hlBtn = colorButton({
|
|
2321
|
+
title: "Highlight",
|
|
2322
|
+
label: "Highlight",
|
|
2323
|
+
clearLabel: "No highlight",
|
|
2324
|
+
value: () => highlight,
|
|
2325
|
+
onPick: (c) => {
|
|
2326
|
+
highlight = c;
|
|
2327
|
+
paint();
|
|
2328
|
+
}
|
|
2329
|
+
});
|
|
2330
|
+
const styleRow = el("div", "bb-fd-grid");
|
|
2331
|
+
styleRow.style.gridTemplateColumns = "auto 1fr 1fr";
|
|
2332
|
+
styleRow.style.alignItems = "end";
|
|
2333
|
+
const styleCell = el("div");
|
|
2334
|
+
styleCell.append(el("div", "bb-fd-lbl", "Style"), seg);
|
|
2335
|
+
const colorCell = el("div");
|
|
2336
|
+
colorCell.append(el("div", "bb-fd-lbl", "Colour"), colorBtn.el);
|
|
2337
|
+
const hlCell = el("div");
|
|
2338
|
+
hlCell.append(el("div", "bb-fd-lbl", "Highlight"), hlBtn.el);
|
|
2339
|
+
styleRow.append(styleCell, colorCell, hlCell);
|
|
2340
|
+
const effWrap = el("div");
|
|
2341
|
+
effWrap.append(el("div", "bb-fd-sec", "Effects"));
|
|
2342
|
+
const effGrid = el("div", "bb-fd-eff");
|
|
2343
|
+
const strikeCb = checkbox("Strikethrough", initial.strike);
|
|
2344
|
+
const dstrikeCb = checkbox("Double strikethrough", initial.doubleStrike);
|
|
2345
|
+
const smallCapsCb = checkbox("Small caps", initial.smallCaps);
|
|
2346
|
+
const supCb = checkbox("Superscript", initial.vertAlign === "super");
|
|
2347
|
+
const subCb = checkbox("Subscript", initial.vertAlign === "sub");
|
|
2348
|
+
const exclusive = (a, b) => {
|
|
2349
|
+
a.addEventListener("change", () => {
|
|
2350
|
+
if (a.checked) b.checked = false;
|
|
2351
|
+
paint();
|
|
2352
|
+
});
|
|
2353
|
+
};
|
|
2354
|
+
exclusive(strikeCb, dstrikeCb);
|
|
2355
|
+
exclusive(dstrikeCb, strikeCb);
|
|
2356
|
+
exclusive(supCb, subCb);
|
|
2357
|
+
exclusive(subCb, supCb);
|
|
2358
|
+
smallCapsCb.addEventListener("change", () => paint());
|
|
2359
|
+
effGrid.append(
|
|
2360
|
+
wrapOf(strikeCb),
|
|
2361
|
+
wrapOf(dstrikeCb),
|
|
2362
|
+
wrapOf(supCb),
|
|
2363
|
+
wrapOf(subCb),
|
|
2364
|
+
wrapOf(smallCapsCb)
|
|
2365
|
+
);
|
|
2366
|
+
effWrap.append(effGrid);
|
|
2367
|
+
fontPane.append(topGrid, styleRow, effWrap);
|
|
2368
|
+
const advWrap = el("div");
|
|
2369
|
+
advWrap.append(el("div", "bb-fd-sec", "Character spacing"));
|
|
2370
|
+
const mkRow = (label, control, stateText, dim = false) => {
|
|
2371
|
+
const row = el("div", "bb-fd-row");
|
|
2372
|
+
if (dim) row.classList.add("bb-fd-dim");
|
|
2373
|
+
const l = el("label", void 0, label);
|
|
2374
|
+
const st = el("span", "bb-fd-state off", stateText);
|
|
2375
|
+
row.append(l, control, st);
|
|
2376
|
+
advWrap.append(row);
|
|
2377
|
+
return st;
|
|
2378
|
+
};
|
|
2379
|
+
const scaleSel = select(
|
|
2380
|
+
SCALE_PRESETS.map((n) => [String(n), `${n}%`]),
|
|
2381
|
+
String(initial.scalePercent)
|
|
2382
|
+
);
|
|
2383
|
+
const scaleState = mkRow("Scale", scaleSel, "");
|
|
2384
|
+
const spacingInput = el("input", "bb-fd-ctl");
|
|
2385
|
+
spacingInput.type = "number";
|
|
2386
|
+
spacingInput.step = "0.05";
|
|
2387
|
+
spacingInput.value = String(twipsToPt(initial.letterSpacingTwips));
|
|
2388
|
+
const spacingState = mkRow("Spacing", spacingInput, "");
|
|
2389
|
+
const positionInput = el("input", "bb-fd-ctl");
|
|
2390
|
+
positionInput.type = "number";
|
|
2391
|
+
positionInput.step = "0.5";
|
|
2392
|
+
positionInput.value = String(halfToPt(initial.positionHalfPoints));
|
|
2393
|
+
const positionState = mkRow("Position", positionInput, "");
|
|
2394
|
+
const kernInput = el("input", "bb-fd-ctl");
|
|
2395
|
+
kernInput.type = "number";
|
|
2396
|
+
kernInput.value = "12";
|
|
2397
|
+
kernInput.disabled = true;
|
|
2398
|
+
mkRow("Kerning", kernInput, "not supported", true);
|
|
2399
|
+
const kernNote = el(
|
|
2400
|
+
"div",
|
|
2401
|
+
"bb-fd-note",
|
|
2402
|
+
"Kerning is read from the file but not reproduced when drawing, so it is shown here rather than silently dropped."
|
|
2403
|
+
);
|
|
2404
|
+
advWrap.append(kernNote);
|
|
2405
|
+
advPane.append(advWrap);
|
|
2406
|
+
const prev = el("div", "bb-fd-prev");
|
|
2407
|
+
const prevLine = el("div", "bb-fd-prev-line");
|
|
2408
|
+
const prevTxt = el("span", "bb-fd-prev-txt", "The quick brown fox");
|
|
2409
|
+
prevLine.append(
|
|
2410
|
+
document.createTextNode("Text before "),
|
|
2411
|
+
prevTxt,
|
|
2412
|
+
document.createTextNode(" and text after.")
|
|
2413
|
+
);
|
|
2414
|
+
prev.append(el("div", "bb-fd-prev-cap", "Preview"), prevLine);
|
|
2415
|
+
const num = (i) => {
|
|
2416
|
+
const v = Number(i.value);
|
|
2417
|
+
return Number.isFinite(v) ? v : 0;
|
|
2418
|
+
};
|
|
2419
|
+
const pressed = (b) => b.getAttribute("aria-pressed") === "true";
|
|
2420
|
+
const pressedOrMixed = (b) => b.getAttribute("aria-pressed") === "mixed" ? void 0 : pressed(b);
|
|
2421
|
+
const checkedOrMixed = (i) => i.indeterminate ? void 0 : i.checked;
|
|
2422
|
+
function paint() {
|
|
2423
|
+
const spacingPt = num(spacingInput);
|
|
2424
|
+
const positionPt = num(positionInput);
|
|
2425
|
+
const scale = Number(scaleSel.value) || 100;
|
|
2426
|
+
scaleState.textContent = scale === 100 ? "normal" : `${scale}%`;
|
|
2427
|
+
scaleState.classList.toggle("off", scale === 100);
|
|
2428
|
+
spacingState.textContent = spacingPt === 0 ? "normal" : spacingPt > 0 ? "expanded" : "condensed";
|
|
2429
|
+
spacingState.classList.toggle("off", spacingPt === 0);
|
|
2430
|
+
positionState.textContent = positionPt === 0 ? "on baseline" : positionPt > 0 ? "raised" : "lowered";
|
|
2431
|
+
positionState.classList.toggle("off", positionPt === 0);
|
|
2432
|
+
const deco = [
|
|
2433
|
+
pressed(underBtn) ? "underline" : "",
|
|
2434
|
+
strikeCb.checked || dstrikeCb.checked ? "line-through" : ""
|
|
2435
|
+
].filter(Boolean).join(" ");
|
|
2436
|
+
const s = prevTxt.style;
|
|
2437
|
+
s.fontFamily = familySel.value || "inherit";
|
|
2438
|
+
const shrink = supCb.checked || subCb.checked ? SUPERSUB_SCALE : 1;
|
|
2439
|
+
s.fontSize = sizeSel.value ? `${Number(sizeSel.value) * shrink}pt` : `${15 * shrink}px`;
|
|
2440
|
+
s.fontWeight = pressed(boldBtn) ? "700" : "400";
|
|
2441
|
+
s.fontStyle = pressed(italicBtn) ? "italic" : "normal";
|
|
2442
|
+
s.textDecoration = deco || "none";
|
|
2443
|
+
s.textDecorationStyle = dstrikeCb.checked ? "double" : "solid";
|
|
2444
|
+
s.fontVariant = smallCapsCb.checked ? "small-caps" : "normal";
|
|
2445
|
+
s.color = color ?? "inherit";
|
|
2446
|
+
s.background = highlight ?? "transparent";
|
|
2447
|
+
s.letterSpacing = `${spacingPt}pt`;
|
|
2448
|
+
s.transform = scale === 100 ? "none" : `scaleX(${scale / 100})`;
|
|
2449
|
+
s.verticalAlign = supCb.checked ? "super" : subCb.checked ? "sub" : `${positionPt}pt`;
|
|
2450
|
+
}
|
|
2451
|
+
for (const c of [familySel, sizeSel, scaleSel])
|
|
2452
|
+
c.addEventListener("change", paint);
|
|
2453
|
+
for (const i of [spacingInput, positionInput])
|
|
2454
|
+
i.addEventListener("input", paint);
|
|
2455
|
+
const foot = el("div", "bb-fd-foot");
|
|
2456
|
+
const cancel = el("button", "bb-fd-btn", "Cancel");
|
|
2457
|
+
const ok = el("button", "bb-fd-btn primary", "OK");
|
|
2458
|
+
cancel.type = ok.type = "button";
|
|
2459
|
+
cancel.addEventListener("click", () => dialog.close());
|
|
2460
|
+
ok.addEventListener("click", () => {
|
|
2461
|
+
const spacingPt = num(spacingInput);
|
|
2462
|
+
const positionPt = num(positionInput);
|
|
2463
|
+
const scale = Number(scaleSel.value) || 100;
|
|
2464
|
+
onApply({
|
|
2465
|
+
family: familySel.value || void 0,
|
|
2466
|
+
sizePt: sizeSel.value ? Number(sizeSel.value) : void 0,
|
|
2467
|
+
bold: pressedOrMixed(boldBtn),
|
|
2468
|
+
italic: pressedOrMixed(italicBtn),
|
|
2469
|
+
underline: pressedOrMixed(underBtn),
|
|
2470
|
+
strike: checkedOrMixed(strikeCb),
|
|
2471
|
+
doubleStrike: checkedOrMixed(dstrikeCb),
|
|
2472
|
+
smallCaps: checkedOrMixed(smallCapsCb),
|
|
2473
|
+
vertAlign: supCb.checked ? "super" : subCb.checked ? "sub" : null,
|
|
2474
|
+
color,
|
|
2475
|
+
highlight,
|
|
2476
|
+
scalePercent: scale,
|
|
2477
|
+
letterSpacingTwips: ptToTwips(spacingPt),
|
|
2478
|
+
positionHalfPoints: ptToHalf(positionPt)
|
|
2479
|
+
});
|
|
2480
|
+
dialog.close();
|
|
2481
|
+
});
|
|
2482
|
+
foot.append(cancel, ok);
|
|
2483
|
+
root.append(tabs, fontPane, advPane, prev, foot);
|
|
2484
|
+
dialog.body.append(root);
|
|
2485
|
+
dialog.onClose(() => dialog.destroy());
|
|
2486
|
+
showTab(false);
|
|
2487
|
+
paint();
|
|
2488
|
+
dialog.open();
|
|
2489
|
+
}
|
|
1926
2490
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1927
2491
|
0 && (module.exports = {
|
|
2492
|
+
COLOR_PALETTE,
|
|
1928
2493
|
Dialog,
|
|
1929
2494
|
cmToPx,
|
|
2495
|
+
colorButton,
|
|
1930
2496
|
createFindDialog,
|
|
1931
2497
|
defaultMenus,
|
|
1932
2498
|
defaultToolbarGroups,
|
|
@@ -1934,6 +2500,8 @@ function openMarginsDialog(options) {
|
|
|
1934
2500
|
mountMenubar,
|
|
1935
2501
|
mountToolbar,
|
|
1936
2502
|
openCellProperties,
|
|
2503
|
+
openColorPicker,
|
|
2504
|
+
openFontDialog,
|
|
1937
2505
|
openMarginsDialog,
|
|
1938
2506
|
openPageSizeDialog,
|
|
1939
2507
|
orientationPicker,
|