Skip to content

Commit de6c6db

Browse files
committed
Update Vite for solid playgrounds and add SSR
1 parent 3b48dd4 commit de6c6db

File tree

11 files changed

+219
-379
lines changed

11 files changed

+219
-379
lines changed

packages/embla-carousel-solid/src/components/useEmblaCarousel.ts

+27-29
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
import EmblaCarousel, {
2-
EmblaCarouselType,
3-
type EmblaOptionsType,
4-
type EmblaPluginType
5-
} from 'embla-carousel'
6-
import { areOptionsEqual, arePluginsEqual } from 'embla-carousel-reactive-utils'
71
import {
82
Accessor,
93
Setter,
104
createEffect,
115
createSignal,
12-
on,
136
onCleanup
147
} from 'solid-js'
8+
import EmblaCarousel, {
9+
EmblaCarouselType,
10+
type EmblaOptionsType,
11+
type EmblaPluginType
12+
} from 'embla-carousel'
13+
import { areOptionsEqual, arePluginsEqual } from 'embla-carousel-reactive-utils'
14+
import { optionsOrFallback, pluginsOrFallback } from './utils'
1515

1616
export type UseEmblaCarouselType = [
1717
Setter<HTMLElement | undefined>,
@@ -20,13 +20,13 @@ export type UseEmblaCarouselType = [
2020
]
2121

2222
function useEmblaCarousel(
23-
options?: Accessor<EmblaOptionsType>,
24-
plugins?: Accessor<EmblaPluginType[]>
23+
options?: Accessor<EmblaOptionsType | undefined>,
24+
plugins?: Accessor<EmblaPluginType[] | undefined>
2525
): UseEmblaCarouselType {
2626
EmblaCarousel.globalOptions = useEmblaCarousel.globalOptions
2727

28-
let storedOptions = options ? options() : {}
29-
let storedPlugins = plugins ? plugins() : []
28+
let storedOptions = optionsOrFallback(options)
29+
let storedPlugins = pluginsOrFallback(plugins)
3030

3131
const serverApi = EmblaCarousel(null, storedOptions, storedPlugins)
3232
const [clientApi, setClientApi] = createSignal<EmblaCarouselType>()
@@ -37,32 +37,30 @@ function useEmblaCarousel(
3737
if (api) api.reInit(storedOptions, storedPlugins)
3838
}
3939

40-
createEffect(
41-
on(rootNode, (rootNode) => {
42-
if (rootNode) {
43-
EmblaCarousel.globalOptions = useEmblaCarousel.globalOptions
44-
const newEmblaApi = EmblaCarousel(
45-
rootNode,
46-
storedOptions,
47-
storedPlugins
48-
)
49-
setClientApi(newEmblaApi)
50-
onCleanup(() => newEmblaApi.destroy())
51-
} else {
52-
setClientApi(undefined)
53-
}
54-
})
55-
)
40+
createEffect(() => {
41+
if (rootNode()) {
42+
EmblaCarousel.globalOptions = useEmblaCarousel.globalOptions
43+
const newEmblaApi = EmblaCarousel(
44+
rootNode(),
45+
storedOptions,
46+
storedPlugins
47+
)
48+
setClientApi(newEmblaApi)
49+
onCleanup(() => newEmblaApi.destroy())
50+
} else {
51+
setClientApi(undefined)
52+
}
53+
})
5654

5755
createEffect(() => {
58-
const newOptions = options ? options() : {}
56+
const newOptions = optionsOrFallback(options)
5957
if (areOptionsEqual(storedOptions, newOptions)) return
6058
storedOptions = newOptions
6159
reInit()
6260
})
6361

6462
createEffect(() => {
65-
const newPlugins = plugins ? plugins() : []
63+
const newPlugins = pluginsOrFallback(plugins)
6664
if (arePluginsEqual(storedPlugins, newPlugins)) return
6765
storedPlugins = newPlugins
6866
reInit()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Accessor } from 'solid-js'
2+
import { EmblaOptionsType } from 'embla-carousel/components/Options'
3+
import { EmblaPluginType } from 'embla-carousel/components/Plugins'
4+
5+
export function optionsOrFallback(
6+
options?: Accessor<EmblaOptionsType | undefined> | undefined
7+
): EmblaOptionsType {
8+
if (!options) return {}
9+
return options() || {}
10+
}
11+
12+
export function pluginsOrFallback(
13+
plugins?: Accessor<EmblaPluginType[] | undefined>
14+
): EmblaPluginType[] {
15+
if (!plugins) return []
16+
return plugins() || []
17+
}

playgrounds/embla-carousel-playground-react/src/Carousel/Carousel.tsx

+1-5
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,7 @@ export const EmblaCarousel = (props: PropType) => {
8181
<div className="embla">
8282
<div
8383
className="embla__viewport"
84-
ref={(node) => {
85-
if (node && refAttached) {
86-
emblaRef(node)
87-
}
88-
}}
84+
ref={refAttached ? emblaRef : undefined}
8985
>
9086
<div className="embla__container">
9187
{slides.map((index) => (

playgrounds/embla-carousel-playground-solid/package.json

+5-4
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@
55
"type": "module",
66
"scripts": {
77
"dev": "vite",
8+
"build": "tsc -b && vite build",
89
"preview": "vite preview",
910
"test": "echo \"Info: no tests specified\" && exit 0"
1011
},
1112
"dependencies": {
12-
"embla-carousel-autoplay": "8.5.2",
1313
"embla-carousel-solid": "8.5.2",
14-
"solid-js": "^1.8.0"
14+
"solid-js": "^1.9.3"
1515
},
1616
"devDependencies": {
17-
"vite": "^3.2.11",
18-
"vite-plugin-solid": "^2.8.0"
17+
"typescript": "~5.6.2",
18+
"vite": "^6.0.5",
19+
"vite-plugin-solid": "^2.11.0"
1920
}
2021
}

playgrounds/embla-carousel-playground-solid/src/Carousel/Carousel.tsx

+61-16
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
1-
import { Component, For, createEffect, createSignal } from 'solid-js'
1+
import { Component, For, Show, createEffect, createSignal } from 'solid-js'
22
import { EmblaCarouselType, EmblaOptionsType } from 'embla-carousel'
3-
import createEmblaCarousel from 'embla-carousel-solid'
3+
import useEmblaCarousel from 'embla-carousel-solid'
44
import { DotButton, NextButton, PrevButton } from './Buttons'
55

66
type PropType = {
77
slides: number[]
8+
isSsr: boolean
89
options?: EmblaOptionsType
910
}
1011

1112
export const EmblaCarousel: Component<PropType> = (props) => {
12-
const [emblaRef, emblaApi] = createEmblaCarousel(() => props.options)
13-
const [prevBtnEnabled, setPrevBtnEnabled] = createSignal(false)
14-
const [nextBtnEnabled, setNextBtnEnabled] = createSignal(false)
15-
const [selectedIndex, setSelectedIndex] = createSignal(0)
13+
const [refAttached, setRefAttached] = createSignal(false)
14+
const [emblaRef, emblaApi, emblaServerApi] = useEmblaCarousel(
15+
() => props.options
16+
)
17+
const [prevBtnEnabled, setPrevBtnEnabled] = createSignal(
18+
emblaServerApi.canScrollPrev()
19+
)
20+
const [nextBtnEnabled, setNextBtnEnabled] = createSignal(
21+
emblaServerApi.canScrollNext()
22+
)
23+
const [selectedIndex, setSelectedIndex] = createSignal(
24+
emblaServerApi.selectedSnap()
25+
)
1626
const [scrollSnaps, setScrollSnaps] = createSignal<number[]>([])
27+
const [showSsr, setShowSsr] = createSignal(props.isSsr && !emblaApi())
1728

1829
function scrollPrev(): void {
1930
emblaApi()?.scrollPrev()
@@ -46,20 +57,54 @@ export const EmblaCarousel: Component<PropType> = (props) => {
4657
api.on('reinit', onInit).on('reinit', onSelect).on('select', onSelect)
4758
})
4859

60+
setTimeout(
61+
() => {
62+
setRefAttached(true)
63+
setShowSsr(false)
64+
},
65+
props.isSsr ? 2000 : 0
66+
)
67+
4968
return (
5069
<>
70+
{showSsr() && (
71+
<style id="embla-ssr-styles">
72+
{emblaServerApi.ssrStyles('.embla__container', '.embla__slide')}
73+
</style>
74+
)}
75+
76+
<div class="playground__ssr-text">
77+
<strong>SSR:</strong> <span>{showSsr().toString()}</span>
78+
</div>
79+
5180
<div class="embla">
52-
<div class="embla__viewport" ref={emblaRef}>
53-
<div class="embla__container">
54-
<For each={props.slides}>
55-
{(slide) => (
56-
<div class="embla__slide">
57-
<div class="embla__slide__number">{slide + 1}</div>
58-
</div>
59-
)}
60-
</For>
81+
<Show when={!refAttached()}>
82+
<div class="embla__viewport">
83+
<div class="embla__container">
84+
<For each={props.slides}>
85+
{(slide) => (
86+
<div class="embla__slide">
87+
<div class="embla__slide__number">{slide + 1}</div>
88+
</div>
89+
)}
90+
</For>
91+
</div>
6192
</div>
62-
</div>
93+
</Show>
94+
95+
<Show when={refAttached()}>
96+
<div class="embla__viewport" ref={emblaRef}>
97+
<div class="embla__container">
98+
<For each={props.slides}>
99+
{(slide) => (
100+
<div class="embla__slide">
101+
<div class="embla__slide__number">{slide + 1}</div>
102+
</div>
103+
)}
104+
</For>
105+
</div>
106+
</div>
107+
</Show>
63108

64109
<div class="embla__controls">
65110
<div class="embla__buttons">

playgrounds/embla-carousel-playground-solid/src/main.css

+5
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,8 @@
1515
font-weight: 900;
1616
text-align: center;
1717
}
18+
19+
.playground__ssr-text {
20+
text-align: center;
21+
margin-bottom: 5rem;
22+
}

playgrounds/embla-carousel-playground-solid/src/main.tsx

+16-7
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,22 @@ import {
1818
import Carousel from './Carousel/Carousel'
1919
import './main.css'
2020

21+
const SSR_ACTIVE = true
22+
const SLIDE_SIZE = 50
23+
const SLIDES = arrayFromNumber(4)
24+
25+
const OPTIONS: EmblaOptionsType = {
26+
loop: true,
27+
direction: 'ltr',
28+
startSnap: 3,
29+
axis: 'x',
30+
ssr: SLIDES.map(() => SLIDE_SIZE)
31+
}
32+
2133
const injectBaseStyles = (): void => {
2234
const styleElement = document.createElement('style')
2335
const carouselStyles = examplesCarouselDefaultStyles(
24-
'100%',
36+
`${SLIDE_SIZE}%`,
2537
'1rem',
2638
'x',
2739
styledComponentsStylesToString(
@@ -33,28 +45,25 @@ const injectBaseStyles = (): void => {
3345
)
3446

3547
styleElement.innerHTML =
48+
SANDBOX_CSS +
3649
styledComponentsStylesToString(
3750
THEME_STYLES,
3851
RESET_STYLES,
3952
BASE_STYLES,
4053
FONT_STYLES
4154
) +
42-
carouselStyles +
43-
SANDBOX_CSS
55+
carouselStyles
4456

4557
document.head.appendChild(styleElement)
4658
}
4759

48-
const OPTIONS: EmblaOptionsType = {}
49-
const SLIDES = arrayFromNumber(5)
50-
5160
injectBaseStyles()
5261

5362
const App: Component = () => {
5463
return (
5564
<main class="playground">
5665
<h1 class="playground__h1">Playground - Solid</h1>
57-
<Carousel options={OPTIONS} slides={SLIDES} />
66+
<Carousel options={OPTIONS} slides={SLIDES} isSsr={SSR_ACTIVE} />
5867
</main>
5968
)
6069
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"compilerOptions": {
3+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4+
"target": "ES2020",
5+
"useDefineForClassFields": true,
6+
"module": "ESNext",
7+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
8+
"skipLibCheck": true,
9+
10+
/* Bundler mode */
11+
"moduleResolution": "bundler",
12+
"allowImportingTsExtensions": true,
13+
"isolatedModules": true,
14+
"moduleDetection": "force",
15+
"noEmit": true,
16+
"jsx": "preserve",
17+
"jsxImportSource": "solid-js",
18+
19+
/* Linting */
20+
"strict": true,
21+
"noUnusedLocals": true,
22+
"noUnusedParameters": true,
23+
"noFallthroughCasesInSwitch": true,
24+
"noUncheckedSideEffectImports": true,
25+
26+
/* Paths */
27+
"paths": {
28+
"utils/*": ["../../packages/embla-carousel-docs/src/utils/*"],
29+
"consts/*": ["../../packages/embla-carousel-docs/src/consts/*"],
30+
"hooks/*": ["../../packages/embla-carousel-docs/src/hooks/*"],
31+
"components/*": ["../../packages/embla-carousel-docs/src/components/*"],
32+
"assets/*": ["../../packages/embla-carousel-docs/src/assets/*"]
33+
}
34+
},
35+
"include": ["src"]
36+
}
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,7 @@
11
{
2-
"compilerOptions": {
3-
"target": "es5",
4-
"esModuleInterop": true,
5-
"jsx": "preserve",
6-
"jsxImportSource": "solid-js",
7-
"paths": {
8-
"utils/*": ["../../packages/embla-carousel-docs/src/utils/*"],
9-
"consts/*": ["../../packages/embla-carousel-docs/src/consts/*"],
10-
"hooks/*": ["../../packages/embla-carousel-docs/src/hooks/*"],
11-
"components/*": ["../../packages/embla-carousel-docs/src/components/*"],
12-
"assets/*": ["../../packages/embla-carousel-docs/src/assets/*"]
13-
}
14-
},
15-
"include": ["src"],
16-
"references": [{ "path": "./tsconfig.node.json" }]
2+
"files": [],
3+
"references": [
4+
{ "path": "./tsconfig.app.json" },
5+
{ "path": "./tsconfig.node.json" }
6+
]
177
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
{
22
"compilerOptions": {
3-
"composite": true,
3+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4+
"target": "ES2022",
5+
"lib": ["ES2023"],
46
"module": "ESNext",
5-
"moduleResolution": "Node",
6-
"allowSyntheticDefaultImports": true
7+
"skipLibCheck": true,
8+
9+
/* Bundler mode */
10+
"moduleResolution": "bundler",
11+
"allowImportingTsExtensions": true,
12+
"isolatedModules": true,
13+
"moduleDetection": "force",
14+
"noEmit": true,
15+
16+
/* Linting */
17+
"strict": true,
18+
"noUnusedLocals": true,
19+
"noUnusedParameters": true,
20+
"noFallthroughCasesInSwitch": true,
21+
"noUncheckedSideEffectImports": true
722
},
823
"include": ["vite.config.ts"]
924
}

0 commit comments

Comments
 (0)