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/image.ts

160 lines
4.2 KiB

import type { Morfo } from '../types';
import { v } from '../types';
/**
* Image — responsive image surface with status-driven fallback.
*
* Eidos-native primitive that consumes the existing `ImageProvider`
* (soma/layers) to track load lifecycle (idle / loading / loaded /
* error) and gate when the Fallback / Error slots are visible.
*
* Designed to be the foundation other components reach for instead of
* dropping raw `<img>` — Avatar.Image, Card images, Carousel slides,
* file thumbnails, etc. all benefit from the shared loading / error
* contract.
*
* Four parts:
* - Provider — outer `<span>` carrying status / fit / radius / placeholder
* - Img — the actual `<img>` element with src / srcset / sizes /
* loading / decoding / fetchpriority forwarded natively
* - Fallback — content rendered while the image is loading (or before
* a src is set). Optional delay before showing.
* - Error — content rendered when the image fails to load. Falls
* back automatically to Fallback when not supplied.
*
* Aspect ratio is intentionally NOT a prop here — consumers compose
* with the existing `<AspectRatio ratio>` primitive when they want to
* lock width / height. Same principle as Card / Banner: one axis, one
* primitive.
*
* 0-event surface: like Avatar, Image emits no semantic commit /
* emerge. The load lifecycle is a passive observation, not an
* evaluative act — consumers wanting a perceptual signal when an
* image lands wire it to the surrounding context (a gallery's
* `commit-select` on click, a hero's `emerge-mount` on the parent
* dialog, etc.).
*/
export const imageMorfo = {
name: 'Image',
kebab: 'image',
scope: ['eidos'],
texts: {
loading: '#?components.image.loading|Loading image',
error: '#?components.image.error|Image failed to load'
},
parts: [
{
name: 'Provider',
kebab: 'provider',
archetype: 'provider',
kind: 'public',
defaultElement: 'span',
optional: false,
states: ['idle', 'loading', 'loaded', 'error'],
data: [
{
attr: 'data-status',
values: ['idle', 'loading', 'loaded', 'error'],
value: v.stateRef('idle')
},
{
attr: 'data-fit',
values: ['cover', 'contain', 'fill', 'none', 'scale-down'],
value: v.propRef('fit'),
severity: 'optional'
},
{
attr: 'data-position',
values: ['center', 'top', 'bottom', 'start', 'end'],
value: v.propRef('position'),
severity: 'optional'
},
{
attr: 'data-radius',
values: ['none', 'sm', 'md', 'lg', 'full'],
value: v.propRef('radius'),
severity: 'optional'
},
{
attr: 'data-size',
values: ['xs', 'sm', 'md', 'lg', 'xl'],
value: v.propRef('size'),
severity: 'optional'
},
{
attr: 'data-placeholder',
values: ['skeleton', 'color', 'none'],
value: v.propRef('placeholder'),
severity: 'optional'
}
],
aria: []
},
{
name: 'Img',
kebab: 'img',
archetype: 'image',
kind: 'public',
defaultElement: 'img',
optional: false,
data: [
{
attr: 'data-status',
values: ['idle', 'loading', 'loaded', 'error'],
value: v.propRef('status')
}
],
aria: []
},
{
name: 'Fallback',
kebab: 'fallback',
archetype: 'fallback',
kind: 'public',
defaultElement: 'span',
optional: true,
data: [
{
attr: 'data-status',
values: ['idle', 'loading', 'loaded', 'error'],
value: v.propRef('status')
}
],
aria: [
{
attr: 'aria-label',
value: v.translationRef('#?components.image.loading|Loading image'),
severity: 'optional'
}
]
},
{
name: 'Error',
kebab: 'error',
archetype: 'fallback',
kind: 'public',
defaultElement: 'span',
optional: true,
data: [
{
attr: 'data-status',
values: ['idle', 'loading', 'loaded', 'error'],
value: v.propRef('status')
}
],
aria: [
{
attr: 'role',
value: v.literal('img'),
severity: 'recommended'
},
{
attr: 'aria-label',
value: v.translationRef('#?components.image.error|Image failed to load'),
severity: 'recommended'
}
]
}
]
} as const satisfies Morfo;

Powered by TurnKey Linux.