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.
112 lines
3.0 KiB
112 lines
3.0 KiB
import type { Morfo } from '../types';
|
|
import { v } from '../types';
|
|
|
|
export const announceMorfo = {
|
|
name: 'Announce',
|
|
kebab: 'announce',
|
|
scope: ['soma', 'sema'],
|
|
// Announce IS sema's `signal.announce/alert` literal. Pack exists in
|
|
// `sema/components/announce.ts` when needed; for now family base is fine.
|
|
expression: 'family-default',
|
|
texts: {
|
|
label: '#?components.announce.label|Announcements'
|
|
},
|
|
events: [
|
|
{
|
|
// Polite message posted (non-critical info — saved, fetched, queued).
|
|
// Per book cap. 24 §5.1 literal: `signal.announce + neutral` —
|
|
// "esto existe, sin urgencia." Announcing is the canonical signal
|
|
// verb. Was misclassified as commit.submit (commit fixes state;
|
|
// announce just orients attention).
|
|
name: 'signal-announce',
|
|
semantic: {
|
|
family: 'signal',
|
|
verb: 'announce',
|
|
target: v.partRef('provider'),
|
|
intent: 'neutral',
|
|
sequence: 'post'
|
|
}
|
|
},
|
|
{
|
|
// Assertive message posted (error or urgent notice — interrupts speech).
|
|
// Per book cap. 24: `signal.alert + threat` — "atiende ahora."
|
|
// Was misclassified as commit.submit + threat.
|
|
//
|
|
// Persistence: book §6.2 — signal.threat = untilAction. The
|
|
// projection stays until the caller clears (typically when the
|
|
// user acknowledges the alert via a Toast action, dismisses the
|
|
// banner, or the next message overwrites it).
|
|
name: 'signal-alert',
|
|
semantic: {
|
|
family: 'signal',
|
|
verb: 'alert',
|
|
target: v.partRef('provider'),
|
|
intent: 'threat',
|
|
sequence: 'post',
|
|
persistence: 'untilAction'
|
|
},
|
|
// Book §9.2: signal.alert + threat needs a persistent trace AND
|
|
// a live region. Focus move is handled by the assertive aria-live
|
|
// behavior of the underlying region — we don't yank focus
|
|
// programmatically because Announce is visually hidden; doing so
|
|
// would teleport sighted users to nowhere.
|
|
a11ySemantic: {
|
|
requiresPersistentTrace: true,
|
|
requiresLiveRegion: true
|
|
}
|
|
},
|
|
{
|
|
// All internal live regions cleared.
|
|
name: 'commit-reset',
|
|
semantic: {
|
|
family: 'commit',
|
|
verb: 'reset',
|
|
target: v.partRef('provider'),
|
|
intent: 'neutral',
|
|
sequence: 'post'
|
|
}
|
|
}
|
|
],
|
|
parts: [
|
|
{
|
|
name: 'Provider',
|
|
kebab: 'provider',
|
|
archetype: 'provider',
|
|
kind: 'public',
|
|
defaultElement: 'div',
|
|
optional: false,
|
|
data: [],
|
|
aria: []
|
|
},
|
|
{
|
|
name: 'Region',
|
|
kebab: 'region',
|
|
archetype: 'content',
|
|
kind: 'public',
|
|
defaultElement: 'div',
|
|
optional: true,
|
|
data: [
|
|
{
|
|
attr: 'data-role',
|
|
values: ['status', 'alert', 'log', 'timer'],
|
|
value: v.propRef('role')
|
|
},
|
|
{
|
|
attr: 'data-live',
|
|
values: ['polite', 'assertive'],
|
|
value: v.propRef('ariaLive')
|
|
}
|
|
],
|
|
aria: [
|
|
{ attr: 'role', value: v.propRef('role') },
|
|
{ attr: 'aria-live', value: v.propRef('ariaLive') },
|
|
{
|
|
attr: 'aria-atomic',
|
|
value: v.mapRef(v.propRef('ariaAtomic'), { true: 'true', false: 'false' })
|
|
},
|
|
{ attr: 'aria-relevant', value: v.propRef('ariaRelevant') }
|
|
]
|
|
}
|
|
]
|
|
} as const satisfies Morfo;
|