analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
1 lines • 10.4 kB
Source Map (JSON)
{"version":3,"sources":["../src/components/Accordation/AccordionGroup.tsx"],"sourcesContent":["import {\n Children,\n cloneElement,\n forwardRef,\n HTMLAttributes,\n isValidElement,\n ReactElement,\n ReactNode,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { create, StoreApi } from 'zustand';\nimport { CardAccordationProps } from './Accordation';\n\ninterface AccordionGroupStore {\n type: 'single' | 'multiple';\n value: string | string[];\n collapsible: boolean;\n setValue: (value: string | string[]) => void;\n isItemExpanded: (itemValue: string) => boolean;\n}\n\ntype AccordionGroupStoreApi = StoreApi<AccordionGroupStore>;\n\nfunction createAccordionGroupStore(\n type: 'single' | 'multiple',\n initialValue: string | string[],\n collapsible: boolean\n): AccordionGroupStoreApi {\n return create<AccordionGroupStore>((set, get) => ({\n type,\n value: initialValue,\n collapsible,\n setValue: (value) => set({ value }),\n isItemExpanded: (itemValue: string): boolean => {\n const state = get();\n if (state.type === 'single') {\n return state.value === itemValue;\n } else {\n return Array.isArray(state.value) && state.value.includes(itemValue);\n }\n },\n }));\n}\n\ninterface AccordionGroupProps extends HTMLAttributes<HTMLDivElement> {\n type?: 'single' | 'multiple';\n defaultValue?: string | string[];\n value?: string | string[];\n onValueChange?: (value: string | string[]) => void;\n collapsible?: boolean;\n children: ReactNode;\n}\n\n// Helper function to inject store only to CardAccordation components\nconst injectStore = (\n children: ReactNode,\n store: AccordionGroupStoreApi,\n indexRef: { current: number },\n onItemToggle: (itemValue: string, isExpanded: boolean) => void\n): ReactNode => {\n return Children.map(children, (child) => {\n if (!isValidElement(child)) {\n return child;\n }\n\n const typedChild = child as ReactElement<\n CardAccordationProps & {\n children?: ReactNode;\n }\n >;\n\n // Check component displayName\n const displayName = (typedChild.type as unknown as { displayName?: string })\n ?.displayName;\n\n // Stop recursion at nested AccordionGroup - it manages its own children\n if (displayName === 'AccordionGroup') {\n return child;\n }\n\n let newProps: Partial<{\n children: ReactNode;\n value: string;\n expanded: boolean;\n onToggleExpanded: (isExpanded: boolean) => void;\n }> = {};\n\n if (displayName === 'CardAccordation') {\n // Generate value if not provided\n const itemValue =\n typedChild.props.value || `accordion-item-${indexRef.current++}`;\n\n // Get expanded state from store\n const storeState = store.getState();\n const expanded = storeState.isItemExpanded(itemValue);\n\n newProps.value = itemValue;\n newProps.expanded = expanded;\n newProps.onToggleExpanded = (isExpanded: boolean) => {\n onItemToggle(itemValue, isExpanded);\n typedChild.props.onToggleExpanded?.(isExpanded);\n };\n }\n\n // Recursively process children\n if (typedChild.props.children) {\n const processedChildren = injectStore(\n typedChild.props.children,\n store,\n indexRef,\n onItemToggle\n );\n\n // If it's a CardAccordation, add children to newProps\n if (displayName === 'CardAccordation') {\n newProps.children = processedChildren;\n } else if (processedChildren !== typedChild.props.children) {\n // For other elements, only clone if children changed\n return cloneElement(typedChild, { children: processedChildren });\n }\n }\n\n // Only clone if we have props to inject (only for CardAccordation)\n if (Object.keys(newProps).length > 0) {\n return cloneElement(typedChild, newProps);\n }\n\n return child;\n });\n};\n\nconst AccordionGroup = forwardRef<HTMLDivElement, AccordionGroupProps>(\n (\n {\n type = 'single',\n defaultValue,\n value: controlledValue,\n onValueChange,\n collapsible = true,\n children,\n className,\n ...props\n },\n ref\n ) => {\n const [internalValue, setInternalValue] = useState<string | string[]>(\n defaultValue || (type === 'single' ? '' : [])\n );\n\n const isControlled = controlledValue !== undefined;\n const currentValue = isControlled ? controlledValue : internalValue;\n\n // Create store only once using useRef\n const storeRef = useRef<AccordionGroupStoreApi | null>(null);\n if (storeRef.current) {\n // Update store configuration when props change\n storeRef.current.setState((prev) => {\n const nextState: Partial<AccordionGroupStore> = {};\n if (prev.type !== type) {\n nextState.type = type;\n }\n if (prev.collapsible !== collapsible) {\n nextState.collapsible = collapsible;\n }\n return nextState;\n });\n } else {\n // Create store on first render\n storeRef.current = createAccordionGroupStore(\n type,\n currentValue,\n collapsible\n );\n }\n const store = storeRef.current;\n\n // Sync store value when currentValue changes\n useEffect(() => {\n store.setState({ value: currentValue });\n }, [currentValue, store]);\n\n // Normalize internal value when type changes (uncontrolled mode)\n useEffect(() => {\n if (!isControlled) {\n setInternalValue((prev) => {\n if (type === 'single') {\n if (Array.isArray(prev)) {\n return prev[0] ?? '';\n }\n return typeof prev === 'string' ? prev : '';\n }\n if (Array.isArray(prev)) {\n return prev;\n }\n return prev ? [prev] : [];\n });\n }\n }, [isControlled, type]);\n\n const handleItemToggle = (itemValue: string, isExpanded: boolean) => {\n const storeState = store.getState();\n let newValue: string | string[];\n\n if (type === 'single') {\n // Single mode: only one item can be open at a time\n if (isExpanded) {\n newValue = itemValue;\n } else {\n // If collapsible, allow closing the current item\n newValue = collapsible ? '' : (storeState.value as string);\n }\n } else {\n // Multiple mode: multiple items can be open\n const currentArray = Array.isArray(storeState.value)\n ? storeState.value\n : [];\n\n if (isExpanded) {\n newValue = [...currentArray, itemValue];\n } else {\n newValue = currentArray.filter((v) => v !== itemValue);\n }\n }\n\n if (!isControlled) {\n setInternalValue(newValue);\n }\n store.setState({ value: newValue });\n onValueChange?.(newValue);\n };\n\n // Use ref to track index across recursive calls\n const indexRef = { current: 0 };\n const enhancedChildren = injectStore(\n children,\n store,\n indexRef,\n handleItemToggle\n );\n\n return (\n <div ref={ref} className={className} {...props}>\n {enhancedChildren}\n </div>\n );\n }\n);\n\nAccordionGroup.displayName = 'AccordionGroup';\n\nexport { AccordionGroup };\n"],"mappings":"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","names":[]}