@bendyline/squisq-react 1.4.2 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +30 -3
  2. package/dist/index.d.ts +177 -28
  3. package/dist/index.js +1330 -611
  4. package/dist/index.js.map +1 -1
  5. package/dist/squisq-player.css +1 -1
  6. package/dist/squisq-player.css.map +1 -1
  7. package/dist/squisq-player.global.js +57 -37
  8. package/dist/squisq-player.global.js.map +1 -1
  9. package/dist/standalone-source.js +1 -1
  10. package/dist/styles/index.css +28 -0
  11. package/package.json +2 -2
  12. package/src/BlockRenderer.tsx +54 -17
  13. package/src/DocControlsSlideshow.tsx +222 -5
  14. package/src/DocPlayer.tsx +367 -183
  15. package/src/DocPlayerWithSidebar.tsx +4 -0
  16. package/src/DocProgressBar.tsx +40 -1
  17. package/src/LinearDocView.tsx +138 -62
  18. package/src/MarkdownRenderer.tsx +40 -97
  19. package/src/MediaClipLayer.tsx +12 -2
  20. package/src/__tests__/BlockRenderer.test.tsx +138 -8
  21. package/src/__tests__/DocControlsSlideshow.test.tsx +94 -1
  22. package/src/__tests__/DocPlayer.test.tsx +505 -0
  23. package/src/__tests__/DocProgressBar.test.tsx +28 -2
  24. package/src/__tests__/LinearDocView.test.tsx +104 -11
  25. package/src/__tests__/MapLayer.test.tsx +63 -0
  26. package/src/__tests__/MarkdownRenderer.test.tsx +16 -5
  27. package/src/__tests__/MediaClipLayer.test.tsx +70 -0
  28. package/src/__tests__/MediaContext.test.tsx +51 -0
  29. package/src/__tests__/PathLayer.test.tsx +12 -1
  30. package/src/__tests__/VideoLayer.test.tsx +94 -0
  31. package/src/__tests__/fillStyle.test.tsx +50 -2
  32. package/src/__tests__/standaloneEntry.test.tsx +103 -0
  33. package/src/__tests__/useAudioSync.test.ts +49 -0
  34. package/src/__tests__/useDocPlayback.transition.test.ts +48 -5
  35. package/src/__tests__/useViewportOrientation.test.ts +22 -0
  36. package/src/hooks/MediaContext.tsx +12 -3
  37. package/src/hooks/useAudioSync.ts +61 -12
  38. package/src/hooks/useDocPlayback.ts +40 -12
  39. package/src/hooks/useViewportOrientation.ts +2 -4
  40. package/src/index.ts +5 -2
  41. package/src/layers/ImageLayer.tsx +106 -1
  42. package/src/layers/MapLayer.tsx +7 -6
  43. package/src/layers/PathLayer.tsx +20 -11
  44. package/src/layers/ShapeLayer.tsx +33 -9
  45. package/src/layers/TextLayer.tsx +4 -3
  46. package/src/layers/TreeLayer.tsx +167 -0
  47. package/src/layers/VideoLayer.tsx +20 -6
  48. package/src/standalone-entry.tsx +91 -14
  49. package/src/styles/doc-animations.css +36 -0
  50. package/src/types.ts +13 -13
@@ -178,6 +178,26 @@
178
178
  }
179
179
  }
180
180
 
