103 lines
4.0 KiB
Plaintext
103 lines
4.0 KiB
Plaintext
/*
|
|
* Copyright 2020 Adobe. All rights reserved.
|
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
* governing permissions and limitations under the License.
|
|
*/
|
|
|
|
import {AriaCheckboxGroupItemProps} from '@react-types/checkbox';
|
|
import {CheckboxAria, useCheckbox} from './useCheckbox';
|
|
import {checkboxGroupData} from './utils';
|
|
import {CheckboxGroupState} from '@react-stately/checkbox';
|
|
import {DEFAULT_VALIDATION_RESULT, privateValidationStateProp, useFormValidationState} from '@react-stately/form';
|
|
import {RefObject, ValidationResult} from '@react-types/shared';
|
|
import {useEffect, useRef} from 'react';
|
|
import {useToggleState} from '@react-stately/toggle';
|
|
|
|
/**
|
|
* Provides the behavior and accessibility implementation for a checkbox component contained within a checkbox group.
|
|
* Checkbox groups allow users to select multiple items from a list of options.
|
|
* @param props - Props for the checkbox.
|
|
* @param state - State for the checkbox, as returned by `useCheckboxGroupState`.
|
|
* @param inputRef - A ref for the HTML input element.
|
|
*/
|
|
export function useCheckboxGroupItem(props: AriaCheckboxGroupItemProps, state: CheckboxGroupState, inputRef: RefObject<HTMLInputElement | null>): CheckboxAria {
|
|
const toggleState = useToggleState({
|
|
isReadOnly: props.isReadOnly || state.isReadOnly,
|
|
isSelected: state.isSelected(props.value),
|
|
defaultSelected: state.defaultValue.includes(props.value),
|
|
onChange(isSelected) {
|
|
if (isSelected) {
|
|
state.addValue(props.value);
|
|
} else {
|
|
state.removeValue(props.value);
|
|
}
|
|
|
|
if (props.onChange) {
|
|
props.onChange(isSelected);
|
|
}
|
|
}
|
|
});
|
|
|
|
let {name, form, descriptionId, errorMessageId, validationBehavior} = checkboxGroupData.get(state)!;
|
|
validationBehavior = props.validationBehavior ?? validationBehavior;
|
|
|
|
// Local validation for this checkbox.
|
|
let {realtimeValidation} = useFormValidationState({
|
|
...props,
|
|
value: toggleState.isSelected,
|
|
// Server validation is handled at the group level.
|
|
name: undefined,
|
|
validationBehavior: 'aria'
|
|
});
|
|
|
|
// Update the checkbox group state when realtime validation changes.
|
|
let nativeValidation = useRef(DEFAULT_VALIDATION_RESULT);
|
|
let updateValidation = () => {
|
|
state.setInvalid(props.value, realtimeValidation.isInvalid ? realtimeValidation : nativeValidation.current);
|
|
};
|
|
|
|
useEffect(updateValidation);
|
|
|
|
// Combine group and checkbox level validation.
|
|
let combinedRealtimeValidation = state.realtimeValidation.isInvalid ? state.realtimeValidation : realtimeValidation;
|
|
let displayValidation = validationBehavior === 'native' ? state.displayValidation : combinedRealtimeValidation;
|
|
|
|
let res = useCheckbox({
|
|
...props,
|
|
isReadOnly: props.isReadOnly || state.isReadOnly,
|
|
isDisabled: props.isDisabled || state.isDisabled,
|
|
name: props.name || name,
|
|
form: props.form || form,
|
|
isRequired: props.isRequired ?? state.isRequired,
|
|
validationBehavior,
|
|
[privateValidationStateProp]: {
|
|
realtimeValidation: combinedRealtimeValidation,
|
|
displayValidation,
|
|
resetValidation: state.resetValidation,
|
|
commitValidation: state.commitValidation,
|
|
updateValidation(v: ValidationResult) {
|
|
nativeValidation.current = v;
|
|
updateValidation();
|
|
}
|
|
}
|
|
}, toggleState, inputRef);
|
|
|
|
return {
|
|
...res,
|
|
inputProps: {
|
|
...res.inputProps,
|
|
'aria-describedby': [
|
|
props['aria-describedby'],
|
|
state.isInvalid ? errorMessageId : null,
|
|
descriptionId
|
|
].filter(Boolean).join(' ') || undefined
|
|
}
|
|
};
|
|
}
|