@cdx-ui/components 0.0.1-beta.138 → 0.0.1-beta.139
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/lib/commonjs/components/Carousel/context.js +13 -0
- package/lib/commonjs/components/Carousel/context.js.map +1 -0
- package/lib/commonjs/components/Carousel/index.js +12 -7
- package/lib/commonjs/components/Carousel/index.js.map +1 -1
- package/lib/commonjs/components/Carousel/navButton.js +119 -0
- package/lib/commonjs/components/Carousel/navButton.js.map +1 -0
- package/lib/commonjs/components/Carousel/styles.js +24 -1
- package/lib/commonjs/components/Carousel/styles.js.map +1 -1
- package/lib/commonjs/components/Carousel/useCarouselActiveIndex.js +52 -0
- package/lib/commonjs/components/Carousel/useCarouselActiveIndex.js.map +1 -0
- package/lib/commonjs/components/IconButton/index.js +4 -2
- package/lib/commonjs/components/IconButton/index.js.map +1 -1
- package/lib/module/components/Carousel/context.js +7 -0
- package/lib/module/components/Carousel/context.js.map +1 -0
- package/lib/module/components/Carousel/index.js +11 -6
- package/lib/module/components/Carousel/index.js.map +1 -1
- package/lib/module/components/Carousel/navButton.js +114 -0
- package/lib/module/components/Carousel/navButton.js.map +1 -0
- package/lib/module/components/Carousel/styles.js +23 -0
- package/lib/module/components/Carousel/styles.js.map +1 -1
- package/lib/module/components/Carousel/useCarouselActiveIndex.js +48 -0
- package/lib/module/components/Carousel/useCarouselActiveIndex.js.map +1 -0
- package/lib/module/components/IconButton/index.js +4 -2
- package/lib/module/components/IconButton/index.js.map +1 -1
- package/lib/typescript/components/Carousel/context.d.ts +15 -0
- package/lib/typescript/components/Carousel/context.d.ts.map +1 -0
- package/lib/typescript/components/Carousel/index.d.ts +5 -2
- package/lib/typescript/components/Carousel/index.d.ts.map +1 -1
- package/lib/typescript/components/Carousel/navButton.d.ts +40 -0
- package/lib/typescript/components/Carousel/navButton.d.ts.map +1 -0
- package/lib/typescript/components/Carousel/styles.d.ts +8 -0
- package/lib/typescript/components/Carousel/styles.d.ts.map +1 -1
- package/lib/typescript/components/Carousel/useCarouselActiveIndex.d.ts +12 -0
- package/lib/typescript/components/Carousel/useCarouselActiveIndex.d.ts.map +1 -0
- package/lib/typescript/components/IconButton/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/components/Carousel/context.ts +15 -0
- package/src/components/Carousel/index.tsx +18 -13
- package/src/components/Carousel/navButton.tsx +160 -0
- package/src/components/Carousel/styles.ts +27 -0
- package/src/components/Carousel/useCarouselActiveIndex.ts +54 -0
- package/src/components/IconButton/index.tsx +5 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["cva","carouselPaginationContainerClassName","carouselPaginationDotVariants","variants","active","true","false","defaultVariants"],"sourceRoot":"../../../../src","sources":["components/Carousel/styles.ts"],"mappings":";;AAAA,SAASA,GAAG,QAA2B,0BAA0B;;AAEjE;AACA,OAAO,MAAMC,oCAAoC,GAAG,YAAY;AAEhE,OAAO,MAAMC,6BAA6B,GAAGF,GAAG,CAAC,cAAc,EAAE;EAC/DG,QAAQ,EAAE;IACRC,MAAM,EAAE;MACNC,IAAI,EAAE,2BAA2B;MACjCC,KAAK,EAAE;IACT;EACF,CAAC;EACDC,eAAe,EAAE;IACfH,MAAM,EAAE;EACV;AACF,CAAC,CAAC","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["cva","carouselPaginationContainerClassName","carouselPaginationDotVariants","variants","active","true","false","defaultVariants","carouselNavButtonRootVariants","disabled","carouselNavButtonIconVariants"],"sourceRoot":"../../../../src","sources":["components/Carousel/styles.ts"],"mappings":";;AAAA,SAASA,GAAG,QAA2B,0BAA0B;;AAEjE;AACA,OAAO,MAAMC,oCAAoC,GAAG,YAAY;AAEhE,OAAO,MAAMC,6BAA6B,GAAGF,GAAG,CAAC,cAAc,EAAE;EAC/DG,QAAQ,EAAE;IACRC,MAAM,EAAE;MACNC,IAAI,EAAE,2BAA2B;MACjCC,KAAK,EAAE;IACT;EACF,CAAC;EACDC,eAAe,EAAE;IACfH,MAAM,EAAE;EACV;AACF,CAAC,CAAC;AAIF;AACA,OAAO,MAAMI,6BAA6B,GAAGR,GAAG,CAAC,EAAE,EAAE;EACnDG,QAAQ,EAAE;IACRM,QAAQ,EAAE;MACRJ,IAAI,EAAE,kCAAkC;MACxCC,KAAK,EAAE;IACT;EACF,CAAC;EACDC,eAAe,EAAE;IACfE,QAAQ,EAAE;EACZ;AACF,CAAC,CAAC;AAEF,OAAO,MAAMC,6BAA6B,GAAGV,GAAG,CAAC,EAAE,EAAE;EACnDG,QAAQ,EAAE;IACRM,QAAQ,EAAE;MACRJ,IAAI,EAAE,uBAAuB;MAC7BC,KAAK,EAAE;IACT;EACF,CAAC;EACDC,eAAe,EAAE;IACfE,QAAQ,EAAE;EACZ;AACF,CAAC,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { useAnimatedReaction } from 'react-native-reanimated';
|
|
5
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
6
|
+
let nextListenerId = 1;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Syncs `Math.round(progress)` into React state for bounds-aware disabled state.
|
|
10
|
+
* Do not call `getCurrentIndex()` during render — the adopted library warns against it.
|
|
11
|
+
*
|
|
12
|
+
* Uses both:
|
|
13
|
+
* - `useAnimatedReaction` + `scheduleOnRN` (native / Babel-transformed web worklets)
|
|
14
|
+
* - SharedValue `addListener` (JS-thread fallback for web hosts that serve bob-built
|
|
15
|
+
* `lib/` without the Reanimated Babel plugin — e.g. the docs Vite SPA)
|
|
16
|
+
*/
|
|
17
|
+
export function useCarouselActiveIndex(progress) {
|
|
18
|
+
const [activeIndex, setActiveIndex] = useState(() => Math.round(progress.get()));
|
|
19
|
+
const setActiveIndexRef = useRef(setActiveIndex);
|
|
20
|
+
setActiveIndexRef.current = setActiveIndex;
|
|
21
|
+
useAnimatedReaction(() => Math.round(progress.get()), (current, previous) => {
|
|
22
|
+
if (current !== previous) {
|
|
23
|
+
scheduleOnRN(setActiveIndexRef.current, current);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
const listenerId = nextListenerId++;
|
|
28
|
+
const onChange = value => {
|
|
29
|
+
const next = Math.round(value);
|
|
30
|
+
setActiveIndexRef.current(prev => prev === next ? prev : next);
|
|
31
|
+
};
|
|
32
|
+
try {
|
|
33
|
+
progress.addListener(listenerId, onChange);
|
|
34
|
+
} catch {
|
|
35
|
+
// Native JS runtime rejects addListener — the worklet path above handles it.
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
return () => {
|
|
39
|
+
try {
|
|
40
|
+
progress.removeListener(listenerId);
|
|
41
|
+
} catch {
|
|
42
|
+
// ignore
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}, [progress]);
|
|
46
|
+
return activeIndex;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=useCarouselActiveIndex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useEffect","useRef","useState","useAnimatedReaction","scheduleOnRN","nextListenerId","useCarouselActiveIndex","progress","activeIndex","setActiveIndex","Math","round","get","setActiveIndexRef","current","previous","listenerId","onChange","value","next","prev","addListener","removeListener"],"sourceRoot":"../../../../src","sources":["components/Carousel/useCarouselActiveIndex.ts"],"mappings":";;AAAA,SAASA,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,OAAO;AACnD,SAASC,mBAAmB,QAA0B,yBAAyB;AAC/E,SAASC,YAAY,QAAQ,uBAAuB;AAEpD,IAAIC,cAAc,GAAG,CAAC;;AAEtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,sBAAsBA,CAACC,QAA6B,EAAU;EAC5E,MAAM,CAACC,WAAW,EAAEC,cAAc,CAAC,GAAGP,QAAQ,CAAC,MAAMQ,IAAI,CAACC,KAAK,CAACJ,QAAQ,CAACK,GAAG,CAAC,CAAC,CAAC,CAAC;EAChF,MAAMC,iBAAiB,GAAGZ,MAAM,CAACQ,cAAc,CAAC;EAChDI,iBAAiB,CAACC,OAAO,GAAGL,cAAc;EAE1CN,mBAAmB,CACjB,MAAMO,IAAI,CAACC,KAAK,CAACJ,QAAQ,CAACK,GAAG,CAAC,CAAC,CAAC,EAChC,CAACE,OAAO,EAAEC,QAAQ,KAAK;IACrB,IAAID,OAAO,KAAKC,QAAQ,EAAE;MACxBX,YAAY,CAACS,iBAAiB,CAACC,OAAO,EAAEA,OAAO,CAAC;IAClD;EACF,CACF,CAAC;EAEDd,SAAS,CAAC,MAAM;IACd,MAAMgB,UAAU,GAAGX,cAAc,EAAE;IACnC,MAAMY,QAAQ,GAAIC,KAAa,IAAK;MAClC,MAAMC,IAAI,GAAGT,IAAI,CAACC,KAAK,CAACO,KAAK,CAAC;MAC9BL,iBAAiB,CAACC,OAAO,CAAEM,IAAI,IAAMA,IAAI,KAAKD,IAAI,GAAGC,IAAI,GAAGD,IAAK,CAAC;IACpE,CAAC;IAED,IAAI;MACFZ,QAAQ,CAACc,WAAW,CAACL,UAAU,EAAEC,QAAQ,CAAC;IAC5C,CAAC,CAAC,MAAM;MACN;MACA;IACF;IAEA,OAAO,MAAM;MACX,IAAI;QACFV,QAAQ,CAACe,cAAc,CAACN,UAAU,CAAC;MACrC,CAAC,CAAC,MAAM;QACN;MAAA;IAEJ,CAAC;EACH,CAAC,EAAE,CAACT,QAAQ,CAAC,CAAC;EAEd,OAAOC,WAAW;AACpB","ignoreList":[]}
|
|
@@ -44,9 +44,11 @@ const IconButtonRoot = /*#__PURE__*/forwardRef(({
|
|
|
44
44
|
className: rootClassName,
|
|
45
45
|
style: style,
|
|
46
46
|
...props,
|
|
47
|
-
...mergeDataAttributes(
|
|
47
|
+
...mergeDataAttributes(dataAttributes({
|
|
48
48
|
slot: 'icon-button'
|
|
49
|
-
})
|
|
49
|
+
}),
|
|
50
|
+
// Consumer/parent compound slots (e.g. carousel-prev-button) win over the default.
|
|
51
|
+
props),
|
|
50
52
|
children: /*#__PURE__*/_jsx(Icon, {
|
|
51
53
|
as: IconComponent,
|
|
52
54
|
className: glyphClassName
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["forwardRef","useEffect","ButtonRoot","dataAttributes","mergeDataAttributes","cn","Icon","iconButtonGlyphVariants","iconButtonIconColorVariants","iconButtonRootVariants","jsx","_jsx","hasWarnedIconButtonTintVariant","IconButtonRoot","variant","variantProp","color","size","className","style","as","IconComponent","iconClassName","accessibilityRole","props","ref","__DEV__","console","warn","rootClassName","glyphClassName","slot","children","displayName","IconButton"],"sourceRoot":"../../../../src","sources":["components/IconButton/index.tsx"],"mappings":";;AAAA,SAASA,UAAU,EAAEC,SAAS,QAAQ,OAAO;AAE7C,SACEC,UAAU,EACVC,cAAc,EACdC,mBAAmB,QAEd,oBAAoB;AAE3B,SAASC,EAAE,QAAQ,eAAe;AAClC,SAASC,IAAI,QAAwB,SAAS;AAC9C,SAEEC,uBAAuB,EACvBC,2BAA2B,EAC3BC,sBAAsB,QACjB,UAAU;;AAIjB;AAAA,SAAAC,GAAA,IAAAC,IAAA;AAGA,IAAIC,8BAA8B,GAAG,KAAK;AAmB1C,MAAMC,cAAc,gBAAGb,UAAU,CAC/B,CACE;EACEc,OAAO,EAAEC,WAAW,GAAG,OAAO;EAC9BC,KAAK,GAAG,SAAS;EACjBC,IAAI,GAAG,SAAS;EAChBC,SAAS;EACTC,KAAK;EACLC,EAAE,EAAEC,aAAa;EACjBC,aAAa;EACbC,iBAAiB,GAAG,QAAQ;EAC5B,GAAGC;AACL,CAAC,EACDC,GAAG,KACA;EACHxB,SAAS,CAAC,MAAM;IACd,IAAIyB,OAAO,IAAIX,WAAW,KAAK,MAAM,IAAI,CAACH,8BAA8B,EAAE;MACxEA,8BAA8B,GAAG,IAAI;MACrCe,OAAO,CAACC,IAAI,CACV,oHACF,CAAC;IACH;EACF,CAAC,EAAE,CAACb,WAAW,CAAC,CAAC;EAEjB,MAAMD,OAAO,GAAGC,WAAW,KAAK,MAAM,GAAG,QAAQ,GAAGA,WAAW;EAE/D,MAAMc,aAAa,GAAGxB,EAAE,CAACI,sBAAsB,CAAC;IAAEK,OAAO;IAAEE,KAAK;IAAEC;EAAK,CAAC,CAAC,EAAEC,SAAS,CAAC;EAErF,MAAMY,cAAc,GAAGzB,EAAE,CACvBE,uBAAuB,CAAC;IAAEU;EAAK,CAAC,CAAC,EACjCT,2BAA2B,CAAC;IAAEM,OAAO;IAAEE;EAAM,CAAC,CAAC,EAC/CM,aACF,CAAC;EAED,oBACEX,IAAA,CAACT,UAAU;IACTuB,GAAG,EAAEA,GAAI;IACTF,iBAAiB,EAAEA,iBAAkB;IACrCL,SAAS,EAAEW,aAAc;IACzBV,KAAK,EAAEA,KAAM;IAAA,GACTK,KAAK;IAAA,GACLpB,mBAAmB,
|
|
1
|
+
{"version":3,"names":["forwardRef","useEffect","ButtonRoot","dataAttributes","mergeDataAttributes","cn","Icon","iconButtonGlyphVariants","iconButtonIconColorVariants","iconButtonRootVariants","jsx","_jsx","hasWarnedIconButtonTintVariant","IconButtonRoot","variant","variantProp","color","size","className","style","as","IconComponent","iconClassName","accessibilityRole","props","ref","__DEV__","console","warn","rootClassName","glyphClassName","slot","children","displayName","IconButton"],"sourceRoot":"../../../../src","sources":["components/IconButton/index.tsx"],"mappings":";;AAAA,SAASA,UAAU,EAAEC,SAAS,QAAQ,OAAO;AAE7C,SACEC,UAAU,EACVC,cAAc,EACdC,mBAAmB,QAEd,oBAAoB;AAE3B,SAASC,EAAE,QAAQ,eAAe;AAClC,SAASC,IAAI,QAAwB,SAAS;AAC9C,SAEEC,uBAAuB,EACvBC,2BAA2B,EAC3BC,sBAAsB,QACjB,UAAU;;AAIjB;AAAA,SAAAC,GAAA,IAAAC,IAAA;AAGA,IAAIC,8BAA8B,GAAG,KAAK;AAmB1C,MAAMC,cAAc,gBAAGb,UAAU,CAC/B,CACE;EACEc,OAAO,EAAEC,WAAW,GAAG,OAAO;EAC9BC,KAAK,GAAG,SAAS;EACjBC,IAAI,GAAG,SAAS;EAChBC,SAAS;EACTC,KAAK;EACLC,EAAE,EAAEC,aAAa;EACjBC,aAAa;EACbC,iBAAiB,GAAG,QAAQ;EAC5B,GAAGC;AACL,CAAC,EACDC,GAAG,KACA;EACHxB,SAAS,CAAC,MAAM;IACd,IAAIyB,OAAO,IAAIX,WAAW,KAAK,MAAM,IAAI,CAACH,8BAA8B,EAAE;MACxEA,8BAA8B,GAAG,IAAI;MACrCe,OAAO,CAACC,IAAI,CACV,oHACF,CAAC;IACH;EACF,CAAC,EAAE,CAACb,WAAW,CAAC,CAAC;EAEjB,MAAMD,OAAO,GAAGC,WAAW,KAAK,MAAM,GAAG,QAAQ,GAAGA,WAAW;EAE/D,MAAMc,aAAa,GAAGxB,EAAE,CAACI,sBAAsB,CAAC;IAAEK,OAAO;IAAEE,KAAK;IAAEC;EAAK,CAAC,CAAC,EAAEC,SAAS,CAAC;EAErF,MAAMY,cAAc,GAAGzB,EAAE,CACvBE,uBAAuB,CAAC;IAAEU;EAAK,CAAC,CAAC,EACjCT,2BAA2B,CAAC;IAAEM,OAAO;IAAEE;EAAM,CAAC,CAAC,EAC/CM,aACF,CAAC;EAED,oBACEX,IAAA,CAACT,UAAU;IACTuB,GAAG,EAAEA,GAAI;IACTF,iBAAiB,EAAEA,iBAAkB;IACrCL,SAAS,EAAEW,aAAc;IACzBV,KAAK,EAAEA,KAAM;IAAA,GACTK,KAAK;IAAA,GACLpB,mBAAmB,CACrBD,cAAc,CAAC;MAAE4B,IAAI,EAAE;IAAc,CAAC,CAAC;IACvC;IACAP,KACF,CAAC;IAAAQ,QAAA,eAEDrB,IAAA,CAACL,IAAI;MAACc,EAAE,EAAEC,aAAc;MAACH,SAAS,EAAEY;IAAe,CAAE;EAAC,CAC5C,CAAC;AAEjB,CACF,CAAC;AAEDjB,cAAc,CAACoB,WAAW,GAAG,YAAY;AAEzC,OAAO,MAAMC,UAAU,GAAGrB,cAAc","ignoreList":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { SharedValue } from 'react-native-reanimated';
|
|
3
|
+
import type { ICarouselInstance } from 'react-native-reanimated-carousel';
|
|
4
|
+
export interface CarouselContextValue {
|
|
5
|
+
progress: SharedValue<number>;
|
|
6
|
+
carouselRef: RefObject<ICarouselInstance | null>;
|
|
7
|
+
loop: boolean;
|
|
8
|
+
itemCount: number;
|
|
9
|
+
vertical: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare const CarouselProgressProvider: import("react").FunctionComponent<{
|
|
12
|
+
children: import("react").ReactNode;
|
|
13
|
+
value: CarouselContextValue;
|
|
14
|
+
}>, useCarouselProgressContext: () => CarouselContextValue;
|
|
15
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../../src/components/Carousel/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAG1E,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9B,WAAW,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACjD,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAO,wBAAwB;;;IAAE,0BAA0B,4BACU,CAAC"}
|
|
@@ -2,6 +2,8 @@ import { type ReactElement, type ReactNode, type Ref, type RefObject } from 'rea
|
|
|
2
2
|
import type { AccessibilityRole, AccessibilityState } from 'react-native';
|
|
3
3
|
import type { SharedValue } from 'react-native-reanimated';
|
|
4
4
|
import { type ICarouselInstance, type TCarouselProps } from 'react-native-reanimated-carousel';
|
|
5
|
+
import { CarouselNextButton, CarouselPrevButton } from './navButton';
|
|
6
|
+
export type { CarouselNavButtonProps } from './navButton';
|
|
5
7
|
export type CarouselRef = ICarouselInstance;
|
|
6
8
|
/**
|
|
7
9
|
* Full passthrough of `react-native-reanimated-carousel`'s own props (per `01-api-design.md`,
|
|
@@ -11,7 +13,7 @@ export type CarouselRef = ICarouselInstance;
|
|
|
11
13
|
*/
|
|
12
14
|
export type CarouselProps<T> = TCarouselProps<T> & {
|
|
13
15
|
className?: string;
|
|
14
|
-
/** Rendered inside the carousel's progress-sharing provider — use to compose `Carousel.Pagination`. */
|
|
16
|
+
/** Rendered inside the carousel's progress-sharing provider — use to compose `Carousel.Pagination`, `Carousel.PrevButton`, and `Carousel.NextButton`. */
|
|
15
17
|
children?: ReactNode;
|
|
16
18
|
};
|
|
17
19
|
declare const CarouselRoot: <T>(props: CarouselProps<T> & {
|
|
@@ -52,6 +54,8 @@ export interface CarouselPaginationProps<T = unknown> {
|
|
|
52
54
|
declare const CarouselPagination: <T>(props: CarouselPaginationProps<T>) => ReactElement | null;
|
|
53
55
|
type CarouselCompoundComponent = typeof CarouselRoot & {
|
|
54
56
|
Pagination: typeof CarouselPagination;
|
|
57
|
+
PrevButton: typeof CarouselPrevButton;
|
|
58
|
+
NextButton: typeof CarouselNextButton;
|
|
55
59
|
};
|
|
56
60
|
export declare const Carousel: CarouselCompoundComponent;
|
|
57
61
|
export interface UseCarouselOptions {
|
|
@@ -66,5 +70,4 @@ export declare function useCarousel(options?: UseCarouselOptions): {
|
|
|
66
70
|
prev: (opts?: Parameters<ICarouselInstance["prev"]>[0]) => void | undefined;
|
|
67
71
|
scrollTo: (opts?: Parameters<ICarouselInstance["scrollTo"]>[0]) => void | undefined;
|
|
68
72
|
};
|
|
69
|
-
export {};
|
|
70
73
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/Carousel/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,GAAG,EACR,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAa,MAAM,cAAc,CAAC;AAErF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAmB,EAEjB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACpB,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/Carousel/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { SharedValue } from 'react-native-reanimated';
|
|
3
|
+
import type { ICarouselInstance } from 'react-native-reanimated-carousel';
|
|
4
|
+
import { type ForgeIcon } from '@cdx-ui/icons';
|
|
5
|
+
import { type IconButtonProps } from '../IconButton';
|
|
6
|
+
export interface CarouselNavButtonProps extends Omit<IconButtonProps, 'as' | 'variant' | 'onPress' | 'disabled' | 'isDisabled'> {
|
|
7
|
+
/** Mirrors `Carousel`'s `data.length` — only required when rendered outside `<Carousel>`. */
|
|
8
|
+
itemCount?: number;
|
|
9
|
+
/** Explicit progress value — only required when rendered outside `<Carousel>`. */
|
|
10
|
+
progress?: SharedValue<number>;
|
|
11
|
+
/** Explicit carousel ref — only required outside `<Carousel>` (unless `onPress` is provided). */
|
|
12
|
+
carouselRef?: RefObject<ICarouselInstance | null>;
|
|
13
|
+
/**
|
|
14
|
+
* Mirrors `Carousel`'s `loop` prop for bounds-aware disabled state.
|
|
15
|
+
* Defaults to `true` (same as `Carousel`) when omitted outside context.
|
|
16
|
+
*/
|
|
17
|
+
loop?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Mirrors `Carousel`'s `vertical` prop for default icons and accessibility labels.
|
|
20
|
+
* Defaults to `false` when omitted outside context.
|
|
21
|
+
*/
|
|
22
|
+
vertical?: boolean;
|
|
23
|
+
/** Overrides the default press-to-navigate behavior (`prev` / `next` with `{ animated: true }`). */
|
|
24
|
+
onPress?: () => void;
|
|
25
|
+
/** Manual override; when omitted, derived from `loop` and `progress` at bounds. */
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
/** Forge icon component — defaults to direction-appropriate chevrons or arrows. */
|
|
28
|
+
as?: ForgeIcon;
|
|
29
|
+
/** Overrides default `"Previous slide"` / `"Next slide"` (or item labels when `vertical`). */
|
|
30
|
+
accessibilityLabel?: string;
|
|
31
|
+
}
|
|
32
|
+
export declare function CarouselPrevButton(props: CarouselNavButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
export declare namespace CarouselPrevButton {
|
|
34
|
+
var displayName: string;
|
|
35
|
+
}
|
|
36
|
+
export declare function CarouselNextButton(props: CarouselNavButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
export declare namespace CarouselNextButton {
|
|
38
|
+
var displayName: string;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=navButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navButton.d.ts","sourceRoot":"","sources":["../../../../src/components/Carousel/navButton.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAKjE,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAClD,eAAe,EACf,IAAI,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,CACzD;IACC,6FAA6F;IAC7F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/B,iGAAiG;IACjG,WAAW,CAAC,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAClD;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oGAAoG;IACpG,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mFAAmF;IACnF,EAAE,CAAC,EAAE,SAAS,CAAC;IACf,8FAA8F;IAC9F,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAuGD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,sBAAsB,2CAE/D;yBAFe,kBAAkB;;;AAMlC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,sBAAsB,2CAE/D;yBAFe,kBAAkB"}
|
|
@@ -5,4 +5,12 @@ export declare const carouselPaginationDotVariants: (props?: ({
|
|
|
5
5
|
active?: boolean | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
export type CarouselPaginationDotVariants = VariantProps<typeof carouselPaginationDotVariants>;
|
|
8
|
+
/** Overrides IconButton's default disabled opacity so tertiary icon color reads clearly at bounds. */
|
|
9
|
+
export declare const carouselNavButtonRootVariants: (props?: ({
|
|
10
|
+
disabled?: boolean | null | undefined;
|
|
11
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
12
|
+
export declare const carouselNavButtonIconVariants: (props?: ({
|
|
13
|
+
disabled?: boolean | null | undefined;
|
|
14
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
15
|
+
export type CarouselNavButtonVariants = VariantProps<typeof carouselNavButtonRootVariants>;
|
|
8
16
|
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../../src/components/Carousel/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAElE,sGAAsG;AACtG,eAAO,MAAM,oCAAoC,eAAe,CAAC;AAEjE,eAAO,MAAM,6BAA6B;;8EAUxC,CAAC;AAEH,MAAM,MAAM,6BAA6B,GAAG,YAAY,CAAC,OAAO,6BAA6B,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../../src/components/Carousel/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAElE,sGAAsG;AACtG,eAAO,MAAM,oCAAoC,eAAe,CAAC;AAEjE,eAAO,MAAM,6BAA6B;;8EAUxC,CAAC;AAEH,MAAM,MAAM,6BAA6B,GAAG,YAAY,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAE/F,sGAAsG;AACtG,eAAO,MAAM,6BAA6B;;8EAUxC,CAAC;AAEH,eAAO,MAAM,6BAA6B;;8EAUxC,CAAC;AAEH,MAAM,MAAM,yBAAyB,GAAG,YAAY,CAAC,OAAO,6BAA6B,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type SharedValue } from 'react-native-reanimated';
|
|
2
|
+
/**
|
|
3
|
+
* Syncs `Math.round(progress)` into React state for bounds-aware disabled state.
|
|
4
|
+
* Do not call `getCurrentIndex()` during render — the adopted library warns against it.
|
|
5
|
+
*
|
|
6
|
+
* Uses both:
|
|
7
|
+
* - `useAnimatedReaction` + `scheduleOnRN` (native / Babel-transformed web worklets)
|
|
8
|
+
* - SharedValue `addListener` (JS-thread fallback for web hosts that serve bob-built
|
|
9
|
+
* `lib/` without the Reanimated Babel plugin — e.g. the docs Vite SPA)
|
|
10
|
+
*/
|
|
11
|
+
export declare function useCarouselActiveIndex(progress: SharedValue<number>): number;
|
|
12
|
+
//# sourceMappingURL=useCarouselActiveIndex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCarouselActiveIndex.d.ts","sourceRoot":"","sources":["../../../../src/components/Carousel/useCarouselActiveIndex.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAKhF;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,MAAM,CAsC5E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/IconButton/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EACL,KAAK,sBAAsB,EAI5B,MAAM,UAAU,CAAC;AAElB,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7D,sEAAsE;AACtE,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAI3C,MAAM,WAAW,eACf,SAAQ,cAAc,EAAE,YAAY,EAAE,IAAI,CAAC,sBAAsB,EAAE,SAAS,CAAC;IAC7E;;;OAGG;IACH,OAAO,CAAC,EACJ,iBAAiB;IACnB,0CAA0C;OACxC,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,EAAE,EAAE,SAAS,CAAC;IACd,+CAA+C;IAC/C,aAAa,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;CACxC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/IconButton/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EACL,KAAK,sBAAsB,EAI5B,MAAM,UAAU,CAAC;AAElB,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7D,sEAAsE;AACtE,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAI3C,MAAM,WAAW,eACf,SAAQ,cAAc,EAAE,YAAY,EAAE,IAAI,CAAC,sBAAsB,EAAE,SAAS,CAAC;IAC7E;;;OAGG;IACH,OAAO,CAAC,EACJ,iBAAiB;IACnB,0CAA0C;OACxC,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,EAAE,EAAE,SAAS,CAAC;IACd,+CAA+C;IAC/C,aAAa,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;CACxC;AAyDD,eAAO,MAAM,UAAU,kGAAiB,CAAC;AAEzC,YAAY,EAAE,sBAAsB,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdx-ui/components",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.139",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -77,9 +77,9 @@
|
|
|
77
77
|
"class-variance-authority": "^0.7.1",
|
|
78
78
|
"react-native-reanimated-carousel": "5.0.0-beta.5",
|
|
79
79
|
"uniwind": "1.10.0",
|
|
80
|
-
"@cdx-ui/primitives": "0.0.1-beta.
|
|
81
|
-
"@cdx-ui/utils": "0.0.1-beta.
|
|
82
|
-
"@cdx-ui/icons": "0.0.1-beta.
|
|
80
|
+
"@cdx-ui/primitives": "0.0.1-beta.139",
|
|
81
|
+
"@cdx-ui/utils": "0.0.1-beta.139",
|
|
82
|
+
"@cdx-ui/icons": "0.0.1-beta.139"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@react-navigation/bottom-tabs": "*",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { SharedValue } from 'react-native-reanimated';
|
|
3
|
+
import type { ICarouselInstance } from 'react-native-reanimated-carousel';
|
|
4
|
+
import { createContext } from '@cdx-ui/utils';
|
|
5
|
+
|
|
6
|
+
export interface CarouselContextValue {
|
|
7
|
+
progress: SharedValue<number>;
|
|
8
|
+
carouselRef: RefObject<ICarouselInstance | null>;
|
|
9
|
+
loop: boolean;
|
|
10
|
+
itemCount: number;
|
|
11
|
+
vertical: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const [CarouselProgressProvider, useCarouselProgressContext] =
|
|
15
|
+
createContext<CarouselContextValue>('CarouselProgress', { strict: false });
|
|
@@ -16,10 +16,18 @@ import RNCarousel, {
|
|
|
16
16
|
type TCarouselProps,
|
|
17
17
|
} from 'react-native-reanimated-carousel';
|
|
18
18
|
import { useResolveClassNames } from 'uniwind';
|
|
19
|
-
import { cn,
|
|
19
|
+
import { cn, mergeRefs } from '@cdx-ui/utils';
|
|
20
|
+
import {
|
|
21
|
+
CarouselProgressProvider,
|
|
22
|
+
useCarouselProgressContext,
|
|
23
|
+
type CarouselContextValue,
|
|
24
|
+
} from './context';
|
|
25
|
+
import { CarouselNextButton, CarouselPrevButton } from './navButton';
|
|
20
26
|
import { resolveCarouselPaginationScrollAction } from './paginationNavigation';
|
|
21
27
|
import { carouselPaginationContainerClassName, carouselPaginationDotVariants } from './styles';
|
|
22
28
|
|
|
29
|
+
export type { CarouselNavButtonProps } from './navButton';
|
|
30
|
+
|
|
23
31
|
export type CarouselRef = ICarouselInstance;
|
|
24
32
|
|
|
25
33
|
/**
|
|
@@ -30,7 +38,7 @@ export type CarouselRef = ICarouselInstance;
|
|
|
30
38
|
*/
|
|
31
39
|
export type CarouselProps<T> = TCarouselProps<T> & {
|
|
32
40
|
className?: string;
|
|
33
|
-
/** Rendered inside the carousel's progress-sharing provider — use to compose `Carousel.Pagination`. */
|
|
41
|
+
/** Rendered inside the carousel's progress-sharing provider — use to compose `Carousel.Pagination`, `Carousel.PrevButton`, and `Carousel.NextButton`. */
|
|
34
42
|
children?: ReactNode;
|
|
35
43
|
};
|
|
36
44
|
|
|
@@ -42,17 +50,6 @@ type CarouselDotStyle = Omit<ViewStyle, 'width' | 'height' | 'backgroundColor' |
|
|
|
42
50
|
borderRadius?: number;
|
|
43
51
|
};
|
|
44
52
|
|
|
45
|
-
interface CarouselContextValue {
|
|
46
|
-
progress: SharedValue<number>;
|
|
47
|
-
carouselRef: RefObject<ICarouselInstance | null>;
|
|
48
|
-
loop: boolean;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const [CarouselProgressProvider, useCarouselProgressContext] = createContext<CarouselContextValue>(
|
|
52
|
-
'CarouselProgress',
|
|
53
|
-
{ strict: false },
|
|
54
|
-
);
|
|
55
|
-
|
|
56
53
|
function isSharedValueProgress(value: unknown): value is SharedValue<number> {
|
|
57
54
|
return typeof value === 'object' && value !== null && 'value' in value;
|
|
58
55
|
}
|
|
@@ -72,6 +69,8 @@ function CarouselInner<T>(
|
|
|
72
69
|
const internalRef = useRef<ICarouselInstance>(null);
|
|
73
70
|
const internalProgress = useSharedValue(defaultIndex);
|
|
74
71
|
const resolvedClassNameStyle = useResolveClassNames(cn(className));
|
|
72
|
+
const vertical = rest.vertical ?? false;
|
|
73
|
+
const itemCount = rest.data.length;
|
|
75
74
|
|
|
76
75
|
const handleProgressChange = useCallback(
|
|
77
76
|
(offsetProgress: number, absoluteProgress: number) => {
|
|
@@ -88,6 +87,8 @@ function CarouselInner<T>(
|
|
|
88
87
|
progress: consumerProgress ?? internalProgress,
|
|
89
88
|
carouselRef: internalRef,
|
|
90
89
|
loop,
|
|
90
|
+
itemCount,
|
|
91
|
+
vertical,
|
|
91
92
|
};
|
|
92
93
|
|
|
93
94
|
return (
|
|
@@ -234,10 +235,14 @@ const CarouselPagination = CarouselPaginationComponent as <T>(
|
|
|
234
235
|
|
|
235
236
|
type CarouselCompoundComponent = typeof CarouselRoot & {
|
|
236
237
|
Pagination: typeof CarouselPagination;
|
|
238
|
+
PrevButton: typeof CarouselPrevButton;
|
|
239
|
+
NextButton: typeof CarouselNextButton;
|
|
237
240
|
};
|
|
238
241
|
|
|
239
242
|
export const Carousel = Object.assign(CarouselRoot, {
|
|
240
243
|
Pagination: CarouselPagination,
|
|
244
|
+
PrevButton: CarouselPrevButton,
|
|
245
|
+
NextButton: CarouselNextButton,
|
|
241
246
|
}) as CarouselCompoundComponent;
|
|
242
247
|
|
|
243
248
|
// =============================================================================
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import type { RefObject } from 'react';
|
|
3
|
+
import type { SharedValue } from 'react-native-reanimated';
|
|
4
|
+
import type { ICarouselInstance } from 'react-native-reanimated-carousel';
|
|
5
|
+
import {
|
|
6
|
+
ChevronLeft,
|
|
7
|
+
ChevronRight,
|
|
8
|
+
KeyboardArrowDown,
|
|
9
|
+
KeyboardArrowUp,
|
|
10
|
+
type ForgeIcon,
|
|
11
|
+
} from '@cdx-ui/icons';
|
|
12
|
+
import { dataAttributes, mergeDataAttributes } from '@cdx-ui/primitives';
|
|
13
|
+
import { cn } from '@cdx-ui/utils';
|
|
14
|
+
import { IconButton, type IconButtonProps } from '../IconButton';
|
|
15
|
+
import { useCarouselProgressContext } from './context';
|
|
16
|
+
import { carouselNavButtonIconVariants, carouselNavButtonRootVariants } from './styles';
|
|
17
|
+
import { useCarouselActiveIndex } from './useCarouselActiveIndex';
|
|
18
|
+
|
|
19
|
+
export interface CarouselNavButtonProps extends Omit<
|
|
20
|
+
IconButtonProps,
|
|
21
|
+
'as' | 'variant' | 'onPress' | 'disabled' | 'isDisabled'
|
|
22
|
+
> {
|
|
23
|
+
/** Mirrors `Carousel`'s `data.length` — only required when rendered outside `<Carousel>`. */
|
|
24
|
+
itemCount?: number;
|
|
25
|
+
/** Explicit progress value — only required when rendered outside `<Carousel>`. */
|
|
26
|
+
progress?: SharedValue<number>;
|
|
27
|
+
/** Explicit carousel ref — only required outside `<Carousel>` (unless `onPress` is provided). */
|
|
28
|
+
carouselRef?: RefObject<ICarouselInstance | null>;
|
|
29
|
+
/**
|
|
30
|
+
* Mirrors `Carousel`'s `loop` prop for bounds-aware disabled state.
|
|
31
|
+
* Defaults to `true` (same as `Carousel`) when omitted outside context.
|
|
32
|
+
*/
|
|
33
|
+
loop?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Mirrors `Carousel`'s `vertical` prop for default icons and accessibility labels.
|
|
36
|
+
* Defaults to `false` when omitted outside context.
|
|
37
|
+
*/
|
|
38
|
+
vertical?: boolean;
|
|
39
|
+
/** Overrides the default press-to-navigate behavior (`prev` / `next` with `{ animated: true }`). */
|
|
40
|
+
onPress?: () => void;
|
|
41
|
+
/** Manual override; when omitted, derived from `loop` and `progress` at bounds. */
|
|
42
|
+
disabled?: boolean;
|
|
43
|
+
/** Forge icon component — defaults to direction-appropriate chevrons or arrows. */
|
|
44
|
+
as?: ForgeIcon;
|
|
45
|
+
/** Overrides default `"Previous slide"` / `"Next slide"` (or item labels when `vertical`). */
|
|
46
|
+
accessibilityLabel?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface CarouselNavButtonInternalProps extends CarouselNavButtonProps {
|
|
50
|
+
direction: 'prev' | 'next';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function resolveDefaultIcon(vertical: boolean, direction: 'prev' | 'next'): ForgeIcon {
|
|
54
|
+
if (vertical) {
|
|
55
|
+
return direction === 'prev' ? KeyboardArrowUp : KeyboardArrowDown;
|
|
56
|
+
}
|
|
57
|
+
return direction === 'prev' ? ChevronLeft : ChevronRight;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function resolveDefaultAccessibilityLabel(vertical: boolean, direction: 'prev' | 'next'): string {
|
|
61
|
+
if (vertical) {
|
|
62
|
+
return direction === 'prev' ? 'Previous item' : 'Next item';
|
|
63
|
+
}
|
|
64
|
+
return direction === 'prev' ? 'Previous slide' : 'Next slide';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function CarouselNavButton({
|
|
68
|
+
direction,
|
|
69
|
+
progress: progressProp,
|
|
70
|
+
carouselRef: carouselRefProp,
|
|
71
|
+
itemCount: itemCountProp,
|
|
72
|
+
loop: loopProp,
|
|
73
|
+
vertical: verticalProp,
|
|
74
|
+
onPress,
|
|
75
|
+
disabled: disabledProp,
|
|
76
|
+
as,
|
|
77
|
+
accessibilityLabel,
|
|
78
|
+
color = 'neutral',
|
|
79
|
+
size = 'default',
|
|
80
|
+
className,
|
|
81
|
+
iconClassName,
|
|
82
|
+
...iconButtonProps
|
|
83
|
+
}: CarouselNavButtonInternalProps) {
|
|
84
|
+
const context = useCarouselProgressContext();
|
|
85
|
+
const progress = progressProp ?? context?.progress;
|
|
86
|
+
const carouselRef = carouselRefProp ?? context?.carouselRef;
|
|
87
|
+
const itemCount = itemCountProp ?? context?.itemCount;
|
|
88
|
+
const loop = loopProp ?? context?.loop ?? true;
|
|
89
|
+
const vertical = verticalProp ?? context?.vertical ?? false;
|
|
90
|
+
|
|
91
|
+
if (!progress) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`Carousel.${direction === 'prev' ? 'PrevButton' : 'NextButton'} must be rendered inside <Carousel> or receive an explicit \`progress\` prop.`,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!onPress && !carouselRef) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`Carousel.${direction === 'prev' ? 'PrevButton' : 'NextButton'} must be rendered inside <Carousel> or receive an explicit \`carouselRef\` prop (or a custom \`onPress\`).`,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (itemCount == null) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
`Carousel.${direction === 'prev' ? 'PrevButton' : 'NextButton'} must be rendered inside <Carousel> or receive an explicit \`itemCount\` prop.`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const activeIndex = useCarouselActiveIndex(progress);
|
|
110
|
+
const atStart = activeIndex <= 0;
|
|
111
|
+
const atEnd = activeIndex >= itemCount - 1;
|
|
112
|
+
const autoDisabled = !loop && (direction === 'prev' ? atStart : atEnd);
|
|
113
|
+
const disabled = disabledProp ?? autoDisabled;
|
|
114
|
+
|
|
115
|
+
const handlePress = useCallback(() => {
|
|
116
|
+
if (onPress) {
|
|
117
|
+
onPress();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (direction === 'prev') {
|
|
122
|
+
carouselRef?.current?.prev({ animated: true });
|
|
123
|
+
} else {
|
|
124
|
+
carouselRef?.current?.next({ animated: true });
|
|
125
|
+
}
|
|
126
|
+
}, [onPress, carouselRef, direction]);
|
|
127
|
+
|
|
128
|
+
const dataSlot = direction === 'prev' ? 'carousel-prev-button' : 'carousel-next-button';
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<IconButton
|
|
132
|
+
as={as ?? resolveDefaultIcon(vertical, direction)}
|
|
133
|
+
variant="ghost"
|
|
134
|
+
color={color}
|
|
135
|
+
size={size}
|
|
136
|
+
isDisabled={disabled}
|
|
137
|
+
onPress={handlePress}
|
|
138
|
+
accessibilityLabel={
|
|
139
|
+
accessibilityLabel ?? resolveDefaultAccessibilityLabel(vertical, direction)
|
|
140
|
+
}
|
|
141
|
+
accessibilityState={{ disabled }}
|
|
142
|
+
className={cn(carouselNavButtonRootVariants({ disabled }), className)}
|
|
143
|
+
iconClassName={cn(carouselNavButtonIconVariants({ disabled }), iconClassName)}
|
|
144
|
+
{...iconButtonProps}
|
|
145
|
+
{...mergeDataAttributes(iconButtonProps, dataAttributes({ slot: dataSlot }))}
|
|
146
|
+
/>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function CarouselPrevButton(props: CarouselNavButtonProps) {
|
|
151
|
+
return <CarouselNavButton direction="prev" {...props} />;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
CarouselPrevButton.displayName = 'Carousel.PrevButton';
|
|
155
|
+
|
|
156
|
+
export function CarouselNextButton(props: CarouselNavButtonProps) {
|
|
157
|
+
return <CarouselNavButton direction="next" {...props} />;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
CarouselNextButton.displayName = 'Carousel.NextButton';
|
|
@@ -16,3 +16,30 @@ export const carouselPaginationDotVariants = cva('rounded-full', {
|
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
export type CarouselPaginationDotVariants = VariantProps<typeof carouselPaginationDotVariants>;
|
|
19
|
+
|
|
20
|
+
/** Overrides IconButton's default disabled opacity so tertiary icon color reads clearly at bounds. */
|
|
21
|
+
export const carouselNavButtonRootVariants = cva([], {
|
|
22
|
+
variants: {
|
|
23
|
+
disabled: {
|
|
24
|
+
true: 'data-[disabled=true]:opacity-100',
|
|
25
|
+
false: '',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
defaultVariants: {
|
|
29
|
+
disabled: false,
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export const carouselNavButtonIconVariants = cva([], {
|
|
34
|
+
variants: {
|
|
35
|
+
disabled: {
|
|
36
|
+
true: 'text-content-tertiary',
|
|
37
|
+
false: '',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
defaultVariants: {
|
|
41
|
+
disabled: false,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export type CarouselNavButtonVariants = VariantProps<typeof carouselNavButtonRootVariants>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { useAnimatedReaction, type SharedValue } from 'react-native-reanimated';
|
|
3
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
4
|
+
|
|
5
|
+
let nextListenerId = 1;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Syncs `Math.round(progress)` into React state for bounds-aware disabled state.
|
|
9
|
+
* Do not call `getCurrentIndex()` during render — the adopted library warns against it.
|
|
10
|
+
*
|
|
11
|
+
* Uses both:
|
|
12
|
+
* - `useAnimatedReaction` + `scheduleOnRN` (native / Babel-transformed web worklets)
|
|
13
|
+
* - SharedValue `addListener` (JS-thread fallback for web hosts that serve bob-built
|
|
14
|
+
* `lib/` without the Reanimated Babel plugin — e.g. the docs Vite SPA)
|
|
15
|
+
*/
|
|
16
|
+
export function useCarouselActiveIndex(progress: SharedValue<number>): number {
|
|
17
|
+
const [activeIndex, setActiveIndex] = useState(() => Math.round(progress.get()));
|
|
18
|
+
const setActiveIndexRef = useRef(setActiveIndex);
|
|
19
|
+
setActiveIndexRef.current = setActiveIndex;
|
|
20
|
+
|
|
21
|
+
useAnimatedReaction(
|
|
22
|
+
() => Math.round(progress.get()),
|
|
23
|
+
(current, previous) => {
|
|
24
|
+
if (current !== previous) {
|
|
25
|
+
scheduleOnRN(setActiveIndexRef.current, current);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const listenerId = nextListenerId++;
|
|
32
|
+
const onChange = (value: number) => {
|
|
33
|
+
const next = Math.round(value);
|
|
34
|
+
setActiveIndexRef.current((prev) => (prev === next ? prev : next));
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
progress.addListener(listenerId, onChange);
|
|
39
|
+
} catch {
|
|
40
|
+
// Native JS runtime rejects addListener — the worklet path above handles it.
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return () => {
|
|
45
|
+
try {
|
|
46
|
+
progress.removeListener(listenerId);
|
|
47
|
+
} catch {
|
|
48
|
+
// ignore
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}, [progress]);
|
|
52
|
+
|
|
53
|
+
return activeIndex;
|
|
54
|
+
}
|
|
@@ -81,7 +81,11 @@ const IconButtonRoot = forwardRef<View, IconButtonProps>(
|
|
|
81
81
|
className={rootClassName}
|
|
82
82
|
style={style}
|
|
83
83
|
{...props}
|
|
84
|
-
{...mergeDataAttributes(
|
|
84
|
+
{...mergeDataAttributes(
|
|
85
|
+
dataAttributes({ slot: 'icon-button' }),
|
|
86
|
+
// Consumer/parent compound slots (e.g. carousel-prev-button) win over the default.
|
|
87
|
+
props,
|
|
88
|
+
)}
|
|
85
89
|
>
|
|
86
90
|
<Icon as={IconComponent} className={glyphClassName} />
|
|
87
91
|
</ButtonRoot>
|