@sikka/hawa
Version:
Modern UI Kit made with Tailwind
641 lines (619 loc) • 19.2 kB
JavaScript
"use client";
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// hooks/index.ts
var hooks_exports = {};
__export(hooks_exports, {
getHotkeyHandler: () => getHotkeyHandler,
getHotkeyMatcher: () => getHotkeyMatcher,
parseHotkey: () => parseHotkey,
reducer: () => reducer,
toast: () => toast,
useBreakpoint: () => useBreakpoint,
useClickOutside: () => useClickOutside,
useClipboard: () => useClipboard,
useDialogCarousel: () => useDialogCarousel,
useFocusWithin: () => useFocusWithin,
useIsomorphicEffect: () => useIsomorphicEffect,
useMeasureDirty: () => useMeasureDirty,
useMediaQuery: () => useMediaQuery,
useMultiStepDialog: () => useMultiStepDialog,
useShortcuts: () => useShortcuts,
useTabs: () => useTabs,
useToast: () => useToast,
useViewportSize: () => useViewportSize,
useWindowEvent: () => useWindowEvent,
useWindowSize: () => useWindowSize
});
module.exports = __toCommonJS(hooks_exports);
// hooks/useIsomorphicEffect.ts
var import_react = require("react");
var useIsomorphicEffect = typeof document !== "undefined" ? import_react.useLayoutEffect : import_react.useEffect;
// hooks/useDiscloser.ts
var import_react2 = require("react");
// hooks/useHover.ts
var import_react3 = require("react");
// hooks/useToast.ts
var React3 = __toESM(require("react"));
var TOAST_LIMIT = 5;
var TOAST_REMOVE_DELAY = 1e5;
var count = 0;
function genId() {
count = (count + 1) % Number.MAX_VALUE;
return count.toString();
}
var toastTimeouts = /* @__PURE__ */ new Map();
var addToRemoveQueue = (toastId) => {
if (toastTimeouts.has(toastId)) {
return;
}
const timeout = setTimeout(() => {
toastTimeouts.delete(toastId);
dispatch({ type: "REMOVE_TOAST", toastId });
}, TOAST_REMOVE_DELAY);
toastTimeouts.set(toastId, timeout);
};
var reducer = (state, action) => {
switch (action.type) {
case "ADD_TOAST":
return {
...state,
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT)
};
case "UPDATE_TOAST":
return {
...state,
toasts: state.toasts.map(
(t) => t.id === action.toast.id ? { ...t, ...action.toast } : t
)
};
case "DISMISS_TOAST": {
const { toastId } = action;
if (toastId) {
addToRemoveQueue(toastId);
} else {
state.toasts.forEach((toast2) => {
addToRemoveQueue(toast2.id);
});
}
return {
...state,
toasts: state.toasts.map(
(t) => t.id === toastId || toastId === void 0 ? { ...t, open: false } : t
)
};
}
case "REMOVE_TOAST":
if (action.toastId === void 0) {
return { ...state, toasts: [] };
}
return {
...state,
toasts: state.toasts.filter((t) => t.id !== action.toastId)
};
}
};
var listeners = [];
var memoryState = { toasts: [] };
function dispatch(action) {
memoryState = reducer(memoryState, action);
listeners.forEach((listener) => {
listener(memoryState);
});
}
function toast({ ...props }) {
const id = genId();
const update = (props2) => dispatch({ type: "UPDATE_TOAST", toast: { ...props2, id } });
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id });
dispatch({
type: "ADD_TOAST",
toast: {
...props,
id,
open: true,
onOpenChange: (open) => {
if (!open) dismiss();
}
}
});
return { id, dismiss, update };
}
function useToast() {
const [state, setState] = React3.useState(memoryState);
React3.useEffect(() => {
listeners.push(setState);
return () => {
const index = listeners.indexOf(setState);
if (index > -1) {
listeners.splice(index, 1);
}
};
}, [state]);
return {
...state,
toast,
dismiss: (toastId) => dispatch({ type: "DISMISS_TOAST", toastId })
};
}
// hooks/useCarousel.ts
var import_react4 = require("react");
// hooks/useDialogCarousel.ts
var import_react5 = require("react");
var import_embla_carousel_auto_height = __toESM(require("embla-carousel-auto-height"));
var import_embla_carousel_react = __toESM(require("embla-carousel-react"));
var useDialogCarousel = (options) => {
const [emblaRef, emblaApi] = (0, import_embla_carousel_react.default)(
{ loop: false, watchDrag: false, startIndex: 0, ...options },
[(0, import_embla_carousel_auto_height.default)({ active: true })]
);
const [canScrollPrev, setCanScrollPrev] = (0, import_react5.useState)(false);
const checkCanScrollPrev = () => {
if (emblaApi) {
setCanScrollPrev(emblaApi.canScrollPrev());
}
};
const nextStep = () => {
if (emblaApi) {
console.log("going to NEXT \u{1F449}");
emblaApi.scrollNext();
}
};
const prevStep = () => {
if (emblaApi) {
console.log("going to BACK \u{1F448}");
emblaApi.scrollPrev();
}
};
(0, import_react5.useEffect)(() => {
checkCanScrollPrev();
emblaApi && emblaApi.on("select", checkCanScrollPrev);
return () => {
emblaApi && emblaApi.off("select", checkCanScrollPrev);
};
}, [emblaApi]);
return {
emblaRef,
emblaApi,
nextStep,
prevStep,
canScrollPrev
};
};
// hooks/useDialogSteps.ts
var import_react6 = require("react");
var useMultiStepDialog = (initialStep, stepIds, setOpenDialog) => {
const [currentStep, setCurrentStep] = (0, import_react6.useState)(initialStep);
const [dialogHeight, setDialogHeight] = (0, import_react6.useState)(null);
const visibleStepRef = (0, import_react6.useRef)(null);
(0, import_react6.useEffect)(() => {
if (visibleStepRef.current) {
setDialogHeight(visibleStepRef.current.offsetHeight);
}
}, [currentStep, setOpenDialog]);
const handleNext = () => {
const currentIndex = stepIds.indexOf(currentStep);
if (currentIndex < stepIds.length - 1) {
setTimeout(() => {
setCurrentStep(stepIds[currentIndex + 1]);
}, 100);
}
};
const handleBack = () => {
const currentIndex = stepIds.indexOf(currentStep);
if (currentIndex > 0) {
setTimeout(() => {
setCurrentStep(stepIds[currentIndex - 1]);
}, 100);
}
};
return {
currentStep,
dialogHeight,
visibleStepRef,
handleNext,
handleBack
};
};
// hooks/useClipboard.ts
var import_react7 = require("react");
function useClipboard({ timeout = 2e3 } = {}) {
const [error, setError] = (0, import_react7.useState)(null);
const [copied, setCopied] = (0, import_react7.useState)(false);
const [copyTimeout, setCopyTimeout] = (0, import_react7.useState)(null);
const handleCopyResult = (value) => {
clearTimeout(copyTimeout);
setCopyTimeout(setTimeout(() => setCopied(false), timeout));
setCopied(value);
};
const copy = (valueToCopy) => {
if ("clipboard" in navigator) {
navigator.clipboard.writeText(valueToCopy).then(() => handleCopyResult(true)).catch((err) => setError(err));
} else {
setError(new Error("useClipboard: navigator.clipboard is not supported"));
}
};
const reset = () => {
setCopied(false);
setError(null);
clearTimeout(copyTimeout);
};
return { copy, reset, error, copied };
}
// hooks/useBreakpoint.ts
var import_react8 = require("react");
var useBreakpoint = () => {
const [breakpoint, setBreakpoint] = (0, import_react8.useState)(null);
(0, import_react8.useEffect)(() => {
if (typeof window !== "undefined") {
const resize = () => {
setBreakpoint(window.innerWidth);
};
resize();
window.addEventListener("resize", resize);
return () => {
window.removeEventListener("resize", resize);
};
}
}, []);
return breakpoint;
};
// hooks/useWindowSize.ts
var import_react9 = require("react");
var useWindowSize = () => {
const [windowSize, setWindowSize] = (0, import_react9.useState)({
width: void 0,
height: void 0
});
(0, import_react9.useEffect)(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight
});
}
window.addEventListener("resize", handleResize);
handleResize();
return () => window.removeEventListener("resize", handleResize);
}, []);
return windowSize;
};
// hooks/useFocusWithin.ts
var import_react10 = require("react");
function containsRelatedTarget(event) {
if (event.currentTarget instanceof HTMLElement && event.relatedTarget instanceof HTMLElement) {
return event.currentTarget.contains(event.relatedTarget);
}
return false;
}
function useFocusWithin({
onBlur,
onFocus
} = {}) {
const ref = (0, import_react10.useRef)(null);
const [focused, _setFocused] = (0, import_react10.useState)(false);
const focusedRef = (0, import_react10.useRef)(false);
const setFocused = (value) => {
_setFocused(value);
focusedRef.current = value;
};
const handleFocusIn = (event) => {
if (!focusedRef.current) {
setFocused(true);
onFocus == null ? void 0 : onFocus(event);
}
};
const handleFocusOut = (event) => {
if (focusedRef.current && !containsRelatedTarget(event)) {
setFocused(false);
onBlur == null ? void 0 : onBlur(event);
}
};
(0, import_react10.useEffect)(() => {
if (ref.current) {
ref.current.addEventListener("focusin", handleFocusIn);
ref.current.addEventListener("focusout", handleFocusOut);
return () => {
var _a, _b;
(_a = ref.current) == null ? void 0 : _a.removeEventListener("focusin", handleFocusIn);
(_b = ref.current) == null ? void 0 : _b.removeEventListener("focusout", handleFocusOut);
};
}
return void 0;
}, [handleFocusIn, handleFocusOut]);
return { ref, focused };
}
// hooks/useMediaQuery.ts
var import_react11 = require("react");
function attachMediaListener(query, callback) {
try {
query.addEventListener("change", callback);
return () => query.removeEventListener("change", callback);
} catch (e) {
query.addListener(callback);
return () => query.removeListener(callback);
}
}
function getInitialValue(query, initialValue) {
if (typeof initialValue === "boolean") {
return initialValue;
}
if (typeof window !== "undefined" && "matchMedia" in window) {
return window.matchMedia(query).matches;
}
return false;
}
function useMediaQuery(query, initialValue, { getInitialValueInEffect } = {
getInitialValueInEffect: true
}) {
const [matches, setMatches] = (0, import_react11.useState)(
getInitialValueInEffect ? initialValue : getInitialValue(query, initialValue)
);
const queryRef = (0, import_react11.useRef)();
(0, import_react11.useEffect)(() => {
if ("matchMedia" in window) {
queryRef.current = window.matchMedia(query);
setMatches(queryRef.current.matches);
return attachMediaListener(
queryRef.current,
(event) => setMatches(event.matches)
);
}
return void 0;
}, [query]);
return matches;
}
// hooks/useScrollPosition.ts
var import_react12 = require("react");
// hooks/useTable.ts
var import_react13 = require("react");
// hooks/useTabs.ts
var import_react14 = require("react");
function useTabs(initialTab = "") {
const [activeTab, setActiveTab] = (0, import_react14.useState)(initialTab);
(0, import_react14.useEffect)(() => {
const handleHashChange = () => {
const hash = window.location.hash.substring(1);
setActiveTab(hash || initialTab);
};
window.addEventListener("hashchange", handleHashChange);
handleHashChange();
return () => {
window.removeEventListener("hashchange", handleHashChange);
};
}, [initialTab]);
const handleTabChange = (index) => {
setActiveTab(index);
window.location.hash = index;
};
return {
activeTab,
handleTabChange
};
}
// hooks/useMeasureDirty.ts
var import_react15 = require("react");
var useMeasureDirty = (ref) => {
const frame = (0, import_react15.useRef)(0);
const [rect, set] = (0, import_react15.useState)({
width: 0,
height: 0,
top: 0,
left: 0,
bottom: 0,
right: 0
});
const [observer] = (0, import_react15.useState)(
() => new ResizeObserver((entries) => {
const entry = entries[0];
if (entry) {
cancelAnimationFrame(frame.current);
frame.current = requestAnimationFrame(() => {
if (ref.current) {
set(entry.contentRect);
}
});
}
})
);
(0, import_react15.useEffect)(() => {
observer.disconnect();
if (ref.current) {
observer.observe(ref.current);
}
}, [ref]);
return rect;
};
// hooks/useClickOutside.ts
var import_react16 = require("react");
var DEFAULT_EVENTS = ["mousedown", "touchstart"];
function useClickOutside(handler, events, nodes) {
const ref = (0, import_react16.useRef)();
(0, import_react16.useEffect)(() => {
const listener = (event) => {
const { target } = event != null ? event : {};
if (Array.isArray(nodes)) {
const shouldIgnore = (target == null ? void 0 : target.hasAttribute("data-ignore-outside-clicks")) || !document.body.contains(target) && target.tagName !== "HTML";
const shouldTrigger = nodes.every(
(node) => !!node && !event.composedPath().includes(node)
);
shouldTrigger && !shouldIgnore && handler();
} else if (ref.current && !ref.current.contains(target)) {
handler();
}
};
(events || DEFAULT_EVENTS).forEach(
(fn) => document.addEventListener(fn, listener)
);
return () => {
(events || DEFAULT_EVENTS).forEach(
(fn) => document.removeEventListener(fn, listener)
);
};
}, [ref, handler, nodes]);
return ref;
}
// hooks/useShortcuts.ts
var import_react17 = require("react");
function parseHotkey(hotkey) {
const keys = hotkey.toLowerCase().split("+").map((part) => part.trim());
const modifiers = {
alt: keys.includes("alt"),
ctrl: keys.includes("ctrl"),
meta: keys.includes("meta"),
mod: keys.includes("mod"),
shift: keys.includes("shift")
};
const reservedKeys = ["alt", "ctrl", "meta", "shift", "mod"];
const freeKey = keys.find((key) => !reservedKeys.includes(key));
return {
...modifiers,
key: freeKey
};
}
function isExactHotkey(hotkey, event) {
const { alt, ctrl, meta, mod, shift, key } = hotkey;
const { altKey, ctrlKey, metaKey, shiftKey, key: pressedKey } = event;
if (alt !== altKey) {
return false;
}
if (mod) {
if (!ctrlKey && !metaKey) {
return false;
}
} else {
if (ctrl !== ctrlKey) {
return false;
}
if (meta !== metaKey) {
return false;
}
}
if (shift !== shiftKey) {
return false;
}
if (key && (pressedKey.toLowerCase() === key.toLowerCase() || event.code.replace("Key", "").toLowerCase() === key.toLowerCase())) {
return true;
}
return false;
}
function getHotkeyMatcher(hotkey) {
return (event) => isExactHotkey(parseHotkey(hotkey), event);
}
function getHotkeyHandler(hotkeys) {
return (event) => {
const _event = "nativeEvent" in event ? event.nativeEvent : event;
hotkeys.forEach(([hotkey, handler, options = { preventDefault: true }]) => {
if (getHotkeyMatcher(hotkey)(_event)) {
if (options.preventDefault) {
event.preventDefault();
}
handler(_event);
}
});
};
}
function shouldFireEvent(event, tagsToIgnore, triggerOnContentEditable = false) {
if (event.target instanceof HTMLElement) {
if (triggerOnContentEditable) {
return !tagsToIgnore.includes(event.target.tagName);
}
return !event.target.isContentEditable && !tagsToIgnore.includes(event.target.tagName);
}
return true;
}
function useShortcuts(hotkeys, tagsToIgnore = ["INPUT", "TEXTAREA", "SELECT"], triggerOnContentEditable = false) {
(0, import_react17.useEffect)(() => {
const keydownListener = (event) => {
hotkeys.forEach(
([hotkey, handler, options = { preventDefault: true }]) => {
if (getHotkeyMatcher(hotkey)(event) && shouldFireEvent(event, tagsToIgnore, triggerOnContentEditable)) {
if (options.preventDefault) {
event.preventDefault();
}
handler(event);
}
}
);
};
document.documentElement.addEventListener("keydown", keydownListener);
return () => document.documentElement.removeEventListener("keydown", keydownListener);
}, [hotkeys]);
}
// hooks/useWindowEvent.ts
var import_react18 = require("react");
function useWindowEvent(type, listener, options) {
(0, import_react18.useEffect)(() => {
window.addEventListener(type, listener, options);
return () => window.removeEventListener(type, listener, options);
}, [type, listener]);
}
// hooks/useViewportSize.ts
var import_react19 = require("react");
var eventListerOptions = {
passive: true
};
function useViewportSize() {
const [windowSize, setWindowSize] = (0, import_react19.useState)({
width: 0,
height: 0
});
const setSize = (0, import_react19.useCallback)(() => {
setWindowSize({
width: window.innerWidth || 0,
height: window.innerHeight || 0
});
}, []);
useWindowEvent("resize", setSize, eventListerOptions);
useWindowEvent("orientationchange", setSize, eventListerOptions);
(0, import_react19.useEffect)(setSize, []);
return windowSize;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
getHotkeyHandler,
getHotkeyMatcher,
parseHotkey,
reducer,
toast,
useBreakpoint,
useClickOutside,
useClipboard,
useDialogCarousel,
useFocusWithin,
useIsomorphicEffect,
useMeasureDirty,
useMediaQuery,
useMultiStepDialog,
useShortcuts,
useTabs,
useToast,
useViewportSize,
useWindowEvent,
useWindowSize
});