@threadlabs/looma 0.29.3 → 0.29.4

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.
@@ -0,0 +1,29 @@
1
+ import type { ViewportRect } from "./viewport.js";
2
+ /** The widest viewport, in CSS pixels, that gets the editing dock; the slash and mention menus use the same width. */
3
+ export declare const LOOMA_MOBILE_DOCK_MAX_WIDTH = 767;
4
+ /** Whether a viewport this wide gets the editing dock rather than floating tools. */
5
+ export declare const usesMobileDock: (viewportWidth: number) => boolean;
6
+ /**
7
+ * Where the dock sits: across the visual viewport, against its bottom edge, so an on-screen keyboard
8
+ * pushes it up. It never rises above the viewport's top.
9
+ */
10
+ export declare function mobileDockPlacement(viewport: ViewportRect, dockHeight: number): {
11
+ left: number;
12
+ top: number;
13
+ width: number;
14
+ };
15
+ export type LoomaMobileDockMode = "formatting" | "table";
16
+ /**
17
+ * Which controls the dock shows. A table holding the selection shows its controls, until the author
18
+ * goes back to formatting; that choice lasts until no table is active.
19
+ *
20
+ * @ownership The host reports table activity and renders the mode; this owns the choice.
21
+ */
22
+ export interface LoomaMobileDock {
23
+ readonly mode: LoomaMobileDockMode;
24
+ tableActive(): void;
25
+ showFormatting(): void;
26
+ tableInactive(): void;
27
+ }
28
+ /** Calls `onChange` with the new mode whenever it changes. */
29
+ export declare function createMobileDock(onChange: (mode: LoomaMobileDockMode) => void): LoomaMobileDock;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threadlabs/looma",
3
- "version": "0.29.3",
3
+ "version": "0.29.4",
4
4
  "type": "module",
5
5
  "description": "Looma components as HTML, Vue, and plain DOM, with design tokens.",
6
6
  "license": "MIT",
@@ -1810,6 +1810,45 @@ function selectionActionDetail(state, id) {
1810
1810
  after: doc.textBetween(to, Math.min(doc.content.size, to + CONTEXT), "\n")
1811
1811
  };
1812
1812
  }
1813
+ /** Whether a viewport this wide gets the editing dock rather than floating tools. */
1814
+ var usesMobileDock = (viewportWidth) => viewportWidth <= 767;
1815
+ /**
1816
+ * Where the dock sits: across the visual viewport, against its bottom edge, so an on-screen keyboard
1817
+ * pushes it up. It never rises above the viewport's top.
1818
+ */
1819
+ function mobileDockPlacement(viewport, dockHeight) {
1820
+ return {
1821
+ left: viewport.left,
1822
+ top: Math.max(viewport.top, viewport.bottom - dockHeight),
1823
+ width: viewport.width
1824
+ };
1825
+ }
1826
+ /** Calls `onChange` with the new mode whenever it changes. */
1827
+ function createMobileDock(onChange) {
1828
+ let mode = "formatting";
1829
+ let formattingChosen = false;
1830
+ const set = (next) => {
1831
+ if (next === mode) return;
1832
+ mode = next;
1833
+ onChange(mode);
1834
+ };
1835
+ return {
1836
+ get mode() {
1837
+ return mode;
1838
+ },
1839
+ tableActive() {
1840
+ if (!formattingChosen) set("table");
1841
+ },
1842
+ showFormatting() {
1843
+ formattingChosen = true;
1844
+ set("formatting");
1845
+ },
1846
+ tableInactive() {
1847
+ formattingChosen = false;
1848
+ set("formatting");
1849
+ }
1850
+ };
1851
+ }
1813
1852
  //#endregion
1814
1853
  //#region src/editor/extensions/relative-links.ts
1815
1854
  /** Keep other origins and non-web schemes intact; same-origin links retain path, query, and fragment. */
@@ -3508,7 +3547,7 @@ var LoomaEditor = defineComponent({
3508
3547
  });
3509
3548
  const tablePickerOpen = ref(false);
