-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
useCard.ts
113 lines (98 loc) · 3.12 KB
/
useCard.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import * as React from 'react';
import { getIntrinsicElementProps, useMergedRefs, slot } from '@fluentui/react-utilities';
import { useFocusableGroup, useFocusWithin } from '@fluentui/react-tabster';
import type { CardProps, CardState } from './Card.types';
import { useCardSelectable } from './useCardSelectable';
import { cardContextDefaultValue } from './CardContext';
const focusMap = {
off: undefined,
'no-tab': 'limited-trap-focus',
'tab-exit': 'limited',
'tab-only': 'unlimited',
} as const;
/**
* Create the state for interactive cards.
*
* This internal hook defines if the card is interactive
* and control focus properties based on that.
*
* @param props - props from this instance of Card
*/
const useCardInteractive = ({ focusMode = 'off', ...props }: CardProps) => {
const interactive = (
[
'onClick',
'onDoubleClick',
'onMouseUp',
'onMouseDown',
'onPointerUp',
'onPointerDown',
'onTouchStart',
'onTouchEnd',
'onDragStart',
'onDragEnd',
] as (keyof React.HTMLAttributes<HTMLElement>)[]
).some(prop => props[prop]);
const groupperAttrs = useFocusableGroup({
tabBehavior: focusMap[interactive ? 'no-tab' : focusMode],
});
const interactiveFocusAttributes = {
...groupperAttrs,
tabIndex: 0,
};
return {
interactive,
focusAttributes: !interactive && focusMode === 'off' ? null : interactiveFocusAttributes,
};
};
/**
* Create the state required to render Card.
*
* The returned state can be modified with hooks such as useCardStyles_unstable,
* before being passed to renderCard_unstable.
*
* @param props - props from this instance of Card
* @param ref - reference to the root element of Card
*/
export const useCard_unstable = (props: CardProps, ref: React.Ref<HTMLDivElement>): CardState => {
const { appearance = 'filled', orientation = 'vertical', size = 'medium' } = props;
const [referenceId, setReferenceId] = React.useState(cardContextDefaultValue.selectableA11yProps.referenceId);
const [referenceLabel, setReferenceLabel] = React.useState(cardContextDefaultValue.selectableA11yProps.referenceId);
const cardBaseRef = useFocusWithin<HTMLDivElement>();
const { selectable, selected, selectableCardProps, selectFocused, checkboxSlot, floatingActionSlot } =
useCardSelectable(props, { referenceId, referenceLabel }, cardBaseRef);
const cardRef = useMergedRefs(cardBaseRef, ref);
const { interactive, focusAttributes } = useCardInteractive(props);
return {
appearance,
orientation,
size,
interactive,
selectable,
selectFocused,
selected,
selectableA11yProps: {
setReferenceId,
referenceId,
referenceLabel,
setReferenceLabel,
},
components: {
root: 'div',
floatingAction: 'div',
checkbox: 'input',
},
root: slot.always(
getIntrinsicElementProps('div', {
ref: cardRef,
role: 'group',
...(!selectable ? focusAttributes : null),
...props,
...selectableCardProps,
}),
{ elementType: 'div' },
),
floatingAction: floatingActionSlot,
checkbox: checkboxSlot,
};
};