|
|
|
|
@ -0,0 +1,586 @@
|
|
|
|
|
<script lang="ts">
|
|
|
|
|
import { Result, type ResultStatus, type ResultTitleLevel } from '$uix/eidos/components/result';
|
|
|
|
|
import { Button } from '$uix/eidos/components/button';
|
|
|
|
|
import { compileMorfo } from '$uix/morfo';
|
|
|
|
|
import { resultMorfo } from '@/uix/morfo/components/result';
|
|
|
|
|
import { getActiveUix } from '$active-uix';
|
|
|
|
|
|
|
|
|
|
import SystemAxes from '../../lib/SystemAxes.svelte';
|
|
|
|
|
import MotionPanel from '../../lib/MotionPanel.svelte';
|
|
|
|
|
import SemaPanel from '../../lib/SemaPanel.svelte';
|
|
|
|
|
import { DemoTrace } from '../../lib/harness.svelte';
|
|
|
|
|
|
|
|
|
|
const uix = getActiveUix();
|
|
|
|
|
|
|
|
|
|
type Tab = 'live' | 'system' | 'motion' | 'sema' | 'services' | 'api' | 'morfo' | 'recipe' | 'a11y';
|
|
|
|
|
let tab = $state<Tab>('live');
|
|
|
|
|
|
|
|
|
|
// ── Stage + System axes ──────────────────────────────────────────────
|
|
|
|
|
const trace = new DemoTrace();
|
|
|
|
|
let stageRef = $state<HTMLElement | null>(null);
|
|
|
|
|
$effect(() => {
|
|
|
|
|
if (stageRef) return trace.observe(stageRef);
|
|
|
|
|
});
|
|
|
|
|
let density = $state('comfortable');
|
|
|
|
|
let scaling = $state(1);
|
|
|
|
|
let mode = $state<'inherit' | 'light' | 'dark'>('inherit');
|
|
|
|
|
let dir = $state<'ltr' | 'rtl'>('ltr');
|
|
|
|
|
let borderWidth = $state(1);
|
|
|
|
|
|
|
|
|
|
// ── Live state ───────────────────────────────────────────────────────
|
|
|
|
|
const statuses: ResultStatus[] = [
|
|
|
|
|
'success',
|
|
|
|
|
'error',
|
|
|
|
|
'info',
|
|
|
|
|
'warning',
|
|
|
|
|
'forbidden',
|
|
|
|
|
'not-found',
|
|
|
|
|
'server-error'
|
|
|
|
|
];
|
|
|
|
|
const levels: ResultTitleLevel[] = [1, 2, 3, 4];
|
|
|
|
|
|
|
|
|
|
let status = $state<ResultStatus>('success');
|
|
|
|
|
let level = $state<ResultTitleLevel>(2);
|
|
|
|
|
let withMedia = $state(true);
|
|
|
|
|
let withDescription = $state(true);
|
|
|
|
|
let withActions = $state(true);
|
|
|
|
|
let withSecondary = $state(true);
|
|
|
|
|
let withExtra = $state(false);
|
|
|
|
|
|
|
|
|
|
// Demo copy per status (app content — the component bakes no strings).
|
|
|
|
|
const COPY: Record<ResultStatus, { title: string; description: string }> = {
|
|
|
|
|
success: { title: 'Payment complete', description: 'We emailed the receipt to you.' },
|
|
|
|
|
error: {
|
|
|
|
|
title: 'Submission failed',
|
|
|
|
|
description: 'Check the details below and try again.'
|
|
|
|
|
},
|
|
|
|
|
info: { title: 'Your request was queued', description: 'We will notify you when it runs.' },
|
|
|
|
|
warning: {
|
|
|
|
|
title: 'Saved with warnings',
|
|
|
|
|
description: 'Some optional fields were skipped.'
|
|
|
|
|
},
|
|
|
|
|
forbidden: {
|
|
|
|
|
title: 'You are not authorized',
|
|
|
|
|
description: 'Ask an administrator for access to this page.'
|
|
|
|
|
},
|
|
|
|
|
'not-found': {
|
|
|
|
|
title: 'Page not found',
|
|
|
|
|
description: 'The page you visited does not exist.'
|
|
|
|
|
},
|
|
|
|
|
'server-error': {
|
|
|
|
|
title: 'Something went wrong',
|
|
|
|
|
description: 'The server had a problem. Try again in a minute.'
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const copy = $derived(COPY[status]);
|
|
|
|
|
|
|
|
|
|
// ── Compiled morfo ───────────────────────────────────────────────────
|
|
|
|
|
const compiled = compileMorfo(resultMorfo);
|
|
|
|
|
const partsList = [...compiled.parts.byKebab.values()];
|
|
|
|
|
const events = [...compiled.actions.byName.values()];
|
|
|
|
|
|
|
|
|
|
// ── Code snippet (parity with the live controls) ─────────────────────
|
|
|
|
|
const eidosSnippet = $derived(
|
|
|
|
|
[
|
|
|
|
|
"<script lang='ts'>",
|
|
|
|
|
" import { Result } from '$uix/eidos/components/result';",
|
|
|
|
|
" import { Button } from '$uix/eidos/components/button';",
|
|
|
|
|
'</' + 'script>',
|
|
|
|
|
'',
|
|
|
|
|
`<Result status="${status}">`,
|
|
|
|
|
withMedia && ' <Result.Media />',
|
|
|
|
|
level === 2
|
|
|
|
|
? ` <Result.Title>${copy.title}</Result.Title>`
|
|
|
|
|
: ` <Result.Title level={${level}}>${copy.title}</Result.Title>`,
|
|
|
|
|
withDescription && ` <Result.Description>${copy.description}</Result.Description>`,
|
|
|
|
|
withActions && ' <Result.Actions label="Result actions">',
|
|
|
|
|
withActions && ' <Button>Back home</Button>',
|
|
|
|
|
withActions && withSecondary && ' <Button variant="ghost">Contact support</Button>',
|
|
|
|
|
withActions && ' </Result.Actions>',
|
|
|
|
|
withExtra && ' <Result.Extra>…detail list…</Result.Extra>',
|
|
|
|
|
'</Result>'
|
|
|
|
|
]
|
|
|
|
|
.filter(Boolean)
|
|
|
|
|
.join('\n')
|
|
|
|
|
);
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<div data-uix-canvas-inner>
|
|
|
|
|
<header>
|
|
|
|
|
<div data-uix-eyebrow>Status · Result</div>
|
|
|
|
|
<h1 data-uix-page-title>Result</h1>
|
|
|
|
|
<p data-uix-page-lede>
|
|
|
|
|
Terminal flow/page state: an operation or route resolved and this surface reports how —
|
|
|
|
|
<code>success · error · info · warning</code> plus the three HTTP situations
|
|
|
|
|
(<code>forbidden · not-found · server-error</code>, rendered NEUTRAL: situations, not
|
|
|
|
|
failures). Shares <a href="/uix/components/empty-state"><EmptyState></a>'s skeleton
|
|
|
|
|
deliberately — EmptyState describes absence of data, Result reports an outcome. The default
|
|
|
|
|
media composes the doctrinal <code>IntentIcon</code> map (success→fulfill · error→threat ·
|
|
|
|
|
warning→risk); children replace it entirely.
|
|
|
|
|
</p>
|
|
|
|
|
<div data-uix-page-meta>
|
|
|
|
|
<span data-uix-meta-pill>
|
|
|
|
|
<span data-uix-meta-key>parts</span>{compiled.parts.order.length}
|
|
|
|
|
</span>
|
|
|
|
|
<span data-uix-meta-pill>
|
|
|
|
|
<span data-uix-meta-key>events</span>{events.length}
|
|
|
|
|
</span>
|
|
|
|
|
<span data-uix-meta-pill>
|
|
|
|
|
<span data-uix-meta-key>statuses</span>{statuses.length}
|
|
|
|
|
</span>
|
|
|
|
|
<span data-uix-meta-pill>
|
|
|
|
|
<span data-uix-meta-key>scope</span>eidos
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<!-- Always-on stage — carries the System axes -->
|
|
|
|
|
<div data-uix-stage>
|
|
|
|
|
<div
|
|
|
|
|
data-uix-stage-area
|
|
|
|
|
bind:this={stageRef}
|
|
|
|
|
data-density={density}
|
|
|
|
|
data-theme={mode === 'inherit' ? undefined : mode}
|
|
|
|
|
data-mode={mode === 'inherit' ? undefined : mode}
|
|
|
|
|
{dir}
|
|
|
|
|
style={`--scaling: ${scaling}; --border-width: ${borderWidth}px;`}
|
|
|
|
|
>
|
|
|
|
|
<Result {status}>
|
|
|
|
|
{#if withMedia}
|
|
|
|
|
<Result.Media />
|
|
|
|
|
{/if}
|
|
|
|
|
<Result.Title {level}>{copy.title}</Result.Title>
|
|
|
|
|
{#if withDescription}
|
|
|
|
|
<Result.Description>{copy.description}</Result.Description>
|
|
|
|
|
{/if}
|
|
|
|
|
{#if withActions}
|
|
|
|
|
<Result.Actions label="Result actions">
|
|
|
|
|
<Button>Back home</Button>
|
|
|
|
|
{#if withSecondary}
|
|
|
|
|
<Button variant="ghost">Contact support</Button>
|
|
|
|
|
{/if}
|
|
|
|
|
</Result.Actions>
|
|
|
|
|
{/if}
|
|
|
|
|
{#if withExtra}
|
|
|
|
|
<Result.Extra>
|
|
|
|
|
<ul style="margin: 0; padding-inline-start: var(--space-4);">
|
|
|
|
|
<li>Your card was not charged.</li>
|
|
|
|
|
<li>Reference: <code>REQ-2481</code> — include it when contacting support.</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</Result.Extra>
|
|
|
|
|
{/if}
|
|
|
|
|
</Result>
|
|
|
|
|
</div>
|
|
|
|
|
<div data-uix-stage-trace>
|
|
|
|
|
<span data-uix-stage-trace-key>trace</span>
|
|
|
|
|
<span>
|
|
|
|
|
{trace.entries.length === 0 ? 'no semantic events' : `${trace.entries.length} event(s)`}
|
|
|
|
|
</span>
|
|
|
|
|
<span style="color: var(--uix-text-faint)">·</span>
|
|
|
|
|
<span data-uix-stage-trace-key>status</span>
|
|
|
|
|
<span>{status}</span>
|
|
|
|
|
<span style="margin-inline-start: auto;">
|
|
|
|
|
<span data-uix-stage-trace-key>level</span> h{level} ·
|
|
|
|
|
<span data-uix-stage-trace-key>extra</span>
|
|
|
|
|
{withExtra ? 'on' : 'off'}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div data-uix-tabs role="tablist">
|
|
|
|
|
<button data-uix-tab data-active={tab === 'live'} onclick={() => (tab = 'live')}>Live</button>
|
|
|
|
|
<button data-uix-tab data-active={tab === 'system'} onclick={() => (tab = 'system')}>
|
|
|
|
|
System
|
|
|
|
|
</button>
|
|
|
|
|
<button data-uix-tab data-active={tab === 'motion'} onclick={() => (tab = 'motion')}>
|
|
|
|
|
Motion
|
|
|
|
|
</button>
|
|
|
|
|
<button data-uix-tab data-active={tab === 'sema'} onclick={() => (tab = 'sema')}>
|
|
|
|
|
<span data-uix-layer-badge="sema">sema</span>
|
|
|
|
|
<span data-uix-tab-count>{events.length}</span>
|
|
|
|
|
</button>
|
|
|
|
|
<button data-uix-tab data-active={tab === 'services'} onclick={() => (tab = 'services')}>
|
|
|
|
|
Services
|
|
|
|
|
</button>
|
|
|
|
|
<button data-uix-tab data-active={tab === 'api'} onclick={() => (tab = 'api')}>API</button>
|
|
|
|
|
<button data-uix-tab data-active={tab === 'morfo'} onclick={() => (tab = 'morfo')}>
|
|
|
|
|
<span data-uix-layer-badge="morfo">morfo</span>
|
|
|
|
|
<span data-uix-tab-count>{partsList.length}p · {events.length}e</span>
|
|
|
|
|
</button>
|
|
|
|
|
<button data-uix-tab data-active={tab === 'recipe'} onclick={() => (tab = 'recipe')}>
|
|
|
|
|
Recipe
|
|
|
|
|
</button>
|
|
|
|
|
<button data-uix-tab data-active={tab === 'a11y'} onclick={() => (tab = 'a11y')}>A11y</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{#if tab === 'live'}
|
|
|
|
|
<section data-uix-section>
|
|
|
|
|
<h2 data-uix-section-title>Controls</h2>
|
|
|
|
|
<p data-uix-section-desc>
|
|
|
|
|
Result is eidos-native — no <span data-uix-layer-badge="soma">soma</span> split.
|
|
|
|
|
<code>status</code> drives an eidos-only <code>data-status</code> attr: the recipe colors
|
|
|
|
|
the default glyph by role (success→<code>fulfill</code> · error→<code>threat</code> ·
|
|
|
|
|
warning→<code>risk</code> · info→<code>primary</code>) and keeps the HTTP codes NEUTRAL.
|
|
|
|
|
No size axis by design (page-level surface — AntD parity).
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<div data-uix-subsection-head>
|
|
|
|
|
<span data-uix-layer-badge="eidos">eidos</span> props
|
|
|
|
|
</div>
|
|
|
|
|
<div data-uix-controls>
|
|
|
|
|
<label data-uix-control>
|
|
|
|
|
<span data-uix-control-label>status</span>
|
|
|
|
|
<span data-uix-chips role="radiogroup">
|
|
|
|
|
{#each statuses as opt (opt)}
|
|
|
|
|
<button data-uix-chip data-active={status === opt} onclick={() => (status = opt)}>
|
|
|
|
|
{opt}
|
|
|
|
|
</button>
|
|
|
|
|
{/each}
|
|
|
|
|
</span>
|
|
|
|
|
</label>
|
|
|
|
|
<label data-uix-control>
|
|
|
|
|
<span data-uix-control-label>title level</span>
|
|
|
|
|
<span data-uix-chips role="radiogroup">
|
|
|
|
|
{#each levels as opt (opt)}
|
|
|
|
|
<button data-uix-chip data-active={level === opt} onclick={() => (level = opt)}>
|
|
|
|
|
h{opt}
|
|
|
|
|
</button>
|
|
|
|
|
{/each}
|
|
|
|
|
</span>
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div data-uix-subsection-head>Composition</div>
|
|
|
|
|
<div data-uix-controls>
|
|
|
|
|
<label data-uix-control>
|
|
|
|
|
<span data-uix-control-label>media (status default)</span>
|
|
|
|
|
<input type="checkbox" bind:checked={withMedia} />
|
|
|
|
|
</label>
|
|
|
|
|
<label data-uix-control>
|
|
|
|
|
<span data-uix-control-label>description</span>
|
|
|
|
|
<input type="checkbox" bind:checked={withDescription} />
|
|
|
|
|
</label>
|
|
|
|
|
<label data-uix-control>
|
|
|
|
|
<span data-uix-control-label>actions</span>
|
|
|
|
|
<input type="checkbox" bind:checked={withActions} />
|
|
|
|
|
</label>
|
|
|
|
|
<label data-uix-control>
|
|
|
|
|
<span data-uix-control-label>secondary action</span>
|
|
|
|
|
<input type="checkbox" bind:checked={withSecondary} />
|
|
|
|
|
</label>
|
|
|
|
|
<label data-uix-control>
|
|
|
|
|
<span data-uix-control-label>extra (detail block)</span>
|
|
|
|
|
<input type="checkbox" bind:checked={withExtra} />
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div data-uix-code>
|
|
|
|
|
<div data-uix-code-head>
|
|
|
|
|
<span data-uix-layer-badge="eidos">eidos</span>
|
|
|
|
|
<span>composition · status / heading level / extra</span>
|
|
|
|
|
<span data-uix-code-lang>svelte</span>
|
|
|
|
|
</div>
|
|
|
|
|
<pre><code>{eidosSnippet}</code></pre>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
{#if tab === 'system'}
|
|
|
|
|
<section data-uix-section>
|
|
|
|
|
<h2 data-uix-section-title>System axes</h2>
|
|
|
|
|
<p data-uix-section-desc>
|
|
|
|
|
Foundation knobs applied to the stage. Result's typography reads fixed bundle sizes
|
|
|
|
|
(page-level surface), so density/scaling re-derive them coherently.
|
|
|
|
|
</p>
|
|
|
|
|
<SystemAxes bind:density bind:scaling bind:mode bind:dir bind:borderWidth />
|
|
|
|
|
</section>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
{#if tab === 'motion'}
|
|
|
|
|
<section data-uix-section>
|
|
|
|
|
<h2 data-uix-section-title>Motion</h2>
|
|
|
|
|
<MotionPanel
|
|
|
|
|
note="Result has no motion prop and no entrance animation of its own — it usually IS the page. For choreographed entrances compose Cascade around its parts."
|
|
|
|
|
/>
|
|
|
|
|
</section>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
{#if tab === 'sema'}
|
|
|
|
|
<section data-uix-section>
|
|
|
|
|
<h2 data-uix-section-title>
|
|
|
|
|
<span data-uix-layer-badge="sema">sema</span> · events
|
|
|
|
|
</h2>
|
|
|
|
|
<p data-uix-section-desc>
|
|
|
|
|
Result declares no semantic events: the outcome it reports already HAPPENED before this
|
|
|
|
|
surface rendered — the perceptual signal belonged to the operation that resolved (its
|
|
|
|
|
form, its toast, its dialog). The composed <code><Button></code>s in
|
|
|
|
|
<code>.Actions</code> own the next step's sema.
|
|
|
|
|
</p>
|
|
|
|
|
<SemaPanel
|
|
|
|
|
actions={events}
|
|
|
|
|
{uix}
|
|
|
|
|
getTarget={() => stageRef?.querySelector('[data-result]') ?? stageRef}
|
|
|
|
|
/>
|
|
|
|
|
</section>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
{#if tab === 'services'}
|
|
|
|
|
<section data-uix-section>
|
|
|
|
|
<h2 data-uix-section-title>Services</h2>
|
|
|
|
|
<p data-uix-section-desc>
|
|
|
|
|
Result consumes <strong>langs</strong> only for its catalog display name
|
|
|
|
|
(<code>texts.label</code> → «{uix.langs.ts('#?components.result.label|Result')}» — switch
|
|
|
|
|
the language in the topbar to see it follow). All visible copy (title, description,
|
|
|
|
|
actions, extra) is app content by design. No format / announce / clipboard consumption.
|
|
|
|
|
</p>
|
|
|
|
|
</section>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
{#if tab === 'api'}
|
|
|
|
|
<section data-uix-section>
|
|
|
|
|
<h2 data-uix-section-title>API reference</h2>
|
|
|
|
|
|
|
|
|
|
<div data-uix-subsection-head>Result props</div>
|
|
|
|
|
<div data-uix-table-wrap>
|
|
|
|
|
<table data-uix-table>
|
|
|
|
|
<thead><tr><th>Prop</th><th>Type</th><th>Notes</th></tr></thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">status</td>
|
|
|
|
|
<td class="type">{statuses.join(' | ')}</td>
|
|
|
|
|
<td>
|
|
|
|
|
The terminal state. Default <code>info</code>. AntD's 7-value enum with the
|
|
|
|
|
HTTP codes renamed semantically (no stringly <code>'404'</code>).
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div data-uix-subsection-head>Parts</div>
|
|
|
|
|
<div data-uix-table-wrap>
|
|
|
|
|
<table data-uix-table>
|
|
|
|
|
<thead><tr><th>Part</th><th>Prop</th><th>Notes</th></tr></thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">Result.Media</td>
|
|
|
|
|
<td class="type">—</td>
|
|
|
|
|
<td>
|
|
|
|
|
Empty = the status default (doctrinal <code>IntentIcon</code> glyph, catalog
|
|
|
|
|
<code>Info</code>, or the big neutral HTTP code). Children replace it entirely
|
|
|
|
|
(illustration, custom art).
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">Result.Title</td>
|
|
|
|
|
<td class="type">level: 1–6</td>
|
|
|
|
|
<td>
|
|
|
|
|
Real <code><h{'{level}'}></code>, default <code>2</code> (page-level;
|
|
|
|
|
EmptyState defaults 3 — deliberate difference).
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">Result.Description</td>
|
|
|
|
|
<td class="type">—</td>
|
|
|
|
|
<td>Muted <code><p></code>, 45ch measure token.</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">Result.Actions</td>
|
|
|
|
|
<td class="type">label?: string</td>
|
|
|
|
|
<td>
|
|
|
|
|
Consumer <code><Button></code>s; <code>label</code> →
|
|
|
|
|
<code>role="group"</code> + <code>aria-label</code> (same contract as
|
|
|
|
|
EmptyState).
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">Result.Extra</td>
|
|
|
|
|
<td class="type">—</td>
|
|
|
|
|
<td>
|
|
|
|
|
Detail block under the actions (AntD <code>children</code>): error lists, ticket
|
|
|
|
|
ids. Left-aligned — detail reads, it doesn't announce.
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div data-uix-subsection-head>Reference comparison</div>
|
|
|
|
|
<div data-uix-table-wrap>
|
|
|
|
|
<table data-uix-table>
|
|
|
|
|
<thead>
|
|
|
|
|
<tr><th>Library</th><th>Closest equivalent</th><th>Difference</th></tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">antd</td>
|
|
|
|
|
<td><code>Result</code></td>
|
|
|
|
|
<td>
|
|
|
|
|
The only first-class reference (status/title/subTitle/extra/icon). We rename
|
|
|
|
|
<code>'403'|'404'|'500'</code> semantically, keep its <code>warning</code>
|
|
|
|
|
slot, default <code>info</code> like it does, and mirror its neutral HTTP
|
|
|
|
|
treatment.
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">tailwind plus</td>
|
|
|
|
|
<td>404 Pages (marketing section)</td>
|
|
|
|
|
<td>
|
|
|
|
|
Frozen page dumps (code eyebrow + heading + CTA). Ours is a component with the
|
|
|
|
|
same anatomy, composable inside any layout.
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">chakra / polaris / radix / ark</td>
|
|
|
|
|
<td>—</td>
|
|
|
|
|
<td>
|
|
|
|
|
None ships a Result. Closest is their empty state — which is why ours shares
|
|
|
|
|
EmptyState's skeleton and differs only by contract.
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
{#if tab === 'morfo'}
|
|
|
|
|
<section data-uix-section>
|
|
|
|
|
<h2 data-uix-section-title>Morfo contract</h2>
|
|
|
|
|
|
|
|
|
|
<div data-uix-table-wrap>
|
|
|
|
|
<table data-uix-table>
|
|
|
|
|
<thead><tr><th>Field</th><th>Value</th></tr></thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<tr><td class="name">name</td><td>{resultMorfo.name}</td></tr>
|
|
|
|
|
<tr><td class="name">kebab</td><td><code>{resultMorfo.kebab}</code></td></tr>
|
|
|
|
|
<tr><td class="name">scope</td><td>{resultMorfo.scope.join(', ')}</td></tr>
|
|
|
|
|
<tr><td class="name">parts</td><td>{partsList.length}</td></tr>
|
|
|
|
|
<tr><td class="name">events</td><td>{events.length}</td></tr>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div data-uix-subsection-head>Parts</div>
|
|
|
|
|
<div data-uix-table-wrap>
|
|
|
|
|
<table data-uix-table>
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th>kebab</th>
|
|
|
|
|
<th>marker</th>
|
|
|
|
|
<th>element</th>
|
|
|
|
|
<th>archetype</th>
|
|
|
|
|
<th>optional</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
{#each partsList as part (part.kebab)}
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">{part.kebab}</td>
|
|
|
|
|
<td><code data-uix-part-marker>[{part.marker}]</code></td>
|
|
|
|
|
<td class="type"><{part.defaultElement}></td>
|
|
|
|
|
<td class="type">{part.archetype ?? '—'}</td>
|
|
|
|
|
<td class="default">{part.optional ? 'yes' : 'no'}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
{/each}
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<p data-uix-section-desc style="margin-top: var(--uix-space-4);">
|
|
|
|
|
<code>data-status</code> is an eidos-only wrapper attr (it never crosses layers — banner
|
|
|
|
|
precedent), so it stays out of the contract. <code>extra</code> declares no archetype: a
|
|
|
|
|
genuinely component-specific part (types.ts sanctions omitting the field).
|
|
|
|
|
</p>
|
|
|
|
|
</section>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
{#if tab === 'recipe'}
|
|
|
|
|
<section data-uix-section>
|
|
|
|
|
<h2 data-uix-section-title>Eidos recipe</h2>
|
|
|
|
|
<p data-uix-section-desc>
|
|
|
|
|
Recipe lives in <code>src/uix/eidos/components/result/result.css</code>. Public tokens:
|
|
|
|
|
<code>--result-gap · actions-gap · description-measure · extra-measure ·
|
|
|
|
|
{'{status}'}-color</code> (overridable via <code>recipes.result.*</code>). The status maps
|
|
|
|
|
to a role color for the GLYPH only; HTTP codes render neutral mono text.
|
|
|
|
|
</p>
|
|
|
|
|
<div data-uix-table-wrap>
|
|
|
|
|
<table data-uix-table>
|
|
|
|
|
<thead><tr><th>Selector</th><th>Owner</th><th>Purpose</th></tr></thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name"><code>[data-result]</code></td>
|
|
|
|
|
<td><span data-uix-tag data-kind="morfo">morfo</span></td>
|
|
|
|
|
<td>Provider marker — centered column, gap + page-level padding.</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name"><code>[data-result][data-status='X']</code></td>
|
|
|
|
|
<td><span data-uix-tag data-kind="eidos">eidos</span></td>
|
|
|
|
|
<td>Glyph color per evaluative status (fulfill / threat / risk / primary).</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name"><code>[data-result-code]</code></td>
|
|
|
|
|
<td><span data-uix-tag data-kind="eidos">eidos</span></td>
|
|
|
|
|
<td>The big neutral HTTP code (mono, semibold, muted).</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name"><code>[data-result-media/title/description/actions/extra]</code></td>
|
|
|
|
|
<td><span data-uix-tag data-kind="morfo">morfo</span></td>
|
|
|
|
|
<td>Part styling — display glyph scale, heading, measure, action row, detail.</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
{#if tab === 'a11y'}
|
|
|
|
|
<section data-uix-section>
|
|
|
|
|
<h2 data-uix-section-title>Accessibility</h2>
|
|
|
|
|
<div data-uix-table-wrap>
|
|
|
|
|
<table data-uix-table>
|
|
|
|
|
<thead><tr><th>Concern</th><th>Contract</th></tr></thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">Role</td>
|
|
|
|
|
<td>
|
|
|
|
|
None on the root — a static terminal surface, not a live region. The outcome's
|
|
|
|
|
perceptual signal belonged to the operation that resolved.
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">SPA navigation</td>
|
|
|
|
|
<td>
|
|
|
|
|
When a Result renders after client-side navigation, the APP moves focus to the
|
|
|
|
|
title (or announces politely) — no reference implements this either; the
|
|
|
|
|
pattern is documented here so consumers wire it deliberately.
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">Heading</td>
|
|
|
|
|
<td>
|
|
|
|
|
Title is a real <code><h{'{level}'}></code> (default h2 — the surface
|
|
|
|
|
usually IS the page).
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">Media</td>
|
|
|
|
|
<td>
|
|
|
|
|
Default glyphs are decorative (<code>aria-hidden</code>); the HTTP code is
|
|
|
|
|
<code>aria-hidden</code> too — the title says "Page not found", the 404 is
|
|
|
|
|
ornament.
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="name">Color</td>
|
|
|
|
|
<td>
|
|
|
|
|
Status never travels on color alone: the title text carries the outcome; the
|
|
|
|
|
glyph color is reinforcement (HTTP codes stay neutral by doctrine).
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
{/if}
|
|
|
|
|
</div>
|