logic-mesh 0.9.0

Control logic engine using event based and reactive blocks written in Rust.
Documentation
<script lang="ts">
	import { Handle, Position } from '@xyflow/svelte';
	import { onMount } from 'svelte';
	import Chart from 'chart.js/auto';
	import BlockCommons from '../BlockCommons.svelte';
	import type { Block } from '$lib/Block';
	import { numericValue } from '$lib/utils';

	interface Props {
		data: { value: Block };
	}

	let { data }: Props = $props();

	const block = $derived(data.value);
	const inputKey = $derived(Object.keys(block.inputs)[0] ?? 'in');

	const chartId = `chart-${crypto.randomUUID()}`;
	let chart: Chart;
	let chartYAxis: number[] = [];
	let chartXAxis: number[] = [];
	let count = 0;

	function draw() {
		chart = new Chart(document.getElementById(chartId) as HTMLCanvasElement, {
			type: 'line',
			data: {
				labels: chartXAxis,
				datasets: [{ data: chartYAxis, fill: false, tension: 0.4 }],
			},
			options: {
				animation: false,
				plugins: { legend: { display: false } },
				elements: { point: { radius: 0 } },
				scales: { y: { ticks: { stepSize: 10 } } },
			},
		});
	}

	onMount(() => {
		draw();
	});

	let prevInputValue: unknown;
	$effect(() => {
		const curVal = block.inputs.in.value;
		if (curVal !== prevInputValue) {
			prevInputValue = curVal;
			if (chart) {
				chart.destroy();
				draw();

				chartXAxis.push(count++);
				chartXAxis = chartXAxis.slice(-10);

				const num = numericValue(curVal);
				chartYAxis.push(num == null ? NaN : num);
				chartYAxis = chartYAxis.slice(-10);
			}
		}
	});
</script>

<BlockCommons data={block}>
	<div class="pin-row pin-row-input">
		<Handle id={inputKey} type="target" position={Position.Left} class="handle-dot handle-input" />
		<span class="pin-name">{inputKey}</span>
	</div>

	<canvas id={chartId} width="200" height="100"></canvas>
</BlockCommons>

<style>
	.pin-row {
		display: flex;
		align-items: center;
		padding: 1px 8px;
		gap: 6px;
		min-height: 20px;
		position: relative;
	}
	.pin-row-input { justify-content: flex-start; }
	.pin-name { font-size: 11px; }

	:global(.handle-dot) {
		width: 8px !important;
		height: 8px !important;
		border-radius: 50% !important;
		min-width: 0 !important;
		border: 1.5px solid white !important;
	}
	:global(.handle-input) { background: #6b9eff !important; }
</style>