@motion-proto/live-tokens 0.85.0 → 0.87.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/CHANGELOG.md +55 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/editor/component-editor/SlidePagerEditor.svelte +118 -0
- package/src/editor/component-editor/VideoFrameEditor.svelte +73 -0
- package/src/editor/component-editor/VideoLightboxEditor.svelte +108 -0
- package/src/editor/component-editor/registry.ts +40 -1
- package/src/editor/core/sketch/sketchLayer.ts +7 -0
- package/src/editor/overlay/LiveEditorOverlay.svelte +45 -52
- package/src/editor/pages/ComponentEditorPage.svelte +1 -1
- package/src/editor/ui/ThemePanel.svelte +9 -53
- package/src/live-tokens/data/themes/autumn.json +97 -0
- package/src/live-tokens/data/themes/halloween.json +97 -0
- package/src/live-tokens/data/themes/midnight-study.json +97 -0
- package/src/live-tokens/data/themes/ocean.json +97 -0
- package/src/live-tokens/data/themes/royal-velvet.json +97 -0
- package/src/live-tokens/data/themes/sketchy.json +97 -0
- package/src/live-tokens/data/themes/spring-meadow.json +97 -0
- package/src/live-tokens/data/themes/sunset.json +97 -0
- package/src/system/assets/slide-04.webp +0 -0
- package/src/system/assets/slide-05.webp +0 -0
- package/src/system/assets/slide-06.webp +0 -0
- package/src/system/assets/watch-navigation-poster.webp +0 -0
- package/src/system/assets/watch-navigation.mp4 +0 -0
- package/src/system/components/ImageLightbox.svelte +20 -21
- package/src/system/components/SlidePager.svelte +516 -0
- package/src/system/components/VideoFrame.svelte +284 -0
- package/src/system/components/VideoLightbox.svelte +454 -0
- package/src/testing-js/{chunk-RDHCBQ6I.js → chunk-FTLASW2R.js} +366 -2
- package/src/testing-js/chunk-FTLASW2R.js.map +1 -0
- package/src/testing-js/{chunk-XV5CYADO.js → chunk-NXRFTTVL.js} +10 -6
- package/src/testing-js/chunk-NXRFTTVL.js.map +1 -0
- package/src/testing-js/component-behavior.contract.js +1 -1
- package/src/testing-js/component-editor.contract.js +1 -1
- package/src/testing-js/component-render.contract.js +1 -1
- package/src/testing-js/index.d.ts +2 -2
- package/src/testing-js/index.js +2 -2
- package/src/testing-js/page-compliance.contract.js +1 -1
- package/src/testing-js/{vitest-BMLIbDs2.d.ts → vitest-5vWtqwWe.d.ts} +2 -2
- package/src/testing-js/vitest.d.ts +1 -1
- package/src/testing-js/vitest.js +2 -2
- package/src/testing-js/chunk-RDHCBQ6I.js.map +0 -1
- package/src/testing-js/chunk-XV5CYADO.js.map +0 -1
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import type { CatalogueEntry } from '../../editor/component-editor/scaffolding/types';
|
|
3
|
+
|
|
4
|
+
export const catalogue = {
|
|
5
|
+
description: 'A deck of slides the reader flips through in place, one at a time.',
|
|
6
|
+
whenToUse:
|
|
7
|
+
'a talk or a set of exported pages read in order, where the reader moves forward and back without leaving the page.',
|
|
8
|
+
whenNotToUse: [
|
|
9
|
+
{ when: 'the pictures have no order and the reader opens one at a time.', use: 'imagelightbox' },
|
|
10
|
+
{ when: 'the reader takes one picture in at a glance.', use: 'image' },
|
|
11
|
+
{ when: 'the content is a clip rather than a set of stills.', use: 'videoframe' }
|
|
12
|
+
],
|
|
13
|
+
constraints: [
|
|
14
|
+
'Every slide carries alt text naming what it says, since the words on a slide reach a screen reader no other way.'
|
|
15
|
+
],
|
|
16
|
+
props: {
|
|
17
|
+
index: 'the slide the pager opens on, counted from zero.',
|
|
18
|
+
aspect: 'the ratio the frame holds. Exported slides are 16 / 9.',
|
|
19
|
+
zoom: 'false drops the full-screen read, leaving the frame unclickable. The full-screen read pages through every slide, with its own close button.',
|
|
20
|
+
inline:
|
|
21
|
+
'true renders the open zoom in flow, without the frame. The editor preview uses it.'
|
|
22
|
+
}
|
|
23
|
+
} satisfies CatalogueEntry;
|
|
24
|
+
|
|
25
|
+
export type SlidePage = {
|
|
26
|
+
src: string;
|
|
27
|
+
alt: string;
|
|
28
|
+
width?: number;
|
|
29
|
+
height?: number;
|
|
30
|
+
};
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<script lang="ts">
|
|
34
|
+
import { tick, untrack } from 'svelte';
|
|
35
|
+
import { portal } from '../internal/portal';
|
|
36
|
+
|
|
37
|
+
interface Props {
|
|
38
|
+
slides: SlidePage[];
|
|
39
|
+
/** The slide the pager opens on, counted from zero. */
|
|
40
|
+
index?: number;
|
|
41
|
+
/** The ratio the frame holds. Exported slides are 16 / 9. */
|
|
42
|
+
aspect?: number;
|
|
43
|
+
/** Drops the full-screen read, leaving the frame unclickable. */
|
|
44
|
+
zoom?: boolean;
|
|
45
|
+
/** Renders the open zoom in flow, without the frame. Used by the editor preview. */
|
|
46
|
+
inline?: boolean;
|
|
47
|
+
/** Fires with the slide the reader moved to. */
|
|
48
|
+
onchange?: (index: number) => void;
|
|
49
|
+
class?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let {
|
|
53
|
+
slides,
|
|
54
|
+
index = 0,
|
|
55
|
+
aspect = 16 / 9,
|
|
56
|
+
zoom = true,
|
|
57
|
+
inline = false,
|
|
58
|
+
onchange = undefined,
|
|
59
|
+
class: className = ''
|
|
60
|
+
}: Props = $props();
|
|
61
|
+
|
|
62
|
+
// `index` seeds the pager and then lets go: once the reader is flipping, a
|
|
63
|
+
// parent re-render must not drag them back to the slide it named.
|
|
64
|
+
let current = $state(untrack(() => index));
|
|
65
|
+
|
|
66
|
+
const count = $derived(slides.length);
|
|
67
|
+
const slide = $derived(slides[Math.min(current, Math.max(count - 1, 0))]);
|
|
68
|
+
const atStart = $derived(current <= 0);
|
|
69
|
+
const atEnd = $derived(current >= count - 1);
|
|
70
|
+
// Held in the DOM so a flip paints the next slide from cache rather than
|
|
71
|
+
// blanking the frame while the browser fetches it.
|
|
72
|
+
const neighbours = $derived(
|
|
73
|
+
[slides[current - 1], slides[current + 1]].filter(Boolean) as SlidePage[]
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
function go(next: number) {
|
|
77
|
+
const clamped = Math.max(0, Math.min(next, count - 1));
|
|
78
|
+
if (clamped === current) return;
|
|
79
|
+
current = clamped;
|
|
80
|
+
onchange?.(clamped);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function onKey(e: KeyboardEvent) {
|
|
84
|
+
if (e.key === 'ArrowLeft') {
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
go(current - 1);
|
|
87
|
+
} else if (e.key === 'ArrowRight') {
|
|
88
|
+
e.preventDefault();
|
|
89
|
+
go(current + 1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let frameEl: HTMLButtonElement | undefined = $state();
|
|
94
|
+
let modalEl: HTMLDivElement | undefined = $state();
|
|
95
|
+
// `mounted` keeps the zoom in the DOM through the fade out, `shown` drives
|
|
96
|
+
// the fade, and `open` is what the frame reports.
|
|
97
|
+
let mounted = $state(false);
|
|
98
|
+
let shown = $state(false);
|
|
99
|
+
let open = $state(false);
|
|
100
|
+
|
|
101
|
+
async function openZoom() {
|
|
102
|
+
if (open || !zoom) return;
|
|
103
|
+
open = true;
|
|
104
|
+
mounted = true;
|
|
105
|
+
await tick();
|
|
106
|
+
if (!modalEl) return;
|
|
107
|
+
// Commit the transparent start so the class change below fades in.
|
|
108
|
+
modalEl.getBoundingClientRect();
|
|
109
|
+
shown = true;
|
|
110
|
+
modalEl.focus();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function closeZoom() {
|
|
114
|
+
if (!open || !modalEl) return;
|
|
115
|
+
open = false;
|
|
116
|
+
shown = false;
|
|
117
|
+
await tick();
|
|
118
|
+
await Promise.all(modalEl.getAnimations().map((a) => a.finished)).catch(() => {});
|
|
119
|
+
if (open) return;
|
|
120
|
+
mounted = false;
|
|
121
|
+
frameEl?.focus();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Tab stays inside the zoom, stepping through its enabled buttons.
|
|
125
|
+
function cycleFocus(dir: 1 | -1) {
|
|
126
|
+
if (!modalEl) return;
|
|
127
|
+
const stops = [...modalEl.querySelectorAll<HTMLButtonElement>('button:not(:disabled)')];
|
|
128
|
+
if (!stops.length) return;
|
|
129
|
+
const at = stops.indexOf(document.activeElement as HTMLButtonElement);
|
|
130
|
+
const next = at < 0 ? (dir > 0 ? 0 : stops.length - 1) : (at + dir + stops.length) % stops.length;
|
|
131
|
+
stops[next].focus();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// A page may turn its own slides on keys it hears at the window, so the zoom
|
|
135
|
+
// keeps every key it uses to itself.
|
|
136
|
+
function onModalKey(e: KeyboardEvent) {
|
|
137
|
+
e.stopPropagation();
|
|
138
|
+
if (e.key === 'Escape') {
|
|
139
|
+
closeZoom();
|
|
140
|
+
} else if (e.key === 'Tab') {
|
|
141
|
+
e.preventDefault();
|
|
142
|
+
cycleFocus(e.shiftKey ? -1 : 1);
|
|
143
|
+
} else {
|
|
144
|
+
onKey(e);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
</script>
|
|
148
|
+
|
|
149
|
+
{#snippet bar()}
|
|
150
|
+
<div class="slidepager-bar">
|
|
151
|
+
<button
|
|
152
|
+
type="button"
|
|
153
|
+
class="slidepager-control sketch-chip"
|
|
154
|
+
data-nav="prev"
|
|
155
|
+
aria-label="Previous slide"
|
|
156
|
+
disabled={atStart}
|
|
157
|
+
onclick={(e) => {
|
|
158
|
+
e.stopPropagation();
|
|
159
|
+
go(current - 1);
|
|
160
|
+
}}
|
|
161
|
+
>
|
|
162
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
163
|
+
<path d="M15 18l-6-6 6-6" />
|
|
164
|
+
</svg>
|
|
165
|
+
</button>
|
|
166
|
+
|
|
167
|
+
<p class="slidepager-counter" aria-live="polite">{current + 1} / {count}</p>
|
|
168
|
+
|
|
169
|
+
<button
|
|
170
|
+
type="button"
|
|
171
|
+
class="slidepager-control sketch-chip"
|
|
172
|
+
data-nav="next"
|
|
173
|
+
aria-label="Next slide"
|
|
174
|
+
disabled={atEnd}
|
|
175
|
+
onclick={(e) => {
|
|
176
|
+
e.stopPropagation();
|
|
177
|
+
go(current + 1);
|
|
178
|
+
}}
|
|
179
|
+
>
|
|
180
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
181
|
+
<path d="M9 18l6-6-6-6" />
|
|
182
|
+
</svg>
|
|
183
|
+
</button>
|
|
184
|
+
</div>
|
|
185
|
+
{/snippet}
|
|
186
|
+
|
|
187
|
+
{#snippet close(onclose?: () => void)}
|
|
188
|
+
<button
|
|
189
|
+
type="button"
|
|
190
|
+
class="slidepager-control slidepager-close sketch-chip"
|
|
191
|
+
aria-label="Close"
|
|
192
|
+
tabindex={onclose ? undefined : -1}
|
|
193
|
+
onclick={(e) => {
|
|
194
|
+
e.stopPropagation();
|
|
195
|
+
onclose?.();
|
|
196
|
+
}}
|
|
197
|
+
>
|
|
198
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
199
|
+
<path d="M18 6L6 18" />
|
|
200
|
+
<path d="M6 6l12 12" />
|
|
201
|
+
</svg>
|
|
202
|
+
</button>
|
|
203
|
+
{/snippet}
|
|
204
|
+
|
|
205
|
+
{#if inline}
|
|
206
|
+
<div class="slidepager-modal inline shown {className}" style:--slidepager-ratio={aspect}>
|
|
207
|
+
<img class="slidepager-full" src={slide?.src} alt={slide?.alt ?? ''} draggable="false" />
|
|
208
|
+
|
|
209
|
+
<div class="slidepager-modal-bar">
|
|
210
|
+
{@render bar()}
|
|
211
|
+
</div>
|
|
212
|
+
{@render close()}
|
|
213
|
+
</div>
|
|
214
|
+
{:else}
|
|
215
|
+
<!-- The keys land here so they reach the pager only while one of its own
|
|
216
|
+
controls holds focus, leaving the rest of the page its own bindings. -->
|
|
217
|
+
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
218
|
+
<div
|
|
219
|
+
class="slidepager {className}"
|
|
220
|
+
role="group"
|
|
221
|
+
aria-roledescription="carousel"
|
|
222
|
+
aria-label="Slide deck"
|
|
223
|
+
onkeydown={onKey}
|
|
224
|
+
>
|
|
225
|
+
<div class="slidepager-frame sketch-surface" style:aspect-ratio={aspect}>
|
|
226
|
+
{#if zoom}
|
|
227
|
+
<button
|
|
228
|
+
bind:this={frameEl}
|
|
229
|
+
type="button"
|
|
230
|
+
class="slidepager-stage"
|
|
231
|
+
aria-label={`Open slide ${current + 1} full screen`}
|
|
232
|
+
aria-haspopup="dialog"
|
|
233
|
+
aria-expanded={open}
|
|
234
|
+
onclick={openZoom}
|
|
235
|
+
>
|
|
236
|
+
<img src={slide?.src} alt={slide?.alt ?? ''} draggable="false" />
|
|
237
|
+
</button>
|
|
238
|
+
{:else}
|
|
239
|
+
<div class="slidepager-stage">
|
|
240
|
+
<img src={slide?.src} alt={slide?.alt ?? ''} draggable="false" />
|
|
241
|
+
</div>
|
|
242
|
+
{/if}
|
|
243
|
+
</div>
|
|
244
|
+
|
|
245
|
+
{@render bar()}
|
|
246
|
+
|
|
247
|
+
<div class="slidepager-preload" aria-hidden="true">
|
|
248
|
+
{#each neighbours as near (near.src)}
|
|
249
|
+
<img src={near.src} alt="" draggable="false" />
|
|
250
|
+
{/each}
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
|
|
254
|
+
{#if mounted}
|
|
255
|
+
<!-- Clicking anywhere but a control closes it, as do the close button and
|
|
256
|
+
Escape. The bar and the arrow keys keep paging at full size. -->
|
|
257
|
+
<div
|
|
258
|
+
bind:this={modalEl}
|
|
259
|
+
class="slidepager-modal"
|
|
260
|
+
class:shown
|
|
261
|
+
role="dialog"
|
|
262
|
+
aria-modal="true"
|
|
263
|
+
aria-label={slide?.alt}
|
|
264
|
+
tabindex="-1"
|
|
265
|
+
style:--slidepager-ratio={aspect}
|
|
266
|
+
use:portal
|
|
267
|
+
onclick={closeZoom}
|
|
268
|
+
onkeydown={onModalKey}
|
|
269
|
+
>
|
|
270
|
+
<img class="slidepager-full" src={slide?.src} alt={slide?.alt ?? ''} draggable="false" />
|
|
271
|
+
|
|
272
|
+
<div class="slidepager-modal-bar">
|
|
273
|
+
{@render bar()}
|
|
274
|
+
</div>
|
|
275
|
+
{@render close(closeZoom)}
|
|
276
|
+
</div>
|
|
277
|
+
{/if}
|
|
278
|
+
{/if}
|
|
279
|
+
|
|
280
|
+
<style>
|
|
281
|
+
:global(:root) {
|
|
282
|
+
--slidepager-frame-surface: var(--surface-neutral-lower);
|
|
283
|
+
--slidepager-frame-border: var(--border-neutral-subtle);
|
|
284
|
+
--slidepager-frame-border-width: var(--border-width-1);
|
|
285
|
+
--slidepager-frame-radius: var(--radius-2xl);
|
|
286
|
+
--slidepager-frame-shadow: var(--shadow-md);
|
|
287
|
+
|
|
288
|
+
--slidepager-bar-gap: var(--space-16);
|
|
289
|
+
--slidepager-bar-padding: var(--space-12);
|
|
290
|
+
|
|
291
|
+
--slidepager-control-surface: var(--surface-neutral-low);
|
|
292
|
+
--slidepager-control-border: var(--border-neutral);
|
|
293
|
+
--slidepager-control-border-width: var(--border-width-1);
|
|
294
|
+
--slidepager-control-radius: var(--radius-full);
|
|
295
|
+
--slidepager-control-size: var(--space-40);
|
|
296
|
+
--slidepager-control-icon: var(--text-primary);
|
|
297
|
+
--slidepager-control-icon-size: var(--icon-size-md);
|
|
298
|
+
|
|
299
|
+
--slidepager-control-hover-surface: var(--surface-brand-high);
|
|
300
|
+
--slidepager-control-hover-border: var(--border-brand);
|
|
301
|
+
--slidepager-control-hover-icon: var(--text-inverted);
|
|
302
|
+
|
|
303
|
+
--slidepager-control-disabled-surface: var(--surface-neutral-lower);
|
|
304
|
+
--slidepager-control-disabled-border: var(--border-neutral-subtle);
|
|
305
|
+
--slidepager-control-disabled-icon: var(--text-disabled);
|
|
306
|
+
|
|
307
|
+
--slidepager-counter-text: var(--text-secondary);
|
|
308
|
+
--slidepager-counter-font-family: var(--font-sans);
|
|
309
|
+
--slidepager-counter-font-size: var(--font-size-lg);
|
|
310
|
+
--slidepager-counter-font-weight: var(--font-weight-medium);
|
|
311
|
+
--slidepager-counter-line-height: var(--line-height-normal);
|
|
312
|
+
--slidepager-counter-letter-spacing: var(--letter-spacing-normal);
|
|
313
|
+
|
|
314
|
+
--slidepager-scrim-surface: var(--scrim-high);
|
|
315
|
+
--slidepager-overlay-padding: var(--space-64);
|
|
316
|
+
--slidepager-close-margin: var(--space-24);
|
|
317
|
+
--slidepager-overlay-duration: var(--duration-300);
|
|
318
|
+
--slidepager-overlay-easing: var(--ease-out-quad);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.slidepager {
|
|
322
|
+
display: flex;
|
|
323
|
+
flex-direction: column;
|
|
324
|
+
width: 100%;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.slidepager-frame {
|
|
328
|
+
width: 100%;
|
|
329
|
+
background: var(--slidepager-frame-surface);
|
|
330
|
+
border: var(--slidepager-frame-border-width) solid var(--slidepager-frame-border);
|
|
331
|
+
border-radius: var(--slidepager-frame-radius);
|
|
332
|
+
box-shadow: var(--slidepager-frame-shadow);
|
|
333
|
+
|
|
334
|
+
--sketch-fill: var(--slidepager-frame-surface);
|
|
335
|
+
--sketch-stroke: var(--slidepager-frame-border);
|
|
336
|
+
--sketch-hatch-color: var(--slidepager-frame-border);
|
|
337
|
+
--sketch-radius: var(--slidepager-frame-radius);
|
|
338
|
+
--sketch-shadow: var(--slidepager-frame-shadow);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/* The slide lives one level in: the sketch layer forces the drawn part's
|
|
342
|
+
overflow visible, which would let the picture's square corners escape. */
|
|
343
|
+
.slidepager-stage {
|
|
344
|
+
display: block;
|
|
345
|
+
width: 100%;
|
|
346
|
+
height: 100%;
|
|
347
|
+
padding: 0;
|
|
348
|
+
border: none;
|
|
349
|
+
background: none;
|
|
350
|
+
overflow: hidden;
|
|
351
|
+
border-radius: var(--sketch-radius, var(--slidepager-frame-radius));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
button.slidepager-stage {
|
|
355
|
+
cursor: zoom-in;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.slidepager-stage:focus-visible {
|
|
359
|
+
outline: none;
|
|
360
|
+
box-shadow: var(--ring-focus-md);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.slidepager-stage img {
|
|
364
|
+
display: block;
|
|
365
|
+
width: 100%;
|
|
366
|
+
height: 100%;
|
|
367
|
+
object-fit: contain;
|
|
368
|
+
user-select: none;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.slidepager-bar {
|
|
372
|
+
display: flex;
|
|
373
|
+
align-items: center;
|
|
374
|
+
justify-content: center;
|
|
375
|
+
gap: var(--slidepager-bar-gap);
|
|
376
|
+
padding: var(--slidepager-bar-padding);
|
|
377
|
+
|
|
378
|
+
/* Travel is stated in px against a glyph the layer cannot measure, so a
|
|
379
|
+
chevron this size tears at the full dial. */
|
|
380
|
+
--sketch-icon-off: var(--sketch-icon-soft);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.slidepager-control {
|
|
384
|
+
display: grid;
|
|
385
|
+
place-items: center;
|
|
386
|
+
flex: none;
|
|
387
|
+
width: var(--slidepager-control-size);
|
|
388
|
+
height: var(--slidepager-control-size);
|
|
389
|
+
padding: 0;
|
|
390
|
+
background: var(--slidepager-control-surface);
|
|
391
|
+
border: var(--slidepager-control-border-width) solid var(--slidepager-control-border);
|
|
392
|
+
border-radius: var(--slidepager-control-radius);
|
|
393
|
+
color: var(--slidepager-control-icon);
|
|
394
|
+
cursor: pointer;
|
|
395
|
+
|
|
396
|
+
--sketch-fill: var(--slidepager-control-surface);
|
|
397
|
+
--sketch-stroke: var(--slidepager-control-border);
|
|
398
|
+
--sketch-hatch-color: var(--slidepager-control-border);
|
|
399
|
+
--sketch-radius: var(--slidepager-control-radius);
|
|
400
|
+
--sketch-shadow: var(--shadow-none);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.slidepager-control:hover:not(:disabled),
|
|
404
|
+
.slidepager.force-hover .slidepager-control:not(:disabled),
|
|
405
|
+
.slidepager-modal.force-hover .slidepager-control:not(:disabled) {
|
|
406
|
+
background: var(--slidepager-control-hover-surface);
|
|
407
|
+
border-color: var(--slidepager-control-hover-border);
|
|
408
|
+
color: var(--slidepager-control-hover-icon);
|
|
409
|
+
|
|
410
|
+
--sketch-fill: var(--slidepager-control-hover-surface);
|
|
411
|
+
--sketch-stroke: var(--slidepager-control-hover-border);
|
|
412
|
+
--sketch-hatch-color: var(--slidepager-control-hover-border);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.slidepager-control:disabled,
|
|
416
|
+
.slidepager.force-disabled .slidepager-control,
|
|
417
|
+
.slidepager-modal.force-disabled .slidepager-control:not(.slidepager-close) {
|
|
418
|
+
background: var(--slidepager-control-disabled-surface);
|
|
419
|
+
border-color: var(--slidepager-control-disabled-border);
|
|
420
|
+
color: var(--slidepager-control-disabled-icon);
|
|
421
|
+
cursor: default;
|
|
422
|
+
|
|
423
|
+
--sketch-fill: var(--slidepager-control-disabled-surface);
|
|
424
|
+
--sketch-stroke: var(--slidepager-control-disabled-border);
|
|
425
|
+
--sketch-hatch-color: var(--slidepager-control-disabled-border);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.slidepager-control svg {
|
|
429
|
+
width: var(--slidepager-control-icon-size);
|
|
430
|
+
height: var(--slidepager-control-icon-size);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.slidepager-close {
|
|
434
|
+
position: absolute;
|
|
435
|
+
top: var(--slidepager-close-margin);
|
|
436
|
+
right: var(--slidepager-close-margin);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.slidepager-control:focus-visible {
|
|
440
|
+
outline: none;
|
|
441
|
+
box-shadow: var(--ring-focus-md);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.slidepager-counter {
|
|
445
|
+
margin: 0;
|
|
446
|
+
color: var(--slidepager-counter-text);
|
|
447
|
+
font-family: var(--slidepager-counter-font-family);
|
|
448
|
+
font-size: var(--slidepager-counter-font-size);
|
|
449
|
+
font-weight: var(--slidepager-counter-font-weight);
|
|
450
|
+
line-height: var(--slidepager-counter-line-height);
|
|
451
|
+
letter-spacing: var(--slidepager-counter-letter-spacing);
|
|
452
|
+
font-variant-numeric: tabular-nums;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.slidepager-preload {
|
|
456
|
+
display: none;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* The ground closes the zoom, so only the controls themselves take a click. */
|
|
460
|
+
.slidepager-modal-bar {
|
|
461
|
+
position: absolute;
|
|
462
|
+
left: 50%;
|
|
463
|
+
bottom: var(--slidepager-bar-padding);
|
|
464
|
+
transform: translateX(-50%);
|
|
465
|
+
pointer-events: none;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
.slidepager-modal-bar .slidepager-control {
|
|
469
|
+
pointer-events: auto;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.slidepager-modal {
|
|
473
|
+
position: fixed;
|
|
474
|
+
inset: 0;
|
|
475
|
+
z-index: var(--z-modal);
|
|
476
|
+
box-sizing: border-box;
|
|
477
|
+
display: grid;
|
|
478
|
+
place-items: center;
|
|
479
|
+
padding: var(--slidepager-overlay-padding);
|
|
480
|
+
background: var(--slidepager-scrim-surface);
|
|
481
|
+
container-type: size;
|
|
482
|
+
opacity: 0;
|
|
483
|
+
transition: opacity var(--slidepager-overlay-duration) var(--slidepager-overlay-easing);
|
|
484
|
+
cursor: zoom-out;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.slidepager-modal.shown {
|
|
488
|
+
opacity: 1;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.slidepager-modal:focus {
|
|
492
|
+
outline: none;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.slidepager-modal.inline {
|
|
496
|
+
position: relative;
|
|
497
|
+
inset: auto;
|
|
498
|
+
z-index: auto;
|
|
499
|
+
width: 100%;
|
|
500
|
+
aspect-ratio: var(--slidepager-ratio, 16 / 9);
|
|
501
|
+
cursor: default;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
@media (prefers-reduced-motion: reduce) {
|
|
505
|
+
.slidepager-modal {
|
|
506
|
+
transition: none;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.slidepager-full {
|
|
511
|
+
display: block;
|
|
512
|
+
width: min(100cqw, 100cqh * var(--slidepager-ratio, 16 / 9));
|
|
513
|
+
aspect-ratio: var(--slidepager-ratio, 16 / 9);
|
|
514
|
+
object-fit: contain;
|
|
515
|
+
}
|
|
516
|
+
</style>
|