@thewhateverapp/tile-sdk 0.17.16 → 0.18.0

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 CHANGED
@@ -1,4 +1,5 @@
1
- export { TileProvider } from './react/TileProvider.js';
1
+ export { TileProvider, TileContext } from './react/TileProvider.js';
2
+ export type { TileContextValue } from './react/TileProvider.js';
2
3
  export { useTile } from './react/useTile.js';
3
4
  export { useTileNavigation } from './react/useTileNavigation.js';
4
5
  export { useKeyboard } from './react/useKeyboard.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C,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,0BAA0B,CAAC;AAClC,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,0BAA0B,CAAC;AAGlC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACnE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGrH,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAGtE,cAAc,kBAAkB,CAAC;AAGjC,cAAc,YAAY,CAAC;AAG3B,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACpE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C,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,0BAA0B,CAAC;AAClC,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,0BAA0B,CAAC;AAGlC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACnE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGrH,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAGtE,cAAc,kBAAkB,CAAC;AAGjC,cAAc,YAAY,CAAC;AAG3B,cAAc,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // React components and hooks
2
- export { TileProvider } from './react/TileProvider.js';
2
+ export { TileProvider, TileContext } from './react/TileProvider.js';
3
3
  export { useTile } from './react/useTile.js';
4
4
  export { useTileNavigation } from './react/useTileNavigation.js';
5
5
  export { useKeyboard } from './react/useKeyboard.js';
@@ -17,7 +17,7 @@
17
17
  *
18
18
  * File path: src/app/(slideshow)/layout.tsx
19
19
  */
20
- export declare const slideshowLayoutTemplate = "'use client';\n\nimport { Slideshow } from '@thewhateverapp/tile-sdk';\n\n// Slideshow configuration injected at generation time\nconst SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;\n\nexport default function SlideshowLayout({ children }: { children: React.ReactNode }) {\n return (\n <Slideshow\n images={SLIDESHOW_CONFIG.images}\n autoAdvance={SLIDESHOW_CONFIG.autoAdvance}\n intervalMs={SLIDESHOW_CONFIG.intervalMs}\n transition={SLIDESHOW_CONFIG.transition}\n showDots={false}\n showArrows={false}\n className=\"w-full h-full\"\n >\n {/* Children are the route-specific overlays */}\n {children}\n </Slideshow>\n );\n}\n";
20
+ export declare const slideshowLayoutTemplate = "'use client';\n\nimport { Slideshow, TileProvider } from '@thewhateverapp/tile-sdk';\n\n// Slideshow configuration injected at generation time\nconst SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;\n\nexport default function SlideshowLayout({ children }: { children: React.ReactNode }) {\n return (\n <TileProvider>\n <Slideshow\n images={SLIDESHOW_CONFIG.images}\n autoAdvance={SLIDESHOW_CONFIG.autoAdvance}\n intervalMs={SLIDESHOW_CONFIG.intervalMs}\n transition={SLIDESHOW_CONFIG.transition}\n showDots={false}\n showArrows={false}\n className=\"w-full h-full\"\n >\n {/* Children are the route-specific overlays */}\n {children}\n </Slideshow>\n </TileProvider>\n );\n}\n";
21
21
  /**
22
22
  * Slideshow Tile Overlay Template
23
23
  *
@@ -44,7 +44,7 @@ export declare const slideshowPageOverlayTemplate = "'use client';\n\nimport { u
44
44
  *
45
45
  * File path: src/app/_preview/tile.tsx
46
46
  */
47
- export declare const slideshowPreviewTileTemplate = "'use client';\n\nimport { Slideshow, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';\n\n// Slideshow configuration injected at generation time\nconst SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;\n\nfunction TileOverlay() {\n const tile = useTile();\n const { state, controls } = useSlideshowState();\n\n return (\n <>\n <div className=\"absolute top-3 right-3 z-20 pointer-events-auto\">\n <button\n onClick={() => tile.navigateToPage()}\n className=\"bg-black/40 backdrop-blur-sm p-2 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Expand to full view\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4\" />\n </svg>\n </button>\n </div>\n\n {state.totalSlides > 1 && (\n <div className=\"absolute top-3 left-3 z-10 pointer-events-none\">\n <div className=\"bg-black/50 backdrop-blur-sm px-2 py-1 rounded text-xs text-white font-medium\">\n {state.currentIndex + 1} / {state.totalSlides}\n </div>\n </div>\n )}\n\n {state.totalSlides > 1 && (\n <div className=\"absolute bottom-3 left-1/2 -translate-x-1/2 z-20 pointer-events-auto\">\n <div className=\"flex gap-1.5\">\n {state.images.map((_, index) => (\n <button\n key={index}\n onClick={() => controls.goTo(index)}\n disabled={state.isTransitioning}\n className={`w-2 h-2 rounded-full transition-colors ${\n index === state.currentIndex\n ? 'bg-white'\n : 'bg-white/40 hover:bg-white/60'\n }`}\n aria-label={`Go to slide ${index + 1}`}\n />\n ))}\n </div>\n </div>\n )}\n\n {state.images[state.currentIndex]?.caption && (\n <div className=\"absolute bottom-10 left-3 right-3 z-10 pointer-events-none\">\n <div className=\"bg-black/50 backdrop-blur-sm px-3 py-2 rounded text-white text-sm\">\n {state.images[state.currentIndex].caption}\n </div>\n </div>\n )}\n </>\n );\n}\n\nexport default function PreviewTile() {\n return (\n <Slideshow\n images={SLIDESHOW_CONFIG.images}\n autoAdvance={SLIDESHOW_CONFIG.autoAdvance}\n intervalMs={SLIDESHOW_CONFIG.intervalMs}\n transition={SLIDESHOW_CONFIG.transition}\n showDots={false}\n showArrows={false}\n className=\"w-full h-full\"\n >\n <TileOverlay />\n </Slideshow>\n );\n}\n";
47
+ export declare const slideshowPreviewTileTemplate = "'use client';\n\nimport { Slideshow, TileProvider, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';\n\n// Slideshow configuration injected at generation time\nconst SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;\n\nfunction TileOverlay() {\n const tile = useTile();\n const { state, controls } = useSlideshowState();\n\n return (\n <>\n <div className=\"absolute top-3 right-3 z-20 pointer-events-auto\">\n <button\n onClick={() => tile.navigateToPage()}\n className=\"bg-black/40 backdrop-blur-sm p-2 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Expand to full view\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4\" />\n </svg>\n </button>\n </div>\n\n {state.totalSlides > 1 && (\n <div className=\"absolute top-3 left-3 z-10 pointer-events-none\">\n <div className=\"bg-black/50 backdrop-blur-sm px-2 py-1 rounded text-xs text-white font-medium\">\n {state.currentIndex + 1} / {state.totalSlides}\n </div>\n </div>\n )}\n\n {state.totalSlides > 1 && (\n <div className=\"absolute bottom-3 left-1/2 -translate-x-1/2 z-20 pointer-events-auto\">\n <div className=\"flex gap-1.5\">\n {state.images.map((_, index) => (\n <button\n key={index}\n onClick={() => controls.goTo(index)}\n disabled={state.isTransitioning}\n className={`w-2 h-2 rounded-full transition-colors ${\n index === state.currentIndex\n ? 'bg-white'\n : 'bg-white/40 hover:bg-white/60'\n }`}\n aria-label={`Go to slide ${index + 1}`}\n />\n ))}\n </div>\n </div>\n )}\n\n {state.images[state.currentIndex]?.caption && (\n <div className=\"absolute bottom-10 left-3 right-3 z-10 pointer-events-none\">\n <div className=\"bg-black/50 backdrop-blur-sm px-3 py-2 rounded text-white text-sm\">\n {state.images[state.currentIndex].caption}\n </div>\n </div>\n )}\n </>\n );\n}\n\nexport default function PreviewTile() {\n return (\n <TileProvider>\n <Slideshow\n images={SLIDESHOW_CONFIG.images}\n autoAdvance={SLIDESHOW_CONFIG.autoAdvance}\n intervalMs={SLIDESHOW_CONFIG.intervalMs}\n transition={SLIDESHOW_CONFIG.transition}\n showDots={false}\n showArrows={false}\n className=\"w-full h-full\"\n >\n <TileOverlay />\n </Slideshow>\n </TileProvider>\n );\n}\n";
48
48
  /**
49
49
  * Slideshow Preview Entry - Page
50
50
  *
@@ -53,5 +53,5 @@ export declare const slideshowPreviewTileTemplate = "'use client';\n\nimport { S
53
53
  *
54
54
  * File path: src/app/_preview/page.tsx
55
55
  */
