Skip to content

Commit 40c06d1

Browse files
committed
Add Svelte playground and add SSR
1 parent de6c6db commit 40c06d1

25 files changed

+685
-53
lines changed

Diff for: .github/workflows/cd.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ jobs:
2525
run: yarn build
2626

2727
- name: NPM PKG Publish 🎉
28-
run: yarn workspaces foreach -t --exclude '{embla-carousel-monorepo,embla-carousel-docs,embla-carousel-playground-vanilla,embla-carousel-playground-react,embla-carousel-playground-solid,embla-carousel-playground-vue}' npm publish
28+
run: yarn workspaces foreach -t --exclude '{embla-carousel-monorepo,embla-carousel-docs,embla-carousel-playground-vanilla,embla-carousel-playground-react,embla-carousel-playground-solid,embla-carousel-playground-vue,embla-carousel-playground-svelte}' npm publish
2929
env:
3030
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Diff for: .vscode/extenstions.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"recommendations": [
33
"esbenp.prettier-vscode",
44
"unifiedjs.vscode-mdx",
5-
"Vue.volar"
5+
"Vue.volar",
6+
"svelte.svelte-vscode"
67
]
78
}

Diff for: .vscode/settings.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
{
2-
"prettier.configPath": ""
2+
"prettier.configPath": "",
3+
"editor.formatOnSave": true,
4+
"editor.defaultFormatter": "esbenp.prettier-vscode",
5+
"[svelte]": {
6+
"editor.defaultFormatter": "svelte.svelte-vscode"
7+
}
38
}

Diff for: package.json

