🙃
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Input } from '$lib/components/ui/input/index.js';
|
import { Input } from '$lib/components/ui/input/index.js';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { getErrDesc, getErrTitle, getEvalLiteral, isErr, type CellT } from './utils';
|
import { getErrDesc, getErrTitle, getEvalLiteral, isErr } from './utils';
|
||||||
import * as HoverCard from '$lib/components/ui/hover-card/index.js';
|
import * as HoverCard from '$lib/components/ui/hover-card/index.js';
|
||||||
|
import type { CellT } from './messages';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
cla = '',
|
cla = '',
|
||||||
@@ -33,7 +34,7 @@
|
|||||||
queueMicrotask(() => {
|
queueMicrotask(() => {
|
||||||
const el = node.querySelector('input') as HTMLInputElement | null;
|
const el = node.querySelector('input') as HTMLInputElement | null;
|
||||||
if (el !== null) {
|
if (el !== null) {
|
||||||
el.value = cell?.raw_val ?? '';
|
el.value = cell?.temp_raw ?? '';
|
||||||
el.focus();
|
el.focus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -49,44 +50,48 @@
|
|||||||
stopediting();
|
stopediting();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPreview() {
|
||||||
|
return !isErr(cell?.temp_eval) ? getEvalLiteral(cell?.temp_eval) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
let showPreview = $derived(getPreview() !== '');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if editing}
|
{#if editing}
|
||||||
|
<div class="relative inline-block">
|
||||||
|
{#if showPreview}
|
||||||
|
<h3
|
||||||
|
class="bubble pointer-events-none absolute -top-[6px] -left-1 z-[500] -translate-y-full text-sm font-semibold tracking-tight text-foreground select-none"
|
||||||
|
role="tooltip"
|
||||||
|
>
|
||||||
|
{getPreview()}
|
||||||
|
</h3>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div use:autofocusWithin onkeydown={handleKeydown}>
|
<div use:autofocusWithin onkeydown={handleKeydown}>
|
||||||
<Input
|
<Input
|
||||||
style="width: {width}; height: {height}"
|
style="width: {width}; height: {height}"
|
||||||
class="relative rounded-none p-1 !transition-none delay-0 duration-0
|
class="relative rounded-none p-1 !transition-none delay-0 duration-0
|
||||||
focus:z-20 focus:shadow-[0_0_0_1px_var(--color-primary)] focus:outline-none"
|
focus:z-20 focus:shadow-[0_0_0_1px_var(--color-primary)] focus:outline-none"
|
||||||
bind:value={
|
bind:value={
|
||||||
() => {
|
() => cell?.temp_raw ?? '',
|
||||||
return cell?.raw_val ?? '';
|
(v) => (cell = { eval: cell?.eval, raw: cell?.raw ?? '', temp_raw: v })
|
||||||
},
|
|
||||||
(v) => {
|
|
||||||
cell = {
|
|
||||||
val: cell?.val,
|
|
||||||
raw_val: v
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
onblur={stopediting}
|
||||||
onblur={(e) => {
|
|
||||||
// cell = {
|
|
||||||
// val: cell?.val,
|
|
||||||
// raw_val: (e.target as HTMLInputElement).value
|
|
||||||
// };
|
|
||||||
stopediting();
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{:else if cell && isErr(cell.val)}
|
</div>
|
||||||
|
{:else if cell && isErr(cell.eval)}
|
||||||
<HoverCard.Root openDelay={500} closeDelay={500}>
|
<HoverCard.Root openDelay={500} closeDelay={500}>
|
||||||
<HoverCard.Trigger>
|
<HoverCard.Trigger>
|
||||||
{@render InnerCell()}
|
{@render InnerCell()}
|
||||||
</HoverCard.Trigger>
|
</HoverCard.Trigger>
|
||||||
<HoverCard.Content side="right">
|
<HoverCard.Content side="right">
|
||||||
<h2 class="text-md font-semibold tracking-tight transition-colors">
|
<h2 class="text-md font-semibold tracking-tight transition-colors">
|
||||||
{getErrTitle(cell.val)}
|
{getErrTitle(cell.eval)}
|
||||||
</h2>
|
</h2>
|
||||||
{getErrDesc(cell.val)}
|
{getErrDesc(cell.eval)}
|
||||||
</HoverCard.Content>
|
</HoverCard.Content>
|
||||||
</HoverCard.Root>
|
</HoverCard.Root>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -101,12 +106,12 @@
|
|||||||
style:height
|
style:height
|
||||||
class={clsx('placeholder bg-background p-1', { active }, cla)}
|
class={clsx('placeholder bg-background p-1', { active }, cla)}
|
||||||
>
|
>
|
||||||
{#if cell && (cell.raw_val !== '' || getEvalLiteral(cell.val) !== '')}
|
{#if cell && (cell.raw !== '' || getEvalLiteral(cell.eval) !== '')}
|
||||||
<span class={clsx('pointer-events-none select-none', { err: isErr(cell.val) })}>
|
<span class={clsx('pointer-events-none select-none', { err: isErr(cell.eval) })}>
|
||||||
{#if cell.val && !externalediting}
|
{#if cell.eval && !externalediting}
|
||||||
{getEvalLiteral(cell.val)}
|
{getEvalLiteral(cell.eval)}
|
||||||
{:else}
|
{:else}
|
||||||
{cell.raw_val}
|
{cell.raw}
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -144,4 +149,37 @@
|
|||||||
border-top: 12px solid red; /* size & color of the triangle */
|
border-top: 12px solid red; /* size & color of the triangle */
|
||||||
border-left: 12px solid transparent;
|
border-left: 12px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bubble {
|
||||||
|
z-index: 500;
|
||||||
|
background: var(--color-popover);
|
||||||
|
border: 1px solid var(--color-border, rgba(0, 0, 0, 0.12));
|
||||||
|
border-radius: 10px;
|
||||||
|
color: var(--color-popover-foreground);
|
||||||
|
padding: 0.35rem 0.6rem;
|
||||||
|
box-shadow: 0 2px 18px rgba(0, 0, 0, 0.08);
|
||||||
|
max-width: min(15rem, 20vw);
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (optional) subtle appear animation */
|
||||||
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
|
.bubble {
|
||||||
|
transform-origin: bottom left;
|
||||||
|
animation: bubble-in 120ms ease-out both;
|
||||||
|
}
|
||||||
|
@keyframes bubble-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(2px) scale(0.98);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0) scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -32,8 +32,8 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const grid = new Grid(socket);
|
const grid = new Grid(socket);
|
||||||
let rows = 100;
|
let rows = 10;
|
||||||
let cols = 40;
|
let cols = 10;
|
||||||
|
|
||||||
function handleCellInteraction(i: number, j: number, e: MouseEvent) {
|
function handleCellInteraction(i: number, j: number, e: MouseEvent) {
|
||||||
let pos = new Position(i, j);
|
let pos = new Position(i, j);
|
||||||
@@ -104,9 +104,12 @@
|
|||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
onmousedown={() => grid.setExternalEdit(grid.getActivePos())}
|
onmousedown={() => grid.setExternalEdit(grid.getActivePos())}
|
||||||
onblur={() => grid.setExternalEdit(null)}
|
onblur={() => grid.setCell(grid.getActivePos())}
|
||||||
bind:value={
|
bind:value={
|
||||||
() => grid.getActiveCell()?.raw_val ?? '', (raw) => grid.quickEval(grid.getActivePos(), raw)
|
() => grid.getActiveCell()?.temp_raw ?? '',
|
||||||
|
(v) => {
|
||||||
|
grid.setCellTemp(grid.getActivePos(), v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
class="relative w-[200px] pl-9"
|
class="relative w-[200px] pl-9"
|
||||||
></Input>
|
></Input>
|
||||||
@@ -114,7 +117,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class={clsx('grid-wrapper relative h-full min-h-0 max-w-full min-w-0 overflow-auto', className)}
|
class={clsx(
|
||||||
|
' grid-wrapper relative h-full min-h-0 max-w-full min-w-0 overflow-auto overflow-visible',
|
||||||
|
className
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<div class="sticky top-0 flex w-fit" style="z-index: {rows + 70}">
|
<div class="sticky top-0 flex w-fit" style="z-index: {rows + 70}">
|
||||||
<div class="sticky top-0 left-0" style="z-index: {rows + 70}">
|
<div class="sticky top-0 left-0" style="z-index: {rows + 70}">
|
||||||
@@ -163,7 +169,8 @@
|
|||||||
handleCellInteraction(i, j, e);
|
handleCellInteraction(i, j, e);
|
||||||
}}
|
}}
|
||||||
bind:cell={
|
bind:cell={
|
||||||
() => grid.getCell(new Position(i, j)), (v) => grid.setCell(new Position(i, j), v)
|
() => grid.getCell(new Position(i, j)),
|
||||||
|
(v) => grid.setCellTemp(new Position(i, j), v?.temp_raw)
|
||||||
}
|
}
|
||||||
active={grid.isActive(new Position(i, j))}
|
active={grid.isActive(new Position(i, j))}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
import type { CellRef, CellT, LeadMsg } from './messages';
|
import type { CellRef, CellT, Eval, LeadMsg } from './messages';
|
||||||
|
|
||||||
class Position {
|
class Position {
|
||||||
public row: number;
|
public row: number;
|
||||||
@@ -41,7 +41,7 @@ class Grid {
|
|||||||
active_cell: Position | null = $state(null);
|
active_cell: Position | null = $state(null);
|
||||||
editing_cell: Position | null = $state(null);
|
editing_cell: Position | null = $state(null);
|
||||||
external_editing_cell: Position | null = $state(null);
|
external_editing_cell: Position | null = $state(null);
|
||||||
editing_preview = $state(null);
|
editing_preview: [Eval, boolean] | null = $state(null); // [Eval, dirty]
|
||||||
|
|
||||||
constructor(socket: WebSocket, default_col_width = '80px', default_row_height = '30px') {
|
constructor(socket: WebSocket, default_col_width = '80px', default_row_height = '30px') {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
@@ -49,30 +49,47 @@ class Grid {
|
|||||||
this.default_row_height = default_row_height;
|
this.default_row_height = default_row_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCell(pos: Position): CellT {
|
public getCell(pos: Position): CellT | undefined {
|
||||||
return this.data[pos.key()];
|
return this.data[pos.key()];
|
||||||
}
|
}
|
||||||
|
|
||||||
public setCell(pos: Position, v: CellT) {
|
public setCell(pos: Position | null) {
|
||||||
if (v?.raw_val == null || v.raw_val === '') {
|
if (pos === null) return;
|
||||||
|
let data = this.data[pos.key()];
|
||||||
|
if (data === undefined) return;
|
||||||
|
|
||||||
|
if (data.temp_raw === '') {
|
||||||
delete this.data[pos.key()];
|
delete this.data[pos.key()];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.data[pos.key()] = {
|
data.raw = data.temp_raw;
|
||||||
raw_val: v?.raw_val,
|
data.eval = data.temp_eval;
|
||||||
val: v.val
|
|
||||||
};
|
|
||||||
|
|
||||||
let msg: LeadMsg = {
|
let msg: LeadMsg = {
|
||||||
msg_type: 'set',
|
msg_type: 'set',
|
||||||
cell: pos.ref(),
|
cell: pos.ref(),
|
||||||
raw: v.raw_val
|
raw: data.temp_raw
|
||||||
};
|
};
|
||||||
|
|
||||||
this.socket.send(JSON.stringify(msg));
|
this.socket.send(JSON.stringify(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setCellTemp(pos: Position | null, raw: string | undefined) {
|
||||||
|
if (pos === null || raw === undefined) return;
|
||||||
|
|
||||||
|
let x = this.data[pos.key()];
|
||||||
|
|
||||||
|
this.data[pos.key()] = {
|
||||||
|
raw: x?.raw ?? '',
|
||||||
|
temp_raw: raw,
|
||||||
|
eval: x?.eval ?? undefined,
|
||||||
|
temp_eval: x?.temp_eval ?? undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
this.quickEval(pos, raw);
|
||||||
|
}
|
||||||
|
|
||||||
public getRowHeight(row: number) {
|
public getRowHeight(row: number) {
|
||||||
return this.row_heights[row] ?? this.default_row_height;
|
return this.row_heights[row] ?? this.default_row_height;
|
||||||
}
|
}
|
||||||
@@ -107,16 +124,19 @@ class Grid {
|
|||||||
public startEditing(pos: Position) {
|
public startEditing(pos: Position) {
|
||||||
this.active_cell = pos;
|
this.active_cell = pos;
|
||||||
this.editing_cell = pos;
|
this.editing_cell = pos;
|
||||||
|
|
||||||
|
let cell = this.getCell(pos);
|
||||||
|
if (!cell) return;
|
||||||
|
cell.temp_eval = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public stopEditing(pos: Position) {
|
public stopEditing(pos: Position) {
|
||||||
this.editing_cell = null;
|
this.editing_cell = null;
|
||||||
this.setCell(pos, this.getCell(pos));
|
this.setCell(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
public stopEditingActive() {
|
public stopEditingActive() {
|
||||||
if (this.active_cell == null) return;
|
if (this.active_cell == null) return;
|
||||||
|
|
||||||
this.stopEditing(this.active_cell);
|
this.stopEditing(this.active_cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,11 +158,12 @@ class Grid {
|
|||||||
this.external_editing_cell = pos;
|
this.external_editing_cell = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getActiveCell(): CellT {
|
public getActiveCell(): CellT | undefined {
|
||||||
if (this.active_cell === null)
|
if (this.active_cell === null)
|
||||||
return {
|
return {
|
||||||
raw_val: '',
|
raw: '',
|
||||||
val: undefined
|
temp_raw: '',
|
||||||
|
eval: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.getCell(this.active_cell);
|
return this.getCell(this.active_cell);
|
||||||
@@ -179,16 +200,22 @@ class Grid {
|
|||||||
}
|
}
|
||||||
case 'set': {
|
case 'set': {
|
||||||
if (msg.cell === undefined) {
|
if (msg.cell === undefined) {
|
||||||
console.error('Expected cell ref for SET msgponse from server.');
|
console.error('Expected cell ref for SET msg from server.');
|
||||||
return;
|
return;
|
||||||
} else if (msg.eval === undefined) {
|
} else if (msg.eval === undefined) {
|
||||||
console.error('Expected cell value for SET msgponse from server.');
|
console.error('Expected cell value for SET msg from server.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.data[Position.key(msg.cell.row, msg.cell.col)] = {
|
let pos = new Position(msg.cell.row, msg.cell.col);
|
||||||
raw_val: msg.raw ?? '',
|
|
||||||
val: msg.eval
|
let x = this.data[pos.key()];
|
||||||
|
|
||||||
|
this.data[pos.key()] = {
|
||||||
|
raw: msg.raw ?? '',
|
||||||
|
eval: msg.eval,
|
||||||
|
temp_raw: x?.temp_raw ?? '',
|
||||||
|
temp_eval: x?.temp_eval ?? undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -200,9 +227,23 @@ class Grid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const m of msg.bulk_msgs) this.handle_msg(m);
|
for (const m of msg.bulk_msgs) this.handle_msg(m);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case 'eval': {
|
case 'eval': {
|
||||||
// TODO
|
if (msg.cell === undefined) {
|
||||||
|
console.error('Expected cell ref for EVAL msg from server.');
|
||||||
|
return;
|
||||||
|
} else if (msg.eval === undefined) {
|
||||||
|
console.error('Expected cell value for EVAL msg from server.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pos = new Position(msg.cell.row, msg.cell.col);
|
||||||
|
if (this.data[pos.key()] === undefined) return;
|
||||||
|
|
||||||
|
this.data[pos.key()].temp_eval = msg.eval;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,9 +45,11 @@ type Eval =
|
|||||||
| { err: LeadErr }
|
| { err: LeadErr }
|
||||||
| 'unset';
|
| 'unset';
|
||||||
|
|
||||||
interface CellT {
|
interface CellT {
|
||||||
raw_val: string;
|
raw: string;
|
||||||
val?: Eval;
|
temp_raw: string;
|
||||||
|
temp_eval?: Eval;
|
||||||
|
eval?: Eval;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type { Eval, LeadMsg, LeadErr, Literal, CellRef, LiteralValue, CellT };
|
export type { Eval, LeadMsg, LeadErr, Literal, CellRef, LiteralValue, CellT };
|
||||||
|
|||||||
17
frontend/src/lib/components/ui/popover/index.ts
Normal file
17
frontend/src/lib/components/ui/popover/index.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { Popover as PopoverPrimitive } from "bits-ui";
|
||||||
|
import Content from "./popover-content.svelte";
|
||||||
|
import Trigger from "./popover-trigger.svelte";
|
||||||
|
const Root = PopoverPrimitive.Root;
|
||||||
|
const Close = PopoverPrimitive.Close;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Content,
|
||||||
|
Trigger,
|
||||||
|
Close,
|
||||||
|
//
|
||||||
|
Root as Popover,
|
||||||
|
Content as PopoverContent,
|
||||||
|
Trigger as PopoverTrigger,
|
||||||
|
Close as PopoverClose,
|
||||||
|
};
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
import { Popover as PopoverPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
sideOffset = 4,
|
||||||
|
align = "center",
|
||||||
|
portalProps,
|
||||||
|
...restProps
|
||||||
|
}: PopoverPrimitive.ContentProps & {
|
||||||
|
portalProps?: PopoverPrimitive.PortalProps;
|
||||||
|
} = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<PopoverPrimitive.Portal {...portalProps}>
|
||||||
|
<PopoverPrimitive.Content
|
||||||
|
bind:ref
|
||||||
|
data-slot="popover-content"
|
||||||
|
{sideOffset}
|
||||||
|
{align}
|
||||||
|
class={cn(
|
||||||
|
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--bits-popover-content-transform-origin) outline-hidden z-50 w-72 rounded-md border p-4 shadow-md",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
</PopoverPrimitive.Portal>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
import { Popover as PopoverPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
...restProps
|
||||||
|
}: PopoverPrimitive.TriggerProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<PopoverPrimitive.Trigger
|
||||||
|
bind:ref
|
||||||
|
data-slot="popover-trigger"
|
||||||
|
class={cn("", className)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Tooltip as TooltipPrimitive } from "bits-ui";
|
import { Tooltip as TooltipPrimitive } from 'bits-ui';
|
||||||
import { cn } from "$lib/utils.js";
|
import { cn } from '$lib/utils.js';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
class: className,
|
class: className,
|
||||||
sideOffset = 0,
|
sideOffset = 0,
|
||||||
side = "top",
|
side = 'top',
|
||||||
children,
|
children,
|
||||||
arrowClasses,
|
arrowClasses,
|
||||||
...restProps
|
...restProps
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
{sideOffset}
|
{sideOffset}
|
||||||
{side}
|
{side}
|
||||||
class={cn(
|
class={cn(
|
||||||
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--bits-tooltip-content-transform-origin) z-50 w-fit text-balance rounded-md px-3 py-1.5 text-xs",
|
'z-[400] w-fit origin-(--bits-tooltip-content-transform-origin) animate-in rounded-md bg-primary px-3 py-1.5 text-xs text-balance text-primary-foreground fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
@@ -32,11 +32,11 @@
|
|||||||
{#snippet child({ props })}
|
{#snippet child({ props })}
|
||||||
<div
|
<div
|
||||||
class={cn(
|
class={cn(
|
||||||
"bg-primary z-50 size-2.5 rotate-45 rounded-[2px]",
|
'z-50 size-2.5 rotate-45 rounded-[2px] bg-primary',
|
||||||
"data-[side=top]:translate-x-1/2 data-[side=top]:translate-y-[calc(-50%_+_2px)]",
|
'data-[side=top]:translate-x-1/2 data-[side=top]:translate-y-[calc(-50%_+_2px)]',
|
||||||
"data-[side=bottom]:-translate-x-1/2 data-[side=bottom]:-translate-y-[calc(-50%_+_1px)]",
|
'data-[side=bottom]:-translate-x-1/2 data-[side=bottom]:-translate-y-[calc(-50%_+_1px)]',
|
||||||
"data-[side=right]:translate-x-[calc(50%_+_2px)] data-[side=right]:translate-y-1/2",
|
'data-[side=right]:translate-x-[calc(50%_+_2px)] data-[side=right]:translate-y-1/2',
|
||||||
"data-[side=left]:-translate-y-[calc(50%_-_3px)]",
|
'data-[side=left]:-translate-y-[calc(50%_-_3px)]',
|
||||||
arrowClasses
|
arrowClasses
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
Reference in New Issue
Block a user