56
- export declare const slideshowPreviewPageTemplate = "'use client';\n\nimport { Slideshow, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';\nimport { useState, useEffect, useCallback } from 'react';\n\n// Slideshow configuration injected at generation time\nconst SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;\n\nfunction PageOverlay() {\n const tile = useTile();\n const { state, controls } = useSlideshowState();\n const [showControls, setShowControls] = useState(true);\n const [hideTimeout, setHideTimeout] = useState<NodeJS.Timeout | null>(null);\n\n const resetHideTimer = useCallback(() => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n setShowControls(true);\n\n if (!state.isPaused) {\n const timeout = setTimeout(() => {\n setShowControls(false);\n }, 3000);\n setHideTimeout(timeout);\n }\n }, [state.isPaused, hideTimeout]);\n\n useEffect(() => {\n if (state.isPaused) {\n setShowControls(true);\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n setHideTimeout(null);\n }\n } else {\n resetHideTimer();\n }\n }, [state.isPaused]);\n\n useEffect(() => {\n return () => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n };\n }, [hideTimeout]);\n\n const handleToggleControls = useCallback((e: React.MouseEvent | React.TouchEvent) => {\n const target = e.target as HTMLElement;\n if (target.closest('button, .controls-area')) {\n return;\n }\n e.preventDefault();\n\n if (showControls) {\n setShowControls(false);\n } else {\n resetHideTimer();\n }\n }, [showControls, resetHideTimer]);\n\n const handleMouseMove = useCallback(() => {\n if (!state.isPaused) {\n resetHideTimer();\n }\n }, [state.isPaused, resetHideTimer]);\n\n return (\n <div\n className=\"absolute inset-0 z-20 pointer-events-auto\"\n onClick={handleToggleControls}\n onTouchEnd={handleToggleControls}\n onMouseMove={handleMouseMove}\n >\n <div\n className={`controls-area transition-opacity duration-300 ${\n showControls ? 'opacity-100' : 'opacity-0 pointer-events-none'\n }`}\n >\n <div className=\"absolute top-0 left-0 right-0 h-20 bg-gradient-to-b from-black/60 to-transparent pointer-events-none\" />\n\n {state.totalSlides > 1 && (\n <div className=\"absolute top-4 right-4 z-10 pointer-events-auto\">\n <div className=\"bg-black/50 backdrop-blur-sm px-3 py-1.5 rounded text-sm text-white font-medium\">\n {state.currentIndex + 1} / {state.totalSlides}\n </div>\n </div>\n )}\n\n {state.totalSlides > 1 && (\n <div className=\"absolute top-4 left-4 z-20 pointer-events-auto\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.toggle();\n }}\n className=\"bg-black/40 backdrop-blur-sm p-2.5 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label={state.isPaused ? 'Resume slideshow' : 'Pause slideshow'}\n >\n {state.isPaused ? (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n ) : (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n )}\n </button>\n </div>\n )}\n\n <div className=\"absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-t from-black/60 to-transparent pointer-events-none\" />\n\n {state.images[state.currentIndex]?.caption && (\n <div className=\"absolute bottom-16 left-4 right-16 z-10 pointer-events-none\">\n <div className=\"text-white\">\n <p className=\"text-base drop-shadow-lg\">{state.images[state.currentIndex].caption}</p>\n {state.images[state.currentIndex]?.alt && (\n <p className=\"text-sm text-white/70 mt-1 drop-shadow-lg\">{state.images[state.currentIndex].alt}</p>\n )}\n </div>\n </div>\n )}\n\n <div className=\"absolute bottom-4 right-4 z-20 pointer-events-auto\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n tile.navigateToTile();\n }}\n className=\"bg-black/40 backdrop-blur-sm p-2.5 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Minimize to tile\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M20 12H4\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nexport default function PreviewPage() {\n return (\n <Slideshow\n images={SLIDESHOW_CONFIG.images}\n autoAdvance={SLIDESHOW_CONFIG.autoAdvance}\n intervalMs={SLIDESHOW_CONFIG.intervalMs}\n transition={SLIDESHOW_CONFIG.transition}\n showDots={true}\n showArrows={true}\n swipeable={true}\n className=\"w-full h-full object-cover\"\n >\n <PageOverlay />\n </Slideshow>\n );\n}\n";
56
+ export declare const slideshowPreviewPageTemplate = "'use client';\n\nimport { Slideshow, TileProvider, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';\nimport { useState, useEffect, useCallback } from 'react';\n\n// Slideshow configuration injected at generation time\nconst SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;\n\nfunction PageOverlay() {\n const tile = useTile();\n const { state, controls } = useSlideshowState();\n const [showControls, setShowControls] = useState(true);\n const [hideTimeout, setHideTimeout] = useState<NodeJS.Timeout | null>(null);\n\n const resetHideTimer = useCallback(() => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n setShowControls(true);\n\n if (!state.isPaused) {\n const timeout = setTimeout(() => {\n setShowControls(false);\n }, 3000);\n setHideTimeout(timeout);\n }\n }, [state.isPaused, hideTimeout]);\n\n useEffect(() => {\n if (state.isPaused) {\n setShowControls(true);\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n setHideTimeout(null);\n }\n } else {\n resetHideTimer();\n }\n }, [state.isPaused]);\n\n useEffect(() => {\n return () => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n };\n }, [hideTimeout]);\n\n const handleToggleControls = useCallback((e: React.MouseEvent | React.TouchEvent) => {\n const target = e.target as HTMLElement;\n if (target.closest('button, .controls-area')) {\n return;\n }\n e.preventDefault();\n\n if (showControls) {\n setShowControls(false);\n } else {\n resetHideTimer();\n }\n }, [showControls, resetHideTimer]);\n\n const handleMouseMove = useCallback(() => {\n if (!state.isPaused) {\n resetHideTimer();\n }\n }, [state.isPaused, resetHideTimer]);\n\n return (\n <div\n className=\"absolute inset-0 z-20 pointer-events-auto\"\n onClick={handleToggleControls}\n onTouchEnd={handleToggleControls}\n onMouseMove={handleMouseMove}\n >\n <div\n className={`controls-area transition-opacity duration-300 ${\n showControls ? 'opacity-100' : 'opacity-0 pointer-events-none'\n }`}\n >\n <div className=\"absolute top-0 left-0 right-0 h-20 bg-gradient-to-b from-black/60 to-transparent pointer-events-none\" />\n\n {state.totalSlides > 1 && (\n <div className=\"absolute top-4 right-4 z-10 pointer-events-auto\">\n <div className=\"bg-black/50 backdrop-blur-sm px-3 py-1.5 rounded text-sm text-white font-medium\">\n {state.currentIndex + 1} / {state.totalSlides}\n </div>\n </div>\n )}\n\n {state.totalSlides > 1 && (\n <div className=\"absolute top-4 left-4 z-20 pointer-events-auto\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.toggle();\n }}\n className=\"bg-black/40 backdrop-blur-sm p-2.5 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label={state.isPaused ? 'Resume slideshow' : 'Pause slideshow'}\n >\n {state.isPaused ? (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n ) : (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n )}\n </button>\n </div>\n )}\n\n <div className=\"absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-t from-black/60 to-transparent pointer-events-none\" />\n\n {state.images[state.currentIndex]?.caption && (\n <div className=\"absolute bottom-16 left-4 right-16 z-10 pointer-events-none\">\n <div className=\"text-white\">\n <p className=\"text-base drop-shadow-lg\">{state.images[state.currentIndex].caption}</p>\n {state.images[state.currentIndex]?.alt && (\n <p className=\"text-sm text-white/70 mt-1 drop-shadow-lg\">{state.images[state.currentIndex].alt}</p>\n )}\n </div>\n </div>\n )}\n\n <div className=\"absolute bottom-4 right-4 z-20 pointer-events-auto\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n tile.navigateToTile();\n }}\n className=\"bg-black/40 backdrop-blur-sm p-2.5 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Minimize to tile\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M20 12H4\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nexport default function PreviewPage() {\n return (\n <TileProvider>\n <Slideshow\n images={SLIDESHOW_CONFIG.images}\n autoAdvance={SLIDESHOW_CONFIG.autoAdvance}\n intervalMs={SLIDESHOW_CONFIG.intervalMs}\n transition={SLIDESHOW_CONFIG.transition}\n showDots={true}\n showArrows={true}\n swipeable={true}\n className=\"w-full h-full object-cover\"\n >\n <PageOverlay />\n </Slideshow>\n </TileProvider>\n );\n}\n";
57
57
  //# sourceMappingURL=layout.tsx.template.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"layout.tsx.template.d.ts","sourceRoot":"","sources":["../../../src/templates/slideshow/layout.tsx.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,wqBAuBnC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,0mGA0FxC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,m/LAmLxC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,qwFA+ExC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,myKAiKxC,CAAC"}
