analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
1,332 lines (1,317 loc) • 229 kB
JavaScript
"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