@octanejs/embla-carousel 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) David Jerleke.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @octanejs/embla-carousel
2
+
3
+ Octane binding for `embla-carousel-react@8.6.0`. It keeps the familiar default
4
+ `useEmblaCarousel` API while reusing Embla's framework-neutral runtime.
5
+
6
+ ```tsrx
7
+ import useEmblaCarousel from '@octanejs/embla-carousel';
8
+
9
+ export function Carousel() @{
10
+ const [viewportRef, api] = useEmblaCarousel({ loop: true });
11
+
12
+ <section>
13
+ <div ref={viewportRef}>
14
+ <div>
15
+ <div>First</div>
16
+ <div>Second</div>
17
+ </div>
18
+ </div>
19
+ <button onClick={() => api?.scrollPrev()}>Previous</button>
20
+ <button onClick={() => api?.scrollNext()}>Next</button>
21
+ </section>
22
+ }
23
+ ```
24
+
25
+ Replace the React import:
26
+
27
+ ```diff
28
+ - import useEmblaCarousel from 'embla-carousel-react';
29
+ + import useEmblaCarousel from '@octanejs/embla-carousel';
30
+ ```
31
+
32
+ The call signature, tuple result, exported types, and `globalOptions` property
33
+ match upstream. The published package has no React runtime or type dependency.
34
+
35
+ Lifecycle and option updates run against the pinned React adapter as a live
36
+ differential oracle. Real layout and pointer physics are delegated unchanged to
37
+ `embla-carousel`. The required Chromium lane verifies nonzero layout, scrolling,
38
+ selection updates, and destroy cleanup against the real core.
package/UPSTREAM.md ADDED
@@ -0,0 +1,58 @@
1
+ # Upstream Embla Carousel React audit
2
+
3
+ This port targets the immutable `embla-carousel-react@8.6.0` release.
4
+
5
+ - Repository: `https://github.com/davidjerleke/embla-carousel`
6
+ - Tag commit: `0fe65834136f1aa35e4c1a4a477e5ccb4bb5ee54`
7
+ - npm integrity: `sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==`
8
+ - Runtime/core oracle: `embla-carousel@8.6.0`
9
+ - Reactive utility oracle: `embla-carousel-reactive-utils@8.6.0`
10
+ - React oracle: `react@19.2.7` / `react-dom@19.2.7` (exact; required differential lane)
11
+ - React types: `@types/react@19.2.17` (exact; declaration consumer matrix)
12
+ - Advertised compatibility: exactly the 8.6.0 React adapter surface
13
+
14
+ The MIT-licensed tag supplied the byte-exact files in `upstream/`. The npm
15
+ artifact supplied the declaration and bundle check; it contains no source or
16
+ tests. Vendored evidence is excluded from the published `files` list.
17
+
18
+ ## Export crosswalk
19
+
20
+ | Upstream root export | Octane disposition | Evidence |
21
+ | --- | --- | --- |
22
+ | `default` (`useEmblaCarousel`) | Ported with `octane` hooks | `tests/conformance/binding.test.ts` |
23
+ | `UseEmblaCarouselType` | Ported without semantic change | `typetests/public.test-d.ts` |
24
+ | `EmblaViewportRefType` | Ported without semantic change | `typetests/public.test-d.ts` |
25
+ | `./package.json` | Package metadata export | package pack check |
26
+
27
+ ## Source and test disposition
28
+
29
+ | Upstream artifact | Disposition |
30
+ | --- | --- |
31
+ | `embla-carousel-react/src/index.ts` | Mirrored by `src/index.ts` |
32
+ | `embla-carousel-react/src/components/useEmblaCarousel.ts` | Ported module-by-module; only the framework hook import and formatting differ |
33
+ | `embla-carousel-reactive-utils/src/components/utils.ts` | Reused unchanged from the published framework-neutral dependency |
34
+ | `embla-carousel-reactive-utils/src/index.ts` | Reused unchanged from the published framework-neutral dependency |
35
+ | `embla-carousel-reactive-utils/src/__tests__/utils.test.ts` | Upstream suite registered as the `embla-pristine-utils` parity lane (`embla-carousel-pristine-utils`) |
36
+ | React adapter tests | No test files exist at the pinned tag; `package.json`'s test script reports no tests |
37
+ | Upstream type tests | None exist at the pinned tag; pristine declaration consumption and adapted public types are checked locally |
38
+
39
+ ## Differences
40
+
41
+ There are no consumer-visible API divergences. Octane compiles the hook calls
42
+ to stable call-site slots and uses native callback refs; neither changes the
43
+ published tuple contract.
44
+
45
+ Real pointer physics and layout remain owned by the unchanged Embla core. The
46
+ adapter suite uses a controlled constructor boundary because jsdom has no
47
+ layout. An unpaired Octane browser harness under `tests/browser` opts into
48
+ `testExecution.group: heavy-browser` and runs in Chromium via the generic
49
+ heavy-browser discovery lane. It verifies nonzero layout, scrolling, selection
50
+ updates, and destroy cleanup. Browser behavior is not simulated with jsdom
51
+ geometry mocks.
52
+
53
+ Every port-authored runtime test and repo-authored type probe is classified in
54
+ `audit/test-classifications.json`. Unpaired conformance/browser/hydration/SSR
55
+ cases stay Octane-only and outside React-parity ownership. The required
56
+ pristine/adapted type probes are `repo-authored-type-oracle` evidence paired
57
+ with the type-parity lanes; the required differential lane is the React runtime
58
+ oracle and rejects React/ReactDOM version drift from the pins above.
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@octanejs/embla-carousel",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=22.22.2"
8
+ },
9
+ "description": "Embla Carousel bindings for Octane, API-compatible with embla-carousel-react 8.6.0.",
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/octanejs/octane.git",
16
+ "directory": "packages/embla-carousel"
17
+ },
18
+ "main": "src/index.ts",
19
+ "module": "src/index.ts",
20
+ "types": "src/index.ts",
21
+ "files": [
22
+ "src",
23
+ "README.md",
24
+ "UPSTREAM.md",
25
+ "status.json"
26
+ ],
27
+ "exports": {
28
+ ".": "./src/index.ts",
29
+ "./package.json": "./package.json"
30
+ },
31
+ "dependencies": {
32
+ "embla-carousel": "8.6.0",
33
+ "embla-carousel-reactive-utils": "8.6.0"
34
+ },
35
+ "peerDependencies": {
36
+ "octane": "0.1.35"
37
+ },
38
+ "devDependencies": {
39
+ "@types/react": "19.2.17",
40
+ "embla-carousel-react": "8.6.0",
41
+ "playwright": "^1.61.1",
42
+ "react": "19.2.7",
43
+ "react-dom": "19.2.7",
44
+ "vite": "^8.1.5",
45
+ "vitest": "^4.1.10",
46
+ "@octanejs/testing-library": "0.1.32",
47
+ "octane": "0.1.35"
48
+ },
49
+ "scripts": {
50
+ "test": "node audit/type-parity.mjs && vitest run --root ../.. --project embla-carousel --project embla-carousel-pristine-utils --project embla-carousel-differential --project embla-carousel-hydration --project embla-carousel-ssr --project embla-carousel-audit --project embla-carousel-browser",
51
+ "typecheck": "tsrx-tsc --noEmit -p tsconfig.json && tsc --noEmit -p typetests/pristine.tsconfig.json && tsrx-tsc --noEmit -p typetests/tsconfig.json"
52
+ }
53
+ }
@@ -0,0 +1,66 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'octane';
2
+ import { areOptionsEqual, arePluginsEqual, canUseDOM } from 'embla-carousel-reactive-utils';
3
+ import EmblaCarousel, {
4
+ type EmblaCarouselType,
5
+ type EmblaOptionsType,
6
+ type EmblaPluginType,
7
+ } from 'embla-carousel';
8
+
9
+ export type EmblaViewportRefType = <ViewportElement extends HTMLElement>(
10
+ instance: ViewportElement | null,
11
+ ) => void;
12
+
13
+ export type UseEmblaCarouselType = [EmblaViewportRefType, EmblaCarouselType | undefined];
14
+
15
+ function useEmblaCarousel(
16
+ options?: EmblaOptionsType,
17
+ plugins?: EmblaPluginType[],
18
+ ): UseEmblaCarouselType;
19
+ function useEmblaCarousel(
20
+ ...args: [options?: EmblaOptionsType, plugins?: EmblaPluginType[], slot?: symbol]
21
+ ): UseEmblaCarouselType {
22
+ const hasCompilerSlot = typeof args.at(-1) === 'symbol';
23
+ const options = (hasCompilerSlot && args.length === 1 ? undefined : args[0]) ?? {};
24
+ const plugins = (hasCompilerSlot && args.length === 2 ? undefined : args[1]) ?? [];
25
+ const storedOptions = useRef(options);
26
+ const storedPlugins = useRef(plugins);
27
+ const [emblaApi, setEmblaApi] = useState<EmblaCarouselType>();
28
+ const [viewport, setViewport] = useState<HTMLElement>();
29
+
30
+ const reInit = useCallback(() => {
31
+ if (emblaApi) emblaApi.reInit(storedOptions.current, storedPlugins.current);
32
+ }, [emblaApi]);
33
+
34
+ useEffect(() => {
35
+ if (areOptionsEqual(storedOptions.current, options)) return;
36
+ storedOptions.current = options;
37
+ reInit();
38
+ }, [options, reInit]);
39
+
40
+ useEffect(() => {
41
+ if (arePluginsEqual(storedPlugins.current, plugins)) return;
42
+ storedPlugins.current = plugins;
43
+ reInit();
44
+ }, [plugins, reInit]);
45
+
46
+ useEffect(() => {
47
+ if (canUseDOM() && viewport) {
48
+ EmblaCarousel.globalOptions = useEmblaCarousel.globalOptions;
49
+ const newEmblaApi = EmblaCarousel(viewport, storedOptions.current, storedPlugins.current);
50
+ setEmblaApi(newEmblaApi);
51
+ return () => newEmblaApi.destroy();
52
+ }
53
+
54
+ setEmblaApi(undefined);
55
+ }, [viewport, setEmblaApi]);
56
+
57
+ return [setViewport as EmblaViewportRefType, emblaApi];
58
+ }
59
+
60
+ declare namespace useEmblaCarousel {
61
+ let globalOptions: EmblaOptionsType | undefined;
62
+ }
63
+
64
+ useEmblaCarousel.globalOptions = undefined;
65
+
66
+ export default useEmblaCarousel;
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export {
2
+ type UseEmblaCarouselType,
3
+ type EmblaViewportRefType,
4
+ default,
5
+ } from './components/useEmblaCarousel';
package/status.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "upstream": {
3
+ "package": "embla-carousel-react",
4
+ "version": "8.6.0",
5
+ "core": "embla-carousel@8.6.0"
6
+ },
7
+ "surface": "Complete package-root adapter: default useEmblaCarousel hook, its viewport-ref and tuple types, and globalOptions; the framework-neutral Embla core and reactive equality utilities are reused unchanged.",
8
+ "divergences": [],
9
+ "ssr": "The hook constructs no carousel without DOM globals; client attachment initializes the core.",
10
+ "verified": "2026-08-02",
11
+ "notes": [
12
+ "The live React differential covers adapter lifecycle. A required Chromium lane verifies real layout, scrolling, selection updates, and destroy cleanup."
13
+ ]
14
+ }