You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/morfo/components/collapsible.ts

136 lines
3.8 KiB

import type { Morfo } from '../types';
import { v } from '../types';
/**
* Collapsible — disclosure pattern (header + body).
*
* Per `src/docs/GUIA_IMPLEMENTACION_SEMAUIX.md` §4.1 (Accordion =
* emerge.expand): the disclosure flip has two perceptual directions
* with distinct signatures, so it declares TWO events instead of one
* `commit-toggle`. Both belong to the `emerge` family (transitional —
* no intent). `emerge-expand` is post-sequence so the content exists
* visually before Eidos reacts to `data-event='emerge-expand'`;
* `emerge-collapse` is post too (collapsible-NEW-001) so the conceal
* plays against a content the flip has not yet hidden.
*
* No intent / color subset — disclosure is non-evaluative. Air had a
* manual `air.interaction.play('expansion', enter|exit)` that the
* sema engine now subsumes via runtime.trigger.
*/
export const collapsibleMorfo = {
name: 'Collapsible',
kebab: 'collapsible',
scope: ['soma', 'sema', 'eidos'],
// expression resolved via the sema pack at
// `src/uix/sema/components/collapsible.ts` — mirrors accordion
// (`emerge.soft` expand + `emerge.exit` collapse). Coherence with
// the sibling disclosure pattern.
expression: 'pack',
texts: {
label: '#?components.collapsible.label|Collapsible'
},
apg: 'https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/',
events: [
{
name: 'emerge-expand',
semantic: {
family: 'emerge',
verb: 'expand',
target: v.partRef('content'),
sequence: 'post'
}
},
{
name: 'emerge-collapse',
semantic: {
family: 'emerge',
verb: 'collapse',
target: v.partRef('content'),
// `post` (not `pre`): the provider sets `open = false` inside the
// runtime HANDLER, so `pre` deferred the close behind the full
// perceptual hold (~250ms measured dead delay — the Checkbox-lag
// class, collapsible-NEW-001). With `post` the content closes
// immediately; the CSS exit animation is keyed on `data-state`.
sequence: 'post'
}
}
],
parts: [
{
name: 'Provider',
kebab: 'provider',
archetype: 'provider',
kind: 'public',
defaultElement: 'div',
optional: false,
states: ['open', 'closed'],
data: [
{ attr: 'data-state', values: ['open', 'closed'], value: v.stateRef('open') },
{
attr: 'data-disabled',
value: v.propRef('disabled'),
severity: 'optional',
condition: { when: 'prop-truthy', prop: 'disabled' }
}
],
aria: []
},
{
name: 'Trigger',
kebab: 'trigger',
archetype: 'trigger',
kind: 'public',
defaultElement: 'button',
role: 'button',
optional: false,
states: ['open', 'closed'],
data: [
{ attr: 'data-state', values: ['open', 'closed'], value: v.stateRef('open') },
{
attr: 'data-disabled',
value: v.propRef('disabled'),
severity: 'optional',
condition: { when: 'prop-truthy', prop: 'disabled' }
}
],
aria: [
{ attr: 'type', value: v.literal('button') },
{ attr: 'aria-expanded', value: v.stateRef('open') },
{
attr: 'aria-controls',
value: v.partRef('content'),
condition: { when: 'part-present', part: 'content' },
severity: 'recommended'
}
]
},
{
name: 'Content',
kebab: 'content',
archetype: 'content',
kind: 'public',
defaultElement: 'div',
role: 'region',
optional: false,
states: ['open', 'closed'],
data: [
{ attr: 'data-state', values: ['open', 'closed'], value: v.stateRef('open') },
{
attr: 'data-disabled',
value: v.propRef('disabled'),
severity: 'optional',
condition: { when: 'prop-truthy', prop: 'disabled' }
}
],
aria: [
{
attr: 'aria-labelledby',
value: v.partRef('trigger'),
condition: { when: 'part-present', part: 'trigger' },
severity: 'recommended'
}
]
}
]
} as const satisfies Morfo;

Powered by TurnKey Linux.