Skip to content

Commit

Permalink
chore: version 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
sLeeNguyen committed Jan 30, 2022
1 parent 762fdb8 commit 46905f9
Show file tree
Hide file tree
Showing 12 changed files with 409 additions and 46 deletions.
12 changes: 6 additions & 6 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react'
import React from 'react';

import { ExampleComponent } from 'react-flip-clock-countdown'
import 'react-flip-clock-countdown/dist/index.css'
import FlipClockCountDown from 'react-flip-clock-countdown';
import 'react-flip-clock-countdown/dist/index.css';

const App = () => {
return <ExampleComponent text="Create React Library Example 😄" />
}
return <FlipClockCountDown to={new Date().getTime() + 24 * 3600 * 1000 + 5000} />;
};

export default App
export default App;
29 changes: 24 additions & 5 deletions example/src/index.css
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
* {
box-sizing: border-box;
}

body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
"Droid Sans", "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
}

html,
body {
height: 100vh;
width: 100vw;
background-color: teal;
}

#root {
width: 100%;
height: 100%;

display: flex;
justify-content: center;
align-items: center;
font-family: Arial, Helvetica, sans-serif;
}
112 changes: 112 additions & 0 deletions src/FlipClockCountDown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import React from 'react';
import clsx from 'clsx';
import { calcTimeDelta, FlipClockCountdownUnitTimeFormatted, parseTimeDelta } from './utils';
import styles from './styles.module.css';
import FlipClockDigit from './FlipClockDigit';

export interface FlipClockCountdownTimeDelta {
readonly total: number;
readonly days: number;
readonly hours: number;
readonly minutes: number;
readonly seconds: number;
}

export interface FlipClockCountdownState {
readonly timeDelta: FlipClockCountdownTimeDelta;
readonly completed: boolean;
}

export type FlipClockCountdownTimeDeltaFn = (props: FlipClockCountdownState) => void;

export interface FlipClockCountdownProps {
readonly to: Date | number | string;
readonly children?: React.ReactElement<any>;
readonly className?: string;
readonly containerProps?: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
readonly onComplete?: () => void;
readonly onTick?: FlipClockCountdownTimeDeltaFn;
}

export interface FlipClockCountdownTimeDeltaFormatted {
readonly days: FlipClockCountdownUnitTimeFormatted;
readonly hours: FlipClockCountdownUnitTimeFormatted;
readonly minutes: FlipClockCountdownUnitTimeFormatted;
readonly seconds: FlipClockCountdownUnitTimeFormatted;
}

export interface FlipClockCountdownRenderProps extends FlipClockCountdownTimeDelta {
readonly formatted: FlipClockCountdownTimeDeltaFormatted;
}

/**
* A 3D animated flip clock countdown component for React.
*/
function FlipClockCountdown(props: FlipClockCountdownProps) {
const { to, className, containerProps, children, onComplete = () => {}, onTick = () => {} } = props;
const [state, setState] = React.useState<FlipClockCountdownState>(constructState);
const countdownRef = React.useRef(0);

React.useEffect(() => {
countdownRef.current = window.setInterval(tick, 1000);

return () => clearTimer();
}, []);

function clearTimer() {
window.clearInterval(countdownRef.current);
}

function constructState(): FlipClockCountdownState {
const timeDelta = calcTimeDelta(to);
return {
timeDelta,
completed: timeDelta.total === 0
};
}

function tick() {
const newState = constructState();
setState(newState);
onTick(newState);
if (newState.completed) {
clearTimer();
onComplete();
}
}

function getRenderProps(): FlipClockCountdownRenderProps {
const { timeDelta } = state;
return {
...timeDelta,
formatted: parseTimeDelta(timeDelta)
};
}

if (state?.completed) {
return <React.Fragment>{children}</React.Fragment>;
}

const renderProps = getRenderProps();
const { days, hours, minutes, seconds } = renderProps.formatted;
const labels = ['days', 'hours', 'minutes', 'seconds'];

return (
<div {...containerProps} className={clsx(styles.fcc__container, className)}>
{[days, hours, minutes, seconds].map((item, idx) => {
return (
<React.Fragment key={`digit-block-${idx}`}>
<div className={styles.fcc__digit_block_container}>
<div className={styles.fcc__digit_block_label}>{labels[idx]}</div>
{item.current.map((cItem, cIdx) => (
<FlipClockDigit key={cIdx} current={cItem} next={item.next[cIdx]} />
))}
</div>
{idx < 3 && <div className={styles.fcc__colon}>:</div>}
</React.Fragment>
);
})}
</div>
);
}
export default FlipClockCountdown;
45 changes: 45 additions & 0 deletions src/FlipClockDigit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import clsx from 'clsx';
import React from 'react';
import styles from './styles.module.css';
import { Digit } from './utils';

