@threadlabs/looma 0.26.18 → 0.26.20

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.
@@ -60,6 +60,7 @@
60
60
  </state>
61
61
  <state
62
62
  name="hovered"
63
+ nullable
63
64
  type="object"
64
65
  >
65
66
  <prop name="left" required type="number"></prop>
@@ -73,6 +74,7 @@
73
74
  </state>
74
75
  <state
75
76
  name="active"
77
+ nullable
76
78
  type="object"
77
79
  >
78
80
  <prop name="left" required type="number"></prop>
@@ -130,7 +130,7 @@ function connect(host) {
130
130
  rowOffset: `${hovered.top + hovered.height / 2}px`,
131
131
  columnOffset: `${hovered.left + hovered.width / 2}px`,
132
132
  };
133
- const active = host.props.geometry.value?.activeCell ?? null;
133
+ const active = hovered ?? host.props.geometry.value?.activeCell ?? null;
134
134
  host.state.active = active && { ...active, menuLeft: `${active.left + active.width - 30}px`, menuTop: `${active.top + 6}px` };
135
135
  queueMicrotask(proximity.refresh);
136
136
  });
@@ -1,4 +1,5 @@
1
1
  import { backgrounds } from "../shared/editor.js";
2
+ import { createAnchoredSurface } from "../shared/overlay.js";
2
3
 
3
4
  const overflowSections = [
4
5
  ["Structure", [["add-row-before", "Add row above", "panel-top"], ["add-column-before", "Add column left", "panel-left"], ["toggle-header-row", "Header row", "rows"], ["toggle-header-column", "Header column", "columns"], ["move-row-up", "Move row up", "rows"], ["move-row-down", "Move row down", "rows"], ["move-column-left", "Move column left", "columns"], ["move-column-right", "Move column right", "columns"]]],
@@ -9,10 +10,19 @@ const overflowSections = [
9
10
  // Lists the actions the table selection permits; the overflow menu opens and closes here.
10
11
  function connect(host) {
11
12
  const element = host.element;
13
+ let surface = null;
14
+ let surfaceMenu = null;
15
+ let positionFrame = null;
12
16
  const positionMenu = () => {
17
+ if (!host.state.overflowOpen) return;
13
18
  const button = element.querySelector(".more");
14
19
  const menu = element.querySelector(".menu");
15
20
  if (!button || !menu) return;
21
+ if (surfaceMenu !== menu) {
22
+ surface?.destroy();
23
+ surfaceMenu = menu;
24
+ surface = createAnchoredSurface(menu, { anchor: button, placement: "bottom-end", gap: 8, viewportGap: 12 });
25
+ }
16
26
  const rect = button.getBoundingClientRect();
17
27
  const viewport = window.visualViewport;
18
28
  const top = viewport?.offsetTop ?? 0;
@@ -20,8 +30,11 @@ function connect(host) {
20
30
  const above = rect.top - top - 20;
21
31
  const below = bottom - rect.bottom - 20;
22
32
  menu.style.maxHeight = `${Math.max(80, Math.floor(Math.max(above, below)))}px`;
23
- menu.style.top = below >= above ? "calc(100% + var(--ui-space-2))" : "auto";
24
- menu.style.bottom = below >= above ? "auto" : "calc(100% + var(--ui-space-2))";
33
+ surface.show();
34
+ };
35
+ const schedulePosition = () => {
36
+ if (positionFrame !== null) cancelAnimationFrame(positionFrame);
37
+ positionFrame = requestAnimationFrame(() => { positionFrame = null; positionMenu(); });
25
38
  };
26
39
  const stop = host.effect(() => {
27
40
  const enabled = new Set(Array.isArray(host.props.actions.value) ? host.props.actions.value : []);
@@ -45,12 +58,19 @@ function connect(host) {
45
58
  host.state.hasOverflow = host.state.swatches.length > 0 || host.state.sections.length > 0;
46
59
  if (!host.props.open.value || !host.state.hasOverflow) host.state.overflowOpen = false;
47
60
  });
61
+ const stopMenu = host.effect(() => {
62
+ if (host.state.overflowOpen) schedulePosition();
63
+ else {
64
+ surface?.destroy();
65
+ surface = null;
66
+ surfaceMenu = null;
67
+ }
68
+ });
48
69
  const onClick = (event) => {
49
70
  const action = event.target.closest?.("[data-action]")?.dataset.action;
50
71
  if (!action) return;
51
72
  if (action === "toggle-overflow") {
52
73
  host.state.overflowOpen = !host.state.overflowOpen;
53
- if (host.state.overflowOpen) requestAnimationFrame(positionMenu);
54
74
  return;
55
75
  }
56
76
  host.state.overflowOpen = false;
@@ -74,6 +94,9 @@ function connect(host) {
74
94
  window.visualViewport?.addEventListener("resize", positionMenu);
75
95
  return () => {
76
96
  stop();
97
+ stopMenu();
98
+ surface?.destroy();
99
+ if (positionFrame !== null) cancelAnimationFrame(positionFrame);
77
100
  element.removeEventListener("click", onClick);
78
101
  document.removeEventListener("pointerdown", onOutside, true);
79
102
  document.removeEventListener("keydown", onKeydown, true);