refactor(createTypographyControl): createControlStore rewrote to runes

This commit is contained in:
Ilia Mashkov
2026-01-07 16:53:17 +03:00
parent baff3b9e27
commit 76f27a64b2
10 changed files with 178 additions and 368 deletions

View File

@@ -1,4 +1,5 @@
<script lang="ts">
import type { TypographyControl } from '$shared/lib';
import { Button } from '$shared/shadcn/ui/button';
import * as ButtonGroup from '$shared/shadcn/ui/button-group';
import { Input } from '$shared/shadcn/ui/input';
@@ -9,22 +10,6 @@ import PlusIcon from '@lucide/svelte/icons/plus';
import type { ChangeEventHandler } from 'svelte/elements';
interface ComboControlProps {
/**
* Controlled value
*/
value: number;
/**
* Callback function to handle value change
*/
onChange: (value: number) => void;
/**
* Callback function to handle increase
*/
onIncrease: () => void;
/**
* Callback function to handle decrease
*/
onDecrease: () => void;
/**
* Text for increase button aria-label
*/
@@ -33,59 +18,35 @@ interface ComboControlProps {
* Text for decrease button aria-label
*/
decreaseLabel?: string;
/**
* Flag for disabling increase button
*/
increaseDisabled?: boolean;
/**
* Flag for disabling decrease button
*/
decreaseDisabled?: boolean;
/**
* Text for control button aria-label
*/
controlLabel?: string;
/**
* Minimum value for the input
* Control instance
*/
minValue?: number;
/**
* Maximum value for the input
*/
maxValue?: number;
/**
* Step value for the slider
*/
step?: number;
control: TypographyControl;
}
const {
value,
onChange,
onIncrease,
onDecrease,
increaseLabel,
control,
decreaseLabel,
increaseDisabled,
decreaseDisabled,
increaseLabel,
controlLabel,
minValue = 0,
maxValue = 100,
step = 1,
}: ComboControlProps = $props();
// Local state for the slider to prevent infinite loops
let sliderValue = $state(value);
let sliderValue = $state(Number(control.value));
// Sync sliderValue when external value changes
$effect(() => {
sliderValue = value;
sliderValue = Number(control.value);
});
const handleInputChange: ChangeEventHandler<HTMLInputElement> = event => {
const parsedValue = parseFloat(event.currentTarget.value);
if (!isNaN(parsedValue)) {
onChange(parsedValue);
control.value = parsedValue;
}
};
@@ -93,8 +54,8 @@ const handleInputChange: ChangeEventHandler<HTMLInputElement> = event => {
* Handle slider value change.
* The Slider component passes the value as a number directly.
*/
const handleSliderChange = (value: number) => {
onChange(value);
const handleSliderChange = (newValue: number) => {
control.value = newValue;
};
</script>
@@ -103,8 +64,8 @@ const handleSliderChange = (value: number) => {
variant="outline"
size="icon"
aria-label={decreaseLabel}
onclick={onDecrease}
disabled={decreaseDisabled}
onclick={control.decrease}
disabled={control.isAtMin}
>
<MinusIcon />
</Button>
@@ -117,16 +78,16 @@ const handleSliderChange = (value: number) => {
size="icon"
aria-label={controlLabel}
>
{value}
{control.value}
</Button>
{/snippet}
</Popover.Trigger>
<Popover.Content class="w-auto p-4">
<div class="flex flex-col items-center gap-3">
<Slider
min={minValue}
max={maxValue}
step={step}
min={control.min}
max={control.max}
step={control.step}
value={sliderValue}
onValueChange={handleSliderChange}
type="single"
@@ -134,10 +95,10 @@ const handleSliderChange = (value: number) => {
class="h-48"
/>
<Input
value={String(value)}
min={minValue}
max={maxValue}
value={control.value}
onchange={handleInputChange}
min={control.min}
max={control.max}
class="w-16 text-center"
/>
</div>
@@ -147,8 +108,8 @@ const handleSliderChange = (value: number) => {
variant="outline"
size="icon"
aria-label={increaseLabel}
onclick={onIncrease}
disabled={increaseDisabled}
onclick={control.increase}
disabled={control.isAtMax}
>
<PlusIcon />
</Button>