altitude-design 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/altitude.css +57 -15
- package/dist/altitude.iife.js +4 -4
- package/dist/altitude.no-fonts.css +57 -15
- package/dist/index.cjs +714 -426
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +714 -426
- package/dist/index.js.map +4 -4
- package/dist/types/collections.d.ts +6 -2
- package/dist/types/controls.d.ts +37 -8
- package/dist/types/index.d.ts +3 -1
- package/dist/types/overlays.d.ts +9 -2
- package/dist/types/suspense.d.ts +74 -0
- package/package.json +3 -2
|
@@ -298,16 +298,19 @@ body { margin: 0; background: var(--surface-ground); color: var(--ink); font-fam
|
|
|
298
298
|
transition: box-shadow var(--dur-travel-1) var(--ease-rise), background-color var(--dur-travel-1) var(--ease-rise),
|
|
299
299
|
color var(--dur-travel-1) var(--ease-rise), transform var(--dur-travel-2) var(--ease-settle);
|
|
300
300
|
}
|
|
301
|
-
/* Focus ring: wraps the whole slab, face and wall, so it follows the button's real shape at every height.
|
|
301
|
+
/* Focus ring: wraps the whole slab, face and wall, so it follows the button's real shape at every height. It's an
|
|
302
|
+
outline 2px off a box that covers the face and the wall, because an outline never adds to the page's scrollable
|
|
303
|
+
area: a button at the edge of a narrow screen must not give the page a sideways scroll. At rest the box is the face
|
|
304
|
+
alone, so only a keyboard-focused button's wall (the box's bottom edge, at most 5px) reaches past its own box. */
|
|
302
305
|
.alt-btn:focus-visible, .alt-crumbs button:focus-visible { outline: none; }
|
|
303
306
|
.alt-btn::after, .alt-crumbs button::after {
|
|
304
307
|
content: ""; position: absolute; pointer-events: none; opacity: 0;
|
|
305
|
-
inset:
|
|
306
|
-
transition: opacity var(--dur-travel-1) var(--ease-rise),
|
|
308
|
+
inset: 0; outline: 2px solid var(--accent-ink); outline-offset: 2px; border-radius: var(--radius-md);
|
|
309
|
+
transition: opacity var(--dur-travel-1) var(--ease-rise), bottom var(--dur-press) ease-out;
|
|
307
310
|
}
|
|
308
|
-
.alt-btn[data-size="sm"]::after, .alt-crumbs button::after { border-radius:
|
|
309
|
-
.alt-btn:focus-visible::after, .alt-crumbs button:focus-visible::after { opacity: 1; }
|
|
310
|
-
.alt-btn:active::after, .alt-btn[data-loading]::after {
|
|
311
|
+
.alt-btn[data-size="sm"]::after, .alt-crumbs button::after { border-radius: var(--radius-sm); }
|
|
312
|
+
.alt-btn:focus-visible::after, .alt-crumbs button:focus-visible::after { opacity: 1; bottom: calc(-1 * var(--wall, 0px) - 1px); }
|
|
313
|
+
.alt-btn:active::after, .alt-btn[data-loading]::after { bottom: 0; }
|
|
311
314
|
.alt-btn-label { display: inline-flex; align-items: center; gap: var(--space-2); transition: opacity var(--dur-travel-1) var(--ease-rise); }
|
|
312
315
|
.alt-btn-label > svg { flex: none; margin-inline: -2px; }
|
|
313
316
|
.alt-btn[data-variant="primary"] {
|
|
@@ -703,7 +706,7 @@ body { margin: 0; background: var(--surface-ground); color: var(--ink); font-fam
|
|
|
703
706
|
.alt-avatar[data-presence] .alt-avatar-face { outline: 2px solid var(--alt-presence); outline-offset: 1px; }
|
|
704
707
|
.alt-avatar-lamp {
|
|
705
708
|
--b-lamp: var(--positive);
|
|
706
|
-
position: absolute; z-index: 2; right:
|
|
709
|
+
position: absolute; z-index: 2; right: 0; bottom: 0; width: max(8px, calc(var(--size) * 0.24)); height: max(8px, calc(var(--size) * 0.24)); border-radius: var(--radius-full);
|
|
707
710
|
background: var(--b-lamp); box-shadow: 0 0 0 2px var(--surface-ground); transform: translateY(calc(-1 * var(--lift)));
|
|
708
711
|
}
|
|
709
712
|
.alt-avatar[data-status="idle"] .alt-avatar-lamp { --b-lamp: var(--caution); }
|
|
@@ -711,15 +714,18 @@ body { margin: 0; background: var(--surface-ground); color: var(--ink); font-fam
|
|
|
711
714
|
.alt-avatar[data-interactive] { cursor: pointer; outline: none; }
|
|
712
715
|
.alt-avatar[data-interactive]:focus-visible .alt-avatar-face { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
|
|
713
716
|
.alt-avatar-group { isolation: isolate; display: inline-flex; align-items: flex-end; padding: calc(var(--size, 36px) * 0.32) 0 calc(var(--size, 36px) * 0.1); }
|
|
714
|
-
.alt-avatar-group
|
|
715
|
-
.
|
|
717
|
+
.alt-avatar-group .alt-avatar { isolation: auto; }
|
|
718
|
+
/* Faces overlap by a fifth. An avatar that waited for its data sits inside its loading wrapper (display: contents at
|
|
719
|
+
rest), so the overlap is counted from the group's own children either way, imprints included. */
|
|
720
|
+
.alt-avatar-group > .alt-avatar:not(:first-child),
|
|
721
|
+
.alt-avatar-group > :is(.alt-await, .alt-await-wait):not(:first-child) :is(.alt-avatar, .alt-avatar-imprint) { margin-left: calc(var(--size, 36px) * -0.22); }
|
|
716
722
|
/* Overlapping faces are cut out of each other with a ring of ground; higher faces sit in front. */
|
|
717
|
-
.alt-avatar-group
|
|
718
|
-
.alt-avatar-group
|
|
719
|
-
.alt-avatar-group
|
|
720
|
-
.alt-avatar-group
|
|
721
|
-
.alt-avatar-group
|
|
722
|
-
.alt-avatar-group
|
|
723
|
+
.alt-avatar-group .alt-avatar .alt-avatar-face { box-shadow: 0 0 0 2px var(--surface-ground), inset 0 0 0 1px var(--alt-ring); }
|
|
724
|
+
.alt-avatar-group .alt-avatar[data-status="offline"] .alt-avatar-face { box-shadow: 0 0 0 2px var(--surface-ground), inset 0 0 0 1px var(--alt-ring), inset 0 1px 2px var(--alt-cast); }
|
|
725
|
+
.alt-avatar-group .alt-avatar[data-status="active"] .alt-avatar-face { z-index: 3; }
|
|
726
|
+
.alt-avatar-group .alt-avatar[data-status="idle"] .alt-avatar-face { z-index: 2; }
|
|
727
|
+
.alt-avatar-group .alt-avatar:not([data-tint="more"]):hover { --hr: 0.32; }
|
|
728
|
+
.alt-avatar-group .alt-avatar:not([data-tint="more"]):hover .alt-avatar-face { z-index: 5; }
|
|
723
729
|
.alt-avatar-group .alt-avatar-lamp { display: none; }
|
|
724
730
|
|
|
725
731
|
/* ── Skeleton: an imprint of the content to come, pressed into the page. Light passes over it while it waits; when the
|
|
@@ -743,6 +749,38 @@ body { margin: 0; background: var(--surface-ground); color: var(--ink); font-fam
|
|
|
743
749
|
}
|
|
744
750
|
@keyframes alt-rise-out { from { transform: translateY(calc(100% * var(--alt-travel))); opacity: 0.25; } }
|
|
745
751
|
|
|
752
|
+
/* ── Suspense: imprints that come with the component. A component given a promise (Avatar's name or src, a Badge's or
|
|
753
|
+
a card title's text, a DataTable's rows) holds its own Suspense boundary, and its fallback is its own imprint, drawn
|
|
754
|
+
from the same props and tokens, so it's the size and shape of what's coming. Card and CardContent hold one for
|
|
755
|
+
anything of yours that suspends inside them. An imprint waits dur-grace before it shows, so quick loads show nothing;
|
|
756
|
+
when content lands it rises 8px out of its imprint as the imprint fills in behind it, within the attention budget.
|
|
757
|
+
Containers just let their content rise. In a RevealGroup, content that lands early stays an imprint until the rest
|
|
758
|
+
arrive. At rest the wrapper is display: contents: it adds nothing to layout or to your selectors' parent chain. ── */
|
|
759
|
+
.alt-await-wait { display: block; animation: alt-onset var(--dur-travel-1) ease-out var(--dur-grace) backwards; }
|
|
760
|
+
.alt-await-wait[data-inline] { display: inline-block; vertical-align: middle; line-height: 0; }
|
|
761
|
+
.alt-await, .alt-await > .alt-await-face { display: contents; }
|
|
762
|
+
.alt-await[data-phase] { display: block; position: relative; isolation: isolate; }
|
|
763
|
+
.alt-await[data-phase] > .alt-await-face { display: block; }
|
|
764
|
+
.alt-await[data-phase][data-inline], .alt-await[data-phase][data-inline] > .alt-await-face { display: inline-block; vertical-align: middle; line-height: 0; }
|
|
765
|
+
.alt-await-imprint { position: absolute; inset: 0; z-index: -1; }
|
|
766
|
+
.alt-await[data-phase="held"] > .alt-await-face { position: absolute; inset: 0 0 auto; visibility: hidden; }
|
|
767
|
+
.alt-await-held { display: block; }
|
|
768
|
+
.alt-await-held[data-early] { animation: alt-onset var(--dur-travel-1) ease-out var(--alt-grace-left, 0ms) backwards; }
|
|
769
|
+
.alt-await[data-inline] > .alt-await-held { display: inline-block; vertical-align: middle; line-height: 0; }
|
|
770
|
+
.alt-await[data-phase="reveal"] > .alt-await-face { --alt-from-y: 8px; animation: alt-emerge var(--dur-travel-3) var(--ease-rise) var(--alt-rise-delay, 0ms) backwards; }
|
|
771
|
+
.alt-await[data-phase="reveal"] > .alt-await-imprint { animation: alt-await-fill var(--dur-travel-3) linear var(--alt-rise-delay, 0ms) forwards; }
|
|
772
|
+
@keyframes alt-await-fill { to { opacity: 0; } }
|
|
773
|
+
/* Text imprints are as tall as the text they stand for: one line-height of the surrounding type per line. */
|
|
774
|
+
.alt-await-lines { display: flex; flex-direction: column; justify-content: space-around; height: calc(var(--lines, 1) * 1lh); max-width: 100%; }
|
|
775
|
+
.alt-await-lines > .alt-skeleton { flex: none; height: 0.6em; }
|
|
776
|
+
.alt-await-card { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-5); }
|
|
777
|
+
.alt-await-card-body { font: 400 15px/23px var(--font-sans); }
|
|
778
|
+
.alt-avatar-imprint { display: inline-block; vertical-align: middle; }
|
|
779
|
+
.alt-badge-imprint { display: inline-block; vertical-align: middle; width: 64px; height: 22px; }
|
|
780
|
+
.alt-badge-imprint[data-variant="count"] { width: 22px; border-radius: var(--radius-full); }
|
|
781
|
+
.alt-check-imprint { display: block; width: 22px; height: 22px; border-radius: var(--radius-xs); }
|
|
782
|
+
.alt-cell-imprint { display: block; height: 0.6em; margin: calc((1lh - 0.6em) / 2) 0; }
|
|
783
|
+
|
|
746
784
|
/* ── Alert: a sheet laid on the page. Status that informs is a thin tinted sheet resting on the ground — you can see
|
|
747
785
|
its paper edge and the contact shadow under it — and it never floats. Status that asks you to act is a raised
|
|
748
786
|
card. Dismissing lifts the sheet off the page and the gap closes behind it. Several alerts make an AlertStack:
|
|
@@ -940,6 +978,9 @@ body { margin: 0; background: var(--surface-ground); color: var(--ink); font-fam
|
|
|
940
978
|
}
|
|
941
979
|
.alt-dialog-head { display: flex; flex-direction: column; gap: 6px; padding-right: var(--space-8); }
|
|
942
980
|
.alt-dialog-title { margin: 0; font: 600 19px/26px var(--font-sans); letter-spacing: -0.01em; }
|
|
981
|
+
/* A title that takes focus (initialFocus="title") isn't a control: no ring after a click, the usual ring from the keyboard. */
|
|
982
|
+
.alt-dialog-title:focus { outline: none; }
|
|
983
|
+
.alt-dialog-title:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; border-radius: var(--radius-xs); }
|
|
943
984
|
.alt-dialog-desc { margin: 0; font: 400 14px/21px var(--font-sans); color: var(--ink-muted); }
|
|
944
985
|
.alt-dialog-body { margin-top: var(--space-5); font: 400 15px/23px var(--font-sans); }
|
|
945
986
|
.alt-dialog-footer { display: flex; justify-content: flex-end; gap: var(--space-2); margin-top: var(--space-6); }
|
|
@@ -1629,6 +1670,7 @@ body { margin: 0; background: var(--surface-ground); color: var(--ink); font-fam
|
|
|
1629
1670
|
/* Forced colours (Windows High Contrast) drop every box-shadow, which erases elevation entirely
|
|
1630
1671
|
(measured: the ladder renders as blank). Height falls back to border weight and style. */
|
|
1631
1672
|
@media (forced-colors: active) {
|
|
1673
|
+
.alt-skeleton { outline: 1px dashed CanvasText; outline-offset: -1px; }
|
|
1632
1674
|
.alt-surface[data-level="1"], .alt-surface[data-level="2"], .alt-card, .alt-btn:not([data-variant="ghost"]), .alt-tabs-indicator,
|
|
1633
1675
|
.alt-switch-thumb, .alt-slider-thumb, .alt-kbd, .alt-avatar-face, .alt-sort-item, .alt-pile-top, .alt-pile-sheet, .alt-scroll { border: 1px solid CanvasText; }
|
|
1634
1676
|
.alt-surface[data-level="3"], .alt-surface[data-level="4"], .alt-pop, .alt-tip, .alt-toast, .alt-sort-item[data-held], [data-held] { border: 2px solid CanvasText; }
|