Private
Public Access
1
0
Files

142 lines
4.4 KiB
JavaScript

'use client';
import * as React from 'react';
import { mergeCallbacks, slot, useControllableState } from '@fluentui/react-utilities';
import { Enter } from '@fluentui/keyboard-keys';
import { useFocusFinders } from '@fluentui/react-tabster';
/**
* Create the state related to selectable cards.
*
* This internal hook controls all the logic for selectable cards and is
* intended to be used alongside with useCard_unstable.
*
* @internal
* @param props - props from this instance of Card
* @param a11yProps - accessibility props shared between elements of the card
* @param cardRef - reference to the root element of Card
*/ export const useCardSelectable = (props, { referenceLabel, referenceId }, cardRef)=>{
const { checkbox = {}, onSelectionChange, floatingAction, onClick, onKeyDown, disabled } = props;
const { findAllFocusable } = useFocusFinders();
const checkboxRef = React.useRef(null);
const [selected, setSelected] = useControllableState({
state: props.selected,
defaultState: props.defaultSelected,
initialState: false
});
const selectable = [
props.selected,
props.defaultSelected,
onSelectionChange
].some((prop)=>typeof prop !== 'undefined');
const [selectFocused, setSelectFocused] = React.useState(false);
const shouldRestrictTriggerAction = React.useCallback((event)=>{
if (!cardRef.current) {
return false;
}
const focusableElements = findAllFocusable(cardRef.current);
const target = event.target;
const isElementInFocusableGroup = focusableElements.some((element)=>element.contains(target));
const isCheckboxSlot = (checkboxRef === null || checkboxRef === void 0 ? void 0 : checkboxRef.current) === target;
return isElementInFocusableGroup && !isCheckboxSlot;
}, [
cardRef,
findAllFocusable
]);
const onChangeHandler = React.useCallback((event)=>{
if (disabled || shouldRestrictTriggerAction(event)) {
return;
}
const newCheckedValue = !selected;
setSelected(newCheckedValue);
if (onSelectionChange) {
onSelectionChange(event, {
selected: newCheckedValue
});
}
}, [
disabled,
onSelectionChange,
selected,
setSelected,
shouldRestrictTriggerAction
]);
const onKeyDownHandler = React.useCallback((event)=>{
if ([
Enter
].includes(event.key)) {
event.preventDefault();
onChangeHandler(event);
}
}, [
onChangeHandler
]);
const checkboxSlot = React.useMemo(()=>{
if (!selectable || floatingAction) {
return;
}
const selectableCheckboxProps = {};
if (referenceId) {
selectableCheckboxProps['aria-labelledby'] = referenceId;
} else if (referenceLabel) {
selectableCheckboxProps['aria-label'] = referenceLabel;
}
return slot.optional(checkbox, {
defaultProps: {
ref: checkboxRef,
type: 'checkbox',
checked: selected,
disabled,
onChange: (event)=>onChangeHandler(event),
onFocus: ()=>setSelectFocused(true),
onBlur: ()=>setSelectFocused(false),
...selectableCheckboxProps
},
elementType: 'input'
});
}, [
checkbox,
disabled,
floatingAction,
selected,
selectable,
onChangeHandler,
referenceId,
referenceLabel
]);
const floatingActionSlot = React.useMemo(()=>{
if (!floatingAction) {
return;
}
return slot.optional(floatingAction, {
defaultProps: {
ref: checkboxRef
},
elementType: 'div'
});
}, [
floatingAction
]);
const selectableCardProps = React.useMemo(()=>{
if (!selectable) {
return null;
}
return {
onClick: mergeCallbacks(onClick, onChangeHandler),
onKeyDown: mergeCallbacks(onKeyDown, onKeyDownHandler)
};
}, [
selectable,
onChangeHandler,
onClick,
onKeyDown,
onKeyDownHandler
]);
return {
selected,
selectable,
selectFocused,
selectableCardProps,
checkboxSlot,
floatingActionSlot
};
};