@waqarfazal/ios-time-picker-react
Version:
A beautiful iOS-style time picker component for React with smooth animations and physics-based scrolling
729 lines (706 loc) • 33.1 kB
JavaScript
import require$$0, { useState, useRef, useEffect, useCallback } from 'react';
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __spreadArray(to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
var jsxRuntime = {exports: {}};
var reactJsxRuntime_production = {};
/**
* @license React
* react-jsx-runtime.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var hasRequiredReactJsxRuntime_production;
function requireReactJsxRuntime_production () {
if (hasRequiredReactJsxRuntime_production) return reactJsxRuntime_production;
hasRequiredReactJsxRuntime_production = 1;
var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"),
REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
function jsxProd(type, config, maybeKey) {
var key = null;
void 0 !== maybeKey && (key = "" + maybeKey);
void 0 !== config.key && (key = "" + config.key);
if ("key" in config) {
maybeKey = {};
for (var propName in config)
"key" !== propName && (maybeKey[propName] = config[propName]);
} else maybeKey = config;
config = maybeKey.ref;
return {
$$typeof: REACT_ELEMENT_TYPE,
type: type,
key: key,
ref: void 0 !== config ? config : null,
props: maybeKey
};
}
reactJsxRuntime_production.Fragment = REACT_FRAGMENT_TYPE;
reactJsxRuntime_production.jsx = jsxProd;
reactJsxRuntime_production.jsxs = jsxProd;
return reactJsxRuntime_production;
}
var reactJsxRuntime_development = {};
/**
* @license React
* react-jsx-runtime.development.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var hasRequiredReactJsxRuntime_development;
function requireReactJsxRuntime_development () {
if (hasRequiredReactJsxRuntime_development) return reactJsxRuntime_development;
hasRequiredReactJsxRuntime_development = 1;
"production" !== process.env.NODE_ENV &&
(function () {
function getComponentNameFromType(type) {
if (null == type) return null;
if ("function" === typeof type)
return type.$$typeof === REACT_CLIENT_REFERENCE
? null
: type.displayName || type.name || null;
if ("string" === typeof type) return type;
switch (type) {
case REACT_FRAGMENT_TYPE:
return "Fragment";
case REACT_PROFILER_TYPE:
return "Profiler";
case REACT_STRICT_MODE_TYPE:
return "StrictMode";
case REACT_SUSPENSE_TYPE:
return "Suspense";
case REACT_SUSPENSE_LIST_TYPE:
return "SuspenseList";
case REACT_ACTIVITY_TYPE:
return "Activity";
}
if ("object" === typeof type)
switch (
("number" === typeof type.tag &&
console.error(
"Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
),
type.$$typeof)
) {
case REACT_PORTAL_TYPE:
return "Portal";
case REACT_CONTEXT_TYPE:
return (type.displayName || "Context") + ".Provider";
case REACT_CONSUMER_TYPE:
return (type._context.displayName || "Context") + ".Consumer";
case REACT_FORWARD_REF_TYPE:
var innerType = type.render;
type = type.displayName;
type ||
((type = innerType.displayName || innerType.name || ""),
(type = "" !== type ? "ForwardRef(" + type + ")" : "ForwardRef"));
return type;
case REACT_MEMO_TYPE:
return (
(innerType = type.displayName || null),
null !== innerType
? innerType
: getComponentNameFromType(type.type) || "Memo"
);
case REACT_LAZY_TYPE:
innerType = type._payload;
type = type._init;
try {
return getComponentNameFromType(type(innerType));
} catch (x) {}
}
return null;
}
function testStringCoercion(value) {
return "" + value;
}
function checkKeyStringCoercion(value) {
try {
testStringCoercion(value);
var JSCompiler_inline_result = !1;
} catch (e) {
JSCompiler_inline_result = true;
}
if (JSCompiler_inline_result) {
JSCompiler_inline_result = console;
var JSCompiler_temp_const = JSCompiler_inline_result.error;
var JSCompiler_inline_result$jscomp$0 =
("function" === typeof Symbol &&
Symbol.toStringTag &&
value[Symbol.toStringTag]) ||
value.constructor.name ||
"Object";
JSCompiler_temp_const.call(
JSCompiler_inline_result,
"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
JSCompiler_inline_result$jscomp$0
);
return testStringCoercion(value);
}
}
function getTaskName(type) {
if (type === REACT_FRAGMENT_TYPE) return "<>";
if (
"object" === typeof type &&
null !== type &&
type.$$typeof === REACT_LAZY_TYPE
)
return "<...>";
try {
var name = getComponentNameFromType(type);
return name ? "<" + name + ">" : "<...>";
} catch (x) {
return "<...>";
}
}
function getOwner() {
var dispatcher = ReactSharedInternals.A;
return null === dispatcher ? null : dispatcher.getOwner();
}
function UnknownOwner() {
return Error("react-stack-top-frame");
}
function hasValidKey(config) {
if (hasOwnProperty.call(config, "key")) {
var getter = Object.getOwnPropertyDescriptor(config, "key").get;
if (getter && getter.isReactWarning) return false;
}
return void 0 !== config.key;
}
function defineKeyPropWarningGetter(props, displayName) {
function warnAboutAccessingKey() {
specialPropKeyWarningShown ||
((specialPropKeyWarningShown = true),
console.error(
"%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
displayName
));
}
warnAboutAccessingKey.isReactWarning = true;
Object.defineProperty(props, "key", {
get: warnAboutAccessingKey,
configurable: true
});
}
function elementRefGetterWithDeprecationWarning() {
var componentName = getComponentNameFromType(this.type);
didWarnAboutElementRef[componentName] ||
((didWarnAboutElementRef[componentName] = true),
console.error(
"Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."
));
componentName = this.props.ref;
return void 0 !== componentName ? componentName : null;
}
function ReactElement(
type,
key,
self,
source,
owner,
props,
debugStack,
debugTask
) {
self = props.ref;
type = {
$$typeof: REACT_ELEMENT_TYPE,
type: type,
key: key,
props: props,
_owner: owner
};
null !== (void 0 !== self ? self : null)
? Object.defineProperty(type, "ref", {
enumerable: false,
get: elementRefGetterWithDeprecationWarning
})
: Object.defineProperty(type, "ref", { enumerable: false, value: null });
type._store = {};
Object.defineProperty(type._store, "validated", {
configurable: false,
enumerable: false,
writable: true,
value: 0
});
Object.defineProperty(type, "_debugInfo", {
configurable: false,
enumerable: false,
writable: true,
value: null
});
Object.defineProperty(type, "_debugStack", {
configurable: false,
enumerable: false,
writable: true,
value: debugStack
});
Object.defineProperty(type, "_debugTask", {
configurable: false,
enumerable: false,
writable: true,
value: debugTask
});
Object.freeze && (Object.freeze(type.props), Object.freeze(type));
return type;
}
function jsxDEVImpl(
type,
config,
maybeKey,
isStaticChildren,
source,
self,
debugStack,
debugTask
) {
var children = config.children;
if (void 0 !== children)
if (isStaticChildren)
if (isArrayImpl(children)) {
for (
isStaticChildren = 0;
isStaticChildren < children.length;
isStaticChildren++
)
validateChildKeys(children[isStaticChildren]);
Object.freeze && Object.freeze(children);
} else
console.error(
"React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
);
else validateChildKeys(children);
if (hasOwnProperty.call(config, "key")) {
children = getComponentNameFromType(type);
var keys = Object.keys(config).filter(function (k) {
return "key" !== k;
});
isStaticChildren =
0 < keys.length
? "{key: someKey, " + keys.join(": ..., ") + ": ...}"
: "{key: someKey}";
didWarnAboutKeySpread[children + isStaticChildren] ||
((keys =
0 < keys.length ? "{" + keys.join(": ..., ") + ": ...}" : "{}"),
console.error(
'A props object containing a "key" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />',
isStaticChildren,
children,
keys,
children
),
(didWarnAboutKeySpread[children + isStaticChildren] = true));
}
children = null;
void 0 !== maybeKey &&
(checkKeyStringCoercion(maybeKey), (children = "" + maybeKey));
hasValidKey(config) &&
(checkKeyStringCoercion(config.key), (children = "" + config.key));
if ("key" in config) {
maybeKey = {};
for (var propName in config)
"key" !== propName && (maybeKey[propName] = config[propName]);
} else maybeKey = config;
children &&
defineKeyPropWarningGetter(
maybeKey,
"function" === typeof type
? type.displayName || type.name || "Unknown"
: type
);
return ReactElement(
type,
children,
self,
source,
getOwner(),
maybeKey,
debugStack,
debugTask
);
}
function validateChildKeys(node) {
"object" === typeof node &&
null !== node &&
node.$$typeof === REACT_ELEMENT_TYPE &&
node._store &&
(node._store.validated = 1);
}
var React = require$$0,
REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"),
REACT_PORTAL_TYPE = Symbol.for("react.portal"),
REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"),
REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"),
REACT_PROFILER_TYPE = Symbol.for("react.profiler");
var REACT_CONSUMER_TYPE = Symbol.for("react.consumer"),
REACT_CONTEXT_TYPE = Symbol.for("react.context"),
REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"),
REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"),
REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"),
REACT_MEMO_TYPE = Symbol.for("react.memo"),
REACT_LAZY_TYPE = Symbol.for("react.lazy"),
REACT_ACTIVITY_TYPE = Symbol.for("react.activity"),
REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"),
ReactSharedInternals =
React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
hasOwnProperty = Object.prototype.hasOwnProperty,
isArrayImpl = Array.isArray,
createTask = console.createTask
? console.createTask
: function () {
return null;
};
React = {
react_stack_bottom_frame: function (callStackForError) {
return callStackForError();
}
};
var specialPropKeyWarningShown;
var didWarnAboutElementRef = {};
var unknownOwnerDebugStack = React.react_stack_bottom_frame.bind(
React,
UnknownOwner
)();
var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
var didWarnAboutKeySpread = {};
reactJsxRuntime_development.Fragment = REACT_FRAGMENT_TYPE;
reactJsxRuntime_development.jsx = function (type, config, maybeKey, source, self) {
var trackActualOwner =
1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;
return jsxDEVImpl(
type,
config,
maybeKey,
false,
source,
self,
trackActualOwner
? Error("react-stack-top-frame")
: unknownOwnerDebugStack,
trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask
);
};
reactJsxRuntime_development.jsxs = function (type, config, maybeKey, source, self) {
var trackActualOwner =
1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;
return jsxDEVImpl(
type,
config,
maybeKey,
true,
source,
self,
trackActualOwner
? Error("react-stack-top-frame")
: unknownOwnerDebugStack,
trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask
);
};
})();
return reactJsxRuntime_development;
}
var hasRequiredJsxRuntime;
function requireJsxRuntime () {
if (hasRequiredJsxRuntime) return jsxRuntime.exports;
hasRequiredJsxRuntime = 1;
if (process.env.NODE_ENV === 'production') {
jsxRuntime.exports = requireReactJsxRuntime_production();
} else {
jsxRuntime.exports = requireReactJsxRuntime_development();
}
return jsxRuntime.exports;
}
var jsxRuntimeExports = requireJsxRuntime();
function TimePicker(_a) {
var _b = _a.initialTime, initialTime = _b === void 0 ? { hours: 9, minutes: 30, period: 'AM' } : _b, onTimeChange = _a.onTimeChange;
// Ensure the initial time has a valid period
var validInitialTime = __assign(__assign({}, initialTime), { period: initialTime.period && ['AM', 'PM'].includes(initialTime.period) ? initialTime.period : 'AM' });
var _c = useState(validInitialTime), selectedTime = _c[0], setSelectedTime = _c[1];
var hoursRef = useRef(null);
var minutesRef = useRef(null);
var periodRef = useRef(null);
var itemHeight = 30;
var visibleItems = 5;
var totalHeight = itemHeight * visibleItems;
// Create original arrays
var originalHours = Array.from({ length: 12 }, function (_, i) { return i + 1; });
var originalMinutes = Array.from({ length: 60 }, function (_, i) { return i.toString().padStart(2, '0'); });
var originalPeriods = ['AM', 'PM'];
// Repeat arrays for infinite scroll effect
var hours = __spreadArray(__spreadArray(__spreadArray([], originalHours, true), originalHours, true), originalHours, true); // 3x repetition
var minutes = __spreadArray(__spreadArray(__spreadArray([], originalMinutes, true), originalMinutes, true), originalMinutes, true); // 3x repetition
// For periods, we'll use padding but handle scrolling differently
var periods = ['', '', 'AM', 'PM', '', '']; // Added more padding for visual centering
// Calculate initial offsets
var initialHoursIndex = originalHours.indexOf(selectedTime.hours);
var initialMinutesIndex = originalMinutes.indexOf(selectedTime.minutes.toString().padStart(2, '0'));
var initialPeriodIndex = selectedTime.period === 'AM' ? 2 : 3; // Direct index in padded array
var _d = useState(-(initialHoursIndex + originalHours.length) * itemHeight), hoursOffset = _d[0], setHoursOffset = _d[1];
var _e = useState(-(initialMinutesIndex + originalMinutes.length) * itemHeight), minutesOffset = _e[0], setMinutesOffset = _e[1];
var _f = useState(-initialPeriodIndex * itemHeight), periodOffset = _f[0], setPeriodOffset = _f[1];
// Physics-based scrolling variables
var _g = useState(false), isDragging = _g[0], setIsDragging = _g[1];
var _h = useState(0); _h[0]; var setStartY = _h[1];
var _j = useState(0), currentY = _j[0], setCurrentY = _j[1];
var _k = useState(0), velocity = _k[0], setVelocity = _k[1];
var _l = useState(0), lastY = _l[0], setLastY = _l[1];
var _m = useState(0), lastTime = _m[0], setLastTime = _m[1];
var _o = useState(false), isAnimating = _o[0], setIsAnimating = _o[1];
var _p = useState(null), animationId = _p[0], setAnimationId = _p[1];
// Ensure proper initialization on mount
useEffect(function () {
// Call onTimeChange with the initial time to ensure proper state
if (onTimeChange) {
onTimeChange(validInitialTime);
}
}, []); // Only run on mount
// Sensitivity and physics constants
var sensitivity = 0.8;
var deceleration = 0.95;
var minVelocity = 0.1;
var maxVelocity = 50;
var snapToNearest = function (offset, items, originalItems) {
var itemIndex = Math.round(-offset / itemHeight);
// For periods, ensure we snap to valid AM/PM positions (index 2 or 3)
if (items === periods) {
// If scrolling would go to index 0, 1 (empty padding at top), snap to AM (index 2)
// If scrolling would go to index 4, 5 (empty padding at bottom), snap to PM (index 3)
var clampedIndex_1 = itemIndex;
if (itemIndex <= 1) {
clampedIndex_1 = 2; // Snap to AM
}
else if (itemIndex >= 4) {
clampedIndex_1 = 3; // Snap to PM
}
else {
// Between 2 and 3, snap to nearest
clampedIndex_1 = Math.round(itemIndex);
}
return -clampedIndex_1 * itemHeight;
}
// For other items, allow scrolling to the very last item
var clampedIndex = Math.max(0, Math.min(items.length - 1, itemIndex));
return -clampedIndex * itemHeight;
};
var getSelectedValue = function (offset, items, originalItems) {
var itemIndex = Math.round(-offset / itemHeight);
var clampedIndex = Math.max(0, Math.min(items.length - 1, itemIndex));
// For repeated arrays (hours, minutes), map back to original array index
if (items === hours || items === minutes) {
var originalIndex = clampedIndex % originalItems.length;
return originalItems[originalIndex];
}
// For periods, handle padded array
if (items === periods) {
// Map index 2 to AM, index 3 to PM
if (clampedIndex === 2)
return 'AM';
if (clampedIndex === 3)
return 'PM';
// Default to current period if somehow out of bounds
return selectedTime.period;
}
return items[clampedIndex];
};
var handleMouseDown = useCallback(function (e, setOffset, currentOffset) {
e.preventDefault();
setIsDragging(true);
setStartY(e.clientY);
setCurrentY(e.clientY);
setLastY(e.clientY);
setLastTime(Date.now());
setVelocity(0);
setIsAnimating(false);
if (animationId) {
cancelAnimationFrame(animationId);
setAnimationId(null);
}
}, [animationId]);
var handleMouseMove = useCallback(function (e, setOffset, currentOffset, items) {
if (!isDragging)
return;
e.preventDefault();
var deltaY = e.clientY - currentY;
var newOffset = currentOffset + deltaY * sensitivity;
// Get the valid snapped position
var snappedOffset = snapToNearest(newOffset, items);
// Always snap to valid position during dragging
setOffset(snappedOffset);
setCurrentY(e.clientY);
// Calculate velocity
var now = Date.now();
var timeDelta = now - lastTime;
if (timeDelta > 0) {
var newVelocity = (e.clientY - lastY) / timeDelta;
setVelocity(Math.max(-maxVelocity, Math.min(maxVelocity, newVelocity)));
}
setLastY(e.clientY);
setLastTime(now);
}, [isDragging, lastY, lastTime, currentY]);
var handleMouseUp = useCallback(function (e, setOffset, currentOffset, items, originalItems) {
if (!isDragging)
return;
setIsDragging(false);
// Always snap to nearest valid position to ensure a value is selected
var snappedOffset = snapToNearest(currentOffset, items);
if (Math.abs(velocity) > minVelocity) {
// If there's significant velocity, use momentum but ensure we end at a valid position
animateWithMomentum(setOffset, currentOffset, velocity, items, originalItems);
}
else {
// Otherwise, snap directly to the nearest valid position
animateToPosition(setOffset, currentOffset, snappedOffset, items, originalItems);
}
}, [isDragging, velocity]);
var animateWithMomentum = useCallback(function (setOffset, startOffset, initialVelocity, items, originalItems) {
setIsAnimating(true);
var currentOffset = startOffset;
var currentVelocity = initialVelocity;
var animate = function () {
if (Math.abs(currentVelocity) < minVelocity) {
// Always snap to nearest valid position when velocity is low
var snappedOffset_1 = snapToNearest(currentOffset, items);
animateToPosition(setOffset, currentOffset, snappedOffset_1, items, originalItems);
return;
}
currentVelocity *= deceleration;
currentOffset += currentVelocity;
// Get the valid snapped position
var snappedOffset = snapToNearest(currentOffset, items);
// If we're not at a valid position, immediately snap to it
if (Math.abs(currentOffset - snappedOffset) > 1) {
animateToPosition(setOffset, currentOffset, snappedOffset, items, originalItems);
return;
}
// Only update if we're at a valid position
setOffset(snappedOffset);
var id = requestAnimationFrame(animate);
setAnimationId(id);
};
animate();
}, []);
var animateToPosition = useCallback(function (setOffset, startOffset, targetOffset, items, originalItems) {
setIsAnimating(true);
var startTime = Date.now();
var duration = 300; // ms
var animate = function () {
var elapsed = Date.now() - startTime;
var progress = Math.min(elapsed / duration, 1);
// Easing function (ease-out cubic)
var easeOutCubic = 1 - Math.pow(1 - progress, 3);
var currentOffset = startOffset + (targetOffset - startOffset) * easeOutCubic;
setOffset(currentOffset);
if (progress < 1) {
var id = requestAnimationFrame(animate);
setAnimationId(id);
}
else {
setIsAnimating(false);
setAnimationId(null);
// Update selected time
if (items === hours) {
var newTime = __assign(__assign({}, selectedTime), { hours: getSelectedValue(targetOffset, hours, originalHours) });
setSelectedTime(newTime);
onTimeChange === null || onTimeChange === void 0 ? void 0 : onTimeChange(newTime);
}
else if (items === minutes) {
var newTime = __assign(__assign({}, selectedTime), { minutes: parseInt(getSelectedValue(targetOffset, minutes, originalMinutes)) });
setSelectedTime(newTime);
onTimeChange === null || onTimeChange === void 0 ? void 0 : onTimeChange(newTime);
}
else if (items === periods) {
var newTime = __assign(__assign({}, selectedTime), { period: getSelectedValue(targetOffset, periods, originalPeriods) });
setSelectedTime(newTime);
onTimeChange === null || onTimeChange === void 0 ? void 0 : onTimeChange(newTime);
}
}
};
animate();
}, [selectedTime, onTimeChange]);
var handleWheel = useCallback(function (e, setOffset, currentOffset, items, originalItems) {
e.preventDefault();
if (isAnimating)
return;
var delta = e.deltaY > 0 ? -1 : 1;
var newOffset = currentOffset + delta * itemHeight;
// For periods, clamp immediately
if (items === periods) {
var maxOffset = -2 * itemHeight; // AM position
var minOffset = -3 * itemHeight; // PM position
newOffset = Math.max(minOffset, Math.min(maxOffset, newOffset));
}
// Snap to nearest
var snappedOffset = snapToNearest(newOffset, items);
animateToPosition(setOffset, currentOffset, snappedOffset, items, originalItems);
}, [isAnimating]);
var renderWheel = function (items, offset, setOffset, ref, originalItems) {
// Calculate which item is currently centered
var centeredIndex = Math.round(-offset / itemHeight);
return (jsxRuntimeExports.jsx("div", { ref: ref, className: "time-picker-wheel", style: {
transform: "translateY(".concat(offset + (totalHeight / 2 - itemHeight / 2), "px)"),
transition: isAnimating ? 'none' : 'transform 0.1s ease-out',
cursor: 'grab'
}, onMouseDown: function (e) { return handleMouseDown(e, setOffset, offset); }, onMouseMove: function (e) { return handleMouseMove(e, setOffset, offset, items); }, onMouseUp: function (e) { return handleMouseUp(e, setOffset, offset, items, originalItems); }, onMouseLeave: function (e) {
if (isDragging) {
handleMouseUp(e, setOffset, offset, items, originalItems);
}
}, onWheel: function (e) { return handleWheel(e, setOffset, offset, items, originalItems); }, children: items.map(function (item, index) {
var isSelected = index === centeredIndex;
// For periods, only show selection styling for AM/PM items
var isPeriodItem = items === periods && (index === 2 || index === 3);
var shouldHighlight = isSelected && (items !== periods || isPeriodItem);
return (jsxRuntimeExports.jsx("div", { className: "time-picker-item ".concat(shouldHighlight ? 'selected' : ''), style: {
height: itemHeight,
lineHeight: "".concat(itemHeight, "px"),
opacity: shouldHighlight ? 1 : (item ? 0.4 : 0),
transform: shouldHighlight ? 'scale(1.3)' : 'scale(0.8)',
fontWeight: shouldHighlight ? 'bold' : 'normal',
fontSize: shouldHighlight ? '1.4rem' : '1.2rem',
color: shouldHighlight ? '#ffffff' : 'rgba(255, 255, 255, 0.5)',
transition: 'all 0.2s ease-out',
userSelect: 'none'
}, children: item }, index));
}) }));
};
return (jsxRuntimeExports.jsxs("div", { className: "time-picker-container", children: [jsxRuntimeExports.jsxs("style", { children: ["\n .time-picker-container {\n /* Removed background, border, and shadow */\n }\n \n .time-picker {\n display: flex;\n align-items: center;\n height: ".concat(totalHeight, "px;\n position: relative;\n overflow: hidden;\n }\n \n .time-picker::before,\n .time-picker::after {\n content: '';\n position: absolute;\n left: 0;\n right: 0;\n height: ").concat(itemHeight * 2, "px;\n pointer-events: none;\n z-index: 10;\n }\n \n .time-picker::before {\n top: 0;\n background: linear-gradient(to bottom, rgba(0, 0, 0, 0.3), transparent);\n }\n \n .time-picker::after {\n bottom: 0;\n background: linear-gradient(to top, rgba(0, 0, 0, 0.3), transparent);\n }\n \n .time-picker-column {\n width: 80px;\n height: 100%;\n position: relative;\n overflow: hidden;\n }\n \n .time-picker-wheel {\n position: absolute;\n width: 100%;\n top: 0;\n }\n \n .time-picker-item {\n text-align: center;\n cursor: pointer;\n }\n \n .time-picker-separator {\n font-size: 1.5rem;\n font-weight: bold;\n color: #ffffff;\n margin: 0 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n height: ").concat(totalHeight, "px;\n transform: translateY(5px);\n }\n \n /* Selection indicator */\n .time-picker::after {\n content: '';\n position: absolute;\n left: 0;\n right: 0;\n top: 50%;\n transform: translateY(-50%);\n height: ").concat(itemHeight * 1.5, "px;\n border-top: 2px solid rgba(255, 255, 255, 0.3);\n border-bottom: 2px solid rgba(255, 255, 255, 0.3);\n pointer-events: none;\n z-index: 5;\n }\n "), " "] }), jsxRuntimeExports.jsxs("div", { className: "time-picker", children: [jsxRuntimeExports.jsx("div", { className: "time-picker-column", children: renderWheel(hours, hoursOffset, setHoursOffset, hoursRef, originalHours) }), jsxRuntimeExports.jsx("div", { className: "time-picker-separator", children: ":" }), jsxRuntimeExports.jsx("div", { className: "time-picker-column", children: renderWheel(minutes, minutesOffset, setMinutesOffset, minutesRef, originalMinutes) }), jsxRuntimeExports.jsx("div", { className: "time-picker-column", children: renderWheel(periods, periodOffset, setPeriodOffset, periodRef, originalPeriods) })] })] }));
}
export { TimePicker as default };
//# sourceMappingURL=index.esm.js.map