Input Elements

Toggle Lock

A beatifully animated locking toggle.

/routes/forms/toggles-spec/+page.svelte

<script lang="ts">
	import { NumberInput, ToggleLock } from '@leon8ix/jhana-ui';

	let value = $state(1);
	let disabled = $state(false);
</script>

<div class="input-group">
	<NumberInput bind:value class="w-sm" {disabled} />
	<ToggleLock bind:checked={disabled} />
</div>

Toggle Link

A beatifully animated linking toggle. Specifically intended for locking an aspect ratio.

/routes/forms/toggles-spec/+page.svelte

<script lang="ts">
	import { NumberInput, ToggleLink } from '@leon8ix/jhana-ui';
	import { rnd } from '@leon8ix/utils';
	import type { InputEvent } from '@leon8ix/utils/dom';

	let v1: number | null = $state(1);
	let v2: number | null = $state(2);
	let ratio: number | null = $state(null);

	function link(e: InputEvent) {
		if (!e.currentTarget.checked) ratio = null;
		else ratio = (v1 || (v1 = 1)) / (v2 || (v2 = 1));
	}
	function getNum(e: InputEvent) {
		const val = e.currentTarget.value;
		if (!val.length) return null;
		const num = Number(val);
		return isNaN(num) ? null : num;
	}
	function setV1(e: InputEvent) {
		const val = getNum(e);
		v1 = val;
		if (ratio) v2 = val ? val / ratio : null;
	}
	function setV2(e: InputEvent) {
		const val = getNum(e);
		v2 = val;
		if (ratio) v1 = val ? val * ratio : null;
	}
</script>

<div class="input-group">
	<NumberInput value={v1 && rnd(v1, 4)} oninput={setV1} class="w-md" />
	<ToggleLink checked={!!ratio} oninput={link} />
	<NumberInput value={v2 && rnd(v2, 4)} oninput={setV2} class="w-md" />
</div>

Specialized Fieldset Sample

Here you can see, how you might pull all of this together. This sample does not implement the logic. It only demonstartes the structure and classes.

/routes/forms/toggles-spec/+page.svelte

<script lang="ts">
	import { NumberInput, ToggleLink, ToggleLock } from '@leon8ix/jhana-ui';

	let linkBleed = $state(true);
	let linkSize = $state(true);
	let locked = $state(false);
	type Config = Record<'bleed' | 'bleedX' | 'bleedY' | 'scale' | 'width' | 'height', number | null>;
	let config: Config = $state({ bleed: 2, bleedX: 2, bleedY: 2, scale: 1, width: 100, height: 100 });
</script>

<div class="dialog space-y-sm" style="width: fit-content">
	<h3 class="h4">Scaling and Size</h3>
	<fieldset class="input-group">
		<NumberInput label="Bleed" bind:value={config.bleed} class="w-md" />
		<ToggleLock bind:checked={locked} />
		<NumberInput label="X-Bleed" bind:value={config.bleedX} class="w-md" />
		<ToggleLink bind:checked={linkBleed} />
		<NumberInput label="Y-Bleed" bind:value={config.bleedY} class="w-md" />
	</fieldset>
	<fieldset class="input-group">
		<NumberInput label="Scale" bind:value={config.scale} class="w-md" step="0.1" min="0" />
		<ToggleLock checked={!locked} oninput={() => (locked = !locked)} />
		<NumberInput label="Width" bind:value={config.width} class="w-md" />
		<ToggleLink bind:checked={linkSize} />
		<NumberInput label="Height" bind:value={config.height} class="w-md" />
	</fieldset>
</div>

Scaling and Size