UNPKG

reablocks

Version:
1,460 lines (1,459 loc) 385 kB
(function(global, factory) { typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react"), require("react/jsx-runtime"), require("body-scroll-lock-upgrade"), require("motion/react"), require("react-dom"), require("@floating-ui/react"), require("date-fns"), require("focus-trap-react"), require("name-initials"), require("ellipsize"), require("ctrl-keys"), require("classnames"), require("tailwind-merge"), require("react-fast-compare"), require("react-textarea-autosize"), require("pluralize"), require("human-format"), require("chroma-js"), require("create-global-state-hook")) : typeof define === "function" && define.amd ? define(["exports", "react", "react/jsx-runtime", "body-scroll-lock-upgrade", "motion/react", "react-dom", "@floating-ui/react", "date-fns", "focus-trap-react", "name-initials", "ellipsize", "ctrl-keys", "classnames", "tailwind-merge", "react-fast-compare", "react-textarea-autosize", "pluralize", "human-format", "chroma-js", "create-global-state-hook"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.reablocks = {}, global.React, global.jsxRuntime, global.bodyScrollLockUpgrade, global.react, global.reactDom, global.react$1, global.dateFns, global.FocusTrap, global.getInitials, global.ellipsize, global.ctrlKeys, global.classNames, global.tailwindMerge, global.isEqual, global.TextareaAutosize, global.pluralizeLib, global.humanFormat, global.chroma, global.creteGlobalStateHook)); })(this, (function(exports2, React, jsxRuntime, bodyScrollLockUpgrade, react, reactDom, react$1, dateFns, FocusTrap, getInitials, ellipsize, ctrlKeys, classNames, tailwindMerge, isEqual, TextareaAutosize, pluralizeLib, humanFormat, chroma, creteGlobalStateHook) { "use strict"; function _interopNamespaceDefault(e) { const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } }); if (e) { for (const k in e) { if (k !== "default") { const d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: () => e[k] }); } } } n.default = e; return Object.freeze(n); } const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React); const useExitListener = ({ ref, open = true, onClickOutside, onEscape }) => { React.useEffect(() => { if (!open) { return; } const handleClick = (event) => { if (ref.current && !ref.current.contains(event.target)) { onClickOutside?.(event); } }; const handleKey = (event) => { if (event.code === "Escape") { onEscape?.(event); } }; if (onClickOutside) { document.addEventListener("mousedown", handleClick); document.addEventListener("touchstart", handleClick); } if (onEscape) { document.addEventListener("keydown", handleKey); } return () => { if (onClickOutside) { document.removeEventListener("mousedown", handleClick); document.removeEventListener("touchstart", handleClick); } if (onEscape) { document.removeEventListener("keydown", handleKey); } }; }, [ref, onClickOutside, onEscape, open]); }; const OverlayContext = React.createContext({ close: () => void 0 }); let id = 0; const genId = () => `ref-${++id}`; const useId = (idFromProps) => { const [id2] = React.useState(idFromProps || genId()); return `${id2}`; }; const useUnmount = (fn) => { const fnRef = React.useRef(fn); fnRef.current = fn; React.useLayoutEffect(() => () => fnRef.current(), []); }; const Portal = React.forwardRef( ({ children, className, style, element = "div", onMount, onUnmount }, ref) => { const elementRef = React.useRef(null); const mounted = React.useRef(false); React.useEffect(() => { if (className && elementRef.current) { elementRef.current.setAttribute("class", `${className} rdk-portal`); } if (style && elementRef.current) { Object.keys(style)?.forEach( (key) => elementRef.current.style?.setProperty(key, style[key]) ); } }, [className, style, elementRef.current]); React.useLayoutEffect(() => { elementRef.current = document.createElement(element); onMount?.(); }, []); useUnmount(() => { onUnmount?.(); const ref2 = elementRef.current; if (ref2 && document.body.contains(ref2)) { document.body.removeChild(ref2); } }); React.useImperativeHandle(ref, () => elementRef.current); if (!elementRef.current) { return null; } if (!mounted.current) { mounted.current = true; elementRef.current.classList.add("rdk-portal"); document.body.appendChild(elementRef.current); } return reactDom.createPortal(children, elementRef.current); } ); const portals = []; const START_INDEX = 990; const OverlayPortal = React.forwardRef( ({ className, children, onMount, onUnmount, appendToBody = true, id: id2, style }, ref) => { let portalId = useId(id2); const [portalIndex, setPortalIndex] = React.useState(null); const [overlayIndex, setOverlayIndex] = React.useState(null); const portalRef = React.useRef(null); React.useImperativeHandle(ref, () => portalRef.current); return /* @__PURE__ */ jsxRuntime.jsx( Portal, { className, ref: portalRef, style, onMount: () => { portals.push(portalId); let pidx = portals.indexOf(portalId); setPortalIndex(pidx); const overlayIdx = START_INDEX + pidx * 2 + 1; setOverlayIndex(overlayIdx); onMount?.({ portalId, overlayIndex: overlayIdx, portalIndex: pidx, backdropIndex: overlayIdx }); }, onUnmount: () => { onUnmount?.(); portals.splice(portals.indexOf(portalId), 1); setPortalIndex(null); setOverlayIndex(null); }, children: children({ overlayIndex, portalIndex, backdropIndex: overlayIndex, portalId }) } ); } ); const Backdrop = ({ zIndex = 998, portalIndex = 0, className, theme: customTheme, onClick }) => { const theme2 = useComponentTheme("backdrop", customTheme); return /* @__PURE__ */ jsxRuntime.jsx( react.motion.div, { className: cn(theme2.base, className), initial: { opacity: 0 }, animate: { opacity: theme2.opacity - portalIndex / 10 }, exit: { opacity: 0 }, style: { zIndex }, onClick } ); }; const backdropTheme = { base: "fixed top-0 left-0 w-full h-full opacity-0 select-none bg-black", opacity: 0.8 }; const GlobalOverlay = ({ open, hasBackdrop = true, closeOnEscape = true, closeOnBackdropClick = true, backdropClassName, children, onClose }) => { const overlayRef = React.useRef(null); const onBackdropClick = React.useCallback(() => { if (closeOnBackdropClick) { onClose?.(); } }, [closeOnBackdropClick, onClose]); useExitListener({ ref: overlayRef, open, onEscape: () => closeOnEscape && onClose?.() }); React.useEffect(() => { if (open && overlayRef.current !== void 0) { bodyScrollLockUpgrade.disableBodyScroll(overlayRef.current, { // allowTouchMove determines which elements to allow touchmove events for iOS // Reference: https://github.com/rick-liruixin/body-scroll-lock-upgrade?tab=readme-ov-file#allowtouchmove // NOTE: allowTouchMove is typed wrong: https://github.com/rick-liruixin/body-scroll-lock-upgrade/issues/21 allowTouchMove: (el) => { while (el && el !== document.body) { if (el.getAttribute("body-scroll-lock-ignore") !== null) { return true; } if (el.parentElement !== null) { el = el.parentElement; } } return false; } }); } else { bodyScrollLockUpgrade.clearAllBodyScrollLocks(); } return () => { bodyScrollLockUpgrade.clearAllBodyScrollLocks(); }; }, [children, open]); return /* @__PURE__ */ jsxRuntime.jsx(OverlayContext.Provider, { value: { close: () => onClose?.() }, children: /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { children: open && /* @__PURE__ */ jsxRuntime.jsx(OverlayPortal, { ref: overlayRef, children: ({ overlayIndex, portalIndex }) => /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [ hasBackdrop && /* @__PURE__ */ jsxRuntime.jsx( Backdrop, { zIndex: overlayIndex, portalIndex, onClick: onBackdropClick, className: backdropClassName } ), /* @__PURE__ */ jsxRuntime.jsx("div", { "body-scroll-lock-ignore": "true", children: children({ overlayIndex, portalIndex }) }) ] }) }) }) }); }; const OverlayTrigger = React.forwardRef( ({ children, className, elementType = "span", trigger = ["click"], onOpen = () => void 0, onClose = () => void 0 }, ref) => { const hasTrigger = React.useCallback( (type) => { if (Array.isArray(trigger)) { return trigger.includes(type); } else { return type === trigger; } }, [trigger] ); const onFocus = React.useCallback( (event) => { if (hasTrigger("focus")) { onOpen({ type: "focus", nativeEvent: event }); } }, [onOpen, hasTrigger] ); const onBlur = React.useCallback( (event) => { if (hasTrigger("focus")) { onClose({ type: "focus", nativeEvent: event }); } }, [onClose, hasTrigger] ); const onMouseEnter = React.useCallback( (event) => { if (hasTrigger("hover")) { onOpen({ type: "hover", nativeEvent: event }); } }, [onOpen, hasTrigger] ); const onMouseLeave = React.useCallback( (event) => { if (hasTrigger("hover")) { onClose({ type: "hover", nativeEvent: event }); } }, [onClose, hasTrigger] ); const onClick = React.useCallback( (event) => { if (hasTrigger("click")) { onOpen({ type: "click", nativeEvent: event }); } if (!hasTrigger("click")) { onClose({ type: "hover", nativeEvent: event }); } }, [onOpen, onClose, hasTrigger] ); const onContextMenu = React.useCallback( (event) => { if (hasTrigger("contextmenu")) { event.preventDefault(); onOpen({ type: "contextmenu", nativeEvent: event }); } }, [hasTrigger, onOpen] ); const tabIndex = hasTrigger("focus") ? -1 : void 0; const Component = elementType; return /* @__PURE__ */ jsxRuntime.jsx( Component, { ref, tabIndex, onMouseEnter, onMouseLeave, onFocus, onBlur, onClick, onContextMenu, className, children } ); } ); const usePosition = ({ reference, floating, followCursor, placement = "top", modifiers = [react$1.flip(), react$1.shift({ limiter: react$1.limitShift() })] } = {}) => { const isVirtualElement = React.useMemo( () => !reference?.nodeType, [reference] ); const { refs, floatingStyles, update } = react$1.useFloating({ open: true, placement, middleware: modifiers, elements: { reference: isVirtualElement ? null : reference, floating }, whileElementsMounted: react$1.autoUpdate }); React.useEffect(() => { if (isVirtualElement && reference && !followCursor) { const refObject = reference; refs.setPositionReference({ getBoundingClientRect() { return { width: refObject.width, height: refObject.height, x: refObject.left, y: refObject.top, left: refObject.left, top: refObject.top, right: refObject.left + refObject.width, bottom: refObject.top + refObject.height }; } }); } }, [reference, refs, isVirtualElement, followCursor]); const onMouseMove = React.useCallback( ({ clientX, clientY }) => { refs.setPositionReference({ getBoundingClientRect() { return { width: 0, height: 0, x: clientX, y: clientY, left: clientX, top: clientY, right: clientX, bottom: clientY }; } }); }, [refs] ); React.useLayoutEffect(() => { if (followCursor) { window.addEventListener("mousemove", onMouseMove); } return () => { window.removeEventListener("mousemove", onMouseMove); }; }, [followCursor, onMouseMove]); return { refs, anchorRef: refs.reference, floatingRef: refs.floating, floatingStyles, update }; }; const ConnectedOverlayContent = React.forwardRef( ({ triggerRef, children, portalClassName, closeOnBodyClick = true, closeOnEscape = true, elementType, appendToBody = true, followCursor, modifiers, placement = "bottom", onClose }, ref) => { const id2 = useId(); const [overlayIndex, setOverlayIndex] = React.useState(null); const { refs, floatingStyles, update } = usePosition({ reference: triggerRef.current ?? triggerRef, followCursor, modifiers, placement }); React.useImperativeHandle(ref, () => ({ updatePosition: () => { update(); } })); const onClickOutside = React.useCallback( (event) => { if (closeOnBodyClick) { let ref2 = null; if (triggerRef.current) { ref2 = triggerRef.current; } else if (triggerRef.contains !== void 0) { ref2 = triggerRef; } const container = event.target.closest(".rdk-portal"); const isLast = portals.indexOf(id2) === portals.length - 1; if (!ref2?.contains(event.target) && (isLast || !container)) { onClose?.(event); } } }, // eslint-disable-next-line react-hooks/exhaustive-deps [closeOnBodyClick, onClose] ); const onEscape = React.useCallback(() => { if (closeOnEscape) { onClose?.(); } }, [closeOnEscape, onClose]); useExitListener({ open: true, ref: refs.floating, onClickOutside, onEscape }); return /* @__PURE__ */ jsxRuntime.jsx( OverlayPortal, { id: id2, ref: refs.setFloating, style: { ...floatingStyles, zIndex: overlayIndex }, className: portalClassName, appendToBody, onMount: (event) => setOverlayIndex(event.overlayIndex), onUnmount: () => setOverlayIndex(null), children } ); } ); const ConnectedOverlay = React.forwardRef( ({ reference, children, open, content, triggerElement, triggerClassName, trigger = "click", onOpen, onClose, ...rest }, ref) => { const mounted = React.useRef(false); const overlayTriggerRef = React.useRef(null); const contentRef = React.useRef(null); const triggerRef = reference || overlayTriggerRef; React.useImperativeHandle(ref, () => ({ updatePosition: () => { contentRef.current?.updatePosition(); } })); React.useEffect(() => { if (mounted.current) { if (!open) { onClose?.(); } else { onOpen?.(); } } }, [open]); React.useEffect(() => { if (!mounted.current) { mounted.current = true; } }); const providerValue = React.useMemo( () => ({ close: () => onClose?.() }), [onClose] ); return /* @__PURE__ */ jsxRuntime.jsxs(OverlayContext.Provider, { value: providerValue, children: [ children && /* @__PURE__ */ jsxRuntime.jsx(React.Fragment, { children: trigger ? /* @__PURE__ */ jsxRuntime.jsx( OverlayTrigger, { elementType: triggerElement, ref: overlayTriggerRef, className: triggerClassName, trigger, onOpen, onClose, children } ) : children }), /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { children: open && /* @__PURE__ */ jsxRuntime.jsx( ConnectedOverlayContent, { ...rest, ref: contentRef, triggerRef, onClose, children: content } ) }) ] }); } ); const useOverlay = () => { const context = React.useContext(OverlayContext); if (context === void 0) { throw new Error( "`useOverlay` hook can only be used inside a overlay component." ); } return context; }; const baseTheme$F = { base: "inline-flex whitespace-no-wrap select-none items-center justify-center px-2.5 py-1 rounded-xs font-sans cursor-pointer", disabled: "disabled:cursor-not-allowed", fullWidth: "flex w-full", group: "rounded-none first:rounded-s last:rounded-e border-s-0 first:border-s", groupText: "border border-y-transparent border-l-transparent last:border-r-transparent hover:bg-initial", adornment: { base: "flex", start: "pr-1", end: "pl-1", sizes: { small: "[&>svg]:w-3 [&>svg]:h-3", medium: "[&>svg]:w-4 [&>svg]:h-4", large: "[&>svg]:w-5 [&>svg]:h-5" } }, sizes: { small: "text-sm px-2 py-1 leading-[normal]", medium: "text-base px-4 py-2 leading-[normal]", large: "text-xl px-5 py-2.5 leading-[normal]" }, iconSizes: { small: "px-2 py-1", medium: "px-4 py-2", large: "px-5 py-2.5" } }; const buttonTheme = { base: [baseTheme$F.base, "text-text-primary font-semibold"].join(" "), disabled: [ baseTheme$F.disabled, "data-[variant=filled]:disabled:bg-gray-600 disabled:text-gray-400 border-gray-500" ].join(" "), fullWidth: baseTheme$F.fullWidth, group: baseTheme$F.group, groupText: baseTheme$F.groupText, adornment: baseTheme$F.adornment, sizes: baseTheme$F.sizes, iconSizes: baseTheme$F.iconSizes, variants: { filled: "bg-secondary hover:bg-border-secondary-hover border-secondary light:text-gray-100", outline: "border-grey border", text: "border-0" }, colors: { default: { filled: "bg-gray-800 hover:bg-gray-700 border-gray-800", outline: "border-secondary border", text: "text-text-primary" }, primary: { filled: "bg-primary hover:bg-primary-hover border-primary text-text-primary", outline: "border border-primary", text: "text-primary hover:text-primary-hover" }, secondary: { filled: "bg-secondary hover:bg-secondary-hover text-text-primary!", outline: "border border-secondary", text: "text-secondary hover:text-secondary-hover" }, success: { filled: "bg-success hover:bg-success-hover border-success text-text-primary", outline: "border border-success", text: "text-success hover:text-success-hover" }, warning: { filled: "bg-warning hover:bg-warning-hover border-warning text-text-primary", outline: "border border-warning", text: "text-warning hover:text-warning-hover" }, error: { filled: "bg-error hover:bg-error-hover border-error text-text-primary", outline: "border border-error", text: "text-error hover:text-error-hover" } } }; const ButtonGroupContext = React.createContext({ variant: null, size: null }); const Button = React.forwardRef( ({ color = "default", variant = "filled", children, fullWidth, size = "medium", disableAnimation, className, disableMargins, disablePadding, disabled, start, end, theme: customTheme, type = "button", ...rest }, ref) => { const theme2 = useComponentTheme("button", customTheme); const { variant: groupVariant, size: groupSize } = React.useContext(ButtonGroupContext); const isGroup = !!groupVariant && !!groupSize; return /* @__PURE__ */ jsxRuntime.jsxs( react.motion.button, { ...rest, type, disabled, ref, whileTap: { scale: disabled || disableAnimation ? 1 : 0.9 }, "data-variant": groupVariant || variant, className: cn( theme2.base, theme2.disabled, fullWidth && theme2.fullWidth, theme2.variants[groupVariant || variant], theme2.colors[color][groupVariant || variant], theme2.sizes[groupSize || size], isGroup && theme2.group, isGroup && groupVariant === "text" && theme2.groupText, disableMargins && "m-0", disablePadding && "p-0", className ), children: [ start && /* @__PURE__ */ jsxRuntime.jsx( "div", { className: cn( theme2.adornment.base, theme2.adornment.start, theme2.adornment.sizes[size] ), children: start } ), children, end && /* @__PURE__ */ jsxRuntime.jsx( "div", { className: cn( theme2.adornment.base, theme2.adornment.end, theme2.adornment.sizes[size] ), children: end } ) ] } ); } ); const ButtonGroup = ({ children, className, variant, size }) => { const values = React.useMemo( () => ({ variant: variant || "filled", size: size || "medium" }), [size, variant] ); return /* @__PURE__ */ jsxRuntime.jsx(ButtonGroupContext.Provider, { value: values, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className, children }) }); }; const Chip = React.forwardRef( ({ children, color = "default", variant = "filled", size = "medium", selected, disabled, className, disableMargins, start, end, onClick, theme: customTheme, ...rest }, ref) => { const theme2 = useComponentTheme("chip", customTheme); return /* @__PURE__ */ jsxRuntime.jsxs( "div", { ...rest, ref, tabIndex: onClick ? 0 : -1, role: onClick ? "button" : void 0, onClick: !disabled ? onClick : void 0, onKeyDown: onClick && !disabled ? (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onClick(e); } } : void 0, className: cn( theme2.base, theme2.variants[variant], theme2.colors[color]?.base, theme2.colors[color]?.variants?.[variant], theme2.sizes[size], theme2.focus, !!onClick && !disabled && theme2.colors[color]?.selectable?.base, !!onClick && !disabled && theme2.colors[color]?.selectable?.variants?.[variant]?.base, selected && theme2.colors[color]?.selectable?.variants?.[variant]?.selected, disableMargins && "m-0", "transition-colors duration-300 ease [&>svg]:transition-[fill] [&>svg]:will-change-[fill]", className, disabled && theme2.disabled ), "aria-disabled": disabled, children: [ start && /* @__PURE__ */ jsxRuntime.jsx( "div", { className: cn( theme2.adornment.base, theme2.adornment.start, theme2.adornment.sizes[size] ), children: start } ), /* @__PURE__ */ jsxRuntime.jsx("div", { className: theme2.label, children }), end && /* @__PURE__ */ jsxRuntime.jsx( "div", { className: cn( theme2.adornment.base, theme2.adornment.end, theme2.adornment.sizes[size] ), children: end } ) ] } ); } ); function getMonthNames(locale, format2 = "short") { if (!locale && typeof window !== "undefined") { locale = navigator.language; } const formatter = new Intl.DateTimeFormat(locale, { month: format2, timeZone: "UTC" }); const months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map((month) => { const mm = month < 10 ? `0${month}` : month; return /* @__PURE__ */ new Date(`2017-${mm}-01T00:00:00+00:00`); }); return months.map((date) => formatter.format(date)); } const monthNames = getMonthNames(); function getDayLabels(locale) { return Array.from({ length: 7 }, (_, i) => { if (!locale && typeof window !== "undefined") { locale = navigator.language; } return new Intl.DateTimeFormat(locale, { weekday: "short" }).format(new Date(1970, 0, 4 + i)); }); } const daysOfWeek = getDayLabels(); function getWeeks(date, options = { format: "MM/dd/yyyy" }) { if (!date) { throw new Error("A date is required"); } else if (!dateFns.isValid(date)) { console.warn("Invalid date - setting to today", date); date = /* @__PURE__ */ new Date(); } const daysInMonth = dateFns.getDaysInMonth(date); let day = dateFns.startOfMonth(date); let offset = dateFns.getDay(day); const numOfWeeks = Math.ceil((daysInMonth + offset) / 7); const weeks = Array.apply(null, { length: numOfWeeks }).map(() => []); const current = /* @__PURE__ */ new Date(); const [firstWeek] = weeks; for (let i = offset; i > 0; i--) { const offsetDay = dateFns.subDays(day, i); firstWeek.push({ date: offsetDay, dayOfMonth: dateFns.getDate(offsetDay), isWeekendDay: dateFns.getISODay(offsetDay) > 5, isPreviousMonth: true, isNextMonth: false, isToday: false, formattedDate: dateFns.format(offsetDay, options.format) }); } for (let i = 0, week = weeks[i]; i < numOfWeeks; i++, week = weeks[i]) { for (let dayOfWeek = offset; dayOfWeek < 7; dayOfWeek++) { week.push({ date: day, dayOfMonth: dateFns.getDate(day), isPreviousMonth: false, isToday: dateFns.isSameDay(day, current), isNextMonth: !dateFns.isSameMonth(day, date), isWeekendDay: dateFns.getISODay(day) > 5, formattedDate: dateFns.format(day, options.format) }); day = dateFns.addDays(day, 1); } offset = 0; } return weeks; } function getDayAttributes(day, current, hover, isRange) { let isActive = false; let isRangeStart = false; let isRangeEnd = false; const isInRange = (date, range) => { const startDate = dateFns.min(range); const endDate = dateFns.max(range); return dateFns.isWithinInterval(date, { start: startDate, end: endDate }); }; const isSelectionStarted = Array.isArray(current) && dateFns.isValid(current[0]); const isSelectionComplete = isSelectionStarted && dateFns.isValid(current[1]); if (!isRange && dateFns.isValid(current)) { isActive = dateFns.isSameDay(day, current); } else if (!isSelectionStarted) { isActive = dateFns.isSameDay(day, hover); isRangeStart = isActive; isRangeEnd = isActive; } else if (isSelectionComplete) { const activeRange = [ dateFns.startOfDay(current[0]), dateFns.endOfDay(current[1]) ]; isActive = isInRange(day, activeRange); isRangeStart = dateFns.isSameDay(day, current[0]); isRangeEnd = dateFns.isSameDay(day, current[1]); } else { const activeRange = [ dateFns.startOfDay(current[0]), dateFns.endOfDay(hover ?? current[0]) ]; isActive = isInRange(day, activeRange); isRangeStart = dateFns.isSameDay(day, dateFns.min(activeRange)); isRangeEnd = dateFns.isSameDay(day, dateFns.max(activeRange)); } return { isActive, isRangeStart, isRangeEnd }; } function isNextWeekEmpty(day, range, hideNextMonth) { const nextWeek = dateFns.addDays(day, 7); const nextWeekInRange = dateFns.isBefore(nextWeek, dateFns.max(range)) || dateFns.isSameDay(nextWeek, dateFns.max(range)); return !(nextWeekInRange && (dateFns.isSameMonth(day, nextWeek) || !hideNextMonth)); } function isPreviousWeekEmpty(day, range, hidePrevMonth) { const prevWeek = dateFns.addDays(day, -7); const prevWeekInRange = dateFns.isAfter(prevWeek, dateFns.min(range)) || dateFns.isSameDay(prevWeek, dateFns.min(range)); return !(prevWeekInRange && (dateFns.isSameMonth(day, prevWeek) || !hidePrevMonth)); } function updateDateTime(currentDate, newDate, isRange = false, rangeStart = false) { let finalDate = newDate; if (currentDate) { const hasTime = dateFns.getHours(newDate) !== 0 || dateFns.getMinutes(newDate) !== 0 || dateFns.getSeconds(newDate) !== 0; if (!hasTime) { if (!isRange) { const originalTimeSource = Array.isArray(currentDate) ? currentDate[0] ?? /* @__PURE__ */ new Date() : currentDate ?? /* @__PURE__ */ new Date(); finalDate = dateFns.setSeconds( dateFns.setMinutes( dateFns.setHours(newDate, dateFns.getHours(originalTimeSource)), dateFns.getMinutes(originalTimeSource) ), dateFns.getSeconds(originalTimeSource) ); } else { if (!rangeStart) { const originalTimeSource = Array.isArray(currentDate) ? currentDate[0] ?? /* @__PURE__ */ new Date() : currentDate ?? /* @__PURE__ */ new Date(); finalDate = dateFns.setSeconds( dateFns.setMinutes( dateFns.setHours(newDate, dateFns.getHours(originalTimeSource)), dateFns.getMinutes(originalTimeSource) ), dateFns.getSeconds(originalTimeSource) ); } else { finalDate = dateFns.setSeconds(dateFns.setMinutes(dateFns.setHours(newDate, 0), 0), 0); } } } } return finalDate; } const isPresetActive = (presetValue, value, includeTime = false) => { if (!value) return false; if (Array.isArray(presetValue) && Array.isArray(value)) { if (includeTime) { const startMinutesDiff = Math.abs( dateFns.differenceInMinutes(presetValue[0], value[0]) ); const endMinutesDiff = Math.abs( dateFns.differenceInMinutes(presetValue[1], value[1]) ); return startMinutesDiff === 0 && endMinutesDiff === 0; } return dateFns.isSameDay(presetValue[0], value[0]) && dateFns.isSameDay(presetValue[1], value[1]); } if (!Array.isArray(presetValue) && !Array.isArray(value)) { if (includeTime) { return Math.abs(dateFns.differenceInSeconds(presetValue, value)) === 0; } return dateFns.isSameDay(presetValue, value); } return false; }; const CalendarDays = ({ value, current, hover = null, isRange, disabled, min: minLimit, max, animated, xAnimation = 0, animation, showDayOfWeek, showToday, showTime, dayOfWeekLabels = daysOfWeek, hidePrevMonthDays, hideNextMonthDays, onChange, onHover, theme: customTheme }) => { const { days } = useComponentTheme("calendar", customTheme); const [hoveringDate, setHoveringDate] = React.useState(hover); const weeks = React.useMemo(() => getWeeks(value), [value]); const maxLimit = React.useMemo(() => max === "now" ? /* @__PURE__ */ new Date() : max, [max]); const dayChangeHandler = React.useCallback( (dayDate) => { if (showTime && !isRange && current) { const currentDate = current; let newDate = new Date(dayDate); newDate.setHours(currentDate.getHours()); newDate.setMinutes(currentDate.getMinutes()); newDate.setSeconds(currentDate.getSeconds()); if (dateFns.isAfter(newDate, maxLimit)) { newDate = maxLimit; } else if (dateFns.isBefore(newDate, minLimit)) { newDate = minLimit; } onChange(newDate); } else { onChange(dayDate); } }, [showTime, isRange, current, maxLimit, minLimit, onChange] ); const renderDay = React.useCallback( (day) => { if (day.isPreviousMonth && hidePrevMonthDays || day.isNextMonth && hideNextMonthDays) { return /* @__PURE__ */ jsxRuntime.jsx("div", {}, day.dayOfMonth); } const handleHover = (value2) => { if (onHover) { onHover(value2); } else { setHoveringDate(value2); } }; const isDisabled = disabled || minLimit && dateFns.isBefore(dateFns.startOfDay(day.date), dateFns.startOfDay(minLimit)) || maxLimit && dateFns.isAfter(dateFns.endOfDay(day.date), dateFns.endOfDay(maxLimit)); const currentHover = hover || hoveringDate; const { isActive, isRangeStart, isRangeEnd } = getDayAttributes( day.date, current, currentHover, isRange ); const currentRange = Array.isArray(current) ? [current[0], current[1] ?? currentHover] : [current ?? hoveringDate, current ?? hoveringDate]; const isRangeMiddle = isRange && isActive && !isRangeStart && !isRangeEnd; const rangeConnectsBottom = isRangeStart && isNextWeekEmpty(day.date, currentRange, hideNextMonthDays); const rangeConnectsTop = isRangeEnd && isPreviousWeekEmpty(day.date, currentRange, hidePrevMonthDays); const colorVariant = isActive ? "primary" : "default"; const buttonVariant = isActive ? "filled" : "text"; return /* @__PURE__ */ jsxRuntime.jsx( Button, { className: cn(days.day, { [days.outside]: !isActive && (day.isNextMonth || day.isPreviousMonth), [days.today]: showToday && dateFns.isToday(day.date), [days.selected]: isActive, [days.hover]: day.date === currentHover, [days.range]: isRangeMiddle, [days.startRangeDate]: isRange && isRangeStart && !isRangeEnd, [days.cornerStartDateBottom]: isRange && isActive && !rangeConnectsBottom, [days.endRangeDate]: isRange && isRangeEnd && !isRangeStart, [days.cornerEndDateTop]: isRange && isActive && !rangeConnectsTop }), onMouseEnter: () => handleHover(day.date), onMouseLeave: () => handleHover(null), variant: buttonVariant, color: colorVariant, disableMargins: true, disabled: isDisabled, title: day.formattedDate, onClick: () => dayChangeHandler(day.date), children: day.dayOfMonth }, day.formattedDate ); }, [ disabled, minLimit, maxLimit, current, hover, isRange, dayChangeHandler, onHover, hoveringDate, days, hideNextMonthDays, hidePrevMonthDays, showToday ] ); return /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { mode: "popLayout", children: /* @__PURE__ */ jsxRuntime.jsxs( react.motion.div, { ...animation ? animation : { initial: { opacity: 0, x: xAnimation }, animate: { opacity: 1, x: 0 }, transition: { x: { type: animated ? "keyframes" : false }, opacity: { duration: 0.2, type: animated ? "tween" : false } } }, children: [ showDayOfWeek && /* @__PURE__ */ jsxRuntime.jsx("div", { className: days.header, children: dayOfWeekLabels.map((day) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: days.dayOfWeek, children: day.substring(0, 2) }, `day-${day}`)) }), weeks.map((week, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: days.week, children: week.map(renderDay) }, `week-${i}`)) ] }, value.toString() ) }); }; const CalendarMonths = ({ value, onChange, theme: customTheme }) => { const { months } = useComponentTheme("calendar", customTheme); return /* @__PURE__ */ jsxRuntime.jsx("div", { className: months.root, children: monthNames.map((month, i) => /* @__PURE__ */ jsxRuntime.jsx( Button, { className: cn(months.month, { [months.selected]: value === i }), color: value === i ? "primary" : "default", variant: value === i ? "filled" : "text", disableMargins: true, title: month, onClick: () => onChange(i), children: month }, month )) }); }; const CalendarYears = ({ decadeStart, decadeEnd, value, animated, xAnimation = 0, animation, onChange, theme: customTheme }) => { const { years } = useComponentTheme("calendar", customTheme); const yearDates = React.useMemo(() => { const arr = []; const start = decadeStart.getFullYear(); const end = decadeEnd.getFullYear(); for (let i = start - 1; i < end + 2; i++) { arr.push(i); } return arr; }, [decadeEnd, decadeStart]); return /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { mode: "popLayout", children: /* @__PURE__ */ jsxRuntime.jsx( react.motion.div, { className: years.root, ...animation ? animation : { initial: { opacity: 0, x: xAnimation }, animate: { opacity: 1, x: 0 }, transition: { x: { type: animated ? "keyframes" : false }, opacity: { duration: 0.2, type: animated ? "tween" : false } } }, children: yearDates.map((year) => /* @__PURE__ */ jsxRuntime.jsx( Button, { className: cn(years.year, { [years.selected]: value === year }), color: value === year ? "primary" : "default", variant: value === year ? "filled" : "text", disableMargins: true, title: year, onClick: () => onChange(year), children: year }, year )) }, `${decadeStart.toString()}-${decadeEnd.toString()}` ) }); }; const Divider = ({ className, disableMargins = false, orientation = "horizontal", variant = "primary", theme: customTheme, ...rest }) => { const theme2 = useComponentTheme("divider", customTheme); return /* @__PURE__ */ jsxRuntime.jsx( "hr", { ...rest, className: cn( theme2.base, theme2.variant[variant], theme2.orientation[orientation], disableMargins && theme2.disableMargins, className ) } ); }; const baseTheme$E = { base: "border-none", orientation: { horizontal: "h-px w-full my-2.5", vertical: "w-px h-full mx-2.5" }, variant: { primary: "bg-surface", secondary: "bg-linear-to-r from-transparent to-transparent via-blue-500" }, disableMargins: "my-0 mx-0" }; const dividerTheme = { ...baseTheme$E }; const typographyTheme = { h1: "scroll-m-20 text-4xl font-extrabold tracking-tight text-balance", h2: "scroll-m-20 border-b border-surface pb-2 text-3xl font-semibold tracking-tight first:mt-0", h3: "scroll-m-20 text-2xl font-semibold tracking-tight", h4: "scroll-m-20 text-xl font-semibold tracking-tight", h5: "scroll-m-20 text-lg font-semibold tracking-tight", h6: "scroll-m-20 text-base font-semibold tracking-tight", p: "leading-7 [&:not(:first-child)]:mt-6", blockquote: "mt-6 border-l-2 border-surface pl-6 italic", lead: "text-xl text-text-secondary", large: "text-lg font-semibold", small: "text-sm leading-none font-medium", muted: "text-sm text-text-secondary" }; const H1 = React.forwardRef( ({ className, theme: customTheme, children, ...rest }, ref) => { const theme2 = useComponentTheme("typography", customTheme); return /* @__PURE__ */ jsxRuntime.jsx("h1", { ref, className: cn(theme2.h1, className), ...rest, children }); } ); H1.displayName = "H1"; const H2 = React.forwardRef( ({ className, theme: customTheme, children, ...rest }, ref) => { const theme2 = useComponentTheme("typography", customTheme); return /* @__PURE__ */ jsxRuntime.jsx("h2", { ref, className: cn(theme2.h2, className), ...rest, children }); } ); H2.displayName = "H2"; const H3 = React.forwardRef( ({ className, theme: customTheme, children, ...rest }, ref) => { const theme2 = useComponentTheme("typography", customTheme); return /* @__PURE__ */ jsxRuntime.jsx("h3", { ref, className: cn(theme2.h3, className), ...rest, children }); } ); H3.displayName = "H3"; const H4 = React.forwardRef( ({ className, theme: customTheme, children, ...rest }, ref) => { const theme2 = useComponentTheme("typography", customTheme); return /* @__PURE__ */ jsxRuntime.jsx("h4", { ref, className: cn(theme2.h4, className), ...rest, children }); } ); H4.displayName = "H4"; const H5 = React.forwardRef( ({ className, theme: customTheme, children, ...rest }, ref) => { const theme2 = useComponentTheme("typography", customTheme); return /* @__PURE__ */ jsxRuntime.jsx("h5", { ref, className: cn(theme2.h5, className), ...rest, children }); } ); H5.displayName = "H5"; const H6 = React.forwardRef( ({ className, theme: customTheme, children, ...rest }, ref) => { const theme2 = useComponentTheme("typography", customTheme); return /* @__PURE__ */ jsxRuntime.jsx("h6", { ref, className: cn(theme2.h6, className), ...rest, children }); } ); H6.displayName = "H6"; const P = React.forwardRef( ({ className, theme: customTheme, children, ...rest }, ref) => { const theme2 = useComponentTheme("typography", customTheme); return /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn(theme2.p, className), ...rest, children }); } ); P.displayName = "P"; const BlockQuote = React.forwardRef( ({ className, theme: customTheme, children, ...rest }, ref) => { const theme2 = useComponentTheme("typography", customTheme); return /* @__PURE__ */ jsxRuntime.jsx( "blockquote", { ref, className: cn(theme2.blockquote, className), ...rest, children } ); } ); BlockQuote.displayName = "BlockQuote"; const Lead = React.forwardRef( ({ className, theme: customTheme, children, ...rest }, ref) => { const theme2 = useComponentTheme("typography", customTheme); return /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn(theme2.lead, className), ...rest, children }); } ); Lead.displayName = "Lead"; const Large = React.forwardRef( ({ className, theme: customTheme, children, ...rest }, ref) => { const theme2 = useComponentTheme("typography", customTheme); return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn(theme2.large, className), ...rest, children }); } ); Large.displayName = "Large"; const Small = React.forwardRef( ({ className, theme: customTheme, children, ...rest }, ref) => { const theme2 = useComponentTheme("typography", customTheme); return /* @__PURE__ */ jsxRuntime.jsx("small", { ref, className: cn(theme2.small, className), ...rest, children }); } ); Small.displayName = "Small"; const Muted = React.forwardRef( ({ className, theme: customTheme, children, ...rest }, ref) => { const theme2 = useComponentTheme("typography", customTheme); return /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn(theme2.muted, className), ...rest, children }); } ); Muted.displayName = "Muted"; const TimeColumn = ({ options, value, min, max, theme: theme2, isPM = false, is12HourCycle = false, onSelect }) => { const containerRef = React.useRef(null); const selectedRef = React.useRef(null); const isOptionDisabled = React.useCallback( (option) => { if (typeof option === "number") { if (options.length === 12 && is12HourCycle) { if (isPM) { const pmOption = option < 12 ? option + 12 : option; return pmOption < min || pmOption > max; } else { return option < min || option > max; } } return option < min || option > max; } else { if (option === "AM" && min >= 12 || option === "PM" && max < 12) { return true; } return false; } }, [options.length, is12HourCycle, isPM, min, max] ); React.useEffect(() => { if (containerRef.current && selectedRef.current) { const container = containerRef.current; const selected = selectedRef.current; const containerHeight = container.clientHeight; const itemOffsetTop = selected.offsetTop; const itemHeight = selected.offsetHeight; let scrollTop = 0; if (is12HourCycle) { scrollTop = itemOffsetTop; } else { scrollTop = itemOffsetTop - containerHeight / 2 + itemHeight / 2; } container.scrollTo({ top: scrollTop, behavior: "smooth" }); } }, [value, is12HourCycle]); return /* @__PURE__ */ jsxRuntime.jsx("div", { className: theme2.items.container, children: /* @__PURE__ */ jsxRuntime.jsx( "ul", { ref: containerRef, className: theme2.items.list, style: { paddingBottom: is12HourCycle && containerRef.current ? containerRef.current?.clientHeight - 24 : void 0 }, children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsx( "li", { ref: value === option ? selectedRef : null, className: cn(theme2.items.item.base, { [theme2.items.item.selected]: value === option, [theme2.items.item.disabled]: isOptionDisabled(option) }), onClick: () => { if (isOptionDisabled(option)) { return; } onSelect(option); }, role: "option", "aria-disabled": isOptionDisabled(option), "aria-selected": value === option, children: typeof option === "number" ? option.toString().padStart(2, "0") : option }, option )) } ) }); }; const VARIANTS$1 = { open: { opacity: 1, height: "auto" }, collapsed: { opacity: 0, height: 0 } }; const TRANSITION = { duration: 0.5, ease: [0.04, 0.62, 0.23, 0.98], when: "beforeChildren" }; const Collapse = ({ children, expanded, className, animated = true, animation, theme: customTheme, ...rest }) => { const theme2 = useComponentTheme("collapse", customTheme); return /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { initial: false, children: expanded && /* @__PURE__ */ React.createElement( react.motion.section, { ...rest, className: cn(theme2.base, className), key: "content", ...animation ? animation : { initial: "collapsed", animate: "open", exit: "collapsed", variants: VARIANTS$1, transition: animated ? TRANSITION : { duration: 0 } } }, typeof children === "function" ? children() : children ) }); }; const baseTheme$D = { base: "will-change-[height,opacity] overflow-hidden" }; const collapseTheme = { ...baseTheme$D }; const groupVariants = { initial: { transition: { staggerChildren: 0.05, staggerDirection: -1 } }, animate: { transition: { staggerChildren: 0.07, delayChildren: 0.2 } } };