@vectoriox/iox-ui 5.84.0 → 5.85.0
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/actions-core/index.d.ts +18 -2
- package/composite-core/index.d.ts +93 -15
- package/design-core/index.d.ts +566 -4
- package/fesm2022/vectoriox-iox-ui-actions-core.mjs +18 -1
- package/fesm2022/vectoriox-iox-ui-actions-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-composite-core.mjs +307 -39
- package/fesm2022/vectoriox-iox-ui-composite-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-design-core.mjs +680 -15
- package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs +35 -4
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-scene-core.mjs +101 -5
- package/fesm2022/vectoriox-iox-ui-scene-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui.mjs +285 -12
- package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
- package/generation-core/index.d.ts +13 -0
- package/index.d.ts +143 -42
- package/package.json +1 -1
- package/scene-core/index.d.ts +32 -4
- package/src/actions-core/dialog-motion.ts +25 -0
- package/src/composite-core/header.ts +25 -0
- package/src/composite-core/public-api.ts +1 -0
- package/src/composite-core/slider-runtime.ts +82 -0
- package/src/composite-core/slider.ts +194 -27
- package/src/composite-core/structure.ts +14 -9
- package/src/design-core/flavor-spec.generated.ts +596 -9
- package/src/design-core/header-behaviour.ts +76 -0
- package/src/design-core/public-api.ts +1 -0
- package/src/design-core/theme-color.ts +21 -5
- package/src/generation-core/compose-site.ts +8 -0
- package/src/generation-core/node-baselines.generated.ts +17 -3
- package/src/generation-core/patterns.ts +2 -0
- package/src/generation-core/site-spec.generated.ts +8 -0
- package/src/scene-core/scene.ts +18 -0
- package/src/scene-core/scroll-driver.ts +83 -6
- package/styles/iox-design.css +232 -1
- package/styles/iox-forms.css +5 -2
package/styles/iox-design.css
CHANGED
|
@@ -142,13 +142,40 @@ iox-gallery.iox-es-media[data-iox-empty] > .iox-gallery {
|
|
|
142
142
|
--iox-image-hover-scale: 1;
|
|
143
143
|
}
|
|
144
144
|
.iox-es-card .iox-es-media {
|
|
145
|
-
transition: transform var(--iox-dur-
|
|
145
|
+
transition: transform var(--iox-dur-ui) var(--iox-ease-standard), scale var(--iox-dur-ui) var(--iox-ease-standard);
|
|
146
146
|
}
|
|
147
147
|
@media (hover: hover) and (pointer: fine) {
|
|
148
148
|
:is(a.iox-es-card, .iox-es-card:has(> a.linked-container-root), .iox-es-card:has(.iox-card-link)):hover .iox-es-media {
|
|
149
149
|
scale: var(--card-media-zoom);
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
|
+
/* M4 (the D3 follow-ups — Emil 144, 28, 74): a LINKED card's lift, its raised shadow and its picture's zoom are ONE
|
|
153
|
+
timing under 300ms (dur-ui; the card style's dur-base and the media's dur-slow ran past it in most looks). Its shadow
|
|
154
|
+
rises by fading a pseudo-element that wears card-shadow-raise — the card's own box-shadow no longer changes on hover
|
|
155
|
+
(every card's hover shadow is its rest shadow now; a non-linked card never rose). `translate: 0px` is identity: it
|
|
156
|
+
makes the card the pseudo's containing block and stacking context whatever position the card holds (the canvas
|
|
157
|
+
forces its own), so the pseudo sits under the card's content and its shadow outside the card's edge. */
|
|
158
|
+
:is(a.iox-es-card, .iox-es-card:has(> a.linked-container-root), .iox-es-card:has(.iox-card-link)) {
|
|
159
|
+
--iox-card-shadow-hover: var(--iox-card-shadow);
|
|
160
|
+
--iox-dur-base: var(--iox-dur-ui);
|
|
161
|
+
translate: 0px;
|
|
162
|
+
}
|
|
163
|
+
:is(a.iox-es-card, .iox-es-card:has(> a.linked-container-root), .iox-es-card:has(.iox-card-link))::before {
|
|
164
|
+
content: '';
|
|
165
|
+
position: absolute;
|
|
166
|
+
inset: calc(var(--iox-card-border-width, 0px) * -1);
|
|
167
|
+
border-radius: inherit;
|
|
168
|
+
box-shadow: var(--iox-card-shadow-raise);
|
|
169
|
+
opacity: 0;
|
|
170
|
+
pointer-events: none;
|
|
171
|
+
z-index: -1;
|
|
172
|
+
transition: opacity var(--iox-dur-ui) var(--iox-ease-standard);
|
|
173
|
+
}
|
|
174
|
+
@media (hover: hover) and (pointer: fine) {
|
|
175
|
+
:is(a.iox-es-card, .iox-es-card:has(> a.linked-container-root), .iox-es-card:has(.iox-card-link)):hover::before {
|
|
176
|
+
opacity: 1;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
152
179
|
|
|
153
180
|
/* ── CC1: mobile navigation (complex-components plan §7a, R1; boards 1–2) ─────────────────────── */
|
|
154
181
|
|
|
@@ -226,6 +253,16 @@ dialog[data-iox-dialog].iox-es:is([data-iox-closing], :not([open]))::backdrop {
|
|
|
226
253
|
@starting-style {
|
|
227
254
|
dialog[data-iox-dialog].iox-es[open]::backdrop { opacity: 0; }
|
|
228
255
|
}
|
|
256
|
+
/* M4 (M1.1's carry-over — Emil 101): a styled dialog separates from the page behind it by a hairline edge in the look's
|
|
257
|
+
`dialog-edge` (its line colour) — on a DARK page under a dark scrim its shadow is swallowed and the phone drawer
|
|
258
|
+
vanished into the page. An outline, so the dialog's own box-shadow (the look's, or the author's) is untouched; drawn
|
|
259
|
+
inside its edge, following its radius. The sheet itself takes focus when it opens (the engine), so it never rings:
|
|
260
|
+
the first Tab moves to its Close, with the ring. */
|
|
261
|
+
dialog[data-iox-dialog].iox-es {
|
|
262
|
+
outline: var(--iox-border-width, 1px) solid var(--iox-dialog-edge, transparent);
|
|
263
|
+
outline-offset: calc(var(--iox-border-width, 1px) * -1);
|
|
264
|
+
}
|
|
265
|
+
|
|
229
266
|
/* The drawer's pages arrive WITH it (decision D1 — Emil 64/65/110: one entrance per container, no menu-row stagger):
|
|
230
267
|
the sheet slides in carrying its links, and they leave with it. */
|
|
231
268
|
|
|
@@ -240,6 +277,7 @@ dialog[data-iox-dialog] {
|
|
|
240
277
|
.iox-role-nav-links,
|
|
241
278
|
.iox-role-nav-drawer-links {
|
|
242
279
|
--iox-link-decoration: none;
|
|
280
|
+
--iox-link-underline-rest: 0;
|
|
243
281
|
}
|
|
244
282
|
|
|
245
283
|
/* The BOTTOM BAR (board 2, "The CSS, exactly"): fixed to the bottom of the viewport (on the canvas, of the
|
|
@@ -474,3 +512,196 @@ span.iox-video__play { pointer-events: none; }
|
|
|
474
512
|
background: var(--iox-scrim);
|
|
475
513
|
}
|
|
476
514
|
}
|
|
515
|
+
|
|
516
|
+
/* ── Premium components M4 (T2): how a header behaves as the page scrolls ─────────────────────────────────────────
|
|
517
|
+
Keyed on the attributes every renderer writes from the header's two traits (design-core headerAttributes). A header
|
|
518
|
+
that STAYS or HIDES keeps to the top of the screen while the page scrolls under it; one that hides steps aside on the
|
|
519
|
+
way down, moved by the header runtime (`translate`, from the live value — HeaderRuntime). On the live site the
|
|
520
|
+
globals' wrapper is `display: contents`, so the header sticks to the whole page; on the builder canvas the header lives
|
|
521
|
+
in the frame-pinned overlay (global-elements.md) and the canvas keeps its own `position`. */
|
|
522
|
+
:root [data-iox-header] {
|
|
523
|
+
position: sticky;
|
|
524
|
+
inset-block-start: 0;
|
|
525
|
+
z-index: 30;
|
|
526
|
+
}
|
|
527
|
+
/* Faded under reduced motion (the runtime): not clickable while it is away. */
|
|
528
|
+
[data-iox-header][data-iox-header-hidden] {
|
|
529
|
+
pointer-events: none;
|
|
530
|
+
}
|
|
531
|
+
/* The EDGE (Emil 99): once the page has moved under it, a header shows a soft fade of its own ground — or a hairline —
|
|
532
|
+
instead of a divider drawn at all times. Its look's own bottom line gives way; the edge is a pseudo-element that only
|
|
533
|
+
fades in (no layout, no box-shadow). An eased gradient (Emil 174): no visible band where the fade ends. Only on a
|
|
534
|
+
header that stays at the top (one that scrolls away is gone by the time the page has moved); the header is its
|
|
535
|
+
containing block — sticky here, and `relative` as stored (the Header section writes it; the canvas forces a node's
|
|
536
|
+
own position, and a transform on the header would trap its drawer's stage). */
|
|
537
|
+
[data-iox-header][data-iox-header-edge] {
|
|
538
|
+
--iox-nav-border-width: 0px;
|
|
539
|
+
}
|
|
540
|
+
[data-iox-header][data-iox-header-edge]::after {
|
|
541
|
+
content: '';
|
|
542
|
+
position: absolute;
|
|
543
|
+
inset-inline: 0;
|
|
544
|
+
inset-block-start: 100%;
|
|
545
|
+
block-size: 16px;
|
|
546
|
+
pointer-events: none;
|
|
547
|
+
opacity: 0;
|
|
548
|
+
transition: opacity var(--iox-dur-ui) var(--iox-ease-standard);
|
|
549
|
+
}
|
|
550
|
+
[data-iox-header][data-iox-header-edge='fade']::after {
|
|
551
|
+
background: linear-gradient(to bottom,
|
|
552
|
+
color-mix(in srgb, var(--iox-nav-bg, transparent) 100%, transparent) 0%,
|
|
553
|
+
color-mix(in srgb, var(--iox-nav-bg, transparent) 74%, transparent) 19%,
|
|
554
|
+
color-mix(in srgb, var(--iox-nav-bg, transparent) 54%, transparent) 34%,
|
|
555
|
+
color-mix(in srgb, var(--iox-nav-bg, transparent) 34%, transparent) 50%,
|
|
556
|
+
color-mix(in srgb, var(--iox-nav-bg, transparent) 17%, transparent) 67%,
|
|
557
|
+
color-mix(in srgb, var(--iox-nav-bg, transparent) 6%, transparent) 83%,
|
|
558
|
+
transparent 100%);
|
|
559
|
+
}
|
|
560
|
+
[data-iox-header][data-iox-header-edge='line']::after {
|
|
561
|
+
block-size: var(--iox-border-width, 1px);
|
|
562
|
+
background: var(--iox-nav-border, currentColor);
|
|
563
|
+
}
|
|
564
|
+
[data-iox-scrolled] [data-iox-header][data-iox-header-edge]:not([data-iox-header-edge='none'])::after {
|
|
565
|
+
opacity: 1;
|
|
566
|
+
}
|
|
567
|
+
/* Emil 194/195: reduced transparency makes the bar solid (the token sheet clears its blur and its ground); more
|
|
568
|
+
contrast makes it near-solid with a defined, contrasting edge. A Brand-scheme bar keeps its own solid ground. */
|
|
569
|
+
@media (prefers-contrast: more) {
|
|
570
|
+
.iox-es-nav:not([class*='iox-scheme-']) {
|
|
571
|
+
--iox-nav-bg: var(--iox-bg);
|
|
572
|
+
}
|
|
573
|
+
.iox-es-nav,
|
|
574
|
+
[data-iox-header][data-iox-header-edge] {
|
|
575
|
+
--iox-nav-backdrop: none;
|
|
576
|
+
--iox-nav-border: var(--iox-text);
|
|
577
|
+
--iox-nav-border-width: 0px 0px var(--iox-border-width, 1px) 0px;
|
|
578
|
+
}
|
|
579
|
+
.iox-es-bottom-bar {
|
|
580
|
+
--iox-tabbar-bg: var(--iox-bg);
|
|
581
|
+
--iox-tabbar-backdrop: none;
|
|
582
|
+
--iox-tabbar-border: var(--iox-text);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/* ── Premium components M4 (T3): a link's underline, drawn ──────────────────────────────────────────────────────────
|
|
587
|
+
An element-styled link draws its underline as a line in its own ink under its words, scaled along them from the
|
|
588
|
+
READING START (mirrored in RTL) — so it can grow on hover. `link-underline-rest` is how much shows at rest (1 in
|
|
589
|
+
running content; 0 in a navigation's lists, by their role): it grows on hover (hover devices only — G1), for keyboard
|
|
590
|
+
focus, and the current page's link holds its 2px accent line. The node's own text-decoration reads none here (the
|
|
591
|
+
two decoration tokens are re-declared), so a line is never drawn twice; a legacy link keeps its text-decoration.
|
|
592
|
+
A background line, so it follows the words onto a second line and needs no positioning (the canvas forces a node's
|
|
593
|
+
position); its growth is a background-size the shared compiler adds to the link's transition (withStateTransitions).
|
|
594
|
+
The colour and the line move on the hover timing — ≤150ms on `ease` (Emil 92). */
|
|
595
|
+
.iox-es-link {
|
|
596
|
+
--iox-link-decoration: none;
|
|
597
|
+
--iox-link-current-decoration: none;
|
|
598
|
+
--iox-dur-fast: var(--iox-dur-hover);
|
|
599
|
+
--iox-ease-standard: var(--iox-ease-hover);
|
|
600
|
+
background-image: linear-gradient(currentColor, currentColor);
|
|
601
|
+
background-repeat: no-repeat;
|
|
602
|
+
background-position: 0% calc(100% - var(--iox-link-underline-offset, 0px));
|
|
603
|
+
background-size: calc(var(--iox-link-underline-rest, 1) * 100%) var(--iox-link-underline-thickness, 1px);
|
|
604
|
+
-webkit-box-decoration-break: clone;
|
|
605
|
+
box-decoration-break: clone;
|
|
606
|
+
}
|
|
607
|
+
.iox-es-link:dir(rtl) {
|
|
608
|
+
background-position-x: 100%;
|
|
609
|
+
}
|
|
610
|
+
@media (hover: hover) and (pointer: fine) {
|
|
611
|
+
.iox-es-link:hover {
|
|
612
|
+
background-size: 100% var(--iox-link-underline-thickness, 1px);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
.iox-es-link:focus-visible {
|
|
616
|
+
background-size: 100% var(--iox-link-underline-thickness, 1px);
|
|
617
|
+
}
|
|
618
|
+
.iox-es-link[aria-current='page'] {
|
|
619
|
+
background-image: linear-gradient(var(--iox-link-current-underline, currentColor), var(--iox-link-current-underline, currentColor));
|
|
620
|
+
background-size: 100% var(--iox-link-current-underline-thickness, 2px);
|
|
621
|
+
}
|
|
622
|
+
/* Reduced motion: the line appears and goes in place (it never travels); the colour still eases (Emil 192). */
|
|
623
|
+
@media (prefers-reduced-motion: reduce) {
|
|
624
|
+
.iox-es.iox-es-link {
|
|
625
|
+
transition-property: color;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
/* A chip's colour moves on the hover timing too (Emil 92 — M3's review). */
|
|
629
|
+
.iox-es-chip {
|
|
630
|
+
--iox-dur-fast: var(--iox-dur-hover);
|
|
631
|
+
--iox-ease-standard: var(--iox-ease-hover);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/* ── Premium components M4 (Emil 55/85): a press lands faster than its release ──────────────────────────────────────
|
|
635
|
+
While pressed, every pressable's transition runs on dur-press; it releases on its own (slower) dur-fast. */
|
|
636
|
+
:is(.iox-es-button-primary, .iox-es-button-secondary, .iox-es-button-ghost, .iox-es-bottom-bar-item):active {
|
|
637
|
+
transition-duration: var(--iox-dur-press);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/* ── Premium components M4 (T3): the Slider's feel, its bar and the slider the scroll plays ─────────────────────────
|
|
641
|
+
One curve for the slides: the look's (Emil 18/21 — never Swiper's built-in `ease`). A horizontal carousel leaves
|
|
642
|
+
vertical panning to the page (M9). */
|
|
643
|
+
:where(.swiper) {
|
|
644
|
+
--swiper-wrapper-transition-timing-function: var(--iox-slider-ease, ease);
|
|
645
|
+
}
|
|
646
|
+
:where(.swiper-horizontal) {
|
|
647
|
+
touch-action: pan-y;
|
|
648
|
+
}
|
|
649
|
+
/* The BAR under the picture (M1.3): the caption at the reading start, then the count and the arrows — in flow, never on
|
|
650
|
+
the picture (the bar node lays them out; these keep its words from pushing the arrows). The count reads "1 / 3" in
|
|
651
|
+
every language. */
|
|
652
|
+
:where(.iox-role-slider-bar) .iox-role-slider-caption {
|
|
653
|
+
min-width: 0;
|
|
654
|
+
}
|
|
655
|
+
/* Their words are the slide in view's, written by the runtime as an attribute (composite-core attachSliderBar). */
|
|
656
|
+
:is(.iox-role-slider-caption, .iox-role-slider-count)::before {
|
|
657
|
+
content: attr(data-iox-text);
|
|
658
|
+
}
|
|
659
|
+
.iox-role-slider-count {
|
|
660
|
+
direction: ltr;
|
|
661
|
+
unicode-bidi: isolate;
|
|
662
|
+
font-variant-numeric: tabular-nums;
|
|
663
|
+
white-space: nowrap;
|
|
664
|
+
}
|
|
665
|
+
/* The caption follows the slide in view: it changes behind a short fade (the runtime holds it at 0 for a frame). */
|
|
666
|
+
.iox-role-slider-caption {
|
|
667
|
+
transition: opacity var(--iox-dur-hover) var(--iox-ease-hover);
|
|
668
|
+
}
|
|
669
|
+
.iox-role-slider-caption[data-iox-swapping] {
|
|
670
|
+
opacity: 0;
|
|
671
|
+
transition-duration: 0ms;
|
|
672
|
+
}
|
|
673
|
+
/* On a phone a "cards" stack stays a centred card with its neighbours peeking out (one picture the full width is
|
|
674
|
+
planSwiperOptions' default for every other effect). */
|
|
675
|
+
@media (max-width: 767px) {
|
|
676
|
+
.swiper.swiper-cards {
|
|
677
|
+
width: 86%;
|
|
678
|
+
margin-inline: auto;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
/* A Slider the SCROLL plays: its runway holds the slider mid-screen while the page scrolls past half a screen per
|
|
682
|
+
picture; the ONE scene driver moves it, resting on each picture (scene-core `heldProgress`). `--slider-steps` is
|
|
683
|
+
written by the renderers (no layout shift), `--slider-h` by the slider's boot. On the canvas the driver pins it
|
|
684
|
+
(its page never scrolls itself) and `--preview-vh` stands for the frame's height. Under reduced motion it is an
|
|
685
|
+
ordinary slider: no runway, swiped and pressed. */
|
|
686
|
+
.iox-slider-runway {
|
|
687
|
+
position: relative;
|
|
688
|
+
}
|
|
689
|
+
.iox-slider-runway > :is(.swiper, .slider-edit-shell) {
|
|
690
|
+
position: sticky;
|
|
691
|
+
inset-block-start: max(0px, calc((var(--preview-vh, 1svh) * 100 - var(--slider-h, 0px)) / 2));
|
|
692
|
+
}
|
|
693
|
+
.iox-slider-runway::after {
|
|
694
|
+
content: '';
|
|
695
|
+
display: block;
|
|
696
|
+
block-size: calc(var(--slider-steps, 0) * var(--preview-vh, 1svh) * 55);
|
|
697
|
+
}
|
|
698
|
+
@media (prefers-reduced-motion: reduce) {
|
|
699
|
+
.iox-slider-runway::after {
|
|
700
|
+
display: none;
|
|
701
|
+
}
|
|
702
|
+
.iox-slider-runway > :is(.swiper, .slider-edit-shell) {
|
|
703
|
+
position: relative;
|
|
704
|
+
inset-block-start: 0;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
package/styles/iox-forms.css
CHANGED
|
@@ -549,7 +549,8 @@ dialog.iox-cal[data-iox-instant]::backdrop { transition: none !important; }
|
|
|
549
549
|
/* ── Premium M3, under the field marker: a Choices field's chips wear the `chip` element style (N1); a Date's words,
|
|
550
550
|
glyph and open box, its calendar the `calendar` style and every day `calendar-day` (N8). These rules ARE the
|
|
551
551
|
contract's fieldClassBaseline entries, verbatim (generated from the element styles by build-spec.mjs; pinned by
|
|
552
|
-
token-names.spec). Hover is gated to hover devices (G1).
|
|
552
|
+
token-names.spec). Hover is gated to hover devices (G1). M4: a chip's colour moves on the hover timing (dur-hover,
|
|
553
|
+
≤150ms on `ease` — Emil 92); a chip and a day press on dur-press and release on the slower dur-fast (Emil 55/85). ── */
|
|
553
554
|
.iox-es-field .iox-field__chip {
|
|
554
555
|
background-color: transparent;
|
|
555
556
|
color: var(--iox-text);
|
|
@@ -561,10 +562,11 @@ dialog.iox-cal[data-iox-instant]::backdrop { transition: none !important; }
|
|
|
561
562
|
font-family: var(--iox-font-label);
|
|
562
563
|
font-size: var(--iox-badge-size);
|
|
563
564
|
font-weight: var(--iox-weight-label);
|
|
564
|
-
transition: border-color var(--iox-dur-
|
|
565
|
+
transition: border-color var(--iox-dur-hover) var(--iox-ease-hover), background-color var(--iox-dur-hover) var(--iox-ease-hover), color var(--iox-dur-hover) var(--iox-ease-hover), box-shadow var(--iox-dur-hover) var(--iox-ease-hover), opacity var(--iox-dur-hover) var(--iox-ease-hover), transform var(--iox-dur-fast) var(--iox-ease-standard);
|
|
565
566
|
}
|
|
566
567
|
.iox-es-field .iox-field__chip:active:not(:has(:disabled)) {
|
|
567
568
|
transform: scale(var(--iox-press-scale));
|
|
569
|
+
transition-duration: var(--iox-dur-press);
|
|
568
570
|
}
|
|
569
571
|
@media (hover: hover) and (pointer: fine) {
|
|
570
572
|
.iox-es-field .iox-field__chip:hover:not(:has(:disabled)) {
|
|
@@ -639,6 +641,7 @@ dialog.iox-cal[data-iox-instant]::backdrop { transition: none !important; }
|
|
|
639
641
|
}
|
|
640
642
|
.iox-es-field .iox-cal .iox-cal__day:active:not([aria-disabled='true']) {
|
|
641
643
|
transform: scale(var(--iox-press-scale));
|
|
644
|
+
transition-duration: var(--iox-dur-press);
|
|
642
645
|
}
|
|
643
646
|
@media (hover: hover) and (pointer: fine) {
|
|
644
647
|
.iox-es-field .iox-cal .iox-cal__day:hover:not([aria-disabled='true']) {
|