v1.0.4 popover ai
parent
dc2e7441d6
commit
895c6d8599
@ -0,0 +1,48 @@
|
|||||||
|
<script>
|
||||||
|
import { fade } from 'svelte/transition';
|
||||||
|
export let content;
|
||||||
|
export let triggerRect;
|
||||||
|
export let options = {};
|
||||||
|
|
||||||
|
$: style = {
|
||||||
|
position: 'fixed',
|
||||||
|
top: `${triggerRect.bottom}px`,
|
||||||
|
left: options.align === "left" ? `${triggerRect.left}px` :
|
||||||
|
options.align === "right" ? `${triggerRect.right}px` :
|
||||||
|
`${triggerRect.left + triggerRect.width / 2}px`,
|
||||||
|
transform: options.align === "left" ? "none" :
|
||||||
|
options.align === "right" ? "translateX(-100%)" :
|
||||||
|
"translateX(-50%)",
|
||||||
|
maxWidth: options.maxWidth || "300px"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="custom-popover"
|
||||||
|
style:position={style.position}
|
||||||
|
style:top={style.top}
|
||||||
|
style:left={style.left}
|
||||||
|
style:transform={style.transform}
|
||||||
|
style:max-width={style.maxWidth}
|
||||||
|
transition:fade={{ duration: 150 }}
|
||||||
|
>
|
||||||
|
{@html content}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.custom-popover {
|
||||||
|
background: #1a1a1a;
|
||||||
|
color: white;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
z-index: 1000;
|
||||||
|
border: 1px solid #333;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
word-wrap: break-word;
|
||||||
|
white-space: normal;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
hyphens: auto;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,50 @@
|
|||||||
|
<script>
|
||||||
|
import { showPopover, hidePopover } from '../stores/popover.js';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
let triggerElement;
|
||||||
|
export let maxWidth = "300px";
|
||||||
|
export let align = "center";
|
||||||
|
|
||||||
|
let contentElement;
|
||||||
|
let currentPopoverId = null;
|
||||||
|
|
||||||
|
function handleMouseEnter() {
|
||||||
|
const rect = triggerElement.getBoundingClientRect();
|
||||||
|
const content = contentElement.innerHTML;
|
||||||
|
currentPopoverId = showPopover(content, rect, { maxWidth, align });
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseLeave() {
|
||||||
|
if (currentPopoverId !== null) {
|
||||||
|
hidePopover(currentPopoverId);
|
||||||
|
currentPopoverId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
return () => {
|
||||||
|
if (currentPopoverId !== null) {
|
||||||
|
hidePopover(currentPopoverId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={triggerElement}
|
||||||
|
on:mouseenter={handleMouseEnter}
|
||||||
|
on:mouseleave={handleMouseLeave}
|
||||||
|
>
|
||||||
|
<slot name="trigger" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div bind:this={contentElement} style="display: none;">
|
||||||
|
<slot name="content" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.relative {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,15 @@
|
|||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
export const popovers = writable([]);
|
||||||
|
|
||||||
|
let popoverId = 0;
|
||||||
|
|
||||||
|
export function showPopover(content, triggerRect, options = {}) {
|
||||||
|
const id = popoverId++;
|
||||||
|
popovers.update(items => [...items, { id, content, triggerRect, options }]);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hidePopover(id) {
|
||||||
|
popovers.update(items => items.filter(item => item.id !== id));
|
||||||
|
}
|
Loading…
Reference in New Issue