Add UIX permutation axis coverage

active-uix
dev 5 months ago
parent 277f1f24dc
commit bddfff9e39

@ -31,6 +31,25 @@ Actualizacion permutation runner 2026-05-16:
- Los 53 morfos restantes no tienen ruta `/uix/components/{kebab}` en el
shell actual; no contarlos como cobertura hasta que exista demo.
Actualizacion permutation axes 2026-05-16:
- Variantes URL del runner activadas en demos que ya tenian estado real para
honrarlas:
- `accordion`: `disabled`.
- `collapsible`: `disabled`.
- `checkbox`: `disabled`, `invalid`.
- `radio-group`: `dir`, `disabled`, `invalid`.
- `switch`: `disabled`, `invalid`.
- `tabs`: `dir`, `orientation`, `disabled`.
- `toggle`: `disabled`, `invalid`.
- `tooltip`: `dir`, `disabled`.
- En variantes `disabled`, los pasos interactivos se omiten desde la propia
demo para validar el estado estatico deshabilitado sin forzar clicks sobre
controles inactivos.
- Validacion: `node --import tsx/esm scripts/permutation-check.ts
http://127.0.0.1:5192` -> 12 demos instrumentadas OK, 54 pasos, 28 variantes
URL.
Arranque rapido para mañana:
- Rama `active-uix` queda por delante de `gita/active-uix` con los commits de

@ -8,8 +8,10 @@
import { compileMorfo } from '$uix/morfo';
import { accordionMorfo } from '@/uix/morfo/components/accordion';
import { getActiveUix } from '$active-uix';
import { page } from '$app/state';
const uix = getActiveUix();
const params = page.url.searchParams;
type Tab = 'live' | 'api' | 'morfo' | 'sema' | 'recipe' | 'a11y';
let tab = $state<Tab>('live');
@ -22,7 +24,7 @@
let size = $state<AccordionSize>('md');
let variant = $state<AccordionVariant>('outline');
let collapsible = $state(true);
let disabled = $state(false);
let disabled = $state(params.get('perm.disabled') === 'true');
let orientation = $state<Orientation>('vertical');
let loop = $state(false);
let region = $state(true);
@ -142,6 +144,10 @@
);
</script>
<svelte:head>
<meta name="perm-axes" content="disabled" />
</svelte:head>
<div data-uix-canvas-inner>
<header>
<div data-uix-eyebrow>Disclosure · Accordion</div>
@ -193,8 +199,8 @@
<Accordion.Trigger
{hideIndicator}
{indicatorPlacement}
data-perm-step={item.value === 'b' ? '0' : undefined}
data-perm-label={item.value === 'b' ? 'open sema item' : undefined}
data-perm-step={!disabled && item.value === 'b' ? '0' : undefined}
data-perm-label={!disabled && item.value === 'b' ? 'open sema item' : undefined}
>{item.title}</Accordion.Trigger>
</Accordion.Header>
<Accordion.Content>

