@hasthiya_/flip-clock 1.0.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/README.md +49 -0
- package/dist/index.d.mts +181 -0
- package/dist/index.d.ts +181 -0
- package/dist/index.js +494 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +473 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +40 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
FlipClock: () => FlipClock_default,
|
|
24
|
+
default: () => FlipClock_default
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/FlipClock.tsx
|
|
29
|
+
var import_react = require("react");
|
|
30
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
31
|
+
var DEFAULT_CARD = {
|
|
32
|
+
background: "#575757",
|
|
33
|
+
backgroundDark: "#4a4a4a",
|
|
34
|
+
width: "7rem",
|
|
35
|
+
height: "9.5rem",
|
|
36
|
+
borderRadius: "0.5rem",
|
|
37
|
+
boxShadow: "0 3px 8px rgba(0,0,0,0.25), 0 1px 3px rgba(0,0,0,0.15)"
|
|
38
|
+
};
|
|
39
|
+
var DEFAULT_DIGIT = {
|
|
40
|
+
color: "#ffffff",
|
|
41
|
+
fontFamily: "'Bebas Neue', sans-serif",
|
|
42
|
+
fontSize: "5.5rem",
|
|
43
|
+
textShadow: "none"
|
|
44
|
+
};
|
|
45
|
+
var DEFAULT_LABEL = {
|
|
46
|
+
visible: true,
|
|
47
|
+
color: "#999999",
|
|
48
|
+
fontFamily: "'Inter', sans-serif",
|
|
49
|
+
fontSize: "0.9rem",
|
|
50
|
+
fontWeight: "500",
|
|
51
|
+
letterSpacing: "0.2em",
|
|
52
|
+
textTransform: "uppercase"
|
|
53
|
+
};
|
|
54
|
+
var DEFAULT_LINE = {
|
|
55
|
+
color: "rgba(0,0,0,0.25)",
|
|
56
|
+
height: "1px"
|
|
57
|
+
};
|
|
58
|
+
var DEFAULT_ANIMATION = {
|
|
59
|
+
flipDuration: 300,
|
|
60
|
+
bounceIntensity: 8,
|
|
61
|
+
flipDownEasing: "ease-in",
|
|
62
|
+
flipUpEasing: "ease-out"
|
|
63
|
+
};
|
|
64
|
+
var DEFAULT_SEPARATOR = {
|
|
65
|
+
type: "none",
|
|
66
|
+
color: "#999999",
|
|
67
|
+
size: "0.5rem"
|
|
68
|
+
};
|
|
69
|
+
function scaleCssLength(value, factor) {
|
|
70
|
+
if (factor === 1) return value;
|
|
71
|
+
const match = value.trim().match(/^(-?\d*\.?\d+)(r?em|px)$/);
|
|
72
|
+
if (!match) return value;
|
|
73
|
+
const num = Number(match[1]);
|
|
74
|
+
const unit = match[2];
|
|
75
|
+
return `${num * factor}${unit}`;
|
|
76
|
+
}
|
|
77
|
+
var styleInjected = false;
|
|
78
|
+
var currentAnimId = "";
|
|
79
|
+
function injectKeyframes(animation) {
|
|
80
|
+
const id = `fc-${animation.flipDuration}-${animation.bounceIntensity}`;
|
|
81
|
+
if (typeof document === "undefined") return id;
|
|
82
|
+
if (styleInjected && currentAnimId === id) return id;
|
|
83
|
+
const existingEl = document.getElementById(id);
|
|
84
|
+
if (existingEl) {
|
|
85
|
+
styleInjected = true;
|
|
86
|
+
currentAnimId = id;
|
|
87
|
+
return id;
|
|
88
|
+
}
|
|
89
|
+
const bounce = animation.bounceIntensity;
|
|
90
|
+
const halfBounce = bounce / 2;
|
|
91
|
+
const css = `
|
|
92
|
+
@keyframes ${id}-flip-top {
|
|
93
|
+
0% { transform: rotateX(0deg); }
|
|
94
|
+
100% { transform: rotateX(-90deg); }
|
|
95
|
+
}
|
|
96
|
+
@keyframes ${id}-flip-bottom {
|
|
97
|
+
0% { transform: rotateX(90deg); }
|
|
98
|
+
60% { transform: rotateX(-${bounce}deg); }
|
|
99
|
+
80% { transform: rotateX(${halfBounce}deg); }
|
|
100
|
+
100% { transform: rotateX(0deg); }
|
|
101
|
+
}
|
|
102
|
+
`;
|
|
103
|
+
const styleEl = document.createElement("style");
|
|
104
|
+
styleEl.id = id;
|
|
105
|
+
styleEl.textContent = css;
|
|
106
|
+
document.head.appendChild(styleEl);
|
|
107
|
+
styleInjected = true;
|
|
108
|
+
currentAnimId = id;
|
|
109
|
+
return id;
|
|
110
|
+
}
|
|
111
|
+
var FlipCardUnit = ({
|
|
112
|
+
digit,
|
|
113
|
+
card,
|
|
114
|
+
digitStyle,
|
|
115
|
+
line,
|
|
116
|
+
animation,
|
|
117
|
+
animId
|
|
118
|
+
}) => {
|
|
119
|
+
const [currentDigit, setCurrentDigit] = (0, import_react.useState)(digit);
|
|
120
|
+
const [previousDigit, setPreviousDigit] = (0, import_react.useState)(digit);
|
|
121
|
+
const [isFlipping, setIsFlipping] = (0, import_react.useState)(false);
|
|
122
|
+
const prevDigitRef = (0, import_react.useRef)(digit);
|
|
123
|
+
const flippingToDigitRef = (0, import_react.useRef)(digit);
|
|
124
|
+
const bottomFlapRef = (0, import_react.useRef)(null);
|
|
125
|
+
(0, import_react.useEffect)(() => {
|
|
126
|
+
if (prevDigitRef.current !== digit) {
|
|
127
|
+
setPreviousDigit(prevDigitRef.current);
|
|
128
|
+
flippingToDigitRef.current = digit;
|
|
129
|
+
prevDigitRef.current = digit;
|
|
130
|
+
setIsFlipping(true);
|
|
131
|
+
}
|
|
132
|
+
}, [digit]);
|
|
133
|
+
(0, import_react.useEffect)(() => {
|
|
134
|
+
if (!isFlipping) return;
|
|
135
|
+
const el = bottomFlapRef.current;
|
|
136
|
+
if (!el) return;
|
|
137
|
+
const done = () => {
|
|
138
|
+
setCurrentDigit(flippingToDigitRef.current);
|
|
139
|
+
setIsFlipping(false);
|
|
140
|
+
};
|
|
141
|
+
const onAnimationEnd = (e) => {
|
|
142
|
+
if (e.animationName.includes("flip-bottom")) {
|
|
143
|
+
done();
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
el.addEventListener("animationend", onAnimationEnd);
|
|
147
|
+
const fallback = setTimeout(done, animation.flipDuration * 2);
|
|
148
|
+
return () => {
|
|
149
|
+
el.removeEventListener("animationend", onAnimationEnd);
|
|
150
|
+
clearTimeout(fallback);
|
|
151
|
+
};
|
|
152
|
+
}, [isFlipping, animation.flipDuration]);
|
|
153
|
+
const containerStyle = {
|
|
154
|
+
position: "relative",
|
|
155
|
+
width: card.width,
|
|
156
|
+
height: card.height,
|
|
157
|
+
perspective: "400px",
|
|
158
|
+
borderRadius: card.borderRadius,
|
|
159
|
+
background: card.background,
|
|
160
|
+
boxShadow: card.boxShadow,
|
|
161
|
+
overflow: "hidden"
|
|
162
|
+
};
|
|
163
|
+
const digitCss = {
|
|
164
|
+
fontFamily: digitStyle.fontFamily,
|
|
165
|
+
fontSize: digitStyle.fontSize,
|
|
166
|
+
lineHeight: 1,
|
|
167
|
+
color: digitStyle.color,
|
|
168
|
+
textShadow: digitStyle.textShadow,
|
|
169
|
+
userSelect: "none"
|
|
170
|
+
};
|
|
171
|
+
const faceBase = {
|
|
172
|
+
position: "absolute",
|
|
173
|
+
width: "100%",
|
|
174
|
+
height: "50%",
|
|
175
|
+
overflow: "hidden",
|
|
176
|
+
backfaceVisibility: "hidden",
|
|
177
|
+
display: "flex",
|
|
178
|
+
justifyContent: "center"
|
|
179
|
+
};
|
|
180
|
+
const topFace = {
|
|
181
|
+
...faceBase,
|
|
182
|
+
top: 0,
|
|
183
|
+
background: card.background,
|
|
184
|
+
borderRadius: `${card.borderRadius} ${card.borderRadius} 0 0`,
|
|
185
|
+
alignItems: "flex-end"
|
|
186
|
+
};
|
|
187
|
+
const bottomFace = {
|
|
188
|
+
...faceBase,
|
|
189
|
+
bottom: 0,
|
|
190
|
+
background: card.backgroundDark,
|
|
191
|
+
borderRadius: `0 0 ${card.borderRadius} ${card.borderRadius}`,
|
|
192
|
+
alignItems: "flex-start"
|
|
193
|
+
};
|
|
194
|
+
const lineStyle = {
|
|
195
|
+
position: "absolute",
|
|
196
|
+
top: "50%",
|
|
197
|
+
left: 0,
|
|
198
|
+
right: 0,
|
|
199
|
+
height: line.height,
|
|
200
|
+
background: line.color,
|
|
201
|
+
zIndex: 10
|
|
202
|
+
};
|
|
203
|
+
const flipTopStyle = {
|
|
204
|
+
...topFace,
|
|
205
|
+
transformOrigin: "bottom center",
|
|
206
|
+
zIndex: 20,
|
|
207
|
+
willChange: "transform",
|
|
208
|
+
animation: isFlipping ? `${animId}-flip-top ${animation.flipDuration}ms ${animation.flipDownEasing} forwards` : void 0
|
|
209
|
+
};
|
|
210
|
+
const flipBottomStyle = {
|
|
211
|
+
...bottomFace,
|
|
212
|
+
transformOrigin: "top center",
|
|
213
|
+
zIndex: 20,
|
|
214
|
+
transform: "rotateX(90deg)",
|
|
215
|
+
willChange: "transform",
|
|
216
|
+
animation: isFlipping ? `${animId}-flip-bottom ${animation.flipDuration}ms ${animation.flipDuration}ms ${animation.flipUpEasing} forwards` : void 0
|
|
217
|
+
};
|
|
218
|
+
const staticTopDigit = !isFlipping && digit !== currentDigit ? currentDigit : digit;
|
|
219
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: containerStyle, children: [
|
|
220
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: topFace, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...digitCss, transform: "translateY(50%)" }, children: staticTopDigit }) }),
|
|
221
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: bottomFace, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...digitCss, transform: "translateY(-50%)" }, children: currentDigit }) }),
|
|
222
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: lineStyle }),
|
|
223
|
+
isFlipping && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: flipTopStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...digitCss, transform: "translateY(50%)" }, children: previousDigit }) }),
|
|
224
|
+
isFlipping && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: bottomFlapRef, style: flipBottomStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...digitCss, transform: "translateY(-50%)" }, children: digit }) })
|
|
225
|
+
] });
|
|
226
|
+
};
|
|
227
|
+
var FlipClockGroupUnit = ({
|
|
228
|
+
value,
|
|
229
|
+
label,
|
|
230
|
+
digits,
|
|
231
|
+
card,
|
|
232
|
+
digitStyle,
|
|
233
|
+
labelStyle,
|
|
234
|
+
line,
|
|
235
|
+
animation,
|
|
236
|
+
animId,
|
|
237
|
+
cardGap,
|
|
238
|
+
labelGap
|
|
239
|
+
}) => {
|
|
240
|
+
const valueStr = String(value).padStart(digits, "0");
|
|
241
|
+
const digitArray = valueStr.split("").map(Number);
|
|
242
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
243
|
+
"div",
|
|
244
|
+
{
|
|
245
|
+
style: {
|
|
246
|
+
display: "flex",
|
|
247
|
+
flexDirection: "column",
|
|
248
|
+
alignItems: "center",
|
|
249
|
+
gap: labelGap,
|
|
250
|
+
flexShrink: 0
|
|
251
|
+
},
|
|
252
|
+
children: [
|
|
253
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", gap: cardGap }, children: digitArray.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
254
|
+
FlipCardUnit,
|
|
255
|
+
{
|
|
256
|
+
digit: d,
|
|
257
|
+
card,
|
|
258
|
+
digitStyle,
|
|
259
|
+
line,
|
|
260
|
+
animation,
|
|
261
|
+
animId
|
|
262
|
+
},
|
|
263
|
+
i
|
|
264
|
+
)) }),
|
|
265
|
+
labelStyle.visible && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
266
|
+
"span",
|
|
267
|
+
{
|
|
268
|
+
style: {
|
|
269
|
+
fontFamily: labelStyle.fontFamily,
|
|
270
|
+
fontSize: labelStyle.fontSize,
|
|
271
|
+
fontWeight: labelStyle.fontWeight,
|
|
272
|
+
letterSpacing: labelStyle.letterSpacing,
|
|
273
|
+
textTransform: labelStyle.textTransform,
|
|
274
|
+
color: labelStyle.color
|
|
275
|
+
},
|
|
276
|
+
children: label
|
|
277
|
+
}
|
|
278
|
+
)
|
|
279
|
+
]
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
};
|
|
283
|
+
var SeparatorUnit = ({ config, cardHeight }) => {
|
|
284
|
+
if (config.type === "none") return null;
|
|
285
|
+
const dotStyle = {
|
|
286
|
+
width: config.size,
|
|
287
|
+
height: config.size,
|
|
288
|
+
borderRadius: "50%",
|
|
289
|
+
background: config.color
|
|
290
|
+
};
|
|
291
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
292
|
+
"div",
|
|
293
|
+
{
|
|
294
|
+
style: {
|
|
295
|
+
display: "flex",
|
|
296
|
+
flexDirection: "column",
|
|
297
|
+
gap: config.size,
|
|
298
|
+
alignItems: "center",
|
|
299
|
+
justifyContent: "center",
|
|
300
|
+
height: cardHeight,
|
|
301
|
+
flexShrink: 0
|
|
302
|
+
},
|
|
303
|
+
children: [
|
|
304
|
+
config.type === "colon" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
305
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: dotStyle }),
|
|
306
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: dotStyle })
|
|
307
|
+
] }),
|
|
308
|
+
config.type === "dot" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: dotStyle })
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
);
|
|
312
|
+
};
|
|
313
|
+
var FlipClock = ({
|
|
314
|
+
targetDate,
|
|
315
|
+
staticTime,
|
|
316
|
+
cardStyle,
|
|
317
|
+
digitStyle,
|
|
318
|
+
labelStyle,
|
|
319
|
+
lineStyle,
|
|
320
|
+
animation,
|
|
321
|
+
separator,
|
|
322
|
+
labels,
|
|
323
|
+
segments,
|
|
324
|
+
dayDigits = 2,
|
|
325
|
+
groupGap = "3rem",
|
|
326
|
+
cardGap = "0.375rem",
|
|
327
|
+
labelGap = "1rem",
|
|
328
|
+
onComplete,
|
|
329
|
+
orientation = "row",
|
|
330
|
+
scale: scaleProp = 1,
|
|
331
|
+
className,
|
|
332
|
+
style
|
|
333
|
+
}) => {
|
|
334
|
+
const cardBase = (0, import_react.useMemo)(() => ({ ...DEFAULT_CARD, ...cardStyle }), [cardStyle]);
|
|
335
|
+
const digitBase = (0, import_react.useMemo)(() => ({ ...DEFAULT_DIGIT, ...digitStyle }), [digitStyle]);
|
|
336
|
+
const labelBase = (0, import_react.useMemo)(() => ({ ...DEFAULT_LABEL, ...labelStyle }), [labelStyle]);
|
|
337
|
+
const lineBase = (0, import_react.useMemo)(() => ({ ...DEFAULT_LINE, ...lineStyle }), [lineStyle]);
|
|
338
|
+
const anim = (0, import_react.useMemo)(() => ({ ...DEFAULT_ANIMATION, ...animation }), [animation]);
|
|
339
|
+
const sepBase = (0, import_react.useMemo)(() => ({ ...DEFAULT_SEPARATOR, ...separator }), [separator]);
|
|
340
|
+
const scale = Math.max(0.1, Math.min(10, scaleProp));
|
|
341
|
+
const card = (0, import_react.useMemo)(
|
|
342
|
+
() => scale === 1 ? cardBase : {
|
|
343
|
+
...cardBase,
|
|
344
|
+
width: scaleCssLength(cardBase.width, scale),
|
|
345
|
+
height: scaleCssLength(cardBase.height, scale),
|
|
346
|
+
borderRadius: scaleCssLength(cardBase.borderRadius, scale)
|
|
347
|
+
},
|
|
348
|
+
[cardBase, scale]
|
|
349
|
+
);
|
|
350
|
+
const digit = (0, import_react.useMemo)(
|
|
351
|
+
() => scale === 1 ? digitBase : { ...digitBase, fontSize: scaleCssLength(digitBase.fontSize, scale) },
|
|
352
|
+
[digitBase, scale]
|
|
353
|
+
);
|
|
354
|
+
const label = (0, import_react.useMemo)(
|
|
355
|
+
() => scale === 1 ? labelBase : { ...labelBase, fontSize: scaleCssLength(labelBase.fontSize, scale) },
|
|
356
|
+
[labelBase, scale]
|
|
357
|
+
);
|
|
358
|
+
const line = (0, import_react.useMemo)(
|
|
359
|
+
() => scale === 1 ? lineBase : { ...lineBase, height: scaleCssLength(lineBase.height, scale) },
|
|
360
|
+
[lineBase, scale]
|
|
361
|
+
);
|
|
362
|
+
const sep = (0, import_react.useMemo)(
|
|
363
|
+
() => scale === 1 ? sepBase : { ...sepBase, size: scaleCssLength(sepBase.size, scale) },
|
|
364
|
+
[sepBase, scale]
|
|
365
|
+
);
|
|
366
|
+
const groupGapScaled = scale === 1 ? groupGap : scaleCssLength(groupGap, scale);
|
|
367
|
+
const cardGapScaled = scale === 1 ? cardGap : scaleCssLength(cardGap, scale);
|
|
368
|
+
const labelGapScaled = scale === 1 ? labelGap : scaleCssLength(labelGap, scale);
|
|
369
|
+
const resolvedLabels = (0, import_react.useMemo)(
|
|
370
|
+
() => ({
|
|
371
|
+
days: labels?.days ?? "Days",
|
|
372
|
+
hours: labels?.hours ?? "Hours",
|
|
373
|
+
minutes: labels?.minutes ?? "Minutes",
|
|
374
|
+
seconds: labels?.seconds ?? "Seconds"
|
|
375
|
+
}),
|
|
376
|
+
[labels]
|
|
377
|
+
);
|
|
378
|
+
const resolvedSegments = (0, import_react.useMemo)(
|
|
379
|
+
() => ({
|
|
380
|
+
days: segments?.days ?? true,
|
|
381
|
+
hours: segments?.hours ?? true,
|
|
382
|
+
minutes: segments?.minutes ?? true,
|
|
383
|
+
seconds: segments?.seconds ?? true
|
|
384
|
+
}),
|
|
385
|
+
[segments]
|
|
386
|
+
);
|
|
387
|
+
const animId = (0, import_react.useMemo)(() => injectKeyframes(anim), [anim]);
|
|
388
|
+
const defaultTarget = (0, import_react.useMemo)(() => {
|
|
389
|
+
const d = /* @__PURE__ */ new Date();
|
|
390
|
+
d.setDate(d.getDate() + 88);
|
|
391
|
+
d.setHours(d.getHours() + 14);
|
|
392
|
+
return d;
|
|
393
|
+
}, []);
|
|
394
|
+
const finalTarget = targetDate ?? defaultTarget;
|
|
395
|
+
const calcTimeLeft = (0, import_react.useCallback)(() => {
|
|
396
|
+
if (staticTime) {
|
|
397
|
+
return {
|
|
398
|
+
days: staticTime.days ?? 0,
|
|
399
|
+
hours: staticTime.hours ?? 0,
|
|
400
|
+
minutes: staticTime.minutes ?? 0,
|
|
401
|
+
seconds: staticTime.seconds ?? 0
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
const dist = finalTarget.getTime() - Date.now();
|
|
405
|
+
if (dist <= 0) return { days: 0, hours: 0, minutes: 0, seconds: 0 };
|
|
406
|
+
return {
|
|
407
|
+
days: Math.floor(dist / 864e5),
|
|
408
|
+
hours: Math.floor(dist % 864e5 / 36e5),
|
|
409
|
+
minutes: Math.floor(dist % 36e5 / 6e4),
|
|
410
|
+
seconds: Math.floor(dist % 6e4 / 1e3)
|
|
411
|
+
};
|
|
412
|
+
}, [finalTarget, staticTime]);
|
|
413
|
+
const [timeLeft, setTimeLeft] = (0, import_react.useState)(() => ({
|
|
414
|
+
days: 0,
|
|
415
|
+
hours: 0,
|
|
416
|
+
minutes: 0,
|
|
417
|
+
seconds: 0
|
|
418
|
+
}));
|
|
419
|
+
const completeFired = (0, import_react.useRef)(false);
|
|
420
|
+
(0, import_react.useEffect)(() => {
|
|
421
|
+
if (staticTime) {
|
|
422
|
+
setTimeLeft(calcTimeLeft());
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
setTimeLeft(calcTimeLeft());
|
|
426
|
+
const timer = setInterval(() => {
|
|
427
|
+
const tl = calcTimeLeft();
|
|
428
|
+
setTimeLeft(tl);
|
|
429
|
+
if (!completeFired.current && tl.days === 0 && tl.hours === 0 && tl.minutes === 0 && tl.seconds === 0) {
|
|
430
|
+
completeFired.current = true;
|
|
431
|
+
onComplete?.();
|
|
432
|
+
}
|
|
433
|
+
}, 1e3);
|
|
434
|
+
return () => clearInterval(timer);
|
|
435
|
+
}, [calcTimeLeft, onComplete, staticTime]);
|
|
436
|
+
const segmentEntries = [];
|
|
437
|
+
if (resolvedSegments.days)
|
|
438
|
+
segmentEntries.push({ value: timeLeft.days, label: resolvedLabels.days, digits: dayDigits });
|
|
439
|
+
if (resolvedSegments.hours)
|
|
440
|
+
segmentEntries.push({ value: timeLeft.hours, label: resolvedLabels.hours, digits: 2 });
|
|
441
|
+
if (resolvedSegments.minutes)
|
|
442
|
+
segmentEntries.push({ value: timeLeft.minutes, label: resolvedLabels.minutes, digits: 2 });
|
|
443
|
+
if (resolvedSegments.seconds)
|
|
444
|
+
segmentEntries.push({ value: timeLeft.seconds, label: resolvedLabels.seconds, digits: 2 });
|
|
445
|
+
const items = [];
|
|
446
|
+
segmentEntries.forEach((seg, i) => {
|
|
447
|
+
if (i > 0) {
|
|
448
|
+
items.push(
|
|
449
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SeparatorUnit, { config: sep, cardHeight: card.height }, `sep-${i}`)
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
items.push(
|
|
453
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
454
|
+
FlipClockGroupUnit,
|
|
455
|
+
{
|
|
456
|
+
value: seg.value,
|
|
457
|
+
label: seg.label,
|
|
458
|
+
digits: seg.digits,
|
|
459
|
+
card,
|
|
460
|
+
digitStyle: digit,
|
|
461
|
+
labelStyle: label,
|
|
462
|
+
line,
|
|
463
|
+
animation: anim,
|
|
464
|
+
animId,
|
|
465
|
+
cardGap: cardGapScaled,
|
|
466
|
+
labelGap: labelGapScaled
|
|
467
|
+
},
|
|
468
|
+
seg.label
|
|
469
|
+
)
|
|
470
|
+
);
|
|
471
|
+
});
|
|
472
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
473
|
+
"div",
|
|
474
|
+
{
|
|
475
|
+
className,
|
|
476
|
+
style: {
|
|
477
|
+
display: "flex",
|
|
478
|
+
flexDirection: orientation === "column" ? "column" : "row",
|
|
479
|
+
flexWrap: "nowrap",
|
|
480
|
+
alignItems: "center",
|
|
481
|
+
justifyContent: "center",
|
|
482
|
+
gap: groupGapScaled,
|
|
483
|
+
...style
|
|
484
|
+
},
|
|
485
|
+
children: items
|
|
486
|
+
}
|
|
487
|
+
);
|
|
488
|
+
};
|
|
489
|
+
var FlipClock_default = FlipClock;
|
|
490
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
491
|
+
0 && (module.exports = {
|
|
492
|
+
FlipClock
|
|
493
|
+
});
|
|
494
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/FlipClock.tsx"],"sourcesContent":["export { default as FlipClock, default } from \"./FlipClock\";\r\nexport type {\r\n FlipAnimationConfig,\r\n FlipCardStyle,\r\n FlipClockLabels,\r\n FlipClockProps,\r\n FlipClockSegments,\r\n FlipDigitStyle,\r\n FlipLabelStyle,\r\n FlipLineStyle,\r\n FlipSeparatorConfig,\r\n} from \"./FlipClock\";\r\n","/**\r\n * FlipClock — A fully self-contained, customizable flip clock countdown component.\r\n *\r\n * This component renders a countdown timer with realistic 3D flip-card animations.\r\n * It is designed to be extracted and dropped into any React + TypeScript project\r\n * with zero external CSS dependencies — all styles are inline.\r\n *\r\n * @example\r\n * ```tsx\r\n * // Basic usage with a target date\r\n * <FlipClock targetDate={new Date('2026-12-31T00:00:00')} />\r\n *\r\n * // Custom styled\r\n * <FlipClock\r\n * targetDate={myDate}\r\n * cardBackground=\"#1a1a2e\"\r\n * digitColor=\"#e94560\"\r\n * labelColor=\"#e94560\"\r\n * bounceIntensity={12}\r\n * />\r\n * ```\r\n *\r\n * @module FlipClock\r\n */\r\n\r\nimport {\r\n useState,\r\n useEffect,\r\n useRef,\r\n useMemo,\r\n useCallback,\r\n type CSSProperties,\r\n type ReactNode,\r\n} from \"react\";\r\n\r\n/* ──────────────────────────────────────────────\r\n * Types\r\n * ────────────────────────────────────────────── */\r\n\r\n/** Configuration for the flip animation timing and feel. */\r\nexport interface FlipAnimationConfig {\r\n /** Duration of each half-flip in milliseconds. @default 300 */\r\n flipDuration?: number;\r\n /** Bounce overshoot angle in degrees (0 = no bounce). @default 8 */\r\n bounceIntensity?: number;\r\n /** Easing function for the top flap falling. @default \"ease-in\" */\r\n flipDownEasing?: string;\r\n /** Easing function for the bottom flap landing. @default \"ease-out\" */\r\n flipUpEasing?: string;\r\n}\r\n\r\n/** Configuration for the card appearance. */\r\nexport interface FlipCardStyle {\r\n /** Top-half background color. @default \"#575757\" */\r\n background?: string;\r\n /** Bottom-half background color (slightly darker). @default \"#4a4a4a\" */\r\n backgroundDark?: string;\r\n /** Card width (CSS value). @default \"7rem\" */\r\n width?: string;\r\n /** Card height (CSS value). @default \"9.5rem\" */\r\n height?: string;\r\n /** Border radius (CSS value). @default \"0.5rem\" */\r\n borderRadius?: string;\r\n /** Box shadow (CSS value). @default \"0 3px 8px rgba(0,0,0,0.25)\" */\r\n boxShadow?: string;\r\n}\r\n\r\n/** Configuration for the digit typography. */\r\nexport interface FlipDigitStyle {\r\n /** Digit text color. @default \"#ffffff\" */\r\n color?: string;\r\n /** Font family for digits. @default \"'Bebas Neue', sans-serif\" */\r\n fontFamily?: string;\r\n /** Font size (CSS value). @default \"5.5rem\" */\r\n fontSize?: string;\r\n /** Text shadow (CSS value). @default \"none\" */\r\n textShadow?: string;\r\n}\r\n\r\n/** Configuration for the group labels (DAYS, HOURS, etc.). */\r\nexport interface FlipLabelStyle {\r\n /** Whether to show labels. @default true */\r\n visible?: boolean;\r\n /** Label text color. @default \"#999999\" */\r\n color?: string;\r\n /** Label font family. @default \"'Inter', sans-serif\" */\r\n fontFamily?: string;\r\n /** Label font size (CSS value). @default \"0.9rem\" */\r\n fontSize?: string;\r\n /** Label font weight. @default \"500\" */\r\n fontWeight?: string;\r\n /** Letter spacing (CSS value). @default \"0.2em\" */\r\n letterSpacing?: string;\r\n /** Text transform. @default \"uppercase\" */\r\n textTransform?: CSSProperties[\"textTransform\"];\r\n}\r\n\r\n/** Configuration for the horizontal divider line on each card. */\r\nexport interface FlipLineStyle {\r\n /** Line color. @default \"rgba(0,0,0,0.25)\" */\r\n color?: string;\r\n /** Line height (CSS value). @default \"1px\" */\r\n height?: string;\r\n}\r\n\r\n/** Optional separator between groups (e.g., colon dots). */\r\nexport interface FlipSeparatorConfig {\r\n /** Type of separator. @default \"none\" */\r\n type?: \"none\" | \"colon\" | \"dot\";\r\n /** Separator color. @default \"#999999\" */\r\n color?: string;\r\n /** Separator size (CSS value). @default \"0.5rem\" */\r\n size?: string;\r\n}\r\n\r\n/** Custom labels for each time unit. */\r\nexport interface FlipClockLabels {\r\n days?: string;\r\n hours?: string;\r\n minutes?: string;\r\n seconds?: string;\r\n}\r\n\r\n/** Which time segments to display. */\r\nexport interface FlipClockSegments {\r\n /** Show days segment. @default true */\r\n days?: boolean;\r\n /** Show hours segment. @default true */\r\n hours?: boolean;\r\n /** Show minutes segment. @default true */\r\n minutes?: boolean;\r\n /** Show seconds segment. @default true */\r\n seconds?: boolean;\r\n}\r\n\r\n/**\r\n * Props for the FlipClock component.\r\n *\r\n * All props are optional and have sensible defaults that produce the\r\n * classic dark-card-on-light-background flip clock aesthetic.\r\n */\r\nexport interface FlipClockProps {\r\n /** The target date to count down to. @default 88 days from now */\r\n targetDate?: Date;\r\n\r\n /** Override the countdown with static values (disables auto-tick). */\r\n staticTime?: {\r\n days?: number;\r\n hours?: number;\r\n minutes?: number;\r\n seconds?: number;\r\n };\r\n\r\n /** Card appearance configuration. */\r\n cardStyle?: FlipCardStyle;\r\n\r\n /** Digit typography configuration. */\r\n digitStyle?: FlipDigitStyle;\r\n\r\n /** Label configuration. */\r\n labelStyle?: FlipLabelStyle;\r\n\r\n /** Horizontal divider line configuration. */\r\n lineStyle?: FlipLineStyle;\r\n\r\n /** Flip animation configuration. */\r\n animation?: FlipAnimationConfig;\r\n\r\n /** Separator between time groups. */\r\n separator?: FlipSeparatorConfig;\r\n\r\n /** Custom label text. */\r\n labels?: FlipClockLabels;\r\n\r\n /** Which segments to display. */\r\n segments?: FlipClockSegments;\r\n\r\n /** Number of digits for the days display. @default 2 */\r\n dayDigits?: number;\r\n\r\n /** Gap between time groups (CSS value). @default \"3rem\" */\r\n groupGap?: string;\r\n\r\n /** Gap between individual digit cards (CSS value). @default \"0.375rem\" */\r\n cardGap?: string;\r\n\r\n /** Gap between cards and the label (CSS value). @default \"1rem\" */\r\n labelGap?: string;\r\n\r\n /** Callback fired when countdown reaches zero. */\r\n onComplete?: () => void;\r\n\r\n /**\r\n * Layout direction: \"row\" (horizontal) or \"column\" (stacked).\r\n * Set from the parent (e.g. via media queries) for optimal view per screen size.\r\n * @default \"row\"\r\n */\r\n orientation?: \"row\" | \"column\";\r\n\r\n /**\r\n * Scale factor for the whole clock (cards, digits, gaps). Use for coarse size control from outside.\r\n * Applied on top of cardStyle / digitStyle. Example: scale={0.8} gives 80% size.\r\n * @default 1\r\n */\r\n scale?: number;\r\n\r\n /** Additional className for the outer wrapper. */\r\n className?: string;\r\n\r\n /** Additional inline style for the outer wrapper. */\r\n style?: CSSProperties;\r\n}\r\n\r\n/* ──────────────────────────────────────────────\r\n * Defaults\r\n * ────────────────────────────────────────────── */\r\n\r\nconst DEFAULT_CARD: Required<FlipCardStyle> = {\r\n background: \"#575757\",\r\n backgroundDark: \"#4a4a4a\",\r\n width: \"7rem\",\r\n height: \"9.5rem\",\r\n borderRadius: \"0.5rem\",\r\n boxShadow: \"0 3px 8px rgba(0,0,0,0.25), 0 1px 3px rgba(0,0,0,0.15)\",\r\n};\r\n\r\nconst DEFAULT_DIGIT: Required<FlipDigitStyle> = {\r\n color: \"#ffffff\",\r\n fontFamily: \"'Bebas Neue', sans-serif\",\r\n fontSize: \"5.5rem\",\r\n textShadow: \"none\",\r\n};\r\n\r\nconst DEFAULT_LABEL: Required<FlipLabelStyle> = {\r\n visible: true,\r\n color: \"#999999\",\r\n fontFamily: \"'Inter', sans-serif\",\r\n fontSize: \"0.9rem\",\r\n fontWeight: \"500\",\r\n letterSpacing: \"0.2em\",\r\n textTransform: \"uppercase\",\r\n};\r\n\r\nconst DEFAULT_LINE: Required<FlipLineStyle> = {\r\n color: \"rgba(0,0,0,0.25)\",\r\n height: \"1px\",\r\n};\r\n\r\nconst DEFAULT_ANIMATION: Required<FlipAnimationConfig> = {\r\n flipDuration: 300,\r\n bounceIntensity: 8,\r\n flipDownEasing: \"ease-in\",\r\n flipUpEasing: \"ease-out\",\r\n};\r\n\r\nconst DEFAULT_SEPARATOR: Required<FlipSeparatorConfig> = {\r\n type: \"none\",\r\n color: \"#999999\",\r\n size: \"0.5rem\",\r\n};\r\n\r\n/** Multiply a CSS length (e.g. \"7rem\", \"0.375rem\") by a factor. Non-length values returned as-is. */\r\nfunction scaleCssLength(value: string, factor: number): string {\r\n if (factor === 1) return value;\r\n const match = value.trim().match(/^(-?\\d*\\.?\\d+)(r?em|px)$/);\r\n if (!match) return value;\r\n const num = Number(match[1]);\r\n const unit = match[2];\r\n return `${num * factor}${unit}`;\r\n}\r\n\r\n/* ──────────────────────────────────────────────\r\n * Utility: generate unique animation keyframes\r\n * ────────────────────────────────────────────── */\r\n\r\nlet styleInjected = false;\r\nlet currentAnimId = \"\";\r\n\r\nfunction injectKeyframes(animation: Required<FlipAnimationConfig>) {\r\n const id = `fc-${animation.flipDuration}-${animation.bounceIntensity}`;\r\n if (typeof document === \"undefined\") return id;\r\n\r\n if (styleInjected && currentAnimId === id) return id;\r\n\r\n const existingEl = document.getElementById(id);\r\n if (existingEl) {\r\n styleInjected = true;\r\n currentAnimId = id;\r\n return id;\r\n }\r\n\r\n const bounce = animation.bounceIntensity;\r\n const halfBounce = bounce / 2;\r\n\r\n const css = `\r\n @keyframes ${id}-flip-top {\r\n 0% { transform: rotateX(0deg); }\r\n 100% { transform: rotateX(-90deg); }\r\n }\r\n @keyframes ${id}-flip-bottom {\r\n 0% { transform: rotateX(90deg); }\r\n 60% { transform: rotateX(-${bounce}deg); }\r\n 80% { transform: rotateX(${halfBounce}deg); }\r\n 100% { transform: rotateX(0deg); }\r\n }\r\n `;\r\n\r\n const styleEl = document.createElement(\"style\");\r\n styleEl.id = id;\r\n styleEl.textContent = css;\r\n document.head.appendChild(styleEl);\r\n\r\n styleInjected = true;\r\n currentAnimId = id;\r\n return id;\r\n}\r\n\r\n/* ──────────────────────────────────────────────\r\n * Sub-component: FlipCardUnit (single digit)\r\n * ────────────────────────────────────────────── */\r\n\r\ninterface FlipCardUnitProps {\r\n digit: number;\r\n card: Required<FlipCardStyle>;\r\n digitStyle: Required<FlipDigitStyle>;\r\n line: Required<FlipLineStyle>;\r\n animation: Required<FlipAnimationConfig>;\r\n animId: string;\r\n}\r\n\r\n/**\r\n * Renders a single flip-card digit with a 3D flip animation\r\n * whenever the digit value changes.\r\n */\r\nconst FlipCardUnit = ({\r\n digit,\r\n card,\r\n digitStyle,\r\n line,\r\n animation,\r\n animId,\r\n}: FlipCardUnitProps) => {\r\n const [currentDigit, setCurrentDigit] = useState(digit);\r\n const [previousDigit, setPreviousDigit] = useState(digit);\r\n const [isFlipping, setIsFlipping] = useState(false);\r\n const prevDigitRef = useRef(digit);\r\n const flippingToDigitRef = useRef(digit);\r\n const bottomFlapRef = useRef<HTMLDivElement>(null);\r\n\r\n useEffect(() => {\r\n if (prevDigitRef.current !== digit) {\r\n setPreviousDigit(prevDigitRef.current);\r\n flippingToDigitRef.current = digit;\r\n prevDigitRef.current = digit;\r\n setIsFlipping(true);\r\n }\r\n }, [digit]);\r\n\r\n useEffect(() => {\r\n if (!isFlipping) return;\r\n const el = bottomFlapRef.current;\r\n if (!el) return;\r\n\r\n const done = () => {\r\n setCurrentDigit(flippingToDigitRef.current);\r\n setIsFlipping(false);\r\n };\r\n\r\n const onAnimationEnd = (e: AnimationEvent) => {\r\n if (e.animationName.includes(\"flip-bottom\")) {\r\n done();\r\n }\r\n };\r\n\r\n el.addEventListener(\"animationend\", onAnimationEnd as EventListener);\r\n const fallback = setTimeout(done, animation.flipDuration * 2);\r\n\r\n return () => {\r\n el.removeEventListener(\"animationend\", onAnimationEnd as EventListener);\r\n clearTimeout(fallback);\r\n };\r\n }, [isFlipping, animation.flipDuration]);\r\n\r\n const containerStyle: CSSProperties = {\r\n position: \"relative\",\r\n width: card.width,\r\n height: card.height,\r\n perspective: \"400px\",\r\n borderRadius: card.borderRadius,\r\n background: card.background,\r\n boxShadow: card.boxShadow,\r\n overflow: \"hidden\",\r\n };\r\n\r\n const digitCss: CSSProperties = {\r\n fontFamily: digitStyle.fontFamily,\r\n fontSize: digitStyle.fontSize,\r\n lineHeight: 1,\r\n color: digitStyle.color,\r\n textShadow: digitStyle.textShadow,\r\n userSelect: \"none\",\r\n };\r\n\r\n const faceBase: CSSProperties = {\r\n position: \"absolute\",\r\n width: \"100%\",\r\n height: \"50%\",\r\n overflow: \"hidden\",\r\n backfaceVisibility: \"hidden\",\r\n display: \"flex\",\r\n justifyContent: \"center\",\r\n };\r\n\r\n const topFace: CSSProperties = {\r\n ...faceBase,\r\n top: 0,\r\n background: card.background,\r\n borderRadius: `${card.borderRadius} ${card.borderRadius} 0 0`,\r\n alignItems: \"flex-end\",\r\n };\r\n\r\n const bottomFace: CSSProperties = {\r\n ...faceBase,\r\n bottom: 0,\r\n background: card.backgroundDark,\r\n borderRadius: `0 0 ${card.borderRadius} ${card.borderRadius}`,\r\n alignItems: \"flex-start\",\r\n };\r\n\r\n const lineStyle: CSSProperties = {\r\n position: \"absolute\",\r\n top: \"50%\",\r\n left: 0,\r\n right: 0,\r\n height: line.height,\r\n background: line.color,\r\n zIndex: 10,\r\n };\r\n\r\n const flipTopStyle: CSSProperties = {\r\n ...topFace,\r\n transformOrigin: \"bottom center\",\r\n zIndex: 20,\r\n willChange: \"transform\",\r\n animation: isFlipping\r\n ? `${animId}-flip-top ${animation.flipDuration}ms ${animation.flipDownEasing} forwards`\r\n : undefined,\r\n };\r\n\r\n const flipBottomStyle: CSSProperties = {\r\n ...bottomFace,\r\n transformOrigin: \"top center\",\r\n zIndex: 20,\r\n transform: \"rotateX(90deg)\",\r\n willChange: \"transform\",\r\n animation: isFlipping\r\n ? `${animId}-flip-bottom ${animation.flipDuration}ms ${animation.flipDuration}ms ${animation.flipUpEasing} forwards`\r\n : undefined,\r\n };\r\n\r\n const staticTopDigit =\r\n !isFlipping && digit !== currentDigit ? currentDigit : digit;\r\n\r\n return (\r\n <div style={containerStyle}>\r\n {/* Static top half — new digit once flap covers or is gone; old only for the one pre-flip frame */}\r\n <div style={topFace}>\r\n <span style={{ ...digitCss, transform: \"translateY(50%)\" }}>{staticTopDigit}</span>\r\n </div>\r\n\r\n {/* Static bottom half — current (old until animation finishes) */}\r\n <div style={bottomFace}>\r\n <span style={{ ...digitCss, transform: \"translateY(-50%)\" }}>\r\n {currentDigit}\r\n </span>\r\n </div>\r\n\r\n {/* Divider line */}\r\n <div style={lineStyle} />\r\n\r\n {/* Animated top flap — old digit flips down */}\r\n {isFlipping && (\r\n <div style={flipTopStyle}>\r\n <span style={{ ...digitCss, transform: \"translateY(50%)\" }}>\r\n {previousDigit}\r\n </span>\r\n </div>\r\n )}\r\n\r\n {/* Animated bottom flap — new digit flips up */}\r\n {isFlipping && (\r\n <div ref={bottomFlapRef} style={flipBottomStyle}>\r\n <span style={{ ...digitCss, transform: \"translateY(-50%)\" }}>\r\n {digit}\r\n </span>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\n/* ──────────────────────────────────────────────\r\n * Sub-component: FlipClockGroupUnit\r\n * ────────────────────────────────────────────── */\r\n\r\ninterface FlipClockGroupUnitProps {\r\n value: number;\r\n label: string;\r\n digits: number;\r\n card: Required<FlipCardStyle>;\r\n digitStyle: Required<FlipDigitStyle>;\r\n labelStyle: Required<FlipLabelStyle>;\r\n line: Required<FlipLineStyle>;\r\n animation: Required<FlipAnimationConfig>;\r\n animId: string;\r\n cardGap: string;\r\n labelGap: string;\r\n}\r\n\r\n/**\r\n * Renders a group of flip-card digits (e.g., two digits for hours)\r\n * with an optional label underneath.\r\n */\r\nconst FlipClockGroupUnit = ({\r\n value,\r\n label,\r\n digits,\r\n card,\r\n digitStyle,\r\n labelStyle,\r\n line,\r\n animation,\r\n animId,\r\n cardGap,\r\n labelGap,\r\n}: FlipClockGroupUnitProps) => {\r\n const valueStr = String(value).padStart(digits, \"0\");\r\n const digitArray = valueStr.split(\"\").map(Number);\r\n\r\n return (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n alignItems: \"center\",\r\n gap: labelGap,\r\n flexShrink: 0,\r\n }}\r\n >\r\n <div style={{ display: \"flex\", gap: cardGap }}>\r\n {digitArray.map((d, i) => (\r\n <FlipCardUnit\r\n key={i}\r\n digit={d}\r\n card={card}\r\n digitStyle={digitStyle}\r\n line={line}\r\n animation={animation}\r\n animId={animId}\r\n />\r\n ))}\r\n </div>\r\n {labelStyle.visible && (\r\n <span\r\n style={{\r\n fontFamily: labelStyle.fontFamily,\r\n fontSize: labelStyle.fontSize,\r\n fontWeight: labelStyle.fontWeight,\r\n letterSpacing: labelStyle.letterSpacing,\r\n textTransform: labelStyle.textTransform,\r\n color: labelStyle.color,\r\n }}\r\n >\r\n {label}\r\n </span>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\n/* ──────────────────────────────────────────────\r\n * Sub-component: Separator\r\n * ────────────────────────────────────────────── */\r\n\r\ninterface SeparatorProps {\r\n config: Required<FlipSeparatorConfig>;\r\n cardHeight: string;\r\n}\r\n\r\n/** Renders an optional separator (colon or dot) between time groups. */\r\nconst SeparatorUnit = ({ config, cardHeight }: SeparatorProps) => {\r\n if (config.type === \"none\") return null;\r\n\r\n const dotStyle: CSSProperties = {\r\n width: config.size,\r\n height: config.size,\r\n borderRadius: \"50%\",\r\n background: config.color,\r\n };\r\n\r\n return (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n gap: config.size,\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n height: cardHeight,\r\n flexShrink: 0,\r\n }}\r\n >\r\n {config.type === \"colon\" && (\r\n <>\r\n <div style={dotStyle} />\r\n <div style={dotStyle} />\r\n </>\r\n )}\r\n {config.type === \"dot\" && <div style={dotStyle} />}\r\n </div>\r\n );\r\n};\r\n\r\n/* ──────────────────────────────────────────────\r\n * Main component: FlipClock\r\n * ────────────────────────────────────────────── */\r\n\r\n/**\r\n * A customizable flip-clock countdown component with realistic 3D card-flip animations.\r\n *\r\n * Features:\r\n * - Countdown to any target date or display static time\r\n * - Full visual customization: card colors, digit font, labels, separators, animation\r\n * - Bounce animation on the bottom flap for a tactile feel\r\n * - Self-contained — no external CSS required (all styles are inline)\r\n * - Responsive-ready — set sizes via props\r\n *\r\n * @example\r\n * ```tsx\r\n * // Minimal\r\n * <FlipClock targetDate={new Date('2027-01-01')} />\r\n *\r\n * // Fully customized\r\n * <FlipClock\r\n * targetDate={deadline}\r\n * cardStyle={{ background: '#1e1e2e', backgroundDark: '#181825', borderRadius: '1rem' }}\r\n * digitStyle={{ color: '#cba6f7', fontFamily: 'monospace', fontSize: '4rem' }}\r\n * labelStyle={{ color: '#a6adc8', fontSize: '0.75rem' }}\r\n * animation={{ bounceIntensity: 15, flipDuration: 400 }}\r\n * separator={{ type: 'colon', color: '#cba6f7' }}\r\n * groupGap=\"2rem\"\r\n * onComplete={() => console.log('Done!')}\r\n * />\r\n * ```\r\n */\r\nconst FlipClock = ({\r\n targetDate,\r\n staticTime,\r\n cardStyle,\r\n digitStyle,\r\n labelStyle,\r\n lineStyle,\r\n animation,\r\n separator,\r\n labels,\r\n segments,\r\n dayDigits = 2,\r\n groupGap = \"3rem\",\r\n cardGap = \"0.375rem\",\r\n labelGap = \"1rem\",\r\n onComplete,\r\n orientation = \"row\",\r\n scale: scaleProp = 1,\r\n className,\r\n style,\r\n}: FlipClockProps) => {\r\n /* Merge props with defaults */\r\n const cardBase = useMemo(() => ({ ...DEFAULT_CARD, ...cardStyle }), [cardStyle]);\r\n const digitBase = useMemo(() => ({ ...DEFAULT_DIGIT, ...digitStyle }), [digitStyle]);\r\n const labelBase = useMemo(() => ({ ...DEFAULT_LABEL, ...labelStyle }), [labelStyle]);\r\n const lineBase = useMemo(() => ({ ...DEFAULT_LINE, ...lineStyle }), [lineStyle]);\r\n const anim = useMemo(() => ({ ...DEFAULT_ANIMATION, ...animation }), [animation]);\r\n const sepBase = useMemo(() => ({ ...DEFAULT_SEPARATOR, ...separator }), [separator]);\r\n\r\n /* Apply scale factor to size-related values (cards, digits, gaps, separator, label/line) */\r\n const scale = Math.max(0.1, Math.min(10, scaleProp));\r\n const card = useMemo(\r\n () =>\r\n scale === 1\r\n ? cardBase\r\n : {\r\n ...cardBase,\r\n width: scaleCssLength(cardBase.width, scale),\r\n height: scaleCssLength(cardBase.height, scale),\r\n borderRadius: scaleCssLength(cardBase.borderRadius, scale),\r\n },\r\n [cardBase, scale]\r\n );\r\n const digit = useMemo(\r\n () =>\r\n scale === 1 ? digitBase : { ...digitBase, fontSize: scaleCssLength(digitBase.fontSize, scale) },\r\n [digitBase, scale]\r\n );\r\n const label = useMemo(\r\n () =>\r\n scale === 1 ? labelBase : { ...labelBase, fontSize: scaleCssLength(labelBase.fontSize, scale) },\r\n [labelBase, scale]\r\n );\r\n const line = useMemo(\r\n () =>\r\n scale === 1 ? lineBase : { ...lineBase, height: scaleCssLength(lineBase.height, scale) },\r\n [lineBase, scale]\r\n );\r\n const sep = useMemo(\r\n () =>\r\n scale === 1 ? sepBase : { ...sepBase, size: scaleCssLength(sepBase.size, scale) },\r\n [sepBase, scale]\r\n );\r\n const groupGapScaled = scale === 1 ? groupGap : scaleCssLength(groupGap, scale);\r\n const cardGapScaled = scale === 1 ? cardGap : scaleCssLength(cardGap, scale);\r\n const labelGapScaled = scale === 1 ? labelGap : scaleCssLength(labelGap, scale);\r\n\r\n const resolvedLabels = useMemo(\r\n () => ({\r\n days: labels?.days ?? \"Days\",\r\n hours: labels?.hours ?? \"Hours\",\r\n minutes: labels?.minutes ?? \"Minutes\",\r\n seconds: labels?.seconds ?? \"Seconds\",\r\n }),\r\n [labels]\r\n );\r\n\r\n const resolvedSegments = useMemo(\r\n () => ({\r\n days: segments?.days ?? true,\r\n hours: segments?.hours ?? true,\r\n minutes: segments?.minutes ?? true,\r\n seconds: segments?.seconds ?? true,\r\n }),\r\n [segments]\r\n );\r\n\r\n /* Inject keyframe styles */\r\n const animId = useMemo(() => injectKeyframes(anim), [anim]);\r\n\r\n /* Countdown logic */\r\n const defaultTarget = useMemo(() => {\r\n const d = new Date();\r\n d.setDate(d.getDate() + 88);\r\n d.setHours(d.getHours() + 14);\r\n return d;\r\n }, []);\r\n\r\n const finalTarget = targetDate ?? defaultTarget;\r\n\r\n const calcTimeLeft = useCallback(() => {\r\n if (staticTime) {\r\n return {\r\n days: staticTime.days ?? 0,\r\n hours: staticTime.hours ?? 0,\r\n minutes: staticTime.minutes ?? 0,\r\n seconds: staticTime.seconds ?? 0,\r\n };\r\n }\r\n const dist = finalTarget.getTime() - Date.now();\r\n if (dist <= 0) return { days: 0, hours: 0, minutes: 0, seconds: 0 };\r\n return {\r\n days: Math.floor(dist / 86400000),\r\n hours: Math.floor((dist % 86400000) / 3600000),\r\n minutes: Math.floor((dist % 3600000) / 60000),\r\n seconds: Math.floor((dist % 60000) / 1000),\r\n };\r\n }, [finalTarget, staticTime]);\r\n\r\n const [timeLeft, setTimeLeft] = useState(() => ({\r\n days: 0,\r\n hours: 0,\r\n minutes: 0,\r\n seconds: 0,\r\n }));\r\n const completeFired = useRef(false);\r\n\r\n useEffect(() => {\r\n if (staticTime) {\r\n setTimeLeft(calcTimeLeft());\r\n return;\r\n }\r\n\r\n setTimeLeft(calcTimeLeft());\r\n const timer = setInterval(() => {\r\n const tl = calcTimeLeft();\r\n setTimeLeft(tl);\r\n\r\n if (\r\n !completeFired.current &&\r\n tl.days === 0 &&\r\n tl.hours === 0 &&\r\n tl.minutes === 0 &&\r\n tl.seconds === 0\r\n ) {\r\n completeFired.current = true;\r\n onComplete?.();\r\n }\r\n }, 1000);\r\n\r\n return () => clearInterval(timer);\r\n }, [calcTimeLeft, onComplete, staticTime]);\r\n\r\n /* Build segment list */\r\n const segmentEntries: { value: number; label: string; digits: number }[] = [];\r\n if (resolvedSegments.days)\r\n segmentEntries.push({ value: timeLeft.days, label: resolvedLabels.days, digits: dayDigits });\r\n if (resolvedSegments.hours)\r\n segmentEntries.push({ value: timeLeft.hours, label: resolvedLabels.hours, digits: 2 });\r\n if (resolvedSegments.minutes)\r\n segmentEntries.push({ value: timeLeft.minutes, label: resolvedLabels.minutes, digits: 2 });\r\n if (resolvedSegments.seconds)\r\n segmentEntries.push({ value: timeLeft.seconds, label: resolvedLabels.seconds, digits: 2 });\r\n\r\n const items: ReactNode[] = [];\r\n segmentEntries.forEach((seg, i) => {\r\n if (i > 0) {\r\n items.push(\r\n <SeparatorUnit key={`sep-${i}`} config={sep} cardHeight={card.height} />\r\n );\r\n }\r\n items.push(\r\n <FlipClockGroupUnit\r\n key={seg.label}\r\n value={seg.value}\r\n label={seg.label}\r\n digits={seg.digits}\r\n card={card}\r\n digitStyle={digit}\r\n labelStyle={label}\r\n line={line}\r\n animation={anim}\r\n animId={animId}\r\n cardGap={cardGapScaled}\r\n labelGap={labelGapScaled}\r\n />\r\n );\r\n });\r\n\r\n return (\r\n <div\r\n className={className}\r\n style={{\r\n display: \"flex\",\r\n flexDirection: orientation === \"column\" ? \"column\" : \"row\",\r\n flexWrap: \"nowrap\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n gap: groupGapScaled,\r\n ...style,\r\n }}\r\n >\r\n {items}\r\n </div>\r\n );\r\n};\r\n\r\nexport default FlipClock;\r\n"],"mappings":"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","names":[]}
|