analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
289 lines (286 loc) • 8.81 kB
JavaScript
// src/components/Menu/Menu.tsx
import { create, useStore } from "zustand";
import {
useEffect,
useRef,
forwardRef,
isValidElement,
Children,
cloneElement,
useState
} from "react";
import { CaretLeft, CaretRight } from "phosphor-react";
// src/utils/utils.ts
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";
function cn(...inputs) {
return twMerge(clsx(inputs));
}
// src/components/Menu/Menu.tsx
import { jsx, jsxs } from "react/jsx-runtime";
var createMenuStore = (onValueChange) => create((set) => ({
value: "",
setValue: (value) => {
set({ value });
onValueChange?.(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": "",
breadcrumb: "bg-transparent shadow-none !px-0"
};
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 { setValue } = useStore(store, (s) => s);
useEffect(() => {
setValue(propValue ?? defaultValue);
}, [defaultValue, propValue, setValue]);
const baseClasses = variant === "menu-overflow" ? "w-fit py-2 flex flex-row items-center justify-center" : "w-full py-2 flex flex-row items-center justify-center";
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 variantClasses = variant === "menu2" || variant === "menu-overflow" ? "overflow-x-auto scroll-smooth" : "";
return /* @__PURE__ */ jsx(
"ul",
{
ref,
className: `
${baseClasses}
${variantClasses}
${variant == "breadcrumb" ? "flex-wrap" : ""}
${className ?? ""}
`,
style: variant === "menu2" || variant === "menu-overflow" ? { 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" })
]
}
),
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(
CaretRight,
{
size: 16,
className: "text-text-600",
"data-testid": "separator"
}
)
]
}
)
};
return variants[variant] ?? variants["menu"];
}
);
MenuItem.displayName = "MenuItem";
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) } : {}
});
});
// src/components/BreadcrumbMenu/BreadcrumbMenu.tsx
import { useNavigate } from "react-router-dom";
import { jsx as jsx2 } from "react/jsx-runtime";
var BreadcrumbMenu = ({
breadcrumbs,
onBreadcrumbClick,
className = "!px-0 py-4 flex-wrap w-full"
}) => {
const navigate = useNavigate();
const handleClick = (breadcrumb, index) => {
if (onBreadcrumbClick) {
onBreadcrumbClick(breadcrumb, index);
}
navigate(breadcrumb.url);
};
return /* @__PURE__ */ jsx2(
Menu,
{
value: `breadcrumb-${breadcrumbs.length - 1}`,
defaultValue: "breadcrumb-0",
variant: "breadcrumb",
className,
children: /* @__PURE__ */ jsx2(MenuContent, { className: "w-full flex flex-row flex-wrap gap-2 !px-0", children: breadcrumbs.map((breadcrumb, index) => {
const isLast = index === breadcrumbs.length - 1;
const hasSeparator = !isLast;
return /* @__PURE__ */ jsx2(
MenuItem,
{
variant: "breadcrumb",
value: `breadcrumb-${index}`,
className: "!p-0 whitespace-nowrap",
onClick: () => handleClick(breadcrumb, index),
separator: hasSeparator,
children: breadcrumb.name
},
breadcrumb.id
);
}) })
}
);
};
export {
BreadcrumbMenu
};
//# sourceMappingURL=index.mjs.map