3510
3549
  const mobileToolbarStyle = ref({});
3511
- const mobile = ref(typeof window !== "undefined" && window.innerWidth <= 767);
3550
+ const mobile = ref(typeof window !== "undefined" && usesMobileDock(window.innerWidth));
3512
3551
  const editorFocused = ref(false);
3513
3552
  let formatting;
3514
3553
  let formattingPopup = null;
@@ -3520,10 +3559,12 @@ var LoomaEditor = defineComponent({
3520
3559
  const formattingActive = () => formatting?.active() ?? false;
3521
3560
  const editorStateVersion = ref(0);
3522
3561
  const mobileToolbarMode = ref("formatting");
3562
+ const mobileDock = createMobileDock((mode) => {
3563
+ mobileToolbarMode.value = mode;
3564
+ });
3523
3565
  let dragLeaveTimer = null;
3524
3566
  let tableResizeActive = false;
3525
3567
  let tableInteractionActive = false;
3526
- let mobileTableControlsDismissed = false;
3527
3568
  let hoveredTableCell = null;
3528
3569
  let overlayTableElement = null;
3529
3570
  let tablePointerFrame = null;
@@ -3993,22 +4034,20 @@ var LoomaEditor = defineComponent({
3993
4034
  tableUi.geometry = null;
3994
4035
  tableUi.capabilities = { ...EMPTY_CAPABILITIES };
3995
4036
  overlayTableElement = null;
3996
- mobileTableControlsDismissed = false;
3997
- mobileToolbarMode.value = "formatting";
4037
+ mobileDock.tableInactive();
3998
4038
  };
3999
4039
  const updateMobileViewport = () => {
4000
- mobile.value = window.innerWidth <= 767;
4040
+ mobile.value = usesMobileDock(window.innerWidth);
4001
4041
  if (!mobile.value) {
4002
4042
  mobileToolbarStyle.value = {};
4003
4043
  return;
4004
4044
  }
4005
4045
  nextTick(() => {
4006
- const viewport = getVisualViewportRect(window);
4007
- const toolbarHeight = mobileToolbarShell.value?.getBoundingClientRect().height || 56;
4046
+ const placement = mobileDockPlacement(getVisualViewportRect(window), mobileToolbarShell.value?.getBoundingClientRect().height || 56);
4008
4047
  mobileToolbarStyle.value = {
4009
- left: `${viewport.left}px`,
4010
- top: `${Math.max(viewport.top, viewport.bottom - toolbarHeight)}px`,
4011
- width: `${viewport.width}px`
4048
+ left: `${placement.left}px`,
4049
+ top: `${placement.top}px`,
4050
+ width: `${placement.width}px`
4012
4051
  };
4013
4052
  });
4014
4053
  };
@@ -4098,7 +4137,7 @@ var LoomaEditor = defineComponent({
4098
4137
  }
4099
4138
  const selectedTableIsActive = state.active && selectedTable === table;
4100
4139
  overlayTableElement = table;
4101
- if (selectedTableIsActive && !mobileTableControlsDismissed) mobileToolbarMode.value = "table";
4140
+ if (selectedTableIsActive) mobileDock.tableActive();
4102
4141
  const rect = table.getBoundingClientRect();
4103
4142
  const maxToolbarWidth = Math.min(420, window.innerWidth - 24);
4104
4143
  const toolbarLeft = Math.min(Math.max(12, rect.left + (rect.width - maxToolbarWidth) / 2), Math.max(12, window.innerWidth - maxToolbarWidth - 12));
@@ -4853,8 +4892,7 @@ var LoomaEditor = defineComponent({
4853
4892
  type: "button",
4854
4893
  "aria-label": "Formatting tools",
4855
4894
  onClick: () => {
4856
- mobileTableControlsDismissed = true;
4857
- mobileToolbarMode.value = "formatting";
4895
+ mobileDock.showFormatting();
4858
4896
  editor.value?.commands.focus();
4859
4897
  nextTick(updateMobileViewport);
4860
4898
  }