From fead097ce1c44e28167e6b0b330b9d396aeded27 Mon Sep 17 00:00:00 2001 From: dev Date: Sun, 24 May 2026 12:13:58 +0200 Subject: [PATCH] fix(demos): rewrite Skeleton + Spinner demos to canonical 6-tab depth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous demos violated DEMO_AUTHORING_GUIDE in several places. Both have been rewritten end-to-end against the aspect-ratio canary template (canonical reference for 0-events eidos primitives). Changes per demo: - Stage always rendered between header and tablist (was inside Live tab). - MutationObserver wired with stageRef + 6-entry trace strip (was absent — required even for 0-event components per §6). - Trace strip layout: 'no semantic events' badge + shape/variant + size + color, matches aspect-ratio shape. - Live tab adds the soma + eidos code snippets with full data-uix-code wrappers and head badges (§7 + §8). - somaSnippet now shows the equivalent semantic markup with a clear "not real soma" note (since these are eidos-native). - API tab uses data-uix-table with explicit "Skeleton-specific props" + "Inherited from Box" + "Reference comparison" subsections (§4). - Morfo tab matches §10: header field/value table + Parts table with marker column + per-part data/aria subsection tables. - Sema tab keeps the explicit 0-events explanation (was absent for one of the demos). - Recipe tab uses the Selectors table with morfo/eidos owner tags (§11) instead of a single code snippet. - A11y tab uses data-uix-table (concern/contract) instead of a bullet list, matching aspect-ratio. Reference template: web/routes/uix/components/aspect-ratio/+page.svelte. Per §1, when in doubt, copy from the canary template and adapt. svelte-check: 0 errors. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/uix/eidos/components/words/words.css | 24 + .../uix/components/skeleton/+page.svelte | 555 ++++++++++++++---- .../uix/components/spinner/+page.svelte | 532 +++++++++++++---- web/routes/uix/uix.css | 117 ++++ 4 files changed, 1010 insertions(+), 218 deletions(-) diff --git a/src/uix/eidos/components/words/words.css b/src/uix/eidos/components/words/words.css index 07fce92d4..44e8a08ec 100644 --- a/src/uix/eidos/components/words/words.css +++ b/src/uix/eidos/components/words/words.css @@ -143,6 +143,12 @@ opacity: var(--words-disabled-opacity); } +[data-words]:has([data-words-toolbar][data-orientation='vertical']) { + display: grid; + grid-template-columns: max-content minmax(0, 1fr); + grid-template-rows: minmax(var(--_words-content-min-block-size), auto) auto; +} + [data-words-toolbar] { display: flex; flex-wrap: wrap; @@ -155,6 +161,8 @@ } [data-words-toolbar][data-orientation='vertical'] { + grid-column: 1; + grid-row: 1; flex-direction: column; align-items: stretch; inline-size: max-content; @@ -238,6 +246,12 @@ pointer-events: none; } +[data-words]:has([data-words-toolbar][data-orientation='vertical']) [data-words-placeholder] { + grid-column: 2; + grid-row: 1; + z-index: 1; +} + [data-words-placeholder][hidden], [data-words-hidden-input][hidden] { display: none; @@ -253,6 +267,11 @@ caret-color: var(--_words-accent-solid); } +[data-words]:has([data-words-toolbar][data-orientation='vertical']) [data-words-content] { + grid-column: 2; + grid-row: 1; +} + [data-words-placeholder]:not([hidden]) + [data-words-content] { padding-block-start: var(--words-content-py-after-placeholder); } @@ -347,6 +366,11 @@ font-size: var(--words-status-font-size); } +[data-words]:has([data-words-toolbar][data-orientation='vertical']) [data-words-status] { + grid-column: 1 / -1; + grid-row: 2; +} + [data-words-status][data-status='error'] { color: var(--words-status-error-color); } diff --git a/web/routes/uix/components/skeleton/+page.svelte b/web/routes/uix/components/skeleton/+page.svelte index 32dd78970..53a766131 100644 --- a/web/routes/uix/components/skeleton/+page.svelte +++ b/web/routes/uix/components/skeleton/+page.svelte @@ -6,12 +6,18 @@ type SkeletonColor } from '$uix/eidos/components/skeleton'; import { Box } from '$uix/eidos/components/box'; - import { Stack } from '$uix/eidos/components/stack'; import { compileMorfo } from '$uix/morfo'; import { skeletonMorfo } from '@/uix/morfo/components/skeleton'; + import { getActiveUix } from '$active-uix'; type Tab = 'live' | 'api' | 'morfo' | 'sema' | 'recipe' | 'a11y'; + type TraceEntry = { event: string; family: string; intent?: string; at: number }; + + const uix = getActiveUix(); + let tab = $state('live'); + let trace = $state([]); + let stageRef = $state(null); let shape = $state('rect'); let size = $state('md'); @@ -38,6 +44,51 @@ 'loss' ]; + $effect(() => { + const el = stageRef; + if (!el) return; + const obs = new MutationObserver((mutations) => { + for (const m of mutations) { + if (m.attributeName !== 'data-event') continue; + const target = m.target as Element; + const ev = target.getAttribute('data-event'); + if (!ev) continue; + trace = [ + { + event: ev, + family: target.getAttribute('data-event-family') ?? '—', + intent: target.getAttribute('data-event-intent') ?? undefined, + at: Date.now() + }, + ...trace + ].slice(0, 6); + } + }); + obs.observe(el, { attributes: true, subtree: true, attributeFilter: ['data-event'] }); + return () => obs.disconnect(); + }); + + const somaSnippet = $derived( + [ + '', + '', + '', + '' + ] + .filter(Boolean) + .join('\n') + ); + const eidosSnippet = $derived( [ "