@ -9,8 +9,10 @@
import { compileMorfo } from '$uix/morfo';
import { checkboxMorfo } from '@/uix/morfo/components/checkbox';
import { getActiveUix } from '$active-uix';
import { page } from '$app/state';
const uix = getActiveUix();
const params = page.url.searchParams;
type Tab = 'live' | 'api' | 'morfo' | 'sema' | 'recipe' | 'a11y';
let tab = $state<Tab>('live');
@ -18,10 +20,10 @@
// ── State ──────────────────────────────────────────────────────────────
let checked = $state(false);
let indeterminate = $state(false);
let disabled = $state(false);
let disabled = $state(params.get('perm.disabled') === 'true');
let readonly = $state(false);
let required = $state(false);
let invalid = $state(false);
let invalid = $state(params.get('perm.invalid') === 'true');
let size = $state<CheckboxSize>('md');
let variant = $state<CheckboxVariant>('solid');
let color = $state<CheckboxColor>('primary');
@ -135,6 +137,10 @@
);
</script>
<svelte:head>
<meta name="perm-axes" content="disabled,invalid" />
</svelte:head>
{#snippet customIcon({ checked: c, indeterminate: i }: CheckboxIconSnippetArgs)}
{#if i}
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="12" cy="12" r="3" /></svg>
@ -178,8 +184,8 @@
{color}
name={nameAttr || undefined}
value={valueAttr}
data-perm-step="0"
data-perm-label="toggle main checkbox"
data-perm-step={disabled ? undefined : '0'}
data-perm-label={disabled ? undefined : 'toggle main checkbox'}
>
<Checkbox.Indicator icon={useCustomIcon ? customIcon : undefined} />
{#if nameAttr}<Checkbox.HiddenInput />{/if}

@ -3,15 +3,17 @@
import { compileMorfo } from '$uix/morfo';
import { collapsibleMorfo } from '@/uix/morfo/components/collapsible';
import { getActiveUix } from '$active-uix';
import { page } from '$app/state';
const uix = getActiveUix();
const params = page.url.searchParams;
type Tab = 'live' | 'api' | 'morfo' | 'sema' | 'recipe' | 'a11y';
let tab = $state<Tab>('live');
// ── Live state ────────────────────────────────────────────────────────
let open = $state(false);
let disabled = $state(false);
let disabled = $state(params.get('perm.disabled') === 'true');
let triggerLabel = $state('Show details');
let bodyText = $state(
'Disclosure is non-evaluative — no intent / color / size. The morfo declares TWO emerge events instead of one toggle so expand (sequence: post) and collapse (sequence: pre) can carry distinct perceptual signatures.'
@ -98,6 +100,10 @@
);
</script>
<svelte:head>
<meta name="perm-axes" content="disabled" />
</svelte:head>
<div data-uix-canvas-inner>
<header>
<div data-uix-eyebrow>Disclosure · Collapsible</div>
@ -128,7 +134,10 @@
<div data-uix-stage>
<div data-uix-stage-area bind:this={stageRef}>
<Collapsible bind:open {disabled}>
<Collapsible.Trigger data-perm-step="0" data-perm-label="toggle disclosure">
<Collapsible.Trigger
data-perm-step={disabled ? undefined : '0'}
data-perm-label={disabled ? undefined : 'toggle disclosure'}
>
{triggerLabel}
</Collapsible.Trigger>
<Collapsible.Content>

@ -10,24 +10,26 @@
import { compileMorfo } from '$uix/morfo';
import { radioGroupMorfo } from '@/uix/morfo/components/radio-group';
import { getActiveUix } from '$active-uix';
import { page } from '$app/state';
const uix = getActiveUix();
const params = page.url.searchParams;
type Tab = 'live' | 'api' | 'morfo' | 'sema' | 'recipe' | 'a11y';
let tab = $state<Tab>('live');
let value = $state('pro');
let disabled = $state(false);
let disabled = $state(params.get('perm.disabled') === 'true');
let readonly = $state(false);
let required = $state(false);
let invalid = $state(false);
let invalid = $state(params.get('perm.invalid') === 'true');
let size = $state<RadioGroupSize>('md');
let variant = $state<RadioGroupVariant>('solid');
let color = $state<RadioGroupColor>('primary');
let orientation = $state<Orientation>('vertical');
let columns = $state<number | undefined>(undefined);
let loop = $state(false);
let dir = $state<'ltr' | 'rtl'>('ltr');
let dir = $state<'ltr' | 'rtl'>((params.get('perm.dir') as 'ltr' | 'rtl' | null) ?? 'ltr');
let nameAttr = $state('plan');
let labelText = $state('Choose a plan');
let useCustomIcon = $state(false);
@ -139,6 +141,10 @@
);
</script>
<svelte:head>
<meta name="perm-axes" content="dir,disabled,invalid" />
</svelte:head>
{#snippet customIcon({ checked: c }: RadioGroupIconSnippetArgs)}
{#if c}
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
@ -187,8 +193,8 @@
<RadioGroup.Item
value={item.value}
disabled={item.disabled}
data-perm-step={item.value === 'team' ? '0' : undefined}
data-perm-label={item.value === 'team' ? 'select team plan' : undefined}
data-perm-step={!disabled && item.value === 'team' ? '0' : undefined}
data-perm-label={!disabled && item.value === 'team' ? 'select team plan' : undefined}
>
<RadioGroup.Indicator icon={useCustomIcon ? customIcon : undefined} />
{#if nameAttr}<RadioGroup.HiddenInput />{/if}

@ -3,8 +3,10 @@
import { compileMorfo } from '$uix/morfo';
import { switchMorfo } from '@/uix/morfo/components/switch';
import { getActiveUix } from '$active-uix';
import { page } from '$app/state';
const uix = getActiveUix();
const params = page.url.searchParams;
type Tab = 'live' | 'api' | 'morfo' | 'sema' | 'recipe' | 'a11y';
let tab = $state<Tab>('live');
@ -17,9 +19,9 @@
let size = $state<SwitchSize>('md');
let intent = $state<SwitchIntent>('neutral');
let color = $state<SwitchColor>(undefined);
let disabled = $state(false);
let disabled = $state(params.get('perm.disabled') === 'true');
let readonly = $state(false);
let invalid = $state(false);
let invalid = $state(params.get('perm.invalid') === 'true');
let required = $state(false);
let label = $state('Notifications');
@ -110,6 +112,10 @@
);
</script>
<svelte:head>
<meta name="perm-axes" content="disabled,invalid" />
</svelte:head>
<div data-uix-canvas-inner>
<header>
<div data-uix-eyebrow>Forms · Switch</div>
@ -155,8 +161,8 @@
{required}
{invalid}
aria-label={label}
data-perm-step="0"
data-perm-label="toggle switch"
data-perm-step={disabled ? undefined : '0'}
data-perm-label={disabled ? undefined : 'toggle switch'}
/>
<span>{label}</span>
</label>

@ -11,8 +11,10 @@
import { compileMorfo } from '$uix/morfo';
import { tabsMorfo } from '@/uix/morfo/components/tabs';
import { getActiveUix } from '$active-uix';
import { page } from '$app/state';
const uix = getActiveUix();
const params = page.url.searchParams;
type Tab = 'live' | 'api' | 'morfo' | 'sema' | 'recipe' | 'a11y';
let tab = $state<Tab>('live');
@ -21,11 +23,13 @@
let value = $state('overview');
let variant = $state<TabsVariant>('line');
let size = $state<TabsSize>('md');
let orientation = $state<Orientation>('horizontal');
let orientation = $state<Orientation>(
(params.get('perm.orientation') as Orientation | null) ?? 'horizontal'
);
let activationMode = $state<ActivationMode>('automatic');
let loop = $state(true);
let dir = $state<'ltr' | 'rtl'>('ltr');
let disabled = $state(false);
let dir = $state<'ltr' | 'rtl'>((params.get('perm.dir') as 'ltr' | 'rtl' | null) ?? 'ltr');
let disabled = $state(params.get('perm.disabled') === 'true');
let fitted = $state(false);
let scrollable = $state(false);
let collapseAt = $state<TabsCollapseAt>('never');
@ -146,6 +150,10 @@
);
</script>
<svelte:head>
<meta name="perm-axes" content="dir,orientation,disabled" />
</svelte:head>
<div data-uix-canvas-inner>
<header>
<div data-uix-eyebrow>Controls · Tabs</div>
@ -191,10 +199,14 @@
<Tabs.Trigger
value="billing"
disabled={billingDisabled}
data-perm-step="0"
data-perm-label="select billing tab"
data-perm-step={disabled ? undefined : '0'}
data-perm-label={disabled ? undefined : 'select billing tab'}
>Billing</Tabs.Trigger>
<Tabs.Trigger value="team" data-perm-step="1" data-perm-label="select team tab">Team</Tabs.Trigger>
<Tabs.Trigger
value="team"
data-perm-step={disabled ? undefined : '1'}
data-perm-label={disabled ? undefined : 'select team tab'}
>Team</Tabs.Trigger>
<Tabs.Trigger value="integrations">Integrations</Tabs.Trigger>
{#if showIndicator && variant !== 'surface'}<Tabs.Indicator />{/if}
</Tabs.List>

@ -6,18 +6,20 @@
import { compileMorfo } from '$uix/morfo';
import { toggleMorfo } from '@/uix/morfo/components/toggle';
import { getActiveUix } from '$active-uix';
import { page } from '$app/state';
const uix = getActiveUix();
const params = page.url.searchParams;
type Tab = 'live' | 'api' | 'morfo' | 'sema' | 'recipe' | 'a11y';
let tab = $state<Tab>('live');
// ── State ──────────────────────────────────────────────────────────────
let pressed = $state(false);
let disabled = $state(false);
let disabled = $state(params.get('perm.disabled') === 'true');
let readonly = $state(false);
let required = $state(false);
let invalid = $state(false);
let invalid = $state(params.get('perm.invalid') === 'true');
let intent = $state<'neutral' | 'affirm' | 'risk' | 'threat'>('neutral');
let color = $state<'primary' | 'secondary' | ''>('');
let size = $state<ToggleSize>('md');
@ -129,6 +131,10 @@
);
</script>
<svelte:head>
<meta name="perm-axes" content="disabled,invalid" />
</svelte:head>
{#snippet boldIcon()}
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z" />
@ -179,8 +185,8 @@
aria-label={ariaLabel || undefined}
icon={showIcon ? boldIcon : undefined}
checkMark={showCheckMark}
data-perm-step="0"
data-perm-label="toggle pressed state"
data-perm-step={disabled ? undefined : '0'}
data-perm-label={disabled ? undefined : 'toggle pressed state'}
>
{labelText}
</Toggle>

@ -7,6 +7,9 @@
import { compileMorfo } from '$uix/morfo';
import { tooltipMorfo } from '@/uix/morfo/components/tooltip';
import type { Side, Align } from '$soma/layers/floating';
import { page } from '$app/state';
const params = page.url.searchParams;
type Tab = 'live' | 'api' | 'morfo' | 'recipe' | 'a11y';
let tab = $state<Tab>('live');
@ -21,7 +24,7 @@
let open = $state(false);
let providerDelay = $state<number | undefined>(undefined);
let closeDelay = $state(150);
let providerDisabled = $state(false);
let providerDisabled = $state(params.get('perm.disabled') === 'true');
// ── Content state ─────────────────────────────────────────────────────
let size = $state<TooltipSize>('md');
@ -35,7 +38,9 @@
let hideWhenDetached = $state(true);
let forceMount = $state(false);
let ariaLabel = $state('');
let dir = $state<'' | 'ltr' | 'rtl'>('');
let dir = $state<'' | 'ltr' | 'rtl'>(
(params.get('perm.dir') as 'ltr' | 'rtl' | null) ?? ''
);
// ── Arrow state ───────────────────────────────────────────────────────
let showArrow = $state(true);
@ -130,6 +135,10 @@
);
</script>
<svelte:head>
<meta name="perm-axes" content="dir,disabled" />
</svelte:head>
<div data-uix-canvas-inner>
<header>
<div data-uix-eyebrow>Overlays · Tooltip</div>
@ -164,9 +173,9 @@
disabled={providerDisabled}
>
<Tooltip.Trigger
data-perm-step="0"
data-perm-label="focus tooltip"
data-perm-mode="focus"
data-perm-step={providerDisabled ? undefined : '0'}
data-perm-label={providerDisabled ? undefined : 'focus tooltip'}
data-perm-mode={providerDisabled ? undefined : 'focus'}
data-perm-settle="900"
>{triggerLabel}</Tooltip.Trigger>
<Tooltip.Content

Loading…
Cancel
Save

Powered by TurnKey Linux.