🙃
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { Input } from '$lib/components/ui/input/index.js';
|
||||
import clsx from 'clsx';
|
||||
import type { CellT } from './utils';
|
||||
|
||||
let {
|
||||
cla = '',
|
||||
width = '80px',
|
||||
height = '30px',
|
||||
raw_val = $bindable(''),
|
||||
val = undefined,
|
||||
cell = $bindable(undefined),
|
||||
onmousedown = () => {},
|
||||
startediting = () => {},
|
||||
stopediting = () => {},
|
||||
@@ -17,8 +17,7 @@
|
||||
cla?: string;
|
||||
width?: string;
|
||||
height?: string;
|
||||
raw_val?: string;
|
||||
val?: LiteralValue | undefined;
|
||||
cell?: CellT;
|
||||
onmousedown?: (e: MouseEvent) => void;
|
||||
startediting?: () => void;
|
||||
stopediting?: () => void;
|
||||
@@ -31,7 +30,7 @@
|
||||
queueMicrotask(() => {
|
||||
const el = node.querySelector('input') as HTMLInputElement | null;
|
||||
if (el !== null) {
|
||||
el.value = raw_val;
|
||||
el.value = cell?.raw_val ?? '';
|
||||
el.focus();
|
||||
}
|
||||
});
|
||||
@@ -56,7 +55,11 @@
|
||||
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"
|
||||
onblur={(e) => {
|
||||
raw_val = (e.target as HTMLInputElement).value;
|
||||
cell = {
|
||||
isErr: false,
|
||||
val: undefined,
|
||||
raw_val: (e.target as HTMLInputElement).value
|
||||
};
|
||||
stopediting();
|
||||
}}
|
||||
/>
|
||||
@@ -69,12 +72,12 @@
|
||||
style:height
|
||||
class={clsx('placeholder bg-background p-1', { active }, cla)}
|
||||
>
|
||||
{#if raw_val !== '' || val !== ''}
|
||||
<span class="pointer-events-none select-none">
|
||||
{#if val !== undefined}
|
||||
{val}
|
||||
{#if cell && (cell.raw_val !== '' || cell.val !== '')}
|
||||
<span class={clsx('pointer-events-none select-none', { err: cell.isErr })}>
|
||||
{#if cell.val}
|
||||
{cell.val}
|
||||
{:else}
|
||||
{raw_val}
|
||||
{cell.raw_val}
|
||||
{/if}
|
||||
</span>
|
||||
{/if}
|
||||
@@ -94,4 +97,21 @@
|
||||
border: 1px solid var(--color-primary);
|
||||
outline: 1px solid var(--color-primary);
|
||||
}
|
||||
|
||||
.active:has(.err),
|
||||
.placeholder:has(.err) {
|
||||
position: relative; /* needed for absolute positioning */
|
||||
}
|
||||
|
||||
.active:has(.err)::after,
|
||||
.placeholder:has(.err)::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 12px solid red; /* size & color of the triangle */
|
||||
border-left: 12px solid transparent;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import Cell from '$lib/components/grid/cell.svelte';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import CellHeader from './cell-header.svelte';
|
||||
import { colToStr, getEvalLiteral, refToStr, type CellT } from './utils';
|
||||
import { colToStr, getEvalLiteral, isErr, refToStr, type CellT } from './utils';
|
||||
import clsx from 'clsx';
|
||||
|
||||
let {
|
||||
@@ -44,7 +44,7 @@
|
||||
console.error('Expected cell value for SET msgponse from server.');
|
||||
return;
|
||||
}
|
||||
setCellVal(msg.cell.row, msg.cell.col, getEvalLiteral(msg.eval));
|
||||
setCellVal(msg.cell.row, msg.cell.col, getEvalLiteral(msg.eval), isErr(msg.eval));
|
||||
break;
|
||||
}
|
||||
case 'bulk': {
|
||||
@@ -107,38 +107,41 @@
|
||||
|
||||
const key = (i: number, j: number) => `${i}:${j}`;
|
||||
|
||||
const getCell = (i: number, j: number) => grid_vals[key(i, j)] ?? undefined;
|
||||
const getCell = (i: number, j: number) => grid_vals[key(i, j)];
|
||||
|
||||
const getCellRaw = (i: number, j: number) => getCell(i, j)?.raw_val ?? '';
|
||||
const setCellRaw = (i: number, j: number, val: string) => {
|
||||
if (grid_vals[key(i, j)] === undefined) {
|
||||
grid_vals[key(i, j)] = {
|
||||
raw_val: val,
|
||||
isErr: false,
|
||||
val: undefined
|
||||
};
|
||||
} else {
|
||||
grid_vals[key(i, j)].raw_val = val;
|
||||
}
|
||||
};
|
||||
const getCellVal = (i: number, j: number) => getCell(i, j)?.val ?? undefined;
|
||||
const setCellVal = (i: number, j: number, val: LiteralValue) => {
|
||||
const getCellVal = (i: number, j: number) => getCell(i, j);
|
||||
const setCellVal = (i: number, j: number, val: LiteralValue, isErr: boolean) => {
|
||||
if (grid_vals[key(i, j)] === undefined) {
|
||||
console.warn('Cell raw value was undefined but recieved eval.');
|
||||
} else {
|
||||
grid_vals[key(i, j)].val = val;
|
||||
let cell = grid_vals[key(i, j)];
|
||||
cell.val = val;
|
||||
cell.isErr = isErr;
|
||||
}
|
||||
};
|
||||
|
||||
const setCell = (row: number, col: number, v: string | undefined) => {
|
||||
const setCell = (row: number, col: number, v: CellT | undefined) => {
|
||||
// ignore “no value” so we don’t create keys on mount
|
||||
if (v == null || v === '') delete grid_vals[key(row, col)];
|
||||
if (v?.raw_val == null || v.raw_val === '') delete grid_vals[key(row, col)];
|
||||
else {
|
||||
setCellRaw(row, col, v);
|
||||
setCellRaw(row, col, v.raw_val);
|
||||
|
||||
let msg: LeadMsg = {
|
||||
msg_type: 'set',
|
||||
cell: { row, col },
|
||||
raw: v
|
||||
raw: v.raw_val
|
||||
};
|
||||
|
||||
socket.send(JSON.stringify(msg));
|
||||
@@ -237,8 +240,7 @@
|
||||
onmousedown={(e) => {
|
||||
handleCellInteraction(i, j, e);
|
||||
}}
|
||||
bind:raw_val={() => getCellRaw(i, j), (v) => setCell(i, j, v)}
|
||||
val={getCellVal(i, j)}
|
||||
bind:cell={() => getCell(i, j), (v) => setCell(i, j, v)}
|
||||
active={active_cell !== null && active_cell[0] === i && active_cell[1] === j}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
@@ -25,5 +25,16 @@ interface EvalCellRef {
|
||||
reference: CellRef;
|
||||
}
|
||||
|
||||
interface LeadErr {
|
||||
code: 'DivZero' | 'TypeErr' | 'Syntax' | 'Server' | 'Unsupported';
|
||||
desc: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
// Tagged union
|
||||
type Eval = { literal: Literal } | { cellref: EvalCellRef } | { range: Range } | 'unset';
|
||||
type Eval =
|
||||
| { literal: Literal }
|
||||
| { cellref: EvalCellRef }
|
||||
| { range: Range }
|
||||
| { err: LeadErr }
|
||||
| 'unset';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export interface CellT {
|
||||
raw_val: string;
|
||||
val: LiteralValue | undefined;
|
||||
isErr: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,6 +48,12 @@ export function getEvalLiteral(value: Eval): LiteralValue {
|
||||
if (value === 'unset') return '';
|
||||
if ('literal' in value) return value.literal.value;
|
||||
if ('cellref' in value) return getEvalLiteral(value.cellref.eval);
|
||||
if ('err' in value) return `err: ${value.err.code}`;
|
||||
// if ('range' in value) return 'err';
|
||||
return 'todo!';
|
||||
}
|
||||
|
||||
export function isErr(value: Eval): boolean {
|
||||
if (value === 'unset') return false;
|
||||
return 'err' in value;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user