1
+ {"version":3,"file":"layout.tsx.template.d.ts","sourceRoot":"","sources":["../../../src/templates/slideshow/layout.tsx.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,uvBAyBnC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,0mGA0FxC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,m/LAmLxC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,k1FAiFxC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,82KAmKxC,CAAC"}
@@ -19,25 +19,27 @@
19
19
  */
20
20
  export const slideshowLayoutTemplate = `'use client';
21
21
 
22
- import { Slideshow } from '@thewhateverapp/tile-sdk';
22
+ import { Slideshow, TileProvider } from '@thewhateverapp/tile-sdk';
23
23
 
24
24
  // Slideshow configuration injected at generation time
25
25
  const SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;
26
26
 
27
27
  export default function SlideshowLayout({ children }: { children: React.ReactNode }) {
28
28
  return (
29
- <Slideshow
30
- images={SLIDESHOW_CONFIG.images}
31
- autoAdvance={SLIDESHOW_CONFIG.autoAdvance}
32
- intervalMs={SLIDESHOW_CONFIG.intervalMs}
33
- transition={SLIDESHOW_CONFIG.transition}
34
- showDots={false}
35
- showArrows={false}
36
- className="w-full h-full"
37
- >
38
- {/* Children are the route-specific overlays */}
39
- {children}
40
- </Slideshow>
29
+ <TileProvider>
30
+ <Slideshow
31
+ images={SLIDESHOW_CONFIG.images}
32
+ autoAdvance={SLIDESHOW_CONFIG.autoAdvance}
33
+ intervalMs={SLIDESHOW_CONFIG.intervalMs}
34
+ transition={SLIDESHOW_CONFIG.transition}
35
+ showDots={false}
36
+ showArrows={false}
37
+ className="w-full h-full"
38
+ >
39
+ {/* Children are the route-specific overlays */}
40
+ {children}
41
+ </Slideshow>
42
+ </TileProvider>
41
43
  );
42
44
  }
43
45
  `;
@@ -338,7 +340,7 @@ function PageOverlay() {
338
340
  */
339
341
  export const slideshowPreviewTileTemplate = `'use client';
340
342
 
341
- import { Slideshow, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';
343
+ import { Slideshow, TileProvider, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';
342
344
 
343
345
  // Slideshow configuration injected at generation time
344
346
  const SLIDESHOW_CONFIG = __SLIDESHOW_CONFIG__;
@@ -402,17 +404,19 @@ function TileOverlay() {
402
404
 
403
405
  export default function PreviewTile() {
404
406
  return (
405
- <Slideshow
406
- images={SLIDESHOW_CONFIG.images}
407
- autoAdvance={SLIDESHOW_CONFIG.autoAdvance}
408
- intervalMs={SLIDESHOW_CONFIG.intervalMs}
409
- transition={SLIDESHOW_CONFIG.transition}
410
- showDots={false}
411
- showArrows={false}
412
- className="w-full h-full"
413
- >
414
- <TileOverlay />
415
- </Slideshow>
407
+ <TileProvider>
408
+ <Slideshow
409
+ images={SLIDESHOW_CONFIG.images}
410
+ autoAdvance={SLIDESHOW_CONFIG.autoAdvance}
411
+ intervalMs={SLIDESHOW_CONFIG.intervalMs}
412
+ transition={SLIDESHOW_CONFIG.transition}
413
+ showDots={false}
414
+ showArrows={false}
415
+ className="w-full h-full"
416
+ >
417
+ <TileOverlay />
418
+ </Slideshow>
419
+ </TileProvider>
416
420
  );
417
421
  }
418
422
  `;
@@ -426,7 +430,7 @@ export default function PreviewTile() {
426
430
  */
427
431
  export const slideshowPreviewPageTemplate = `'use client';
428
432
 
429
- import { Slideshow, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';
433
+ import { Slideshow, TileProvider, useSlideshowState, useTile } from '@thewhateverapp/tile-sdk';
430
434
  import { useState, useEffect, useCallback } from 'react';
431
435
 
432
436
  // Slideshow configuration injected at generation time
@@ -571,18 +575,20 @@ function PageOverlay() {
571
575
 
572
576
  export default function PreviewPage() {
573
577
  return (
574
- <Slideshow
575
- images={SLIDESHOW_CONFIG.images}
576
- autoAdvance={SLIDESHOW_CONFIG.autoAdvance}
577
- intervalMs={SLIDESHOW_CONFIG.intervalMs}
578
- transition={SLIDESHOW_CONFIG.transition}
579
- showDots={true}
580
- showArrows={true}
581
- swipeable={true}
578
+ <TileProvider>
579
+ <Slideshow
580
+ images={SLIDESHOW_CONFIG.images}
581
+ autoAdvance={SLIDESHOW_CONFIG.autoAdvance}
582
+ intervalMs={SLIDESHOW_CONFIG.intervalMs}
583
+ transition={SLIDESHOW_CONFIG.transition}
584
+ showDots={true}
585
+ showArrows={true}
586
+ swipeable={true}
582
587
  className="w-full h-full object-cover"
583
588
  >
584
- <PageOverlay />
585
- </Slideshow>
589
+ <PageOverlay />
590
+ </Slideshow>
591
+ </TileProvider>
586
592
  );
587
593
  }
588
594
  `;
@@ -17,7 +17,7 @@
17
17
  *
18
18
  * File path: src/app/(video)/layout.tsx
19
19
  */
20
- export declare const videoLayoutTemplate = "'use client';\n\nimport { VideoPlayer } from '@thewhateverapp/tile-sdk';\n\nexport default function VideoLayout({ children }: { children: React.ReactNode }) {\n return (\n <VideoPlayer className=\"w-full h-full\">\n {/* Children are the route-specific overlays */}\n {children}\n </VideoPlayer>\n );\n}\n";
20
+ export declare const videoLayoutTemplate = "'use client';\n\nimport { VideoPlayer, TileProvider } from '@thewhateverapp/tile-sdk';\n\nexport default function VideoLayout({ children }: { children: React.ReactNode }) {\n return (\n <TileProvider>\n <VideoPlayer className=\"w-full h-full\">\n {/* Children are the route-specific overlays */}\n {children}\n </VideoPlayer>\n </TileProvider>\n );\n}\n";
21
21
  /**
22
22
  * Video Tile Overlay Template
23
23
  *
@@ -44,7 +44,7 @@ export declare const videoPageOverlayTemplate = "'use client';\n\nimport { useSt
44
44
  *
45
45
  * File path: src/app/_preview/tile.tsx
46
46
  */
47
- export declare const videoPreviewTileTemplate = "'use client';\n\nimport { VideoPlayer, useVideoState, useTile } from '@thewhateverapp/tile-sdk';\nimport { useState, useEffect, useRef, useCallback } from 'react';\n\nfunction formatTime(seconds: number): string {\n if (!seconds || !isFinite(seconds)) return '0:00';\n const mins = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nconst CONTROLS_HIDE_DELAY = 3000;\n\nfunction TileOverlay() {\n const tile = useTile();\n const { state, controls } = useVideoState();\n\n const [hasInteracted, setHasInteracted] = useState(false);\n const [controlsVisible, setControlsVisible] = useState(false);\n const hideTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n const showControls = useCallback(() => {\n setHasInteracted(true);\n setControlsVisible(true);\n\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n\n if (state.isPlaying) {\n hideTimeoutRef.current = setTimeout(() => {\n setControlsVisible(false);\n }, CONTROLS_HIDE_DELAY);\n }\n }, [state.isPlaying]);\n\n useEffect(() => {\n if (!state.isPlaying && hasInteracted) {\n setControlsVisible(true);\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n }\n }, [state.isPlaying, hasInteracted]);\n\n useEffect(() => {\n return () => {\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n };\n }, []);\n\n const handleInteraction = useCallback(() => {\n if (!hasInteracted) {\n showControls();\n controls.toggle();\n } else if (controlsVisible) {\n controls.toggle();\n showControls();\n } else {\n showControls();\n }\n }, [hasInteracted, controlsVisible, showControls, controls]);\n\n const showCenterPlayButton = hasInteracted && !state.isPlaying && !state.isLoading && controlsVisible;\n const showBottomControls = hasInteracted && controlsVisible;\n\n return (\n <>\n <div\n className=\"absolute inset-0 z-5 pointer-events-auto cursor-pointer\"\n onClick={handleInteraction}\n onMouseMove={() => hasInteracted && showControls()}\n />\n\n <div className=\"absolute top-3 right-3 z-20 pointer-events-auto\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n tile.navigateToPage();\n }}\n className=\"bg-black/40 backdrop-blur-sm p-2 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Expand to full view\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4\" />\n </svg>\n </button>\n </div>\n\n <div\n className={`absolute inset-0 flex items-center justify-center z-10 pointer-events-none transition-opacity duration-300 ${\n showCenterPlayButton ? 'opacity-100' : 'opacity-0'\n }`}\n >\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.play();\n showControls();\n }}\n className=\"bg-black/50 backdrop-blur-sm p-4 rounded-full text-white hover:bg-black/70 transition-colors pointer-events-auto\"\n aria-label=\"Play video\"\n style={{ pointerEvents: showCenterPlayButton ? 'auto' : 'none' }}\n >\n <svg className=\"w-12 h-12\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </button>\n </div>\n\n <div\n className={`absolute bottom-0 left-0 right-0 h-24 bg-gradient-to-t from-black/80 to-transparent pointer-events-none transition-opacity duration-300 ${\n showBottomControls ? 'opacity-100' : 'opacity-0'\n }`}\n />\n\n <div\n className={`absolute bottom-3 left-3 right-3 z-20 transition-opacity duration-300 ${\n showBottomControls ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'\n }`}\n >\n <div\n className=\"h-1 bg-white/30 rounded-full overflow-hidden mb-2 cursor-pointer\"\n onClick={(e) => {\n e.stopPropagation();\n const rect = e.currentTarget.getBoundingClientRect();\n const percent = (e.clientX - rect.left) / rect.width;\n controls.seek(percent * state.duration);\n showControls();\n }}\n >\n <div\n className=\"h-full bg-white rounded-full transition-all duration-100\"\n style={{ width: `${(state.currentTime / state.duration) * 100 || 0}%` }}\n />\n </div>\n\n <div className=\"flex items-center justify-between text-white text-xs\">\n <div className=\"flex items-center gap-2\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.toggle();\n showControls();\n }}\n className=\"p-1 hover:bg-white/20 rounded transition-colors\"\n aria-label={state.isPlaying ? 'Pause' : 'Play'}\n >\n {state.isPlaying ? (\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n ) : (\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n )}\n </button>\n <span className=\"font-mono\">\n {formatTime(state.currentTime)} / {formatTime(state.duration)}\n </span>\n </div>\n\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.setMuted(!state.muted);\n showControls();\n }}\n className=\"p-1 hover:bg-white/20 rounded transition-colors\"\n aria-label={state.muted ? 'Unmute' : 'Mute'}\n >\n {state.muted ? (\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z\" />\n </svg>\n ) : (\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z\" />\n </svg>\n )}\n </button>\n </div>\n </div>\n </>\n );\n}\n\nexport default function PreviewTile() {\n return (\n <VideoPlayer className=\"w-full h-full\">\n <TileOverlay />\n </VideoPlayer>\n );\n}\n";
47
+ export declare const videoPreviewTileTemplate = "'use client';\n\nimport { VideoPlayer, TileProvider, useVideoState, useTile } from '@thewhateverapp/tile-sdk';\nimport { useState, useEffect, useRef, useCallback } from 'react';\n\nfunction formatTime(seconds: number): string {\n if (!seconds || !isFinite(seconds)) return '0:00';\n const mins = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nconst CONTROLS_HIDE_DELAY = 3000;\n\nfunction TileOverlay() {\n const tile = useTile();\n const { state, controls } = useVideoState();\n\n const [hasInteracted, setHasInteracted] = useState(false);\n const [controlsVisible, setControlsVisible] = useState(false);\n const hideTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n const showControls = useCallback(() => {\n setHasInteracted(true);\n setControlsVisible(true);\n\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n\n if (state.isPlaying) {\n hideTimeoutRef.current = setTimeout(() => {\n setControlsVisible(false);\n }, CONTROLS_HIDE_DELAY);\n }\n }, [state.isPlaying]);\n\n useEffect(() => {\n if (!state.isPlaying && hasInteracted) {\n setControlsVisible(true);\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n }\n }, [state.isPlaying, hasInteracted]);\n\n useEffect(() => {\n return () => {\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n };\n }, []);\n\n const handleInteraction = useCallback(() => {\n if (!hasInteracted) {\n showControls();\n controls.toggle();\n } else if (controlsVisible) {\n controls.toggle();\n showControls();\n } else {\n showControls();\n }\n }, [hasInteracted, controlsVisible, showControls, controls]);\n\n const showCenterPlayButton = hasInteracted && !state.isPlaying && !state.isLoading && controlsVisible;\n const showBottomControls = hasInteracted && controlsVisible;\n\n return (\n <>\n <div\n className=\"absolute inset-0 z-5 pointer-events-auto cursor-pointer\"\n onClick={handleInteraction}\n onMouseMove={() => hasInteracted && showControls()}\n />\n\n <div className=\"absolute top-3 right-3 z-20 pointer-events-auto\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n tile.navigateToPage();\n }}\n className=\"bg-black/40 backdrop-blur-sm p-2 rounded-full text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Expand to full view\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4\" />\n </svg>\n </button>\n </div>\n\n <div\n className={`absolute inset-0 flex items-center justify-center z-10 pointer-events-none transition-opacity duration-300 ${\n showCenterPlayButton ? 'opacity-100' : 'opacity-0'\n }`}\n >\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.play();\n showControls();\n }}\n className=\"bg-black/50 backdrop-blur-sm p-4 rounded-full text-white hover:bg-black/70 transition-colors pointer-events-auto\"\n aria-label=\"Play video\"\n style={{ pointerEvents: showCenterPlayButton ? 'auto' : 'none' }}\n >\n <svg className=\"w-12 h-12\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </button>\n </div>\n\n <div\n className={`absolute bottom-0 left-0 right-0 h-24 bg-gradient-to-t from-black/80 to-transparent pointer-events-none transition-opacity duration-300 ${\n showBottomControls ? 'opacity-100' : 'opacity-0'\n }`}\n />\n\n <div\n className={`absolute bottom-3 left-3 right-3 z-20 transition-opacity duration-300 ${\n showBottomControls ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'\n }`}\n >\n <div\n className=\"h-1 bg-white/30 rounded-full overflow-hidden mb-2 cursor-pointer\"\n onClick={(e) => {\n e.stopPropagation();\n const rect = e.currentTarget.getBoundingClientRect();\n const percent = (e.clientX - rect.left) / rect.width;\n controls.seek(percent * state.duration);\n showControls();\n }}\n >\n <div\n className=\"h-full bg-white rounded-full transition-all duration-100\"\n style={{ width: `${(state.currentTime / state.duration) * 100 || 0}%` }}\n />\n </div>\n\n <div className=\"flex items-center justify-between text-white text-xs\">\n <div className=\"flex items-center gap-2\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.toggle();\n showControls();\n }}\n className=\"p-1 hover:bg-white/20 rounded transition-colors\"\n aria-label={state.isPlaying ? 'Pause' : 'Play'}\n >\n {state.isPlaying ? (\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n ) : (\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n )}\n </button>\n <span className=\"font-mono\">\n {formatTime(state.currentTime)} / {formatTime(state.duration)}\n </span>\n </div>\n\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.setMuted(!state.muted);\n showControls();\n }}\n className=\"p-1 hover:bg-white/20 rounded transition-colors\"\n aria-label={state.muted ? 'Unmute' : 'Mute'}\n >\n {state.muted ? (\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z\" />\n </svg>\n ) : (\n <svg className=\"w-4 h-4\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z\" />\n </svg>\n )}\n </button>\n </div>\n </div>\n </>\n );\n}\n\nexport default function PreviewTile() {\n return (\n <TileProvider>\n <VideoPlayer className=\"w-full h-full\">\n <TileOverlay />\n </VideoPlayer>\n </TileProvider>\n );\n}\n";
48
48
  /**
49
49
  * Video Preview Entry - Page
50
50
  *
@@ -53,5 +53,5 @@ export declare const videoPreviewTileTemplate = "'use client';\n\nimport { Video
53
53
  *
54
54
  * File path: src/app/_preview/page.tsx
55
55
  */
56
- export declare const videoPreviewPageTemplate = "'use client';\n\nimport { VideoPlayer, useVideoState, useTile } from '@thewhateverapp/tile-sdk';\nimport { useState, useEffect, useCallback } from 'react';\n\nfunction formatTime(seconds: number): string {\n if (!seconds || !isFinite(seconds)) return '0:00';\n const mins = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nfunction PageOverlay() {\n const tile = useTile();\n const { state, controls } = useVideoState();\n const [showControls, setShowControls] = useState(true);\n const [hideTimeout, setHideTimeout] = useState<NodeJS.Timeout | null>(null);\n\n const resetHideTimer = useCallback(() => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n setShowControls(true);\n\n if (state.isPlaying) {\n const timeout = setTimeout(() => {\n setShowControls(false);\n }, 3000);\n setHideTimeout(timeout);\n }\n }, [state.isPlaying, hideTimeout]);\n\n useEffect(() => {\n if (!state.isPlaying) {\n setShowControls(true);\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n setHideTimeout(null);\n }\n } else {\n resetHideTimer();\n }\n }, [state.isPlaying]);\n\n useEffect(() => {\n return () => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n };\n }, [hideTimeout]);\n\n const handleToggleControls = useCallback((e: React.MouseEvent | React.TouchEvent) => {\n const target = e.target as HTMLElement;\n if (target.closest('button, .controls-area')) {\n return;\n }\n e.preventDefault();\n\n if (showControls) {\n setShowControls(false);\n } else {\n resetHideTimer();\n }\n }, [showControls, resetHideTimer]);\n\n const handleMouseMove = useCallback(() => {\n if (state.isPlaying) {\n resetHideTimer();\n }\n }, [state.isPlaying, resetHideTimer]);\n\n return (\n <div\n className=\"absolute inset-0 z-20 pointer-events-auto\"\n onClick={handleToggleControls}\n onTouchEnd={handleToggleControls}\n onMouseMove={handleMouseMove}\n >\n {!state.isPlaying && !state.isLoading && (\n <div className=\"absolute inset-0 flex items-center justify-center pointer-events-auto\">\n <button\n onClick={controls.play}\n className=\"bg-black/50 backdrop-blur-sm p-6 rounded-full text-white hover:bg-black/70 transition-colors\"\n aria-label=\"Play video\"\n >\n <svg className=\"w-16 h-16\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </button>\n </div>\n )}\n\n <div\n className={`controls-area absolute bottom-0 left-0 right-0 transition-opacity duration-300 ${\n showControls ? 'opacity-100' : 'opacity-0 pointer-events-none'\n }`}\n >\n <div className=\"absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-t from-black/80 to-transparent pointer-events-none\" />\n\n <div className=\"absolute bottom-4 left-4 right-4 z-20 pointer-events-auto\">\n <div\n className=\"h-1.5 bg-white/30 rounded-full overflow-hidden mb-3 cursor-pointer group hover:h-2 transition-all\"\n onClick={(e) => {\n e.stopPropagation();\n const rect = e.currentTarget.getBoundingClientRect();\n const percent = (e.clientX - rect.left) / rect.width;\n controls.seek(percent * state.duration);\n resetHideTimer();\n }}\n >\n <div\n className=\"h-full bg-white rounded-full transition-all duration-100 group-hover:bg-blue-400\"\n style={{ width: `${(state.currentTime / state.duration) * 100 || 0}%` }}\n />\n </div>\n\n <div className=\"flex items-center justify-between text-white\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.toggle();\n }}\n className=\"p-2 hover:bg-white/20 rounded-full transition-colors\"\n aria-label={state.isPlaying ? 'Pause' : 'Play'}\n >\n {state.isPlaying ? (\n <svg className=\"w-6 h-6\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n ) : (\n <svg className=\"w-6 h-6\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n )}\n </button>\n\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.setMuted(!state.muted);\n resetHideTimer();\n }}\n className=\"p-2 hover:bg-white/20 rounded-full transition-colors\"\n aria-label={state.muted ? 'Unmute' : 'Mute'}\n >\n {state.muted ? (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z\" />\n </svg>\n ) : (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z\" />\n </svg>\n )}\n </button>\n\n <span className=\"text-sm font-mono\">\n {formatTime(state.currentTime)} / {formatTime(state.duration)}\n </span>\n </div>\n\n <button\n onClick={(e) => {\n e.stopPropagation();\n tile.navigateToTile();\n }}\n className=\"p-2 hover:bg-white/20 rounded-full transition-colors\"\n aria-label=\"Minimize to tile\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M20 12H4\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nexport default function PreviewPage() {\n return (\n <VideoPlayer className=\"w-full h-full\">\n <PageOverlay />\n </VideoPlayer>\n );\n}\n";
56
+ export declare const videoPreviewPageTemplate = "'use client';\n\nimport { VideoPlayer, TileProvider, useVideoState, useTile } from '@thewhateverapp/tile-sdk';\nimport { useState, useEffect, useCallback } from 'react';\n\nfunction formatTime(seconds: number): string {\n if (!seconds || !isFinite(seconds)) return '0:00';\n const mins = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nfunction PageOverlay() {\n const tile = useTile();\n const { state, controls } = useVideoState();\n const [showControls, setShowControls] = useState(true);\n const [hideTimeout, setHideTimeout] = useState<NodeJS.Timeout | null>(null);\n\n const resetHideTimer = useCallback(() => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n setShowControls(true);\n\n if (state.isPlaying) {\n const timeout = setTimeout(() => {\n setShowControls(false);\n }, 3000);\n setHideTimeout(timeout);\n }\n }, [state.isPlaying, hideTimeout]);\n\n useEffect(() => {\n if (!state.isPlaying) {\n setShowControls(true);\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n setHideTimeout(null);\n }\n } else {\n resetHideTimer();\n }\n }, [state.isPlaying]);\n\n useEffect(() => {\n return () => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n }\n };\n }, [hideTimeout]);\n\n const handleToggleControls = useCallback((e: React.MouseEvent | React.TouchEvent) => {\n const target = e.target as HTMLElement;\n if (target.closest('button, .controls-area')) {\n return;\n }\n e.preventDefault();\n\n if (showControls) {\n setShowControls(false);\n } else {\n resetHideTimer();\n }\n }, [showControls, resetHideTimer]);\n\n const handleMouseMove = useCallback(() => {\n if (state.isPlaying) {\n resetHideTimer();\n }\n }, [state.isPlaying, resetHideTimer]);\n\n return (\n <div\n className=\"absolute inset-0 z-20 pointer-events-auto\"\n onClick={handleToggleControls}\n onTouchEnd={handleToggleControls}\n onMouseMove={handleMouseMove}\n >\n {!state.isPlaying && !state.isLoading && (\n <div className=\"absolute inset-0 flex items-center justify-center pointer-events-auto\">\n <button\n onClick={controls.play}\n className=\"bg-black/50 backdrop-blur-sm p-6 rounded-full text-white hover:bg-black/70 transition-colors\"\n aria-label=\"Play video\"\n >\n <svg className=\"w-16 h-16\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </button>\n </div>\n )}\n\n <div\n className={`controls-area absolute bottom-0 left-0 right-0 transition-opacity duration-300 ${\n showControls ? 'opacity-100' : 'opacity-0 pointer-events-none'\n }`}\n >\n <div className=\"absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-t from-black/80 to-transparent pointer-events-none\" />\n\n <div className=\"absolute bottom-4 left-4 right-4 z-20 pointer-events-auto\">\n <div\n className=\"h-1.5 bg-white/30 rounded-full overflow-hidden mb-3 cursor-pointer group hover:h-2 transition-all\"\n onClick={(e) => {\n e.stopPropagation();\n const rect = e.currentTarget.getBoundingClientRect();\n const percent = (e.clientX - rect.left) / rect.width;\n controls.seek(percent * state.duration);\n resetHideTimer();\n }}\n >\n <div\n className=\"h-full bg-white rounded-full transition-all duration-100 group-hover:bg-blue-400\"\n style={{ width: `${(state.currentTime / state.duration) * 100 || 0}%` }}\n />\n </div>\n\n <div className=\"flex items-center justify-between text-white\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.toggle();\n }}\n className=\"p-2 hover:bg-white/20 rounded-full transition-colors\"\n aria-label={state.isPlaying ? 'Pause' : 'Play'}\n >\n {state.isPlaying ? (\n <svg className=\"w-6 h-6\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n ) : (\n <svg className=\"w-6 h-6\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n )}\n </button>\n\n <button\n onClick={(e) => {\n e.stopPropagation();\n controls.setMuted(!state.muted);\n resetHideTimer();\n }}\n className=\"p-2 hover:bg-white/20 rounded-full transition-colors\"\n aria-label={state.muted ? 'Unmute' : 'Mute'}\n >\n {state.muted ? (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z\" />\n </svg>\n ) : (\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z\" />\n </svg>\n )}\n </button>\n\n <span className=\"text-sm font-mono\">\n {formatTime(state.currentTime)} / {formatTime(state.duration)}\n </span>\n </div>\n\n <button\n onClick={(e) => {\n e.stopPropagation();\n tile.navigateToTile();\n }}\n className=\"p-2 hover:bg-white/20 rounded-full transition-colors\"\n aria-label=\"Minimize to tile\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M20 12H4\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nexport default function PreviewPage() {\n return (\n <TileProvider>\n <VideoPlayer className=\"w-full h-full\">\n <PageOverlay />\n </VideoPlayer>\n </TileProvider>\n );\n}\n";
57
57
  //# sourceMappingURL=layout.tsx.template.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"layout.tsx.template.d.ts","sourceRoot":"","sources":["../../../src/templates/video/layout.tsx.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,uUAY/B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,2mOAkMpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,+6OAyMpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,suOAsMpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,q4NA6LpC,CAAC"}
1
+ {"version":3,"file":"layout.tsx.template.d.ts","sourceRoot":"","sources":["../../../src/templates/video/layout.tsx.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,sYAc/B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,2mOAkMpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,+6OAyMpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,myOAwMpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,k8NA+LpC,CAAC"}
@@ -19,14 +19,16 @@
19
19
  */
20
20
  export const videoLayoutTemplate = `'use client';
21
21
 
22
- import { VideoPlayer } from '@thewhateverapp/tile-sdk';
22
+ import { VideoPlayer, TileProvider } from '@thewhateverapp/tile-sdk';
23
23
 
24
24
  export default function VideoLayout({ children }: { children: React.ReactNode }) {
25
25
  return (
26
- <VideoPlayer className="w-full h-full">
27
- {/* Children are the route-specific overlays */}
28
- {children}
29
- </VideoPlayer>
26
+ <TileProvider>
27
+ <VideoPlayer className="w-full h-full">
28
+ {/* Children are the route-specific overlays */}
29
+ {children}
30
+ </VideoPlayer>
31
+ </TileProvider>
30
32
  );
31
33
  }
32
34
  `;
@@ -453,7 +455,7 @@ export default PageOverlay;
453
455
  */
454
456
  export const videoPreviewTileTemplate = `'use client';
455
457
 
456
- import { VideoPlayer, useVideoState, useTile } from '@thewhateverapp/tile-sdk';
458
+ import { VideoPlayer, TileProvider, useVideoState, useTile } from '@thewhateverapp/tile-sdk';
457
459
  import { useState, useEffect, useRef, useCallback } from 'react';
458
460
 
459
461
  function formatTime(seconds: number): string {
@@ -644,9 +646,11 @@ function TileOverlay() {
644
646
 
645
647
  export default function PreviewTile() {
646
648
  return (
647
- <VideoPlayer className="w-full h-full">
648
- <TileOverlay />
649
- </VideoPlayer>
649
+ <TileProvider>
650
+ <VideoPlayer className="w-full h-full">
651
+ <TileOverlay />
652
+ </VideoPlayer>
653
+ </TileProvider>
650
654
  );
651
655
  }
652
656
  `;
@@ -660,7 +664,7 @@ export default function PreviewTile() {
660
664
  */
661
665
  export const videoPreviewPageTemplate = `'use client';
662
666
 
663
- import { VideoPlayer, useVideoState, useTile } from '@thewhateverapp/tile-sdk';
667
+ import { VideoPlayer, TileProvider, useVideoState, useTile } from '@thewhateverapp/tile-sdk';
664
668
  import { useState, useEffect, useCallback } from 'react';
665
669
 
666
670
  function formatTime(seconds: number): string {
@@ -842,9 +846,11 @@ function PageOverlay() {
842
846
 
843
847
  export default function PreviewPage() {
844
848
  return (
845
- <VideoPlayer className="w-full h-full">
846
- <PageOverlay />
847
- </VideoPlayer>
849
+ <TileProvider>
850
+ <VideoPlayer className="w-full h-full">
851
+ <PageOverlay />
852
+ </VideoPlayer>
853
+ </TileProvider>
848
854
  );
849
855
  }
850
856
  `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thewhateverapp/tile-sdk",
3
- "version": "0.17.16",
3
+ "version": "0.18.0",
4
4
  "description": "SDK for building interactive tiles on The Whatever App platform",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -9,10 +9,6 @@
9
9
  "types": "./dist/index.d.ts",
10
10
  "import": "./dist/index.js"
11
11
  },
12
- "./react": {
13
- "types": "./dist/react/index.d.ts",
14
- "import": "./dist/react/index.js"
15
- },
16
12
  "./excalibur": {
17
13
  "types": "./dist/excalibur/index.d.ts",
18
14
  "import": "./dist/excalibur/index.js"
@@ -20,22 +16,6 @@
20
16
  "./spec": {
21
17
  "types": "./dist/spec/index.d.ts",
22
18
  "import": "./dist/spec/index.js"
23
- },
24
- "./tools": {
25
- "types": "./dist/tools/index.d.ts",
26
- "import": "./dist/tools/index.js"
27
- },
28
- "./templates": {
29
- "types": "./dist/templates/index.d.ts",
30
- "import": "./dist/templates/index.js"
31
- },
32
- "./templates/video": {
33
- "types": "./dist/templates/video/index.d.ts",
34
- "import": "./dist/templates/video/index.js"
35
- },
36
- "./scene": {
37
- "types": "./dist/scene/index.d.ts",
38
- "import": "./dist/scene/index.js"
39
19
  }
40
20
  },
41
21
  "files": [