Migrate terra reactive APIs and introduce air spinner

main
dev 6 months ago
parent 20cfd3f50b
commit 8d5e47b2a7

@ -43,7 +43,7 @@
};
</script>
<div class="page" class:dark={actx.uiux.theme.resolved === 'dark'}>
<div class="page h-full w-full" class:dark={actx.uiux.theme.resolved === 'dark' }>
<!-- ── HEADER ───────────────────────────────────────────────────────────── -->
<header>
@ -74,6 +74,8 @@
<a href="/test/label" class="comp-link">Label</a>
<a href="/test/progress" class="comp-link">Progress</a>
<a href="/test/meter" class="comp-link">Meter</a>
<a href="/test/air/spinner" class="comp-link">Spinner</a>
<a href="/test/air" class="comp-link">Air Hub</a>
<a href="/test/toggle" class="comp-link">Toggle</a>
<a href="/test/toggle-group" class="comp-link">ToggleGroup</a>
<a href="/test/pagination" class="comp-link">Pagination</a>
@ -629,4 +631,5 @@
.log-msg { color: #666; }
.page.dark .log-msg { color: #555; }
.muted { color: #aaa; font-size: .75rem; font-style: italic; }
</style>
</style>

@ -0,0 +1,178 @@
<script lang="ts">
type DemoItem = {
name: string;
path: string;
status?: 'stable' | 'wip';
};
type DemoGroup = {
title: string;
description: string;
items: DemoItem[];
};
const groups: DemoGroup[] = [
{
title: 'Visual / Styled',
description: 'Componentes visuales u opinionated construidos sobre terra.',
items: [{ name: 'Spinner', path: '/test/air/spinner', status: 'stable' }],
},
];
const totals = {
all: groups.reduce((count, group) => count + group.items.length, 0),
stable: groups.reduce(
(count, group) => count + group.items.filter((item) => item.status !== 'wip').length,
0,
),
wip: groups.reduce(
(count, group) => count + group.items.filter((item) => item.status === 'wip').length,
0,
),
};
</script>
<svelte:head>
<title>Air Tests</title>
</svelte:head>
<div class="page">
<header class="hero">
<div>
<p class="eyebrow">Air</p>
<h1>Test hub</h1>
<p class="lead">Punto único para revisar los componentes visuales construidos sobre terra.</p>
</div>
<div class="stats">
<div class="stat">
<span class="stat-label">Total</span>
<strong>{totals.all}</strong>
</div>
<div class="stat">
<span class="stat-label">Estables</span>
<strong>{totals.stable}</strong>
</div>
<div class="stat stat--wip">
<span class="stat-label">WIP</span>
<strong>{totals.wip}</strong>
</div>
</div>
</header>
<nav class="top-links">
<a href="/test">Indice general</a>
<a href="/test/terra">Terra hub</a>
<a href="/test/air/spinner">Spinner</a>
</nav>
<main class="grid">
{#each groups as group}
<section class="card">
<header class="card-header">
<h2>{group.title}</h2>
<p>{group.description}</p>
</header>
<div class="links">
{#each group.items as item}
<a class="link" href={item.path}>
<span>{item.name}</span>
<span class:badge={true} class:badge--wip={item.status === 'wip'}>
{item.status === 'wip' ? 'WIP' : 'OK'}
</span>
</a>
{/each}
</div>
</section>
{/each}
</main>
</div>
<style>
:global(*, *::before, *::after) { box-sizing: border-box; }
.page {
min-height: 100vh;
padding: 2rem;
background: #111827;
color: #f3f4f6;
font-family: Inter, system-ui, sans-serif;
}
.hero {
display: flex;
justify-content: space-between;
gap: 1.5rem;
align-items: flex-start;
margin-bottom: 1.5rem;
padding: 1.5rem;
border: 1px solid #374151;
border-radius: 18px;
background: linear-gradient(180deg, rgba(31, 41, 55, 0.98), rgba(17, 24, 39, 0.98));
}
.eyebrow {
margin: 0 0 .35rem;
font-size: .72rem;
font-weight: 700;
letter-spacing: .14em;
text-transform: uppercase;
color: #93c5fd;
}
h1 { margin: 0; font-size: 2rem; line-height: 1.1; }
.lead { max-width: 60ch; margin: .65rem 0 0; color: #cbd5e1; line-height: 1.5; }
.stats { display: flex; gap: .75rem; flex-wrap: wrap; }
.stat {
min-width: 96px;
padding: .85rem 1rem;
border-radius: 14px;
background: #1f2937;
border: 1px solid #374151;
}
.stat-label { display: block; font-size: .72rem; color: #cbd5e1; margin-bottom: .25rem; }
.stat strong { font-size: 1.15rem; }
.stat--wip strong { color: #fbbf24; }
.top-links { display: flex; gap: .75rem; flex-wrap: wrap; margin-bottom: 1.25rem; }
.top-links a,
.link { color: inherit; text-decoration: none; }
.top-links a {
padding: .55rem .85rem;
border-radius: 999px;
background: #1f2937;
border: 1px solid #374151;
color: #e5e7eb;
}
.top-links a:hover,
.link:hover { border-color: #93c5fd; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1rem; }
.card {
padding: 1.15rem;
border-radius: 18px;
background: #1f2937;
border: 1px solid #374151;
}
.card-header h2 { margin: 0; font-size: 1rem; }
.card-header p { margin: .45rem 0 0; font-size: .88rem; line-height: 1.45; color: #cbd5e1; }
.links { display: flex; flex-direction: column; gap: .6rem; margin-top: 1rem; }
.link {
display: flex;
align-items: center;
justify-content: space-between;
gap: .75rem;
padding: .75rem .85rem;
border-radius: 14px;
background: #111827;
border: 1px solid #374151;
}
.badge {
padding: .18rem .48rem;
border-radius: 999px;
font-size: .72rem;
font-weight: 700;
letter-spacing: .04em;
background: rgba(34, 197, 94, .14);
color: #86efac;
}
.badge--wip {
background: rgba(251, 191, 36, .14);
color: #fbbf24;
}
</style>

@ -0,0 +1,176 @@
<script lang="ts">
import { Spinner } from '$uix/air';
let size = $state<'sm' | 'md' | 'lg' | 'xl'>('md');
let speed = $state<'slow' | 'normal' | 'fast'>('normal');
let variant = $state<'circular' | 'dots' | 'bars' | 'pulse'>('circular');
const variants = ['circular', 'dots', 'bars', 'pulse'] as const;
const sizes = ['sm', 'md', 'lg', 'xl'] as const;
const speeds = ['slow', 'normal', 'fast'] as const;
</script>
<div class="page">
<h1>Spinner</h1>
<section class="card">
<h2>Playground</h2>
<div class="playground">
<Spinner.Root variant={variant} size={size} speed={speed} class="spinner spinner--hero" />
<div class="controls">
<div class="control">
<span>Variant</span>
<div class="chips">
{#each variants as item}
<button class:active={variant === item} onclick={() => (variant = item)}>{item}</button>
{/each}
</div>
</div>
<div class="control">
<span>Size</span>
<div class="chips">
{#each sizes as item}
<button class:active={size === item} onclick={() => (size = item)}>{item}</button>
{/each}
</div>
</div>
<div class="control">
<span>Speed</span>
<div class="chips">
{#each speeds as item}
<button class:active={speed === item} onclick={() => (speed = item)}>{item}</button>
{/each}
</div>
</div>
</div>
</div>
</section>
<section class="card">
<h2>Variants</h2>
<div class="grid grid--variants">
{#each variants as item}
<div class="demo">
<Spinner.Root variant={item} size="lg" class="spinner" label={`Loading (${item})`} />
<span>{item}</span>
</div>
{/each}
</div>
</section>
<section class="card">
<h2>Custom</h2>
<div class="grid grid--variants">
<Spinner.Root size="lg" class="spinner">
<Spinner.Circular size="lg" speed="fast" />
</Spinner.Root>
</div>
</section>
<section class="card">
<h2>Sizes</h2>
<div class="grid grid--sizes">
{#each sizes as item}
<div class="demo">
<Spinner.Root variant="circular" size={item} class="spinner" />
<span>{item}</span>
</div>
{/each}
</div>
</section>
<section class="card">
<h2>In context</h2>
<div class="panel">
<button class="action" disabled>Saving <Spinner.Root variant="dots" size="sm" speed="fast" class="spinner spinner--inline" /></button>
<div class="status">
<Spinner.Root variant="pulse" size="sm" class="spinner spinner--success" />
<span>Syncing background data</span>
</div>
</div>
</section>
</div>
<style>
.page {
max-width: 900px;
margin: 0 auto;
padding: 2rem 1.5rem;
font-family: 'DM Mono', monospace;
display: flex;
flex-direction: column;
gap: 1.5rem;
}
h1 { font-size: 1.4rem; font-weight: 700; letter-spacing: .05em; }
.card {
border: 1.5px solid #e0ddd6;
border-radius: 4px;
padding: 1.25rem;
display: flex;
flex-direction: column;
gap: 1rem;
}
h2 { font-size: .65rem; font-weight: 700; letter-spacing: .2em; text-transform: uppercase; color: #999; }
.playground {
display: grid;
grid-template-columns: 140px 1fr;
gap: 1.5rem;
align-items: center;
}
.controls { display: flex; flex-direction: column; gap: .85rem; }
.control { display: flex; flex-direction: column; gap: .35rem; }
.control span { font-size: .72rem; color: #777; }
.chips { display: flex; flex-wrap: wrap; gap: .4rem; }
button {
padding: .35rem .7rem;
border: 1px solid #d6d1c7;
background: #fff;
border-radius: 999px;
font: inherit;
font-size: .72rem;
cursor: pointer;
}
button.active { background: #111827; color: #fff; border-color: #111827; }
.grid { display: grid; gap: 1rem; }
.grid--variants { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid--sizes { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.demo {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: .75rem;
padding: 1rem;
border: 1px dashed #ddd6c9;
border-radius: 4px;
min-height: 110px;
}
.demo span { font-size: .72rem; color: #777; }
.panel { display: flex; flex-direction: column; gap: .9rem; }
.action {
display: inline-flex;
align-items: center;
justify-content: center;
gap: .55rem;
padding: .7rem 1rem;
border-radius: 4px;
border: none;
background: #111827;
color: #fff;
opacity: .9;
cursor: default;
}
.status { display: inline-flex; align-items: center; gap: .6rem; font-size: .82rem; color: #444; }
:global(.spinner) { display: inline-flex; color: #111827; }
:global(.spinner--hero) { color: #2563eb; }
:global(.spinner--inline) { color: currentColor; }
:global(.spinner--success) { color: #16a34a; }
@media (max-width: 720px) {
.playground { grid-template-columns: 1fr; }
.grid--variants, .grid--sizes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
</style>

@ -121,6 +121,7 @@
<a href="/test">Indice general</a>
<a href="/test/tooltip">Último floating</a>
<a href="/test/link-preview">Último link-preview</a>
<a href="/test/air/spinner">Spinner (air)</a>
</nav>
<main class="grid">
@ -306,3 +307,5 @@
color: #fbbf24;
}
</style>

@ -0,0 +1 @@
export * as Spinner from './spinner';

@ -0,0 +1,48 @@
<script lang="ts">
import { mergeProps } from '$terra/utils';
import { resolveSpinnerSizeToken, resolveSpinnerSpeedToken, useSpinnerRootState } from '$terra/spinner/spinner.svelte';
import type { SpinnerBarsProps } from '$terra/spinner/types';
let { size = undefined, speed = undefined, ...restProps }: SpinnerBarsProps = $props();
const rootState = useSpinnerRootState();
const resolvedSize = $derived(resolveSpinnerSizeToken(size ?? rootState?.opts.size.current));
const resolvedSpeed = $derived(resolveSpinnerSpeedToken(speed ?? rootState?.opts.speed.current));
const mergedProps = $derived(mergeProps(restProps, {
class: 'bars',
'aria-hidden': true,
'data-size': resolvedSize,
'data-speed': resolvedSpeed,
}));
</script>
<div {...mergedProps}>
{#each [0, 1, 2, 3, 4] as _item, i}
<span data-index={i}></span>
{/each}
</div>
<style>
.bars { display: inline-flex; align-items: center; height: var(--spinner-size); gap: var(--spinner-gap); }
.bars span {
width: var(--spinner-bar-width);
border-radius: 2px;
background: currentColor;
animation: bars-scale var(--spinner-speed) ease-in-out infinite;
}
.bars span[data-index='1'] { animation-delay: calc(var(--spinner-speed) * 0.1); }
.bars span[data-index='2'] { animation-delay: calc(var(--spinner-speed) * 0.2); }
.bars span[data-index='3'] { animation-delay: calc(var(--spinner-speed) * 0.3); }
.bars span[data-index='4'] { animation-delay: calc(var(--spinner-speed) * 0.4); }
.bars[data-size='sm'] { --spinner-size: 16px; --spinner-gap: 2px; --spinner-bar-width: 2px; }
.bars[data-size='md'] { --spinner-size: 24px; --spinner-gap: 2px; --spinner-bar-width: 3px; }
.bars[data-size='lg'] { --spinner-size: 32px; --spinner-gap: 3px; --spinner-bar-width: 4px; }
.bars[data-size='xl'] { --spinner-size: 48px; --spinner-gap: 5px; --spinner-bar-width: 6px; }
.bars[data-speed='slow'] { --spinner-speed: 1.4s; }
.bars[data-speed='normal'] { --spinner-speed: 0.8s; }
.bars[data-speed='fast'] { --spinner-speed: 0.45s; }
@keyframes bars-scale {
0%, 100% { height: 30%; opacity: 0.4; }
50% { height: 100%; opacity: 1; }
}
</style>

@ -0,0 +1,60 @@
<script lang="ts">
import { mergeProps } from '$terra/utils';
import { resolveSpinnerSizePx, resolveSpinnerSpeedToken, useSpinnerRootState } from '$terra/spinner/spinner.svelte';
import type { SpinnerCircularProps } from '$terra/spinner/types';
let {
size = undefined,
speed = undefined,
...restProps
}: SpinnerCircularProps = $props();
const rootState = useSpinnerRootState();
const resolvedSize = $derived(resolveSpinnerSizePx(size ?? rootState?.opts.size.current));
const resolvedSpeed = $derived(resolveSpinnerSpeedToken(speed ?? rootState?.opts.speed.current));
const radius = 10;
const strokeWidth = 2.5;
const circumference = 2 * Math.PI * radius;
const mergedProps = $derived(
mergeProps(restProps, {
class: 'circular',
'aria-hidden': true,
'data-speed': resolvedSpeed,
width: resolvedSize,
height: resolvedSize,
viewBox: '0 0 24 24',
})
);
</script>
<svg {...mergedProps}>
<circle cx="12" cy="12" r={radius} fill="none" stroke="currentColor" stroke-width={strokeWidth} opacity="0.2" />
<circle
class="spinner-arc"
cx="12"
cy="12"
r={radius}
fill="none"
stroke="currentColor"
stroke-width={strokeWidth}
stroke-linecap="round"
stroke-dasharray={circumference}
stroke-dashoffset={circumference * 0.75}
/>
</svg>
<style>
.circular { display: inline-block; }
.circular[data-speed='slow'] { --spinner-speed: 1.4s; }
.circular[data-speed='normal'] { --spinner-speed: 0.8s; }
.circular[data-speed='fast'] { --spinner-speed: 0.45s; }
.spinner-arc {
transform-box: fill-box;
transform-origin: center;
animation: spinner-rotate var(--spinner-speed) linear infinite;
}
@keyframes spinner-rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
</style>

@ -0,0 +1,47 @@
<script lang="ts">
import { mergeProps } from '$terra/utils';
import { resolveSpinnerSizeToken, resolveSpinnerSpeedToken, useSpinnerRootState } from '$terra/spinner/spinner.svelte';
import type { SpinnerDotsProps } from '$terra/spinner/types';
let { size = undefined, speed = undefined, ...restProps }: SpinnerDotsProps = $props();
const rootState = useSpinnerRootState();
const resolvedSize = $derived(resolveSpinnerSizeToken(size ?? rootState?.opts.size.current));
const resolvedSpeed = $derived(resolveSpinnerSpeedToken(speed ?? rootState?.opts.speed.current));
const mergedProps = $derived(mergeProps(restProps, {
class: 'dots',
'aria-hidden': true,
'data-size': resolvedSize,
'data-speed': resolvedSpeed,
}));
</script>
<div {...mergedProps}>
<span data-index="0"></span>
<span data-index="1"></span>
<span data-index="2"></span>
</div>
<style>
.dots { display: inline-flex; align-items: center; height: var(--spinner-size); gap: var(--spinner-gap); }
.dots span {
width: var(--spinner-dot-size);
height: var(--spinner-dot-size);
border-radius: 50%;
background: currentColor;
animation: dots-bounce var(--spinner-speed) ease-in-out infinite;
}
.dots span[data-index='1'] { animation-delay: calc(var(--spinner-speed) * 0.16); }
.dots span[data-index='2'] { animation-delay: calc(var(--spinner-speed) * 0.32); }
.dots[data-size='sm'] { --spinner-size: 16px; --spinner-gap: 3px; --spinner-dot-size: 4px; }
.dots[data-size='md'] { --spinner-size: 24px; --spinner-gap: 3px; --spinner-dot-size: 5px; }
.dots[data-size='lg'] { --spinner-size: 32px; --spinner-gap: 4px; --spinner-dot-size: 7px; }
.dots[data-size='xl'] { --spinner-size: 48px; --spinner-gap: 7px; --spinner-dot-size: 11px; }
.dots[data-speed='slow'] { --spinner-speed: 1.4s; }
.dots[data-speed='normal'] { --spinner-speed: 0.8s; }
.dots[data-speed='fast'] { --spinner-speed: 0.45s; }
@keyframes dots-bounce {
0%, 80%, 100% { transform: scale(0.6); opacity: 0.4; }
40% { transform: scale(1); opacity: 1; }
}
</style>

@ -0,0 +1,5 @@
export { default as Root } from './spinner.svelte';
export { default as Circular } from './circular.svelte';
export { default as Dots } from './dots.svelte';
export { default as Bars } from './bars.svelte';
export { default as Pulse } from './pulse.svelte';

@ -0,0 +1,61 @@
<script lang="ts">
import { mergeProps } from '$terra/utils';
import { resolveSpinnerSizeToken, resolveSpinnerSpeedToken, useSpinnerRootState } from '$terra/spinner/spinner.svelte';
import type { SpinnerPulseProps } from '$terra/spinner/types';
let { size = undefined, speed = undefined, ...restProps }: SpinnerPulseProps = $props();
const rootState = useSpinnerRootState();
const resolvedSize = $derived(resolveSpinnerSizeToken(size ?? rootState?.opts.size.current));
const resolvedSpeed = $derived(resolveSpinnerSpeedToken(speed ?? rootState?.opts.speed.current));
const mergedProps = $derived(mergeProps(restProps, {
class: 'pulse',
'aria-hidden': true,
'data-size': resolvedSize,
'data-speed': resolvedSpeed,
}));
</script>
<div {...mergedProps}>
<span class="ring ring-1"></span>
<span class="ring ring-2"></span>
<span class="dot"></span>
</div>
<style>
.pulse {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--spinner-size);
height: var(--spinner-size);
}
.ring {
position: absolute;
inset: 0;
border-radius: 50%;
border: 2px solid currentColor;
opacity: 0;
animation: pulse-ring var(--spinner-speed) ease-out infinite;
}
.ring-2 { animation-delay: calc(var(--spinner-speed) * 0.4); }
.dot {
width: 28%;
height: 28%;
border-radius: 50%;
background: currentColor;
opacity: 0.8;
}
.pulse[data-size='sm'] { --spinner-size: 16px; }
.pulse[data-size='md'] { --spinner-size: 24px; }
.pulse[data-size='lg'] { --spinner-size: 32px; }
.pulse[data-size='xl'] { --spinner-size: 48px; }
.pulse[data-speed='slow'] { --spinner-speed: 1.4s; }
.pulse[data-speed='normal'] { --spinner-speed: 0.8s; }
.pulse[data-speed='fast'] { --spinner-speed: 0.45s; }
@keyframes pulse-ring {
0% { transform: scale(0.3); opacity: 0.8; }
100% { transform: scale(1); opacity: 0; }
}
</style>

@ -0,0 +1,32 @@
<script lang="ts">
import { Spinner } from '$terra';
import type { SpinnerRootProps } from '$terra/spinner/types';
import Circular from './circular.svelte';
import Dots from './dots.svelte';
import Bars from './bars.svelte';
import Pulse from './pulse.svelte';
let {
variant = 'circular',
size = 'md',
speed = 'normal',
children,
...restProps
}: SpinnerRootProps = $props();
</script>
<Spinner.Root variant={variant} size={size} speed={speed} {...restProps}>
{#snippet children()}
{#if children}
{@render children()}
{:else if variant === 'circular'}
<Circular size={size} speed={speed} />
{:else if variant === 'dots'}
<Dots size={size} speed={speed} />
{:else if variant === 'bars'}
<Bars size={size} speed={speed} />
{:else if variant === 'pulse'}
<Pulse size={size} speed={speed} />
{/if}
{/snippet}
</Spinner.Root>

@ -4,8 +4,8 @@ import {
readableActive,
writableActive,
type State,
type ActiveValues,
type StateValues,
type ActiveProps,
type StateProps,
} from "../utils/index";
import { Context, watch } from "runed";
import type {
@ -31,7 +31,7 @@ const AccordionItemContext = new Context<AccordionItemState>("Accordion.Item");
interface AccordionBaseStateOpts
extends WithRefOpts,
ActiveValues<{
ActiveProps<{
disabled: boolean;
orientation: Orientation;
loop: boolean;
@ -39,16 +39,16 @@ interface AccordionBaseStateOpts
interface AccordionSingleStateOpts
extends AccordionBaseStateOpts,
StateValues<{ value: string }> {}
StateProps<{ value: string }> {}
interface AccordionMultiStateOpts
extends AccordionBaseStateOpts,
StateValues<{ value: string[] }> {}
StateProps<{ value: string[] }> {}
type AccordionRoot = AccordionSingleState | AccordionMultiState;
interface AccordionItemStateOpts
extends WithRefOpts,
ActiveValues<{
ActiveProps<{
value: string;
disabled: boolean;
}> {
@ -57,27 +57,27 @@ interface AccordionItemStateOpts
interface AccordionTriggerStateOpts
extends WithRefOpts,
ActiveValues<{
ActiveProps<{
disabled: boolean | null | undefined;
tabindex: number;
}> {}
interface AccordionContentStateOpts
extends WithRefOpts,
ActiveValues<{
ActiveProps<{
forceMount: boolean;
hiddenUntilFound: boolean;
}> {}
interface AccordionHeaderStateOpts
extends WithRefOpts,
ActiveValues<{
ActiveProps<{
level: 1 | 2 | 3 | 4 | 5 | 6;
}> {}
interface AccordionRootStateOpts
extends WithRefOpts,
ActiveValues<{
ActiveProps<{
disabled: boolean;
orientation: Orientation;
loop: boolean;

@ -1,8 +1,8 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { DialogActionState } from "../../dialog/dialog.svelte";
import type { AlertDialogActionProps } from "../types";
import { createId } from "../../utils/create-id";
import { readableActive, writableActive, mergeProps } from '../../utils';
import { DialogActionState } from '../../dialog/dialog.svelte';
import type { AlertDialogActionProps } from '../types';
import { createId } from '../../utils/create-id';
const uid = $props.id();
@ -15,11 +15,8 @@
}: AlertDialogActionProps = $props();
const actionState = DialogActionState.create({
id: boxWith(() => id),
ref: boxWith(
() => ref,
(v) => (ref = v)
),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
});
const mergedProps = $derived(mergeProps(restProps, actionState.props));
@ -32,4 +29,3 @@
{@render children?.()}
</button>
{/if}

@ -1,8 +1,8 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { AlertDialogCancelState } from "../../dialog/dialog.svelte";
import type { AlertDialogCancelProps } from "../types";
import { createId } from "../../utils/create-id";
import { readableActive, writableActive, mergeProps } from '../../utils';
import { AlertDialogCancelState } from '../../dialog/dialog.svelte';
import type { AlertDialogCancelProps } from '../types';
import { createId } from '../../utils/create-id';
const uid = $props.id();
@ -16,12 +16,9 @@
}: AlertDialogCancelProps = $props();
const cancelState = AlertDialogCancelState.create({
id: boxWith(() => id),
ref: boxWith(
() => ref,
(v) => (ref = v)
),
disabled: boxWith(() => Boolean(disabled)),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
disabled: readableActive(() => Boolean(disabled)),
});
const mergedProps = $derived(mergeProps(restProps, cancelState.props));
@ -34,4 +31,3 @@
{@render children?.()}
</button>
{/if}

@ -1,9 +1,9 @@
<script lang="ts">
import { boxWith, mergeProps, afterSleep } from "../../utils/index";
import { DialogContentState } from "../../dialog/dialog.svelte";
import type { AlertDialogContentProps } from "../types";
import { createId } from "../../utils/create-id";
import { noop } from "../../utils/noop";
import { readableActive, writableActive, mergeProps, afterSleep } from '../../utils';
import { DialogContentState } from '../../dialog/dialog.svelte';
import type { AlertDialogContentProps } from '../types';
import { createId } from '../../utils/create-id';
import { noop } from '../../utils/noop';
const uid = $props.id();
@ -20,28 +20,24 @@
}: AlertDialogContentProps = $props();
const contentState = DialogContentState.create({
id: boxWith(() => id),
ref: boxWith(
() => ref,
(v) => (ref = v)
),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
});
const mergedProps = $derived(mergeProps(restProps, contentState.props));
function handleKeydown(e: KeyboardEvent) {
if (e.key === "Escape") {
if (e.key === 'Escape') {
onEscapeKeydown(e);
// alert-dialog ignores Escape by default (must use action/cancel)
}
}
$effect(() => {
if (contentState.root.opts.open.current) {
onOpenAutoFocus(new Event("focus"));
onOpenAutoFocus(new Event('focus'));
afterSleep(0, () => ref?.focus());
} else {
onCloseAutoFocus(new Event("focus"));
onCloseAutoFocus(new Event('focus'));
}
});
</script>
@ -57,4 +53,3 @@
</div>
{/if}
{/if}

@ -1,8 +1,8 @@
<script lang="ts">
import { boxWith } from "../../utils/index";
import { DialogRootState } from "../../dialog/dialog.svelte";
import type { AlertDialogRootProps } from "../types";
import { noop } from "../../utils/noop";
import { readableActive, writableActive } from '../../utils';
import { DialogRootState } from '../../dialog/dialog.svelte';
import type { AlertDialogRootProps } from '../types';
import { noop } from '../../utils/noop';
let {
open = $bindable(false),
@ -12,17 +12,13 @@
}: AlertDialogRootProps = $props();
DialogRootState.create({
variant: boxWith(() => "alert-dialog"),
open: boxWith(
() => open,
(v) => {
open = v;
onOpenChange(v);
}
),
onOpenChangeComplete: boxWith(() => onOpenChangeComplete),
variant: readableActive(() => 'alert-dialog'),
open: writableActive(() => open, (v) => {
open = v;
onOpenChange(v);
}),
onOpenChangeComplete: readableActive(() => onOpenChangeComplete),
});
</script>
{@render children?.()}

@ -1,4 +1,4 @@
import { attachRef, type ReadableBoxedValues } from "../utils/index";
import { attachRef, type ActiveProps } from "../utils/index";
import type { RefAttachment, WithRefOpts } from "../utils/types";
import { createTerraAttrs } from "../utils/attrs";
@ -7,7 +7,7 @@ const aspectRatioAttrs = createTerraAttrs({
parts: ["root"] as const,
});
interface AspectRatioRootStateOpts extends WithRefOpts, ReadableBoxedValues<{ ratio: number }> {}
interface AspectRatioRootStateOpts extends WithRefOpts, ActiveProps<{ ratio: number }> {}
export class AspectRatioRootState {
static create(opts: AspectRatioRootStateOpts) {

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils";
import type { AspectRatioRootProps } from "../types";
import { AspectRatioRootState } from "../aspect-ratio.svelte";
import { createId } from "../../utils/create-id";
@ -16,12 +16,12 @@
}: AspectRatioRootProps = $props();
const rootState = AspectRatioRootState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
ratio: boxWith(() => ratio),
ratio: readableActive(() => ratio),
});
const mergedProps = $derived(mergeProps(restProps, rootState.props));

@ -1,4 +1,4 @@
import { attachRef, type ReadableBoxedValues, type WritableBoxedValues } from "../utils/index";
import { attachRef, type ActiveProps, type StateProps } from "../utils/index";
import type { HTMLImgAttributes } from "svelte/elements";
import { Context, watch } from "runed";
import type { AvatarImageLoadingStatus } from "./types";
@ -16,8 +16,8 @@ type AvatarImageSrc = string | null | undefined;
interface AvatarRootStateOpts
extends WithRefOpts,
ReadableBoxedValues<{ delayMs: number }>,
WritableBoxedValues<{ loadingStatus: AvatarImageLoadingStatus }> {}
ActiveProps<{ delayMs: number }>,
StateProps<{ loadingStatus: AvatarImageLoadingStatus }> {}
const AvatarRootContext = new Context<AvatarRootState>("Avatar.Root");
@ -85,7 +85,7 @@ export class AvatarRootState {
interface AvatarImageStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
src: AvatarImageSrc;
crossOrigin: CrossOrigin;
referrerPolicy: ReferrerPolicy;

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils";
import type { AvatarFallbackProps } from "../types";
import { AvatarFallbackState } from "../avatar.svelte";
import { createId } from "../../utils/create-id";
@ -15,8 +15,8 @@
}: AvatarFallbackProps = $props();
const fallbackState = AvatarFallbackState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
});
const mergedProps = $derived(mergeProps(restProps, fallbackState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils";
import type { AvatarImageProps } from "../types";
import { AvatarImageState } from "../avatar.svelte";
import { createId } from "../../utils/create-id";
@ -17,11 +17,11 @@
}: AvatarImageProps = $props();
const imageState = AvatarImageState.create({
src: boxWith(() => src),
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
crossOrigin: boxWith(() => crossorigin),
referrerPolicy: boxWith(() => referrerpolicy),
src: readableActive(() => src),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
crossOrigin: readableActive(() => crossorigin),
referrerPolicy: readableActive(() => referrerpolicy),
});
// FIX vs uisv: src ya viene dentro de mergedProps (imageState.props).

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils";
import type { AvatarRootProps } from "../types";
import { AvatarRootState } from "../avatar.svelte";
import { createId } from "../../utils/create-id";
@ -18,8 +18,8 @@
}: AvatarRootProps = $props();
const rootState = AvatarRootState.create({
delayMs: boxWith(() => delayMs),
loadingStatus: boxWith(
delayMs: readableActive(() => delayMs),
loadingStatus: writableActive(
() => loadingStatus,
(v) => {
if (loadingStatus !== v) {
@ -28,8 +28,8 @@
}
}
),
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
});
const mergedProps = $derived(mergeProps(restProps, rootState.props));

@ -1,8 +1,8 @@
import { Context } from 'runed';
import { readableActive, type Active, type ActiveValues } from '../../utils';
import { readableActive, type Active, type ActiveProps } from '../../utils';
import type { TerraConfigPropsWithoutChildren } from './types';
type TerraConfigStateProps = ActiveValues<TerraConfigPropsWithoutChildren>;
type TerraConfigStateProps = ActiveProps<TerraConfigPropsWithoutChildren>;
export const TerraConfigContext = new Context<TerraConfigState>('TerraConfig');

@ -11,7 +11,7 @@ import {
noop,
onDestroyEffect,
type Active,
type ActiveValues,
type ActiveProps,
} from '../../utils';
import { watch } from 'runed';
import { on } from 'svelte/events';
@ -24,7 +24,7 @@ globalThis.terraDismissableLayers ??= new Map<
>();
interface DismissibleLayerStateOpts
extends ActiveValues<Required<Omit<DismissibleLayerImplProps, 'children' | 'ref'>>> {
extends ActiveProps<Required<Omit<DismissibleLayerImplProps, 'children' | 'ref'>>> {
ref: Active<HTMLElement | null>;
}

@ -1,4 +1,4 @@
import { DOMContext, type Active, type ActiveState, type ActiveValues } from '../../utils';
import { DOMContext, type Active, type ActiveState, type ActiveProps } from '../../utils';
import { watch } from 'runed';
import { on } from 'svelte/events';
import type { EscapeBehaviorType, EscapeLayerImplProps } from './types.ts';
@ -7,7 +7,7 @@ import { kbd, noop } from '../../utils';
globalThis.terraEscapeLayers ??= new Map<EscapeLayerState, Active<EscapeBehaviorType>>();
interface EscapeLayerStateOpts
extends ActiveValues<Required<Omit<EscapeLayerImplProps, 'children' | 'ref'>>> {
extends ActiveProps<Required<Omit<EscapeLayerImplProps, 'children' | 'ref'>>> {
ref: ActiveState<HTMLElement | null>;
}

@ -18,7 +18,7 @@ import {
state,
styleToString,
type Active,
type ReadableBoxedValues,
type ActiveProps,
} from '../../utils';
import { Context, ElementSize, watch } from "runed";
import type { Arrayable, WithRefOpts } from '../../utils';
@ -74,7 +74,7 @@ export class FloatingRootState {
}
export interface FloatingContentStateOpts
extends ReadableBoxedValues<{
extends ActiveProps<{
id: string;
wrapperId: string;
side: Side;
@ -344,7 +344,7 @@ export class FloatingArrowState {
}
interface FloatingAnchorStateOpts
extends ReadableBoxedValues<{
extends ActiveProps<{
id: string;
virtualEl?: Measurable | null;
ref: Measurable | HTMLElement | null;

@ -1,11 +1,11 @@
import { onDestroyEffect, type Active, type ActiveValues } from '../../utils';
import { onDestroyEffect, type Active, type ActiveProps } from '../../utils';
import { FocusScopeManager } from './focus-scope-manager.ts';
import { focusable, isFocusable, tabbable } from 'tabbable';
import { on } from 'svelte/events';
import { watch } from 'runed';
interface FocusScopeOpts
extends ActiveValues<{
extends ActiveProps<{
onOpenAutoFocus: (event: Event) => void;
onCloseAutoFocus: (event: Event) => void;
trap: boolean;
@ -15,7 +15,7 @@ interface FocusScopeOpts
interface FocusScopeUseOpts
extends FocusScopeOpts,
ActiveValues<{
ActiveProps<{
enabled: boolean;
ref: HTMLElement | null;
}> {}

@ -1,10 +1,10 @@
import { type Active, type ActiveValues, executeCallbacks } from '../../utils';
import { type Active, type ActiveProps, executeCallbacks } from '../../utils';
import { Previous, watch } from 'runed';
import { on } from 'svelte/events';
import { StateMachine } from '../../utils';
export interface PresenceOptions
extends ActiveValues<{
extends ActiveProps<{
open: boolean;
ref: HTMLElement | null;
}> {}

@ -1,7 +1,7 @@
import {
DOMContext,
type Active,
type ActiveValues,
type ActiveProps,
composeHandlers,
contains,
executeCallbacks,
@ -13,7 +13,7 @@ import { on } from 'svelte/events';
import type { TextSelectionLayerImplProps } from './types.ts';
interface TextSelectionLayerStateOpts
extends ActiveValues<
extends ActiveProps<
Required<
Omit<TextSelectionLayerImplProps, 'children' | 'preventOverflowTextSelection' | 'ref'> & {
ref: HTMLElement | null;

@ -10,8 +10,8 @@ import { DEV } from "esm-env";
import { onMount, untrack } from "svelte";
import {
attachRef,
type ActiveValues,
type StateValues,
type ActiveProps,
type StateProps,
} from "../utils/index";
import { Context, watch } from "runed";
import {
@ -60,11 +60,11 @@ import {
interface CalendarRootStateOpts
extends WithRefOpts,
StateValues<{
StateProps<{
value: DateValue | undefined | DateValue[];
placeholder: DateValue;
}>,
ActiveValues<{
ActiveProps<{
preventDeselect: boolean;
minValue: DateValue | undefined;
maxValue: DateValue | undefined;
@ -554,7 +554,7 @@ const CalendarCellContext = new Context<CalendarCellState>("Calendar.Cell");
interface CalendarCellStateOpts
extends WithRefOpts,
ActiveValues<{
ActiveProps<{
date: DateValue;
month: DateValue;
}> {}
@ -990,7 +990,7 @@ export class CalendarHeaderState {
interface CalendarMonthSelectStateOpts
extends WithRefOpts,
ActiveValues<{
ActiveProps<{
months: number[];
monthFormat: Intl.DateTimeFormatOptions["month"] | ((month: number) => string);
disabled: boolean;
@ -1074,7 +1074,7 @@ export class CalendarMonthSelectState {
interface CalendarYearSelectStateOpts
extends WithRefOpts,
ActiveValues<{
ActiveProps<{
years: number[] | undefined;
yearFormat: Intl.DateTimeFormatOptions["year"] | ((year: number) => string);
disabled: boolean;

@ -1,4 +1,4 @@
import { attachRef, type ReadableBoxedValues, type WritableBoxedValues } from "../utils/index";
import { attachRef, type ActiveProps, type StateProps } from "../utils/index";
import type { RefAttachment, WithRefOpts, TerraKeyboardEvent, TerraMouseEvent, TerraFocusEvent } from "../utils/types";
import { createTerraAttrs, getAriaChecked, boolToStr, boolToEmptyStrOrUndef } from "../utils/attrs";
import { Context, watch } from "runed";
@ -17,14 +17,14 @@ export const CheckboxGroupContext = new Context<CheckboxGroupState>("Checkbox.Gr
interface CheckboxGroupStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
name: string | undefined;
disabled: boolean;
required: boolean;
readonly: boolean;
onValueChange: (v: string[]) => void;
}>,
WritableBoxedValues<{ value: string[] }> {}
StateProps<{ value: string[] }> {}
export class CheckboxGroupState {
static create(opts: CheckboxGroupStateOpts) {
@ -106,7 +106,7 @@ const CheckboxRootContext = new Context<CheckboxRootState>("Checkbox.Root");
interface CheckboxRootStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
disabled: boolean;
required: boolean;
readonly: boolean;
@ -115,7 +115,7 @@ interface CheckboxRootStateOpts
onCheckedChange: (v: boolean) => void;
onIndeterminateChange: (v: boolean) => void;
}>,
WritableBoxedValues<{
StateProps<{
checked: boolean;
indeterminate: boolean;
}> {}

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils";
import type { CheckboxGroupLabelProps } from "../types";
import { CheckboxGroupLabelState } from "../checkbox.svelte";
import { createId } from "../../utils/create-id";
@ -15,8 +15,8 @@
}: CheckboxGroupLabelProps = $props();
const labelState = CheckboxGroupLabelState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
});
const mergedProps = $derived(mergeProps(restProps, labelState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils";
import type { CheckboxGroupProps } from "../types";
import { CheckboxGroupState } from "../checkbox.svelte";
import { createId } from "../../utils/create-id";
@ -22,14 +22,14 @@
}: CheckboxGroupProps = $props();
const groupState = CheckboxGroupState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
value: boxWith(() => value, (v) => (value = v)),
onValueChange: boxWith(() => onValueChange),
name: boxWith(() => name),
disabled: boxWith(() => disabled),
required: boxWith(() => required),
readonly: boxWith(() => readonly),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
value: writableActive(() => value, (v) => (value = v)),
onValueChange: readableActive(() => onValueChange),
name: readableActive(() => name),
disabled: readableActive(() => disabled),
required: readableActive(() => required),
readonly: readableActive(() => readonly),
});
const mergedProps = $derived(mergeProps(restProps, groupState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils";
import type { CheckboxRootProps } from "../types";
import { CheckboxRootState, CheckboxInputState, CheckboxGroupContext } from "../checkbox.svelte";
import { createId } from "../../utils/create-id";
@ -30,17 +30,17 @@
// svelte-ignore state_referenced_locally
const rootState = CheckboxRootState.create(
{
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
checked: boxWith(() => checked, (v) => (checked = v)),
indeterminate: boxWith(() => indeterminate, (v) => (indeterminate = v)),
onCheckedChange: boxWith(() => onCheckedChange),
onIndeterminateChange: boxWith(() => onIndeterminateChange),
disabled: boxWith(() => disabled),
required: boxWith(() => required),
readonly: boxWith(() => readonly),
name: boxWith(() => name),
value: boxWith(() => value),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
checked: writableActive(() => checked, (v) => (checked = v)),
indeterminate: writableActive(() => indeterminate, (v) => (indeterminate = v)),
onCheckedChange: readableActive(() => onCheckedChange),
onIndeterminateChange: readableActive(() => onIndeterminateChange),
disabled: readableActive(() => disabled),
required: readableActive(() => required),
readonly: readableActive(() => readonly),
name: readableActive(() => name),
value: readableActive(() => value),
},
group
);

@ -3,8 +3,8 @@ import {
afterTick,
srOnlyStyles,
attachRef,
type WritableBoxedValues,
type ReadableBoxedValues,
type StateProps,
type ActiveProps,
} from "../utils/index";
import { Context, watch } from "runed";
import { findNextSibling, findPreviousSibling } from "./utils";
@ -63,7 +63,7 @@ type ItemsGrid = GridItem[][];
interface CommandRootStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
filter: (value: string, search: string, keywords?: string[]) => number;
shouldFilter: boolean;
loop: boolean;
@ -73,7 +73,7 @@ interface CommandRootStateOpts
disableInitialScroll: boolean;
onStateChange?: (state: Readonly<CommandState>) => void;
}>,
WritableBoxedValues<{
StateProps<{
value: string;
}> {}
@ -652,7 +652,7 @@ function itemIsDisabled(item: HTMLElement) {
// ── CommandEmptyState ─────────────────────────────────────────────────────────
interface CommandEmptyStateOpts extends WithRefOpts, ReadableBoxedValues<{ forceMount: boolean }> {}
interface CommandEmptyStateOpts extends WithRefOpts, ActiveProps<{ forceMount: boolean }> {}
export class CommandEmptyState {
static create(opts: CommandEmptyStateOpts) {
@ -685,7 +685,7 @@ export class CommandEmptyState {
interface CommandGroupContainerStateOpts
extends WithRefOpts,
ReadableBoxedValues<{ value: string; forceMount: boolean }> {}
ActiveProps<{ value: string; forceMount: boolean }> {}
export class CommandGroupContainerState {
static create(opts: CommandGroupContainerStateOpts) {
@ -798,8 +798,8 @@ export class CommandGroupItemsState {
interface CommandInputStateOpts
extends WithRefOpts,
WritableBoxedValues<{ value: string }>,
ReadableBoxedValues<{ autofocus: boolean }> {}
StateProps<{ value: string }>,
ActiveProps<{ autofocus: boolean }> {}
export class CommandInputState {
static create(opts: CommandInputStateOpts) {
@ -863,7 +863,7 @@ export class CommandInputState {
interface CommandItemStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
value: string;
disabled: boolean;
onSelect: () => void;
@ -971,7 +971,7 @@ export class CommandItemState {
// ── CommandLoadingState ───────────────────────────────────────────────────────
interface CommandLoadingStateOpts extends WithRefOpts, ReadableBoxedValues<{ progress: number }> {}
interface CommandLoadingStateOpts extends WithRefOpts, ActiveProps<{ progress: number }> {}
export class CommandLoadingState {
static create(opts: CommandLoadingStateOpts) {
@ -1001,7 +1001,7 @@ export class CommandLoadingState {
// ── CommandSeparatorState ─────────────────────────────────────────────────────
interface CommandSeparatorStateOpts extends WithRefOpts, ReadableBoxedValues<{ forceMount: boolean }> {}
interface CommandSeparatorStateOpts extends WithRefOpts, ActiveProps<{ forceMount: boolean }> {}
export class CommandSeparatorState {
static create(opts: CommandSeparatorStateOpts) {
@ -1032,7 +1032,7 @@ export class CommandSeparatorState {
// ── CommandListState ──────────────────────────────────────────────────────────
interface CommandListStateOpts extends WithRefOpts, ReadableBoxedValues<{ ariaLabel: string }> {}
interface CommandListStateOpts extends WithRefOpts, ActiveProps<{ ariaLabel: string }> {}
export class CommandListState {
static create(opts: CommandListStateOpts) {
@ -1061,7 +1061,7 @@ export class CommandListState {
// ── CommandLabelState ─────────────────────────────────────────────────────────
interface CommandLabelStateOpts extends WithRefOpts, ReadableBoxedValues<{ for?: string }> {}
interface CommandLabelStateOpts extends WithRefOpts, ActiveProps<{ for?: string }> {}
export class CommandLabelState {
static create(opts: CommandLabelStateOpts) {

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import { CommandLabelState } from "../command.svelte";
import { useId } from "../../utils/use-id";
import type { TerraPrimitiveLabelAttributes } from "../../utils/attributes";
@ -13,8 +13,8 @@
}: WithChildren<TerraPrimitiveLabelAttributes & { ref?: HTMLLabelElement | null }> = $props();
const labelState = CommandLabelState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { CommandEmptyProps } from "../types";
import { CommandEmptyState } from "../command.svelte";
import { useId } from "../../utils/use-id";
@ -14,12 +14,12 @@
}: CommandEmptyProps = $props();
const emptyState = CommandEmptyState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
forceMount: boxWith(() => forceMount),
forceMount: readableActive(() => forceMount),
});
const mergedProps = $derived(mergeProps(emptyState.props, restProps));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import { CommandGroupHeadingState } from "../command.svelte";
import type { CommandGroupHeadingProps } from "../types";
import { useId } from "../../utils/use-id";
@ -13,8 +13,8 @@
}: CommandGroupHeadingProps = $props();
const headingState = CommandGroupHeadingState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { CommandGroupItemsProps } from "../types";
import { CommandGroupItemsState } from "../command.svelte";
import { useId } from "../../utils/use-id";
@ -13,8 +13,8 @@
}: CommandGroupItemsProps = $props();
const groupItemsState = CommandGroupItemsState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { CommandGroupProps } from "../types";
import { CommandGroupContainerState } from "../command.svelte";
import { useId } from "../../utils/use-id";
@ -15,13 +15,13 @@
}: CommandGroupProps = $props();
const groupState = CommandGroupContainerState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
forceMount: boxWith(() => forceMount),
value: boxWith(() => value),
forceMount: readableActive(() => forceMount),
value: readableActive(() => value),
});
const mergedProps = $derived(mergeProps(restProps, groupState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { CommandInputProps } from "../types";
import { CommandInputState } from "../command.svelte";
import { useId } from "../../utils/use-id";
@ -14,16 +14,16 @@
}: CommandInputProps = $props();
const inputState = CommandInputState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
value: boxWith(
value: writableActive(
() => value,
(v) => { value = v; }
),
autofocus: boxWith(() => autofocus ?? false),
autofocus: readableActive(() => autofocus ?? false),
});
const mergedProps = $derived(mergeProps(restProps, inputState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { CommandItemProps } from "../types";
import { CommandItemState } from "../command.svelte";
import { noop } from "../../utils/noop";
@ -19,16 +19,16 @@
}: CommandItemProps = $props();
const itemState = CommandItemState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
value: boxWith(() => value),
disabled: boxWith(() => disabled),
onSelect: boxWith(() => onSelect),
forceMount: boxWith(() => forceMount),
keywords: boxWith(() => keywords),
value: readableActive(() => value),
disabled: readableActive(() => disabled),
onSelect: readableActive(() => onSelect),
forceMount: readableActive(() => forceMount),
keywords: readableActive(() => keywords),
});
const mergedProps = $derived(mergeProps(restProps, itemState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { CommandLinkItemProps } from "../types";
import { CommandItemState } from "../command.svelte";
import { noop } from "../../utils/noop";
@ -19,16 +19,16 @@
}: CommandLinkItemProps = $props();
const itemState = CommandItemState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
value: boxWith(() => value),
disabled: boxWith(() => disabled),
onSelect: boxWith(() => onSelect),
forceMount: boxWith(() => forceMount),
keywords: boxWith(() => keywords),
value: readableActive(() => value),
disabled: readableActive(() => disabled),
onSelect: readableActive(() => onSelect),
forceMount: readableActive(() => forceMount),
keywords: readableActive(() => keywords),
});
const mergedProps = $derived(mergeProps(restProps, itemState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { CommandListProps } from "../types";
import { CommandListState } from "../command.svelte";
import { useId } from "../../utils/use-id";
@ -14,12 +14,12 @@
}: CommandListProps = $props();
const listState = CommandListState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
ariaLabel: boxWith(() => ariaLabel ?? "Suggestions..."),
ariaLabel: readableActive(() => ariaLabel ?? "Suggestions..."),
});
const mergedProps = $derived(mergeProps(restProps, listState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { CommandLoadingProps } from "../types";
import { CommandLoadingState } from "../command.svelte";
import { useId } from "../../utils/use-id";
@ -14,12 +14,12 @@
}: CommandLoadingProps = $props();
const loadingState = CommandLoadingState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
progress: boxWith(() => progress),
progress: readableActive(() => progress),
});
const mergedProps = $derived(mergeProps(restProps, loadingState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { CommandSeparatorProps } from "../types";
import { CommandSeparatorState } from "../command.svelte";
import { useId } from "../../utils/use-id";
@ -14,12 +14,12 @@
}: CommandSeparatorProps = $props();
const separatorState = CommandSeparatorState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
forceMount: boxWith(() => forceMount),
forceMount: readableActive(() => forceMount),
});
const mergedProps = $derived(mergeProps(restProps, separatorState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import { CommandViewportState } from "../command.svelte";
import type { CommandViewportProps } from "../types";
import { useId } from "../../utils/use-id";
@ -13,8 +13,8 @@
}: CommandViewportProps = $props();
const listViewportState = CommandViewportState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import { CommandRootState } from "../command.svelte";
import type { CommandRootProps } from "../types";
import CommandLabel from "./_command-label.svelte";
@ -27,15 +27,15 @@
}: CommandRootProps = $props();
const rootState = CommandRootState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
filter: boxWith(() => filter),
shouldFilter: boxWith(() => shouldFilter),
loop: boxWith(() => loop),
value: boxWith(
filter: readableActive(() => filter),
shouldFilter: readableActive(() => shouldFilter),
loop: readableActive(() => loop),
value: writableActive(
() => value,
(v) => {
if (value !== v) {
@ -44,11 +44,11 @@
}
}
),
vimBindings: boxWith(() => vimBindings),
disablePointerSelection: boxWith(() => disablePointerSelection),
disableInitialScroll: boxWith(() => disableInitialScroll),
onStateChange: boxWith(() => onStateChange),
columns: boxWith(() => columns),
vimBindings: readableActive(() => vimBindings),
disablePointerSelection: readableActive(() => disablePointerSelection),
disableInitialScroll: readableActive(() => disableInitialScroll),
onStateChange: readableActive(() => onStateChange),
columns: readableActive(() => columns),
});
// Imperative APIs

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from '../../utils/index';
import { readableActive, writableActive, mergeProps } from '../../utils';
import type { ContextMenuContentProps } from '../types';
import { CONTEXT_MENU_TRIGGER_ATTR, MenuContentState } from '../../menu/menu.svelte';
import { useId } from '../../utils/use-id';
@ -31,13 +31,10 @@
}: ContextMenuContentProps = $props();
const contentState = MenuContentState.create({
id: boxWith(() => id),
loop: boxWith(() => loop),
ref: boxWith(
() => ref,
(v) => (ref = v)
),
onCloseAutoFocus: boxWith(() => onCloseAutoFocus),
id: readableActive(() => id),
loop: readableActive(() => loop),
ref: writableActive(() => ref, (v) => (ref = v)),
onCloseAutoFocus: readableActive(() => onCloseAutoFocus),
});
const mergedProps = $derived(mergeProps(restProps, contentState.props));
@ -112,4 +109,3 @@
{/if}
{/snippet}
</PopperLayer>

@ -1,9 +1,9 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import type { ContextMenuTriggerProps } from "../types";
import { ContextMenuTriggerState } from "../../menu/menu.svelte";
import { useId } from "../../utils/use-id";
import FloatingLayerAnchor from "../../base/floating-layer/components/floating-layer-anchor.svelte";
import { readableActive, writableActive, mergeProps } from '../../utils';
import type { ContextMenuTriggerProps } from '../types';
import { ContextMenuTriggerState } from '../../menu/menu.svelte';
import { useId } from '../../utils/use-id';
import FloatingLayerAnchor from '../../base/floating-layer/components/floating-layer-anchor.svelte';
let {
id = useId(),
@ -15,19 +15,16 @@
}: ContextMenuTriggerProps = $props();
const triggerState = ContextMenuTriggerState.create({
id: boxWith(() => id),
disabled: boxWith(() => disabled),
ref: boxWith(
() => ref,
(v) => (ref = v)
),
id: readableActive(() => id),
disabled: readableActive(() => disabled),
ref: writableActive(() => ref, (v) => (ref = v)),
});
const mergedProps = $derived(
mergeProps(
restProps,
triggerState.props,
{ style: { pointerEvents: "auto" } },
{ style: { pointerEvents: 'auto' } },
{
style: restProps.style,
tabindex: restProps.tabindex,
@ -45,5 +42,3 @@
</div>
{/if}
</FloatingLayerAnchor>

@ -1,21 +1,21 @@
<script lang="ts">
import { boxWith } from "../../utils/index";
import type { ContextMenuRootProps } from "../types";
import FloatingLayer from "../../base/floating-layer/components/floating-layer.svelte";
import { noop } from "../../utils/noop";
import { MenuMenuState, MenuRootState } from "../../menu/menu.svelte";
import { readableActive, writableActive } from '../../utils';
import type { ContextMenuRootProps } from '../types';
import FloatingLayer from '../../base/floating-layer/components/floating-layer.svelte';
import { noop } from '../../utils/noop';
import { MenuMenuState, MenuRootState } from '../../menu/menu.svelte';
let {
open = $bindable(false),
dir = "ltr",
dir = 'ltr',
onOpenChange = noop,
onOpenChangeComplete = noop,
children,
}: ContextMenuRootProps = $props();
const root = MenuRootState.create({
variant: boxWith(() => "context-menu"),
dir: boxWith(() => dir),
variant: readableActive(() => 'context-menu'),
dir: readableActive(() => dir),
onClose: () => {
open = false;
onOpenChange?.(false);
@ -24,14 +24,11 @@
MenuMenuState.create(
{
open: boxWith(
() => open,
(v) => {
open = v;
onOpenChange(v);
}
),
onOpenChangeComplete: boxWith(() => onOpenChangeComplete),
open: writableActive(() => open, (v) => {
open = v;
onOpenChange(v);
}),
onOpenChangeComplete: readableActive(() => onOpenChangeComplete),
},
root
);
@ -40,5 +37,3 @@
<FloatingLayer>
{@render children?.()}
</FloatingLayer>

@ -6,8 +6,8 @@ import {
onDestroyEffect,
attachRef,
DOMContext,
type ActiveValues,
type StateValues,
type ActiveProps,
type StateProps,
} from "../utils";
import { onMount, untrack } from "svelte";
import { Context, watch } from "runed";
@ -160,11 +160,11 @@ const SEGMENT_CONFIGS: Record<
const DateFieldRootContext = new Context<DateFieldRootState>("DateField.Root");
interface DateFieldRootStateOpts
extends StateValues<{
extends StateProps<{
value: DateValue | undefined;
placeholder: DateValue;
}>,
ActiveValues<{
ActiveProps<{
readonlySegments: SegmentPart[];
validate: DateValidator | undefined;
onInvalid: DateOnInvalid | undefined;
@ -734,7 +734,7 @@ export class DateFieldRootState {
interface DateFieldInputStateOpts
extends WithRefOpts,
ActiveValues<{
ActiveProps<{
name: string;
}> {}

@ -1,8 +1,8 @@
<script lang="ts">
import { boxWith, mergeProps, createId } from "../../utils/index";
import type { DatePickerCalendarProps } from "../types.ts";
import { DatePickerRootContext } from "../date-picker.svelte.ts";
import { CalendarRootState } from "../../calendar/calendar.svelte.ts";
import { readableActive, writableActive, mergeProps, createId } from '../../utils';
import type { DatePickerCalendarProps } from '../types.ts';
import { DatePickerRootContext } from '../date-picker.svelte.ts';
import { CalendarRootState } from '../../calendar/calendar.svelte.ts';
const uid = $props.id();
@ -17,11 +17,8 @@
const datePickerRootState = DatePickerRootContext.get();
const calendarState = CalendarRootState.create({
id: boxWith(() => id),
ref: boxWith(
() => ref,
(v) => (ref = v)
),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
calendarLabel: datePickerRootState.opts.calendarLabel,
fixedWeeks: datePickerRootState.opts.fixedWeeks,
isDateDisabled: datePickerRootState.opts.isDateDisabled,
@ -40,11 +37,11 @@
minValue: datePickerRootState.opts.minValue,
placeholder: datePickerRootState.opts.placeholder,
value: datePickerRootState.opts.value,
type: boxWith(() => 'single' as const),
onDateSelect: boxWith(() => datePickerRootState.opts.onDateSelect?.current ?? (() => {})),
type: readableActive(() => 'single' as const),
onDateSelect: readableActive(() => datePickerRootState.opts.onDateSelect?.current ?? (() => {})),
initialFocus: datePickerRootState.opts.initialFocus,
defaultPlaceholder: datePickerRootState.opts.defaultPlaceholder,
maxDays: boxWith(() => undefined),
maxDays: readableActive(() => undefined),
monthFormat: datePickerRootState.opts.monthFormat,
yearFormat: datePickerRootState.opts.yearFormat,
});
@ -59,4 +56,3 @@
{@render children?.(calendarState.snippetProps)}
</div>
{/if}

@ -1,14 +1,14 @@
<script lang="ts">
import { watch } from "runed";
import type { DateValue } from "$lib/glob/lib";
import { boxWith, mergeProps, noop, useId } from "../../utils/index";
import { DatePickerRootState } from "../date-picker.svelte.ts";
import type { DatePickerRootProps } from "../types.ts";
import { PopoverRootState } from "../../popover/popover.svelte.ts";
import { DateFieldRootState } from "../../date-field/date-field.svelte.ts";
import FloatingLayer from "../../base/floating-layer/components/floating-layer.svelte";
import { getDefaultDate } from "$lib/glob/lib";
import { resolveDateOrderProp, resolveHourCycleProp, resolveLocaleProp } from "../../base/config/prop-resolvers.ts";
import { watch } from 'runed';
import type { DateValue } from '$lib/glob/lib';
import { readableActive, writableActive, mergeProps, noop, useId } from '../../utils';
import { DatePickerRootState } from '../date-picker.svelte.ts';
import type { DatePickerRootProps } from '../types.ts';
import { PopoverRootState } from '../../popover/popover.svelte.ts';
import { DateFieldRootState } from '../../date-field/date-field.svelte.ts';
import FloatingLayer from '../../base/floating-layer/components/floating-layer.svelte';
import { getDefaultDate } from '$lib/glob/lib';
import { resolveDateOrderProp, resolveHourCycleProp, resolveLocaleProp } from '../../base/config/prop-resolvers.ts';
let {
open = $bindable(false),
@ -84,66 +84,57 @@
}
const pickerRootState = DatePickerRootState.create({
open: boxWith(
() => open,
(v) => {
open = v;
onOpenChange(v);
}
),
value: boxWith(
() => value,
(v) => {
value = v;
onValueChange(v);
}
),
placeholder: boxWith(
() => placeholder as DateValue,
(v) => {
placeholder = v;
onPlaceholderChange(v as DateValue);
}
),
isDateUnavailable: boxWith(() => isDateUnavailable),
minValue: boxWith(() => minValue),
maxValue: boxWith(() => maxValue),
disabled: boxWith(() => disabled),
readonly: boxWith(() => readonly),
granularity: boxWith(() => granularity),
readonlySegments: boxWith(() => readonlySegments),
open: writableActive(() => open, (v) => {
open = v;
onOpenChange(v);
}),
value: writableActive(() => value, (v) => {
value = v;
onValueChange(v);
}),
placeholder: writableActive(() => placeholder as DateValue, (v) => {
placeholder = v;
onPlaceholderChange(v as DateValue);
}),
isDateUnavailable: readableActive(() => isDateUnavailable),
minValue: readableActive(() => minValue),
maxValue: readableActive(() => maxValue),
disabled: readableActive(() => disabled),
readonly: readableActive(() => readonly),
granularity: readableActive(() => granularity),
readonlySegments: readableActive(() => readonlySegments),
hourCycle: resolveHourCycleProp(() => timeFormat, () => hourCycle),
locale: resolveLocaleProp(() => locale),
dateOrder: resolveDateOrderProp(() => dateOrder),
hideTimeZone: boxWith(() => hideTimeZone),
required: boxWith(() => required),
calendarLabel: boxWith(() => calendarLabel),
disableDaysOutsideMonth: boxWith(() => disableDaysOutsideMonth),
preventDeselect: boxWith(() => preventDeselect),
pagedNavigation: boxWith(() => pagedNavigation),
weekStartsOn: boxWith(() => weekStartsOn),
weekdayFormat: boxWith(() => weekdayFormat),
isDateDisabled: boxWith(() => isDateDisabled),
fixedWeeks: boxWith(() => fixedWeeks),
numberOfMonths: boxWith(() => numberOfMonths),
onDateSelect: boxWith(() => onDateSelect),
initialFocus: boxWith(() => initialFocus),
monthFormat: boxWith(() => monthFormat),
yearFormat: boxWith(() => yearFormat),
hideTimeZone: readableActive(() => hideTimeZone),
required: readableActive(() => required),
calendarLabel: readableActive(() => calendarLabel),
disableDaysOutsideMonth: readableActive(() => disableDaysOutsideMonth),
preventDeselect: readableActive(() => preventDeselect),
pagedNavigation: readableActive(() => pagedNavigation),
weekStartsOn: readableActive(() => weekStartsOn),
weekdayFormat: readableActive(() => weekdayFormat),
isDateDisabled: readableActive(() => isDateDisabled),
fixedWeeks: readableActive(() => fixedWeeks),
numberOfMonths: readableActive(() => numberOfMonths),
onDateSelect: readableActive(() => onDateSelect),
initialFocus: readableActive(() => initialFocus),
monthFormat: readableActive(() => monthFormat),
yearFormat: readableActive(() => yearFormat),
defaultPlaceholder: getDefaultPlaceholder(),
});
PopoverRootState.create({
open: pickerRootState.opts.open,
onOpenChangeComplete: boxWith(() => onOpenChangeComplete),
onOpenChangeComplete: readableActive(() => onOpenChangeComplete),
});
const fieldRootState = DateFieldRootState.create({
DateFieldRootState.create({
value: pickerRootState.opts.value,
disabled: pickerRootState.opts.disabled,
readonly: pickerRootState.opts.readonly,
readonlySegments: pickerRootState.opts.readonlySegments,
validate: boxWith(() => validate),
validate: readableActive(() => validate),
minValue: pickerRootState.opts.minValue,
maxValue: pickerRootState.opts.maxValue,
granularity: pickerRootState.opts.granularity,
@ -153,9 +144,9 @@
dateOrder: pickerRootState.opts.dateOrder,
required: pickerRootState.opts.required,
placeholder: pickerRootState.opts.placeholder,
onInvalid: boxWith(() => onInvalid),
errorMessageId: boxWith(() => errorMessageId),
isInvalidProp: boxWith(() => undefined),
onInvalid: readableActive(() => onInvalid),
errorMessageId: readableActive(() => errorMessageId),
isInvalidProp: readableActive(() => undefined),
});
const mergedProps = $derived(
@ -175,4 +166,3 @@
</div>
{/if}
</FloatingLayer>

@ -1,24 +1,24 @@
import type { DateValue } from "$lib/glob/lib";
import { Context } from "runed";
import { type ReadableBoxedValues, type WritableBoxedValues } from "../utils";
import type { DateValue } from '$lib/glob/lib';
import { Context } from 'runed';
import type { ActiveProps, StateProps } from '../utils';
import type {
DateMatcher,
Granularity,
HourCycle,
WeekStartsOn,
DatiDateOrder,
} from "$lib/glob/lib";
import type { SegmentPart } from "../utils/datetime/types";
} from '$lib/glob/lib';
import type { SegmentPart } from '../utils/datetime/types';
export const DatePickerRootContext = new Context<DatePickerRootState>('DatePicker.Root');
interface DatePickerRootStateOpts
extends WritableBoxedValues<{
extends StateProps<{
value: DateValue | undefined;
open: boolean;
placeholder: DateValue;
}>,
ReadableBoxedValues<{
ActiveProps<{
readonlySegments: SegmentPart[];
isDateUnavailable: DateMatcher;
isDateDisabled: DateMatcher;
@ -58,4 +58,3 @@ export class DatePickerRootState {
this.opts = opts;
}
}

@ -2,8 +2,8 @@ import { Context, watch } from "runed";
import type { DateValue, DatiDateOrder } from "$lib/glob/lib";
import type {
ActiveValues,
StateValues,
ActiveProps,
StateProps,
RefAttachment,
WithRefOpts,
} from "../utils";
@ -44,13 +44,13 @@ export const DateRangeFieldRootContext = new Context<DateRangeFieldRootState>(
interface DateRangeFieldRootStateOpts
extends WithRefOpts,
StateValues<{
StateProps<{
value: DateRange;
placeholder: DateValue;
startValue: DateValue | undefined;
endValue: DateValue | undefined;
}>,
ActiveValues<{
ActiveProps<{
readonlySegments: SegmentPart[];
validate: DateRangeValidator | undefined;
onInvalid: DateOnInvalid | undefined;
@ -271,10 +271,10 @@ export class DateRangeFieldLabelState {
interface DateRangeFieldInputStateOpts
extends WithRefOpts,
StateValues<{
StateProps<{
value: DateValue | undefined;
}>,
ActiveValues<{
ActiveProps<{
name: string;
}> {}

@ -1,6 +1,6 @@
import type { DateValue } from "$lib/glob/lib";
import { Context } from "runed";
import { type ActiveValues, type StateValues } from "../utils";
import { type ActiveProps, type StateProps } from "../utils";
import type {
DateMatcher,
DateRange,
@ -16,14 +16,14 @@ export const DateRangePickerRootContext = new Context<DateRangePickerRootState>(
);
interface DateRangePickerRootStateOpts
extends StateValues<{
extends StateProps<{
value: DateRange;
startValue: DateValue | undefined;
endValue: DateValue | undefined;
open: boolean;
placeholder: DateValue;
}>,
ActiveValues<{
ActiveProps<{
readonlySegments: SegmentPart[];
isDateUnavailable: DateMatcher;
isDateDisabled: DateMatcher;

@ -1,8 +1,8 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { DialogCloseState } from "../dialog.svelte";
import type { DialogCloseProps } from "../types";
import { createId } from "../../utils/create-id";
import { readableActive, writableActive, mergeProps } from '../../utils';
import { DialogCloseState } from '../dialog.svelte';
import type { DialogCloseProps } from '../types';
import { createId } from '../../utils/create-id';
const uid = $props.id();
@ -16,13 +16,10 @@
}: DialogCloseProps = $props();
const closeState = DialogCloseState.create({
variant: boxWith(() => "close"),
id: boxWith(() => id),
ref: boxWith(
() => ref,
(v) => (ref = v)
),
disabled: boxWith(() => Boolean(disabled)),
variant: readableActive(() => 'close'),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
disabled: readableActive(() => Boolean(disabled)),
});
const mergedProps = $derived(mergeProps(restProps, closeState.props));
@ -35,4 +32,3 @@
{@render children?.()}
</button>
{/if}

@ -1,9 +1,9 @@
<script lang="ts">
import { boxWith, mergeProps, afterSleep } from "../../utils/index";
import { DialogContentState } from "../dialog.svelte";
import type { DialogContentProps } from "../types";
import { createId } from "../../utils/create-id";
import { noop } from "../../utils/noop";
import { readableActive, writableActive, mergeProps, afterSleep } from '../../utils';
import { DialogContentState } from '../dialog.svelte';
import type { DialogContentProps } from '../types';
import { createId } from '../../utils/create-id';
import { noop } from '../../utils/noop';
const uid = $props.id();
@ -20,17 +20,14 @@
}: DialogContentProps = $props();
const contentState = DialogContentState.create({
id: boxWith(() => id),
ref: boxWith(
() => ref,
(v) => (ref = v)
),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
});
const mergedProps = $derived(mergeProps(restProps, contentState.props));
function handleKeydown(e: KeyboardEvent) {
if (e.key === "Escape") {
if (e.key === 'Escape') {
onEscapeKeydown(e);
if (!e.defaultPrevented) {
contentState.root.handleClose();
@ -40,10 +37,10 @@
$effect(() => {
if (contentState.root.opts.open.current) {
onOpenAutoFocus(new Event("focus"));
onOpenAutoFocus(new Event('focus'));
afterSleep(0, () => ref?.focus());
} else {
onCloseAutoFocus(new Event("focus"));
onCloseAutoFocus(new Event('focus'));
}
});
</script>
@ -59,4 +56,3 @@
</div>
{/if}
{/if}

@ -1,8 +1,8 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { DialogDescriptionState } from "../dialog.svelte";
import type { DialogDescriptionProps } from "../types";
import { createId } from "../../utils/create-id";
import { readableActive, writableActive, mergeProps } from '../../utils';
import { DialogDescriptionState } from '../dialog.svelte';
import type { DialogDescriptionProps } from '../types';
import { createId } from '../../utils/create-id';
const uid = $props.id();
@ -15,11 +15,8 @@
}: DialogDescriptionProps = $props();
const descriptionState = DialogDescriptionState.create({
id: boxWith(() => id),
ref: boxWith(
() => ref,
(v) => (ref = v)
),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
});
const mergedProps = $derived(mergeProps(restProps, descriptionState.props));
@ -32,4 +29,3 @@
{@render children?.()}
</div>
{/if}

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from '../../utils/index';
import { readableActive, writableActive, mergeProps } from '../../utils';
import { DialogOverlayState } from '../dialog.svelte';
import type { DialogOverlayProps } from '../types';
import { createId } from '../../utils/create-id';
@ -16,11 +16,8 @@
}: DialogOverlayProps = $props();
const overlayState = DialogOverlayState.create({
id: boxWith(() => id),
ref: boxWith(
() => ref,
(v) => (ref = v)
),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
});
const mergedProps = $derived(mergeProps(restProps, overlayState.props));

@ -1,8 +1,8 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { DialogTitleState } from "../dialog.svelte";
import type { DialogTitleProps } from "../types";
import { createId } from "../../utils/create-id";
import { readableActive, writableActive, mergeProps } from '../../utils';
import { DialogTitleState } from '../dialog.svelte';
import type { DialogTitleProps } from '../types';
import { createId } from '../../utils/create-id';
const uid = $props.id();
@ -16,12 +16,9 @@
}: DialogTitleProps = $props();
const titleState = DialogTitleState.create({
id: boxWith(() => id),
level: boxWith(() => level),
ref: boxWith(
() => ref,
(v) => (ref = v)
),
id: readableActive(() => id),
level: readableActive(() => level),
ref: writableActive(() => ref, (v) => (ref = v)),
});
const mergedProps = $derived(mergeProps(restProps, titleState.props));
@ -34,4 +31,3 @@
{@render children?.()}
</div>
{/if}

@ -1,8 +1,8 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { DialogTriggerState } from "../dialog.svelte";
import type { DialogTriggerProps } from "../types";
import { createId } from "../../utils/create-id";
import { readableActive, writableActive, mergeProps } from '../../utils';
import { DialogTriggerState } from '../dialog.svelte';
import type { DialogTriggerProps } from '../types';
import { createId } from '../../utils/create-id';
const uid = $props.id();
@ -16,12 +16,9 @@
}: DialogTriggerProps = $props();
const triggerState = DialogTriggerState.create({
id: boxWith(() => id),
ref: boxWith(
() => ref,
(v) => (ref = v)
),
disabled: boxWith(() => Boolean(disabled)),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
disabled: readableActive(() => Boolean(disabled)),
});
const mergedProps = $derived(mergeProps(restProps, triggerState.props));
@ -34,4 +31,3 @@
{@render children?.()}
</button>
{/if}

@ -1,8 +1,8 @@
<script lang="ts">
import { boxWith } from "../../utils/index";
import { DialogRootState } from "../dialog.svelte";
import type { DialogRootProps } from "../types";
import { noop } from "../../utils/noop";
import { readableActive, writableActive } from '../../utils';
import { DialogRootState } from '../dialog.svelte';
import type { DialogRootProps } from '../types';
import { noop } from '../../utils/noop';
let {
open = $bindable(false),
@ -12,17 +12,13 @@
}: DialogRootProps = $props();
DialogRootState.create({
variant: boxWith(() => "dialog"),
open: boxWith(
() => open,
(v) => {
open = v;
onOpenChange(v);
}
),
onOpenChangeComplete: boxWith(() => onOpenChangeComplete),
variant: readableActive(() => 'dialog'),
open: writableActive(() => open, (v) => {
open = v;
onOpenChange(v);
}),
onOpenChangeComplete: readableActive(() => onOpenChangeComplete),
});
</script>
{@render children?.()}

@ -1,9 +1,9 @@
import {
attachRef,
boxWith,
readableActive,
onDestroyEffect,
type ReadableBoxedValues,
type WritableBoxedValues,
type ActiveProps,
type StateProps,
} from "../utils/index";
import { Context, watch } from "runed";
import {
@ -32,8 +32,8 @@ const dialogAttrs = createTerraAttrs({
const DialogRootContext = new Context<DialogRootState>("Dialog.Root | AlertDialog.Root");
interface DialogRootStateOpts
extends WritableBoxedValues<{ open: boolean }>,
ReadableBoxedValues<{
extends StateProps<{ open: boolean }>,
ActiveProps<{
variant: DialogVariant;
onOpenChangeComplete: OnChangeFn<boolean>;
}> {}
@ -68,7 +68,7 @@ export class DialogRootState {
this.handleClose = this.handleClose.bind(this);
this.contentPresence = new PresenceManager({
ref: boxWith(() => this.contentNode),
ref: readableActive(() => this.contentNode),
open: this.opts.open,
onComplete: () => {
this.opts.onOpenChangeComplete.current(this.opts.open.current);
@ -76,7 +76,7 @@ export class DialogRootState {
});
this.overlayPresence = new PresenceManager({
ref: boxWith(() => this.overlayNode),
ref: readableActive(() => this.overlayNode),
open: this.opts.open,
});
@ -130,7 +130,7 @@ export class DialogRootState {
);
}
interface DialogTriggerStateOpts extends WithRefOpts, ReadableBoxedValues<{ disabled: boolean }> {}
interface DialogTriggerStateOpts extends WithRefOpts, ActiveProps<{ disabled: boolean }> {}
export class DialogTriggerState {
static create(opts: DialogTriggerStateOpts) {
@ -185,7 +185,7 @@ export class DialogTriggerState {
interface DialogCloseStateOpts
extends WithRefOpts,
ReadableBoxedValues<{ variant: "action" | "cancel" | "close"; disabled: boolean }> {}
ActiveProps<{ variant: "action" | "cancel" | "close"; disabled: boolean }> {}
export class DialogCloseState {
static create(opts: DialogCloseStateOpts) {
@ -261,7 +261,7 @@ export class DialogActionState {
);
}
interface DialogTitleStateOpts extends WithRefOpts, ReadableBoxedValues<{ level: 1 | 2 | 3 | 4 | 5 | 6 }> {}
interface DialogTitleStateOpts extends WithRefOpts, ActiveProps<{ level: 1 | 2 | 3 | 4 | 5 | 6 }> {}
export class DialogTitleState {
static create(opts: DialogTitleStateOpts) {
@ -425,7 +425,7 @@ export class DialogOverlayState {
interface AlertDialogCancelStateOpts
extends WithRefOpts,
ReadableBoxedValues<{ disabled: boolean }> {}
ActiveProps<{ disabled: boolean }> {}
export class AlertDialogCancelState {
static create(opts: AlertDialogCancelStateOpts) {

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from '../../utils/index';
import { readableActive, writableActive, mergeProps } from '../../utils/index';
import type { DropdownMenuContentProps } from '../types';
import { MenuContentState } from '../../menu/menu.svelte';
import { createId } from '../../utils/create-id';
@ -33,13 +33,13 @@
}: DropdownMenuContentProps = $props();
const contentState = MenuContentState.create({
id: boxWith(() => id),
loop: boxWith(() => loop),
ref: boxWith(
id: readableActive(() => id),
loop: readableActive(() => loop),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
onCloseAutoFocus: boxWith(() => onCloseAutoFocus),
onCloseAutoFocus: readableActive(() => onCloseAutoFocus),
});
const mergedProps = $derived(mergeProps(restProps, contentState.props));

@ -1,7 +1,7 @@
import { Context } from "runed";
import type {
ActiveValues,
StateValues,
ActiveProps,
StateProps,
WithRefOpts,
RefAttachment,
OnChangeFn,
@ -31,7 +31,7 @@ export const FieldRootContext = new Context<FieldRootState>("Field.Root");
interface FieldRootStateOpts
extends WithRefOpts,
ActiveValues<{
ActiveProps<{
state: FieldState;
disabled: boolean;
readonly: boolean;
@ -158,11 +158,11 @@ export class FieldControlState {
interface FieldInputStateOpts
extends WithRefOpts,
ActiveValues<{
ActiveProps<{
type: FieldInputType;
onValueChange: OnChangeFn<string>;
}>,
StateValues<{ value: string }> {}
StateProps<{ value: string }> {}
export class FieldInputState {
static create(opts: FieldInputStateOpts): FieldInputState {

@ -25,6 +25,7 @@ export * as RadioGroup from './radio-group';
export * as RatingGroup from './rating-group';
export * as Separator from './separator';
export * as Switch from './switch';
export * as Spinner from './spinner';
export * as Tabs from './tabs';
export * as Toggle from './toggle';
export * as ToggleGroup from './toggle-group';

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { LabelRootProps } from "../types";
import { LabelRootState } from "../label.svelte";
import { createId } from "../../utils/create-id";
@ -15,8 +15,8 @@
}: LabelRootProps = $props();
const rootState = LabelRootState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
});
const mergedProps = $derived(mergeProps(restProps, rootState.props));

@ -8,10 +8,10 @@ import {
type TerraFocusEvent,
type TerraPointerEvent,
type OnChangeFn,
type ActiveValues,
type ActiveProps,
type RefAttachment,
type WithRefOpts,
type StateValues,
type StateProps,
createTerraAttrs,
boolToStr,
getDataOpenClosed,
@ -33,10 +33,10 @@ const linkPreviewAttrs = createTerraAttrs({
const LinkPreviewRootContext = new Context<LinkPreviewRootState>('LinkPreview.Root');
interface LinkPreviewRootStateOpts
extends StateValues<{
extends StateProps<{
open: boolean;
}>,
ActiveValues<{
ActiveProps<{
disabled: boolean;
openDelay: number;
closeDelay: number;
@ -213,7 +213,7 @@ export class LinkPreviewTriggerState {
interface LinkPreviewContentStateOpts
extends WithRefOpts,
ActiveValues<{
ActiveProps<{
onInteractOutside: (e: PointerEvent) => void;
onEscapeKeydown: (e: KeyboardEvent) => void;
}> {}

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { MenuCheckboxGroupProps } from "../types";
import { MenuCheckboxGroupState } from "../menu.svelte";
import { noop } from "../../utils/noop";
@ -18,19 +18,19 @@
}: MenuCheckboxGroupProps = $props();
const checkboxGroupState = MenuCheckboxGroupState.create({
value: boxWith(
value: writableActive(
() => $state.snapshot(value),
(v) => {
value = $state.snapshot(v);
onValueChange(v);
}
),
onValueChange: boxWith(() => onValueChange),
ref: boxWith(
onValueChange: readableActive(() => onValueChange),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
id: boxWith(() => id),
id: readableActive(() => id),
});
const mergedProps = $derived(mergeProps(restProps, checkboxGroupState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { MenuCheckboxItemProps } from "../types";
import { MenuCheckboxGroupContext, MenuCheckboxItemState } from "../menu.svelte";
import { createId } from "../../utils/create-id";
@ -32,7 +32,7 @@
const checkboxItemState = MenuCheckboxItemState.create(
{
checked: boxWith(
checked: writableActive(
() => checked,
(v) => {
if (v !== checked) {
@ -41,15 +41,15 @@
}
}
),
id: boxWith(() => id),
disabled: boxWith(() => disabled),
onSelect: boxWith(() => handleSelect),
ref: boxWith(
id: readableActive(() => id),
disabled: readableActive(() => disabled),
onSelect: readableActive(() => handleSelect),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
closeOnSelect: boxWith(() => closeOnSelect),
indeterminate: boxWith(
closeOnSelect: readableActive(() => closeOnSelect),
indeterminate: writableActive(
() => indeterminate,
(v) => {
if (v !== indeterminate) {
@ -58,7 +58,7 @@
}
}
),
value: boxWith(() => value),
value: readableActive(() => value),
},
group
);

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from '../../utils/index';
import { readableActive, writableActive, mergeProps } from '../../utils/index';
import type { MenuContentProps } from '../types';
import { MenuContentState } from '../menu.svelte';
import { createId } from '../../utils/create-id';
@ -36,13 +36,13 @@
}: MenuContentProps = $props();
const contentState = MenuContentState.create({
id: boxWith(() => id),
loop: boxWith(() => loop),
ref: boxWith(
id: readableActive(() => id),
loop: readableActive(() => loop),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
onCloseAutoFocus: boxWith(() => onCloseAutoFocus),
onCloseAutoFocus: readableActive(() => onCloseAutoFocus),
});
const mergedProps = $derived(mergeProps(restProps, contentState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { MenuGroupHeadingProps } from "../types";
import { MenuGroupHeadingState } from "../menu.svelte";
import { createId } from "../../utils/create-id";
@ -15,8 +15,8 @@
}: MenuGroupHeadingProps = $props();
const groupHeadingState = MenuGroupHeadingState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { MenuGroupProps } from "../types";
import { MenuGroupState } from "../menu.svelte";
import { createId } from "../../utils/create-id";
@ -15,8 +15,8 @@
}: MenuGroupProps = $props();
const groupState = MenuGroupState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { MenuItemProps } from "../types";
import { MenuItemState } from "../menu.svelte";
import { createId } from "../../utils/create-id";
@ -19,14 +19,14 @@
}: MenuItemProps = $props();
const itemState = MenuItemState.create({
id: boxWith(() => id),
disabled: boxWith(() => disabled),
onSelect: boxWith(() => onSelect),
ref: boxWith(
id: readableActive(() => id),
disabled: readableActive(() => disabled),
onSelect: readableActive(() => onSelect),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
closeOnSelect: boxWith(() => closeOnSelect),
closeOnSelect: readableActive(() => closeOnSelect),
});
const mergedProps = $derived(mergeProps(restProps, itemState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { MenuRadioGroupProps } from "../types";
import { MenuRadioGroupState } from "../menu.svelte";
import { noop } from "../../utils/noop";
@ -18,18 +18,18 @@
}: MenuRadioGroupProps = $props();
const radioGroupState = MenuRadioGroupState.create({
value: boxWith(
value: writableActive(
() => value,
(v) => {
value = v;
onValueChange(v);
}
),
ref: boxWith(
ref: writableActive(
() => ref,
(v) => (ref = v)
),
id: boxWith(() => id),
id: readableActive(() => id),
});
const mergedProps = $derived(mergeProps(restProps, radioGroupState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { MenuRadioItemProps } from "../types";
import { MenuRadioItemState } from "../menu.svelte";
import { createId } from "../../utils/create-id";
@ -20,15 +20,15 @@
}: MenuRadioItemProps = $props();
const radioItemState = MenuRadioItemState.create({
value: boxWith(() => value),
id: boxWith(() => id),
disabled: boxWith(() => disabled),
onSelect: boxWith(() => handleSelect),
ref: boxWith(
value: readableActive(() => value),
id: readableActive(() => id),
disabled: readableActive(() => disabled),
onSelect: readableActive(() => handleSelect),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
closeOnSelect: boxWith(() => closeOnSelect),
closeOnSelect: readableActive(() => closeOnSelect),
});
function handleSelect(e: Event) {

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { MenuSeparatorProps } from "../types";
import { MenuSeparatorState } from "../menu.svelte";
import { createId } from "../../utils/create-id";
@ -15,8 +15,8 @@
}: MenuSeparatorProps = $props();
const separatorState = MenuSeparatorState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from '../../utils/index';
import { readableActive, writableActive, mergeProps } from '../../utils/index';
import type { MenuSubContentProps } from '../types';
import { MenuContentState } from '../menu.svelte';
import { SUB_CLOSE_KEYS } from '../utils';
@ -38,14 +38,14 @@
}: MenuSubContentProps = $props();
const subContentState = MenuContentState.create({
id: boxWith(() => id),
loop: boxWith(() => loop),
ref: boxWith(
id: readableActive(() => id),
loop: readableActive(() => loop),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
isSub: true,
onCloseAutoFocus: boxWith(() => handleCloseAutoFocus),
onCloseAutoFocus: readableActive(() => handleCloseAutoFocus),
});
function onkeydown(e: KeyboardEvent) {

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { MenuSubTriggerProps } from "../types";
import { MenuSubTriggerState } from "../menu.svelte";
import FloatingLayerAnchor from "../../base/floating-layer/components/floating-layer-anchor.svelte";
@ -20,14 +20,14 @@
}: MenuSubTriggerProps = $props();
const subTriggerState = MenuSubTriggerState.create({
disabled: boxWith(() => disabled),
onSelect: boxWith(() => onSelect),
id: boxWith(() => id),
ref: boxWith(
disabled: readableActive(() => disabled),
onSelect: readableActive(() => onSelect),
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
openDelay: boxWith(() => openDelay),
openDelay: readableActive(() => openDelay),
});
const mergedProps = $derived(mergeProps(restProps, subTriggerState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith } from "../../utils/index";
import { readableActive, writableActive } from "../../utils/index";
import type { MenuSubProps } from "../types";
import { MenuSubmenuState } from "../menu.svelte";
import FloatingLayer from "../../base/floating-layer/components/floating-layer.svelte";
@ -13,14 +13,14 @@
}: MenuSubProps = $props();
MenuSubmenuState.create({
open: boxWith(
open: writableActive(
() => open,
(v) => {
open = v;
onOpenChange?.(v);
}
),
onOpenChangeComplete: boxWith(() => onOpenChangeComplete),
onOpenChangeComplete: readableActive(() => onOpenChangeComplete),
});
</script>

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { MenuTriggerProps } from "../types";
import { DropdownMenuTriggerState } from "../menu.svelte";
import { createId } from "../../utils/create-id";
@ -18,9 +18,9 @@
}: MenuTriggerProps & { type?: string } = $props();
const triggerState = DropdownMenuTriggerState.create({
id: boxWith(() => id),
disabled: boxWith(() => disabled ?? false),
ref: boxWith(
id: readableActive(() => id),
disabled: readableActive(() => disabled ?? false),
ref: writableActive(
() => ref,
(v) => (ref = v)
),

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith } from "../../utils/index";
import { readableActive, writableActive } from "../../utils/index";
import type { MenuRootProps } from "../types";
import { MenuMenuState, MenuRootState } from "../menu.svelte";
import { noop } from "../../utils/noop";
@ -17,8 +17,8 @@
} = $props();
const root = MenuRootState.create({
variant: boxWith(() => variant),
dir: boxWith(() => dir),
variant: readableActive(() => variant),
dir: readableActive(() => dir),
onClose: () => {
open = false;
onOpenChange(false);
@ -27,14 +27,14 @@
MenuMenuState.create(
{
open: boxWith(
open: writableActive(
() => open,
(v) => {
open = v;
onOpenChange(v);
}
),
onOpenChangeComplete: boxWith(() => onOpenChangeComplete),
onOpenChangeComplete: readableActive(() => onOpenChangeComplete),
},
root
);

@ -5,11 +5,11 @@ import {
attachRef,
DOMContext,
getWindow,
type ReadableBoxedValues,
type WritableBoxedValues,
simpleBox,
boxWith,
type ReadableBox,
type ActiveProps,
type StateProps,
state,
readableActive,
type Active,
} from "../utils/index";
import { Context, watch } from "runed";
import {
@ -67,7 +67,7 @@ export const MenuCheckboxGroupContext = new Context<MenuCheckboxGroupState>("Men
type MenuVariant = "context-menu" | "dropdown-menu" | "menubar";
export interface MenuRootStateOpts
extends ReadableBoxedValues<{
extends ActiveProps<{
dir: Direction;
variant: MenuVariant;
}> {
@ -119,10 +119,10 @@ export class MenuRootState {
}
interface MenuMenuStateOpts
extends WritableBoxedValues<{
extends StateProps<{
open: boolean;
}>,
ReadableBoxedValues<{
ActiveProps<{
onOpenChangeComplete: OnChangeFn<boolean>;
}> {}
@ -134,7 +134,7 @@ export class MenuMenuState {
readonly opts: MenuMenuStateOpts;
readonly root: MenuRootState;
readonly parentMenu: MenuMenuState | null;
contentId = boxWith<string>(() => "");
contentId: Active<string> = readableActive(() => "");
contentNode = $state<HTMLElement | null>(null);
contentPresence: PresenceManager;
triggerNode = $state<HTMLElement | null>(null);
@ -145,7 +145,7 @@ export class MenuMenuState {
this.parentMenu = parentMenu;
this.contentPresence = new PresenceManager({
ref: boxWith(() => this.contentNode),
ref: readableActive(() => this.contentNode),
open: this.opts.open,
onComplete: () => {
this.opts.onOpenChangeComplete.current(this.opts.open.current);
@ -178,7 +178,7 @@ export class MenuMenuState {
interface MenuContentStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
loop: boolean;
onCloseAutoFocus: (event: Event) => void;
}> {
@ -243,10 +243,10 @@ export class MenuContentState {
}).handleTypeaheadSearch;
this.rovingFocusGroup = new RovingFocusGroup({
rootNode: boxWith(() => this.parentMenu.contentNode),
rootNode: readableActive(() => this.parentMenu.contentNode),
candidateAttr: this.parentMenu.root.getBitsAttr("item"),
loop: this.opts.loop,
orientation: boxWith(() => "vertical"),
orientation: readableActive(() => "vertical"),
});
watch(
@ -436,7 +436,7 @@ export class MenuContentState {
interface MenuItemSharedStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
disabled: boolean;
}> {}
@ -513,7 +513,7 @@ class MenuItemSharedState {
type MenuItemCombinedProps = MenuItemSharedStateOpts & MenuItemStateOpts;
interface MenuItemStateOpts
extends ReadableBoxedValues<{
extends ActiveProps<{
onSelect: AnyFn;
closeOnSelect: boolean;
}> {}
@ -594,7 +594,7 @@ export class MenuItemState {
interface MenuSubTriggerStateOpts
extends MenuItemSharedStateOpts,
Pick<MenuItemStateOpts, "onSelect"> {
openDelay: ReadableBox<number>;
openDelay: Active<number>;
}
export class MenuSubTriggerState {
@ -711,11 +711,11 @@ export class MenuSubTriggerState {
// ─── Checkbox item ────────────────────────────────────────────────────────
interface MenuCheckboxItemStateOpts
extends WritableBoxedValues<{
extends StateProps<{
checked: boolean;
indeterminate: boolean;
}>,
ReadableBoxedValues<{
ActiveProps<{
value: string;
}> {}
@ -917,7 +917,7 @@ export class MenuArrowState {
interface MenuRadioGroupStateOpts
extends WithRefOpts,
WritableBoxedValues<{
StateProps<{
value: string;
}> {}
@ -961,7 +961,7 @@ export class MenuRadioGroupState {
interface MenuRadioItemStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
value: string;
closeOnSelect: boolean;
}> {}
@ -1010,7 +1010,7 @@ export class MenuRadioItemState {
interface DropdownMenuTriggerStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
disabled: boolean;
}> {}
@ -1095,7 +1095,7 @@ export class DropdownMenuTriggerState {
interface ContextMenuTriggerStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
disabled: boolean;
}> {}
@ -1109,7 +1109,7 @@ export class ContextMenuTriggerState {
readonly attachment: RefAttachment;
#point = $state({ x: 0, y: 0 });
virtualElement = simpleBox({
virtualElement = state({
getBoundingClientRect: () => DOMRect.fromRect({ width: 0, height: 0, ...this.#point }),
});
#longPressTimer: number | null = null;
@ -1209,10 +1209,10 @@ export class ContextMenuTriggerState {
interface MenuCheckboxGroupStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
onValueChange: (value: string[]) => void;
}>,
WritableBoxedValues<{
StateProps<{
value: string[];
}> {}

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from '../../utils/index';
import { readableActive, writableActive, mergeProps } from '../../utils/index';
import type { MenubarContentProps } from '../types';
import type { MenuContentProps } from '../../menu/types';
import { MenubarContentState } from '../menubar.svelte';
@ -18,15 +18,15 @@
}: MenubarContentProps = $props();
const contentState = MenubarContentState.create({
id: boxWith(() => id),
ref: boxWith(
id: readableActive(() => id),
ref: writableActive(
() => ref,
(v) => (ref = v)
),
onInteractOutside: boxWith(() => onInteractOutside),
onFocusOutside: boxWith(() => onFocusOutside),
onCloseAutoFocus: boxWith(() => onCloseAutoFocus),
onOpenAutoFocus: boxWith(() => onOpenAutoFocus),
onInteractOutside: readableActive(() => onInteractOutside),
onFocusOutside: readableActive(() => onFocusOutside),
onCloseAutoFocus: readableActive(() => onCloseAutoFocus),
onOpenAutoFocus: readableActive(() => onOpenAutoFocus),
});
const mergedProps = $derived(mergeProps(restProps, contentState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith } from "../../utils/index";
import { readableActive, writableActive } from "../../utils/index";
import type { MenubarMenuProps } from "../types";
import { MenubarMenuState } from "../menubar.svelte";
import Menu from "../../menu/components/menu.svelte";
@ -9,8 +9,8 @@
let { value = useId(), onOpenChange = noop, ...restProps }: MenubarMenuProps = $props();
const menuState = MenubarMenuState.create({
value: boxWith(() => value),
onOpenChange: boxWith(() => onOpenChange),
value: readableActive(() => value),
onOpenChange: readableActive(() => onOpenChange),
});
</script>

@ -1,5 +1,5 @@
<script lang="ts">
import { attachRef, boxWith, mergeProps } from "../../utils/index";
import { attachRef, readableActive, writableActive, mergeProps } from "../../utils/index";
import type { MenubarTriggerProps } from "../types";
import { MenubarTriggerState } from "../menubar.svelte";
import { useId } from "../../utils/use-id";
@ -16,9 +16,9 @@
}: MenubarTriggerProps = $props();
const triggerState = MenubarTriggerState.create({
id: boxWith(() => id),
disabled: boxWith(() => disabled ?? false),
ref: boxWith(
id: readableActive(() => id),
disabled: readableActive(() => disabled ?? false),
ref: writableActive(
() => ref,
(v) => (ref = v)
),

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { MenubarRootProps } from "../types";
import { MenubarRootState } from "../menubar.svelte";
import { useId } from "../../utils/use-id";
@ -18,17 +18,17 @@
}: MenubarRootProps = $props();
const rootState = MenubarRootState.create({
id: boxWith(() => id),
value: boxWith(
id: readableActive(() => id),
value: writableActive(
() => value,
(v) => {
value = v;
onValueChange?.(v);
}
),
dir: boxWith(() => dir),
loop: boxWith(() => loop),
ref: boxWith(
dir: readableActive(() => dir),
loop: readableActive(() => loop),
ref: writableActive(
() => ref,
(v) => (ref = v)
),

@ -1,10 +1,10 @@
import {
type ReadableBox,
type Active,
afterTick,
boxWith,
readableActive,
attachRef,
type ReadableBoxedValues,
type WritableBoxedValues,
type ActiveProps,
type StateProps,
} from "../utils/index";
import { Context, watch } from "runed";
import type { Direction } from "../utils/index";
@ -27,11 +27,11 @@ const MenubarMenuContext = new Context<MenubarMenuState>("Menubar.Menu");
interface MenubarRootStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
dir: Direction;
loop: boolean;
}>,
WritableBoxedValues<{
StateProps<{
value: string;
}> {}
@ -44,7 +44,7 @@ export class MenubarRootState {
readonly attachment: RefAttachment;
wasOpenedByKeyboard = $state(false);
triggerIds = $state<string[]>([]);
valueToChangeHandler = new Map<string, ReadableBox<OnChangeFn<boolean>>>();
valueToChangeHandler = new Map<string, Active<OnChangeFn<boolean>>>();
constructor(opts: MenubarRootStateOpts) {
this.opts = opts;
@ -53,7 +53,7 @@ export class MenubarRootState {
rootNode: this.opts.ref,
candidateAttr: menubarAttrs.trigger,
loop: this.opts.loop,
orientation: boxWith(() => "horizontal"),
orientation: readableActive(() => "horizontal"),
});
}
@ -62,7 +62,7 @@ export class MenubarRootState {
return () => { this.triggerIds = this.triggerIds.filter((tid) => tid !== id); };
};
registerMenu = (value: string, onOpenChange: ReadableBox<OnChangeFn<boolean>>) => {
registerMenu = (value: string, onOpenChange: Active<OnChangeFn<boolean>>) => {
this.valueToChangeHandler.set(value, onOpenChange);
return () => { this.valueToChangeHandler.delete(value); };
};
@ -104,7 +104,7 @@ export class MenubarRootState {
// ── MenubarMenuState ──────────────────────────────────────────────────────────
interface MenubarMenuStateOpts
extends ReadableBoxedValues<{
extends ActiveProps<{
value: string;
onOpenChange: OnChangeFn<boolean>;
}> {}
@ -145,7 +145,7 @@ export class MenubarMenuState {
interface MenubarTriggerStateOpts
extends WithRefOpts,
ReadableBoxedValues<{ disabled: boolean }> {}
ActiveProps<{ disabled: boolean }> {}
export class MenubarTriggerState {
static create(opts: MenubarTriggerStateOpts) {
@ -234,7 +234,7 @@ export class MenubarTriggerState {
interface MenubarContentStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
onOpenAutoFocus: (e: Event) => void;
onCloseAutoFocus: (e: Event) => void;
onFocusOutside: (e: FocusEvent) => void;

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { MeterRootProps } from "../types";
import { MeterRootState } from "../meter.svelte";
import { createId } from "../../utils/create-id";
@ -18,11 +18,11 @@
}: MeterRootProps = $props();
const rootState = MeterRootState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
value: boxWith(() => value),
max: boxWith(() => max),
min: boxWith(() => min),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
value: readableActive(() => value),
max: readableActive(() => max),
min: readableActive(() => min),
});
const mergedProps = $derived(mergeProps(restProps, rootState.props));

@ -1,4 +1,4 @@
import { attachRef, type ReadableBoxedValues } from "../utils/index";
import { attachRef, type ActiveProps } from "../utils/index";
import type { RefAttachment, WithRefOpts } from "../utils/types";
import { createTerraAttrs } from "../utils/attrs";
@ -9,7 +9,7 @@ const meterAttrs = createTerraAttrs({
interface MeterRootStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
value: number;
max: number;
min: number;

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { PaginationNextButtonProps } from "../types";
import { PaginationNextButtonState } from "../pagination.svelte";
import { createId } from "../../utils/create-id";
@ -15,8 +15,8 @@
}: PaginationNextButtonProps = $props();
const buttonState = PaginationNextButtonState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
});
const mergedProps = $derived(mergeProps(restProps, buttonState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { PaginationPageProps } from "../types";
import { PaginationPageState } from "../pagination.svelte";
import { createId } from "../../utils/create-id";
@ -17,10 +17,10 @@
}: PaginationPageProps = $props();
const pageState = PaginationPageState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
page: boxWith(() => page),
disabled: boxWith(() => disabled),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
page: readableActive(() => page),
disabled: readableActive(() => disabled),
});
const mergedProps = $derived(mergeProps(restProps, pageState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { PaginationPrevButtonProps } from "../types";
import { PaginationPrevButtonState } from "../pagination.svelte";
import { createId } from "../../utils/create-id";
@ -15,8 +15,8 @@
}: PaginationPrevButtonProps = $props();
const buttonState = PaginationPrevButtonState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
});
const mergedProps = $derived(mergeProps(restProps, buttonState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { PaginationRootProps } from "../types";
import { PaginationRootState } from "../pagination.svelte";
import { createId } from "../../utils/create-id";
@ -23,15 +23,15 @@
}: PaginationRootProps = $props();
const rootState = PaginationRootState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
count: boxWith(() => count),
perPage: boxWith(() => perPage),
siblingCount: boxWith(() => siblingCount),
page: boxWith(() => page, (v) => (page = v)),
onPageChange: boxWith(() => onPageChange),
orientation: boxWith(() => orientation),
loop: boxWith(() => loop),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
count: readableActive(() => count),
perPage: readableActive(() => perPage),
siblingCount: readableActive(() => siblingCount),
page: writableActive(() => page, (v) => (page = v)),
onPageChange: readableActive(() => onPageChange),
orientation: readableActive(() => orientation),
loop: readableActive(() => loop),
});
const mergedProps = $derived(mergeProps(restProps, rootState.props));

@ -1,7 +1,7 @@
import {
attachRef,
type ReadableBoxedValues,
type WritableBoxedValues,
type ActiveProps,
type StateProps,
} from "../utils/index";
import type { RefAttachment, WithRefOpts, TerraKeyboardEvent, TerraMouseEvent } from "../utils/types";
import { createTerraAttrs } from "../utils/attrs";
@ -28,7 +28,7 @@ const PaginationRootContext = new Context<PaginationRootState>("Pagination.Root"
interface PaginationRootStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
count: number;
perPage: number;
siblingCount: number;
@ -36,7 +36,7 @@ interface PaginationRootStateOpts
loop: boolean;
onPageChange: (page: number) => void;
}>,
WritableBoxedValues<{ page: number }> {}
StateProps<{ page: number }> {}
export class PaginationRootState {
static create(opts: PaginationRootStateOpts) {
@ -111,7 +111,7 @@ export class PaginationRootState {
interface PaginationPageStateOpts
extends WithRefOpts,
ReadableBoxedValues<{ page: number; disabled: boolean }> {}
ActiveProps<{ page: number; disabled: boolean }> {}
export class PaginationPageState {
static create(opts: PaginationPageStateOpts) {

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { PinInputCellProps } from "../types";
import { PinInputCellState } from "../pin-input.svelte";
import { createId } from "../../utils/create-id";
@ -16,9 +16,9 @@
}: PinInputCellProps = $props();
const cellState = PinInputCellState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
cell: boxWith(() => cell),
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
cell: readableActive(() => cell),
});
const mergedProps = $derived(mergeProps(restProps, cellState.props));

@ -1,5 +1,5 @@
<script lang="ts">
import { boxWith, mergeProps } from "../../utils/index";
import { readableActive, writableActive, mergeProps } from "../../utils/index";
import type { PinInputRootProps } from "../types";
import { PinInputRootState } from "../pin-input.svelte";
import { createId } from "../../utils/create-id";
@ -28,25 +28,25 @@
}: PinInputRootProps = $props();
const rootState = PinInputRootState.create({
id: boxWith(() => id),
ref: boxWith(() => ref, (v) => (ref = v)),
inputId: boxWith(() => inputId),
autocomplete: boxWith(() => autocomplete),
maxLength: boxWith(() => maxlength),
textAlign: boxWith(() => textalign),
disabled: boxWith(() => disabled),
inputmode: boxWith(() => inputmode),
pattern: boxWith(() => pattern),
onComplete: boxWith(() => onComplete),
value: boxWith(
id: readableActive(() => id),
ref: writableActive(() => ref, (v) => (ref = v)),
inputId: readableActive(() => inputId),
autocomplete: readableActive(() => autocomplete),
maxLength: readableActive(() => maxlength),
textAlign: readableActive(() => textalign),
disabled: readableActive(() => disabled),
inputmode: readableActive(() => inputmode),
pattern: readableActive(() => pattern),
onComplete: readableActive(() => onComplete),
value: writableActive(
() => value,
(v) => {
value = v;
(onValueChange as (v: string) => void)(v);
}
),
pushPasswordManagerStrategy: boxWith(() => pushPasswordManagerStrategy),
pasteTransformer: boxWith(() => pasteTransformer),
pushPasswordManagerStrategy: readableActive(() => pushPasswordManagerStrategy),
pasteTransformer: readableActive(() => pasteTransformer),
});
const mergedInputProps = $derived(mergeProps(restProps, rootState.inputProps));

@ -1,12 +1,12 @@
import { Previous, watch } from "runed";
import { onMount } from "svelte";
import {
type WritableBox,
type State,
attachRef,
DOMContext,
type ReadableBoxedValues,
type WritableBoxedValues,
simpleBox,
type ActiveProps,
type StateProps,
state,
getWindow,
} from "../utils/index";
import { usePasswordManagerBadge } from "./usePasswordManager.svelte";
@ -33,10 +33,10 @@ const pinInputAttrs = createTerraAttrs({
interface PinInputRootStateOpts
extends WithRefOpts,
WritableBoxedValues<{
StateProps<{
value: string;
}>,
ReadableBoxedValues<{
ActiveProps<{
inputId: string;
disabled: boolean;
// oxlint-disable-next-line no-explicit-any
@ -56,7 +56,7 @@ interface PrevInputMetadata {
willSyntheticBlur: boolean;
}
interface InitialLoad {
value: WritableBox<string>;
value: State<string>;
isIOS: boolean;
}
@ -84,10 +84,10 @@ export class PinInputRootState {
readonly opts: PinInputRootStateOpts;
readonly attachment: RefAttachment;
#inputRef = simpleBox<HTMLInputElement | null>(null);
#inputRef = state<HTMLInputElement | null>(null);
#isHoveringInput = $state(false);
readonly inputAttachment: RefAttachment<HTMLInputElement> = attachRef(this.#inputRef);
#isFocused = simpleBox(false);
#isFocused = state(false);
#mirrorSelectionStart = $state<number | null>(null);
#mirrorSelectionEnd = $state<number | null>(null);
@ -512,7 +512,7 @@ export class PinInputRootState {
interface PinInputCellStateOpts
extends WithRefOpts,
ReadableBoxedValues<{
ActiveProps<{
cell: PinInputCell;
}> {}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save

Powered by TurnKey Linux.