@thewhateverapp/tile-sdk 0.13.0 → 0.13.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/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/react/overlay/Slideshow.d.ts +62 -2
- package/dist/react/overlay/Slideshow.d.ts.map +1 -1
- package/dist/react/overlay/Slideshow.js +218 -68
- package/dist/react/overlay/index.d.ts +1 -1
- package/dist/react/overlay/index.d.ts.map +1 -1
- package/dist/react/overlay/index.js +3 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -5,8 +5,9 @@ export { useKeyboard } from './react/useKeyboard';
|
|
|
5
5
|
export { TileContainer } from './react/TileContainer';
|
|
6
6
|
export { withTile } from './react/withTile';
|
|
7
7
|
export { VideoPlayer, useVideoState, useVideo, // Alias for useVideoState
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
useCuePoint, useCuePoints, useVideoProgress, Slideshow, useSlideshowState, useSlideshow, // Alias for useSlideshowState
|
|
9
|
+
OverlaySlot, FullOverlay, GradientOverlay, } from './react/overlay';
|
|
10
|
+
export type { VideoState, VideoControls, VideoContextValue, VideoPlayerProps, CuePoint, SlideImage, SlideshowState, SlideshowControls, SlideshowContextValue, SlideshowProps, SlotPosition, OverlaySlotProps, FullOverlayProps, GradientOverlayProps, } from './react/overlay';
|
|
10
11
|
export { getTileBridge, TileBridge } from './bridge/TileBridge';
|
|
11
12
|
export type { TileMessage, TileConfig, TileTokenData, KeyboardState, VisibilityState } from './bridge/TileBridge';
|
|
12
13
|
export { StateClient } from './state/StateClient';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAEL,WAAW,EACX,aAAa,EACb,QAAQ,EAAE,0BAA0B;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAEL,WAAW,EACX,aAAa,EACb,QAAQ,EAAE,0BAA0B;AACpC,WAAW,EACX,YAAY,EACZ,gBAAgB,EAEhB,SAAS,EACT,iBAAiB,EACjB,YAAY,EAAE,8BAA8B;AAE5C,WAAW,EACX,WAAW,EACX,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAEV,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,QAAQ,EAER,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,EAEd,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGlH,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnE,cAAc,SAAS,CAAC;AAGxB,cAAc,SAAS,CAAC;AAGxB,cAAc,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,8 +9,9 @@ export { withTile } from './react/withTile';
|
|
|
9
9
|
export {
|
|
10
10
|
// Video player (with route persistence)
|
|
11
11
|
VideoPlayer, useVideoState, useVideo, // Alias for useVideoState
|
|
12
|
-
|
|
13
|
-
Slideshow
|
|
12
|
+
useCuePoint, useCuePoints, useVideoProgress,
|
|
13
|
+
// Slideshow (with route persistence)
|
|
14
|
+
Slideshow, useSlideshowState, useSlideshow, // Alias for useSlideshowState
|
|
14
15
|
// Positioning components
|
|
15
16
|
OverlaySlot, FullOverlay, GradientOverlay, } from './react/overlay';
|
|
16
17
|
// Bridge for secure communication
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import React, { type ReactNode } from 'react';
|
|
2
|
+
declare global {
|
|
3
|
+
interface Window {
|
|
4
|
+
__slideshowSingleton?: SlideshowSingletonClass;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
2
7
|
export interface SlideImage {
|
|
3
8
|
url: string;
|
|
4
9
|
alt?: string;
|
|
@@ -23,6 +28,49 @@ export interface SlideshowContextValue {
|
|
|
23
28
|
state: SlideshowState;
|
|
24
29
|
controls: SlideshowControls;
|
|
25
30
|
}
|
|
31
|
+
type StateCallback = (state: SlideshowState) => void;
|
|
32
|
+
/**
|
|
33
|
+
* SlideshowSingleton - Manages slideshow state across route changes.
|
|
34
|
+
*
|
|
35
|
+
* The current slide index and pause state persist across Next.js soft navigations.
|
|
36
|
+
* When navigating from /tile to /page, the slideshow maintains its position.
|
|
37
|
+
*/
|
|
38
|
+
declare class SlideshowSingletonClass {
|
|
39
|
+
private stateCallbacks;
|
|
40
|
+
private currentState;
|
|
41
|
+
private intervalRef;
|
|
42
|
+
private intervalMs;
|
|
43
|
+
private transitionDuration;
|
|
44
|
+
/**
|
|
45
|
+
* Initialize slideshow with images
|
|
46
|
+
*/
|
|
47
|
+
initialize(images: SlideImage[], options?: {
|
|
48
|
+
intervalMs?: number;
|
|
49
|
+
autoAdvance?: boolean;
|
|
50
|
+
transitionDuration?: number;
|
|
51
|
+
}): void;
|
|
52
|
+
/**
|
|
53
|
+
* Start auto-advance timer
|
|
54
|
+
*/
|
|
55
|
+
private startAutoAdvance;
|
|
56
|
+
/**
|
|
57
|
+
* Stop auto-advance timer
|
|
58
|
+
*/
|
|
59
|
+
private stopAutoAdvance;
|
|
60
|
+
next(): void;
|
|
61
|
+
prev(): void;
|
|
62
|
+
goTo(index: number): void;
|
|
63
|
+
pause(): void;
|
|
64
|
+
resume(): void;
|
|
65
|
+
toggle(): void;
|
|
66
|
+
getState(): SlideshowState;
|
|
67
|
+
onStateChange(callback: StateCallback): () => void;
|
|
68
|
+
private notifyListeners;
|
|
69
|
+
/**
|
|
70
|
+
* Clean up (call when slideshow is removed)
|
|
71
|
+
*/
|
|
72
|
+
destroy(): void;
|
|
73
|
+
}
|
|
26
74
|
export interface SlideshowProps {
|
|
27
75
|
/** Array of images to display */
|
|
28
76
|
images: SlideImage[];
|
|
@@ -46,12 +94,24 @@ export interface SlideshowProps {
|
|
|
46
94
|
imageClassName?: string;
|
|
47
95
|
}
|
|
48
96
|
/**
|
|
49
|
-
* Slideshow component with auto-advancing image carousel.
|
|
50
|
-
*
|
|
97
|
+
* Slideshow component with auto-advancing image carousel and route persistence.
|
|
98
|
+
*
|
|
99
|
+
* The current slide index persists across Next.js route changes (tile ↔ page).
|
|
100
|
+
* When navigating between routes, the slideshow maintains its position.
|
|
101
|
+
*
|
|
102
|
+
* Usage:
|
|
103
|
+
* ```tsx
|
|
104
|
+
* <Slideshow images={images} className="w-full h-full">
|
|
105
|
+
* <YourOverlay />
|
|
106
|
+
* </Slideshow>
|
|
107
|
+
* ```
|
|
51
108
|
*/
|
|
52
109
|
export declare function Slideshow({ images, intervalMs, autoAdvance, transition, transitionDuration, showDots, showArrows, children, className, imageClassName, }: SlideshowProps): React.JSX.Element;
|
|
53
110
|
/**
|
|
54
111
|
* Hook to access slideshow state and controls from within Slideshow children.
|
|
112
|
+
* Also aliased as useSlideshow for consistency with VideoPlayer.
|
|
55
113
|
*/
|
|
56
114
|
export declare function useSlideshowState(): SlideshowContextValue;
|
|
115
|
+
export declare const useSlideshow: typeof useSlideshowState;
|
|
116
|
+
export {};
|
|
57
117
|
//# sourceMappingURL=Slideshow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Slideshow.d.ts","sourceRoot":"","sources":["../../../src/react/overlay/Slideshow.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAOZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Slideshow.d.ts","sourceRoot":"","sources":["../../../src/react/overlay/Slideshow.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,67 +1,209 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React, { createContext, useContext, useEffect,
|
|
3
|
-
const SlideshowContext = createContext(null);
|
|
2
|
+
import React, { createContext, useContext, useEffect, useState, useCallback, } from 'react';
|
|
4
3
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* SlideshowSingleton - Manages slideshow state across route changes.
|
|
5
|
+
*
|
|
6
|
+
* The current slide index and pause state persist across Next.js soft navigations.
|
|
7
|
+
* When navigating from /tile to /page, the slideshow maintains its position.
|
|
7
8
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
class SlideshowSingletonClass {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.stateCallbacks = new Set();
|
|
12
|
+
this.currentState = {
|
|
13
|
+
currentIndex: 0,
|
|
14
|
+
totalSlides: 0,
|
|
15
|
+
isTransitioning: false,
|
|
16
|
+
isPaused: false,
|
|
17
|
+
images: [],
|
|
18
|
+
};
|
|
19
|
+
this.intervalRef = null;
|
|
20
|
+
this.intervalMs = 5000;
|
|
21
|
+
this.transitionDuration = 500;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Initialize slideshow with images
|
|
25
|
+
*/
|
|
26
|
+
initialize(images, options) {
|
|
27
|
+
const imagesChanged = JSON.stringify(images) !== JSON.stringify(this.currentState.images);
|
|
28
|
+
// Only reset if images changed
|
|
29
|
+
if (imagesChanged) {
|
|
30
|
+
this.currentState = {
|
|
31
|
+
...this.currentState,
|
|
32
|
+
currentIndex: 0,
|
|
33
|
+
totalSlides: images.length,
|
|
34
|
+
images,
|
|
35
|
+
isPaused: options?.autoAdvance === false,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// Just update totalSlides in case it changed
|
|
40
|
+
this.currentState = {
|
|
41
|
+
...this.currentState,
|
|
42
|
+
totalSlides: images.length,
|
|
43
|
+
images,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (options?.intervalMs) {
|
|
47
|
+
this.intervalMs = options.intervalMs;
|
|
48
|
+
}
|
|
49
|
+
if (options?.transitionDuration) {
|
|
50
|
+
this.transitionDuration = options.transitionDuration;
|
|
51
|
+
}
|
|
52
|
+
this.notifyListeners();
|
|
53
|
+
this.startAutoAdvance();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Start auto-advance timer
|
|
57
|
+
*/
|
|
58
|
+
startAutoAdvance() {
|
|
59
|
+
this.stopAutoAdvance();
|
|
60
|
+
if (this.currentState.isPaused || this.currentState.totalSlides <= 1) {
|
|
17
61
|
return;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
62
|
+
}
|
|
63
|
+
this.intervalRef = setInterval(() => {
|
|
64
|
+
this.next();
|
|
65
|
+
}, this.intervalMs);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Stop auto-advance timer
|
|
69
|
+
*/
|
|
70
|
+
stopAutoAdvance() {
|
|
71
|
+
if (this.intervalRef) {
|
|
72
|
+
clearInterval(this.intervalRef);
|
|
73
|
+
this.intervalRef = null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Navigation controls
|
|
77
|
+
next() {
|
|
78
|
+
if (this.currentState.isTransitioning || this.currentState.totalSlides <= 1)
|
|
24
79
|
return;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
80
|
+
this.currentState = {
|
|
81
|
+
...this.currentState,
|
|
82
|
+
isTransitioning: true,
|
|
83
|
+
currentIndex: (this.currentState.currentIndex + 1) % this.currentState.totalSlides,
|
|
84
|
+
};
|
|
85
|
+
this.notifyListeners();
|
|
86
|
+
setTimeout(() => {
|
|
87
|
+
this.currentState = { ...this.currentState, isTransitioning: false };
|
|
88
|
+
this.notifyListeners();
|
|
89
|
+
}, this.transitionDuration);
|
|
90
|
+
}
|
|
91
|
+
prev() {
|
|
92
|
+
if (this.currentState.isTransitioning || this.currentState.totalSlides <= 1)
|
|
31
93
|
return;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (intervalRef.current) {
|
|
49
|
-
clearInterval(intervalRef.current);
|
|
50
|
-
intervalRef.current = null;
|
|
51
|
-
}
|
|
94
|
+
this.currentState = {
|
|
95
|
+
...this.currentState,
|
|
96
|
+
isTransitioning: true,
|
|
97
|
+
currentIndex: (this.currentState.currentIndex - 1 + this.currentState.totalSlides) % this.currentState.totalSlides,
|
|
98
|
+
};
|
|
99
|
+
this.notifyListeners();
|
|
100
|
+
setTimeout(() => {
|
|
101
|
+
this.currentState = { ...this.currentState, isTransitioning: false };
|
|
102
|
+
this.notifyListeners();
|
|
103
|
+
}, this.transitionDuration);
|
|
104
|
+
}
|
|
105
|
+
goTo(index) {
|
|
106
|
+
if (this.currentState.isTransitioning ||
|
|
107
|
+
index === this.currentState.currentIndex ||
|
|
108
|
+
index < 0 ||
|
|
109
|
+
index >= this.currentState.totalSlides)
|
|
52
110
|
return;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
clearInterval(intervalRef.current);
|
|
58
|
-
intervalRef.current = null;
|
|
59
|
-
}
|
|
111
|
+
this.currentState = {
|
|
112
|
+
...this.currentState,
|
|
113
|
+
isTransitioning: true,
|
|
114
|
+
currentIndex: index,
|
|
60
115
|
};
|
|
61
|
-
|
|
116
|
+
this.notifyListeners();
|
|
117
|
+
setTimeout(() => {
|
|
118
|
+
this.currentState = { ...this.currentState, isTransitioning: false };
|
|
119
|
+
this.notifyListeners();
|
|
120
|
+
}, this.transitionDuration);
|
|
121
|
+
}
|
|
122
|
+
pause() {
|
|
123
|
+
this.currentState = { ...this.currentState, isPaused: true };
|
|
124
|
+
this.stopAutoAdvance();
|
|
125
|
+
this.notifyListeners();
|
|
126
|
+
}
|
|
127
|
+
resume() {
|
|
128
|
+
this.currentState = { ...this.currentState, isPaused: false };
|
|
129
|
+
this.startAutoAdvance();
|
|
130
|
+
this.notifyListeners();
|
|
131
|
+
}
|
|
132
|
+
toggle() {
|
|
133
|
+
if (this.currentState.isPaused) {
|
|
134
|
+
this.resume();
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
this.pause();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// State management
|
|
141
|
+
getState() {
|
|
142
|
+
return { ...this.currentState };
|
|
143
|
+
}
|
|
144
|
+
onStateChange(callback) {
|
|
145
|
+
this.stateCallbacks.add(callback);
|
|
146
|
+
callback(this.currentState);
|
|
147
|
+
return () => this.stateCallbacks.delete(callback);
|
|
148
|
+
}
|
|
149
|
+
notifyListeners() {
|
|
150
|
+
this.stateCallbacks.forEach(cb => cb(this.currentState));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Clean up (call when slideshow is removed)
|
|
154
|
+
*/
|
|
155
|
+
destroy() {
|
|
156
|
+
this.stopAutoAdvance();
|
|
157
|
+
this.stateCallbacks.clear();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get the SlideshowSingleton instance (creates if needed)
|
|
162
|
+
*/
|
|
163
|
+
function getSlideshowSingleton() {
|
|
164
|
+
if (typeof window === 'undefined') {
|
|
165
|
+
return new SlideshowSingletonClass();
|
|
166
|
+
}
|
|
167
|
+
if (!window.__slideshowSingleton) {
|
|
168
|
+
window.__slideshowSingleton = new SlideshowSingletonClass();
|
|
169
|
+
}
|
|
170
|
+
return window.__slideshowSingleton;
|
|
171
|
+
}
|
|
172
|
+
// =============================================================================
|
|
173
|
+
// React Context and Component
|
|
174
|
+
// =============================================================================
|
|
175
|
+
const SlideshowContext = createContext(null);
|
|
176
|
+
/**
|
|
177
|
+
* Slideshow component with auto-advancing image carousel and route persistence.
|
|
178
|
+
*
|
|
179
|
+
* The current slide index persists across Next.js route changes (tile ↔ page).
|
|
180
|
+
* When navigating between routes, the slideshow maintains its position.
|
|
181
|
+
*
|
|
182
|
+
* Usage:
|
|
183
|
+
* ```tsx
|
|
184
|
+
* <Slideshow images={images} className="w-full h-full">
|
|
185
|
+
* <YourOverlay />
|
|
186
|
+
* </Slideshow>
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export function Slideshow({ images, intervalMs = 5000, autoAdvance = true, transition = 'fade', transitionDuration = 500, showDots = true, showArrows = true, children, className = '', imageClassName = '', }) {
|
|
190
|
+
const [state, setState] = useState(() => getSlideshowSingleton().getState());
|
|
191
|
+
// Initialize and subscribe to singleton
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
const singleton = getSlideshowSingleton();
|
|
194
|
+
// Initialize with images and options
|
|
195
|
+
singleton.initialize(images, {
|
|
196
|
+
intervalMs,
|
|
197
|
+
autoAdvance,
|
|
198
|
+
transitionDuration,
|
|
199
|
+
});
|
|
200
|
+
// Subscribe to state changes
|
|
201
|
+
const unsubscribe = singleton.onStateChange(setState);
|
|
202
|
+
return unsubscribe;
|
|
203
|
+
}, [images, intervalMs, autoAdvance, transitionDuration]);
|
|
62
204
|
// Get transition styles
|
|
63
205
|
const getTransitionStyles = (index) => {
|
|
64
|
-
const isActive = index === currentIndex;
|
|
206
|
+
const isActive = index === state.currentIndex;
|
|
65
207
|
switch (transition) {
|
|
66
208
|
case 'fade':
|
|
67
209
|
return {
|
|
@@ -71,7 +213,7 @@ export function Slideshow({ images, intervalMs = 5000, autoAdvance = true, trans
|
|
|
71
213
|
inset: 0,
|
|
72
214
|
};
|
|
73
215
|
case 'slide':
|
|
74
|
-
const offset = (index - currentIndex) * 100;
|
|
216
|
+
const offset = (index - state.currentIndex) * 100;
|
|
75
217
|
return {
|
|
76
218
|
transform: `translateX(${offset}%)`,
|
|
77
219
|
transition: `transform ${transitionDuration}ms ease-in-out`,
|
|
@@ -87,15 +229,19 @@ export function Slideshow({ images, intervalMs = 5000, autoAdvance = true, trans
|
|
|
87
229
|
};
|
|
88
230
|
}
|
|
89
231
|
};
|
|
232
|
+
// Control functions bound to singleton
|
|
233
|
+
const singleton = getSlideshowSingleton();
|
|
234
|
+
const controls = {
|
|
235
|
+
next: useCallback(() => singleton.next(), []),
|
|
236
|
+
prev: useCallback(() => singleton.prev(), []),
|
|
237
|
+
goTo: useCallback((index) => singleton.goTo(index), []),
|
|
238
|
+
pause: useCallback(() => singleton.pause(), []),
|
|
239
|
+
resume: useCallback(() => singleton.resume(), []),
|
|
240
|
+
toggle: useCallback(() => singleton.toggle(), []),
|
|
241
|
+
};
|
|
90
242
|
const contextValue = {
|
|
91
|
-
state
|
|
92
|
-
|
|
93
|
-
totalSlides,
|
|
94
|
-
isTransitioning,
|
|
95
|
-
isPaused,
|
|
96
|
-
images,
|
|
97
|
-
},
|
|
98
|
-
controls: { next, prev, goTo, pause, resume, toggle },
|
|
243
|
+
state,
|
|
244
|
+
controls,
|
|
99
245
|
};
|
|
100
246
|
if (images.length === 0) {
|
|
101
247
|
return (React.createElement("div", { className: `relative w-full h-full bg-black flex items-center justify-center ${className}` },
|
|
@@ -105,20 +251,22 @@ export function Slideshow({ images, intervalMs = 5000, autoAdvance = true, trans
|
|
|
105
251
|
React.createElement("div", { className: `relative w-full h-full bg-black overflow-hidden ${className}` },
|
|
106
252
|
React.createElement("div", { className: "relative w-full h-full" }, images.map((image, index) => (React.createElement("div", { key: `${image.url}-${index}`, style: getTransitionStyles(index), className: imageClassName },
|
|
107
253
|
React.createElement("img", { src: image.url, alt: image.alt || `Slide ${index + 1}`, className: "w-full h-full object-contain", loading: index === 0 ? 'eager' : 'lazy' }))))),
|
|
108
|
-
showArrows && totalSlides > 1 && (React.createElement(React.Fragment, null,
|
|
109
|
-
React.createElement("button", { onClick: prev, disabled: isTransitioning, className: "absolute left-2 top-1/2 -translate-y-1/2 p-2 bg-black/40 hover:bg-black/60 rounded-full text-white transition-colors disabled:opacity-50", "aria-label": "Previous slide" },
|
|
254
|
+
showArrows && state.totalSlides > 1 && (React.createElement(React.Fragment, null,
|
|
255
|
+
React.createElement("button", { onClick: controls.prev, disabled: state.isTransitioning, className: "absolute left-2 top-1/2 -translate-y-1/2 p-2 bg-black/40 hover:bg-black/60 rounded-full text-white transition-colors disabled:opacity-50", "aria-label": "Previous slide" },
|
|
110
256
|
React.createElement("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
|
|
111
257
|
React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }))),
|
|
112
|
-
React.createElement("button", { onClick: next, disabled: isTransitioning, className: "absolute right-2 top-1/2 -translate-y-1/2 p-2 bg-black/40 hover:bg-black/60 rounded-full text-white transition-colors disabled:opacity-50", "aria-label": "Next slide" },
|
|
258
|
+
React.createElement("button", { onClick: controls.next, disabled: state.isTransitioning, className: "absolute right-2 top-1/2 -translate-y-1/2 p-2 bg-black/40 hover:bg-black/60 rounded-full text-white transition-colors disabled:opacity-50", "aria-label": "Next slide" },
|
|
113
259
|
React.createElement("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
|
|
114
260
|
React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }))))),
|
|
115
|
-
showDots && totalSlides > 1 && (React.createElement("div", { className: "absolute bottom-3 left-1/2 -translate-x-1/2 flex gap-1.5" }, images.map((_, index) => (React.createElement("button", { key: index, onClick: () => goTo(index), disabled: isTransitioning, className: `w-2 h-2 rounded-full transition-colors ${index === currentIndex
|
|
261
|
+
showDots && state.totalSlides > 1 && (React.createElement("div", { className: "absolute bottom-3 left-1/2 -translate-x-1/2 flex gap-1.5" }, images.map((_, index) => (React.createElement("button", { key: index, onClick: () => controls.goTo(index), disabled: state.isTransitioning, className: `w-2 h-2 rounded-full transition-colors ${index === state.currentIndex
|
|
116
262
|
? 'bg-white'
|
|
117
263
|
: 'bg-white/40 hover:bg-white/60'}`, "aria-label": `Go to slide ${index + 1}` }))))),
|
|
118
|
-
|
|
264
|
+
React.createElement("div", { className: "absolute inset-0 z-10 pointer-events-none" },
|
|
265
|
+
React.createElement("div", { className: "pointer-events-auto" }, children)))));
|
|
119
266
|
}
|
|
120
267
|
/**
|
|
121
268
|
* Hook to access slideshow state and controls from within Slideshow children.
|
|
269
|
+
* Also aliased as useSlideshow for consistency with VideoPlayer.
|
|
122
270
|
*/
|
|
123
271
|
export function useSlideshowState() {
|
|
124
272
|
const context = useContext(SlideshowContext);
|
|
@@ -127,3 +275,5 @@ export function useSlideshowState() {
|
|
|
127
275
|
}
|
|
128
276
|
return context;
|
|
129
277
|
}
|
|
278
|
+
// Alias for consistency with useVideo/useVideoState
|
|
279
|
+
export const useSlideshow = useSlideshowState;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { VideoPlayer, useVideoState, useVideo, // Alias for useVideoState (compatibility)
|
|
2
2
|
useCuePoint, useCuePoints, useVideoProgress, } from './VideoPlayer';
|
|
3
3
|
export type { VideoState, VideoControls, VideoContextValue, VideoPlayerProps, CuePoint, } from './VideoPlayer';
|
|
4
|
-
export { Slideshow, useSlideshowState, } from './Slideshow';
|
|
4
|
+
export { Slideshow, useSlideshowState, useSlideshow, } from './Slideshow';
|
|
5
5
|
export type { SlideImage, SlideshowState, SlideshowControls, SlideshowContextValue, SlideshowProps, } from './Slideshow';
|
|
6
6
|
export { OverlaySlot, FullOverlay, GradientOverlay, } from './OverlaySlot';
|
|
7
7
|
export type { SlotPosition, OverlaySlotProps, FullOverlayProps, GradientOverlayProps, } from './OverlaySlot';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/overlay/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,aAAa,EACb,QAAQ,EAAE,0CAA0C;AACpD,WAAW,EACX,YAAY,EACZ,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,QAAQ,GACT,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,SAAS,EACT,iBAAiB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/overlay/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,aAAa,EACb,QAAQ,EAAE,0CAA0C;AACpD,WAAW,EACX,YAAY,EACZ,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,QAAQ,GACT,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,GACf,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,WAAW,EACX,WAAW,EACX,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,eAAe,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Video player with HLS streaming support and route persistence
|
|
2
2
|
export { VideoPlayer, useVideoState, useVideo, // Alias for useVideoState (compatibility)
|
|
3
3
|
useCuePoint, useCuePoints, useVideoProgress, } from './VideoPlayer';
|
|
4
|
-
// Image slideshow component
|
|
5
|
-
export { Slideshow, useSlideshowState,
|
|
4
|
+
// Image slideshow component with route persistence
|
|
5
|
+
export { Slideshow, useSlideshowState, useSlideshow, // Alias for useSlideshowState (consistency)
|
|
6
|
+
} from './Slideshow';
|
|
6
7
|
// Overlay positioning components
|
|
7
8
|
export { OverlaySlot, FullOverlay, GradientOverlay, } from './OverlaySlot';
|