@shadow-garden/bapbong-ui 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -21,13 +21,20 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  Dialog: () => Dialog,
24
+ cmToPx: () => cmToPx,
24
25
  createFindDialog: () => createFindDialog,
25
26
  defaultMenus: () => defaultMenus,
26
27
  defaultToolbarGroups: () => defaultToolbarGroups,
28
+ marginPresetPicker: () => marginPresetPicker,
27
29
  mountMenubar: () => mountMenubar,
28
30
  mountToolbar: () => mountToolbar,
29
31
  openCellProperties: () => openCellProperties,
32
+ openMarginsDialog: () => openMarginsDialog,
33
+ openPageSizeDialog: () => openPageSizeDialog,
34
+ orientationPicker: () => orientationPicker,
35
+ pageSizePicker: () => pageSizePicker,
30
36
  promptDialog: () => promptDialog,
37
+ pxToCm: () => pxToCm,
31
38
  showContextMenu: () => showContextMenu,
32
39
  showLinkPanel: () => showLinkPanel,
33
40
  tableGridPicker: () => tableGridPicker
@@ -670,7 +677,9 @@ var STYLE3 = `
670
677
  `;
671
678
  function defaultMenus(commands) {
672
679
  const names = [...commands].map((c) => c.name);
673
- const marks = ["bold", "italic", "underline", "strike"].filter((n) => commands.has(n));
680
+ const marks = ["bold", "italic", "underline", "strike"].filter(
681
+ (n) => commands.has(n)
682
+ );
674
683
  const aligns = names.filter((n) => n.startsWith("align-"));
675
684
  const entries = [
676
685
  ...marks.map((command) => ({ command })),
@@ -709,7 +718,8 @@ function mountMenubar(host, editor, options = {}) {
709
718
  p.title.setAttribute("aria-expanded", "true");
710
719
  openIdx = idx;
711
720
  if (latest) refresh(latest);
712
- if (focusFirst) p.dropdown.querySelector(".bb-menu-item")?.focus();
721
+ if (focusFirst)
722
+ p.dropdown.querySelector(".bb-menu-item")?.focus();
713
723
  };
714
724
  const makeRow = (label, opts) => {
715
725
  const item = document.createElement("button");
@@ -753,7 +763,9 @@ function mountMenubar(host, editor, options = {}) {
753
763
  flyout.setAttribute("role", "menu");
754
764
  if ("widget" in entry) {
755
765
  flyout.classList.add("bb-submenu-widget");
756
- flyout.appendChild(entry.widget(() => close()));
766
+ const build = () => flyout.replaceChildren(entry.widget(() => close()));
767
+ wrap.addEventListener("mouseenter", build);
768
+ wrap.addEventListener("focusin", build);
757
769
  } else {
758
770
  buildEntries(entry.submenu, flyout);
759
771
  }
@@ -762,25 +774,37 @@ function mountMenubar(host, editor, options = {}) {
762
774
  } else if ("command" in entry) {
763
775
  const cmd = editor.commands.get(entry.command);
764
776
  if (!cmd) continue;
765
- const { item, check } = makeRow(entry.label ?? labels[entry.command] ?? entry.command, {});
777
+ const { item, check } = makeRow(
778
+ entry.label ?? labels[entry.command] ?? entry.command,
779
+ {}
780
+ );
766
781
  item.setAttribute("role", "menuitemcheckbox");
767
782
  item.addEventListener("click", () => {
768
- if (latest) editor.commands.get(entry.command)?.run(latest, (tr) => editor.dispatch(tr));
783
+ if (latest)
784
+ editor.commands.get(entry.command)?.run(latest, (tr) => editor.dispatch(tr));
769
785
  close();
770
786
  editor.focus();
771
787
  });
772
788
  checks.push({ el: check, active: (s) => cmd.isActive?.(s) ?? false });
773
- if (cmd.isEnabled) enables.push({ el: item, enabled: (s) => cmd.isEnabled(s) });
789
+ if (cmd.isEnabled)
790
+ enables.push({ el: item, enabled: (s) => cmd.isEnabled(s) });
774
791
  container.appendChild(item);
775
792
  } else {
776
- const { item, check } = makeRow(entry.label, { shortcut: entry.shortcut });
777
- item.setAttribute("role", entry.isActive ? "menuitemcheckbox" : "menuitem");
793
+ const { item, check } = makeRow(entry.label, {
794
+ shortcut: entry.shortcut
795
+ });
796
+ item.setAttribute(
797
+ "role",
798
+ entry.isActive ? "menuitemcheckbox" : "menuitem"
799
+ );
778
800
  item.addEventListener("click", () => {
779
801
  entry.run();
780
802
  close();
781
803
  });
782
- if (entry.isActive) checks.push({ el: check, active: () => entry.isActive() });
783
- if (entry.isEnabled) enables.push({ el: item, enabled: () => entry.isEnabled() });
804
+ if (entry.isActive)
805
+ checks.push({ el: check, active: () => entry.isActive() });
806
+ if (entry.isEnabled)
807
+ enables.push({ el: item, enabled: () => entry.isEnabled() });
784
808
  container.appendChild(item);
785
809
  }
786
810
  }
@@ -800,7 +824,10 @@ function mountMenubar(host, editor, options = {}) {
800
824
  dropdown.setAttribute("role", "menu");
801
825
  dropdown.hidden = true;
802
826
  title.addEventListener("mousedown", (e) => e.preventDefault());
803
- title.addEventListener("click", () => openIdx === idx ? close() : open(idx));
827
+ title.addEventListener(
828
+ "click",
829
+ () => openIdx === idx ? close() : open(idx)
830
+ );
804
831
  title.addEventListener("mouseenter", () => {
805
832
  if (openIdx >= 0 && openIdx !== idx) open(idx);
806
833
  });
@@ -868,8 +895,11 @@ var STYLE4 = `
868
895
  .bb-find-btn:hover:not(:disabled){background:var(--bb-ui-hover,#f1efe8)}
869
896
  .bb-find-btn:disabled{opacity:.4;cursor:default}
870
897
  `;
871
- function createFindDialog(find, options = {}) {
898
+ function createFindDialog(handle, options = {}) {
872
899
  injectStyle("bb-ui-find-styles", STYLE4);
900
+ const find = typeof handle === "function" ? new Proxy({}, {
901
+ get: (_t, prop) => handle()[prop]
902
+ }) : handle;
873
903
  const labels = { ...DEFAULT_LABELS2, ...options.labels ?? {} };
874
904
  const root = document.createElement("div");
875
905
  root.className = "bb-find";
@@ -916,8 +946,14 @@ function createFindDialog(find, options = {}) {
916
946
  });
917
947
  prev.addEventListener("click", () => find.prev());
918
948
  next.addEventListener("click", () => find.next());
919
- replaceOne.addEventListener("click", () => find.replaceCurrent(replaceInput.value));
920
- replaceAll.addEventListener("click", () => find.replaceAll(replaceInput.value));
949
+ replaceOne.addEventListener(
950
+ "click",
951
+ () => find.replaceCurrent(replaceInput.value)
952
+ );
953
+ replaceAll.addEventListener(
954
+ "click",
955
+ () => find.replaceAll(replaceInput.value)
956
+ );
921
957
  const off = find.onState((s) => {
922
958
  count.textContent = s.count ? `${s.active}/${s.count}` : "0";
923
959
  for (const b of matchButtons) b.disabled = s.count === 0;
@@ -945,7 +981,8 @@ function createFindDialog(find, options = {}) {
945
981
  openPanel();
946
982
  }
947
983
  };
948
- if (options.shortcut !== false) document.addEventListener("keydown", onHotkey);
984
+ if (options.shortcut !== false)
985
+ document.addEventListener("keydown", onHotkey);
949
986
  return {
950
987
  open: openPanel,
951
988
  close() {
@@ -1546,16 +1583,335 @@ function tableGridPicker(options) {
1546
1583
  root.append(cellsEl, label);
1547
1584
  return root;
1548
1585
  }
1586
+
1587
+ // packages/ui/src/lib/page-setup.ts
1588
+ var PX_PER_CM = 96 / 2.54;
1589
+ var pxToCm = (px) => px / PX_PER_CM;
1590
+ var cmToPx = (cm) => Math.round(cm * PX_PER_CM);
1591
+ function fmtCm(cm) {
1592
+ return `${Number(cm.toFixed(3))} cm`;
1593
+ }
1594
+ var STYLE9 = `
1595
+ .bb-ps{display:flex;flex-direction:column;min-width:250px;max-height:min(70vh,460px);overflow-y:auto}
1596
+ .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}
1597
+ .bb-ps-row:hover,.bb-ps-row:focus{background:var(--bb-ui-hover,#f1efe8);outline:none}
1598
+ .bb-ps-row[aria-checked="true"]{background:var(--bb-ui-active-bg,#e6f1fb)}
1599
+ .bb-ps-icon{flex:none;width:34px;height:42px;display:block}
1600
+ .bb-ps-text{flex:1 1 auto;min-width:0}
1601
+ .bb-ps-name{font-size:13px;font-weight:600;line-height:1.3}
1602
+ .bb-ps-dims{font-size:11.5px;opacity:.68;line-height:1.45;white-space:nowrap}
1603
+ .bb-ps-grid{display:grid;grid-template-columns:auto auto;gap:0 14px;justify-content:start}
1604
+ .bb-ps-sep{height:1px;margin:4px 6px;background:var(--bb-ui-border,#e3e3e0)}
1605
+ .bb-pd{display:flex;flex-direction:column;gap:14px;min-width:300px}
1606
+ .bb-pd-fields{display:grid;gap:10px 18px}
1607
+ .bb-pd-field{display:flex;align-items:center;gap:8px}
1608
+ .bb-pd-label{flex:0 0 74px;font-size:13px}
1609
+ .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}
1610
+ .bb-pd-input:focus{outline:2px solid var(--bb-ui-active-border,#7fb2ec);outline-offset:-1px}
1611
+ .bb-pd-actions{display:flex;justify-content:flex-end;gap:8px}
1612
+ `;
1613
+ var SVG_NS = "http://www.w3.org/2000/svg";
1614
+ function svgEl(name, attrs) {
1615
+ const el = document.createElementNS(SVG_NS, name);
1616
+ for (const [k, v] of Object.entries(attrs)) el.setAttribute(k, String(v));
1617
+ return el;
1618
+ }
1619
+ function pagePreview(ratio) {
1620
+ const svg = svgEl("svg", { viewBox: "0 0 34 42", class: "bb-ps-icon" });
1621
+ const maxW = 26;
1622
+ const maxH = 36;
1623
+ const w = Math.min(maxW, maxH * ratio);
1624
+ const h = w / ratio;
1625
+ svg.appendChild(
1626
+ svgEl("rect", {
1627
+ x: (34 - w) / 2,
1628
+ y: (42 - h) / 2,
1629
+ width: w,
1630
+ height: h,
1631
+ rx: 1,
1632
+ fill: "var(--bb-ui-bg,#fff)",
1633
+ stroke: "var(--bb-ui-fg,#2c2c2a)",
1634
+ "stroke-opacity": 0.45,
1635
+ "stroke-width": 1
1636
+ })
1637
+ );
1638
+ return svg;
1639
+ }
1640
+ function marginPreview(margin, page) {
1641
+ const svg = pagePreview(page.width / page.height);
1642
+ const outline = svg.firstChild;
1643
+ const px = Number(outline.getAttribute("x"));
1644
+ const py = Number(outline.getAttribute("y"));
1645
+ const pw = Number(outline.getAttribute("width"));
1646
+ const ph = Number(outline.getAttribute("height"));
1647
+ const sx = pw / page.width;
1648
+ const sy = ph / page.height;
1649
+ const cw = Math.max(2, pw - (margin.left + margin.right) * sx);
1650
+ const ch = Math.max(2, ph - (margin.top + margin.bottom) * sy);
1651
+ svg.appendChild(
1652
+ svgEl("rect", {
1653
+ x: px + margin.left * sx,
1654
+ y: py + margin.top * sy,
1655
+ width: cw,
1656
+ height: ch,
1657
+ fill: "var(--bb-ui-active-border,#7fb2ec)",
1658
+ "fill-opacity": 0.28,
1659
+ stroke: "var(--bb-ui-active-fg,#0c447c)",
1660
+ "stroke-opacity": 0.55,
1661
+ "stroke-width": 0.8
1662
+ })
1663
+ );
1664
+ return svg;
1665
+ }
1666
+ function presetRow(icon, name, caption, active, onPick) {
1667
+ const row = document.createElement("button");
1668
+ row.type = "button";
1669
+ row.className = "bb-ps-row";
1670
+ row.setAttribute("role", "menuitemradio");
1671
+ row.setAttribute("aria-checked", String(active));
1672
+ const text = document.createElement("span");
1673
+ text.className = "bb-ps-text";
1674
+ const nameEl = document.createElement("span");
1675
+ nameEl.className = "bb-ps-name";
1676
+ nameEl.textContent = name;
1677
+ text.append(nameEl, caption);
1678
+ row.append(icon, text);
1679
+ row.addEventListener("mousedown", (e) => e.preventDefault());
1680
+ row.addEventListener("click", onPick);
1681
+ return row;
1682
+ }
1683
+ function captionLine(text) {
1684
+ const el = document.createElement("span");
1685
+ el.className = "bb-ps-dims";
1686
+ el.style.display = "block";
1687
+ el.textContent = text;
1688
+ return el;
1689
+ }
1690
+ function customRow(icon, title, description, onPick) {
1691
+ icon.appendChild(
1692
+ svgEl("circle", {
1693
+ cx: 26,
1694
+ cy: 34,
1695
+ r: 5.5,
1696
+ fill: "var(--bb-ui-active-fg,#0c447c)"
1697
+ })
1698
+ );
1699
+ const plus = svgEl("path", {
1700
+ d: "M26 31.2v5.6M23.2 34h5.6",
1701
+ stroke: "var(--bb-ui-bg,#fff)",
1702
+ "stroke-width": 1.4,
1703
+ "stroke-linecap": "round"
1704
+ });
1705
+ icon.appendChild(plus);
1706
+ return presetRow(icon, title, captionLine(description), false, onPick);
1707
+ }
1708
+ function pageSizePicker(options) {
1709
+ injectStyle("bb-ui-pagesetup-styles", STYLE9);
1710
+ const root = document.createElement("div");
1711
+ root.className = "bb-ps";
1712
+ root.setAttribute("role", "menu");
1713
+ for (const item of options.items) {
1714
+ root.appendChild(
1715
+ presetRow(
1716
+ pagePreview(item.px[0] / item.px[1]),
1717
+ item.label,
1718
+ captionLine(`${fmtCm(item.cm[0])} x ${fmtCm(item.cm[1])}`),
1719
+ !!item.active,
1720
+ () => options.onPick(item.key)
1721
+ )
1722
+ );
1723
+ }
1724
+ const sep = document.createElement("div");
1725
+ sep.className = "bb-ps-sep";
1726
+ root.appendChild(sep);
1727
+ root.appendChild(
1728
+ customRow(
1729
+ pagePreview(0.773),
1730
+ "Custom page size",
1731
+ "Define custom page size",
1732
+ options.onCustom
1733
+ )
1734
+ );
1735
+ return root;
1736
+ }
1737
+ function orientationPicker(options) {
1738
+ injectStyle("bb-ui-pagesetup-styles", STYLE9);
1739
+ const root = document.createElement("div");
1740
+ root.className = "bb-ps";
1741
+ root.setAttribute("role", "menu");
1742
+ const short = Math.min(options.page.width, options.page.height);
1743
+ const long = Math.max(options.page.width, options.page.height);
1744
+ for (const [key, label, ratio] of [
1745
+ ["portrait", "Portrait", short / long],
1746
+ ["landscape", "Landscape", long / short]
1747
+ ]) {
1748
+ root.appendChild(
1749
+ presetRow(
1750
+ pagePreview(ratio),
1751
+ label,
1752
+ captionLine(""),
1753
+ options.active === key,
1754
+ () => options.onPick(key)
1755
+ )
1756
+ );
1757
+ }
1758
+ return root;
1759
+ }
1760
+ function marginPresetPicker(options) {
1761
+ injectStyle("bb-ui-pagesetup-styles", STYLE9);
1762
+ const root = document.createElement("div");
1763
+ root.className = "bb-ps";
1764
+ root.setAttribute("role", "menu");
1765
+ for (const item of options.items) {
1766
+ const grid = document.createElement("span");
1767
+ grid.className = "bb-ps-dims bb-ps-grid";
1768
+ for (const [label, px] of [
1769
+ ["Top:", item.margin.top],
1770
+ ["Bottom:", item.margin.bottom],
1771
+ ["Left:", item.margin.left],
1772
+ ["Right:", item.margin.right]
1773
+ ]) {
1774
+ const cell = document.createElement("span");
1775
+ cell.textContent = `${label} ${fmtCm(pxToCm(px))}`;
1776
+ grid.appendChild(cell);
1777
+ }
1778
+ root.appendChild(
1779
+ presetRow(
1780
+ marginPreview(item.margin, options.page),
1781
+ item.label,
1782
+ grid,
1783
+ !!item.active,
1784
+ () => options.onPick(item.key)
1785
+ )
1786
+ );
1787
+ }
1788
+ const sep = document.createElement("div");
1789
+ sep.className = "bb-ps-sep";
1790
+ root.appendChild(sep);
1791
+ root.appendChild(
1792
+ customRow(
1793
+ marginPreview({ top: 96, right: 96, bottom: 96, left: 96 }, options.page),
1794
+ "Custom margins",
1795
+ "Define custom margins",
1796
+ options.onCustom
1797
+ )
1798
+ );
1799
+ return root;
1800
+ }
1801
+ function cmField(label, valuePx, min) {
1802
+ const row = document.createElement("label");
1803
+ row.className = "bb-pd-field";
1804
+ const name = document.createElement("span");
1805
+ name.className = "bb-pd-label";
1806
+ name.textContent = label;
1807
+ const input = document.createElement("input");
1808
+ input.className = "bb-pd-input";
1809
+ input.type = "number";
1810
+ input.step = "0.01";
1811
+ input.min = String(Number(pxToCm(min).toFixed(3)));
1812
+ input.value = String(Number(pxToCm(valuePx).toFixed(3)));
1813
+ row.append(name, input);
1814
+ return { row, input };
1815
+ }
1816
+ function dialogActions() {
1817
+ const el = document.createElement("div");
1818
+ el.className = "bb-pd-actions";
1819
+ const cancel = document.createElement("button");
1820
+ cancel.type = "button";
1821
+ cancel.className = "bb-prompt-btn";
1822
+ cancel.textContent = "Cancel";
1823
+ const ok = document.createElement("button");
1824
+ ok.type = "submit";
1825
+ ok.className = "bb-prompt-btn";
1826
+ ok.dataset["primary"] = "true";
1827
+ ok.textContent = "OK";
1828
+ el.append(cancel, ok);
1829
+ return { el, ok, cancel };
1830
+ }
1831
+ function readPx(input, fallbackPx) {
1832
+ const n = Number(input.value);
1833
+ return Number.isFinite(n) && n > 0 ? cmToPx(n) : fallbackPx;
1834
+ }
1835
+ function openPageSizeDialog(options) {
1836
+ injectStyle("bb-ui-pagesetup-styles", STYLE9);
1837
+ const dialog = new Dialog({ title: "Paper size", modal: true });
1838
+ const form = document.createElement("form");
1839
+ form.className = "bb-pd";
1840
+ const fields = document.createElement("div");
1841
+ fields.className = "bb-pd-fields";
1842
+ const width = cmField("Width:", options.initial.width, 96);
1843
+ const height = cmField("Height:", options.initial.height, 96);
1844
+ fields.append(width.row, height.row);
1845
+ const actions = dialogActions();
1846
+ form.append(fields, actions.el);
1847
+ dialog.setContent(form);
1848
+ dialog.onClose(() => dialog.destroy());
1849
+ actions.cancel.addEventListener("click", () => dialog.close());
1850
+ form.addEventListener("submit", (e) => {
1851
+ e.preventDefault();
1852
+ options.onApply({
1853
+ width: readPx(width.input, options.initial.width),
1854
+ height: readPx(height.input, options.initial.height)
1855
+ });
1856
+ dialog.close();
1857
+ });
1858
+ dialog.open();
1859
+ width.input.focus();
1860
+ width.input.select();
1861
+ }
1862
+ function openMarginsDialog(options) {
1863
+ injectStyle("bb-ui-pagesetup-styles", STYLE9);
1864
+ const dialog = new Dialog({ title: "Margins", modal: true });
1865
+ const form = document.createElement("form");
1866
+ form.className = "bb-pd";
1867
+ const fields = document.createElement("div");
1868
+ fields.className = "bb-pd-fields";
1869
+ fields.style.gridTemplateColumns = "1fr 1fr";
1870
+ const top = cmField("Top:", options.initial.top, 0);
1871
+ const left = cmField("Left:", options.initial.left, 0);
1872
+ const bottom = cmField("Bottom:", options.initial.bottom, 0);
1873
+ const right = cmField("Right:", options.initial.right, 0);
1874
+ fields.append(top.row, left.row, bottom.row, right.row);
1875
+ const actions = dialogActions();
1876
+ form.append(fields, actions.el);
1877
+ dialog.setContent(form);
1878
+ dialog.onClose(() => dialog.destroy());
1879
+ actions.cancel.addEventListener("click", () => dialog.close());
1880
+ form.addEventListener("submit", (e) => {
1881
+ e.preventDefault();
1882
+ const px = (input, fallback) => {
1883
+ const n = Number(input.value);
1884
+ return Number.isFinite(n) && n >= 0 ? cmToPx(n) : fallback;
1885
+ };
1886
+ options.onApply({
1887
+ top: px(top.input, options.initial.top),
1888
+ right: px(right.input, options.initial.right),
1889
+ bottom: px(bottom.input, options.initial.bottom),
1890
+ left: px(left.input, options.initial.left)
1891
+ });
1892
+ dialog.close();
1893
+ });
1894
+ dialog.open();
1895
+ top.input.focus();
1896
+ top.input.select();
1897
+ }
1549
1898
  // Annotate the CommonJS export names for ESM import in node:
1550
1899
  0 && (module.exports = {
1551
1900
  Dialog,
1901
+ cmToPx,
1552
1902
  createFindDialog,
1553
1903
  defaultMenus,
1554
1904
  defaultToolbarGroups,
1905
+ marginPresetPicker,
1555
1906
  mountMenubar,
1556
1907
  mountToolbar,
1557
1908
  openCellProperties,
1909
+ openMarginsDialog,
1910
+ openPageSizeDialog,
1911
+ orientationPicker,
1912
+ pageSizePicker,
1558
1913
  promptDialog,
1914
+ pxToCm,
1559
1915
  showContextMenu,
1560
1916
  showLinkPanel,
1561
1917
  tableGridPicker
package/dist/index.d.ts CHANGED
@@ -7,4 +7,5 @@ export * from './lib/context-menu.js';
7
7
  export * from './lib/link-panel.js';
8
8
  export * from './lib/cell-properties.js';
9
9
  export * from './lib/table-grid.js';
10
+ export * from './lib/page-setup.js';
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACrE,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACrE,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -634,7 +634,9 @@ var STYLE3 = `
634
634
  `;
635
635
  function defaultMenus(commands) {
636
636
  const names = [...commands].map((c) => c.name);
637
- const marks = ["bold", "italic", "underline", "strike"].filter((n) => commands.has(n));
637
+ const marks = ["bold", "italic", "underline", "strike"].filter(
638
+ (n) => commands.has(n)
639
+ );
638
640
  const aligns = names.filter((n) => n.startsWith("align-"));
639
641
  const entries = [
640
642
  ...marks.map((command) => ({ command })),
@@ -673,7 +675,8 @@ function mountMenubar(host, editor, options = {}) {
673
675
  p.title.setAttribute("aria-expanded", "true");
674
676
  openIdx = idx;
675
677
  if (latest) refresh(latest);
676
- if (focusFirst) p.dropdown.querySelector(".bb-menu-item")?.focus();
678
+ if (focusFirst)
679
+ p.dropdown.querySelector(".bb-menu-item")?.focus();
677
680
  };
678
681
  const makeRow = (label, opts) => {
679
682
  const item = document.createElement("button");
@@ -717,7 +720,9 @@ function mountMenubar(host, editor, options = {}) {
717
720
  flyout.setAttribute("role", "menu");
718
721
  if ("widget" in entry) {
719
722
  flyout.classList.add("bb-submenu-widget");
720
- flyout.appendChild(entry.widget(() => close()));
723
+ const build = () => flyout.replaceChildren(entry.widget(() => close()));
724
+ wrap.addEventListener("mouseenter", build);
725
+ wrap.addEventListener("focusin", build);
721
726
  } else {
722
727
  buildEntries(entry.submenu, flyout);
723
728
  }
@@ -726,25 +731,37 @@ function mountMenubar(host, editor, options = {}) {
726
731
  } else if ("command" in entry) {
727
732
  const cmd = editor.commands.get(entry.command);
728
733
  if (!cmd) continue;
729
- const { item, check } = makeRow(entry.label ?? labels[entry.command] ?? entry.command, {});
734
+ const { item, check } = makeRow(
735
+ entry.label ?? labels[entry.command] ?? entry.command,
736
+ {}
737
+ );
730
738
  item.setAttribute("role", "menuitemcheckbox");
731
739
  item.addEventListener("click", () => {
732
- if (latest) editor.commands.get(entry.command)?.run(latest, (tr) => editor.dispatch(tr));
740
+ if (latest)
741
+ editor.commands.get(entry.command)?.run(latest, (tr) => editor.dispatch(tr));
733
742
  close();
734
743
  editor.focus();
735
744
  });
736
745
  checks.push({ el: check, active: (s) => cmd.isActive?.(s) ?? false });
737
- if (cmd.isEnabled) enables.push({ el: item, enabled: (s) => cmd.isEnabled(s) });
746
+ if (cmd.isEnabled)
747
+ enables.push({ el: item, enabled: (s) => cmd.isEnabled(s) });
738
748
  container.appendChild(item);
739
749
  } else {
740
- const { item, check } = makeRow(entry.label, { shortcut: entry.shortcut });
741
- item.setAttribute("role", entry.isActive ? "menuitemcheckbox" : "menuitem");
750
+ const { item, check } = makeRow(entry.label, {
751
+ shortcut: entry.shortcut
752
+ });
753
+ item.setAttribute(
754
+ "role",
755
+ entry.isActive ? "menuitemcheckbox" : "menuitem"
756
+ );
742
757
  item.addEventListener("click", () => {
743
758
  entry.run();
744
759
  close();
745
760
  });
746
- if (entry.isActive) checks.push({ el: check, active: () => entry.isActive() });
747
- if (entry.isEnabled) enables.push({ el: item, enabled: () => entry.isEnabled() });
761
+ if (entry.isActive)
762
+ checks.push({ el: check, active: () => entry.isActive() });
763
+ if (entry.isEnabled)
764
+ enables.push({ el: item, enabled: () => entry.isEnabled() });
748
765
  container.appendChild(item);
749
766
  }
750
767
  }
@@ -764,7 +781,10 @@ function mountMenubar(host, editor, options = {}) {
764
781
  dropdown.setAttribute("role", "menu");
765
782
  dropdown.hidden = true;
766
783
  title.addEventListener("mousedown", (e) => e.preventDefault());
767
- title.addEventListener("click", () => openIdx === idx ? close() : open(idx));
784
+ title.addEventListener(
785
+ "click",
786
+ () => openIdx === idx ? close() : open(idx)
787
+ );
768
788
  title.addEventListener("mouseenter", () => {
769
789
  if (openIdx >= 0 && openIdx !== idx) open(idx);
770
790
  });
@@ -832,8 +852,11 @@ var STYLE4 = `
832
852
  .bb-find-btn:hover:not(:disabled){background:var(--bb-ui-hover,#f1efe8)}
833
853
  .bb-find-btn:disabled{opacity:.4;cursor:default}
834
854
  `;
835
- function createFindDialog(find, options = {}) {
855
+ function createFindDialog(handle, options = {}) {
836
856
  injectStyle("bb-ui-find-styles", STYLE4);
857
+ const find = typeof handle === "function" ? new Proxy({}, {
858
+ get: (_t, prop) => handle()[prop]
859
+ }) : handle;
837
860
  const labels = { ...DEFAULT_LABELS2, ...options.labels ?? {} };
838
861
  const root = document.createElement("div");
839
862
  root.className = "bb-find";
@@ -880,8 +903,14 @@ function createFindDialog(find, options = {}) {
880
903
  });
881
904
  prev.addEventListener("click", () => find.prev());
882
905
  next.addEventListener("click", () => find.next());
883
- replaceOne.addEventListener("click", () => find.replaceCurrent(replaceInput.value));
884
- replaceAll.addEventListener("click", () => find.replaceAll(replaceInput.value));
906
+ replaceOne.addEventListener(
907
+ "click",
908
+ () => find.replaceCurrent(replaceInput.value)
909
+ );
910
+ replaceAll.addEventListener(
911
+ "click",
912
+ () => find.replaceAll(replaceInput.value)
913
+ );
885
914
  const off = find.onState((s) => {
886
915
  count.textContent = s.count ? `${s.active}/${s.count}` : "0";
887
916
  for (const b of matchButtons) b.disabled = s.count === 0;
@@ -909,7 +938,8 @@ function createFindDialog(find, options = {}) {
909
938
  openPanel();
910
939
  }
911
940
  };
912
- if (options.shortcut !== false) document.addEventListener("keydown", onHotkey);
941
+ if (options.shortcut !== false)
942
+ document.addEventListener("keydown", onHotkey);
913
943
  return {
914
944
  open: openPanel,
915
945
  close() {
@@ -1510,15 +1540,334 @@ function tableGridPicker(options) {
1510
1540
  root.append(cellsEl, label);
1511
1541
  return root;
1512
1542
  }
1543
+
1544
+ // packages/ui/src/lib/page-setup.ts
1545
+ var PX_PER_CM = 96 / 2.54;
1546
+ var pxToCm = (px) => px / PX_PER_CM;
1547
+ var cmToPx = (cm) => Math.round(cm * PX_PER_CM);
1548
+ function fmtCm(cm) {
1549
+ return `${Number(cm.toFixed(3))} cm`;
1550
+ }
1551
+ var STYLE9 = `
1552
+ .bb-ps{display:flex;flex-direction:column;min-width:250px;max-height:min(70vh,460px);overflow-y:auto}
1553
+ .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}
1554
+ .bb-ps-row:hover,.bb-ps-row:focus{background:var(--bb-ui-hover,#f1efe8);outline:none}
1555
+ .bb-ps-row[aria-checked="true"]{background:var(--bb-ui-active-bg,#e6f1fb)}
1556
+ .bb-ps-icon{flex:none;width:34px;height:42px;display:block}
1557
+ .bb-ps-text{flex:1 1 auto;min-width:0}
1558
+ .bb-ps-name{font-size:13px;font-weight:600;line-height:1.3}
1559
+ .bb-ps-dims{font-size:11.5px;opacity:.68;line-height:1.45;white-space:nowrap}
1560
+ .bb-ps-grid{display:grid;grid-template-columns:auto auto;gap:0 14px;justify-content:start}
1561
+ .bb-ps-sep{height:1px;margin:4px 6px;background:var(--bb-ui-border,#e3e3e0)}
1562
+ .bb-pd{display:flex;flex-direction:column;gap:14px;min-width:300px}
1563
+ .bb-pd-fields{display:grid;gap:10px 18px}
1564
+ .bb-pd-field{display:flex;align-items:center;gap:8px}
1565
+ .bb-pd-label{flex:0 0 74px;font-size:13px}
1566
+ .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}
1567
+ .bb-pd-input:focus{outline:2px solid var(--bb-ui-active-border,#7fb2ec);outline-offset:-1px}
1568
+ .bb-pd-actions{display:flex;justify-content:flex-end;gap:8px}
1569
+ `;
1570
+ var SVG_NS = "http://www.w3.org/2000/svg";
1571
+ function svgEl(name, attrs) {
1572
+ const el = document.createElementNS(SVG_NS, name);
1573
+ for (const [k, v] of Object.entries(attrs)) el.setAttribute(k, String(v));
1574
+ return el;
1575
+ }
1576
+ function pagePreview(ratio) {
1577
+ const svg = svgEl("svg", { viewBox: "0 0 34 42", class: "bb-ps-icon" });
1578
+ const maxW = 26;
1579
+ const maxH = 36;
1580
+ const w = Math.min(maxW, maxH * ratio);
1581
+ const h = w / ratio;
1582
+ svg.appendChild(
1583
+ svgEl("rect", {
1584
+ x: (34 - w) / 2,
1585
+ y: (42 - h) / 2,
1586
+ width: w,
1587
+ height: h,
1588
+ rx: 1,
1589
+ fill: "var(--bb-ui-bg,#fff)",
1590
+ stroke: "var(--bb-ui-fg,#2c2c2a)",
1591
+ "stroke-opacity": 0.45,
1592
+ "stroke-width": 1
1593
+ })
1594
+ );
1595
+ return svg;
1596
+ }
1597
+ function marginPreview(margin, page) {
1598
+ const svg = pagePreview(page.width / page.height);
1599
+ const outline = svg.firstChild;
1600
+ const px = Number(outline.getAttribute("x"));
1601
+ const py = Number(outline.getAttribute("y"));
1602
+ const pw = Number(outline.getAttribute("width"));
1603
+ const ph = Number(outline.getAttribute("height"));
1604
+ const sx = pw / page.width;
1605
+ const sy = ph / page.height;
1606
+ const cw = Math.max(2, pw - (margin.left + margin.right) * sx);
1607
+ const ch = Math.max(2, ph - (margin.top + margin.bottom) * sy);
1608
+ svg.appendChild(
1609
+ svgEl("rect", {
1610
+ x: px + margin.left * sx,
1611
+ y: py + margin.top * sy,
1612
+ width: cw,
1613
+ height: ch,
1614
+ fill: "var(--bb-ui-active-border,#7fb2ec)",
1615
+ "fill-opacity": 0.28,
1616
+ stroke: "var(--bb-ui-active-fg,#0c447c)",
1617
+ "stroke-opacity": 0.55,
1618
+ "stroke-width": 0.8
1619
+ })
1620
+ );
1621
+ return svg;
1622
+ }
1623
+ function presetRow(icon, name, caption, active, onPick) {
1624
+ const row = document.createElement("button");
1625
+ row.type = "button";
1626
+ row.className = "bb-ps-row";
1627
+ row.setAttribute("role", "menuitemradio");
1628
+ row.setAttribute("aria-checked", String(active));
1629
+ const text = document.createElement("span");
1630
+ text.className = "bb-ps-text";
1631
+ const nameEl = document.createElement("span");
1632
+ nameEl.className = "bb-ps-name";
1633
+ nameEl.textContent = name;
1634
+ text.append(nameEl, caption);
1635
+ row.append(icon, text);
1636
+ row.addEventListener("mousedown", (e) => e.preventDefault());
1637
+ row.addEventListener("click", onPick);
1638
+ return row;
1639
+ }
1640
+ function captionLine(text) {
1641
+ const el = document.createElement("span");
1642
+ el.className = "bb-ps-dims";
1643
+ el.style.display = "block";
1644
+ el.textContent = text;
1645
+ return el;
1646
+ }
1647
+ function customRow(icon, title, description, onPick) {
1648
+ icon.appendChild(
1649
+ svgEl("circle", {
1650
+ cx: 26,
1651
+ cy: 34,
1652
+ r: 5.5,
1653
+ fill: "var(--bb-ui-active-fg,#0c447c)"
1654
+ })
1655
+ );
1656
+ const plus = svgEl("path", {
1657
+ d: "M26 31.2v5.6M23.2 34h5.6",
1658
+ stroke: "var(--bb-ui-bg,#fff)",
1659
+ "stroke-width": 1.4,
1660
+ "stroke-linecap": "round"
1661
+ });
1662
+ icon.appendChild(plus);
1663
+ return presetRow(icon, title, captionLine(description), false, onPick);
1664
+ }
1665
+ function pageSizePicker(options) {
1666
+ injectStyle("bb-ui-pagesetup-styles", STYLE9);
1667
+ const root = document.createElement("div");
1668
+ root.className = "bb-ps";
1669
+ root.setAttribute("role", "menu");
1670
+ for (const item of options.items) {
1671
+ root.appendChild(
1672
+ presetRow(
1673
+ pagePreview(item.px[0] / item.px[1]),
1674
+ item.label,
1675
+ captionLine(`${fmtCm(item.cm[0])} x ${fmtCm(item.cm[1])}`),
1676
+ !!item.active,
1677
+ () => options.onPick(item.key)
1678
+ )
1679
+ );
1680
+ }
1681
+ const sep = document.createElement("div");
1682
+ sep.className = "bb-ps-sep";
1683
+ root.appendChild(sep);
1684
+ root.appendChild(
1685
+ customRow(
1686
+ pagePreview(0.773),
1687
+ "Custom page size",
1688
+ "Define custom page size",
1689
+ options.onCustom
1690
+ )
1691
+ );
1692
+ return root;
1693
+ }
1694
+ function orientationPicker(options) {
1695
+ injectStyle("bb-ui-pagesetup-styles", STYLE9);
1696
+ const root = document.createElement("div");
1697
+ root.className = "bb-ps";
1698
+ root.setAttribute("role", "menu");
1699
+ const short = Math.min(options.page.width, options.page.height);
1700
+ const long = Math.max(options.page.width, options.page.height);
1701
+ for (const [key, label, ratio] of [
1702
+ ["portrait", "Portrait", short / long],
1703
+ ["landscape", "Landscape", long / short]
1704
+ ]) {
1705
+ root.appendChild(
1706
+ presetRow(
1707
+ pagePreview(ratio),
1708
+ label,
1709
+ captionLine(""),
1710
+ options.active === key,
1711
+ () => options.onPick(key)
1712
+ )
1713
+ );
1714
+ }
1715
+ return root;
1716
+ }
1717
+ function marginPresetPicker(options) {
1718
+ injectStyle("bb-ui-pagesetup-styles", STYLE9);
1719
+ const root = document.createElement("div");
1720
+ root.className = "bb-ps";
1721
+ root.setAttribute("role", "menu");
1722
+ for (const item of options.items) {
1723
+ const grid = document.createElement("span");
1724
+ grid.className = "bb-ps-dims bb-ps-grid";
1725
+ for (const [label, px] of [
1726
+ ["Top:", item.margin.top],
1727
+ ["Bottom:", item.margin.bottom],
1728
+ ["Left:", item.margin.left],
1729
+ ["Right:", item.margin.right]
1730
+ ]) {
1731
+ const cell = document.createElement("span");
1732
+ cell.textContent = `${label} ${fmtCm(pxToCm(px))}`;
1733
+ grid.appendChild(cell);
1734
+ }
1735
+ root.appendChild(
1736
+ presetRow(
1737
+ marginPreview(item.margin, options.page),
1738
+ item.label,
1739
+ grid,
1740
+ !!item.active,
1741
+ () => options.onPick(item.key)
1742
+ )
1743
+ );
1744
+ }
1745
+ const sep = document.createElement("div");
1746
+ sep.className = "bb-ps-sep";
1747
+ root.appendChild(sep);
1748
+ root.appendChild(
1749
+ customRow(
1750
+ marginPreview({ top: 96, right: 96, bottom: 96, left: 96 }, options.page),
1751
+ "Custom margins",
1752
+ "Define custom margins",
1753
+ options.onCustom
1754
+ )
1755
+ );
1756
+ return root;
1757
+ }
1758
+ function cmField(label, valuePx, min) {
1759
+ const row = document.createElement("label");
1760
+ row.className = "bb-pd-field";
1761
+ const name = document.createElement("span");
1762
+ name.className = "bb-pd-label";
1763
+ name.textContent = label;
1764
+ const input = document.createElement("input");
1765
+ input.className = "bb-pd-input";
1766
+ input.type = "number";
1767
+ input.step = "0.01";
1768
+ input.min = String(Number(pxToCm(min).toFixed(3)));
1769
+ input.value = String(Number(pxToCm(valuePx).toFixed(3)));
1770
+ row.append(name, input);
1771
+ return { row, input };
1772
+ }
1773
+ function dialogActions() {
1774
+ const el = document.createElement("div");
1775
+ el.className = "bb-pd-actions";
1776
+ const cancel = document.createElement("button");
1777
+ cancel.type = "button";
1778
+ cancel.className = "bb-prompt-btn";
1779
+ cancel.textContent = "Cancel";
1780
+ const ok = document.createElement("button");
1781
+ ok.type = "submit";
1782
+ ok.className = "bb-prompt-btn";
1783
+ ok.dataset["primary"] = "true";
1784
+ ok.textContent = "OK";
1785
+ el.append(cancel, ok);
1786
+ return { el, ok, cancel };
1787
+ }
1788
+ function readPx(input, fallbackPx) {
1789
+ const n = Number(input.value);
1790
+ return Number.isFinite(n) && n > 0 ? cmToPx(n) : fallbackPx;
1791
+ }
1792
+ function openPageSizeDialog(options) {
1793
+ injectStyle("bb-ui-pagesetup-styles", STYLE9);
1794
+ const dialog = new Dialog({ title: "Paper size", modal: true });
1795
+ const form = document.createElement("form");
1796
+ form.className = "bb-pd";
1797
+ const fields = document.createElement("div");
1798
+ fields.className = "bb-pd-fields";
1799
+ const width = cmField("Width:", options.initial.width, 96);
1800
+ const height = cmField("Height:", options.initial.height, 96);
1801
+ fields.append(width.row, height.row);
1802
+ const actions = dialogActions();
1803
+ form.append(fields, actions.el);
1804
+ dialog.setContent(form);
1805
+ dialog.onClose(() => dialog.destroy());
1806
+ actions.cancel.addEventListener("click", () => dialog.close());
1807
+ form.addEventListener("submit", (e) => {
1808
+ e.preventDefault();
1809
+ options.onApply({
1810
+ width: readPx(width.input, options.initial.width),
1811
+ height: readPx(height.input, options.initial.height)
1812
+ });
1813
+ dialog.close();
1814
+ });
1815
+ dialog.open();
1816
+ width.input.focus();
1817
+ width.input.select();
1818
+ }
1819
+ function openMarginsDialog(options) {
1820
+ injectStyle("bb-ui-pagesetup-styles", STYLE9);
1821
+ const dialog = new Dialog({ title: "Margins", modal: true });
1822
+ const form = document.createElement("form");
1823
+ form.className = "bb-pd";
1824
+ const fields = document.createElement("div");
1825
+ fields.className = "bb-pd-fields";
1826
+ fields.style.gridTemplateColumns = "1fr 1fr";
1827
+ const top = cmField("Top:", options.initial.top, 0);
1828
+ const left = cmField("Left:", options.initial.left, 0);
1829
+ const bottom = cmField("Bottom:", options.initial.bottom, 0);
1830
+ const right = cmField("Right:", options.initial.right, 0);
1831
+ fields.append(top.row, left.row, bottom.row, right.row);
1832
+ const actions = dialogActions();
1833
+ form.append(fields, actions.el);
1834
+ dialog.setContent(form);
1835
+ dialog.onClose(() => dialog.destroy());
1836
+ actions.cancel.addEventListener("click", () => dialog.close());
1837
+ form.addEventListener("submit", (e) => {
1838
+ e.preventDefault();
1839
+ const px = (input, fallback) => {
1840
+ const n = Number(input.value);
1841
+ return Number.isFinite(n) && n >= 0 ? cmToPx(n) : fallback;
1842
+ };
1843
+ options.onApply({
1844
+ top: px(top.input, options.initial.top),
1845
+ right: px(right.input, options.initial.right),
1846
+ bottom: px(bottom.input, options.initial.bottom),
1847
+ left: px(left.input, options.initial.left)
1848
+ });
1849
+ dialog.close();
1850
+ });
1851
+ dialog.open();
1852
+ top.input.focus();
1853
+ top.input.select();
1854
+ }
1513
1855
  export {
1514
1856
  Dialog,
1857
+ cmToPx,
1515
1858
  createFindDialog,
1516
1859
  defaultMenus,
1517
1860
  defaultToolbarGroups,
1861
+ marginPresetPicker,
1518
1862
  mountMenubar,
1519
1863
  mountToolbar,
1520
1864
  openCellProperties,
1865
+ openMarginsDialog,
1866
+ openPageSizeDialog,
1867
+ orientationPicker,
1868
+ pageSizePicker,
1521
1869
  promptDialog,
1870
+ pxToCm,
1522
1871
  showContextMenu,
1523
1872
  showLinkPanel,
1524
1873
  tableGridPicker
@@ -49,5 +49,5 @@ export interface FindDialogHandle {
49
49
  * closing clears the search so highlights go away. The host (any framework)
50
50
  * just opens it from a menu / shortcut.
51
51
  */
52
- export declare function createFindDialog(find: FindHandle, options?: FindDialogOptions): FindDialogHandle;
52
+ export declare function createFindDialog(handle: FindHandle | (() => FindHandle), options?: FindDialogOptions): FindDialogHandle;
53
53
  //# sourceMappingURL=find.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../src/lib/find.ts"],"names":[],"mappings":"AAGA,0DAA0D;AAC1D,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IACd,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,uEAAuE;IACvE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACjD;AAED,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,OAAO,GAAG,IAAI,CAAC;IAC9B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sDAAsD;IACtD,MAAM,CAAC,EAAE,OAAO,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IACd,OAAO,IAAI,IAAI,CAAC;CACjB;AAuBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAuGpG"}
1
+ {"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../src/lib/find.ts"],"names":[],"mappings":"AAGA,0DAA0D;AAC1D,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IACd,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,uEAAuE;IACvE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACjD;AAED,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,OAAO,GAAG,IAAI,CAAC;IAC9B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sDAAsD;IACtD,MAAM,CAAC,EAAE,OAAO,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IACd,OAAO,IAAI,IAAI,CAAC;CACjB;AAuBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,UAAU,GAAG,CAAC,MAAM,UAAU,CAAC,EACvC,OAAO,GAAE,iBAAsB,GAC9B,gBAAgB,CA2HlB"}
@@ -1 +1 @@
1
- {"version":3,"file":"menubar.d.ts","sourceRoot":"","sources":["../../src/lib/menubar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,KAAK,YAAY,EAAmC,MAAM,eAAe,CAAC;AAEnF,kEAAkE;AAClE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AACD,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,IAAI,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AACD,yBAAyB;AACzB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AACD,kFAAkF;AAClF,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,WAAW,CAAC;CAC5C;AACD,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,CAAC;AAE9F,uDAAuD;AACvD,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,kFAAkF;IAClF,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC;;+EAE2E;IAC3E,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,IAAI,IAAI,CAAC;CACjB;AAmDD;mDACmD;AACnD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,EAAE,CAUlE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,cAAmB,GAC3B,aAAa,CA0Lf"}
1
+ {"version":3,"file":"menubar.d.ts","sourceRoot":"","sources":["../../src/lib/menubar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,eAAe,CAAC;AAEvB,kEAAkE;AAClE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AACD,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,IAAI,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AACD,yBAAyB;AACzB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AACD,kFAAkF;AAClF,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,WAAW,CAAC;CAC5C;AACD,MAAM,MAAM,SAAS,GACjB,WAAW,GACX,YAAY,GACZ,WAAW,GACX,YAAY,GACZ,WAAW,CAAC;AAEhB,uDAAuD;AACvD,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,kFAAkF;IAClF,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC;;+EAE2E;IAC3E,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,IAAI,IAAI,CAAC;CACjB;AAmDD;mDACmD;AACnD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,EAAE,CAYlE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,cAAmB,GAC3B,aAAa,CAiOf"}
@@ -0,0 +1,92 @@
1
+ /** px → cm. */
2
+ export declare const pxToCm: (px: number) => number;
3
+ /** cm → px (rounded — the model is integer px). */
4
+ export declare const cmToPx: (cm: number) => number;
5
+ export interface PaperChoice {
6
+ /** Stable key echoed back to `onPick` (e.g. a PaperSize name). */
7
+ key: string;
8
+ label: string;
9
+ /** Nominal portrait size in cm — the caption. Exact values, not derived
10
+ * from px (rounding would print A4 as 21.006 cm). */
11
+ cm: readonly [number, number];
12
+ /** Portrait size in px — drives the preview icon's aspect ratio. */
13
+ px: readonly [number, number];
14
+ active?: boolean;
15
+ }
16
+ export interface MarginChoice {
17
+ key: string;
18
+ label: string;
19
+ /** Margins in px; shown in cm and drawn as the preview's content box. */
20
+ margin: PageMargin;
21
+ active?: boolean;
22
+ }
23
+ export interface PageMargin {
24
+ top: number;
25
+ right: number;
26
+ bottom: number;
27
+ left: number;
28
+ }
29
+ export interface PageSizePickerOptions {
30
+ items: readonly PaperChoice[];
31
+ /** Called with the chosen item's `key`. */
32
+ onPick: (key: string) => void;
33
+ /** Called for the trailing "Custom page size" row. */
34
+ onCustom: () => void;
35
+ }
36
+ /**
37
+ * Layout ▸ Page size flyout: one row per paper preset (preview, name, size in
38
+ * cm) plus a custom row. Returns a detached element for a menu widget slot.
39
+ */
40
+ export declare function pageSizePicker(options: PageSizePickerOptions): HTMLElement;
41
+ export interface OrientationPickerOptions {
42
+ /** Current page size in px — the previews are drawn at its aspect ratio. */
43
+ page: {
44
+ width: number;
45
+ height: number;
46
+ };
47
+ active: 'portrait' | 'landscape';
48
+ onPick: (orientation: 'portrait' | 'landscape') => void;
49
+ }
50
+ /**
51
+ * Layout ▸ Orientation flyout. Same row shape as the other two pickers, so all
52
+ * three entries of the Layout menu read as one family.
53
+ */
54
+ export declare function orientationPicker(options: OrientationPickerOptions): HTMLElement;
55
+ export interface MarginPickerOptions {
56
+ items: readonly MarginChoice[];
57
+ /** Page size in px — the previews draw each preset's content box to scale. */
58
+ page: {
59
+ width: number;
60
+ height: number;
61
+ };
62
+ onPick: (key: string) => void;
63
+ onCustom: () => void;
64
+ }
65
+ /**
66
+ * Layout ▸ Margins flyout: one row per preset (a preview showing the content
67
+ * box to scale, the name, and the four edges in cm) plus a custom row.
68
+ */
69
+ export declare function marginPresetPicker(options: MarginPickerOptions): HTMLElement;
70
+ export interface PageSizeDialogOptions {
71
+ /** Current size in px. */
72
+ initial: {
73
+ width: number;
74
+ height: number;
75
+ };
76
+ /** Applied size in px. */
77
+ onApply: (size: {
78
+ width: number;
79
+ height: number;
80
+ }) => void;
81
+ }
82
+ /** Layout ▸ Page size ▸ Custom page size — width/height in cm. */
83
+ export declare function openPageSizeDialog(options: PageSizeDialogOptions): void;
84
+ export interface MarginsDialogOptions {
85
+ /** Current margins in px. */
86
+ initial: PageMargin;
87
+ /** Applied margins in px. */
88
+ onApply: (margin: PageMargin) => void;
89
+ }
90
+ /** Layout ▸ Margins ▸ Custom margins — the four edges in cm. */
91
+ export declare function openMarginsDialog(options: MarginsDialogOptions): void;
92
+ //# sourceMappingURL=page-setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-setup.d.ts","sourceRoot":"","sources":["../../src/lib/page-setup.ts"],"names":[],"mappings":"AAkBA,eAAe;AACf,eAAO,MAAM,MAAM,GAAI,IAAI,MAAM,KAAG,MAAwB,CAAC;AAC7D,mDAAmD;AACnD,eAAO,MAAM,MAAM,GAAI,IAAI,MAAM,KAAG,MAAoC,CAAC;AAOzE,MAAM,WAAW,WAAW;IAC1B,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd;0DACsD;IACtD,EAAE,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,oEAAoE;IACpE,EAAE,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAqJD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;IAC9B,2CAA2C;IAC3C,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,sDAAsD;IACtD,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,WAAW,CA8B1E;AAED,MAAM,WAAW,wBAAwB;IACvC,4EAA4E;IAC5E,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,MAAM,EAAE,UAAU,GAAG,WAAW,CAAC;IACjC,MAAM,EAAE,CAAC,WAAW,EAAE,UAAU,GAAG,WAAW,KAAK,IAAI,CAAC;CACzD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,wBAAwB,GAChC,WAAW,CA0Bb;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,8EAA8E;IAC9E,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,WAAW,CA0C5E;AAkDD,MAAM,WAAW,qBAAqB;IACpC,0BAA0B;IAC1B,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,0BAA0B;IAC1B,OAAO,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CAC5D;AAED,kEAAkE;AAClE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CA2BvE;AAED,MAAM,WAAW,oBAAoB;IACnC,6BAA6B;IAC7B,OAAO,EAAE,UAAU,CAAC;IACpB,6BAA6B;IAC7B,OAAO,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAuCrE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shadow-garden/bapbong-ui",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "bapbong — framework-agnostic editor UI (toolbar/menubar) that mounts into a host element and binds to editor.commands",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -56,6 +56,6 @@
56
56
  }
57
57
  },
58
58
  "dependencies": {
59
- "@shadow-garden/bapbong-contracts": "^0.3.0"
59
+ "@shadow-garden/bapbong-contracts": "^0.4.0"
60
60
  }
61
61
  }