@getvitops/core 8.0.0 → 8.0.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/CHANGELOG.md +2 -0
- package/css/patterns/lightbox.css +69 -10
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -70,18 +70,31 @@ dialog.lightbox-dialog {
|
|
|
70
70
|
|
|
71
71
|
.lightbox-dialog__track {
|
|
72
72
|
max-inline-size: 100%;
|
|
73
|
+
/* Inert: `.carousel`'s implicit grid row is `auto`, so this percentage is
|
|
74
|
+
cyclic (CSS Sizing 3 §5.2) — it resolves against the row's own
|
|
75
|
+
content-derived size, i.e. against itself, and can never actually clamp
|
|
76
|
+
it. Kept only to state intent; the `<img>`/`<picture>` cap below is what
|
|
77
|
+
does the real work by capping the thing with an intrinsic size instead
|
|
78
|
+
of trying to cap a box that is sized BY that intrinsic size. */
|
|
73
79
|
max-block-size: 100%;
|
|
74
80
|
|
|
81
|
+
/* One source of truth for the slide's breathing room: the padding below
|
|
82
|
+
and the image's block cap both read these, so they cannot drift apart. */
|
|
83
|
+
--lightbox-pad-block: 5dvh;
|
|
84
|
+
--lightbox-pad-inline: 5dvw;
|
|
85
|
+
|
|
75
86
|
/* `.carousel__media`'s own rule reads this for its `object-fit` (default
|
|
76
87
|
`cover`, right for a thumbnail strip, wrong for a full image — nothing
|
|
77
88
|
here should be cropped). Nesting under `dialog.lightbox-dialog` gives
|
|
78
89
|
this whole block higher specificity than carousel.css's bare
|
|
79
|
-
`.carousel__media` rule regardless of import order, so it always wins.
|
|
90
|
+
`.carousel__media` rule regardless of import order, so it always wins.
|
|
91
|
+
Belt-and-braces only now: the image rule below sizes the box to the
|
|
92
|
+
image, so there's normally nothing left for `object-fit` to do. */
|
|
80
93
|
--carousel-media-fit: contain;
|
|
81
94
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
95
|
+
/* No `.carousel__track { max-block-size: 100% }` override here — same
|
|
96
|
+
cyclic-percentage trap as above, against `.carousel`'s own implicit
|
|
97
|
+
`auto` row. It has never applied. */
|
|
85
98
|
|
|
86
99
|
/* Breathing room against the edge-to-edge dialog, on the SLIDE rather than
|
|
87
100
|
the media box — a slide is the grid item `align-items: stretch` fills to
|
|
@@ -89,21 +102,31 @@ dialog.lightbox-dialog {
|
|
|
89
102
|
glass instead of the media box's aspect-ratio doing it. */
|
|
90
103
|
.carousel__slide {
|
|
91
104
|
box-sizing: border-box;
|
|
92
|
-
padding:
|
|
105
|
+
padding: var(--lightbox-pad-block) var(--lightbox-pad-inline);
|
|
106
|
+
|
|
107
|
+
/* carousel.css gives a slide `align-content: start` so a `cover`ed media
|
|
108
|
+
box (which fills the row) hugs the top. Here the media box is
|
|
109
|
+
deliberately SMALLER than the slide — it's sized to the image, not the
|
|
110
|
+
other way around — so it must be centred instead, or a 16/9 image
|
|
111
|
+
would hang from the top of a row sized by a 9/16 neighbour. */
|
|
112
|
+
align-content: center;
|
|
93
113
|
}
|
|
94
114
|
|
|
95
115
|
.carousel__media {
|
|
96
|
-
/* Full images vary wildly in ratio;
|
|
97
|
-
|
|
98
|
-
|
|
116
|
+
/* Full images vary wildly in ratio; drop carousel.css's fixed 16/9 box
|
|
117
|
+
(right for a thumbnail strip, wrong here) and let the image below
|
|
118
|
+
determine the box's size. carousel.css's `block-size: 100%` is
|
|
119
|
+
deliberately NOT reinstated here: against this slide's content-sized
|
|
120
|
+
`auto` row it's the same cyclic percentage as the caps above, and it
|
|
121
|
+
only ever resolved back to the content height it was meant to cap. */
|
|
99
122
|
aspect-ratio: unset;
|
|
100
|
-
block-size: 100%;
|
|
101
123
|
|
|
102
124
|
/* Painted the instant a slide is visible, whether or not the full image
|
|
103
125
|
has loaded yet — the morph target is never an empty box. Set per-slide
|
|
104
126
|
by `<Gallery />` from the thumbnail URL; declared as a var rather than
|
|
105
127
|
a bare property so a slide that omits a thumb (no placeholder) simply
|
|
106
|
-
paints nothing extra.
|
|
128
|
+
paints nothing extra. `contain` + `center` lands on the same rect the
|
|
129
|
+
image below resolves to, so the placeholder doesn't jump on load. */
|
|
107
130
|
background-image: var(--lightbox-placeholder, none);
|
|
108
131
|
background-size: contain;
|
|
109
132
|
background-position: center;
|
|
@@ -118,6 +141,42 @@ dialog.lightbox-dialog {
|
|
|
118
141
|
a `view-transition-name` on the image here statically. */
|
|
119
142
|
}
|
|
120
143
|
|
|
144
|
+
/* THE FIX. carousel.css sizes the media to fill its box
|
|
145
|
+
(`inline-size`/`block-size: 100%`) so `object-fit: cover` has something
|
|
146
|
+
to crop — right for a thumbnail strip, backwards for a lightbox, where
|
|
147
|
+
the BOX should instead be sized to the image. With both axes `auto` and
|
|
148
|
+
both maxes set, the browser's replaced-element min/max algorithm
|
|
149
|
+
(CSS 2.1 §10.4) does a ratio-preserving clamp against whichever axis
|
|
150
|
+
binds — so the element's border box IS the visible image, with no
|
|
151
|
+
cyclic percentages and no dependency on how many rows the grid above
|
|
152
|
+
ends up with. That also matters for two things beyond sizing: it's the
|
|
153
|
+
`view-transition-name` target (WCGallery.ts), so the morph must not
|
|
154
|
+
land on an oversized box; and it keeps the letterbox area click-through
|
|
155
|
+
for the dialog's `closedby="any"`.
|
|
156
|
+
|
|
157
|
+
A DESCENDANT selector, not a direct-child `>`: an `ImageMetadata` src
|
|
158
|
+
renders `<picture><img></picture>` (ResponsiveImage.astro), and
|
|
159
|
+
carousel.css's own rule only reaches the non-replaced `<picture>` via
|
|
160
|
+
`> :is(img, picture, …)` — `object-fit` is a no-op there, and the real
|
|
161
|
+
`<img>` inside gets no sizing at all. This selector covers both the
|
|
162
|
+
bare-`<img>` demo and the `<picture>`-wrapped case. */
|
|
163
|
+
.carousel__media :is(img, picture) {
|
|
164
|
+
/* Undo carousel.css's `inline-size/block-size: 100%` — a fixed size on
|
|
165
|
+
either axis would defeat the ratio-preserving clamp below. */
|
|
166
|
+
inline-size: auto;
|
|
167
|
+
block-size: auto;
|
|
168
|
+
max-inline-size: 100%; /* of the padded slide, i.e. ~90dvw */
|
|
169
|
+
/* The one cap that actually binds (not a percentage, so not cyclic).
|
|
170
|
+
`--lightbox-caption-space` is 0 by default — nothing here uses a
|
|
171
|
+
caption today, but `<figcaption>` stacks below the image inside this
|
|
172
|
+
same box (Gallery.astro), so a captioned gallery must set it to
|
|
173
|
+
reserve room or the slide can exceed the viewport by that height. */
|
|
174
|
+
max-block-size: calc(
|
|
175
|
+
100dvh - 2 * var(--lightbox-pad-block) - var(--lightbox-caption-space, 0px)
|
|
176
|
+
);
|
|
177
|
+
margin-inline: auto; /* centre in the full-width figure; vertical centring is the slide's align-content */
|
|
178
|
+
}
|
|
179
|
+
|
|
121
180
|
.carousel__caption {
|
|
122
181
|
color: inherit;
|
|
123
182
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getvitops/core",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.1",
|
|
4
4
|
"description": "The Vitops design-system framework — CSS partials, Lit web components, and browser polyfills.",
|
|
5
5
|
"homepage": "https://docs.vitops.ca",
|
|
6
6
|
"bugs": "https://github.com/getvitops/design-system/issues",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"scroll-timeline-polyfill": "^1.1.0",
|
|
47
47
|
"temporal-polyfill": "^1.0.1",
|
|
48
48
|
"vitest": "4.1.9",
|
|
49
|
-
"@getvitops/utils": "8.0.
|
|
49
|
+
"@getvitops/utils": "8.0.1"
|
|
50
50
|
},
|
|
51
51
|
"engines": {
|
|
52
52
|
"node": ">=24"
|