+8-4
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,33 @@
2929
"playgrounds/embla-carousel-playground-vanilla",
3030
"playgrounds/embla-carousel-playground-react",
3131
"playgrounds/embla-carousel-playground-solid",
32-
"playgrounds/embla-carousel-playground-vue"
32+
"playgrounds/embla-carousel-playground-vue",
33+
"playgrounds/embla-carousel-playground-svelte"
3334
],
3435
"scripts": {
35-
"eslint:report": "yarn workspaces foreach -v --exclude \"{embla-carousel-monorepo,embla-carousel-playground-vanilla,embla-carousel-playground-react,embla-carousel-playground-solid,embla-carousel-playground-vue}\" run eslint:report",
36+
"eslint:report": "yarn workspaces foreach -v --exclude \"{embla-carousel-monorepo,embla-carousel-playground-vanilla,embla-carousel-playground-react,embla-carousel-playground-solid,embla-carousel-playground-vue,embla-carousel-playground-svelte}\" run eslint:report",
3637
"prettier:report": "prettier \"**/*.{js,jsx,tsx,ts,scss,json}\" --check",
3738
"lint": "npm-run-all prettier:report eslint:report",
3839
"format": "prettier \"**/*.{js,jsx,tsx,ts,scss,json}\" --write",
39-
"test": "yarn workspaces foreach -v --exclude \"{embla-carousel-monorepo,embla-carousel-playground-vanilla,embla-carousel-playground-react,embla-carousel-playground-solid,embla-carousel-playground-vue}\" run test",
40+
"test": "yarn workspaces foreach -v --exclude \"{embla-carousel-monorepo,embla-carousel-playground-vanilla,embla-carousel-playground-react,embla-carousel-playground-solid,embla-carousel-playground-vue,embla-carousel-playground-svelte}\" run test",
4041
"watch:package-vanilla": "yarn workspace embla-carousel run start",
4142
"watch:package-react": "yarn workspace embla-carousel-react run start",
4243
"watch:package-solid": "yarn workspace embla-carousel-solid run start",
4344
"watch:package-vue": "yarn workspace embla-carousel-vue run start",
45+
"watch:package-svelte": "yarn workspace embla-carousel-svelte run start",
4446
"watch:playground-vanilla": "yarn workspace embla-carousel-playground-vanilla run dev",
4547
"watch:playground-react": "yarn workspace embla-carousel-playground-react run dev",
4648
"watch:playground-solid": "yarn workspace embla-carousel-playground-solid run dev",
4749
"watch:playground-vue": "yarn workspace embla-carousel-playground-vue run dev",
50+
"watch:playground-svelte": "yarn workspace embla-carousel-playground-svelte run dev",
4851
"start": "yarn workspace embla-carousel-docs run start",
4952
"start:vanilla": "npm-run-all --parallel watch:package-vanilla watch:playground-vanilla",
5053
"start:react": "npm-run-all --parallel watch:package-vanilla watch:package-react watch:playground-react",
5154
"start:solid": "npm-run-all --parallel watch:package-vanilla watch:package-solid watch:playground-solid",
5255
"start:vue": "npm-run-all --parallel watch:package-vanilla watch:package-vue watch:playground-vue",
56+
"start:svelte": "npm-run-all --parallel watch:package-vanilla watch:package-svelte watch:playground-svelte",
5357
"build": "npm-run-all build:packages build:package-readmes format",
54-
"build:packages": "yarn workspaces foreach -vt --exclude \"{embla-carousel-monorepo,embla-carousel-playground-vanilla,embla-carousel-playground-react,embla-carousel-playground-solid,embla-carousel-playground-vue}\" run build",
58+
"build:packages": "yarn workspaces foreach -vt --exclude \"{embla-carousel-monorepo,embla-carousel-playground-vanilla,embla-carousel-playground-react,embla-carousel-playground-solid,embla-carousel-playground-vue,embla-carousel-playground-svelte}\" run build",
5559
"build:package-readmes": "npx ts-node --project scripts/tsconfig.node.json scripts/create-readmes/index.ts --templatePath=scripts/create-readmes/readme-template.md",
5660
"build:docs": "yarn workspace embla-carousel-docs run predeploy",
5761
"version:patch": "yarn workspaces foreach version patch && yarn version:push",

Diff for: playgrounds/embla-carousel-playground-react/eslint.config.js

-28
This file was deleted.
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Vite + Svelte + TS</title>
8+
</head>
9+
<body class="theme-dark">
10+
<div id="app"></div>
11+
<script type="module" src="/src/main.ts"></script>
12+
</body>
13+
</html>
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "embla-carousel-playground-svelte",
3+
"private": true,
4+
"version": "8.5.2",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "vite build",
9+
"preview": "vite preview",
10+
"test": "echo \"Info: no tests specified\" && exit 0",
11+
"check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"
12+
},
13+
"dependencies": {
14+
"embla-carousel-svelte": "8.5.2"
15+
},
16+
"devDependencies": {
17+
"@sveltejs/vite-plugin-svelte": "^5.0.3",
18+
"@tsconfig/svelte": "^5.0.4",
19+
"svelte": "^5.15.0",
20+
"svelte-check": "^4.1.1",
21+
"typescript": "~5.6.2",
22+
"vite": "^6.0.5"
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<script lang="ts">
2+
import type { EmblaOptionsType } from 'embla-carousel'
3+
import { arrayFromNumber } from 'utils/arrayFromNumber'
4+
import { styledComponentsStylesToString } from 'utils/styledComponentStylesToString'
5+
import { RESET_STYLES } from 'components/Layout/GlobalStyles/reset'
6+
import { BASE_STYLES } from 'components/Layout/GlobalStyles/base'
7+
import { FONT_STYLES } from 'components/Layout/GlobalStyles/font'
8+
import { SANDBOX_CSS } from 'components/Sandbox/sandboxStyles'
9+
import { THEME_STYLES } from 'consts/themes'
10+
import {
11+
ARROWS_STYLES,
12+
CONTROLS_STYLES,
13+
DOTS_STYLES,
14+
SLIDE_NUMBER_STYLES,
15+
examplesCarouselDefaultStyles
16+
} from 'components/Examples/examplesCarouselStyles'
17+
import Carousel from './Carousel/Carousel.svelte'
18+
import './main.css'
19+
20+
const SSR_ACTIVE = true
21+
const SLIDE_SIZE = 50
22+
const SLIDES = arrayFromNumber(4)
23+
24+
const OPTIONS: EmblaOptionsType = {
25+
loop: true,
26+
direction: 'ltr',
27+
startSnap: 3,
28+
axis: 'x',
29+
ssr: SLIDES.map(() => SLIDE_SIZE)
30+
}
31+
32+
const injectBaseStyles = (): void => {
33+
const styleElement = document.createElement('style')
34+
const carouselStyles = examplesCarouselDefaultStyles(
35+
`${SLIDE_SIZE}%`,
36+
'1rem',
37+
'x',
38+
styledComponentsStylesToString(
39+
CONTROLS_STYLES,
40+
SLIDE_NUMBER_STYLES,
41+
ARROWS_STYLES,
42+
DOTS_STYLES
43+
)
44+
)
45+
46+
styleElement.innerHTML =
47+
SANDBOX_CSS +
48+
styledComponentsStylesToString(
49+
THEME_STYLES,
50+
RESET_STYLES,
51+
BASE_STYLES,
52+
FONT_STYLES
53+
) +
54+
carouselStyles
55+
56+
document.head.appendChild(styleElement)
57+
}
58+
59+
injectBaseStyles()
60+
</script>
61+
62+
<main class="playground">
63+
<h1 class="playground__h1">Playground - Svelte</h1>
64+
<Carousel options={OPTIONS} slides={SLIDES} isSsr={SSR_ACTIVE} />
65+
</main>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<script lang="ts">
2+
import type { EmblaCarouselType, EmblaOptionsType } from 'embla-carousel'
3+
import useEmblaCarousel from 'embla-carousel-svelte'
4+
import DotButton from './DotButton.svelte'
5+
import PrevButton from './PrevButton.svelte'
6+
import NextButton from './NextButton.svelte'
7+
8+
const { options, slides, isSsr } = $props<{
9+
options?: EmblaOptionsType
10+
slides: number[]
11+
isSsr: boolean
12+
}>()
13+
14+
const emblaServerApi = useEmblaCarousel({ options })
15+
let emblaApi: EmblaCarouselType | null = $state(null)
16+
17+
let actionAttached = $state(false)
18+
let prevBtnEnabled = $state(emblaServerApi.canScrollPrev())
19+
let nextBtnEnabled = $state(emblaServerApi.canScrollNext())
20+
let scrollSnaps = $state<number[]>([])
21+
let selectedIndex = $state(emblaServerApi.selectedSnap())
22+
let showSsr = $derived(isSsr && !emblaApi)
23+
24+
const ssrStyles = `<style>${emblaServerApi.ssrStyles(
25+
'.embla__container',
26+
'.embla__slide'
27+
)}</style>`
28+
29+
function onInit(emblaApi: EmblaCarouselType): void {
30+
scrollSnaps = emblaApi.snapList()
31+
}
32+
33+
function onEmblaInit(event: CustomEvent<EmblaCarouselType>): void {
34+
emblaApi = event.detail
35+
36+
onInit(emblaApi)
37+
onSelect(emblaApi)
38+
emblaApi.on('reinit', onInit).on('reinit', onSelect).on('select', onSelect)
39+
}
40+
41+
function onSelect(emblaApi: EmblaCarouselType): void {
42+
prevBtnEnabled = emblaApi.canScrollPrev()
43+
nextBtnEnabled = emblaApi.canScrollNext()
44+
selectedIndex = emblaApi.selectedSnap()
45+
}
46+
47+
function scrollPrev(): void {
48+
emblaApi?.scrollPrev()
49+
}
50+
51+
function scrollNext(): void {
52+
emblaApi?.scrollNext()
53+
}
54+
55+
function scrollTo(index: number): void {
56+
emblaApi?.scrollToSnap(index)
57+
}
58+
59+
setTimeout(
60+
() => {
61+
actionAttached = true
62+
},
63+
isSsr ? 2000 : 0
64+
)
65+
</script>
66+
67+
{#if showSsr}
68+
<div id="embla-ssr-styles">
69+
{@html ssrStyles}
70+
</div>
71+
{/if}
72+
73+
<div class="playground__ssr-text">
74+
<strong>SSR:</strong> <span>{showSsr.toString()}</span>
75+
</div>
76+
77+
<div class="embla">
78+
{#if actionAttached}
79+
<div
80+
class="embla__viewport"
81+
use:useEmblaCarousel={{ options }}
82+
onemblainit={onEmblaInit}
83+
>
84+
<div class="embla__container">
85+
{#each slides as index}
86+
<div class="embla__slide">
87+
<div class="embla__slide__number">{index + 1}</div>
88+
</div>
89+
{/each}
90+
</div>
91+
</div>
92+
{:else}
93+
<div class="embla__viewport">
94+
<div class="embla__container">
95+
{#each slides as index}
96+
<div class="embla__slide">
97+
<div class="embla__slide__number">{index + 1}</div>
98+
</div>
99+
{/each}
100+
</div>
101+
</div>
102+
{/if}
103+
104+
<div class="embla__controls">
105+
<div class="embla__buttons">
106+
<PrevButton enabled={prevBtnEnabled} onClick={scrollPrev} />
107+
<NextButton enabled={nextBtnEnabled} onClick={scrollNext} />
108+
</div>
109+
110+
<div class="embla__dots">
111+
{#each scrollSnaps as _, index}
112+
<DotButton
113+
selected={index === selectedIndex}
114+
onClick={() => scrollTo(index)}
115+
/>
116+
{/each}
117+
</div>
118+
</div>
119+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<script lang="ts">
2+
const { selected, onClick } = $props<{
3+
selected: boolean
4+
onClick: () => void
5+
}>()
6+
</script>
7+
8+
<button
9+
class="embla__dot {selected ? 'embla__dot--selected' : ''}"
10+
type="button"
11+
onclick={onClick}
12+
aria-label="Go to slide"
13+
>
14+
</button>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script lang="ts">
2+
const { enabled, onClick } = $props<{
3+
enabled: boolean
4+
onClick: () => void
5+
}>()
6+
</script>
7+
8+
<button
9+
class="embla__button embla__button--next"
10+
type="button"
11+
onclick={onClick}
12+
disabled={!enabled}
13+
aria-label="Go to slide"
14+
>
15+
<svg
16+
class="embla__button__svg"
17+
viewBox="0 0 238.003 238.003"
18+
fill="currentColor"
19+
>
20+
<path
21+
d="M181.776 107.719L78.705 4.648c-6.198-6.198-16.273-6.198-22.47 0s-6.198 16.273 0 22.47l91.883 91.883-91.883 91.883c-6.198 6.198-6.198 16.273 0 22.47s16.273 6.198 22.47 0l103.071-103.039a15.741 15.741 0 0 0 4.64-11.283c0-4.13-1.526-8.199-4.64-11.313z"
22+
/>
23+
</svg>
24+
</button>

0 commit comments

Comments
 (0)