From 0d55473d13913362d05f6d89d967f13a0392b394 Mon Sep 17 00:00:00 2001 From: Waishnav Date: Mon, 11 Nov 2024 02:28:05 +0530 Subject: [PATCH 1/7] feat: tried implementing it using embla carousel --- packages/core/package.json | 2 + .../core/src/carousel/carousel-context.tsx | 33 +++++ packages/core/src/carousel/carousel-dots.tsx | 52 ++++++++ packages/core/src/carousel/carousel-item.tsx | 46 +++++++ packages/core/src/carousel/carousel-next.tsx | 41 +++++++ .../core/src/carousel/carousel-previous.tsx | 41 +++++++ packages/core/src/carousel/carousel-root.tsx | 116 ++++++++++++++++++ .../core/src/carousel/carousel-viewport.tsx | 29 +++++ packages/core/src/carousel/index.tsx | 76 ++++++++++++ packages/core/src/index.tsx | 3 + pnpm-lock.yaml | 101 ++++++++------- 11 files changed, 497 insertions(+), 43 deletions(-) create mode 100644 packages/core/src/carousel/carousel-context.tsx create mode 100644 packages/core/src/carousel/carousel-dots.tsx create mode 100644 packages/core/src/carousel/carousel-item.tsx create mode 100644 packages/core/src/carousel/carousel-next.tsx create mode 100644 packages/core/src/carousel/carousel-previous.tsx create mode 100644 packages/core/src/carousel/carousel-root.tsx create mode 100644 packages/core/src/carousel/carousel-viewport.tsx create mode 100644 packages/core/src/carousel/index.tsx diff --git a/packages/core/package.json b/packages/core/package.json index edc1870b..32b89cb6 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -76,6 +76,8 @@ "@kobalte/utils": "^0.9.1", "@solid-primitives/props": "^3.1.8", "@solid-primitives/resize-observer": "^2.0.26", + "embla-carousel": "^8.3.1", + "embla-carousel-solid": "^8.3.1", "solid-presence": "^0.1.8", "solid-prevent-scroll": "^0.1.4" }, diff --git a/packages/core/src/carousel/carousel-context.tsx b/packages/core/src/carousel/carousel-context.tsx new file mode 100644 index 00000000..6ac53ea4 --- /dev/null +++ b/packages/core/src/carousel/carousel-context.tsx @@ -0,0 +1,33 @@ +import { + type Accessor, + type JSX, + type Setter, + createContext, + useContext, +} from "solid-js"; +import { type EmblaCarouselType } from "embla-carousel"; + +export interface CarouselContextValue { + emblaApi: Accessor; + canScrollNext: Accessor; + canScrollPrev: Accessor; + scrollNext: () => void; + scrollPrev: () => void; + scrollTo: (index: number) => void; + selectedIndex: Accessor; + scrollSnaps: Accessor; +} + +export const CarouselContext = createContext(); + +export function useCarouselContext() { + const context = useContext(CarouselContext); + + if (context === undefined) { + throw new Error( + "[kobalte]: `useCarouselContext` must be used within a `Carousel` component" + ); + } + + return context; +} diff --git a/packages/core/src/carousel/carousel-dots.tsx b/packages/core/src/carousel/carousel-dots.tsx new file mode 100644 index 00000000..75dafb73 --- /dev/null +++ b/packages/core/src/carousel/carousel-dots.tsx @@ -0,0 +1,52 @@ +import { For, JSX } from "solid-js"; +import { type ValidComponent, splitProps } from "solid-js"; +import * as Button from "../button"; +import { type ElementOf, Polymorphic, type PolymorphicProps } from "../polymorphic"; +import { useCarouselContext } from "./carousel-context"; + +export interface CarouselDotsOptions { } + +export interface CarouselDotsCommonProps { + /** The component to render as a dot button */ + dotComponent?: (props: { index: number; isSelected: boolean }) => JSX.Element; +} + +export interface CarouselDotsRenderProps extends CarouselDotsCommonProps { + children?: JSX.Element; +} + +export type CarouselDotsProps = + CarouselDotsOptions & Partial>>; + +export function CarouselDots( + props: PolymorphicProps> +) { + const context = useCarouselContext(); + const [local, others] = splitProps(props as CarouselDotsProps, ["dotComponent"]); + + const DefaultDot = (props: { index: number; isSelected: boolean }) => ( + context.scrollTo(props.index)} + /> + ); + + const DotComponent = local.dotComponent || DefaultDot; + + return ( + + as="div" + {...others} + > + + {(_, index) => ( + + )} + + + ); +} diff --git a/packages/core/src/carousel/carousel-item.tsx b/packages/core/src/carousel/carousel-item.tsx new file mode 100644 index 00000000..8e7ec468 --- /dev/null +++ b/packages/core/src/carousel/carousel-item.tsx @@ -0,0 +1,46 @@ +import { type ValidComponent, splitProps, JSX } from "solid-js"; +import { type ElementOf, Polymorphic, type PolymorphicProps } from "../polymorphic"; +import { useCarouselContext } from "./carousel-context"; + +export interface CarouselItemOptions { } + +export interface CarouselItemCommonProps { + children: JSX.Element; +} + +export interface CarouselItemRenderProps extends CarouselItemCommonProps { + "data-active": "" | undefined; +} + +export type CarouselItemProps = + CarouselItemOptions & Partial>>; + +export function CarouselItem( + props: PolymorphicProps> +) { + const context = useCarouselContext(); + const [local, others] = splitProps(props, ["children"]) as [ + { children: JSX.Element }, + { ref?: HTMLElement } + ]; + + const isActive = () => { + const api = context.emblaApi(); + if (!api) return false; + const currentIndex = api.selectedScrollSnap(); + const slideNodes = api.slideNodes(); + const currentNode = slideNodes[currentIndex]; + return currentNode === others.ref; + }; + + return ( + + as="div" + //class="embla__slide" + data-active={isActive() ? "" : undefined} + {...others} + > + {local.children} + + ); +} diff --git a/packages/core/src/carousel/carousel-next.tsx b/packages/core/src/carousel/carousel-next.tsx new file mode 100644 index 00000000..783bb053 --- /dev/null +++ b/packages/core/src/carousel/carousel-next.tsx @@ -0,0 +1,41 @@ +import { composeEventHandlers } from "@kobalte/utils"; +import { type Component, type JSX, type ValidComponent, splitProps } from "solid-js"; +import * as Button from "../button"; +import { type ElementOf, type PolymorphicProps } from "../polymorphic"; +import { useCarouselContext } from "./carousel-context"; + +export interface CarouselNextOptions {} + +export interface CarouselNextCommonProps { + onClick: JSX.EventHandlerUnion; +} + +export interface CarouselNextRenderProps + extends CarouselNextCommonProps, + Button.ButtonRootRenderProps {} + +export type CarouselNextProps = + CarouselNextOptions & Partial>>; + +export function CarouselNext( + props: PolymorphicProps> +) { + const context = useCarouselContext(); + const [local, others] = splitProps(props as CarouselNextProps, ["onClick"]); + + const onClick: JSX.EventHandlerUnion = () => { + context.scrollNext(); + }; + + const isDisabled = () => !context.canScrollNext(); + + return ( + >> + disabled={isDisabled()} + aria-disabled={isDisabled() || undefined} + data-disabled={isDisabled() ? "" : undefined} + onClick={composeEventHandlers([local.onClick, onClick])} + {...others} + /> + ); +} diff --git a/packages/core/src/carousel/carousel-previous.tsx b/packages/core/src/carousel/carousel-previous.tsx new file mode 100644 index 00000000..0834407b --- /dev/null +++ b/packages/core/src/carousel/carousel-previous.tsx @@ -0,0 +1,41 @@ +import { composeEventHandlers } from "@kobalte/utils"; +import { type Component, type JSX, type ValidComponent, splitProps } from "solid-js"; +import * as Button from "../button"; +import { type ElementOf, type PolymorphicProps } from "../polymorphic"; +import { useCarouselContext } from "./carousel-context"; + +export interface CarouselPreviousOptions {} + +export interface CarouselPreviousCommonProps { + onClick: JSX.EventHandlerUnion; +} + +export interface CarouselPreviousRenderProps + extends CarouselPreviousCommonProps, + Button.ButtonRootRenderProps {} + +export type CarouselPreviousProps = + CarouselPreviousOptions & Partial>>; + +export function CarouselPrevious( + props: PolymorphicProps> +) { + const context = useCarouselContext(); + const [local, others] = splitProps(props as CarouselPreviousProps, ["onClick"]); + + const onClick: JSX.EventHandlerUnion = () => { + context.scrollPrev(); + }; + + const isDisabled = () => !context.canScrollPrev(); + + return ( + >> + disabled={isDisabled()} + aria-disabled={isDisabled() || undefined} + data-disabled={isDisabled() ? "" : undefined} + onClick={composeEventHandlers([local.onClick, onClick])} + {...others} + /> + ); +} diff --git a/packages/core/src/carousel/carousel-root.tsx b/packages/core/src/carousel/carousel-root.tsx new file mode 100644 index 00000000..46e10ee5 --- /dev/null +++ b/packages/core/src/carousel/carousel-root.tsx @@ -0,0 +1,116 @@ +import { mergeDefaultProps } from "@kobalte/utils"; +import { + type Component, + type JSX, + type ValidComponent, + createSignal, + createUniqueId, + onCleanup, + onMount, + splitProps, +} from "solid-js"; +import createEmblaCarousel from 'embla-carousel-solid'; +import type { EmblaOptionsType } from 'embla-carousel'; + +import { + type ElementOf, + Polymorphic, + type PolymorphicProps, +} from "../polymorphic"; +import { CarouselContext, type CarouselContextValue } from "./carousel-context"; + +export interface CarouselRootOptions { + /** The options passed to Embla Carousel. */ + options?: EmblaOptionsType; + + /** Event handler called when the selected slide changes. */ + onSelectedIndexChange?: (index: number) => void; + + /** Whether the carousel is disabled. */ + disabled?: boolean; +} + +export interface CarouselRootCommonProps { + id: string; + children: JSX.Element; +} + +export interface CarouselRootRenderProps extends CarouselRootCommonProps { + "data-disabled": "" | undefined; +} + +export type CarouselRootProps = + CarouselRootOptions & Partial>>; + +export function CarouselRoot( + props: PolymorphicProps> +) { + const defaultId = `carousel-${createUniqueId()}`; + + const mergedProps = mergeDefaultProps( + { + id: defaultId, + options: {}, + }, + props as CarouselRootProps + ); + + const [local, others] = splitProps(mergedProps, [ + "options", + "onSelectedIndexChange", + "disabled", + "children", + ]); + + const [emblaRef, emblaApi] = createEmblaCarousel(() => local.options); + const [canScrollNext, setCanScrollNext] = createSignal(false); + const [canScrollPrev, setCanScrollPrev] = createSignal(false); + const [selectedIndex, setSelectedIndex] = createSignal(0); + const [scrollSnaps, setScrollSnaps] = createSignal([]); + + const onSelect = () => { + if (!emblaApi()) return; + + setSelectedIndex(emblaApi()!.selectedScrollSnap()); + setCanScrollPrev(emblaApi()!.canScrollPrev()); + setCanScrollNext(emblaApi()!.canScrollNext()); + local.onSelectedIndexChange?.(emblaApi()!.selectedScrollSnap()); + }; + + onMount(() => { + if (!emblaApi()) return; + + setScrollSnaps(emblaApi()!.scrollSnapList()); + emblaApi()!.on("select", onSelect); + onSelect(); + }); + + onCleanup(() => { + if (!emblaApi()) return; + emblaApi()!.off("select", onSelect); + }); + + const context: CarouselContextValue = { + emblaApi, + canScrollNext, + canScrollPrev, + scrollNext: () => emblaApi()?.scrollNext(), + scrollPrev: () => emblaApi()?.scrollPrev(), + scrollTo: (index: number) => emblaApi()?.scrollTo(index), + selectedIndex, + scrollSnaps, + }; + + return ( + + + as="div" + ref={emblaRef} + data-disabled={local.disabled ? "" : undefined} + {...others} + > + {local.children} + + + ); +} diff --git a/packages/core/src/carousel/carousel-viewport.tsx b/packages/core/src/carousel/carousel-viewport.tsx new file mode 100644 index 00000000..71461d8e --- /dev/null +++ b/packages/core/src/carousel/carousel-viewport.tsx @@ -0,0 +1,29 @@ +import { type ValidComponent, splitProps, JSX } from "solid-js"; +import { type ElementOf, Polymorphic, type PolymorphicProps } from "../polymorphic"; + +export interface CarouselViewportOptions {} + +export interface CarouselViewportCommonProps { + children: JSX.Element; +} + +export interface CarouselViewportRenderProps extends CarouselViewportCommonProps {} + +export type CarouselViewportProps = + CarouselViewportOptions & Partial>>; + +export function CarouselViewport( + props: PolymorphicProps> +) { + const [local, others] = splitProps(props as CarouselViewportProps, ["children"]); + + return ( + + as="div" + //class="embla__viewport" + {...others} + > + {local.children} + + ); +} diff --git a/packages/core/src/carousel/index.tsx b/packages/core/src/carousel/index.tsx new file mode 100644 index 00000000..4fa422e9 --- /dev/null +++ b/packages/core/src/carousel/index.tsx @@ -0,0 +1,76 @@ +import { + CarouselDots as Dots, + type CarouselDotsOptions, + type CarouselDotsCommonProps, + type CarouselDotsRenderProps, + type CarouselDotsProps, +} from "./carousel-dots"; +import { + CarouselItem as Item, + type CarouselItemProps, + type CarouselItemOptions, + type CarouselItemCommonProps, + type CarouselItemRenderProps, +} from "./carousel-item"; +import { + CarouselNext as Next, + type CarouselNextProps, + type CarouselNextOptions, + type CarouselNextCommonProps, + type CarouselNextRenderProps, +} from "./carousel-next"; +import { + CarouselPrevious as Previous, + type CarouselPreviousProps, + type CarouselPreviousOptions, + type CarouselPreviousCommonProps, + type CarouselPreviousRenderProps, +} from "./carousel-previous"; +import { + CarouselRoot as Root, + type CarouselRootProps, + type CarouselRootOptions, + type CarouselRootCommonProps, + type CarouselRootRenderProps, +} from "./carousel-root"; +import { + CarouselViewport as Viewport, + type CarouselViewportProps, + type CarouselViewportOptions, + type CarouselViewportCommonProps, + type CarouselViewportRenderProps, +} from "./carousel-viewport"; +export type { + CarouselDotsOptions, + CarouselDotsCommonProps, + CarouselDotsRenderProps, + CarouselDotsProps, + CarouselItemOptions, + CarouselItemCommonProps, + CarouselItemRenderProps, + CarouselItemProps, + CarouselNextOptions, + CarouselNextCommonProps, + CarouselNextRenderProps, + CarouselNextProps, + CarouselPreviousOptions, + CarouselPreviousCommonProps, + CarouselPreviousRenderProps, + CarouselPreviousProps, + CarouselRootOptions, + CarouselRootCommonProps, + CarouselRootRenderProps, + CarouselRootProps, + CarouselViewportOptions, + CarouselViewportCommonProps, + CarouselViewportRenderProps, + CarouselViewportProps, +}; +export { Dots, Item, Next, Previous, Root, Viewport }; +export const Carousel = Object.assign(Root, { + Dots, + Item, + Next, + Previous, + Viewport, +}); diff --git a/packages/core/src/index.tsx b/packages/core/src/index.tsx index f6a5ae0b..7636e862 100644 --- a/packages/core/src/index.tsx +++ b/packages/core/src/index.tsx @@ -1,3 +1,5 @@ +import { Carousel } from "./carousel"; + // utils export * from "./color-mode"; export * from "./form-control"; @@ -45,6 +47,7 @@ export * as Toast from "./toast"; export * as ToggleButton from "./toggle-button"; export * as ToggleGroup from "./toggle-group"; export * as Tooltip from "./tooltip"; +export * as Carousel from "./carousel" // @ts-ignore console["w" + "arn"]( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index af49a389..83b648ea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,7 +37,7 @@ importers: version: 9.3.4 '@testing-library/jest-dom': specifier: 6.4.2 - version: 6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)) + version: 6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)) '@testing-library/user-event': specifier: 14.5.2 version: 14.5.2(@testing-library/dom@9.3.4) @@ -97,7 +97,7 @@ importers: version: 5.0.11(@types/node@20.5.4)(terser@5.31.0) vite-plugin-solid: specifier: 2.9.1 - version: 2.9.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(solid-js@1.8.15)(vite@5.0.11(@types/node@20.5.4)(terser@5.31.0)) + version: 2.9.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(solid-js@1.8.15)(vite@5.0.11(@types/node@20.5.4)(terser@5.31.0)) vitest: specifier: 1.3.1 version: 1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0) @@ -121,7 +121,7 @@ importers: version: 0.12.4(solid-js@1.8.15) '@solidjs/start': specifier: 0.6.1 - version: 0.6.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(rollup@4.18.0)(solid-js@1.8.15)(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0))(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)) + version: 0.6.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(rollup@4.18.0)(solid-js@1.8.15)(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0))(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)) '@tanstack/solid-virtual': specifier: 3.0.0-beta.6 version: 3.0.0-beta.6 @@ -139,7 +139,7 @@ importers: version: 5.23.0 vinxi: specifier: 0.3.9 - version: 0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0) + version: 0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0) devDependencies: '@kobalte/tailwindcss': specifier: 0.9.0 @@ -215,13 +215,19 @@ importers: version: 3.5.3 '@kobalte/utils': specifier: ^0.9.1 - version: 0.9.1(solid-js@1.8.15) + version: link:../utils '@solid-primitives/props': specifier: ^3.1.8 version: 3.1.11(solid-js@1.8.15) '@solid-primitives/resize-observer': specifier: ^2.0.26 version: 2.0.26(solid-js@1.8.15) + embla-carousel: + specifier: ^8.3.1 + version: 8.3.1 + embla-carousel-solid: + specifier: ^8.3.1 + version: 8.3.1(solid-js@1.8.15) solid-js: specifier: ^1.8.15 version: 1.8.15 @@ -1858,11 +1864,6 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@kobalte/utils@0.9.1': - resolution: {integrity: sha512-eeU60A3kprIiBDAfv9gUJX1tXGLuZiKMajUfSQURAF2pk4ZoMYiqIzmrMBvzcxP39xnYttgTyQEVLwiTZnrV4w==} - peerDependencies: - solid-js: ^1.8.8 - '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -3547,6 +3548,19 @@ packages: electron-to-chromium@1.4.788: resolution: {integrity: sha512-ubp5+Ev/VV8KuRoWnfP2QF2Bg+O2ZFdb49DiiNbz2VmgkIqrnyYaqIOqj8A6K/3p1xV0QcU5hBQ1+BmB6ot1OA==} + embla-carousel-reactive-utils@8.3.1: + resolution: {integrity: sha512-Js6rTTINNGnUGPu7l5kTcheoSbEnP5Ak2iX0G9uOoI8okTNLMzuWlEIpYFd1WP0Sq82FFcLkKM2oiO6jcElZ/Q==} + peerDependencies: + embla-carousel: 8.3.1 + + embla-carousel-solid@8.3.1: + resolution: {integrity: sha512-WHci2oGGVFNaZ/yGTJ3HSqPXj+soOlUq752ZvccimAxUTPMPrrI/1NP9qWqF92NuTJoltwbUOzssgFa7No0QXQ==} + peerDependencies: + solid-js: ^1.0.0 + + embla-carousel@8.3.1: + resolution: {integrity: sha512-DutFjtEO586XptDn4cwvBJwsR/8fMa4jUk5Jk2g+/elKgu8mdn0Z2sx33g4JskvbLc1/6P8Xg4QlfELGJFcP5A==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -8725,17 +8739,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - '@kobalte/utils@0.9.1(solid-js@1.8.15)': - dependencies: - '@solid-primitives/event-listener': 2.3.3(solid-js@1.8.15) - '@solid-primitives/keyed': 1.2.2(solid-js@1.8.15) - '@solid-primitives/map': 0.4.11(solid-js@1.8.15) - '@solid-primitives/media': 2.2.9(solid-js@1.8.15) - '@solid-primitives/props': 3.1.11(solid-js@1.8.15) - '@solid-primitives/refs': 1.0.8(solid-js@1.8.15) - '@solid-primitives/utils': 6.2.3(solid-js@1.8.15) - solid-js: 1.8.15 - '@manypkg/find-root@1.1.0': dependencies: '@babel/runtime': 7.24.6 @@ -9269,11 +9272,11 @@ snapshots: dependencies: solid-js: 1.8.15 - '@solidjs/start@0.6.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(rollup@4.18.0)(solid-js@1.8.15)(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0))(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0))': + '@solidjs/start@0.6.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(rollup@4.18.0)(solid-js@1.8.15)(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0))(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0))': dependencies: - '@vinxi/plugin-directives': 0.3.1(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0)) - '@vinxi/server-components': 0.3.3(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0)) - '@vinxi/server-functions': 0.3.2(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0)) + '@vinxi/plugin-directives': 0.3.1(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0)) + '@vinxi/server-components': 0.3.3(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0)) + '@vinxi/server-functions': 0.3.2(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0)) defu: 6.1.4 error-stack-parser: 2.1.4 html-to-image: 1.11.11 @@ -9284,7 +9287,7 @@ snapshots: source-map-js: 1.2.0 terracotta: 1.0.5(solid-js@1.8.15) vite-plugin-inspect: 0.7.42(rollup@4.18.0)(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)) - vite-plugin-solid: 2.9.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(solid-js@1.8.15)(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)) + vite-plugin-solid: 2.9.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(solid-js@1.8.15)(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)) transitivePeerDependencies: - '@nuxt/kit' - '@testing-library/jest-dom' @@ -9327,7 +9330,7 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0))': + '@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0))': dependencies: '@adobe/css-tools': 4.3.3 '@babel/runtime': 7.24.6 @@ -9526,14 +9529,14 @@ snapshots: - encoding - supports-color - '@vinxi/devtools@0.2.0(@babel/core@7.24.6)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(preact@10.22.0)(rollup@4.18.0)(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0))': + '@vinxi/devtools@0.2.0(@babel/core@7.24.6)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(preact@10.22.0)(rollup@4.18.0)(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0))': dependencies: '@preact/preset-vite': 2.8.2(@babel/core@7.24.6)(preact@10.22.0)(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)) '@solidjs/router': 0.8.4(solid-js@1.8.15) birpc: 0.2.17 solid-js: 1.8.15 vite-plugin-inspect: 0.7.42(rollup@4.18.0)(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)) - vite-plugin-solid: 2.9.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(solid-js@1.8.15)(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)) + vite-plugin-solid: 2.9.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(solid-js@1.8.15)(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)) ws: 8.17.0 transitivePeerDependencies: - '@babel/core' @@ -9568,7 +9571,7 @@ snapshots: transitivePeerDependencies: - uWebSockets.js - '@vinxi/plugin-directives@0.3.1(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0))': + '@vinxi/plugin-directives@0.3.1(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0))': dependencies: '@babel/parser': 7.24.6 acorn: 8.10.0 @@ -9579,7 +9582,7 @@ snapshots: magicast: 0.2.11 recast: 0.23.9 tslib: 2.6.2 - vinxi: 0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0) + vinxi: 0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0) '@vinxi/plugin-mdx@3.7.1(@mdx-js/mdx@3.0.0)': dependencies: @@ -9590,27 +9593,27 @@ snapshots: unified: 9.2.2 vfile: 5.3.7 - '@vinxi/server-components@0.3.3(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0))': + '@vinxi/server-components@0.3.3(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0))': dependencies: - '@vinxi/plugin-directives': 0.3.1(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0)) + '@vinxi/plugin-directives': 0.3.1(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0)) acorn: 8.10.0 acorn-loose: 8.4.0 acorn-typescript: 1.4.13(acorn@8.10.0) astring: 1.8.6 magicast: 0.2.11 recast: 0.23.9 - vinxi: 0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0) + vinxi: 0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0) - '@vinxi/server-functions@0.3.2(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0))': + '@vinxi/server-functions@0.3.2(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0))': dependencies: - '@vinxi/plugin-directives': 0.3.1(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0)) + '@vinxi/plugin-directives': 0.3.1(vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0)) acorn: 8.10.0 acorn-loose: 8.4.0 acorn-typescript: 1.4.13(acorn@8.10.0) astring: 1.8.6 magicast: 0.2.11 recast: 0.23.9 - vinxi: 0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0) + vinxi: 0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0) '@vitest/expect@1.3.1': dependencies: @@ -10607,6 +10610,18 @@ snapshots: electron-to-chromium@1.4.788: {} + embla-carousel-reactive-utils@8.3.1(embla-carousel@8.3.1): + dependencies: + embla-carousel: 8.3.1 + + embla-carousel-solid@8.3.1(solid-js@1.8.15): + dependencies: + embla-carousel: 8.3.1 + embla-carousel-reactive-utils: 8.3.1(embla-carousel@8.3.1) + solid-js: 1.8.15 + + embla-carousel@8.3.1: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -14518,7 +14533,7 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0): + vinxi@0.3.9(@opentelemetry/api@1.8.0)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(@types/node@20.5.4)(ioredis@5.4.1)(preact@10.22.0)(rollup@4.18.0)(terser@5.31.0): dependencies: '@babel/core': 7.24.6 '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6) @@ -14526,7 +14541,7 @@ snapshots: '@types/micromatch': 4.0.7 '@types/serve-static': 1.15.7 '@types/ws': 8.5.10 - '@vinxi/devtools': 0.2.0(@babel/core@7.24.6)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(preact@10.22.0)(rollup@4.18.0)(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)) + '@vinxi/devtools': 0.2.0(@babel/core@7.24.6)(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(preact@10.22.0)(rollup@4.18.0)(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)) '@vinxi/listhen': 1.5.6 boxen: 7.1.1 chokidar: 3.6.0 @@ -14627,7 +14642,7 @@ snapshots: - rollup - supports-color - vite-plugin-solid@2.9.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(solid-js@1.8.15)(vite@5.0.11(@types/node@20.5.4)(terser@5.31.0)): + vite-plugin-solid@2.9.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(solid-js@1.8.15)(vite@5.0.11(@types/node@20.5.4)(terser@5.31.0)): dependencies: '@babel/core': 7.24.6 '@types/babel__core': 7.20.5 @@ -14638,11 +14653,11 @@ snapshots: vite: 5.0.11(@types/node@20.5.4)(terser@5.31.0) vitefu: 0.2.5(vite@5.0.11(@types/node@20.5.4)(terser@5.31.0)) optionalDependencies: - '@testing-library/jest-dom': 6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)) + '@testing-library/jest-dom': 6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)) transitivePeerDependencies: - supports-color - vite-plugin-solid@2.9.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)))(solid-js@1.8.15)(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)): + vite-plugin-solid@2.9.1(@testing-library/jest-dom@6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)))(solid-js@1.8.15)(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)): dependencies: '@babel/core': 7.24.6 '@types/babel__core': 7.20.5 @@ -14653,7 +14668,7 @@ snapshots: vite: 5.1.4(@types/node@20.5.4)(terser@5.31.0) vitefu: 0.2.5(vite@5.1.4(@types/node@20.5.4)(terser@5.31.0)) optionalDependencies: - '@testing-library/jest-dom': 6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0(vitest@1.3.1))(jsdom@19.0.0)(terser@5.31.0)) + '@testing-library/jest-dom': 6.4.2(vitest@1.3.1(@types/node@20.5.4)(@vitest/ui@1.6.0)(jsdom@19.0.0)(terser@5.31.0)) transitivePeerDependencies: - supports-color From 8417a1b9ef790a45c1e653c1f0b61fbcee177922 Mon Sep 17 00:00:00 2001 From: Waishnav Date: Sat, 16 Nov 2024 17:41:07 +0530 Subject: [PATCH 2/7] fix: emblaAPI is not accsible to end user | instead it can be customize through options and plugins props to Root of Carousel --- packages/core/package.json | 1 - .../core/src/carousel/carousel-context.tsx | 24 ++- packages/core/src/carousel/carousel-dots.tsx | 52 ------ .../core/src/carousel/carousel-indicator.tsx | 52 ++++++ packages/core/src/carousel/carousel-item.tsx | 42 ++--- packages/core/src/carousel/carousel-next.tsx | 33 ++-- .../core/src/carousel/carousel-previous.tsx | 35 ++-- packages/core/src/carousel/carousel-root.tsx | 154 ++++++++++++------ .../core/src/carousel/carousel-viewport.tsx | 23 ++- packages/core/src/carousel/index.tsx | 96 ++++++----- packages/core/src/index.tsx | 2 - pnpm-lock.yaml | 3 - 12 files changed, 274 insertions(+), 243 deletions(-) delete mode 100644 packages/core/src/carousel/carousel-dots.tsx create mode 100644 packages/core/src/carousel/carousel-indicator.tsx diff --git a/packages/core/package.json b/packages/core/package.json index 32b89cb6..ed7cd736 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -76,7 +76,6 @@ "@kobalte/utils": "^0.9.1", "@solid-primitives/props": "^3.1.8", "@solid-primitives/resize-observer": "^2.0.26", - "embla-carousel": "^8.3.1", "embla-carousel-solid": "^8.3.1", "solid-presence": "^0.1.8", "solid-prevent-scroll": "^0.1.4" diff --git a/packages/core/src/carousel/carousel-context.tsx b/packages/core/src/carousel/carousel-context.tsx index 6ac53ea4..c21f99b8 100644 --- a/packages/core/src/carousel/carousel-context.tsx +++ b/packages/core/src/carousel/carousel-context.tsx @@ -1,21 +1,19 @@ -import { - type Accessor, - type JSX, - type Setter, - createContext, - useContext, -} from "solid-js"; -import { type EmblaCarouselType } from "embla-carousel"; +import { type Accessor, createContext, useContext } from "solid-js"; +import type { CreateEmblaCarouselType } from "embla-carousel-solid"; +import type { Orientation } from "@kobalte/utils"; + +export type CarouselApi = CreateEmblaCarouselType[1]; export interface CarouselContextValue { - emblaApi: Accessor; - canScrollNext: Accessor; + isDisabled: Accessor; + orientation: Accessor; canScrollPrev: Accessor; - scrollNext: () => void; + canScrollNext: Accessor; + selectedIndex: Accessor; + api: Accessor; scrollPrev: () => void; + scrollNext: () => void; scrollTo: (index: number) => void; - selectedIndex: Accessor; - scrollSnaps: Accessor; } export const CarouselContext = createContext(); diff --git a/packages/core/src/carousel/carousel-dots.tsx b/packages/core/src/carousel/carousel-dots.tsx deleted file mode 100644 index 75dafb73..00000000 --- a/packages/core/src/carousel/carousel-dots.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { For, JSX } from "solid-js"; -import { type ValidComponent, splitProps } from "solid-js"; -import * as Button from "../button"; -import { type ElementOf, Polymorphic, type PolymorphicProps } from "../polymorphic"; -import { useCarouselContext } from "./carousel-context"; - -export interface CarouselDotsOptions { } - -export interface CarouselDotsCommonProps { - /** The component to render as a dot button */ - dotComponent?: (props: { index: number; isSelected: boolean }) => JSX.Element; -} - -export interface CarouselDotsRenderProps extends CarouselDotsCommonProps { - children?: JSX.Element; -} - -export type CarouselDotsProps = - CarouselDotsOptions & Partial>>; - -export function CarouselDots( - props: PolymorphicProps> -) { - const context = useCarouselContext(); - const [local, others] = splitProps(props as CarouselDotsProps, ["dotComponent"]); - - const DefaultDot = (props: { index: number; isSelected: boolean }) => ( - context.scrollTo(props.index)} - /> - ); - - const DotComponent = local.dotComponent || DefaultDot; - - return ( - - as="div" - {...others} - > - - {(_, index) => ( - - )} - - - ); -} diff --git a/packages/core/src/carousel/carousel-indicator.tsx b/packages/core/src/carousel/carousel-indicator.tsx new file mode 100644 index 00000000..8ff83cae --- /dev/null +++ b/packages/core/src/carousel/carousel-indicator.tsx @@ -0,0 +1,52 @@ +import { type ValidComponent, splitProps } from "solid-js"; +import { type ElementOf, Polymorphic, type PolymorphicProps } from "../polymorphic"; +import { useCarouselContext } from "./carousel-context"; + +export interface CarouselIndicatorOptions { + /** The index this indicator represents and will navigate to when clicked. */ + index: number; +} + +export interface CarouselIndicatorCommonProps { + ref?: T | ((el: T) => void); +} + +export interface CarouselIndicatorRenderProps extends CarouselIndicatorCommonProps { + role: "tab"; + type: "button"; + "aria-label": string; + "aria-selected": boolean; + "data-orientation": string; + "data-selected": string | undefined; + onClick: () => void; +} + +export type CarouselIndicatorProps = + CarouselIndicatorOptions & Partial>>; + +/** + * A button that allows users to navigate directly to a specific slide. + */ +export function CarouselIndicator( + props: PolymorphicProps> +) { + const context = useCarouselContext(); + const [local, others] = splitProps(props as CarouselIndicatorProps, ["index", "ref"]); + + const isSelected = () => context.selectedIndex() === local.index; + + return ( + + as="button" + ref={local.ref} + role="tab" + type="button" + aria-label={`Slide ${local.index + 1}`} + aria-selected={isSelected()} + data-orientation={context.orientation()} + data-selected={isSelected() ? "" : undefined} + onClick={() => { context.scrollTo(local.index) }} + {...others} + /> + ); +} diff --git a/packages/core/src/carousel/carousel-item.tsx b/packages/core/src/carousel/carousel-item.tsx index 8e7ec468..3481f891 100644 --- a/packages/core/src/carousel/carousel-item.tsx +++ b/packages/core/src/carousel/carousel-item.tsx @@ -1,46 +1,46 @@ -import { type ValidComponent, splitProps, JSX } from "solid-js"; +import { type ValidComponent, splitProps } from "solid-js"; import { type ElementOf, Polymorphic, type PolymorphicProps } from "../polymorphic"; import { useCarouselContext } from "./carousel-context"; -export interface CarouselItemOptions { } +export interface CarouselItemOptions { + /** The index of this item in the carousel. */ + index: number; +} export interface CarouselItemCommonProps { - children: JSX.Element; + ref?: T | ((el: T) => void); } export interface CarouselItemRenderProps extends CarouselItemCommonProps { - "data-active": "" | undefined; + role: "group"; + "aria-roledescription": "slide"; + "data-orientation": string; + "data-selected": string | undefined; } export type CarouselItemProps = CarouselItemOptions & Partial>>; +/** + * An individual slide within the carousel. + */ export function CarouselItem( props: PolymorphicProps> ) { const context = useCarouselContext(); - const [local, others] = splitProps(props, ["children"]) as [ - { children: JSX.Element }, - { ref?: HTMLElement } - ]; + const [local, others] = splitProps(props as CarouselItemProps, ["index", "ref"]); - const isActive = () => { - const api = context.emblaApi(); - if (!api) return false; - const currentIndex = api.selectedScrollSnap(); - const slideNodes = api.slideNodes(); - const currentNode = slideNodes[currentIndex]; - return currentNode === others.ref; - }; + const isSelected = () => context.selectedIndex() === local.index; return ( as="div" - //class="embla__slide" - data-active={isActive() ? "" : undefined} + ref={local.ref} + role="group" + aria-roledescription="slide" + data-orientation={context.orientation()} + data-selected={isSelected() ? "" : undefined} {...others} - > - {local.children} - + /> ); } diff --git a/packages/core/src/carousel/carousel-next.tsx b/packages/core/src/carousel/carousel-next.tsx index 783bb053..0dc8ea5f 100644 --- a/packages/core/src/carousel/carousel-next.tsx +++ b/packages/core/src/carousel/carousel-next.tsx @@ -1,40 +1,33 @@ -import { composeEventHandlers } from "@kobalte/utils"; -import { type Component, type JSX, type ValidComponent, splitProps } from "solid-js"; -import * as Button from "../button"; +import { type ValidComponent, splitProps } from "solid-js"; import { type ElementOf, type PolymorphicProps } from "../polymorphic"; import { useCarouselContext } from "./carousel-context"; +import { Button } from "../button"; export interface CarouselNextOptions {} export interface CarouselNextCommonProps { - onClick: JSX.EventHandlerUnion; + ref?: T | ((el: T) => void); } -export interface CarouselNextRenderProps - extends CarouselNextCommonProps, - Button.ButtonRootRenderProps {} - export type CarouselNextProps = CarouselNextOptions & Partial>>; +/** + * Button that navigates to the next slide in the carousel. + */ export function CarouselNext( props: PolymorphicProps> ) { const context = useCarouselContext(); - const [local, others] = splitProps(props as CarouselNextProps, ["onClick"]); - - const onClick: JSX.EventHandlerUnion = () => { - context.scrollNext(); - }; - - const isDisabled = () => !context.canScrollNext(); + const [local, others] = splitProps(props as CarouselNextProps, ["ref"]); return ( - >> - disabled={isDisabled()} - aria-disabled={isDisabled() || undefined} - data-disabled={isDisabled() ? "" : undefined} - onClick={composeEventHandlers([local.onClick, onClick])} +