@excom/content-carousel 0.1.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/.rush/temp/chunked-rush-logs/content-carousel.apply-exports.chunks.jsonl +1 -0
- package/.rush/temp/chunked-rush-logs/content-carousel.build_docs.chunks.jsonl +1 -0
- package/.rush/temp/chunked-rush-logs/content-carousel.build_package-metas.chunks.jsonl +1 -0
- package/.rush/temp/operation/apply-exports/all.log +1 -0
- package/.rush/temp/operation/apply-exports/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/apply-exports/state.json +3 -0
- package/.rush/temp/operation/build_docs/all.log +1 -0
- package/.rush/temp/operation/build_docs/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/build_docs/state.json +3 -0
- package/.rush/temp/operation/build_package-metas/all.log +1 -0
- package/.rush/temp/operation/build_package-metas/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/build_package-metas/state.json +3 -0
- package/.rush/temp/shrinkwrap-deps.json +3 -0
- package/config/rig.json +5 -0
- package/content-carousel-slide.ts +19 -0
- package/content-carousel.ts +218 -0
- package/index.css +5 -0
- package/index.ts +24 -0
- package/package.json +43 -0
- package/rush-logs/content-carousel.apply-exports.cache.log +1 -0
- package/rush-logs/content-carousel.apply-exports.log +1 -0
- package/rush-logs/content-carousel.build_docs.cache.log +1 -0
- package/rush-logs/content-carousel.build_docs.log +1 -0
- package/rush-logs/content-carousel.build_package-metas.cache.log +1 -0
- package/rush-logs/content-carousel.build_package-metas.log +1 -0
- package/src/content-carousel.css +239 -0
- package/support/custom-elements.json +398 -0
- package/support/demos/fade.html +7 -0
- package/support/demos/manual.html +9 -0
- package/support/demos/simple.html +7 -0
- package/support/dist-docs/content-carousel-slide.md +20 -0
- package/support/dist-docs/content-carousel.md +184 -0
- package/support/docs/INTERNAL.md +4 -0
- package/support/docs/README.md +66 -0
- package/support/package-meta.json +287 -0
- package/support/tests/content-carousel.test.ts +534 -0
- package/support/tests/fade.view.test.ts +23 -0
- package/support/tests/manual.view.test.ts +34 -0
- package/support/tests/simple.view.test.ts +24 -0
- package/tsconfig.json +5 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"kind":"O","text":"Invoking: cd \"$RUSH_PROJECT_FOLDER\" && node ../heft-rig/scripts/apply-exports.mjs \n"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"kind":"O","text":"Invoking: node node_modules/@excom/heft-rig/scripts/build-docs.mjs \n"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"kind":"O","text":"Invoking: node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs \n"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Invoking: cd "$RUSH_PROJECT_FOLDER" && node ../heft-rig/scripts/apply-exports.mjs
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"kind":"O","text":"Invoking: cd \"$RUSH_PROJECT_FOLDER\" && node ../heft-rig/scripts/apply-exports.mjs \n"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Invoking: node node_modules/@excom/heft-rig/scripts/build-docs.mjs
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"kind":"O","text":"Invoking: node node_modules/@excom/heft-rig/scripts/build-docs.mjs \n"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Invoking: node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"kind":"O","text":"Invoking: node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs \n"}
|
package/config/rig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Neutron } from "@excom/neutron";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A single slide within `<content-carousel>`.
|
|
5
|
+
*
|
|
6
|
+
* @summary One rotating slide of a content-carousel.
|
|
7
|
+
*/
|
|
8
|
+
export const ContentCarouselSlide = Neutron({
|
|
9
|
+
tag: "content-carousel-slide",
|
|
10
|
+
props: {
|
|
11
|
+
/**
|
|
12
|
+
* @option
|
|
13
|
+
* @state
|
|
14
|
+
* Marks this as the currently shown slide. The parent
|
|
15
|
+
* `<content-carousel>` keeps exactly one slide active.
|
|
16
|
+
*/
|
|
17
|
+
isActive: Boolean,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import type { ContentCarouselSlide } from "./content-carousel-slide";
|
|
2
|
+
import { ConstructorType, Neutron, TEvent } from "@excom/neutron";
|
|
3
|
+
|
|
4
|
+
type T_HTMLContentCarouselSlideElement =
|
|
5
|
+
typeof ContentCarouselSlide.CustomElement;
|
|
6
|
+
|
|
7
|
+
export type ContentCarouselSlideChangedDetail = {
|
|
8
|
+
activeSlide: HTMLElement | null;
|
|
9
|
+
previousSlide: HTMLElement | null;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type ContentCarouselSlideChangedEvent = TEvent & {
|
|
13
|
+
type: "content-carousel-slide-changed";
|
|
14
|
+
detail: ContentCarouselSlideChangedDetail;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/** Position of a `<content-carousel>` among its own slides. */
|
|
18
|
+
export interface ContentCarouselProvision {
|
|
19
|
+
/** Index of the active slide; `-1` when there are no slides. */
|
|
20
|
+
index: number;
|
|
21
|
+
/** Number of own slides (a nested carousel's slides are not counted). */
|
|
22
|
+
count: number;
|
|
23
|
+
/** Direction of the most recent move; `null` until the first move. */
|
|
24
|
+
lastMove: "forward" | "back" | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Rotates a set of slides — swipe-free, command-driven, auto-play optional.
|
|
29
|
+
* Nav buttons are plain `<button command="--next" commandfor="…">`; fires a
|
|
30
|
+
* change event other elements can react to.
|
|
31
|
+
*
|
|
32
|
+
* `.provision` holds the position (`{ index, count, lastMove }`) so a
|
|
33
|
+
* progress readout can bind to it with `prop("provision")`.
|
|
34
|
+
*
|
|
35
|
+
* @summary Slide rotator — auto-play, manual nav, slide or fade transition.
|
|
36
|
+
*
|
|
37
|
+
* @descendant content-carousel-slide - Slides to rotate through. The first,
|
|
38
|
+
* or whichever has `is-active`, is shown initially.
|
|
39
|
+
*
|
|
40
|
+
* @command --back - Shows the previous slide (wraps to last). Stops
|
|
41
|
+
* auto-play.
|
|
42
|
+
* @command --next - Shows the next slide (wraps to first). Stops auto-play.
|
|
43
|
+
*
|
|
44
|
+
* @fires content-carousel-slide-changed - After any slide change, manual or
|
|
45
|
+
* auto.
|
|
46
|
+
* @type ContentCarouselSlideChangedEvent
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* <content-carousel auto-play="5">
|
|
50
|
+
* <content-carousel-slide is-active>One</content-carousel-slide>
|
|
51
|
+
* <content-carousel-slide>Two</content-carousel-slide>
|
|
52
|
+
* </content-carousel>
|
|
53
|
+
*/
|
|
54
|
+
export const ContentCarousel = Neutron({
|
|
55
|
+
tag: "content-carousel",
|
|
56
|
+
props: {
|
|
57
|
+
/**
|
|
58
|
+
* @option
|
|
59
|
+
* Seconds between automatic slide advances. Unset disables auto-play.
|
|
60
|
+
*/
|
|
61
|
+
autoPlay: Number,
|
|
62
|
+
/**
|
|
63
|
+
* @option
|
|
64
|
+
* Set when the element is being dragged. Used by CSS only to disable `transition`.
|
|
65
|
+
*/
|
|
66
|
+
isScrubbing: Boolean,
|
|
67
|
+
/**
|
|
68
|
+
* @option
|
|
69
|
+
* Transition used when the active slide changes.
|
|
70
|
+
* @values slide | fade
|
|
71
|
+
* @default slide
|
|
72
|
+
*/
|
|
73
|
+
slideAnimation: String,
|
|
74
|
+
/**
|
|
75
|
+
* @state
|
|
76
|
+
* Direction of the most recent slide change — drives the CSS
|
|
77
|
+
* animation direction.
|
|
78
|
+
* @values forward | back
|
|
79
|
+
*/
|
|
80
|
+
lastMove: String,
|
|
81
|
+
/**
|
|
82
|
+
* @option
|
|
83
|
+
* @state
|
|
84
|
+
* Set automatically after manual navigation, or when the element
|
|
85
|
+
* leaves the document (a DOM move keeps auto-play running), to pause
|
|
86
|
+
* auto-play. Set it directly to pause / resume auto-play
|
|
87
|
+
* programmatically.
|
|
88
|
+
*/
|
|
89
|
+
autoPlayStopped: Boolean,
|
|
90
|
+
/**
|
|
91
|
+
* @provision
|
|
92
|
+
* Position: `{ index, count, lastMove }` — the active slide's index
|
|
93
|
+
* among this carousel's own slides, how many there are, and the
|
|
94
|
+
* direction of the last move. Set on connect and after every slide
|
|
95
|
+
* change. Not reflected as an attribute.
|
|
96
|
+
* @type ContentCarouselProvision
|
|
97
|
+
*/
|
|
98
|
+
provision: Object as unknown as ConstructorType<ContentCarouselProvision>,
|
|
99
|
+
// private state
|
|
100
|
+
autoPlayIntervalId: Object as unknown as ConstructorType<
|
|
101
|
+
ReturnType<typeof setInterval>
|
|
102
|
+
>,
|
|
103
|
+
},
|
|
104
|
+
})
|
|
105
|
+
.defineMethods({
|
|
106
|
+
intervalCallback: () => ({ _move: [false, false] }),
|
|
107
|
+
/** Show the previous / next slide; a manual move stops auto-play. */
|
|
108
|
+
// `any`: `getActiveSlide` is declared in this same call (circular type)
|
|
109
|
+
_move: (element: any, isBack: boolean, isManual: boolean) => {
|
|
110
|
+
const { getActiveSlide, autoPlay } = element;
|
|
111
|
+
const activeSlide =
|
|
112
|
+
getActiveSlide() as T_HTMLContentCarouselSlideElement | null;
|
|
113
|
+
const nextSlide = findSlide(element, activeSlide, isBack);
|
|
114
|
+
nextSlide?.setAttribute?.("is-active", "");
|
|
115
|
+
activeSlide?.removeAttribute("is-active");
|
|
116
|
+
const lastMove = isBack ? "back" : "forward";
|
|
117
|
+
return {
|
|
118
|
+
lastMove,
|
|
119
|
+
...(isManual && autoPlay ? { autoPlayStopped: true } : {}),
|
|
120
|
+
provision: readProvision(element, lastMove),
|
|
121
|
+
emit: [
|
|
122
|
+
"content-carousel-slide-changed",
|
|
123
|
+
{ detail: { activeSlide: nextSlide, previousSlide: activeSlide } },
|
|
124
|
+
] as any,
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
getActiveSlide: (element) => {
|
|
128
|
+
const slides = getOwnSlides(element);
|
|
129
|
+
return {
|
|
130
|
+
// Explicit type: inference hits a circular type issue here
|
|
131
|
+
returns: (slides.find((slide) => slide.hasAttribute("is-active")) ||
|
|
132
|
+
slides[0] ||
|
|
133
|
+
null) as unknown as T_HTMLContentCarouselSlideElement | null,
|
|
134
|
+
};
|
|
135
|
+
},
|
|
136
|
+
/** The current `{ index, count, lastMove }`, read from the DOM. */
|
|
137
|
+
_readProvision: (element) => ({
|
|
138
|
+
returns: readProvision(element, element.lastMove),
|
|
139
|
+
}),
|
|
140
|
+
})
|
|
141
|
+
.onConnected(({ _readProvision }) => ({
|
|
142
|
+
provision: _readProvision() as ContentCarouselProvision,
|
|
143
|
+
}))
|
|
144
|
+
.onPropChanged(
|
|
145
|
+
"autoPlay",
|
|
146
|
+
(
|
|
147
|
+
{ autoPlay, autoPlayIntervalId, intervalCallback, autoPlayStopped },
|
|
148
|
+
previous
|
|
149
|
+
) => {
|
|
150
|
+
if (previous.autoPlay && autoPlayIntervalId) {
|
|
151
|
+
clearInterval(autoPlayIntervalId);
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
autoPlayIntervalId:
|
|
155
|
+
autoPlay && !autoPlayStopped
|
|
156
|
+
? setInterval(intervalCallback, autoPlay * 1000)
|
|
157
|
+
: null,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
)
|
|
161
|
+
.onDisconnected(
|
|
162
|
+
// A DOM move keeps the interval running; only a real removal stops auto-play
|
|
163
|
+
({ autoPlay, isMoving }) =>
|
|
164
|
+
!isMoving &&
|
|
165
|
+
autoPlay && {
|
|
166
|
+
autoPlayStopped: true,
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
.onPropSet("autoPlayStopped", ({ autoPlayIntervalId }) => {
|
|
170
|
+
if (autoPlayIntervalId || autoPlayIntervalId === 0) {
|
|
171
|
+
clearInterval(autoPlayIntervalId);
|
|
172
|
+
return {
|
|
173
|
+
autoPlayIntervalId: null,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
.onCommand("--back", () => ({ _move: [true, true] }))
|
|
178
|
+
.onCommand("--next", () => ({ _move: [false, true] }));
|
|
179
|
+
|
|
180
|
+
/** A fresh provision object from the carousel's own slides. */
|
|
181
|
+
function readProvision(
|
|
182
|
+
element: HTMLElement,
|
|
183
|
+
lastMove: string | null | undefined
|
|
184
|
+
): ContentCarouselProvision {
|
|
185
|
+
const slides = getOwnSlides(element);
|
|
186
|
+
const active =
|
|
187
|
+
slides.find((slide) => slide.hasAttribute("is-active")) || slides[0];
|
|
188
|
+
return {
|
|
189
|
+
index: active ? slides.indexOf(active) : -1,
|
|
190
|
+
count: slides.length,
|
|
191
|
+
lastMove: lastMove === "forward" || lastMove === "back" ? lastMove : null,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Slides this carousel owns, in document order. A nested carousel keeps
|
|
197
|
+
* its own slides, excluded here the same way `<content-tabs>` scopes
|
|
198
|
+
* headers / bodies.
|
|
199
|
+
*/
|
|
200
|
+
function getOwnSlides(element: HTMLElement): HTMLElement[] {
|
|
201
|
+
return [...element.querySelectorAll("content-carousel-slide")].filter(
|
|
202
|
+
(slide) => slide.closest("content-carousel") === element
|
|
203
|
+
) as HTMLElement[];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function findSlide(
|
|
207
|
+
element: HTMLElement,
|
|
208
|
+
currentSlide: T_HTMLContentCarouselSlideElement | null,
|
|
209
|
+
isPrevious: boolean
|
|
210
|
+
): T_HTMLContentCarouselSlideElement | null {
|
|
211
|
+
if (!currentSlide) return null;
|
|
212
|
+
const slides = getOwnSlides(element);
|
|
213
|
+
const currentIndex = slides.indexOf(currentSlide as unknown as HTMLElement);
|
|
214
|
+
if (currentIndex < 0) return null;
|
|
215
|
+
const nextIndex =
|
|
216
|
+
(currentIndex + (isPrevious ? -1 : 1) + slides.length) % slides.length;
|
|
217
|
+
return slides[nextIndex] as unknown as T_HTMLContentCarouselSlideElement;
|
|
218
|
+
}
|
package/index.css
ADDED
package/index.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ContentCarousel } from "./content-carousel";
|
|
2
|
+
import { ContentCarouselSlide } from "./content-carousel-slide";
|
|
3
|
+
|
|
4
|
+
ContentCarousel.define();
|
|
5
|
+
ContentCarouselSlide.define();
|
|
6
|
+
|
|
7
|
+
export { ContentCarousel, ContentCarouselSlide };
|
|
8
|
+
|
|
9
|
+
type T_HTMLContentCarouselElement = typeof ContentCarousel.CustomElement;
|
|
10
|
+
type T_HTMLContentCarouselSlideElement =
|
|
11
|
+
typeof ContentCarouselSlide.CustomElement;
|
|
12
|
+
declare global {
|
|
13
|
+
interface HTMLContentCarouselElement extends T_HTMLContentCarouselElement {}
|
|
14
|
+
interface HTMLContentCarouselSlideElement extends T_HTMLContentCarouselSlideElement {}
|
|
15
|
+
interface Window {
|
|
16
|
+
HTMLContentCarouselElement: HTMLContentCarouselElement;
|
|
17
|
+
HTMLContentCarouselSlideElement: HTMLContentCarouselSlideElement;
|
|
18
|
+
}
|
|
19
|
+
interface HTMLElementTagNameMap {
|
|
20
|
+
"content-carousel": HTMLContentCarouselElement;
|
|
21
|
+
"content-carousel-slide": HTMLContentCarouselSlideElement;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export type { HTMLContentCarouselElement, HTMLContentCarouselSlideElement };
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@excom/content-carousel",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "<content-carousel> custom element",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=24.13.0"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@excom/kit-utils": "^0.1.0",
|
|
12
|
+
"@excom/neutron": "^0.1.0"
|
|
13
|
+
},
|
|
14
|
+
"peerDependencies": {},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@excom/heft-rig": "^0.1.0"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"url": "excom-dev/nucleus",
|
|
20
|
+
"directory": "packages/content-carousel"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/excom-dev/nucleus/tree/main/packages/content-carousel/support/docs/README.md",
|
|
23
|
+
"bugs": "https://github.com/excom-dev/nucleus/issues",
|
|
24
|
+
"keywords": [
|
|
25
|
+
"content-carousel",
|
|
26
|
+
"neutron",
|
|
27
|
+
"custom-elements"
|
|
28
|
+
],
|
|
29
|
+
"excom": {
|
|
30
|
+
"packageType": "kit-element"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "node node_modules/@excom/heft-rig/scripts/vite-build.mjs",
|
|
34
|
+
"build:watch": "node node_modules/@excom/heft-rig/scripts/vite-build-watch.mjs",
|
|
35
|
+
"format": "node node_modules/@excom/heft-rig/scripts/format.mjs",
|
|
36
|
+
"test": "node node_modules/@excom/heft-rig/scripts/vitest.mjs",
|
|
37
|
+
"coverage": "node node_modules/@excom/heft-rig/scripts/coverage.mjs",
|
|
38
|
+
"dev": "node node_modules/@excom/heft-rig/scripts/vite-dev.mjs",
|
|
39
|
+
"preview": "node node_modules/@excom/heft-rig/scripts/vite-preview.mjs",
|
|
40
|
+
"build:package-metas": "node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs",
|
|
41
|
+
"build:docs": "node node_modules/@excom/heft-rig/scripts/build-docs.mjs"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Caching has been disabled for this project's "apply-exports" command.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Invoking: cd "$RUSH_PROJECT_FOLDER" && node ../heft-rig/scripts/apply-exports.mjs
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
This project does not define the caching behavior of the "build:docs" command, so caching has been disabled.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Invoking: node node_modules/@excom/heft-rig/scripts/build-docs.mjs
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
This project does not define the caching behavior of the "build:package-metas" command, so caching has been disabled.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Invoking: node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Styles for `<content-carousel>`.
|
|
3
|
+
* @element content-carousel
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* Aliases */
|
|
7
|
+
@custom-selector :--content-carousel content-carousel, .tag-content-carousel;
|
|
8
|
+
@custom-selector :--content-carousel--last-move [last-move], [data-last-move];
|
|
9
|
+
@custom-selector :--content-carousel--last-move-forward [last-move="forward"], [data-last-move="forward"];
|
|
10
|
+
@custom-selector :--content-carousel--last-move-back [last-move="back"], [data-last-move="back"];
|
|
11
|
+
@custom-selector :--content-carousel--slide-animation [slide-animation], [data-slide-animation];
|
|
12
|
+
@custom-selector :--content-carousel--slide-animation-slide [slide-animation="slide"], [data-slide-animation="slide"];
|
|
13
|
+
@custom-selector :--content-carousel--slide-animation-fade [slide-animation="fade"], [data-slide-animation="fade"];
|
|
14
|
+
@custom-selector :--content-carousel--slide-animation-track [slide-animation="track"], [data-slide-animation="track"];
|
|
15
|
+
@custom-selector :--content-carousel--is-scrubbing [is-scrubbing], [data-scrubbing];
|
|
16
|
+
@custom-selector :--content-carousel-slide content-carousel-slide, .tag-content-carousel-slide;
|
|
17
|
+
@custom-selector :--content-carousel-slide--is-active [is-active], [aria-current];
|
|
18
|
+
|
|
19
|
+
@define-mixin module-content-carousel {
|
|
20
|
+
:root {
|
|
21
|
+
/**
|
|
22
|
+
* Length of the slide / fade transition.
|
|
23
|
+
* @cssproperty
|
|
24
|
+
* @syntax <time>
|
|
25
|
+
* @default 0.25s
|
|
26
|
+
*/
|
|
27
|
+
--content-carousel-slide-animation-duration: var(
|
|
28
|
+
--v-transition-duration-standard,
|
|
29
|
+
0.25s
|
|
30
|
+
);
|
|
31
|
+
/**
|
|
32
|
+
* Easing used for the fade transition.
|
|
33
|
+
* @cssproperty
|
|
34
|
+
* @syntax <easing-function>
|
|
35
|
+
* @default ease-out
|
|
36
|
+
*/
|
|
37
|
+
--content-carousel-transition-ease: var(--v-transition-ease-out, ease-out);
|
|
38
|
+
/**
|
|
39
|
+
* Min-width of the nav buttons.
|
|
40
|
+
* @cssproperty
|
|
41
|
+
* @syntax <length>
|
|
42
|
+
* @default 25px
|
|
43
|
+
*/
|
|
44
|
+
--content-carousel-button-size: 25px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
:--content-carousel {
|
|
48
|
+
/**
|
|
49
|
+
* `slide-animation="track"` only: how far the track is dragged, in slide
|
|
50
|
+
* widths — `1` shows the next slide, `-1` the previous. While
|
|
51
|
+
* `is-scrubbing` it follows a wrapping `<gesture-handler>`'s inherited
|
|
52
|
+
* `--gesture-progress` unless set explicitly — swipeable carousels.
|
|
53
|
+
* @cssproperty
|
|
54
|
+
* @syntax <number>
|
|
55
|
+
* @default 0
|
|
56
|
+
*/
|
|
57
|
+
--content-carousel-progress: 0;
|
|
58
|
+
display: block;
|
|
59
|
+
position: relative;
|
|
60
|
+
overflow: hidden;
|
|
61
|
+
width: 100%;
|
|
62
|
+
height: auto;
|
|
63
|
+
white-space: nowrap;
|
|
64
|
+
|
|
65
|
+
> [rel="prev"],
|
|
66
|
+
.tag-content-carousel-prev,
|
|
67
|
+
> [rel="next"],
|
|
68
|
+
.tag-content-carousel-next {
|
|
69
|
+
position: absolute;
|
|
70
|
+
top: calc(50% - calc(var(--content-carousel-button-size) / 2));
|
|
71
|
+
min-width: var(--content-carousel-button-size);
|
|
72
|
+
z-index: 3;
|
|
73
|
+
text-align: center;
|
|
74
|
+
cursor: pointer;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Positions a direct child with `rel="prev"` (or
|
|
79
|
+
* `.tag-content-carousel-prev`) as the "previous slide" nav control.
|
|
80
|
+
* @cssclass tag-content-carousel-prev
|
|
81
|
+
*/
|
|
82
|
+
> [rel="prev"],
|
|
83
|
+
.tag-content-carousel-prev {
|
|
84
|
+
left: 0;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Positions a direct child with `rel="next"` (or
|
|
88
|
+
* `.tag-content-carousel-next`) as the "next slide" nav control.
|
|
89
|
+
* @cssclass tag-content-carousel-next
|
|
90
|
+
*/
|
|
91
|
+
> [rel="next"],
|
|
92
|
+
.tag-content-carousel-next {
|
|
93
|
+
right: 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
:--content-carousel-slide {
|
|
97
|
+
position: absolute;
|
|
98
|
+
top: 0;
|
|
99
|
+
left: 0;
|
|
100
|
+
width: 100%;
|
|
101
|
+
height: auto;
|
|
102
|
+
display: block;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* slide / default */
|
|
106
|
+
&:not(:--content-carousel--slide-animation),
|
|
107
|
+
&:--content-carousel--slide-animation-slide {
|
|
108
|
+
:--content-carousel-slide {
|
|
109
|
+
animation-duration: var(--content-carousel-slide-animation-duration);
|
|
110
|
+
animation-fill-mode: forwards;
|
|
111
|
+
z-index: -1;
|
|
112
|
+
}
|
|
113
|
+
/* Initial state. No animation. */
|
|
114
|
+
&:not(:--content-carousel--last-move) :--content-carousel-slide {
|
|
115
|
+
&:--content-carousel-slide--is-active {
|
|
116
|
+
transform: translateX(0);
|
|
117
|
+
z-index: 2;
|
|
118
|
+
}
|
|
119
|
+
&:not(:--content-carousel-slide--is-active) {
|
|
120
|
+
opacity: 0;
|
|
121
|
+
z-index: 1;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
&:--content-carousel--last-move-forward :--content-carousel-slide {
|
|
125
|
+
&:--content-carousel-slide--is-active {
|
|
126
|
+
animation-name: right-to-center;
|
|
127
|
+
z-index: 2;
|
|
128
|
+
}
|
|
129
|
+
&:not(:--content-carousel-slide--is-active):has(
|
|
130
|
+
+ :--content-carousel-slide--is-active
|
|
131
|
+
),
|
|
132
|
+
&:first-of-type:--content-carousel-slide--is-active ~ :last-of-type {
|
|
133
|
+
animation-name: center-to-left;
|
|
134
|
+
z-index: 1;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
&:--content-carousel--last-move-back :--content-carousel-slide {
|
|
138
|
+
&:--content-carousel-slide--is-active {
|
|
139
|
+
animation-name: left-to-center;
|
|
140
|
+
z-index: 2;
|
|
141
|
+
}
|
|
142
|
+
&:--content-carousel-slide--is-active
|
|
143
|
+
+ :not(:--content-carousel-slide--is-active),
|
|
144
|
+
&:first-of-type:not(:--content-carousel-slide--is-active):has(
|
|
145
|
+
~ :last-of-type:--content-carousel-slide--is-active
|
|
146
|
+
) {
|
|
147
|
+
animation-name: center-to-right;
|
|
148
|
+
z-index: 1;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* fade */
|
|
154
|
+
&:--content-carousel--slide-animation-fade {
|
|
155
|
+
:--content-carousel-slide {
|
|
156
|
+
opacity: 0;
|
|
157
|
+
z-index: 1;
|
|
158
|
+
transition: opacity var(--content-carousel-transition-ease);
|
|
159
|
+
transition-duration: var(--content-carousel-slide-animation-duration);
|
|
160
|
+
&:--content-carousel-slide--is-active {
|
|
161
|
+
opacity: 1;
|
|
162
|
+
z-index: 2;
|
|
163
|
+
}
|
|
164
|
+
&:not(:--content-carousel-slide--is-active) {
|
|
165
|
+
opacity: 0;
|
|
166
|
+
z-index: 1;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* track: the active slide sits at 0, neighbours at ±100%, all shifted by
|
|
172
|
+
`--content-carousel-progress`. Transitions animate a slide change;
|
|
173
|
+
none while `is-scrubbing`, when a finger drives the offset. */
|
|
174
|
+
&:--content-carousel--slide-animation-track {
|
|
175
|
+
:--content-carousel-slide {
|
|
176
|
+
--content-carousel-slot: 1;
|
|
177
|
+
transform: translateX(
|
|
178
|
+
calc(
|
|
179
|
+
(var(--content-carousel-slot) - var(--content-carousel-progress)) *
|
|
180
|
+
100%
|
|
181
|
+
)
|
|
182
|
+
);
|
|
183
|
+
transition: transform var(--content-carousel-slide-animation-duration)
|
|
184
|
+
var(--content-carousel-transition-ease);
|
|
185
|
+
&:--content-carousel-slide--is-active {
|
|
186
|
+
--content-carousel-slot: 0;
|
|
187
|
+
z-index: 2;
|
|
188
|
+
}
|
|
189
|
+
&:has(~ :--content-carousel-slide--is-active) {
|
|
190
|
+
--content-carousel-slot: -1;
|
|
191
|
+
}
|
|
192
|
+
&:is(&:--content-carousel-slide--is-active + & + &),
|
|
193
|
+
&:has(+ & + &:--content-carousel-slide--is-active) {
|
|
194
|
+
/* hide slides that are two slides away */
|
|
195
|
+
display: none !important;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
&:--content-carousel--is-scrubbing {
|
|
199
|
+
--content-carousel-progress: var(--gesture-progress, 0);
|
|
200
|
+
:--content-carousel-slide {
|
|
201
|
+
transition: none;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
@keyframes right-to-center {
|
|
208
|
+
0% {
|
|
209
|
+
transform: translateX(100%);
|
|
210
|
+
}
|
|
211
|
+
100% {
|
|
212
|
+
transform: translateX(0);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
@keyframes center-to-left {
|
|
216
|
+
0% {
|
|
217
|
+
transform: translateX(0);
|
|
218
|
+
}
|
|
219
|
+
100% {
|
|
220
|
+
transform: translateX(-100%);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
@keyframes left-to-center {
|
|
224
|
+
0% {
|
|
225
|
+
transform: translateX(-100%);
|
|
226
|
+
}
|
|
227
|
+
100% {
|
|
228
|
+
transform: translateX(0);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
@keyframes center-to-right {
|
|
232
|
+
0% {
|
|
233
|
+
transform: translateX(0);
|
|
234
|
+
}
|
|
235
|
+
100% {
|
|
236
|
+
transform: translateX(100%);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|