mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-03-04 02:20:19 +01:00
Make accordion hook (#4464)
# Description of Changes Make accordion hook, which controls step collapsed state, enforcing only one step being open at any time
This commit is contained in:
123
frontend/src/hooks/tools/shared/useAccordionSteps.ts
Normal file
123
frontend/src/hooks/tools/shared/useAccordionSteps.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import { useState, useCallback, useMemo, useEffect } from 'react';
|
||||
|
||||
/**
|
||||
* State conditions that affect accordion behavior
|
||||
*/
|
||||
export interface AccordionStateConditions {
|
||||
/** Whether files are present (steps collapse when false) */
|
||||
hasFiles?: boolean;
|
||||
/** Whether results are available (steps collapse when true) */
|
||||
hasResults?: boolean;
|
||||
/** Whether the accordion is disabled (steps collapse when true) */
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for the useAccordionSteps hook
|
||||
*/
|
||||
export interface UseAccordionStepsConfig<T extends string | number | symbol> {
|
||||
/** Special step that represents "no step open" state */
|
||||
noneValue: T;
|
||||
/** Initial step to open */
|
||||
initialStep: T;
|
||||
/** Current state conditions that affect accordion behavior */
|
||||
stateConditions?: AccordionStateConditions;
|
||||
/** Callback to run when interacting with a step when we have results (usually used for resetting params) */
|
||||
afterResults?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return type for the useAccordionSteps hook
|
||||
*/
|
||||
export interface AccordionStepsAPI<T extends string | number | symbol> {
|
||||
/** Currently active/open step (noneValue if no step is open) */
|
||||
currentStep: T;
|
||||
/** Get whether a specific step should be collapsed */
|
||||
getCollapsedState: (step: T) => boolean;
|
||||
/** Toggle a step open/closed (accordion behavior - only one open at a time) */
|
||||
handleStepToggle: (step: T) => void;
|
||||
/** Set the currently open step */
|
||||
setOpenStep: (step: T) => void;
|
||||
/** Close all steps */
|
||||
closeAllSteps: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accordion-style step management hook.
|
||||
*
|
||||
* Provides sophisticated accordion behavior where only one step can be open at a time,
|
||||
* with configurable collapse conditions.
|
||||
*/
|
||||
export function useAccordionSteps<T extends string | number | symbol>(
|
||||
config: UseAccordionStepsConfig<T>
|
||||
): AccordionStepsAPI<T> {
|
||||
const { initialStep, stateConditions, noneValue } = config;
|
||||
|
||||
const [openStep, setOpenStep] = useState<T>(initialStep);
|
||||
|
||||
// Determine if all steps should be collapsed based on conditions
|
||||
const shouldCollapseAll = useMemo(() => {
|
||||
if (!stateConditions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
(stateConditions.hasFiles === false) ||
|
||||
(stateConditions.hasResults === true) ||
|
||||
(stateConditions.disabled === true)
|
||||
);
|
||||
}, [stateConditions]);
|
||||
|
||||
// Get collapsed state for a specific step
|
||||
const getCollapsedState = useCallback((step: T): boolean => {
|
||||
if (shouldCollapseAll) {
|
||||
return true;
|
||||
} else {
|
||||
return openStep !== step;
|
||||
}
|
||||
}, [openStep, shouldCollapseAll]);
|
||||
|
||||
// Handle step toggle with accordion behavior
|
||||
const handleStepToggle = useCallback((step: T) => {
|
||||
if (stateConditions?.hasResults) {
|
||||
config.afterResults?.();
|
||||
}
|
||||
|
||||
// If all steps should be collapsed, don't allow opening
|
||||
if (shouldCollapseAll) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Accordion behavior: if clicking the open step, close it; otherwise open the clicked step
|
||||
setOpenStep(currentStep => {
|
||||
if (currentStep === step) {
|
||||
// Clicking the open step - close it
|
||||
return noneValue;
|
||||
} else {
|
||||
// Open the clicked step
|
||||
return step;
|
||||
}
|
||||
});
|
||||
}, [shouldCollapseAll, noneValue, stateConditions?.hasResults, config.afterResults]);
|
||||
|
||||
// Close all steps
|
||||
const closeAllSteps = useCallback(() => {
|
||||
setOpenStep(noneValue);
|
||||
}, [noneValue]);
|
||||
|
||||
// Automatically reset to first step if we have results
|
||||
// Note that everything is still collapsed when this happens, it's just preparing for re-running the tool
|
||||
useEffect(() => {
|
||||
if (stateConditions?.hasResults) {
|
||||
setOpenStep(initialStep);
|
||||
}
|
||||
}, [stateConditions?.hasResults, initialStep]);
|
||||
|
||||
return {
|
||||
currentStep: shouldCollapseAll ? noneValue : openStep,
|
||||
getCollapsedState,
|
||||
handleStepToggle,
|
||||
setOpenStep,
|
||||
closeAllSteps
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user