analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
1 lines • 53.9 kB
Source Map (JSON)
{"version":3,"sources":["../../src/components/Alternative/Alternative.tsx","../../src/components/Badge/Badge.tsx","../../src/utils/utils.ts","../../src/components/Radio/Radio.tsx","../../src/components/Text/Text.tsx"],"sourcesContent":["import { CheckCircle, XCircle } from 'phosphor-react';\nimport Badge from '../Badge/Badge';\nimport { RadioGroup, RadioGroupItem } from '../Radio/Radio';\nimport { forwardRef, HTMLAttributes, useId, useState } from 'react';\nimport { cn } from '../../utils/utils';\n\n/**\n * Interface para definir uma alternativa\n */\nexport interface Alternative {\n value: string;\n label: string;\n status?: 'correct' | 'incorrect' | 'neutral';\n disabled?: boolean;\n description?: string;\n}\n\n/**\n * Props do componente AlternativesList\n */\nexport interface AlternativesListProps {\n /** Lista de alternativas */\n alternatives: Alternative[];\n /** Nome do grupo de radio */\n name?: string;\n /** Valor selecionado por padrão */\n defaultValue?: string;\n /** Valor controlado */\n value?: string;\n /** Callback quando uma alternativa é selecionada */\n onValueChange?: (value: string) => void;\n /** Se o componente está desabilitado */\n disabled?: boolean;\n /** Layout das alternativas */\n layout?: 'default' | 'compact' | 'detailed';\n /** Classes CSS adicionais */\n className?: string;\n /** Modo de exibição: interativo (com radios funcionais) ou readonly (apenas visual) */\n mode?: 'interactive' | 'readonly';\n /** Valor selecionado pelo usuário (apenas para modo readonly) */\n selectedValue?: string;\n}\n\n/**\n * Componente reutilizável para exibir lista de alternativas com RadioGroup\n *\n * Suporta dois modos:\n * - `interactive`: Permite interação com radios (padrão)\n * - `readonly`: Apenas exibição visual dos estados\n *\n * @example\n * ```tsx\n * // Modo interativo (padrão)\n * <AlternativesList\n * mode=\"interactive\"\n * alternatives={[\n * { value: \"a\", label: \"Alternativa A\", status: \"correct\" },\n * { value: \"b\", label: \"Alternativa B\", status: \"incorrect\" },\n * { value: \"c\", label: \"Alternativa C\" }\n * ]}\n * defaultValue=\"a\"\n * onValueChange={(value) => console.log(value)}\n * />\n *\n * // Modo readonly - mostra seleção do usuário\n * <AlternativesList\n * mode=\"readonly\"\n * selectedValue=\"b\" // O que o usuário selecionou\n * alternatives={[\n * { value: \"a\", label: \"Resposta A\", status: \"correct\" }, // Mostra como correta\n * { value: \"b\", label: \"Resposta B\" }, // Mostra radio selecionado + badge incorreto\n * { value: \"c\", label: \"Resposta C\" }\n * ]}\n * />\n * ```\n */\nconst AlternativesList = ({\n alternatives,\n name,\n defaultValue,\n value,\n onValueChange,\n disabled = false,\n layout = 'default',\n className = '',\n mode = 'interactive',\n selectedValue,\n}: AlternativesListProps) => {\n // Gerar um ID único para garantir que cada instância tenha seu próprio grupo\n const uniqueId = useId();\n const groupName = name || `alternatives-${uniqueId}`;\n const [actualValue, setActualValue] = useState(value);\n // No modo readonly, não precisamos de interação\n const isReadonly = mode === 'readonly';\n const getStatusStyles = (\n status?: Alternative['status'],\n isReadonly?: boolean\n ) => {\n const hoverClass = isReadonly ? '' : 'hover:bg-background-50';\n\n switch (status) {\n case 'correct':\n return 'bg-success-background border-success-300';\n case 'incorrect':\n return 'bg-error-background border-error-300';\n default:\n return `bg-background border-border-100 ${hoverClass}`;\n }\n };\n\n const getStatusBadge = (status?: Alternative['status']) => {\n switch (status) {\n case 'correct':\n return (\n <Badge variant=\"solid\" action=\"success\" iconLeft={<CheckCircle />}>\n Resposta correta\n </Badge>\n );\n case 'incorrect':\n return (\n <Badge variant=\"solid\" action=\"error\" iconLeft={<XCircle />}>\n Resposta incorreta\n </Badge>\n );\n default:\n return null;\n }\n };\n\n const getLayoutClasses = () => {\n switch (layout) {\n case 'compact':\n return 'gap-2';\n case 'detailed':\n return 'gap-4';\n default:\n return 'gap-3.5';\n }\n };\n\n // Componente para renderizar alternativa no modo readonly\n const renderReadonlyAlternative = (alternative: Alternative) => {\n const alternativeId = alternative.value;\n const isUserSelected = selectedValue === alternative.value;\n const isCorrectAnswer = alternative.status === 'correct';\n\n // Determinar o status da alternativa para visualização\n let displayStatus: Alternative['status'] = undefined;\n if (isUserSelected && !isCorrectAnswer) {\n // Usuário selecionou alternativa incorreta\n displayStatus = 'incorrect';\n } else if (isCorrectAnswer) {\n // Alternativa correta (independente se foi selecionada ou não)\n displayStatus = 'correct';\n }\n\n const statusStyles = getStatusStyles(displayStatus, true);\n const statusBadge = getStatusBadge(displayStatus);\n\n // Radio visual - apenas mostra selecionado se o usuário escolheu esta alternativa\n const renderRadio = () => {\n const radioClasses = `w-6 h-6 rounded-full border-2 cursor-default transition-all duration-200 flex items-center justify-center ${\n isUserSelected\n ? 'border-primary-950 bg-background'\n : 'border-border-400 bg-background'\n }`;\n\n const dotClasses =\n 'w-3 h-3 rounded-full bg-primary-950 transition-all duration-200';\n\n return (\n <div className={radioClasses}>\n {isUserSelected && <div className={dotClasses} />}\n </div>\n );\n };\n\n if (layout === 'detailed') {\n return (\n <div\n key={alternativeId}\n className={cn(\n 'border-2 rounded-lg p-4 w-full',\n statusStyles,\n alternative.disabled ? 'opacity-50' : ''\n )}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3 flex-1\">\n <div className=\"mt-1\">{renderRadio()}</div>\n <div className=\"flex-1\">\n <p\n className={cn(\n 'block font-medium',\n selectedValue === alternative.value || statusBadge\n ? 'text-text-950'\n : 'text-text-600'\n )}\n >\n {alternative.label}\n </p>\n {alternative.description && (\n <p className=\"text-sm text-text-600 mt-1\">\n {alternative.description}\n </p>\n )}\n </div>\n </div>\n {statusBadge && <div className=\"flex-shrink-0\">{statusBadge}</div>}\n </div>\n </div>\n );\n }\n\n return (\n <div\n key={alternativeId}\n className={cn(\n 'flex flex-row justify-between items-start gap-2 p-2 rounded-lg w-full',\n statusStyles,\n alternative.disabled ? 'opacity-50' : ''\n )}\n >\n <div className=\"flex items-center gap-2 flex-1\">\n {renderRadio()}\n <span\n className={cn(\n 'flex-1',\n selectedValue === alternative.value || statusBadge\n ? 'text-text-950'\n : 'text-text-600'\n )}\n >\n {alternative.label}\n </span>\n </div>\n {statusBadge && <div className=\"flex-shrink-0\">{statusBadge}</div>}\n </div>\n );\n };\n\n // Se for modo readonly, renderizar sem RadioGroup\n if (isReadonly) {\n return (\n <div\n className={cn('flex flex-col', getLayoutClasses(), 'w-full', className)}\n >\n {alternatives.map((alternative) =>\n renderReadonlyAlternative(alternative)\n )}\n </div>\n );\n }\n\n return (\n <RadioGroup\n name={groupName}\n defaultValue={defaultValue}\n value={value}\n onValueChange={(value) => {\n setActualValue(value);\n onValueChange?.(value);\n }}\n disabled={disabled}\n className={cn('flex flex-col', getLayoutClasses(), className)}\n >\n {alternatives.map((alternative, index) => {\n const alternativeId = alternative.value || `alt-${index}`;\n const statusStyles = getStatusStyles(alternative.status, false);\n const statusBadge = getStatusBadge(alternative.status);\n\n if (layout === 'detailed') {\n return (\n <div\n key={alternativeId}\n className={cn(\n 'border-2 rounded-lg p-4 transition-all',\n statusStyles,\n alternative.disabled\n ? 'opacity-50 cursor-not-allowed'\n : 'cursor-pointer'\n )}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3 flex-1\">\n <RadioGroupItem\n value={alternative.value}\n id={alternativeId}\n disabled={alternative.disabled}\n className=\"mt-1\"\n />\n <div className=\"flex-1\">\n <label\n htmlFor={alternativeId}\n className={cn(\n 'block font-medium',\n actualValue === alternative.value\n ? 'text-text-950'\n : 'text-text-600',\n alternative.disabled\n ? 'cursor-not-allowed'\n : 'cursor-pointer'\n )}\n >\n {alternative.label}\n </label>\n {alternative.description && (\n <p className=\"text-sm text-text-600 mt-1\">\n {alternative.description}\n </p>\n )}\n </div>\n </div>\n {statusBadge && (\n <div className=\"flex-shrink-0\">{statusBadge}</div>\n )}\n </div>\n </div>\n );\n }\n\n return (\n <div\n key={alternativeId}\n className={cn(\n 'flex flex-row justify-between gap-2 items-start p-2 rounded-lg transition-all',\n statusStyles,\n alternative.disabled ? 'opacity-50 cursor-not-allowed' : ''\n )}\n >\n <div className=\"flex items-center gap-2 flex-1\">\n <RadioGroupItem\n value={alternative.value}\n id={alternativeId}\n disabled={alternative.disabled}\n />\n <label\n htmlFor={alternativeId}\n className={cn(\n 'flex-1',\n actualValue === alternative.value\n ? 'text-text-950'\n : 'text-text-600',\n alternative.disabled ? 'cursor-not-allowed' : 'cursor-pointer'\n )}\n >\n {alternative.label}\n </label>\n </div>\n {statusBadge && <div className=\"flex-shrink-0\">{statusBadge}</div>}\n </div>\n );\n })}\n </RadioGroup>\n );\n};\n\ninterface HeaderAlternativeProps extends HTMLAttributes<HTMLDivElement> {\n title: string;\n subTitle: string;\n content: string;\n}\n\nconst HeaderAlternative = forwardRef<HTMLDivElement, HeaderAlternativeProps>(\n ({ className, title, subTitle, content, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\n 'bg-background p-4 flex flex-col gap-4 rounded-xl',\n className\n )}\n {...props}\n >\n <span className=\"flex flex-col\">\n <p className=\"text-text-950 font-bold text-lg\">{title}</p>\n <p className=\"text-text-700 text-sm \">{subTitle}</p>\n </span>\n\n <p className=\"text-text-950 text-md\">{content}</p>\n </div>\n );\n }\n);\n\nexport { AlternativesList, HeaderAlternative };\n","import { HTMLAttributes, ReactNode } from 'react';\nimport { Bell } from 'phosphor-react';\nimport { cn } from '../../utils/utils';\n\n/**\n * Lookup table for variant and action class combinations\n */\nconst VARIANT_ACTION_CLASSES = {\n solid: {\n error: 'bg-error-background text-error-700 focus-visible:outline-none',\n warning: 'bg-warning text-warning-800 focus-visible:outline-none',\n success: 'bg-success text-success-800 focus-visible:outline-none',\n info: 'bg-info text-info-800 focus-visible:outline-none',\n muted: 'bg-background-muted text-background-800 focus-visible:outline-none',\n },\n outlined: {\n error:\n 'bg-error text-error-700 border border-error-300 focus-visible:outline-none',\n warning:\n 'bg-warning text-warning-800 border border-warning-300 focus-visible:outline-none',\n success:\n 'bg-success text-success-800 border border-success-300 focus-visible:outline-none',\n info: 'bg-info text-info-800 border border-info-300 focus-visible:outline-none',\n muted:\n 'bg-background-muted text-background-800 border border-border-300 focus-visible:outline-none',\n },\n exams: {\n exam1: 'bg-exam-1 text-info-700 focus-visible:outline-none',\n exam2: 'bg-exam-2 text-typography-1 focus-visible:outline-none',\n exam3: 'bg-exam-3 text-typography-2 focus-visible:outline-none',\n exam4: 'bg-exam-4 text-success-700 focus-visible:outline-none',\n },\n examsOutlined: {\n exam1:\n 'bg-exam-1 text-info-700 border border-info-700 focus-visible:outline-none',\n exam2:\n 'bg-exam-2 text-typography-1 border border-typography-1 focus-visible:outline-none',\n exam3:\n 'bg-exam-3 text-typography-2 border border-typography-2 focus-visible:outline-none',\n exam4:\n 'bg-exam-4 text-success-700 border border-success-700 focus-visible:outline-none',\n },\n resultStatus: {\n negative: 'bg-error text-error-800 focus-visible:outline-none',\n positive: 'bg-success text-success-800 focus-visible:outline-none',\n },\n notification: 'text-primary',\n} as const;\n\n/**\n * Lookup table for size classes\n */\nconst SIZE_CLASSES = {\n small: 'text-2xs px-2 py-1',\n medium: 'text-xs px-2 py-1',\n large: 'text-sm px-2 py-1',\n} as const;\n\nconst SIZE_CLASSES_ICON = {\n small: 'size-3',\n medium: 'size-3.5',\n large: 'size-4',\n} as const;\n\n/**\n * Badge component props interface\n */\ntype BadgeProps = {\n /** Content to be displayed inside the badge */\n children?: ReactNode;\n /** Ícone à direita do texto */\n iconRight?: ReactNode;\n /** Ícone à esquerda do texto */\n iconLeft?: ReactNode;\n /** Size of the badge */\n size?: 'small' | 'medium' | 'large';\n /** Visual variant of the badge */\n variant?:\n | 'solid'\n | 'outlined'\n | 'exams'\n | 'examsOutlined'\n | 'resultStatus'\n | 'notification';\n /** Action type of the badge */\n action?:\n | 'error'\n | 'warning'\n | 'success'\n | 'info'\n | 'muted'\n | 'exam1'\n | 'exam2'\n | 'exam3'\n | 'exam4'\n | 'positive'\n | 'negative';\n /** Additional CSS classes to apply */\n className?: string;\n notificationActive?: boolean;\n} & HTMLAttributes<HTMLDivElement>;\n\n/**\n * Badge component for Analytica Ensino platforms\n *\n * A flexible button component with multiple variants, sizes and actions.\n *\n * @param children - The content to display inside the badge\n * @param size - The size variant (extra-small, small, medium, large, extra-large)\n * @param variant - The visual style variant (solid, outline, link)\n * @param action - The action type (primary, positive, negative)\n * @param className - Additional CSS classes\n * @param props - All other standard div HTML attributes\n * @returns A styled badge element\n *\n * @example\n * ```tsx\n * <Badge variant=\"solid\" action=\"info\" size=\"medium\">\n * Information\n * </Badge>\n * ```\n */\nconst Badge = ({\n children,\n iconLeft,\n iconRight,\n size = 'medium',\n variant = 'solid',\n action = 'error',\n className = '',\n notificationActive = false,\n ...props\n}: BadgeProps) => {\n // Get classes from lookup tables\n const sizeClasses = SIZE_CLASSES[size];\n const sizeClassesIcon = SIZE_CLASSES_ICON[size];\n const variantActionMap = VARIANT_ACTION_CLASSES[variant] || {};\n const variantClasses =\n typeof variantActionMap === 'string'\n ? variantActionMap\n : ((variantActionMap as Record<string, string>)[action] ??\n (variantActionMap as Record<string, string>).muted ??\n '');\n\n const baseClasses =\n 'inline-flex items-center justify-center rounded-xs font-normal gap-1 relative';\n\n const baseClassesIcon = 'flex items-center';\n if (variant === 'notification') {\n return (\n <div\n className={cn(baseClasses, variantClasses, sizeClasses, className)}\n {...props}\n >\n <Bell size={24} className=\"text-current\" aria-hidden=\"true\" />\n\n {notificationActive && (\n <span\n data-testid=\"notification-dot\"\n className=\"absolute top-[5px] right-[10px] block h-2 w-2 rounded-full bg-indicator-error ring-2 ring-white\"\n />\n )}\n </div>\n );\n }\n return (\n <div\n className={cn(baseClasses, variantClasses, sizeClasses, className)}\n {...props}\n >\n {iconLeft && (\n <span className={cn(baseClassesIcon, sizeClassesIcon)}>{iconLeft}</span>\n )}\n {children}\n {iconRight && (\n <span className={cn(baseClassesIcon, sizeClassesIcon)}>\n {iconRight}\n </span>\n )}\n </div>\n );\n};\n\nexport default Badge;\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import {\n InputHTMLAttributes,\n HTMLAttributes,\n ReactNode,\n forwardRef,\n useState,\n useId,\n ChangeEvent,\n useEffect,\n useRef,\n Children,\n cloneElement,\n isValidElement,\n ReactElement,\n} from 'react';\nimport { create, StoreApi, useStore } from 'zustand';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\n\n/**\n * Radio size variants\n */\ntype RadioSize = 'small' | 'medium' | 'large' | 'extraLarge';\n\n/**\n * Radio visual state\n */\ntype RadioState = 'default' | 'hovered' | 'focused' | 'invalid' | 'disabled';\n\n/**\n * Size configurations using Tailwind classes\n */\nconst SIZE_CLASSES = {\n small: {\n radio: 'w-5 h-5',\n textSize: 'sm' as const,\n spacing: 'gap-1.5',\n borderWidth: 'border-2',\n dotSize: 'w-2.5 h-2.5',\n labelHeight: 'h-5',\n },\n medium: {\n radio: 'w-6 h-6',\n textSize: 'md' as const,\n spacing: 'gap-2',\n borderWidth: 'border-2',\n dotSize: 'w-3 h-3',\n labelHeight: 'h-6',\n },\n large: {\n radio: 'w-7 h-7',\n textSize: 'lg' as const,\n spacing: 'gap-2',\n borderWidth: 'border-2',\n dotSize: 'w-3.5 h-3.5',\n labelHeight: 'h-7',\n },\n extraLarge: {\n radio: 'w-8 h-8',\n textSize: 'xl' as const,\n spacing: 'gap-3',\n borderWidth: 'border-2',\n dotSize: 'w-4 h-4',\n labelHeight: 'h-8',\n },\n} as const;\n\n/**\n * Focused state maintains the same sizes as default state\n * Only adds wrapper styling, does not change radio/dot sizes\n */\n\n/**\n * Base radio styling classes using design system colors\n */\nconst BASE_RADIO_CLASSES =\n 'rounded-full border cursor-pointer transition-all duration-200 flex items-center justify-center focus:outline-none';\n\n/**\n * State-based styling classes using design system colors from styles.css\n */\nconst STATE_CLASSES = {\n default: {\n unchecked: 'border-border-400 bg-background hover:border-border-500',\n checked: 'border-primary-950 bg-background hover:border-primary-800',\n },\n hovered: {\n unchecked: 'border-border-500 bg-background',\n checked: 'border-info-700 bg-background',\n },\n focused: {\n unchecked: 'border-border-400 bg-background',\n checked: 'border-primary-950 bg-background',\n },\n invalid: {\n unchecked: 'border-border-400 bg-background',\n checked: 'border-primary-950 bg-background',\n },\n disabled: {\n unchecked: 'border-border-400 bg-background cursor-not-allowed',\n checked: 'border-primary-950 bg-background cursor-not-allowed',\n },\n} as const;\n\n/**\n * Dot styling classes for the inner dot when checked\n */\nconst DOT_CLASSES = {\n default: 'bg-primary-950',\n hovered: 'bg-info-700',\n focused: 'bg-primary-950',\n invalid: 'bg-primary-950',\n disabled: 'bg-primary-950',\n} as const;\n\n/**\n * Radio component props interface\n */\nexport type RadioProps = {\n /** Label text to display next to the radio */\n label?: ReactNode;\n /** Size variant of the radio */\n size?: RadioSize;\n /** Visual state of the radio */\n state?: RadioState;\n /** Error message to display */\n errorMessage?: string;\n /** Helper text to display */\n helperText?: string;\n /** Additional CSS classes */\n className?: string;\n /** Label CSS classes */\n labelClassName?: string;\n /** Radio group name */\n name?: string;\n /** Radio value */\n value?: string;\n /** Default checked state for uncontrolled radios */\n defaultChecked?: boolean;\n} & Omit<\n InputHTMLAttributes<HTMLInputElement>,\n 'size' | 'type' | 'defaultChecked'\n>;\n\n/**\n * Radio component for Analytica Ensino platforms\n *\n * A radio button component with essential states, sizes and themes.\n * Uses the Analytica Ensino Design System colors from styles.css with automatic\n * light/dark mode support. Includes Text component integration for consistent typography.\n *\n * @example\n * ```tsx\n * // Basic radio\n * <Radio name=\"option\" value=\"1\" label=\"Option 1\" />\n *\n * // Small size\n * <Radio size=\"small\" name=\"option\" value=\"2\" label=\"Small option\" />\n *\n * // Invalid state\n * <Radio state=\"invalid\" name=\"option\" value=\"3\" label=\"Required field\" />\n *\n * // Disabled state\n * <Radio disabled name=\"option\" value=\"4\" label=\"Disabled option\" />\n *\n * // Default checked (uncontrolled)\n * <Radio defaultChecked name=\"option\" value=\"5\" label=\"Initially checked\" />\n * ```\n */\nconst Radio = forwardRef<HTMLInputElement, RadioProps>(\n (\n {\n label,\n size = 'medium',\n state = 'default',\n errorMessage,\n helperText,\n className = '',\n labelClassName = '',\n checked: checkedProp,\n defaultChecked = false,\n disabled,\n id,\n name,\n value,\n onChange,\n ...props\n },\n ref\n ) => {\n // Generate unique ID if not provided\n const generatedId = useId();\n const inputId = id ?? `radio-${generatedId}`;\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Handle controlled vs uncontrolled behavior\n const [internalChecked, setInternalChecked] = useState(defaultChecked);\n const isControlled = checkedProp !== undefined;\n const checked = isControlled ? checkedProp : internalChecked;\n\n // Handle change events\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n const newChecked = event.target.checked;\n\n if (!isControlled) {\n setInternalChecked(newChecked);\n }\n\n // Prevent automatic scroll when input changes\n if (event.target) {\n event.target.blur();\n }\n\n onChange?.(event);\n };\n\n // Determine current state based on props\n const currentState = disabled ? 'disabled' : state;\n\n // Get size classes\n const sizeClasses = SIZE_CLASSES[size];\n\n // Focused state maintains original sizes, only adds wrapper\n const actualRadioSize = sizeClasses.radio;\n const actualDotSize = sizeClasses.dotSize;\n\n // Determine radio visual variant\n const radioVariant = checked ? 'checked' : 'unchecked';\n\n // Get styling classes\n const stylingClasses = STATE_CLASSES[currentState][radioVariant];\n\n // Border width logic - consistent across all states and sizes\n const getBorderWidth = () => {\n if (currentState === 'focused') {\n return 'border-2';\n }\n return sizeClasses.borderWidth;\n };\n\n const borderWidthClass = getBorderWidth();\n\n // Get final radio classes\n const radioClasses = cn(\n BASE_RADIO_CLASSES,\n actualRadioSize,\n borderWidthClass,\n stylingClasses,\n className\n );\n\n // Get dot classes\n const dotClasses = cn(\n actualDotSize,\n 'rounded-full',\n DOT_CLASSES[currentState],\n 'transition-all duration-200'\n );\n\n // Determine if wrapper is needed only for focused or invalid states\n const isWrapperNeeded =\n currentState === 'focused' || currentState === 'invalid';\n const wrapperBorderColor =\n currentState === 'focused'\n ? 'border-indicator-info'\n : 'border-indicator-error';\n\n // Determine text color based on state and checked status\n const getTextColor = () => {\n if (currentState === 'disabled') {\n return checked ? 'text-text-900' : 'text-text-600';\n }\n\n if (currentState === 'focused') {\n return 'text-text-900';\n }\n\n return checked ? 'text-text-900' : 'text-text-600';\n };\n\n // Determine cursor class based on disabled state\n const getCursorClass = () => {\n return currentState === 'disabled'\n ? 'cursor-not-allowed'\n : 'cursor-pointer';\n };\n\n return (\n <div className=\"flex flex-col\">\n <div\n className={cn(\n 'flex flex-row items-center',\n isWrapperNeeded\n ? cn('p-1 border-2', wrapperBorderColor, 'rounded-lg gap-1.5')\n : sizeClasses.spacing,\n disabled ? 'opacity-40' : ''\n )}\n >\n {/* Hidden native input for accessibility and form submission */}\n <input\n ref={(node) => {\n inputRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n }}\n type=\"radio\"\n id={inputId}\n checked={checked}\n disabled={disabled}\n name={name}\n value={value}\n onChange={handleChange}\n className=\"sr-only\"\n style={{\n position: 'absolute',\n left: '-9999px',\n visibility: 'hidden',\n }}\n {...props}\n />\n\n {/* Custom styled radio */}\n <button\n type=\"button\"\n className={radioClasses}\n disabled={disabled}\n aria-pressed={checked}\n onClick={(e) => {\n // Prevent scroll when radio is clicked\n e.preventDefault();\n if (!disabled) {\n // Simulate click on hidden input\n if (inputRef.current) {\n inputRef.current.click();\n // Remove focus to prevent scroll behavior\n inputRef.current.blur();\n }\n }\n }}\n onKeyDown={(e) => {\n // Handle keyboard activation (Enter or Space)\n if ((e.key === 'Enter' || e.key === ' ') && !disabled) {\n e.preventDefault();\n if (inputRef.current) {\n inputRef.current.click();\n inputRef.current.blur();\n }\n }\n }}\n >\n {/* Show dot when checked */}\n {checked && <div className={dotClasses} />}\n </button>\n\n {/* Label text */}\n {label && (\n <div\n className={cn(\n 'flex flex-row items-center',\n sizeClasses.labelHeight,\n 'flex-1 min-w-0'\n )}\n >\n <Text\n as=\"label\"\n htmlFor={inputId}\n size={sizeClasses.textSize}\n weight=\"normal\"\n className={cn(\n getCursorClass(),\n 'select-none leading-normal flex items-center font-roboto truncate',\n labelClassName\n )}\n color={getTextColor()}\n >\n {label}\n </Text>\n </div>\n )}\n </div>\n\n {/* Error message */}\n {errorMessage && (\n <Text\n size=\"sm\"\n weight=\"normal\"\n className=\"mt-1.5 truncate\"\n color=\"text-error-600\"\n >\n {errorMessage}\n </Text>\n )}\n\n {/* Helper text */}\n {helperText && !errorMessage && (\n <Text\n size=\"sm\"\n weight=\"normal\"\n className=\"mt-1.5 truncate\"\n color=\"text-text-500\"\n >\n {helperText}\n </Text>\n )}\n </div>\n );\n }\n);\n\nRadio.displayName = 'Radio';\n\n/**\n * RadioGroup store interface\n */\ninterface RadioGroupStore {\n value: string;\n setValue: (value: string) => void;\n onValueChange?: (value: string) => void;\n disabled: boolean;\n name: string;\n}\n\ntype RadioGroupStoreApi = StoreApi<RadioGroupStore>;\n\n/**\n * Create a new RadioGroup store\n */\nconst createRadioGroupStore = (\n name: string,\n defaultValue: string,\n disabled: boolean,\n onValueChange?: (value: string) => void\n): RadioGroupStoreApi =>\n create<RadioGroupStore>((set, get) => ({\n value: defaultValue,\n setValue: (value) => {\n if (!get().disabled) {\n set({ value });\n get().onValueChange?.(value);\n }\n },\n onValueChange,\n disabled,\n name,\n }));\n\n/**\n * Hook to access RadioGroup store\n */\nexport const useRadioGroupStore = (externalStore?: RadioGroupStoreApi) => {\n if (!externalStore) {\n throw new Error('RadioGroupItem must be used within a RadioGroup');\n }\n return externalStore;\n};\n\n/**\n * Inject store into RadioGroupItem children\n */\nconst injectStore = (\n children: ReactNode,\n store: RadioGroupStoreApi\n): ReactNode =>\n Children.map(children, (child) => {\n if (!isValidElement(child)) return child;\n /* eslint-disable-next-line @typescript-eslint/no-explicit-any */\n const typedChild = child as ReactElement<any>;\n const shouldInject = typedChild.type === RadioGroupItem;\n return cloneElement(typedChild, {\n ...(shouldInject ? { store } : {}),\n ...(typedChild.props.children\n ? { children: injectStore(typedChild.props.children, store) }\n : {}),\n });\n });\n\n/**\n * RadioGroup component props interface\n */\nexport type RadioGroupProps = {\n /** Current selected value */\n value?: string;\n /** Default selected value for uncontrolled usage */\n defaultValue?: string;\n /** Callback when selection changes */\n onValueChange?: (value: string) => void;\n /** Group name for all radios */\n name?: string;\n /** Disabled state for the entire group */\n disabled?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Children components */\n children: ReactNode;\n} & Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue'>;\n\n/**\n * RadioGroup component for flexible radio group composition\n *\n * Uses Zustand for state management with automatic store injection.\n * Allows complete control over layout and styling by composing with RadioGroupItem.\n *\n * @example\n * ```tsx\n * <RadioGroup defaultValue=\"option1\" onValueChange={setValue}>\n * <div className=\"flex items-center gap-3\">\n * <RadioGroupItem value=\"option1\" id=\"r1\" />\n * <label htmlFor=\"r1\">Option 1</label>\n * </div>\n * <div className=\"flex items-center gap-3\">\n * <RadioGroupItem value=\"option2\" id=\"r2\" />\n * <label htmlFor=\"r2\">Option 2</label>\n * </div>\n * </RadioGroup>\n * ```\n */\nconst RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(\n (\n {\n value: propValue,\n defaultValue = '',\n onValueChange,\n name: propName,\n disabled = false,\n className = '',\n children,\n ...props\n },\n ref\n ) => {\n // Generate unique name if not provided\n const generatedId = useId();\n const name = propName || `radio-group-${generatedId}`;\n\n // Create store reference\n const storeRef = useRef<RadioGroupStoreApi>(null);\n storeRef.current ??= createRadioGroupStore(\n name,\n defaultValue,\n disabled,\n onValueChange\n );\n const store = storeRef.current;\n\n // Get store actions\n const { setValue } = useStore(store, (s) => s);\n\n // Call onValueChange with initial value\n useEffect(() => {\n const currentValue = store.getState().value;\n if (currentValue && onValueChange) {\n onValueChange(currentValue);\n }\n }, []); // Empty dependency array for mount only\n\n // Handle controlled value changes\n useEffect(() => {\n if (propValue !== undefined) {\n setValue(propValue);\n }\n }, [propValue, setValue]);\n\n // Update disabled state\n useEffect(() => {\n store.setState({ disabled });\n }, [disabled, store]);\n\n return (\n <div\n ref={ref}\n className={className}\n role=\"radiogroup\"\n aria-label={name}\n {...props}\n >\n {injectStore(children, store)}\n </div>\n );\n }\n);\n\nRadioGroup.displayName = 'RadioGroup';\n\n/**\n * RadioGroupItem component props interface\n */\nexport type RadioGroupItemProps = {\n /** Value for this radio item */\n value: string;\n /** Store reference (automatically injected by RadioGroup) */\n store?: RadioGroupStoreApi;\n /** Disabled state for this specific item */\n disabled?: boolean;\n /** Size variant */\n size?: RadioSize;\n /** Visual state */\n state?: RadioState;\n /** Additional CSS classes */\n className?: string;\n} & Omit<\n InputHTMLAttributes<HTMLInputElement>,\n 'type' | 'name' | 'value' | 'checked' | 'onChange' | 'size'\n>;\n\n/**\n * RadioGroupItem component for use within RadioGroup\n *\n * A radio button without label that works within RadioGroup context.\n * Provides just the radio input for maximum flexibility in composition.\n *\n * @example\n * ```tsx\n * <RadioGroup defaultValue=\"option1\">\n * <div className=\"flex items-center gap-3\">\n * <RadioGroupItem value=\"option1\" id=\"r1\" />\n * <label htmlFor=\"r1\">Option 1</label>\n * </div>\n * </RadioGroup>\n * ```\n */\nconst RadioGroupItem = forwardRef<HTMLInputElement, RadioGroupItemProps>(\n (\n {\n value,\n store: externalStore,\n disabled: itemDisabled,\n size = 'medium',\n state = 'default',\n className = '',\n id,\n ...props\n },\n ref\n ) => {\n // Get store and state\n const store = useRadioGroupStore(externalStore);\n const {\n value: groupValue,\n setValue,\n disabled: groupDisabled,\n name,\n } = useStore(store);\n\n // Generate unique ID if not provided\n const generatedId = useId();\n const inputId = id ?? `radio-item-${generatedId}`;\n\n // Determine states\n const isChecked = groupValue === value;\n const isDisabled = groupDisabled || itemDisabled;\n const currentState = isDisabled ? 'disabled' : state;\n\n // Use standard Radio component for consistency and simplicity\n return (\n <Radio\n ref={ref}\n id={inputId}\n name={name}\n value={value}\n checked={isChecked}\n disabled={isDisabled}\n size={size}\n state={currentState}\n className={className}\n onChange={(e) => {\n if (e.target.checked && !isDisabled) {\n setValue(value);\n }\n }}\n {...props}\n />\n );\n }\n);\n\nRadioGroupItem.displayName = 'RadioGroupItem';\n\nexport default Radio;\nexport { RadioGroup, RadioGroupItem };\n","import { ComponentPropsWithoutRef, ElementType, ReactNode } from 'react';\nimport { cn } from '../../utils/utils';\n\n/**\n * Base text component props\n */\ntype BaseTextProps = {\n /** Content to be displayed */\n children?: ReactNode;\n /** Text size variant */\n size?:\n | '2xs'\n | 'xs'\n | 'sm'\n | 'md'\n | 'lg'\n | 'xl'\n | '2xl'\n | '3xl'\n | '4xl'\n | '5xl'\n | '6xl';\n /** Font weight variant */\n weight?:\n | 'hairline'\n | 'light'\n | 'normal'\n | 'medium'\n | 'semibold'\n | 'bold'\n | 'extrabold'\n | 'black';\n /** Color variant - white for light backgrounds, black for dark backgrounds */\n color?: string;\n /** Additional CSS classes to apply */\n className?: string;\n};\n\n/**\n * Polymorphic text component props that ensures type safety based on the 'as' prop\n */\ntype TextProps<T extends ElementType = 'p'> = BaseTextProps & {\n /** HTML tag to render */\n as?: T;\n} & Omit<ComponentPropsWithoutRef<T>, keyof BaseTextProps>;\n\n/**\n * Text component for Analytica Ensino platforms\n *\n * A flexible polymorphic text component with multiple sizes, weights, and colors.\n * Automatically adapts to dark and light themes with full type safety.\n *\n * @param children - The content to display\n * @param size - The text size variant (2xs, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl)\n * @param weight - The font weight variant (hairline, light, normal, medium, semibold, bold, extrabold, black)\n * @param color - The color variant - adapts to theme\n * @param as - The HTML tag to render - determines allowed attributes via TypeScript\n * @param className - Additional CSS classes\n * @param props - HTML attributes valid for the chosen tag only\n * @returns A styled text element with type-safe attributes\n *\n * @example\n * ```tsx\n * <Text size=\"lg\" weight=\"bold\" color=\"text-info-800\">\n * This is a large, bold text\n * </Text>\n *\n * <Text as=\"a\" href=\"/link\" target=\"_blank\">\n * Link with type-safe anchor attributes\n * </Text>\n *\n * <Text as=\"button\" onClick={handleClick} disabled>\n * Button with type-safe button attributes\n * </Text>\n * ```\n */\nconst Text = <T extends ElementType = 'p'>({\n children,\n size = 'md',\n weight = 'normal',\n color = 'text-text-950',\n as,\n className = '',\n ...props\n}: TextProps<T>) => {\n let sizeClasses = '';\n let weightClasses = '';\n\n // Text size classes mapping\n const sizeClassMap = {\n '2xs': 'text-2xs',\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-md',\n lg: 'text-lg',\n xl: 'text-xl',\n '2xl': 'text-2xl',\n '3xl': 'text-3xl',\n '4xl': 'text-4xl',\n '5xl': 'text-5xl',\n '6xl': 'text-6xl',\n } as const;\n\n sizeClasses = sizeClassMap[size] ?? sizeClassMap.md;\n\n // Font weight classes mapping\n const weightClassMap = {\n hairline: 'font-hairline',\n light: 'font-light',\n normal: 'font-normal',\n medium: 'font-medium',\n semibold: 'font-semibold',\n bold: 'font-bold',\n extrabold: 'font-extrabold',\n black: 'font-black',\n } as const;\n\n weightClasses = weightClassMap[weight] ?? weightClassMap.normal;\n\n const baseClasses = 'font-primary';\n const Component = as ?? ('p' as ElementType);\n\n return (\n <Component\n className={cn(baseClasses, sizeClasses, weightClasses, color, className)}\n {...props}\n >\n {children}\n </Component>\n );\n};\n\nexport default Text;\n"],"mappings":"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