@bendyline/squisq-react 2.0.0 → 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.
package/dist/index.d.ts CHANGED
@@ -691,8 +691,10 @@ interface ImageLayerProps {
691
691
  };
692
692
  /** Current time relative to block start (for animation timing) */
693
693
  blockTime: number;
694
+ /** Whether authored and responsive image motion should run. */
695
+ animationsEnabled?: boolean;
694
696
  }
695
- declare function ImageLayer({ layer, basePath, viewport, blockTime }: ImageLayerProps): react_jsx_runtime.JSX.Element;
697
+ declare function ImageLayer({ layer, basePath, viewport, blockTime, animationsEnabled, }: ImageLayerProps): react_jsx_runtime.JSX.Element;
696
698
 
697
699
  interface TextLayerProps {
698
700
  layer: TextLayer$1;
package/dist/index.js CHANGED
@@ -207,7 +207,13 @@ function getAnchorOffset(anchor, width, height) {
207
207
 
208
208
  // src/layers/ImageLayer.tsx
209
209
  import { jsx as jsx2 } from "react/jsx-runtime";
210
- function ImageLayer({ layer, basePath, viewport, blockTime }) {
210
+ function ImageLayer({
211
+ layer,
212
+ basePath,
213
+ viewport,
214
+ blockTime,
215
+ animationsEnabled = true
216
+ }) {
211
217
  const { content, position, animation } = layer;
212
218
  const x = resolveValue(position.x, viewport.width);
213
219
  const y = resolveValue(position.y, viewport.height);
@@ -222,6 +228,50 @@ function ImageLayer({ layer, basePath, viewport, blockTime }) {
222
228
  const preserveAspectRatio = getPreserveAspectRatio(content.fit);
223
229
  const isCover = content.fit === "cover";
224
230
  const isSpatialAnim = animation && SPATIAL_ANIMATION_TYPES.has(animation.type);
231
+ const usesPortraitPan = isCover && shouldUsePortraitPan(viewport, width, height, animationsEnabled, animation);
232
+ if (usesPortraitPan) {
233
+ const panClass = getPortraitPanClass(animation);
234
+ const panStyle = getPortraitPanStyle(isSpatialAnim ? animation : void 0);
235
+ const containerAnim = isSpatialAnim ? { className: "", style: {} } : animStyle;
236
+ return /* @__PURE__ */ jsx2(
237
+ "g",
238
+ {
239
+ className: `block-layer block-layer--image ${containerAnim.className}`,
240
+ style: containerAnim.style,
241
+ "data-layer-id": layer.id,
242
+ "data-image-framing": "portrait-pan",
243
+ children: /* @__PURE__ */ jsx2("foreignObject", { x: finalX, y: finalY, width, height, children: /* @__PURE__ */ jsx2(
244
+ "div",
245
+ {
246
+ style: {
247
+ width: `${width}px`,
248
+ height: `${height}px`,
249
+ overflow: "hidden"
250
+ },
251
+ children: /* @__PURE__ */ jsx2(
252
+ "img",
253
+ {
254
+ src,
255
+ alt: content.alt || "",
256
+ className: panClass,
257
+ style: {
258
+ width: `${width}px`,
259
+ height: `${height}px`,
260
+ objectFit: "cover",
261
+ objectPosition: "center",
262
+ display: "block",
263
+ pointerEvents: "none",
264
+ ...filter ? { filter } : {},
265
+ ...content.blur && content.blur > 0 ? { transform: "scale(1.06)" } : {},
266
+ ...panStyle
267
+ }
268
+ }
269
+ )
270
+ }
271
+ ) })
272
+ }
273
+ );
274
+ }
225
275
  if (isCover && isSpatialAnim && animation) {
226
276
  const kbAnim = remapToKenBurns(animation);
227
277
  const kbStyle = getAnimationStyle(kbAnim, blockTime);
@@ -317,6 +367,23 @@ function getPreserveAspectRatio(fit) {
317
367
  }
318
368
  }
319
369
  var SPATIAL_ANIMATION_TYPES = /* @__PURE__ */ new Set(["panLeft", "panRight", "slowZoom", "zoomIn", "zoomOut"]);
370
+ var PORTRAIT_ASPECT_CUTOFF = 0.83;
371
+ function shouldUsePortraitPan(viewport, layerWidth, layerHeight, animationsEnabled, animation) {
372
+ if (!animationsEnabled || animation?.type === "none") return false;
373
+ if (viewport.width / viewport.height >= PORTRAIT_ASPECT_CUTOFF) return false;
374
+ return layerWidth >= viewport.width * 0.7 && layerHeight >= viewport.height * 0.7;
375
+ }
376
+ function getPortraitPanClass(animation) {
377
+ const pansBack = animation?.type === "panRight" || animation?.type === "slowZoom" && animation.panDirection === "right";
378
+ return pansBack ? "squisq-image--portrait-pan-left" : "squisq-image--portrait-pan-right";
379
+ }
380
+ function getPortraitPanStyle(animation) {
381
+ return {
382
+ "--portrait-pan-duration": `${animation?.duration ?? 12}s`,
383
+ "--portrait-pan-delay": `${animation?.delay ?? 0}s`,
384
+ "--portrait-pan-easing": animation?.easing ?? "ease-in-out"
385
+ };
386
+ }
320
387
  function remapToKenBurns(anim) {
321
388
  switch (anim.type) {
322
389
  case "panLeft":
@@ -766,6 +833,7 @@ function wrapText(text, fontSize, maxWidth) {
766
833
  // src/layers/ShapeLayer.tsx
767
834
  import { useId as useId2 } from "react";
768
835
  import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
836
+ var FULL_BLEED_OVERSCAN = 1;
769
837
  function ShapeLayer({ layer, viewport, blockTime }) {
770
838
  const { content, position, animation } = layer;
771
839
  const defsId = `${useId2().replace(/:/g, "")}-${layer.id}`;
@@ -776,6 +844,12 @@ function ShapeLayer({ layer, viewport, blockTime }) {
776
844
  const anchorOffset = getAnchorOffset(position.anchor, width, height);
777
845
  const x = rawX + anchorOffset.x;
778
846
  const y = rawY + anchorOffset.y;
847
+ const isUnborderedFullBleedRect = content.shape === "rect" && x === 0 && y === 0 && width === viewport.width && height === viewport.height && !content.stroke && !content.borderRadius;
848
+ const overscan = isUnborderedFullBleedRect ? FULL_BLEED_OVERSCAN : 0;
849
+ const paintX = x - overscan;
850
+ const paintY = y - overscan;
851
+ const paintWidth = width + overscan * 2;
852
+ const paintHeight = height + overscan * 2;
779
853
  const animStyle = getAnimationStyle(animation, blockTime);
780
854
  const fill = content.fill || "none";
781
855
  const isCSSGradient = typeof fill === "string" && fill.includes("gradient(");
@@ -786,12 +860,12 @@ function ShapeLayer({ layer, viewport, blockTime }) {
786
860
  className: `block-layer block-layer--shape ${animStyle.className}`,
787
861
  style: animStyle.style,
788
862
  "data-layer-id": layer.id,
789
- children: /* @__PURE__ */ jsx5("foreignObject", { x, y, width, height, children: /* @__PURE__ */ jsx5(
863
+ children: /* @__PURE__ */ jsx5("foreignObject", { x: paintX, y: paintY, width: paintWidth, height: paintHeight, children: /* @__PURE__ */ jsx5(
790
864
  "div",
791
865
  {
792
866
  style: {
793
- width: `${width}px`,
794
- height: `${height}px`,
867
+ width: `${paintWidth}px`,
868
+ height: `${paintHeight}px`,
795
869
  background: fill,
796
870
  borderRadius: content.borderRadius ? `${content.borderRadius}px` : void 0,
797
871
  pointerEvents: "none"
@@ -831,10 +905,10 @@ function ShapeLayer({ layer, viewport, blockTime }) {
831
905
  content.shape === "rect" && /* @__PURE__ */ jsx5(
832
906
  "rect",
833
907
  {
834
- x,
835
- y,
836
- width,
837
- height,
908
+ x: paintX,
909
+ y: paintY,
910
+ width: paintWidth,
911
+ height: paintHeight,
838
912
  rx: content.borderRadius,
839
913
  ry: content.borderRadius,
840
914
  ...shapeProps
@@ -1661,7 +1735,8 @@ function LayerRenderer({
1661
1735
  layer: renderedLayer,
1662
1736
  basePath,
1663
1737
  viewport,
1664
- blockTime
1738
+ blockTime,
1739
+ animationsEnabled
1665
1740
  }
1666
1741
  );
1667
1742
  case "text":
@@ -3946,6 +4021,9 @@ function LinearDocView({
3946
4021
  .squisq-linear-content p {
3947
4022
  margin-bottom: 0.75em;
3948
4023
  }
4024
+ .squisq-linear-content p + p {
4025
+ margin-top: 1.25em;
4026
+ }
3949
4027
  .squisq-linear-content ul,
3950
4028
  .squisq-linear-content ol {
3951
4029
  padding-left: 2em;