UNPKG

analytica-frontend-lib

Version:

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

1,332 lines (1,317 loc) 229 kB
"use strict"; 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); // src/components/AlertManager/AlertsManager.tsx var AlertsManager_exports = {}; __export(AlertsManager_exports, { AlertsManager: () => AlertsManager }); module.exports = __toCommonJS(AlertsManager_exports); var import_react19 = require("react"); // src/utils/utils.ts var import_clsx = require("clsx"); var import_tailwind_merge = require("tailwind-merge"); function cn(...inputs) { return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs)); } // src/components/Text/Text.tsx var import_jsx_runtime = require("react/jsx-runtime"); var Text = ({ children, size = "md", weight = "normal", color = "text-text-950", as, className = "", ...props }) => { let sizeClasses = ""; let weightClasses = ""; const sizeClassMap = { "2xs": "text-2xs", xs: "text-xs", sm: "text-sm", md: "text-md", lg: "text-lg", xl: "text-xl", "2xl": "text-2xl", "3xl": "text-3xl", "4xl": "text-4xl", "5xl": "text-5xl", "6xl": "text-6xl" }; sizeClasses = sizeClassMap[size] ?? sizeClassMap.md; const weightClassMap = { hairline: "font-hairline", light: "font-light", normal: "font-normal", medium: "font-medium", semibold: "font-semibold", bold: "font-bold", extrabold: "font-extrabold", black: "font-black" }; weightClasses = weightClassMap[weight] ?? weightClassMap.normal; const baseClasses = "font-primary"; const Component = as ?? "p"; return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( Component, { className: cn(baseClasses, sizeClasses, weightClasses, color, className), ...props, children } ); }; var Text_default = Text; // src/components/Button/Button.tsx var import_jsx_runtime2 = require("react/jsx-runtime"); var VARIANT_ACTION_CLASSES = { solid: { primary: "bg-primary-950 text-text border border-primary-950 hover:bg-primary-800 hover:border-primary-800 focus-visible:outline-none focus-visible:bg-primary-950 focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:ring-indicator-info active:bg-primary-700 active:border-primary-700 disabled:bg-primary-500 disabled:border-primary-500 disabled:opacity-40 disabled:cursor-not-allowed", positive: "bg-success-500 text-text border border-success-500 hover:bg-success-600 hover:border-success-600 focus-visible:outline-none focus-visible:bg-success-500 focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:ring-indicator-info active:bg-success-700 active:border-success-700 disabled:bg-success-500 disabled:border-success-500 disabled:opacity-40 disabled:cursor-not-allowed", negative: "bg-error-500 text-text border border-error-500 hover:bg-error-600 hover:border-error-600 focus-visible:outline-none focus-visible:bg-error-500 focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:ring-indicator-info active:bg-error-700 active:border-error-700 disabled:bg-error-500 disabled:border-error-500 disabled:opacity-40 disabled:cursor-not-allowed" }, outline: { primary: "bg-transparent text-primary-950 border border-primary-950 hover:bg-background-50 hover:text-primary-400 hover:border-primary-400 focus-visible:border-0 focus-visible:outline-none focus-visible:text-primary-600 focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:ring-indicator-info active:text-primary-700 active:border-primary-700 disabled:opacity-40 disabled:cursor-not-allowed", positive: "bg-transparent text-success-500 border border-success-300 hover:bg-background-50 hover:text-success-400 hover:border-success-400 focus-visible:border-0 focus-visible:outline-none focus-visible:text-success-600 focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:ring-indicator-info active:text-success-700 active:border-success-700 disabled:opacity-40 disabled:cursor-not-allowed", negative: "bg-transparent text-error-500 border border-error-300 hover:bg-background-50 hover:text-error-400 hover:border-error-400 focus-visible:border-0 focus-visible:outline-none focus-visible:text-error-600 focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:ring-indicator-info active:text-error-700 active:border-error-700 disabled:opacity-40 disabled:cursor-not-allowed" }, link: { primary: "bg-transparent text-primary-950 hover:text-primary-400 focus-visible:outline-none focus-visible:text-primary-600 focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:ring-indicator-info active:text-primary-700 disabled:opacity-40 disabled:cursor-not-allowed", positive: "bg-transparent text-success-500 hover:text-success-400 focus-visible:outline-none focus-visible:text-success-600 focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:ring-indicator-info active:text-success-700 disabled:opacity-40 disabled:cursor-not-allowed", negative: "bg-transparent text-error-500 hover:text-error-400 focus-visible:outline-none focus-visible:text-error-600 focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:ring-indicator-info active:text-error-700 disabled:opacity-40 disabled:cursor-not-allowed" } }; var SIZE_CLASSES = { "extra-small": "text-xs px-3.5 py-2", small: "text-sm px-4 py-2.5", medium: "text-md px-5 py-2.5", large: "text-lg px-6 py-3", "extra-large": "text-lg px-7 py-3.5" }; var Button = ({ children, iconLeft, iconRight, size = "medium", variant = "solid", action = "primary", className = "", disabled, type = "button", ...props }) => { const sizeClasses = SIZE_CLASSES[size]; const variantClasses = VARIANT_ACTION_CLASSES[variant][action]; const baseClasses = "inline-flex items-center justify-center rounded-full cursor-pointer font-medium"; return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)( "button", { className: cn(baseClasses, variantClasses, sizeClasses, className), disabled, type, ...props, children: [ iconLeft && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "mr-2 flex items-center", children: iconLeft }), children, iconRight && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "ml-2 flex items-center", children: iconRight }) ] } ); }; var Button_default = Button; // src/components/Badge/Badge.tsx var import_phosphor_react = require("phosphor-react"); var import_jsx_runtime3 = require("react/jsx-runtime"); var VARIANT_ACTION_CLASSES2 = { solid: { error: "bg-error-background text-error-700 focus-visible:outline-none", warning: "bg-warning text-warning-800 focus-visible:outline-none", success: "bg-success text-success-800 focus-visible:outline-none", info: "bg-info text-info-800 focus-visible:outline-none", muted: "bg-background-muted text-background-800 focus-visible:outline-none" }, outlined: { error: "bg-error text-error-700 border border-error-300 focus-visible:outline-none", warning: "bg-warning text-warning-800 border border-warning-300 focus-visible:outline-none", success: "bg-success text-success-800 border border-success-300 focus-visible:outline-none", info: "bg-info text-info-800 border border-info-300 focus-visible:outline-none", muted: "bg-background-muted text-background-800 border border-border-300 focus-visible:outline-none" }, exams: { exam1: "bg-exam-1 text-info-700 focus-visible:outline-none", exam2: "bg-exam-2 text-typography-1 focus-visible:outline-none", exam3: "bg-exam-3 text-typography-2 focus-visible:outline-none", exam4: "bg-exam-4 text-success-700 focus-visible:outline-none" }, examsOutlined: { exam1: "bg-exam-1 text-info-700 border border-info-700 focus-visible:outline-none", exam2: "bg-exam-2 text-typography-1 border border-typography-1 focus-visible:outline-none", exam3: "bg-exam-3 text-typography-2 border border-typography-2 focus-visible:outline-none", exam4: "bg-exam-4 text-success-700 border border-success-700 focus-visible:outline-none" }, resultStatus: { negative: "bg-error text-error-800 focus-visible:outline-none", positive: "bg-success text-success-800 focus-visible:outline-none" }, notification: "text-primary" }; var SIZE_CLASSES2 = { small: "text-2xs px-2 py-1", medium: "text-xs px-2 py-1", large: "text-sm px-2 py-1" }; var SIZE_CLASSES_ICON = { small: "size-3", medium: "size-3.5", large: "size-4" }; var Badge = ({ children, iconLeft, iconRight, size = "medium", variant = "solid", action = "error", className = "", notificationActive = false, ...props }) => { const sizeClasses = SIZE_CLASSES2[size]; const sizeClassesIcon = SIZE_CLASSES_ICON[size]; const variantActionMap = VARIANT_ACTION_CLASSES2[variant] || {}; const variantClasses = typeof variantActionMap === "string" ? variantActionMap : variantActionMap[action] ?? variantActionMap.muted ?? ""; const baseClasses = "inline-flex items-center justify-center rounded-xs font-normal gap-1 relative"; const baseClassesIcon = "flex items-center"; if (variant === "notification") { return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)( "div", { className: cn(baseClasses, variantClasses, sizeClasses, className), ...props, children: [ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_phosphor_react.Bell, { size: 24, className: "text-current", "aria-hidden": "true" }), notificationActive && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)( "span", { "data-testid": "notification-dot", className: "absolute top-[5px] right-[10px] block h-2 w-2 rounded-full bg-indicator-error ring-2 ring-white" } ) ] } ); } return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)( "div", { className: cn(baseClasses, variantClasses, sizeClasses, className), ...props, children: [ iconLeft && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: cn(baseClassesIcon, sizeClassesIcon), children: iconLeft }), children, iconRight && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: cn(baseClassesIcon, sizeClassesIcon), children: iconRight }) ] } ); }; var Badge_default = Badge; // src/components/SelectionButton/SelectionButton.tsx var import_react = require("react"); var import_jsx_runtime4 = require("react/jsx-runtime"); var SelectionButton = (0, import_react.forwardRef)( ({ icon, label, selected = false, className = "", disabled, ...props }, ref) => { const baseClasses = [ "inline-flex", "items-center", "justify-start", "gap-2", "p-4", "rounded-xl", "cursor-pointer", "border", "border-border-50", "bg-background", "text-sm", "text-text-700", "font-bold", "shadow-soft-shadow-1", "hover:bg-background-100", "focus-visible:outline-none", "focus-visible:ring-2", "focus-visible:ring-indicator-info", "focus-visible:ring-offset-0", "focus-visible:shadow-none", "active:ring-2", "active:ring-primary-950", "active:ring-offset-0", "active:shadow-none", "disabled:opacity-50", "disabled:cursor-not-allowed" ]; const stateClasses = selected ? ["ring-primary-950", "ring-2", "ring-offset-0", "shadow-none"] : []; const allClasses = [...baseClasses, ...stateClasses].join(" "); return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)( "button", { ref, type: "button", className: cn(allClasses, className), disabled, "aria-pressed": selected, ...props, children: [ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "flex items-center justify-center w-6 h-6", children: icon }), /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: label }) ] } ); } ); SelectionButton.displayName = "SelectionButton"; var SelectionButton_default = SelectionButton; // src/components/CheckBox/CheckBox.tsx var import_react2 = require("react"); var import_phosphor_react2 = require("phosphor-react"); var import_jsx_runtime5 = require("react/jsx-runtime"); var SIZE_CLASSES3 = { small: { checkbox: "w-4 h-4", // 16px x 16px textSize: "sm", spacing: "gap-1.5", // 6px borderWidth: "border-2", iconSize: 14, // pixels for Phosphor icons labelHeight: "h-[21px]" }, medium: { checkbox: "w-5 h-5", // 20px x 20px textSize: "md", spacing: "gap-2", // 8px borderWidth: "border-2", iconSize: 16, // pixels for Phosphor icons labelHeight: "h-6" }, large: { checkbox: "w-6 h-6", // 24px x 24px textSize: "lg", spacing: "gap-2", // 8px borderWidth: "border-[3px]", // 3px border iconSize: 20, // pixels for Phosphor icons labelHeight: "h-[27px]" } }; var BASE_CHECKBOX_CLASSES = "rounded border cursor-pointer transition-all duration-200 flex items-center justify-center focus:outline-none"; var STATE_CLASSES = { default: { unchecked: "border-border-400 bg-background hover:border-border-500", checked: "border-primary-950 bg-primary-950 text-text hover:border-primary-800 hover:bg-primary-800" }, hovered: { unchecked: "border-border-500 bg-background", checked: "border-primary-800 bg-primary-800 text-text" }, focused: { unchecked: "border-indicator-info bg-background ring-2 ring-indicator-info/20", checked: "border-indicator-info bg-primary-950 text-text ring-2 ring-indicator-info/20" }, invalid: { unchecked: "border-error-700 bg-background hover:border-error-600", checked: "border-error-700 bg-primary-950 text-text" }, disabled: { unchecked: "border-border-400 bg-background cursor-not-allowed opacity-40", checked: "border-primary-600 bg-primary-600 text-text cursor-not-allowed opacity-40" } }; var CheckBox = (0, import_react2.forwardRef)( ({ label, size = "medium", state = "default", indeterminate = false, errorMessage, helperText, className = "", labelClassName = "", checked: checkedProp, disabled, id, onChange, ...props }, ref) => { const generatedId = (0, import_react2.useId)(); const inputId = id ?? `checkbox-${generatedId}`; const [internalChecked, setInternalChecked] = (0, import_react2.useState)(false); const isControlled = checkedProp !== void 0; const checked = isControlled ? checkedProp : internalChecked; const handleChange = (event) => { if (!isControlled) { setInternalChecked(event.target.checked); } onChange?.(event); }; const currentState = disabled ? "disabled" : state; const sizeClasses = SIZE_CLASSES3[size]; const checkVariant = checked || indeterminate ? "checked" : "unchecked"; const stylingClasses = STATE_CLASSES[currentState][checkVariant]; const borderWidthClass = state === "focused" || state === "hovered" && size === "large" ? "border-[3px]" : sizeClasses.borderWidth; const checkboxClasses = cn( BASE_CHECKBOX_CLASSES, sizeClasses.checkbox, borderWidthClass, stylingClasses, className ); const renderIcon = () => { if (indeterminate) { return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( import_phosphor_react2.Minus, { size: sizeClasses.iconSize, weight: "bold", color: "currentColor" } ); } if (checked) { return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( import_phosphor_react2.Check, { size: sizeClasses.iconSize, weight: "bold", color: "currentColor" } ); } return null; }; return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col", children: [ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)( "div", { className: cn( "flex flex-row items-center", sizeClasses.spacing, disabled ? "opacity-40" : "" ), children: [ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( "input", { ref, type: "checkbox", id: inputId, checked, disabled, onChange: handleChange, className: "sr-only", ...props } ), /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: inputId, className: checkboxClasses, children: renderIcon() }), label && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( "div", { className: cn( "flex flex-row items-center", sizeClasses.labelHeight ), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( Text_default, { as: "label", htmlFor: inputId, size: sizeClasses.textSize, weight: "normal", className: cn( "cursor-pointer select-none leading-[150%] flex items-center font-roboto", labelClassName ), children: label } ) } ) ] } ), errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( Text_default, { size: "sm", weight: "normal", className: "mt-1.5", color: "text-error-600", children: errorMessage } ), helperText && !errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( Text_default, { size: "sm", weight: "normal", className: "mt-1.5", color: "text-text-500", children: helperText } ) ] }); } ); CheckBox.displayName = "CheckBox"; var CheckBox_default = CheckBox; // src/components/ImageUpload/ImageUpload.tsx var import_react3 = require("react"); var import_phosphor_react3 = require("phosphor-react"); var import_jsx_runtime6 = require("react/jsx-runtime"); function ImageUpload({ selectedFile, onFileSelect, onRemoveFile, buttonText = "Inserir imagem", buttonIcon, accept = "image/*", disabled = false, className, maxSize, onSizeError, onTypeError, variant = "default" }) { const fileInputRef = (0, import_react3.useRef)(null); const [internalFile, setInternalFile] = (0, import_react3.useState)(null); const currentFile = selectedFile ?? internalFile; const hasFile = currentFile !== null; const handleButtonClick = () => { if (!disabled) { fileInputRef.current?.click(); } }; const handleFileChange = (event) => { const file = event.target.files?.[0]; if (!file) return; const acceptedTypes = accept.split(",").map((type) => type.trim()); const isValidType = acceptedTypes.some((type) => { if (type.endsWith("/*")) { const mainType = type.split("/")[0]; return file.type.startsWith(mainType + "/"); } if (type.startsWith(".")) { return file.name.toLowerCase().endsWith(type.toLowerCase()); } return file.type === type; }); if (!isValidType) { onTypeError?.(file); return; } if (maxSize && file.size > maxSize) { onSizeError?.(file, maxSize); return; } if (selectedFile === void 0) { setInternalFile(file); } onFileSelect?.(file); event.target.value = ""; }; const handleRemoveFile = () => { if (!disabled) { if (selectedFile === void 0) { setInternalFile(null); } onRemoveFile?.(); } }; if (variant === "compact") { return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: cn("inline-flex items-center gap-2", className), children: [ hasFile ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "inline-flex items-center gap-2 bg-muted rounded-md px-3 py-1.5", children: [ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_phosphor_react3.Paperclip, { className: "h-4 w-4 text-text-800" }), /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text_default, { size: "sm", weight: "medium", className: "text-text-800", children: currentFile.name }), /* @__PURE__ */ (0, import_jsx_runtime6.jsx)( "button", { type: "button", onClick: handleRemoveFile, disabled, className: "hover:opacity-70 disabled:cursor-not-allowed disabled:opacity-50", "aria-label": "Remover imagem", title: "Remover imagem", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_phosphor_react3.X, { className: "h-3 w-3 text-primary-950" }) } ) ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)( Button_default, { type: "button", variant: "link", size: "extra-small", onClick: handleButtonClick, disabled, children: [ buttonIcon || /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_phosphor_react3.Image, { className: "h-4 w-4" }), /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ml-2", children: buttonText }) ] } ), /* @__PURE__ */ (0, import_jsx_runtime6.jsx)( "input", { ref: fileInputRef, type: "file", accept, className: "hidden", onChange: handleFileChange, disabled } ) ] }); } return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: cn("space-y-3", className), children: [ hasFile ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "space-y-2", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "inline-flex items-center gap-2 bg-muted rounded-md px-3 py-2", children: [ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_phosphor_react3.Paperclip, { className: "h-4 w-4 text-text-800" }), /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text_default, { size: "sm", weight: "medium", className: "text-text-800", children: currentFile.name }), /* @__PURE__ */ (0, import_jsx_runtime6.jsx)( "button", { type: "button", onClick: handleRemoveFile, disabled, className: "hover:opacity-70 disabled:cursor-not-allowed disabled:opacity-50", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_phosphor_react3.X, { className: "h-4 w-4 text-primary-950 cursor-pointer" }) } ) ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)( Button_default, { type: "button", variant: "link", onClick: handleButtonClick, disabled, children: [ buttonIcon || /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_phosphor_react3.Image, { className: "h-4 w-4 mr-2" }), buttonText ] } ), /* @__PURE__ */ (0, import_jsx_runtime6.jsx)( "input", { ref: fileInputRef, type: "file", accept, className: "hidden", onChange: handleFileChange, disabled } ) ] }); } // src/components/CheckBoxGroup/CheckBoxGroup.tsx var import_react4 = require("react"); // src/components/CheckBoxGroup/CheckBoxGroup.helpers.ts var areSelectedIdsEqual = (ids1, ids2) => { if (ids1 === ids2) return true; if (!ids1 || !ids2) return ids1 === ids2; if (ids1.length !== ids2.length) return false; for (let i = 0; i < ids1.length; i++) { if (ids1[i] !== ids2[i]) return false; } return true; }; var isCategoryEnabled = (category, allCategories) => { if (!category.dependsOn || category.dependsOn.length === 0) { return true; } return category.dependsOn.every((depKey) => { const depCat = allCategories.find((c) => c.key === depKey); return depCat?.selectedIds && depCat.selectedIds.length > 0; }); }; var isItemMatchingFilter = (item, filter, allCategories) => { const parentCat = allCategories.find((c) => c.key === filter.key); const parentSelectedIds = parentCat?.selectedIds || []; const itemFieldValue = item[filter.internalField]; return parentSelectedIds.includes(String(itemFieldValue)); }; var getBadgeText = (category, formattedItems) => { const visibleIds = formattedItems.flatMap((group) => group.itens || []).map((i) => i.id); const selectedVisibleCount = visibleIds.filter( (id) => category.selectedIds?.includes(id) ).length; const totalVisible = visibleIds.length; return `${selectedVisibleCount} de ${totalVisible} ${selectedVisibleCount === 1 ? "selecionado" : "selecionados"}`; }; var handleAccordionValueChange = (value, categories, isCategoryEnabledFn) => { if (typeof value !== "string") { if (!value) { return ""; } return null; } if (!value) { return ""; } const category = categories.find((c) => c.key === value); if (!category) { return null; } const isEnabled = isCategoryEnabledFn(category); if (!isEnabled) { return null; } return value; }; var calculateFormattedItemsForAutoSelection = (category, allCategories) => { if (!category?.dependsOn || category.dependsOn.length === 0) { return category?.itens || []; } const isEnabled = isCategoryEnabled(category, allCategories); if (!isEnabled) { return []; } const filters = category.filteredBy || []; if (filters.length === 0) { return category?.itens || []; } const selectedIdsArr = filters.map((f) => { const parentCat = allCategories.find((c) => c.key === f.key); if (!parentCat?.selectedIds?.length) { return []; } return parentCat.selectedIds; }); if (selectedIdsArr.some((arr) => arr.length === 0)) { return []; } const filteredItems = (category.itens || []).filter( (item) => filters.every((filter) => isItemMatchingFilter(item, filter, allCategories)) ); return filteredItems; }; // src/components/CheckBoxGroup/CheckBoxGroup.tsx var import_jsx_runtime7 = require("react/jsx-runtime"); var CheckboxGroup = ({ categories, onCategoriesChange, compactSingleItem = true, showDivider = true, showSingleItem = false }) => { const [openAccordion, setOpenAccordion] = (0, import_react4.useState)(""); const autoSelectionAppliedRef = (0, import_react4.useRef)(false); const onCategoriesChangeRef = (0, import_react4.useRef)(onCategoriesChange); const previousCategoriesRef = (0, import_react4.useRef)(categories); (0, import_react4.useEffect)(() => { onCategoriesChangeRef.current = onCategoriesChange; }, [onCategoriesChange]); const categoriesWithAutoSelection = (0, import_react4.useMemo)(() => { return categories.map((category) => { const filteredItems = calculateFormattedItemsForAutoSelection( category, categories ); if (filteredItems.length === 1 && (!category.selectedIds || category.selectedIds.length === 0)) { return { ...category, selectedIds: [filteredItems[0].id] }; } return category; }); }, [categories]); (0, import_react4.useEffect)(() => { const categoriesChanged = categories !== previousCategoriesRef.current; if (!categoriesChanged && autoSelectionAppliedRef.current) { return; } previousCategoriesRef.current = categories; const hasAutoSelectionChanges = categoriesWithAutoSelection.some( (cat, index) => { const originalCat = categories[index]; return !areSelectedIdsEqual(cat.selectedIds, originalCat.selectedIds); } ); if (hasAutoSelectionChanges) { autoSelectionAppliedRef.current = true; onCategoriesChangeRef.current(categoriesWithAutoSelection); } else if (categoriesChanged) { autoSelectionAppliedRef.current = false; } }, [categoriesWithAutoSelection, categories]); const isCheckBoxIsSelected = (categoryKey, itemId) => { const category = categories.find((c) => c.key === categoryKey); if (!category) return false; return category.selectedIds?.includes(itemId) || false; }; const isMinimalOneCheckBoxIsSelected = (categoryKey) => { const category = categories.find((c) => c.key === categoryKey); if (!category) return false; const formattedItems = getFormattedItems(categoryKey); const filteredItems = formattedItems.flatMap((group) => group.itens || []); const filteredItemIds = filteredItems.map((item) => item.id); return filteredItemIds.some( (itemId) => category.selectedIds?.includes(itemId) ); }; const createCombinations = (acc, currentArray) => { const combinations = []; for (const existingCombo of acc) { for (const item of currentArray) { combinations.push([...existingCombo, item]); } } return combinations; }; const cartesian = (arr) => { return arr.reduce(createCombinations, [[]]); }; const getSelectedIdsForFilters = (filters) => { return filters.map((f) => { const parentCat = categories.find((c) => c.key === f.key); if (!parentCat?.selectedIds?.length) { return []; } return parentCat.selectedIds; }); }; const generateSingleFilterLabel = (filter, comboId) => { const cat = categories.find((c) => c.key === filter.key); return cat?.itens?.find((i) => i.id === comboId)?.name || comboId; }; const generateMultipleFiltersLabel = (filters, comboIds) => { const firstCat = categories.find((c) => c.key === filters[0].key); const firstVal = firstCat?.itens?.find((i) => i.id === comboIds[0])?.name || comboIds[0]; const labelParts = [firstVal]; for (let idx = 1; idx < filters.length; idx++) { const f = filters[idx]; const cat = categories.find((c) => c.key === f.key); const val = cat?.itens?.find((i) => i.id === comboIds[idx])?.name || comboIds[idx]; labelParts.push(`(${val})`); } return labelParts.join(" "); }; const processCombination = (comboIds, filters, category, groupedMap) => { const filteredItems = (category?.itens || []).filter( (item) => filters.every((f, idx) => item[f.internalField] === comboIds[idx]) ); if (filteredItems.length === 0) return; let groupLabel = void 0; if (filters.length === 1) { groupLabel = generateSingleFilterLabel(filters[0], comboIds[0]); } else if (filters.length > 1) { groupLabel = generateMultipleFiltersLabel(filters, comboIds); } const key = groupLabel || ""; if (!groupedMap[key]) { groupedMap[key] = groupLabel ? { groupLabel, itens: [] } : { itens: [] }; } groupedMap[key].itens.push(...filteredItems); }; const calculateFormattedItems = (categoryKey) => { const category = categories.find((c) => c.key === categoryKey); if (!category?.dependsOn || category.dependsOn.length === 0) { return [{ itens: category?.itens || [] }]; } const isEnabled = category.dependsOn.every((depKey) => { const depCat = categories.find((c) => c.key === depKey); return depCat?.selectedIds && depCat.selectedIds.length > 0; }); if (!isEnabled) { return [{ itens: [] }]; } const filters = category.filteredBy || []; if (filters.length === 0) { return [{ itens: category?.itens || [] }]; } const selectedIdsArr = getSelectedIdsForFilters(filters); if (selectedIdsArr.some((arr) => arr.length === 0)) { return [{ itens: [] }]; } const combinations = cartesian(selectedIdsArr); const groupedMap = {}; for (const comboIds of combinations) { processCombination(comboIds, filters, category, groupedMap); } const groupedItems = Object.values(groupedMap).filter( (g) => g.itens.length ); return groupedItems.length ? groupedItems : [{ itens: [] }]; }; const formattedItemsMap = (0, import_react4.useMemo)(() => { const formattedItemsMap2 = {}; for (const category of categories) { const formattedItems = calculateFormattedItems(category.key); formattedItemsMap2[category.key] = formattedItems; } return formattedItemsMap2; }, [categories]); const getFormattedItems = (categoryKey) => { return formattedItemsMap[categoryKey] || [{ itens: [] }]; }; const getBadgeText2 = (category) => { const formattedItems = getFormattedItems(category.key); return getBadgeText(category, formattedItems); }; const isCategoryEnabled2 = (category) => { return isCategoryEnabled(category, categories); }; const handleAccordionValueChange2 = (value) => { const newValue = handleAccordionValueChange( value, categories, isCategoryEnabled2 ); if (newValue !== null) { setOpenAccordion(newValue); } }; const getDependentCategories = (categoryKey) => { return categories.filter((cat) => cat.dependsOn?.includes(categoryKey)).map((cat) => cat.key); }; const findItemsToRemove = (depCategory, relevantFilter, deselectedItemId) => { return depCategory.itens?.filter( (item) => item[relevantFilter.internalField] === deselectedItemId ).map((item) => item.id) || []; }; const processDependentCategory = (depCategoryKey, categoryKey, deselectedItemId, itemsToDeselect) => { const depCategory = categories.find((c) => c.key === depCategoryKey); if (!depCategory?.filteredBy) return; const relevantFilter = depCategory.filteredBy.find( (f) => f.key === categoryKey ); if (!relevantFilter) return; const itemsToRemove = findItemsToRemove( depCategory, relevantFilter, deselectedItemId ); if (itemsToRemove.length > 0) { itemsToDeselect[depCategoryKey] = itemsToRemove; } }; const getItemsToDeselect = (categoryKey, deselectedItemId) => { const deselectedItem = categories.find((c) => c.key === categoryKey)?.itens?.find((item) => item.id === deselectedItemId); if (!deselectedItem) return {}; const itemsToDeselect = {}; const dependentCategories = getDependentCategories(categoryKey); for (const depCategoryKey of dependentCategories) { processDependentCategory( depCategoryKey, categoryKey, deselectedItemId, itemsToDeselect ); } return itemsToDeselect; }; const updateCategorySelectedIds = (updatedCategories, depCategoryIndex, depCategory, itemIds) => { const newSelectedIds = depCategory.selectedIds?.filter((id) => !itemIds.includes(id)) || []; updatedCategories[depCategoryIndex] = { ...depCategory, selectedIds: newSelectedIds }; return updatedCategories; }; const applyRecursiveCascade = (depCategoryKey, itemIds, updatedCategories) => { let result = updatedCategories; for (const itemId of itemIds) { result = applyCascadeDeselection(depCategoryKey, itemId, result); } return result; }; const applyCascadeDeselection = (categoryKey, deselectedItemId, currentCategories) => { const itemsToDeselect = getItemsToDeselect(categoryKey, deselectedItemId); let updatedCategories = [...currentCategories]; for (const [depCategoryKey, itemIds] of Object.entries(itemsToDeselect)) { const depCategoryIndex = updatedCategories.findIndex( (c) => c.key === depCategoryKey ); if (depCategoryIndex !== -1) { const depCategory = updatedCategories[depCategoryIndex]; updatedCategories = updateCategorySelectedIds( updatedCategories, depCategoryIndex, depCategory, itemIds ); updatedCategories = applyRecursiveCascade( depCategoryKey, itemIds, updatedCategories ); } } return updatedCategories; }; const toggleAllInCategory = (categoryKey) => { const category = categories.find((c) => c.key === categoryKey); if (!category) return; const formattedItems = getFormattedItems(categoryKey); const filteredItems = formattedItems.flatMap((group) => group.itens || []); const filteredItemIds = filteredItems.map((item) => item.id); const selectedFilteredCount = filteredItemIds.filter( (itemId) => category.selectedIds?.includes(itemId) ).length; const allFilteredSelected = selectedFilteredCount === filteredItemIds.length; const newSelection = allFilteredSelected ? category.selectedIds?.filter((id) => !filteredItemIds.includes(id)) || [] : [ ...category.selectedIds || [], ...filteredItemIds.filter( (id) => !category.selectedIds?.includes(id) ) ]; let updatedCategories = categories.map( (c) => c.key === categoryKey ? { ...c, selectedIds: newSelection } : c ); if (allFilteredSelected) { for (const itemId of filteredItemIds) { updatedCategories = applyCascadeDeselection( categoryKey, itemId, updatedCategories ); } } onCategoriesChange(updatedCategories); }; const toggleItem = (categoryKey, itemId) => { const category = categories.find((c) => c.key === categoryKey); if (!category) return; const isCurrentlySelected = category.selectedIds?.includes(itemId); const newSelection = isCurrentlySelected ? category.selectedIds?.filter((id) => id !== itemId) : [...category.selectedIds || [], itemId]; let updatedCategories = categories.map( (c) => c.key === categoryKey ? { ...c, selectedIds: newSelection } : c ); if (isCurrentlySelected) { updatedCategories = applyCascadeDeselection( categoryKey, itemId, updatedCategories ); } onCategoriesChange(updatedCategories); }; const renderCheckboxItem = (item, categoryKey) => { const uniqueId = `${categoryKey}-${item.id}`; return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)( "div", { className: "flex items-center gap-3 px-2", role: "presentation", onClick: (e) => e.stopPropagation(), onMouseDown: (e) => e.stopPropagation(), onMouseUp: (e) => e.stopPropagation(), onKeyDown: (e) => e.stopPropagation(), children: [ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)( CheckBox_default, { id: uniqueId, checked: isCheckBoxIsSelected(categoryKey, item.id), onChange: () => toggleItem(categoryKey, item.id) } ), /* @__PURE__ */ (0, import_jsx_runtime7.jsx)( "label", { htmlFor: uniqueId, className: "text-sm text-text-950 cursor-pointer select-none", children: item.name } ) ] }, item.id ); }; const renderFormattedGroup = (formattedGroup, idx, categoryKey) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)( "div", { className: "flex flex-col gap-3", children: [ "groupLabel" in formattedGroup && formattedGroup.groupLabel && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text_default, { size: "sm", className: "mt-2", weight: "semibold", children: formattedGroup.groupLabel }), formattedGroup.itens?.map( (item) => renderCheckboxItem(item, categoryKey) ) ] }, formattedGroup.groupLabel || `group-${idx}` ); const renderAccordionTrigger = (category, isEnabled) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center justify-between w-full p-2", children: [ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-3", children: [ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)( CheckBox_default, { checked: isMinimalOneCheckBoxIsSelected(category.key), disabled: !isEnabled, indeterminate: isMinimalOneCheckBoxIsSelected(category.key), onChange: () => toggleAllInCategory(category.key) } ), /* @__PURE__ */ (0, import_jsx_runtime7.jsx)( Text_default, { size: "sm", weight: "medium", className: cn("text-text-800", !isEnabled && "opacity-40"), children: category.label } ) ] }), (openAccordion === category.key || isEnabled) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Badge_default, { variant: "solid", action: "info", children: getBadgeText2(category) }) ] }); const renderCompactSingleItem = (category) => { const formattedItems = getFormattedItems(category.key); const allItems = formattedItems.flatMap((group) => group.itens || []); if (allItems.length !== 1) { return null; } const singleItem = allItems[0]; return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)( "div", { className: "flex items-center justify-between w-full px-3 py-2", children: [ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text_default, { size: "sm", weight: "bold", className: "text-text-800", children: category.label }), /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text_default, { size: "sm", className: "text-text-950", children: singleItem.name }) ] }, category.key ); }; const renderCategoryAccordion = (category) => { const isEnabled = isCategoryEnabled2(category); const hasOnlyOneItem = category.itens?.length === 1; if (hasOnlyOneItem && !compactSingleItem && !showSingleItem) { return null; } const formattedItems = getFormattedItems(category.key); const allItems = formattedItems.flatMap((group) => group.itens || []); const hasOnlyOneAvailableItem = allItems.length === 1; if (compactSingleItem && hasOnlyOneAvailableItem && isEnabled) { return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [ renderCompactSingleItem(category), showDivider && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Divider_default, {}) ] }, category.key); } const hasNoItems = formattedItems.every( (group) => !group.itens || group.itens.length === 0 ); return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)( CardAccordation, { value: category.key, disabled: !isEnabled, className: cn( "bg-transparent border-0", openAccordion === category.key && "bg-background-50 border-none" ), trigger: renderAccordionTrigger(category, isEnabled), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex flex-col gap-3 pt-2", children: hasNoItems && isEnabled ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "px-2 py-4", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text_default, { size: "sm", className: "text-text-500 text-center", children: "Sem dados" }) }) : formattedItems.map( (formattedGroup, idx) => renderFormattedGroup(formattedGroup, idx, category.key) ) }) } ), openAccordion !== category.key && showDivider && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Divider_default, {}) ] }, category.key); }; (0, import_react4.useEffect)(() => { if (!openAccordion) return; const category = categories.find((c) => c.key === openAccordion); if (!category) return; const isEnabled = isCategoryEnabled2(category); if (!isEnabled) { setTimeout(() => { setOpenAccordion(""); }, 0); } }, [categories, openAccordion]); return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)( AccordionGroup, { type: "single", collapsible: true, value: openAccordion, onValueChange: handleAccordionValueChange2, children: categories.map(renderCategoryAccordion) } ); }; // src/components/AlertManager/useAlertForm.ts var import_zustand = require("zustand"); var initialState = { title: "", message: "", image: null, date: "", time: "", sendToday: false, sendCopyToEmail: false, recipientCategories: {} }; var useAlertFormStore = (0, import_zustand.create)((set) => ({ ...initialState, // Step 1 - Mensagem setTitle: (title) => set({ title }), setMessage: (message) => set({ message }), setImage: (image) => set({ image }), // Step 2 - Destinatários (Dinâmico) initializeCategory: (category) => set((state) => ({ recipientCategories: { ...state.recipientCategories, [category.key]: { ...category, selectedIds: category.selectedIds || [], allSelected: category.allSelected || false } } })), updateCategoryItems: (key, items) => set((state) => { const base = state.recipientCategories[key] ?? { key, label: key, availableItems: [], selectedIds: [], allSelected: false }; return { recipientCategories: { ...state.recipientCategories, [key]: { ...base, availableItems: items } } }; }), updateCategorySelection: (key, selectedIds, allSelected) => set((state) => { const base = state.recipientCategories[key] ?? { key, label: key, availableItems: [], selectedIds: [], allSelected: false }; return { recipientCategories: { ...state.recipientCategories, [key]: { ...base, selectedIds, allSelected } } }; }), clearCategorySelection: (key) => set((state) => { const base = state.recipientCategories[key] ?? { key, label: key, availableItems: [], selectedIds: [], allSelected: false }; return { recipientCategories: { ...state.recipientCategories, [key]: { ...base, selectedIds: [], allSelected: false } } }; }), // Step 3 - Data de envio setDate: (date) => set({ date }), setTime: (time) => set({ time }), setSendToday: (sendToday) => { const now = /* @__PURE__ */ new Date(); const year = now.getFullYear(); const month = String(now.getMonth() + 1).padStart(2, "0"); const day = String(now.getDate()).padStart(2, "0"); const hours = String(now.getHours()).padStart(2, "0"); const minutes = String(now.getMinutes()).padStart(2, "0"); set({ sendToday, date: `${year}-${month}-${day}`, time: `${hours}:${minutes}` }); }, setSendCopyToEmail: (sendCopyToEmail) => set({ sendCopyToEmail }), // Reset form resetForm: () => set(initialState) })); // src/components/Modal/Modal.tsx var import_react5 = require("react"); var import_phosphor_react4 = require("phosphor-react"); // src/components/Modal/utils/videoUtils.ts var isYouTubeUrl = (url) => { const youtubeRegex = /^(https?:\/\/)?((www|m|music)\.)?(youtube\.com|youtu\.be|youtube-nocookie\.com)\/.+/i; return youtubeRegex.test(url); }; var isValidYouTubeHost = (host) => { if (host === "youtu.be") return "youtu.be"; const isValidYouTubeCom = host === "youtube.com" || host.endsWith(".youtube.com") && /^(www|m|music)\.youtube\.com$/.test(host); if (isValidYouTubeCom) return "youtube"; const isValidNoCookie = host === "youtube-nocookie.com" || host.endsWith(".youtube-nocookie.com") && /^(www|m|music)\.youtube-nocookie\.com$/.test(host); if (isValidNoCookie) return "nocookie"; return null; }; var extractYoutuBeId = (pathname) => { const firstSeg = pathname.split("/").filter(Boolean)[0]; return firstSeg || null; }; var extractYouTubeId = (pathname, searchParams) => { const parts = pathname.split("/").filter(Boolean); const [first, second] = parts; if (first === "embed" && second) return second; if (first === "shorts" && second) return second; if (first === "live" && second) return second; const v = searchParams.get("v"); if (v) return v; return null; }; var getYouTubeVideoId = (url) => { try { const u = new URL(url); const hostType = isValidYouTubeHost(u.hostname.toLowerCase()); if (!hostType) return null; if (hostType === "youtu.be") { return extractYoutuBeId(u.pathname); } return extractYouTubeId(u.pathname, u.searchParams); } catch { return null; } }; var getYouTubeEmbedUrl = (videoId) => { return `https://www.youtube-nocookie.com/embed/${videoId}?autoplay=0&rel=0&modestbranding=1`; }; // s