export interface FlipClockDigitProps {
current: Digit;
next: Digit;
className?: string;
}

type FlipClockDigitState = FlipClockDigitProps;

export default function FlipClockDigit(props: FlipClockDigitProps) {
const { current, next, className } = props;
const [digit, setDigit] = React.useState<FlipClockDigitState>({ current: 0, next: 0 });
const [flipped, setFlipped] = React.useState(false);

React.useEffect(() => {
if (digit.current !== current) {
if (digit.current === digit.next) {
setDigit({ ...digit, next });
}
setFlipped(true);
} else {
setFlipped(false);
}
}, [current, next]);

const handleTransitionEnd = (): void => {
setDigit({ current, next });
setFlipped(false);
};

return (
<div className={clsx(styles.fcc__digit_block, className)}>
<div className={styles.fcc__next_above}>{digit.next}</div>
<div className={styles.fcc__current_below}>{digit.current}</div>
<div className={clsx(styles.fcc__card, { [styles.fcc__flipped]: flipped })} onTransitionEnd={handleTransitionEnd}>
<div className={clsx(styles.fcc__card_face, styles.fcc__card_face_front)}>{digit.current}</div>
<div className={clsx(styles.fcc__card_face, styles.fcc__card_face_back)}>{digit.next}</div>
</div>
</div>
);
}
7 changes: 7 additions & 0 deletions src/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import FlipClockCountDown from '.';

describe('ExampleComponent', () => {
it('is truthy', () => {
expect(FlipClockCountDown).toBeTruthy();
});
});
7 changes: 0 additions & 7 deletions src/index.test.tsx

This file was deleted.

10 changes: 10 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import FlipClockCountdown from './FlipClockCountDown';

export type {
FlipClockCountdownProps,
FlipClockCountdownRenderProps,
FlipClockCountdownTimeDelta,
FlipClockCountdownState,
FlipClockCountdownTimeDeltaFormatted
} from './FlipClockCountDown';
export default FlipClockCountdown;
10 changes: 0 additions & 10 deletions src/index.tsx

This file was deleted.

134 changes: 126 additions & 8 deletions src/styles.module.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,127 @@
/* add css module styles here (optional) */

.test {
margin: 2em;
padding: 0.5em;
border: 2px solid #000;
font-size: 2em;
text-align: center;
:root {
--fcc-flip-duration: 0.7s;
--fcc-digit-block-width: 46px;
--fcc-digit-block-height: 80px;
--fcc-digit-font-size: 50px;
--fcc-background: #0f181a;
--fcc-label-color: #ffffff;
--fcc-digit-color: #ffffff;
}

.fcc__container {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
"Droid Sans", "Helvetica Neue", sans-serif;
font-size: var(--fcc-digit-font-size);
color: var(--fcc-digit-color);
line-height: 0;
font-weight: 500;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
cursor: default;
display: flex;
align-items: center;
}

.fcc__digit_block_container .fcc__digit_block:not(:last-child) {
margin-right: 4px;
}

.fcc__digit_block_container {
position: relative;
display: flex;
align-items: center;
}

.fcc__digit_block_label {
color: var(--fcc-digit-color);
line-height: 1;
font-weight: 400;
font-size: 16px;
position: absolute;
bottom: 0;
left: 50%;
transform: translate(-50%, 150%);
text-transform: capitalize;
}

.fcc__digit_block {
perspective: 200px;
position: relative;
width: var(--fcc-digit-block-width);
height: var(--fcc-digit-block-height);
box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.1);
border-radius: 4px;
}

.fcc__current_below,
.fcc__next_above {
position: absolute;
width: 100%;
height: 50%;
overflow: hidden;
display: flex;
justify-content: center;
background: var(--fcc-background);
}

.fcc__next_above {
align-items: flex-end;
top: 0;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom: 1px solid #ffffff66;
}

.fcc__current_below {
align-items: flex-start;
bottom: 0;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}

.fcc__card {
position: relative;
z-index: 2;
width: 100%;
height: 50%;
transform-style: preserve-3d;
transform-origin: bottom;
transform: rotateX(0);
}

.fcc__card.fcc__flipped {
transition: transform var(--fcc-flip-duration) ease-in-out;
transform: rotateX(-180deg);
}

.fcc__card_face {
position: absolute;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
overflow: hidden;
backface-visibility: hidden;
background: var(--fcc-background);
}

.fcc__card_face_front {
align-items: flex-end;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom: 1px solid #ffffff66;
}

.fcc__card_face_back {
align-items: flex-start;
transform: rotateX(-180deg);
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}

.fcc__colon {
margin-left: 8px;
margin-right: 8px;
line-height: 1;
}
Loading

0 comments on commit 46905f9

Please sign in to comment.