@threadlabs/looma 0.23.23 → 0.23.24
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/components/shared/overlay.js +23 -2
- package/package.json +1 -1
- package/vue/components.css +0 -23
- package/vue/editor/index.js +17 -0
|
@@ -205,6 +205,8 @@ export function createAnchoredSurface(surface, options = {}) {
|
|
|
205
205
|
let point = null;
|
|
206
206
|
let open = false;
|
|
207
207
|
let frame = null;
|
|
208
|
+
let anchorFrame = null;
|
|
209
|
+
let lastAnchorRect = null;
|
|
208
210
|
let abort = null;
|
|
209
211
|
let sizeObserver = null;
|
|
210
212
|
surface.setAttribute("popover", "manual");
|
|
@@ -218,12 +220,31 @@ export function createAnchoredSurface(surface, options = {}) {
|
|
|
218
220
|
return;
|
|
219
221
|
}
|
|
220
222
|
if (!anchor) return;
|
|
221
|
-
|
|
223
|
+
lastAnchorRect = anchor.getBoundingClientRect();
|
|
224
|
+
fallbackPosition(surface, lastAnchorRect, placement, gap(), viewportGap);
|
|
222
225
|
};
|
|
223
226
|
const schedule = () => {
|
|
224
227
|
if (open && frame === null) frame = owner.requestAnimationFrame(position);
|
|
225
228
|
};
|
|
229
|
+
// Resize and scroll events do not report an ancestor's transition or layout shift.
|
|
230
|
+
// While visible, sample the anchor and only re-position when its bounds change.
|
|
231
|
+
const trackAnchor = () => {
|
|
232
|
+
anchorFrame = null;
|
|
233
|
+
if (!open || !anchor || point) return;
|
|
234
|
+
const rect = anchor.getBoundingClientRect();
|
|
235
|
+
if (!lastAnchorRect || rect.left !== lastAnchorRect.left || rect.top !== lastAnchorRect.top
|
|
236
|
+
|| rect.width !== lastAnchorRect.width || rect.height !== lastAnchorRect.height) schedule();
|
|
237
|
+
anchorFrame = owner.requestAnimationFrame(trackAnchor);
|
|
238
|
+
};
|
|
239
|
+
const stopTracking = () => {
|
|
240
|
+
if (anchorFrame !== null) owner.cancelAnimationFrame(anchorFrame);
|
|
241
|
+
anchorFrame = null;
|
|
242
|
+
lastAnchorRect = null;
|
|
243
|
+
};
|
|
226
244
|
const syncListeners = () => {
|
|
245
|
+
if (open && anchor && !point) {
|
|
246
|
+
if (anchorFrame === null) anchorFrame = owner.requestAnimationFrame(trackAnchor);
|
|
247
|
+
} else stopTracking();
|
|
227
248
|
const needed = open && (point || anchor);
|
|
228
249
|
if (!needed) {
|
|
229
250
|
abort?.abort();
|
|
@@ -251,7 +272,7 @@ export function createAnchoredSurface(surface, options = {}) {
|
|
|
251
272
|
showAtPoint(next) { point = next; open = true; syncListeners(); show(surface); position(); schedule(); observeSize(); },
|
|
252
273
|
hide() { open = false; point = null; syncListeners(); stopSize(); if (frame !== null) owner.cancelAnimationFrame(frame); frame = null; hide(surface); },
|
|
253
274
|
refresh: schedule,
|
|
254
|
-
destroy() { open = false; abort?.abort(); abort = null; stopSize(); if (frame !== null) owner.cancelAnimationFrame(frame); frame = null; hide(surface); anchor = null; },
|
|
275
|
+
destroy() { open = false; stopTracking(); abort?.abort(); abort = null; stopSize(); if (frame !== null) owner.cancelAnimationFrame(frame); frame = null; hide(surface); anchor = null; },
|
|
255
276
|
};
|
|
256
277
|
}
|
|
257
278
|
|
package/package.json
CHANGED
package/vue/components.css
CHANGED
|
@@ -9969,27 +9969,4 @@ html[data-ui-input-modality="touch"]
|
|
|
9969
9969
|
width: 3px;
|
|
9970
9970
|
background: var(--ui-affordance-direct-color, var(--ui-accent-solid, #5b55d6));
|
|
9971
9971
|
}
|
|
9972
|
-
|
|
9973
|
-
.ProseMirror .column-resize-handle::before {
|
|
9974
|
-
content: "Drag to resize column";
|
|
9975
|
-
position: absolute;
|
|
9976
|
-
z-index: 4;
|
|
9977
|
-
top: 4px;
|
|
9978
|
-
left: calc(100% + 6px);
|
|
9979
|
-
width: max-content;
|
|
9980
|
-
padding: var(--ui-space-1, 4px) var(--ui-space-2, 8px);
|
|
9981
|
-
border-radius: var(--ui-radius-sm, 4px);
|
|
9982
|
-
background: var(--ui-text-primary, #1a1a1a);
|
|
9983
|
-
color: var(--ui-surface-elevated, #fff);
|
|
9984
|
-
font-size: var(--ui-font-size-xs, 0.75rem);
|
|
9985
|
-
line-height: var(--ui-line-height-md, 1.4);
|
|
9986
|
-
opacity: 0;
|
|
9987
|
-
transform: none;
|
|
9988
|
-
transition: opacity var(--ui-affordance-motion, var(--ui-motion-fast, 120ms)) var(--ui-motion-ease, ease);
|
|
9989
|
-
pointer-events: none;
|
|
9990
|
-
}
|
|
9991
|
-
|
|
9992
|
-
.ProseMirror .column-resize-handle:hover::before {
|
|
9993
|
-
opacity: 1;
|
|
9994
|
-
}
|
|
9995
9972
|
/*$vite$:1*/
|
package/vue/editor/index.js
CHANGED
|
@@ -1758,6 +1758,8 @@ var LoomaEditor = defineComponent({
|
|
|
1758
1758
|
const tooltipLabel = ref("");
|
|
1759
1759
|
const tooltipShortcut = ref("");
|
|
1760
1760
|
const tooltipOpen = ref(false);
|
|
1761
|
+
const resizeHintFor = ref("");
|
|
1762
|
+
let resizeHintSequence = 0;
|
|
1761
1763
|
let tooltipTimer = 0;
|
|
1762
1764
|
const clearTooltipTimer = () => {
|
|
1763
1765
|
if (tooltipTimer) window.clearTimeout(tooltipTimer);
|
|
@@ -2879,6 +2881,11 @@ var LoomaEditor = defineComponent({
|
|
|
2879
2881
|
nextTick(updateTableUi);
|
|
2880
2882
|
};
|
|
2881
2883
|
const onEditorPointerOver = (event) => {
|
|
2884
|
+
const handle = event.pointerType !== "touch" && event.target instanceof HTMLElement ? event.target.closest(".column-resize-handle") : null;
|
|
2885
|
+
if (handle) {
|
|
2886
|
+
if (!handle.id) handle.id = `${toolbarScope}-resize-${++resizeHintSequence}`;
|
|
2887
|
+
resizeHintFor.value = handle.id;
|
|
2888
|
+
}
|
|
2882
2889
|
const cell = event.target instanceof HTMLElement ? event.target.closest("td, th") : null;
|
|
2883
2890
|
if (!cell) return;
|
|
2884
2891
|
if (cell === hoveredTableCell) return;
|
|
@@ -2890,6 +2897,8 @@ var LoomaEditor = defineComponent({
|
|
|
2890
2897
|
});
|
|
2891
2898
|
};
|
|
2892
2899
|
const onEditorPointerOut = (event) => {
|
|
2900
|
+
const handle = event.target instanceof HTMLElement ? event.target.closest(".column-resize-handle") : null;
|
|
2901
|
+
if (handle && (!(event.relatedTarget instanceof Node) || !handle.contains(event.relatedTarget))) resizeHintFor.value = "";
|
|
2893
2902
|
const fromCell = event.target instanceof HTMLElement ? event.target.closest("td, th") : null;
|
|
2894
2903
|
if (!fromCell || fromCell !== hoveredTableCell) return;
|
|
2895
2904
|
const next = event.relatedTarget;
|
|
@@ -2898,6 +2907,7 @@ var LoomaEditor = defineComponent({
|
|
|
2898
2907
|
nextTick(updateTableUi);
|
|
2899
2908
|
};
|
|
2900
2909
|
const onEditorPointerLeave = (event) => {
|
|
2910
|
+
resizeHintFor.value = "";
|
|
2901
2911
|
const next = event.relatedTarget;
|
|
2902
2912
|
if (next instanceof Node && (tableOverlayShell.value?.contains(next) || tableToolbarShell.value?.contains(next) || tableMenuShell.value?.contains(next))) return;
|
|
2903
2913
|
if (!hoveredTableCell) return;
|
|
@@ -3111,6 +3121,13 @@ var LoomaEditor = defineComponent({
|
|
|
3111
3121
|
onDblclick: onImageDoubleClick,
|
|
3112
3122
|
onKeydown: onImageKeyDown
|
|
3113
3123
|
}, [
|
|
3124
|
+
resizeHintFor.value ? h(Tooltip, {
|
|
3125
|
+
for: resizeHintFor.value,
|
|
3126
|
+
open: true,
|
|
3127
|
+
trigger: "focus",
|
|
3128
|
+
placement: "top",
|
|
3129
|
+
inverse: true
|
|
3130
|
+
}, () => "Drag to resize column") : null,
|
|
3114
3131
|
instance && props.editable && !mobile.value && (props.toolbarMode === "bubble" || props.toolbarMode === "popover" || props.toolbarMode === "contextual") ? h(BubbleMenu, {
|
|
3115
3132
|
editor: instance,
|
|
3116
3133
|
pluginKey: "looma-text-formatting-menu",
|