Skip to content

Commit

Permalink
Add ResizeObserver to sync parameters when resizing
Browse files Browse the repository at this point in the history
  • Loading branch information
namti committed Feb 6, 2024
1 parent 28b284a commit b8504df
Show file tree
Hide file tree
Showing 18 changed files with 324 additions and 269 deletions.
19 changes: 7 additions & 12 deletions src/components/Book/Book.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,26 @@ export default meta;
type Story = StoryObj<typeof Book>;

export const Regular: Story = args => (
<div style={ { width: '10rem' } }>
<div style={ { width: '30vw' } }>
<Book { ...args } />
</div>
);

Regular.args = {
cover: 'https://pictures.abebooks.com/inventory/md/md30869329205.jpg',
thickness: '1rem',
coverCloseAngle: 0,
coverOpenAngle: 10,
title: 'Lorem Ipsum',
};
Regular.args = { cover: 'https://pictures.abebooks.com/inventory/md/md30869329205.jpg' };

export const CustomCoverAndContent: Story = args => (
<div style={ { width: '10rem' } }>
<Book { ...args } />
</div>
);
CustomCoverAndContent.args = {
transitionDuration: '500ms',
coverOpenAngle: 45,
coverContent: <div style={ { color: '#fff', fontWeight: '900', fontFamily: 'sans-serif' } }>
transitionDuration: '400ms',
transitionTimingFunction: 'ease-out',
coverColor: '#ac7244',
coverEndAngle: 45,
coverContent: <div style={ { color: 'rgba(255,255,255,.85)', fontWeight: '900', fontFamily: 'sans-serif', filter: 'drop-shadow(0px -1px 0px rgba(0,0,0,.5))' } }>
Lorem Ipsum
</div>,
// _pageContent: <div><img src="https://pictures.abebooks.com/inventory/md/md31356128146.jpg" /></div>,
pageContent: <div style={ { color: '#333', fontSize: '.35rem', padding: '2rem 1rem' } }>
<div style={ { textAlign: 'center', fontSize: '.75rem', fontWeight: 'bolder' } }>Duis aute</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ipsum nunc aliquet bibendum enim facilisis. Orci eu lobortis elementum nibh. Eget felis eget nunc lobortis mattis aliquam faucibus purus. Sit amet aliquam id diam. Tincidunt lobortis feugiat vivamus at augue eget. Id interdum velit laoreet id donec ultrices tincidunt. Tempor id eu nisl nunc mi. Eu augue ut lectus arcu bibendum. In pellentesque massa placerat duis.</p>
Expand Down
74 changes: 51 additions & 23 deletions src/components/Book/Book.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { PropsWithChildren, useEffect, useState } from 'react';
import React, { PropsWithChildren, useEffect, useRef, useState } from 'react';
import { BookProps, TransitionDuration, TransitionTimingFunction } from './Book.types';
import { interpolateNumber } from '../../utils';
import { BackCover, BookWrapper, FrontCover, Pages } from './Styled';
import _ from 'lodash';

const defaultRatio = 0.7;

Expand All @@ -17,17 +18,18 @@ type TImageSize = [
];

const defaults = {
borderRadiusLeft: '.125rem',
borderRadiusRight: '.5rem',
thickness: '1rem',
creaseMargin: '.5rem',
creaseWidth: '.5rem',
borderRadiusLeft: .025,
borderRadiusRight: .045,
thickness: .075,
creaseWidth: .035,
creaseMargin: .06,
coverMargin: .018,

coverColor: '#555',
coverMargin: '.25rem',
transitionDuration: '300ms',
transitionTimingFunction: 'ease-out',
coverStartAngle: 0,
coverEndAndle: 25,
coverEndAngle: 10,
};

const Book: React.FC<PropsWithChildren<BookProps>> = (props): React.JSX.Element => {
Expand All @@ -39,6 +41,29 @@ const Book: React.FC<PropsWithChildren<BookProps>> = (props): React.JSX.Element
const [ transformScaleEnd, setTransformScaleEnd ] = useState(1);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [ isCoverLoading, setIsCoverLoading ] = useState(false);
const [ wrapperSize, setWrapperSize ] = useState<{ width: number, height: number } | null>(null);

const wrapperRef = useRef<HTMLDivElement>(null);

useEffect(() => {
if(wrapperRef.current){
const { width, height } = wrapperRef.current.getBoundingClientRect();
setWrapperSize({ width, height });
}

const resizeObserver = new ResizeObserver(entries => {
if(entries?.length){
const { width, height } = entries?.[0]?.contentRect || {};
setWrapperSize({ width, height });
}
});

if(wrapperRef.current) resizeObserver.observe(wrapperRef.current);

return () => {
if(wrapperRef.current) resizeObserver.unobserve(wrapperRef.current);
};
}, []);

useEffect(() => {
if (props.cover) {
Expand Down Expand Up @@ -73,20 +98,20 @@ const Book: React.FC<PropsWithChildren<BookProps>> = (props): React.JSX.Element

type args = [number, number, number, number, number];

if (Number.isFinite(props.coverCloseAngle)) {
const skew = interpolateNumber(...[ props.coverCloseAngle as number, ...argsSkew ] as args);
const scale = interpolateNumber(...[ props.coverCloseAngle as number, ...argsScale ] as args);
if (Number.isFinite(props.coverStartAngle)) {
const skew = interpolateNumber(...[ props.coverStartAngle as number, ...argsSkew ] as args);
const scale = interpolateNumber(...[ props.coverStartAngle as number, ...argsScale ] as args);
setTransformSkewStart(skew);
setTransformScaleStart(scale);
}

if (Number.isFinite(props.coverOpenAngle)) {
const skew = interpolateNumber(...[ props.coverOpenAngle as number, ...argsSkew ] as args);
const scale = interpolateNumber(...[ props.coverOpenAngle as number, ...argsScale ] as args);
if (Number.isFinite(props.coverEndAngle)) {
const skew = interpolateNumber(...[ props.coverEndAngle as number, ...argsSkew ] as args);
const scale = interpolateNumber(...[ props.coverEndAngle as number, ...argsScale ] as args);
setTransformSkewEnd(skew);
setTransformScaleEnd(scale);
}
}, [ props.coverCloseAngle, props.coverOpenAngle ]);
}, [ props.coverStartAngle, props.coverEndAngle ]);


const getImageSize = (url = '') => new Promise<TImageSize>((resolve, reject) => {
Expand All @@ -107,12 +132,14 @@ const Book: React.FC<PropsWithChildren<BookProps>> = (props): React.JSX.Element
style={ {
'aspectRatio': imageRatio,
'--cover-image': `url(${src})`,
'--border-radius-left': props.leftCornerRadius,
'--border-radius-right': props.rightCornerRadius,
'--crease-margin': props.creaseMargin,
'--crease-width': props.creaseWidth,
'--thickness': props.thickness,
'--cover-margin': props.coverMargin,

'--border-radius-left': ((wrapperSize?.width ?? 0) * (_.clamp(props.leftCornerRadius ?? defaults.borderRadiusLeft, 0, props.creaseMargin ?? defaults.creaseMargin))).toFixed(2) + 'px',
'--border-radius-right': ((wrapperSize?.width ?? 0) * (props.rightCornerRadius ?? defaults.borderRadiusRight)).toFixed(2) + 'px',
'--crease-margin': ((wrapperSize?.width || 0) * (props.creaseMargin ?? defaults.creaseMargin)).toFixed(2) + 'px',
'--crease-width': ((wrapperSize?.width || 0) * (props.creaseWidth ?? defaults.creaseWidth)).toFixed(2) + 'px',
'--thickness': ((wrapperSize?.height || 0) * (props.thickness ?? defaults.thickness)).toFixed(2) + 'px',
'--cover-margin': ((wrapperSize?.height || 0) * (props.coverMargin ?? defaults.coverMargin)).toFixed(2) + 'px',

'--fallback-color': props.coverColor,
'--transition-duration': props.transitionDuration,
'--transition-timing-function': props.transitionTimingFunction,
Expand All @@ -121,6 +148,7 @@ const Book: React.FC<PropsWithChildren<BookProps>> = (props): React.JSX.Element
'--start-scale': transformScaleStart,
'--end-scale': transformScaleEnd,
} as React.CSSProperties }
ref={ wrapperRef }
>
<FrontCover className="cover">

Expand Down Expand Up @@ -163,6 +191,6 @@ Book.defaultProps = {
coverMargin: defaults.coverMargin,
transitionDuration: defaults.transitionDuration as TransitionDuration,
transitionTimingFunction: defaults.transitionTimingFunction as TransitionTimingFunction,
coverCloseAngle: 0,
coverOpenAngle: 45,
coverStartAngle: defaults.coverStartAngle,
coverEndAngle: defaults.coverEndAngle,
};
50 changes: 40 additions & 10 deletions src/components/Book/Book.types.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,50 @@
import React from 'react';

export interface BookProps {
/**
* Cover image URL
*/
cover?: string;
title?: string;
subtitle?: string;
leftCornerRadius?: string;
rightCornerRadius?: string;
creaseMargin?: string,
creaseWidth?: string,
thickness?: string;

/**
* Border radius, relative to the width of the book. `0` - `1`
*/
leftCornerRadius?: number;
/**
* Border radius, relative to the width of the book. `0` - `1`
*/
rightCornerRadius?: number;
/**
* Crease margin to the left, ralative to the width of the book. `0` - `1`
*/
creaseMargin?: number,
/**
* Crease width, ralative to the width of the book. `0` - `1`
*/
creaseWidth?: number,
/**
* Thickness, relative to the height of the book. `0` - `1`
*/
thickness?: number;
/**
* Cover margin, relative to the height of the book. `0` - `1`
*/
coverMargin?: number;

/**
* Cover color shows when the cover image is loading or not provided.
*/
coverColor?: string;
coverMargin?: string;
transitionTimingFunction?: TransitionTimingFunction;
transitionDuration: TransitionDuration;
coverCloseAngle?: number;
coverOpenAngle?: number;
/**
* Initial cover angle. `0` - `45`
*/
coverStartAngle?: number;
/**
* Cover angle when hover on it. `0` - `45`
*/
coverEndAngle?: number;
coverContent?: React.JSX.Element | React.JSX.Element[];
pageContent?: React.JSX.Element | React.JSX.Element[];
}
Expand Down
11 changes: 6 additions & 5 deletions src/components/Book/Styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ border-bottom-left-radius: var(--border-radius-left);
border-top-right-radius: var(--border-radius-right);
border-bottom-right-radius: var(--border-radius-right);
transition: aspect-ratio ease 150ms;
// transition: aspect-ratio ease 150ms;
@media (hover: hover) {
&:hover{
Expand All @@ -39,6 +39,7 @@ position: absolute;
left: 0;
top: 0;
transform: translateY(calc(var(--thickness) * -1));
// transition: transform ease-out 300ms;
border-top-left-radius: var(--border-radius-left);
border-bottom-left-radius: var(--border-radius-left);
Expand Down Expand Up @@ -159,10 +160,10 @@ bottom: var(--cover-margin);
left: calc(var(--cover-margin) / 2);
&, &>.first-page{
border-top-left-radius: calc(var(--border-radius-left) / 2);
border-bottom-left-radius: calc(var(--border-radius-left) / 2);
border-top-right-radius: calc(var(--border-radius-right) / 2);
border-bottom-right-radius: calc(var(--border-radius-right) / 2);
border-top-left-radius: calc(var(--border-radius-left) - var(--cover-margin) / 2);
border-bottom-left-radius: calc(var(--border-radius-left) - var(--cover-margin) / 2);
border-top-right-radius: calc(var(--border-radius-right) - var(--cover-margin) / 2);
border-bottom-right-radius: calc(var(--border-radius-right) - var(--cover-margin) / 2);
}
&>.first-page{
Expand Down
206 changes: 206 additions & 0 deletions storybook-static/assets/Book.stories-924782ea.js

Large diffs are not rendered by default.

205 changes: 0 additions & 205 deletions storybook-static/assets/Book.stories-d20bc5ec.js

This file was deleted.

Large diffs are not rendered by default.

Loading

0 comments on commit b8504df

Please sign in to comment.