├── .npmrc ├── .husky └── pre-commit ├── examples ├── tanstackstart-react-18 │ ├── .gitignore │ ├── src │ │ ├── global.d.ts │ │ ├── routes │ │ │ ├── index.tsx │ │ │ └── __root.tsx │ │ ├── client.tsx │ │ ├── router.ts │ │ ├── components │ │ │ ├── DevTools.tsx │ │ │ └── GlideExample.tsx │ │ ├── styles.css │ │ └── routeTree.gen.ts │ ├── tsconfig.json │ ├── vite.config.ts │ ├── CHANGELOG.md │ └── package.json ├── .DS_Store └── nextjs-react-19 │ ├── postcss.config.mjs │ ├── src │ ├── app │ │ ├── favicon.ico │ │ ├── page.tsx │ │ ├── layout.tsx │ │ └── globals.css │ └── components │ │ ├── Layout.tsx │ │ └── GlideExample.tsx │ ├── public │ ├── vercel.svg │ ├── window.svg │ ├── file.svg │ ├── globe.svg │ └── next.svg │ ├── next.config.ts │ ├── .gitignore │ ├── package.json │ ├── CHANGELOG.md │ ├── tsconfig.json │ └── README.md ├── src ├── setupTests.ts ├── index.tsx ├── utils │ ├── isReactChild.ts │ ├── usePrevious.ts │ ├── classnames.ts │ ├── useComposedRefs.ts │ ├── useCountdownTimer.ts │ └── useIntersectionObserver.ts ├── stories │ ├── style.css │ └── Glide.stories.tsx ├── types.ts ├── components │ ├── GlideItem.tsx │ ├── Glide.tsx │ └── Glide.test.tsx └── reactGlide.css ├── .DS_Store ├── glide.png ├── commitlint.config.js ├── .npmignore ├── pnpm-workspace.yaml ├── .gitignore ├── .storybook ├── preview.ts └── main.ts ├── .changeset ├── config.json └── README.md ├── .github ├── CODEOWNERS └── workflows │ ├── pull_request.yml │ ├── chromatic.yml │ └── release.yml ├── CONTRIBUTING.md ├── vitest.config.ts ├── tsconfig.json ├── biome.json ├── vite.config.mts ├── package.json ├── CHANGELOG.md └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | pnpm lint-staged 2 | -------------------------------------------------------------------------------- /examples/tanstackstart-react-18/.gitignore: -------------------------------------------------------------------------------- 1 | .tanstack -------------------------------------------------------------------------------- /src/setupTests.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | -------------------------------------------------------------------------------- /examples/tanstackstart-react-18/src/global.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*?url'; 2 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewangelle/react-glide/HEAD/.DS_Store -------------------------------------------------------------------------------- /glide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewangelle/react-glide/HEAD/glide.png -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] }; 2 | -------------------------------------------------------------------------------- /examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewangelle/react-glide/HEAD/examples/.DS_Store -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | .env 3 | tsconfig.json 4 | tslint.json 5 | glide.png 6 | node_modules 7 | README.md 8 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: ['@tailwindcss/postcss'], 3 | }; 4 | 5 | export default config; 6 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewangelle/react-glide/HEAD/examples/nextjs-react-19/src/app/favicon.ico -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | onlyBuiltDependencies: 2 | - '@biomejs/biome' 3 | - core-js 4 | - esbuild 5 | 6 | packages: 7 | - 'examples/**/*' 8 | - './' 9 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { GlideExample } from '@/components/GlideExample'; 2 | 3 | export default function Home() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | bin 4 | lib 5 | coverage 6 | .next 7 | ./ssr-testing/package-lock.json 8 | build-storybook.log 9 | .DS_Store 10 | app.config.timestamp* 11 | -------------------------------------------------------------------------------- /.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | export const parameters = { 2 | controls: { 3 | matchers: { 4 | color: /(background|color)$/i, 5 | date: /Date$/, 6 | }, 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import { Glide } from '~/components/Glide'; 2 | 3 | export { Glide }; 4 | export { Glide as default }; 5 | export * from '~/types'; 6 | export * from '~/reactGlide.css'; 7 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from 'next'; 2 | 3 | const nextConfig: NextConfig = { 4 | /* config options here */ 5 | }; 6 | 7 | export default nextConfig; 8 | -------------------------------------------------------------------------------- /src/utils/isReactChild.ts: -------------------------------------------------------------------------------- 1 | import type { ReactElement } from 'react'; 2 | 3 | export function isReactChild(child?: unknown): child is ReactElement { 4 | return Boolean(child && '$$typeof' in (child as object)); 5 | } 6 | -------------------------------------------------------------------------------- /examples/tanstackstart-react-18/src/routes/index.tsx: -------------------------------------------------------------------------------- 1 | import { createFileRoute } from '@tanstack/react-router'; 2 | import { GlideExample } from 'src/components/GlideExample'; 3 | 4 | export const Route = createFileRoute('/')({ 5 | component: GlideExample, 6 | }); 7 | -------------------------------------------------------------------------------- /src/stories/style.css: -------------------------------------------------------------------------------- 1 | @import "../reactGlide.css"; 2 | 3 | body { 4 | margin: 0; 5 | padding: 0; 6 | font-family: sans-serif; 7 | } 8 | 9 | .glide-storybook { 10 | height: 600px; 11 | width: 600px; 12 | 13 | iframe { 14 | border: none; 15 | padding: 3rem; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/utils/usePrevious.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react'; 2 | 3 | export function usePrevious(value: DataType): DataType { 4 | const ref = useRef(undefined); 5 | 6 | useEffect(() => { 7 | ref.current = value; 8 | }, [value]); 9 | 10 | return ref.current as DataType; 11 | } 12 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "master", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /examples/tanstackstart-react-18/src/client.tsx: -------------------------------------------------------------------------------- 1 | import { StartClient } from '@tanstack/react-start'; 2 | import { hydrateRoot } from 'react-dom/client'; 3 | import { createRouter } from 'src/router'; 4 | 5 | const router = createRouter(); 6 | 7 | hydrateRoot(document, ); 8 | 9 | export default router; 10 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This is a comment. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # These owners will be the default owners for everything in 5 | # the repo. Unless a later match takes precedence, 6 | # @global-owner1 and @global-owner2 will be requested for 7 | # review when someone opens a pull request. 8 | * @andrewangelle 9 | -------------------------------------------------------------------------------- /examples/tanstackstart-react-18/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react-jsx", 4 | "moduleResolution": "Bundler", 5 | "module": "ESNext", 6 | "target": "ES2022", 7 | "skipLibCheck": true, 8 | "strictNullChecks": true, 9 | "baseUrl": ".", 10 | "paths": { 11 | "~/*": ["src/*"] 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/tanstackstart-react-18/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { tanstackStart } from '@tanstack/react-start/plugin/vite'; 2 | import { defineConfig } from 'vite'; 3 | import tsConfigPaths from 'vite-tsconfig-paths'; 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | tsConfigPaths({ 8 | projects: ['./tsconfig.json'], 9 | }), 10 | tanstackStart(), 11 | ], 12 | }); 13 | -------------------------------------------------------------------------------- /src/utils/classnames.ts: -------------------------------------------------------------------------------- 1 | function isString(value: string | boolean): value is string { 2 | return Boolean(typeof value === 'string' && value?.trim()); 3 | } 4 | 5 | export function classnames(...argz: (string | boolean)[]) { 6 | let result = ''; 7 | 8 | for (const arg of argz) { 9 | if (isString(arg)) { 10 | result += ` ${arg.trim()}`; 11 | } 12 | } 13 | 14 | return result; 15 | } 16 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/tanstackstart-react-18/src/router.ts: -------------------------------------------------------------------------------- 1 | import { createRouter as createTanStackRouter } from '@tanstack/react-router'; 2 | import { routeTree } from 'src/routeTree.gen'; 3 | 4 | export function createRouter() { 5 | const router = createTanStackRouter({ 6 | routeTree, 7 | }); 8 | 9 | return router; 10 | } 11 | 12 | declare module '@tanstack/react-router' { 13 | interface Register { 14 | router: ReturnType; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.storybook/main.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], 3 | 4 | addons: [ 5 | '@storybook/addon-links', 6 | '@storybook/addon-essentials', 7 | '@storybook/addon-interactions', 8 | '@chromatic-com/storybook', 9 | ], 10 | 11 | framework: { 12 | name: '@storybook/react-vite', 13 | }, 14 | 15 | core: { 16 | builder: '@storybook/builder-vite', 17 | }, 18 | 19 | docs: {}, 20 | 21 | typescript: { 22 | reactDocgen: 'react-docgen-typescript', 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /examples/tanstackstart-react-18/src/components/DevTools.tsx: -------------------------------------------------------------------------------- 1 | import { Suspense, lazy } from 'react'; 2 | 3 | function createDevTools() { 4 | if (process.env.NODE_ENV === 'production') { 5 | return () => null; 6 | } 7 | 8 | return lazy(() => 9 | import('@tanstack/react-router-devtools').then((res) => ({ 10 | default: res.TanStackRouterDevtools, 11 | })), 12 | ); 13 | } 14 | 15 | const TanStackRouterDevtools = createDevTools(); 16 | 17 | export function DevTools() { 18 | return ( 19 | 20 | 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: PR Checks 2 | 3 | on: 4 | pull_request: 5 | branches: [master] 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-node@v4 13 | - name: Setup pnpm 14 | uses: pnpm/action-setup@v4 15 | with: 16 | version: 9.15.5 17 | 18 | - name: Install deps 19 | run: pnpm install 20 | 21 | - name: Run unit tests 22 | run: pnpm test:once 23 | 24 | - name: Run lint checks 25 | run: pnpm lint:check 26 | 27 | - name: Run production build 28 | run: pnpm build 29 | 30 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/src/components/Layout.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | import React, { type PropsWithChildren } from 'react'; 3 | 4 | type LayoutProps = { 5 | title?: string; 6 | }; 7 | const layoutStyle = { 8 | margin: 20, 9 | padding: 20, 10 | border: '1px solid #DDD', 11 | }; 12 | 13 | export function Layout({ children, title }: PropsWithChildren) { 14 | return ( 15 |
16 | 17 | {title} 18 | 19 | 20 | 21 | {children} 22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # env files (can opt-in for committing if needed) 34 | .env* 35 | 36 | # vercel 37 | .vercel 38 | 39 | # typescript 40 | *.tsbuildinfo 41 | next-env.d.ts 42 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ssr-testing-react-19", 3 | "version": "0.1.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev --turbopack", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "next": "15.2.3", 13 | "react": "^19.1.0", 14 | "react-dom": "^19.1.0", 15 | "react-glide": "workspace:*" 16 | }, 17 | "devDependencies": { 18 | "@tailwindcss/postcss": "^4.1.5", 19 | "@types/node": "^20.17.32", 20 | "@types/react": "^19.1.2", 21 | "@types/react-dom": "^19.1.3", 22 | "tailwindcss": "^4.1.5", 23 | "typescript": "^5.8.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/tanstackstart-react-18/src/styles.css: -------------------------------------------------------------------------------- 1 | @import "react-glide/lib/reactGlide.css"; 2 | 3 | :root { 4 | --react-glide-spinner-border: 5px solid #ccc; 5 | --react-glide-spinner-color: red; 6 | --react-glide-button-background: blue; 7 | --react-glide-button-color: red; 8 | --react-glide-dots-container-margin: 20px; 9 | --react-glide-dot-color: green; 10 | --react-glide-dot-selected-color: red; 11 | --react-glide-dot-gap: 12px; 12 | --react-glide-animation: fade 1.5s ease-in; 13 | } 14 | 15 | .glide--container { 16 | height: 600px; 17 | width: 600px; 18 | 19 | iframe { 20 | border: none; 21 | padding: 3rem; 22 | } 23 | } 24 | 25 | .svg-slide { 26 | height: 100%; 27 | width: 100%; 28 | } 29 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | ## Contributing Guide 3 | 4 | Install dependencies: 5 | 6 | ```sh 7 | $ pnpm install 8 | ``` 9 | 10 | Run storybook at http://localhost:6006: 11 | 12 | ```sh 13 | $ pnpm start 14 | # or 15 | $ pnpm dev 16 | ``` 17 | 18 | Run ssr test app at http://localhost:3000: 19 | 20 | ```sh 21 | $ pnpm run:example:react19 22 | # or 23 | $ pnpm run:example:react18 24 | ``` 25 | 26 | Run tests in watch mode: 27 | 28 | ```sh 29 | $ pnpm test 30 | ``` 31 | 32 | Execute a single run of tests: 33 | 34 | ```sh 35 | $ pnpm test:once 36 | ``` 37 | 38 | Run linter check: 39 | 40 | ```sh 41 | $ pnpm lint:check 42 | ``` 43 | 44 | Run linter auto fix: 45 | 46 | ```sh 47 | pnpm lint:fix 48 | ``` 49 | 50 | 51 | ## License 52 | MIT 53 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import tsConfigPaths from 'vite-tsconfig-paths'; 2 | import { coverageConfigDefaults, defineConfig } from 'vitest/config'; 3 | import type { Plugin } from 'vitest/config'; 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | tsConfigPaths({ 8 | projects: ['./tsconfig.json'], 9 | }) as Plugin, 10 | ], 11 | test: { 12 | globals: true, 13 | environment: 'jsdom', 14 | setupFiles: './src/setupTests.ts', 15 | coverage: { 16 | exclude: [ 17 | ...coverageConfigDefaults.exclude, 18 | '**/*.stories.tsx', 19 | '**/index.tsx', 20 | '**/types.ts', 21 | '**/utils.ts', 22 | ], 23 | include: ['src/**/*.{ts,tsx}'], 24 | }, 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # ssr-testing-react-19 2 | 3 | ## 0.1.1 4 | 5 | ### Patch Changes 6 | 7 | - Updated dependencies [622b415] 8 | - Updated dependencies [15cd663] 9 | - Updated dependencies [2839f1a] 10 | - Updated dependencies [1e7f9bd] 11 | - Updated dependencies [15584ab] 12 | - Updated dependencies [f4e749f] 13 | - Updated dependencies [3c53b43] 14 | - Updated dependencies [51b8140] 15 | - Updated dependencies [08b6e22] 16 | - Updated dependencies [6dca60b] 17 | - Updated dependencies [622b415] 18 | - Updated dependencies [21084e7] 19 | - Updated dependencies [0a019f0] 20 | - react-glide@5.0.0 21 | 22 | ## 0.1.1-next.0 23 | 24 | ### Patch Changes 25 | 26 | - Updated dependencies [2839f1a] 27 | - react-glide@5.0.0-next.10 28 | -------------------------------------------------------------------------------- /src/utils/useComposedRefs.ts: -------------------------------------------------------------------------------- 1 | import { useCallback } from 'react'; 2 | import type { Ref } from 'react'; 3 | 4 | export type PossibleRef = Ref | undefined; 5 | 6 | function setRef(ref: PossibleRef, value: T): void { 7 | if (typeof ref === 'function') { 8 | ref(value); 9 | } else if (ref !== null && ref !== undefined) { 10 | ref.current = value; 11 | } 12 | } 13 | 14 | export function composeRefs( 15 | ...refs: Array> 16 | ): (node: T) => void { 17 | return (node: T) => { 18 | for (const ref of refs) { 19 | setRef(ref, node); 20 | } 21 | }; 22 | } 23 | 24 | export function useComposedRefs(...refs: Array>): Ref { 25 | return useCallback(composeRefs(...refs), refs); 26 | } 27 | -------------------------------------------------------------------------------- /examples/tanstackstart-react-18/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # ssr-testing-react-18 2 | 3 | ## 1.0.1 4 | 5 | ### Patch Changes 6 | 7 | - Updated dependencies [622b415] 8 | - Updated dependencies [15cd663] 9 | - Updated dependencies [2839f1a] 10 | - Updated dependencies [1e7f9bd] 11 | - Updated dependencies [15584ab] 12 | - Updated dependencies [f4e749f] 13 | - Updated dependencies [3c53b43] 14 | - Updated dependencies [51b8140] 15 | - Updated dependencies [08b6e22] 16 | - Updated dependencies [6dca60b] 17 | - Updated dependencies [622b415] 18 | - Updated dependencies [21084e7] 19 | - Updated dependencies [0a019f0] 20 | - react-glide@5.0.0 21 | 22 | ## 1.0.1-next.0 23 | 24 | ### Patch Changes 25 | 26 | - Updated dependencies [2839f1a] 27 | - react-glide@5.0.0-next.10 28 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type { CSSProperties, JSX, Ref } from 'react'; 2 | export type PreloaderProps = { 3 | currentIndex: number; 4 | width: number; 5 | }; 6 | 7 | export type PreloaderState = { 8 | loading: boolean; 9 | done: boolean; 10 | loadCount: number; 11 | }; 12 | 13 | export type GlideState = { 14 | currentIndex: number; 15 | }; 16 | 17 | export type GlideProps = { 18 | autoPlay?: boolean; 19 | autoPlaySpeed?: number; 20 | dots?: boolean; 21 | infinite?: boolean; 22 | className?: string; 23 | children?: string | JSX.Element | JSX.Element[]; 24 | containerStyles?: CSSProperties; 25 | loading?: boolean; 26 | swipeable?: boolean; 27 | scrollBehavior?: ScrollBehavior; 28 | ref?: Ref | null; 29 | onSlideChange?: () => void; 30 | }; 31 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": [ 26 | "**/*.ts", 27 | "**/*.tsx", 28 | "next-env.d.ts", 29 | "nextjs-react-19/.next/types/**/*.ts", 30 | ".next/types/**/*.ts" 31 | ], 32 | "exclude": ["node_modules"] 33 | } 34 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noEmit": true, 4 | "rootDir": ".", 5 | "outDir": "lib", 6 | "module": "ESNext", 7 | "target": "ESNext", 8 | "lib": ["ESNext", "dom", "esnext.asynciterable"], 9 | "sourceMap": false, 10 | "allowJs": false, 11 | "jsx": "react-jsx", 12 | "moduleResolution": "node", 13 | "allowSyntheticDefaultImports": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noImplicitReturns": true, 16 | "noImplicitThis": true, 17 | "noImplicitAny": false, 18 | "strictNullChecks": true, 19 | "noUnusedLocals": true, 20 | "skipLibCheck": true, 21 | "types": ["vite/client", "vitest/globals", "@testing-library/jest-dom"], 22 | "baseUrl": ".", 23 | "paths": { 24 | "~/*": ["./src/*"] 25 | } 26 | }, 27 | "include": ["src"] 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/chromatic.yml: -------------------------------------------------------------------------------- 1 | name: "Publish to chromatic" 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | workflow_dispatch: 8 | 9 | jobs: 10 | chromatic: 11 | name: Run Chromatic 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | - uses: actions/setup-node@v4 19 | with: 20 | node-version: 20 21 | 22 | - name: Setup pnpm 23 | uses: pnpm/action-setup@v4 24 | with: 25 | version: 9.15.5 26 | 27 | - name: Install dependencies 28 | run: pnpm install 29 | 30 | - name: Run Chromatic 31 | uses: chromaui/action@latest 32 | with: 33 | projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} 34 | buildScriptName: "build:storybook" -------------------------------------------------------------------------------- /examples/nextjs-react-19/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next'; 2 | import { Geist, Geist_Mono } from 'next/font/google'; 3 | import './globals.css'; 4 | 5 | const geistSans = Geist({ 6 | variable: '--font-geist-sans', 7 | subsets: ['latin'], 8 | }); 9 | 10 | const geistMono = Geist_Mono({ 11 | variable: '--font-geist-mono', 12 | subsets: ['latin'], 13 | }); 14 | 15 | export const metadata: Metadata = { 16 | title: 'Create Next App', 17 | description: 'Generated by create next app', 18 | }; 19 | 20 | export default function RootLayout({ 21 | children, 22 | }: Readonly<{ 23 | children: React.ReactNode; 24 | }>) { 25 | return ( 26 | 27 | 30 | {children} 31 | 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", 3 | "vcs": { 4 | "enabled": false, 5 | "clientKind": "git", 6 | "useIgnoreFile": false 7 | }, 8 | "files": { 9 | "ignoreUnknown": false, 10 | "ignore": [ 11 | ".next", 12 | "lib", 13 | "coverage", 14 | "node_modules", 15 | "routeTree.gen.ts", 16 | "app.config.timestamp*" 17 | ] 18 | }, 19 | "formatter": { 20 | "enabled": true, 21 | "indentWidth": 2, 22 | "indentStyle": "space" 23 | }, 24 | "organizeImports": { 25 | "enabled": true 26 | }, 27 | "linter": { 28 | "enabled": true, 29 | "rules": { 30 | "recommended": true 31 | } 32 | }, 33 | "javascript": { 34 | "formatter": { 35 | "quoteStyle": "single", 36 | "indentWidth": 2, 37 | "indentStyle": "space" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | @import "~react-glide/lib/reactGlide.css"; 3 | 4 | :root { 5 | --background: #ffffff; 6 | --foreground: #171717; 7 | } 8 | 9 | @theme inline { 10 | --color-background: var(--background); 11 | --color-foreground: var(--foreground); 12 | --font-sans: var(--font-geist-sans); 13 | --font-mono: var(--font-geist-mono); 14 | } 15 | 16 | @media (prefers-color-scheme: dark) { 17 | :root { 18 | --background: #0a0a0a; 19 | --foreground: #ededed; 20 | } 21 | } 22 | 23 | body { 24 | background: var(--background); 25 | color: var(--foreground); 26 | font-family: Arial, Helvetica, sans-serif; 27 | } 28 | 29 | .glide--container { 30 | height: 600px; 31 | width: 600px; 32 | 33 | iframe { 34 | border: none; 35 | padding: 3rem; 36 | } 37 | } 38 | 39 | .svg-slide { 40 | height: 100%; 41 | width: 100%; 42 | } 43 | -------------------------------------------------------------------------------- /vite.config.mts: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react'; 2 | import { defineConfig } from 'vite'; 3 | import tsConfigPaths from 'vite-tsconfig-paths'; 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | react(), 8 | tsConfigPaths({ 9 | projects: ['./tsconfig.json'], 10 | }), 11 | ], 12 | build: { 13 | outDir: 'lib', 14 | minify: true, 15 | lib: { 16 | entry: './src/index.tsx', 17 | name: 'react-glide', 18 | fileName: (_format) => 'index.mjs', 19 | formats: ['es'], 20 | }, 21 | rollupOptions: { 22 | external: ['react', 'react/jsx-runtime'], 23 | output: { 24 | assetFileNames: (assetInfo) => { 25 | const oldName = 'react-glide.css'; 26 | const newName = 'reactGlide.css'; 27 | 28 | if (assetInfo.names.includes(oldName)) { 29 | return newName; 30 | } 31 | 32 | return assetInfo.names[0]; 33 | }, 34 | }, 35 | }, 36 | }, 37 | }); 38 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/tanstackstart-react-18/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ssr-testing-react-18", 3 | "version": "1.0.1", 4 | "private": true, 5 | "description": "", 6 | "keywords": [], 7 | "author": "andrewangelle@gmail.com", 8 | "license": "MIT", 9 | "main": "index.ts", 10 | "type": "module", 11 | "scripts": { 12 | "dev": "vite dev", 13 | "build": "vite build", 14 | "start": "node .output/server/index.mjs" 15 | }, 16 | "engines": { 17 | "node": ">=22.0.0" 18 | }, 19 | "dependencies": { 20 | "@tanstack/react-router": "^1.121.21", 21 | "@tanstack/react-start": "^1.121.23", 22 | "react": "^18.3.1", 23 | "react-dom": "^18.3.1", 24 | "react-glide": "workspace:*" 25 | }, 26 | "devDependencies": { 27 | "@tanstack/react-router-devtools": "^1.121.21", 28 | "@types/node": "^22.15.3", 29 | "@types/react": "^18.3.20", 30 | "@types/react-dom": "^18.3.7", 31 | "husky": "^9.1.7", 32 | "lint-staged": "^15.5.1", 33 | "typescript": "^5.8.3", 34 | "vite": "^6.3.5", 35 | "vite-tsconfig-paths": "^5.1.4" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | 10 | ## Prerelease Steps 11 | 12 | Add a normal set of changeset 13 | ```sh 14 | npx @changesets/cli 15 | ``` 16 | 17 | Enter prerelease mode 18 | ```sh 19 | npx changeset pre enter next 20 | ``` 21 | 22 | Version the prerelease with a tag 23 | ```sh 24 | npx changeset version 25 | ``` 26 | 27 | Publish the prerelease 28 | ```sh 29 | npx changeset publish 30 | ``` 31 | 32 | Push up the tags 33 | ```sh 34 | git push --follow-tags 35 | ``` 36 | 37 | Before PRing the next branch into main run... 38 | ```sh 39 | npx changeset pre exit 40 | ``` 41 | 42 | ```sh 43 | npx changeset version 44 | ``` 45 | 46 | Then commit a version commit and PR -------------------------------------------------------------------------------- /src/utils/useCountdownTimer.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useRef, useState } from 'react'; 2 | 3 | export type CountdownTimerOptions = { 4 | interval?: number; 5 | skip?: boolean; 6 | resetOnExpire?: boolean; 7 | onExpire: () => void; 8 | }; 9 | 10 | type UseCountdownTimer = { 11 | reset: () => void; 12 | }; 13 | 14 | export function useCountdownTimer({ 15 | interval = 2000, 16 | skip = false, 17 | resetOnExpire = true, 18 | onExpire, 19 | }: CountdownTimerOptions): UseCountdownTimer { 20 | const initialCount = interval / 1000; 21 | 22 | const [count, setCount] = useState(initialCount); 23 | const onExpireRef = useRef(onExpire); 24 | 25 | const reset = useCallback(() => { 26 | setCount(initialCount); 27 | }, [initialCount]); 28 | 29 | useEffect(() => { 30 | onExpireRef.current = onExpire; 31 | }); 32 | 33 | useEffect(() => { 34 | if (skip) { 35 | return; 36 | } 37 | 38 | const id = setInterval(() => { 39 | setCount((prev) => prev - 1); 40 | }, 1000); 41 | 42 | if (count <= 0) { 43 | onExpireRef.current(); 44 | resetOnExpire && setCount(initialCount); 45 | } 46 | 47 | return () => { 48 | clearInterval(id); 49 | }; 50 | }, [skip, count, initialCount, resetOnExpire]); 51 | 52 | return { 53 | reset, 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /examples/tanstackstart-react-18/src/routes/__root.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | HeadContent, 3 | Outlet, 4 | Scripts, 5 | createRootRoute, 6 | } from '@tanstack/react-router'; 7 | import type { ReactNode } from 'react'; 8 | import { DevTools } from 'src/components/DevTools'; 9 | import appStyles from '~/styles.css?url'; 10 | 11 | export const Route = createRootRoute({ 12 | head: () => ({ 13 | meta: [ 14 | { 15 | charSet: 'utf-8', 16 | }, 17 | { 18 | name: 'viewport', 19 | content: 'width=device-width, initial-scale=1', 20 | }, 21 | { 22 | title: 'React Glide Example', 23 | }, 24 | { 25 | rel: 'icon', 26 | link: '/favicon.ico', 27 | }, 28 | ], 29 | links: [ 30 | { 31 | rel: 'stylesheet', 32 | href: appStyles, 33 | }, 34 | ], 35 | }), 36 | component: Root, 37 | }); 38 | 39 | function Root() { 40 | return ( 41 | 42 | 43 | 44 | ); 45 | } 46 | 47 | function RootDocument({ children }: { children: ReactNode }) { 48 | return ( 49 | 50 | 51 | 52 | 53 | 54 | {children} 55 | 56 | 57 | 58 | 59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /examples/nextjs-react-19/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/tanstackstart-react-18/src/components/GlideExample.tsx: -------------------------------------------------------------------------------- 1 | import { Glide, type GlideProps } from 'react-glide'; 2 | 3 | const props: GlideProps = { 4 | autoPlay: false, 5 | autoPlaySpeed: 5000, 6 | onSlideChange: () => console.log('slide changed'), 7 | infinite: true, 8 | dots: true, 9 | swipeable: true, 10 | }; 11 | 12 | export function GlideExample() { 13 | return ( 14 | 15 | photo1 16 | photo2 17 | photo1 18 |
19 |