1414
1515import React , { type PropsWithChildren } from 'react' ;
1616import type { SelectInterface } from './form.d' ;
17+ import type { OptionType } from '~/utils/types' ;
1718
1819import { FormSelect } from './form-select' ;
1920import { checkIsComponentOfType } from '~/utils/component-type-checker' ;
2021
2122/**
22- * SelectGroup
23+ * collectSelectsInfo
2324 *
24- * Inspects children and deduplicates options across FormSelect children by cloning them .
25+ * Inspects children to collect FormSelect components and their options and values .
2526 *
26- * @param {object } props - component props
27- * @param {React.ReactNode } props.children - child nodes which should only include FormSelect components;
28- * SelectGroup will detect those and clone them with filtered options
27+ * @param {React.ReactNode } children - child nodes which may include FormSelect components
2928 *
30- * Behaviour notes:
31- * - Looks for direct children of type FormSelect.
32- * - Builds list of values used by other selects and removes them from each select's options to avoid duplicates.
33- * - Clones and returns modified select children; non-select children are not displayed so they shouldn't be used.
29+ * @returns {object } - object containing:
30+ * - selects: array of FormSelect components found among children
31+ * - selectsLen: number of FormSelect components found
32+ * - optionsList: array of options arrays for each FormSelect
33+ * - values: array of selected values for each FormSelect
3434 */
35- export function SelectGroup ( { children } : PropsWithChildren ) {
35+ function collectSelectsInfo ( children : React . ReactNode ) {
3636 const arrChildren = React . Children . toArray ( children ) ;
3737 const selects = arrChildren . filter ( ( component ) => checkIsComponentOfType ( component , FormSelect ) ) ;
3838 const optionsList = selects . map ( ( select ) => React . isValidElement ( select ) ? ( select . props as SelectInterface ) . options : null ) ;
3939 const values = selects . map ( ( select ) => React . isValidElement ( select ) ? ( select . props as SelectInterface ) . value : null ) ;
40+ const selectsLen = selects . length ;
41+
42+ return {
43+ selects,
44+ selectsLen,
45+ optionsList,
46+ values,
47+ } ;
48+ }
4049
50+ type valuesType = ( string | number | ( string | number ) [ ] | null ) [ ] ;
51+
52+ /**
53+ * FilterSelectedFromOptions
54+ *
55+ * Clones select components with filtered options to remove already selected values from other selects.
56+ *
57+ * @param {React.ReactNode[] } selects - array of select components
58+ * @param {number } selectsLen - length of selects array
59+ * @param {(OptionType[] | null)[] } optionsList - array of options arrays for each select
60+ * @param {valuesType } values - array of selected values for each select
61+ *
62+ * @returns {React.ReactNode[] } - array of cloned select components with filtered options
63+ */
64+ function filterSelectedFromOptions ( selects : React . ReactNode [ ] , selectsLen : number , optionsList : ( OptionType [ ] | null ) [ ] , values : valuesType ) {
4165 const returnChildren = [ ] ;
42- const noSelects = selects . length ;
4366
44- for ( let i = 0 ; i < noSelects ; i ++ ) {
67+ for ( let i = 0 ; i < selectsLen ; i ++ ) {
4568 let select = selects [ i ] ;
4669 let options = optionsList [ i ] ;
4770
71+ // Get all values selected in other selects
4872 const differentSelectValues = values . filter ( ( _ , idx ) => idx != i ) ;
4973
5074 if ( options !== null ) {
@@ -58,3 +82,22 @@ export function SelectGroup({ children }: PropsWithChildren) {
5882
5983 return [ ...returnChildren ] ;
6084}
85+
86+ /**
87+ * SelectGroup
88+ *
89+ * Inspects children and deduplicates options across FormSelect children by cloning them.
90+ *
91+ * @param {object } props - component props
92+ * @param {React.ReactNode } props.children - child nodes which should only include FormSelect components;
93+ * SelectGroup will detect those and clone them with filtered options
94+ *
95+ * Behaviour notes:
96+ * - Looks for direct children of type FormSelect.
97+ * - Builds list of values used by other selects and removes them from each select's options to avoid duplicates.
98+ * - Clones and returns modified select children; non-select children are not displayed so they shouldn't be used.
99+ */
100+ export function SelectGroup ( { children } : PropsWithChildren ) {
101+ const { selects, selectsLen, optionsList, values } = collectSelectsInfo ( children ) ;
102+ return filterSelectedFromOptions ( selects , selectsLen , optionsList , values ) ;
103+ }
0 commit comments