88217c5e7d
* Implement a first version of WithFloating and Portal * Add outside slot for Portal * Execute computePosition from WithFloating * Set up a first example of new WithFloating with the Latex menu * Use autoUpdate in WithFloating * Create sveltelib/position * Add event-store * Use event-store in close-on-click * Implement subscribeToUpdates * Introduce sass/elevation * Split close-on-click to closing-click and subscribe-trigger * Have closing-* stores return a symbol - This way they act more of an EventEmitter than a store * Allow passing show store * Remove styling on float on updatePosition removal * Implement a nice border for dropdowns * Apply different border and box-shadow to Popover in dark/light theme * Fix Ctrl+Shift+T not working * Satisfy formatters and tests * Add copyright header * move copyright header to top (dae)
83 lines
1.9 KiB
TypeScript
83 lines
1.9 KiB
TypeScript
// Copyright: Ankitects Pty Ltd and contributors
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
import type { Placement } from "@floating-ui/dom";
|
|
import { arrow, autoUpdate, computePosition, offset, shift } from "@floating-ui/dom";
|
|
|
|
interface PositionArgs {
|
|
/**
|
|
* The floating element which is positioned relative to `reference`.
|
|
*/
|
|
floating: HTMLElement | null;
|
|
placement: Placement;
|
|
arrow: HTMLElement;
|
|
}
|
|
|
|
function position(
|
|
reference: HTMLElement,
|
|
positionArgs: PositionArgs,
|
|
): { update(args: PositionArgs): void; destroy(): void } {
|
|
let args = positionArgs;
|
|
|
|
async function updateInner(): Promise<void> {
|
|
const { x, y, middlewareData } = await computePosition(
|
|
reference,
|
|
args.floating!,
|
|
{
|
|
middleware: [
|
|
offset(5),
|
|
shift({ padding: 5 }),
|
|
arrow({ element: args.arrow }),
|
|
],
|
|
placement: args.placement,
|
|
},
|
|
);
|
|
|
|
const arrowX = middlewareData.arrow?.x ?? "";
|
|
|
|
Object.assign(args.arrow.style, {
|
|
left: `${arrowX}px`,
|
|
top: `-5px`,
|
|
});
|
|
|
|
Object.assign(args.floating!.style, {
|
|
left: `${x}px`,
|
|
top: `${y}px`,
|
|
});
|
|
}
|
|
|
|
let cleanup: (() => void) | null = null;
|
|
|
|
function destroy(): void {
|
|
cleanup?.();
|
|
cleanup = null;
|
|
|
|
if (!args.floating) {
|
|
return;
|
|
}
|
|
|
|
args.floating.style.removeProperty("left");
|
|
args.floating.style.removeProperty("top");
|
|
}
|
|
|
|
function update(updateArgs: PositionArgs): void {
|
|
destroy();
|
|
args = updateArgs;
|
|
|
|
if (!args.floating) {
|
|
return;
|
|
}
|
|
|
|
cleanup = autoUpdate(reference, args.floating, updateInner);
|
|
}
|
|
|
|
update(args);
|
|
|
|
return {
|
|
update,
|
|
destroy,
|
|
};
|
|
}
|
|
|
|
export default position;
|