181
+ /* Portrait framing for dominant cover photos. Animating object-position scans
182
+ exactly across the crop overflow without adding another scale transform. */
183
+ @keyframes portraitCoverPanRight {
184
+ from {
185
+ object-position: left center;
186
+ }
187
+ to {
188
+ object-position: right center;
189
+ }
190
+ }
191
+
192
+ @keyframes portraitCoverPanLeft {
193
+ from {
194
+ object-position: right center;
195
+ }
196
+ to {
197
+ object-position: left center;
198
+ }
199
+ }
200
+
181
201
  @keyframes slideInLeft {
182
202
  from {
183
203
  transform: translateX(-100%);
@@ -2170,6 +2190,18 @@
2170
2190
  forwards;
2171
2191
  }
2172
2192
 
2193
+ .squisq-image--portrait-pan-right {
2194
+ animation: portraitCoverPanRight var(--portrait-pan-duration, 12s)
2195
+ var(--portrait-pan-easing, ease-in-out) var(--portrait-pan-delay, 0s) forwards;
2196
+ will-change: object-position;
2197
+ }
2198
+
2199
+ .squisq-image--portrait-pan-left {
2200
+ animation: portraitCoverPanLeft var(--portrait-pan-duration, 12s)
2201
+ var(--portrait-pan-easing, ease-in-out) var(--portrait-pan-delay, 0s) forwards;
2202
+ will-change: object-position;
2203
+ }
2204
+
2173
2205
  .anim-typewriter {
2174
2206
  animation: typewriter var(--anim-duration, 2s) var(--anim-easing, steps(40, end))
2175
2207
  var(--anim-delay, 0s) forwards;
@@ -2369,6 +2401,10 @@
2369
2401
  .anim-slowZoom-out,
2370
2402
  .anim-slowZoom-panLeft,
2371
2403
  .anim-slowZoom-panRight,
2404
+ .anim-panLeft,
2405
+ .anim-panRight,
2406
+ .squisq-image--portrait-pan-left,
2407
+ .squisq-image--portrait-pan-right,
2372
2408
  .anim-drift {
2373
2409
  animation: none;
2374
2410
  }
package/src/types.ts CHANGED
@@ -33,8 +33,12 @@ export type ControlsLayout = 'overlay' | 'sidebar' | 'bottom';
33
33
  * `markdownDocToPlainHtml` export produces. No SquisqPlayer, no SVG
34
34
  * cards — just `<h1>`/`<p>`/`<ul>` etc. inside a sandboxed iframe.
35
35
  * Use when you want a WYSIWYG view of the simple HTML export.
36
+ * - `'narrate'` — Teleprompter/performance surface. DocPlayer does not
37
+ * implement this mode; it is owned by the editor package
38
+ * (`@bendyline/squisq-editor-react`), which renders its own
39
+ * voice-paced teleprompter view for it.
36
40
  */
37
- export type DisplayMode = 'video' | 'slideshow' | 'linear' | 'page';
41
+ export type DisplayMode = 'video' | 'slideshow' | 'linear' | 'page' | 'narrate';
38
42
 
39
43
  /**
40
44
  * Caption display style.
@@ -68,6 +72,8 @@ export interface PlaybackState {
68
72
  isPlaying: boolean;
69
73
  currentTime: number;
70
74
  totalDuration: number;
75
+ /** Whether the managed cover is the visual currently shown. */
76
+ isCoverVisible?: boolean;
71
77
  currentBlockIndex: number;
72
78
  totalBlocks: number;
73
79
  docProgress: number;
@@ -146,15 +152,15 @@ export interface RenderChapterInfo {
146
152
  }
147
153
 
148
154
  /**
149
- * API surface exposed on `window` in render mode and debug mode.
150
- * Used by Playwright for video export and by ?debug=true for testing.
155
+ * Instance-scoped API created in render mode and debug mode.
156
+ * React hosts receive it via `DocPlayer.onRenderAPIReady`; standalone hosts
157
+ * receive it from their mount handle.
151
158
  *
152
159
  * @example
153
160
  * ```ts
154
- * // In Playwright:
155
- * const w = window as unknown as SquisqWindow;
156
- * await w.seekTo!(5.0);
157
- * const blocks = w.getBlocks!();
161
+ * const handle = SquisqPlayer.getHandle(rootElement);
162
+ * const api = await handle?.renderAPI;
163
+ * await api?.seekTo(5.0);
158
164
  * ```
159
165
  */
160
166
  export interface SquisqRenderAPI {
@@ -169,12 +175,6 @@ export interface SquisqRenderAPI {
169
175
  hasCoverBlock: () => boolean;
170
176
  }
171
177
 
172
- /**
173
- * Window augmented with optional SquisqRenderAPI properties.
174
- * Each property is optional because they're only present in render/debug mode.
175
- */
176
- export type SquisqWindow = Window & typeof globalThis & Partial<SquisqRenderAPI>;
177
-
178
178
  /** Format time in seconds to MM:SS string */
179
179
  export function formatTime(seconds: number): string {
180
180
  const mins = Math.floor(seconds / 60);