UNPKG

analytica-frontend-lib

Version:

Repositório público dos componentes utilizados nas plataformas da Analytica Ensino

381 lines (379 loc) 12.1 kB
import { cn } from "./chunk-53ICLDGS.mjs"; // src/components/Menu/Menu.tsx import { create, useStore } from "zustand"; import { useEffect, useRef, forwardRef, isValidElement, Children, cloneElement, useState } from "react"; import { CaretLeftIcon } from "@phosphor-icons/react/dist/csr/CaretLeft"; import { CaretRightIcon } from "@phosphor-icons/react/dist/csr/CaretRight"; import { jsx, jsxs } from "react/jsx-runtime"; var createMenuStore = (onValueChange) => create((set) => ({ value: "", setValue: (value) => { set({ value }); onValueChange?.(value); }, syncValue: (value) => set((state) => state.value === value ? state : { value }), onValueChange })); var useMenuStore = (externalStore) => { if (!externalStore) throw new Error("MenuItem must be inside Menu"); return externalStore; }; var VARIANT_CLASSES = { menu: "bg-background shadow-soft-shadow-1 px-6", menu2: "", "menu-overflow": "", "menu-overflow-col": "bg-background shadow-soft-shadow-1", breadcrumb: "bg-transparent shadow-none !px-0" }; var BASE_CLASSES_BY_VARIANT = { menu: "w-full py-2 flex flex-row items-center justify-center", menu2: "w-full py-2 flex flex-row items-center justify-center", "menu-overflow": "w-fit py-2 flex flex-row items-center justify-center", "menu-overflow-col": "w-full py-2 flex flex-row items-center justify-start", breadcrumb: "w-full py-2 flex flex-row items-center justify-center" }; var Menu = forwardRef( ({ className, children, defaultValue, value: propValue, variant = "menu", onValueChange, ...props }, ref) => { const storeRef = useRef(null); storeRef.current ??= createMenuStore(onValueChange); const store = storeRef.current; const { syncValue } = useStore(store, (s) => s); useEffect(() => { syncValue(propValue ?? defaultValue); }, [defaultValue, propValue, syncValue]); const baseClasses = BASE_CLASSES_BY_VARIANT[variant]; const variantClasses = VARIANT_CLASSES[variant]; return /* @__PURE__ */ jsx( "div", { ref, className: ` ${baseClasses} ${variantClasses} ${className ?? ""} `, ...props, children: injectStore(children, store) } ); } ); Menu.displayName = "Menu"; var MenuContent = forwardRef( ({ className, children, variant = "menu", ...props }, ref) => { const baseClasses = "w-full flex flex-row items-center gap-2"; const isOverflowVariant = variant === "menu2" || variant === "menu-overflow" || variant === "menu-overflow-col"; const variantClasses = isOverflowVariant ? "overflow-x-auto scroll-smooth" : ""; return /* @__PURE__ */ jsx( "ul", { ref, className: ` ${baseClasses} ${variantClasses} ${variant == "breadcrumb" ? "flex-wrap" : ""} ${className ?? ""} `, style: isOverflowVariant ? { scrollbarWidth: "none", msOverflowStyle: "none" } : void 0, ...props, children } ); } ); MenuContent.displayName = "MenuContent"; var MenuItem = forwardRef( ({ className, children, value, disabled = false, store: externalStore, variant = "menu", separator = false, ...props }, ref) => { const store = useMenuStore(externalStore); const { value: selectedValue, setValue } = useStore(store, (s) => s); const handleClick = (e) => { if (!disabled) { setValue(value); } props.onClick?.(e); }; const commonProps = { role: "menuitem", "aria-disabled": disabled, ref, onClick: handleClick, onKeyDown: (e) => { if (["Enter", " "].includes(e.key)) handleClick(e); }, tabIndex: disabled ? -1 : 0, onMouseDown: (e) => { e.preventDefault(); }, ...props }; const variants = { menu: /* @__PURE__ */ jsx( "li", { "data-variant": "menu", className: ` w-full flex flex-col items-center justify-center gap-0.5 py-1 px-2 rounded-sm font-medium text-xs [&>svg]:size-6 cursor-pointer hover:bg-primary-600 hover:text-text focus:outline-none focus:border-indicator-info focus:border-2 ${selectedValue === value ? "bg-primary-50 text-primary-950" : "text-text-950"} ${className ?? ""} `, ...commonProps, children } ), menu2: /* @__PURE__ */ jsxs( "li", { "data-variant": "menu2", className: ` w-full flex flex-col items-center px-2 pt-4 gap-3 cursor-pointer focus:rounded-sm justify-center hover:bg-background-100 rounded-lg focus:outline-none focus:border-indicator-info focus:border-2 ${selectedValue === value ? "" : "pb-4"} `, ...commonProps, children: [ /* @__PURE__ */ jsx( "span", { className: cn( "flex flex-row items-center gap-2 px-4 text-text-950 text-xs font-bold", className ), children } ), selectedValue === value && /* @__PURE__ */ jsx("div", { className: "h-1 w-full bg-primary-950 rounded-lg" }) ] } ), "menu-overflow": /* @__PURE__ */ jsxs( "li", { "data-variant": "menu-overflow", className: ` w-fit flex flex-col items-center px-2 pt-4 gap-3 cursor-pointer focus:rounded-sm justify-center hover:bg-background-100 rounded-lg focus:outline-none focus:border-indicator-info focus:border-2 ${selectedValue === value ? "" : "pb-4"} `, ...commonProps, children: [ /* @__PURE__ */ jsx( "span", { className: cn( "flex flex-row items-center gap-2 px-4 text-text-950 text-xs font-bold", className ), children } ), selectedValue === value && /* @__PURE__ */ jsx("div", { className: "h-1 w-full bg-primary-950 rounded-lg" }) ] } ), "menu-overflow-col": /* @__PURE__ */ jsx( "li", { "data-variant": "menu-overflow-col", className: cn( "flex-1 min-w-fit flex flex-col items-center justify-center gap-0.5 py-1 px-2 rounded-sm font-medium text-xs whitespace-nowrap [&>svg]:size-6 cursor-pointer hover:bg-primary-600 hover:text-text focus:outline-none focus:border-indicator-info focus:border-2", selectedValue === value ? "bg-primary-50 text-primary-950" : "text-text-950", className ), ...commonProps, children } ), breadcrumb: /* @__PURE__ */ jsxs( "li", { "data-variant": "breadcrumb", className: ` flex flex-row gap-2 items-center w-fit p-2 rounded-lg hover:text-primary-600 cursor-pointer font-bold text-xs focus:outline-none focus:border-indicator-info focus:border-2 ${selectedValue === value ? "text-text-950" : "text-text-600"} ${className ?? ""} `, ...commonProps, children: [ /* @__PURE__ */ jsx( "span", { className: cn( "border-b border-text-600 hover:border-primary-600 text-inherit text-xs", selectedValue === value ? "border-b-0 font-bold" : "border-b-text-600" ), children } ), separator && /* @__PURE__ */ jsx( CaretRightIcon, { size: 16, className: "text-text-600", "data-testid": "separator" } ) ] } ) }; return variants[variant] ?? variants["menu"]; } ); MenuItem.displayName = "MenuItem"; var MenuItemIcon = ({ className, icon, ...props }) => /* @__PURE__ */ jsx( "span", { className: cn( "bg-background-500 w-[21px] h-[21px] flex items-center justify-center [&>svg]:w-[17px] [&>svg]:h-[17px] rounded-sm", className ), ...props, children: icon } ); var internalScroll = (container, direction) => { if (!container) return; container.scrollBy({ left: direction === "left" ? -150 : 150, behavior: "smooth" }); }; var internalCheckScroll = (container, setShowLeftArrow, setShowRightArrow) => { if (!container) return; const { scrollLeft, scrollWidth, clientWidth } = container; setShowLeftArrow(scrollLeft > 0); setShowRightArrow(scrollLeft + clientWidth < scrollWidth); }; var MenuOverflow = ({ children, className, defaultValue, value, onValueChange, ...props }) => { const containerRef = useRef(null); const [showLeftArrow, setShowLeftArrow] = useState(false); const [showRightArrow, setShowRightArrow] = useState(false); useEffect(() => { const checkScroll = () => internalCheckScroll( containerRef.current, setShowLeftArrow, setShowRightArrow ); checkScroll(); const container = containerRef.current; container?.addEventListener("scroll", checkScroll); window.addEventListener("resize", checkScroll); let mutationObserver = null; if (container) { mutationObserver = new MutationObserver(checkScroll); mutationObserver.observe(container, { childList: true, subtree: true }); } return () => { container?.removeEventListener("scroll", checkScroll); window.removeEventListener("resize", checkScroll); mutationObserver?.disconnect(); }; }, []); return /* @__PURE__ */ jsxs( "div", { "data-testid": "menu-overflow-wrapper", className: cn("relative w-full overflow-hidden", className), children: [ showLeftArrow && /* @__PURE__ */ jsxs( "button", { onClick: () => internalScroll(containerRef.current, "left"), className: "absolute left-0 top-1/2 -translate-y-1/2 z-10 flex h-8 w-8 items-center justify-center rounded-full bg-white shadow-md cursor-pointer", "data-testid": "scroll-left-button", children: [ /* @__PURE__ */ jsx(CaretLeftIcon, { size: 16 }), /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Scroll left" }) ] } ), /* @__PURE__ */ jsx( Menu, { defaultValue, onValueChange, value, variant: "menu2", ...props, children: /* @__PURE__ */ jsx(MenuContent, { ref: containerRef, variant: "menu2", children }) } ), showRightArrow && /* @__PURE__ */ jsxs( "button", { onClick: () => internalScroll(containerRef.current, "right"), className: "absolute right-0 top-1/2 -translate-y-1/2 z-10 flex h-8 w-8 items-center justify-center rounded-full bg-white shadow-md cursor-pointer", "data-testid": "scroll-right-button", children: [ /* @__PURE__ */ jsx(CaretRightIcon, { size: 16 }), /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Scroll right" }) ] } ) ] } ); }; var injectStore = (children, store) => Children.map(children, (child) => { if (!isValidElement(child)) return child; const typedChild = child; const shouldInject = typedChild.type === MenuItem; return cloneElement(typedChild, { ...shouldInject ? { store } : {}, ...typedChild.props.children ? { children: injectStore(typedChild.props.children, store) } : {} }); }); var Menu_default = Menu; export { useMenuStore, Menu, MenuContent, MenuItem, MenuItemIcon, internalScroll, internalCheckScroll, MenuOverflow, Menu_default }; //# sourceMappingURL=chunk-WI3GQX74.mjs.map