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/eidos/components/dialog/dialog.css

343 lines
13 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* Eidos — Dialog component recipe.
*
* Eidos applies universally to the data-attrs the dialog morfo emits. Tokens
* follow the bare-prefixed convention (`--dialog-*` public, `--_dialog-*`
* internal — see `eidos/components/README.md`). No `air-` / `eidos-`
* keyframe prefixes either.
*
* The morfo declares `data-last-action` as a prewrite on every close-* event,
* written BEFORE the `data-state` flips to 'closed'. The exit border-top is
* tinted by causa during the closing animation. See the data-last-action
* block at the bottom of this file.
*/
/* ── Trigger ───────────────────────────────────────────────────────────────
* The trigger composes the framework `<Button>` (eidos `dialog-trigger.svelte`
* renders `<Button {...props}>` via soma's `child`), so ALL its chrome —
* layout, bg, hover, focus-ring, disabled — comes from the Button recipe. No
* bespoke `[data-dialog-trigger]` envelope here: it would paint the SAME
* element as `[data-button]` and fight it (the Close recipe is the model).
*/
/* ── Overlay ───────────────────────────────────────────────────────────── */
[data-dialog-overlay] {
position: fixed;
inset: 0;
background: color-mix(
in srgb,
var(--dialog-overlay-bg) var(--dialog-overlay-opacity),
transparent
);
backdrop-filter: blur(var(--dialog-overlay-blur));
z-index: var(--dialog-overlay-z);
}
/* Overlay + content enter/exit motion comes from the motion system (presets
* `fade` / `scale-fade` via `data-animation-style`). `data-state` here is only
* steady styling. Asymmetric timing — `fast` in / `slow` out — drawn from the
* canonical duration scale. See `eidos-motion.md`. */
[data-dialog-overlay],
[data-dialog-content] {
--motion-duration-enter: var(--duration-fast);
--motion-duration-exit: var(--duration-slow);
}
/* ── Content ───────────────────────────────────────────────────────────── */
[data-dialog-content] {
--_dialog-size-width: var(--dialog-content-width-md);
--_dialog-padding: var(--dialog-content-padding-md);
--_dialog-width: var(--_dialog-content-width-override, var(--_dialog-size-width));
position: fixed;
left: 50%;
top: 50%;
translate: -50% -50%;
z-index: calc(var(--dialog-overlay-z) + 1);
display: flex;
flex-direction: column;
gap: var(--dialog-stack-gap);
width: min(calc(100vw - var(--dialog-content-width-inset)), var(--_dialog-width));
min-width: var(--_dialog-content-min-width-override, auto);
max-width: var(--_dialog-content-max-width-override, none);
height: var(--_dialog-content-height-override, auto);
min-height: var(--_dialog-content-min-height-override, auto);
max-height: var(--_dialog-content-max-height-override, var(--dialog-content-max-height));
padding: var(--_dialog-padding);
overflow: auto;
/* Elevation bundle (surface · border · shadow) comes from the `modal` plane
via `data-depth` (A1, Decisión 8). The panel keeps only its own radius /
color — radius is a separate axis (Radix factor, A2). The intent variants
below override `border-color` on top of the plane's border. */
border-radius: var(--dialog-content-radius);
color: var(--dialog-content-color);
outline: none;
}
/* Content enter/exit motion comes from the motion system (preset `scale-fade`
* via `data-animation-style`). Soma's Presence waits for `getAnimations()`
* before unmounting, so the preset animation gates the cycle. `data-state` is
* steady styling only. */
/* ── Position (3×3 grid) ────────────────────────────────────────────────
* The default `[data-dialog-content]` rule above already centers the panel
* (`left/top: 50%; translate: -50% -50%;`) — that is the implicit
* `middle-center` form. The selectors below override the anchoring axes
* for the other 8 cells. `data-size='full'` and `data-sheet` come AFTER
* these in the cascade and win when applicable. */
[data-dialog-content][data-position='top-left'] {
top: var(--dialog-content-position-inset);
left: var(--dialog-content-position-inset);
right: auto;
bottom: auto;
translate: none;
}
[data-dialog-content][data-position='top-center'] {
top: var(--dialog-content-position-inset);
left: 50%;
right: auto;
bottom: auto;
translate: -50% 0;
}
[data-dialog-content][data-position='top-right'] {
top: var(--dialog-content-position-inset);
right: var(--dialog-content-position-inset);
left: auto;
bottom: auto;
translate: none;
}
[data-dialog-content][data-position='middle-left'] {
top: 50%;
left: var(--dialog-content-position-inset);
right: auto;
bottom: auto;
translate: 0 -50%;
}
/* `middle-center` is the default — no override needed. */
[data-dialog-content][data-position='middle-right'] {
top: 50%;
right: var(--dialog-content-position-inset);
left: auto;
bottom: auto;
translate: 0 -50%;
}
[data-dialog-content][data-position='bottom-left'] {
bottom: var(--dialog-content-position-inset);
left: var(--dialog-content-position-inset);
top: auto;
right: auto;
translate: none;
}
[data-dialog-content][data-position='bottom-center'] {
bottom: var(--dialog-content-position-inset);
left: 50%;
top: auto;
right: auto;
translate: -50% 0;
}
[data-dialog-content][data-position='bottom-right'] {
bottom: var(--dialog-content-position-inset);
right: var(--dialog-content-position-inset);
top: auto;
left: auto;
translate: none;
}
/* ── Sizing ────────────────────────────────────────────────────────────── */
[data-dialog-content][data-size='sm'] {
--_dialog-size-width: var(--dialog-content-width-sm);
--_dialog-padding: var(--dialog-content-padding-sm);
}
[data-dialog-content][data-size='md'] {
--_dialog-size-width: var(--dialog-content-width-md);
--_dialog-padding: var(--dialog-content-padding-md);
}
[data-dialog-content][data-size='lg'] {
--_dialog-size-width: var(--dialog-content-width-lg);
--_dialog-padding: var(--dialog-content-padding-lg);
}
[data-dialog-content][data-size='xl'] {
--_dialog-size-width: var(--dialog-content-width-xl);
--_dialog-padding: var(--dialog-content-padding-full);
border-radius: var(--dialog-content-full-radius);
}
[data-dialog-content][data-size='full'] {
inset: var(--dialog-content-full-inset);
translate: none;
width: var(--_dialog-content-width-override, auto);
border-radius: var(--dialog-content-full-radius);
--_dialog-padding: var(--dialog-content-padding-full);
}
/* Auto-sheet: the eidos wrapper sets `data-sheet=""` on Content when the
* viewport is narrower than the `sm` breakpoint AND the requested size is
* not `full`. Bottom-anchored, full-width, top-rounded. */
[data-dialog-content][data-sheet] {
left: 0;
top: auto;
bottom: 0;
translate: none;
width: 100%;
max-height: var(--dialog-content-max-height-sheet);
border-radius: var(--dialog-content-radius) var(--dialog-content-radius) 0 0;
--_dialog-padding: var(--dialog-content-padding-sm);
}
/* ── Color (intent → palette) ──────────────────────────────────────────────
* Modal subset of the 8 system tokens (canon §3.1). Soma resolves the
* consumer's `intent` prop to `data-color`. The subset is intentionally
* tight: a dialog is not a hierarchy and irreversible loss should not be
* a dialog at all. Each intent tints the panel border and (for evaluative
* intents) the title color. The body background stays neutral so long-form
* content doesn't compete with the intent signal. */
/* neutral = the plane's own border (`--depth-modal-border`); no override needed. */
[data-dialog-content][data-color='risk'] {
border-color: var(--color-risk-border);
}
[data-dialog-content][data-color='risk'] [data-dialog-title] {
color: var(--color-risk-text);
}
[data-dialog-content][data-color='threat'] {
border-color: var(--color-threat-border);
}
[data-dialog-content][data-color='threat'] [data-dialog-title] {
color: var(--color-threat-text);
}
/* ── Layout shells (eidos-only, no morfo backing) ──────────────────────── */
[data-dialog-header] {
display: flex;
flex-direction: column;
align-items: start;
gap: var(--dialog-header-gap);
/* Reserve space on the trailing edge so a top-right close doesn't
* collide with title text. The padding flips when a close is anchored
* top-left via the rules below. */
padding-inline-end: calc(var(--dialog-close-size) + var(--space-2));
}
[data-dialog-content]:has([data-dialog-close][data-position^='top-left']) [data-dialog-header] {
padding-inline-end: 0;
padding-inline-start: calc(var(--dialog-close-size) + var(--space-2));
}
[data-dialog-content]:has([data-dialog-close][data-position^='bottom-']) [data-dialog-header],
[data-dialog-content]:has([data-dialog-close][data-position='top-center']) [data-dialog-header] {
padding-inline: 0;
}
[data-dialog-footer] {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: end;
gap: var(--dialog-footer-gap);
margin-top: var(--dialog-footer-margin-top);
}
/* ── Title / Description ───────────────────────────────────────────────── */
[data-dialog-title] {
margin: 0;
/* Typography role (Arq. 5 / THEMING §3): the title reads its own
`--dialog-title-*` knobs, which the recipe defaults to the canonical `h3`
heading role (primary/sans · lg · semibold). The role gives coherence by
default; the `--dialog-title-*` tokens stay the override surface — a theme,
the recipe config, or one `<Dialog.Content style>` can restyle dialog titles
WITHOUT retuning every `h3`. The intent tints below still override color. */
font-family: var(--dialog-title-font-family);
font-size: var(--dialog-title-font-size);
font-weight: var(--dialog-title-font-weight);
line-height: var(--dialog-title-line-height);
letter-spacing: var(--dialog-title-letter-spacing);
color: var(--dialog-title-color);
text-wrap: balance;
}
[data-dialog-description] {
margin: 0;
font-family: var(--dialog-description-font-family);
font-size: var(--dialog-description-font-size);
line-height: var(--dialog-description-line-height);
color: var(--dialog-description-color);
}
/* ── Close ─────────────────────────────────────────────────────────────────
* The close composes the canonical `<Button>` / `<IconButton>` (eidos
* `dialog-close.svelte`), so its chrome — layout, bg, hover, focus-ring,
* disabled, icon-only sizing — comes from the Button recipe. This recipe owns
* ONLY the dialog-specific concern: floating the close over Content when the
* consumer assigns `data-position`. Without `data-position` the button flows
* inline (e.g. a <Dialog.Close> in a Footer). */
[data-dialog-close][data-position] {
position: absolute;
z-index: 1;
}
/* ── Close position (subset of canonical Position — corners + top/bottom centers) ── */
/* Default: top-right (matches the eidos wrapper's `closePosition` default). */
[data-dialog-close][data-position='top-right'] {
top: var(--dialog-close-inset);
right: var(--dialog-close-inset);
}
[data-dialog-close][data-position='top-left'] {
top: var(--dialog-close-inset);
left: var(--dialog-close-inset);
}
[data-dialog-close][data-position='top-center'] {
top: var(--dialog-close-inset);
left: 50%;
translate: -50% 0;
}
[data-dialog-close][data-position='bottom-right'] {
bottom: var(--dialog-close-inset);
right: var(--dialog-close-inset);
}
[data-dialog-close][data-position='bottom-left'] {
bottom: var(--dialog-close-inset);
left: var(--dialog-close-inset);
}
[data-dialog-close][data-position='bottom-center'] {
bottom: var(--dialog-close-inset);
left: 50%;
translate: -50% 0;
}
/* ── data-last-action exit tinting ─────────────────────────────────────────
* The dialog morfo declares `prewrite` on every close-* event that writes
* `data-last-action` before `data-state` flips to 'closed'. Both attrs
* coexist during the exit animation; CSS tints the border-top by causa.
*/
[data-dialog-content][data-state='closed'][data-last-action='saved'] {
border-top-color: var(--color-fulfill-element);
}
[data-dialog-content][data-state='closed'][data-last-action='failed'] {
border-top-color: var(--color-threat-element);
}
[data-dialog-content][data-state='closed'][data-last-action='cancelled'],
[data-dialog-content][data-state='closed'][data-last-action='dismissed'],
[data-dialog-content][data-state='closed'][data-last-action='dismissed-outside'] {
border-top-color: var(--color-neutral-element);
}

Powered by TurnKey Linux.