Skip to content

Commit bf6e3e6

Browse files
committed
feat(react-tag-picker-preview): adds disabled state
1 parent aa9a77c commit bf6e3e6

File tree

10 files changed

+95
-33
lines changed

10 files changed

+95
-33
lines changed

packages/react-components/react-tag-picker-preview/etc/react-tag-picker-preview.api.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ export type TagPickerInputSlots = {
141141
} & Pick<ComboboxSlots, 'expandIcon'>;
142142

143143
// @public
144-
export type TagPickerInputState = ComponentState<TagPickerInputSlots> & Pick<TagPickerContextValue, 'size'>;
144+
export type TagPickerInputState = ComponentState<TagPickerInputSlots> & Pick<TagPickerContextValue, 'size' | 'disabled'>;
145145

146146
// @public
147147
export const TagPickerList: ForwardRefComponent<TagPickerListProps>;
@@ -183,15 +183,15 @@ export type TagPickerOptionSlots = Omit<OptionSlots, 'checkIcon'> & {
183183
export type TagPickerOptionState = ComponentState<TagPickerOptionSlots> & Omit<OptionState, 'checkIcon'>;
184184

185185
// @public
186-
export type TagPickerProps = ComponentProps<TagPickerSlots> & Pick<ComboboxProps, 'onOptionSelect' | 'positioning'> & Pick<Partial<TagPickerContextValue>, 'size' | 'selectedOptions' | 'appearance'> & {
186+
export type TagPickerProps = ComponentProps<TagPickerSlots> & Pick<ComboboxProps, 'onOptionSelect' | 'positioning' | 'disabled'> & Pick<Partial<TagPickerContextValue>, 'size' | 'selectedOptions' | 'appearance'> & {
187187
children: [JSX.Element, JSX.Element] | JSX.Element;
188188
};
189189

190190
// @public (undocumented)
191191
export type TagPickerSlots = {};
192192

193193
// @public
194-
export type TagPickerState = ComponentState<TagPickerSlots> & Omit<ComboboxState, 'listbox' | 'root' | 'input' | 'expandIcon' | 'clearIcon' | 'components' | 'size'> & Pick<TagPickerContextValue, 'triggerRef' | 'popoverId' | 'popoverRef' | 'targetRef' | 'size'> & {
194+
export type TagPickerState = ComponentState<TagPickerSlots> & Omit<ComboboxState, 'listbox' | 'root' | 'input' | 'expandIcon' | 'clearIcon' | 'components' | 'size'> & Pick<TagPickerContextValue, 'triggerRef' | 'popoverId' | 'popoverRef' | 'targetRef' | 'size' | 'disabled'> & {
195195
positioning?: PositioningShorthand;
196196
trigger: React_2.ReactNode;
197197
popover?: React_2.ReactNode;

packages/react-components/react-tag-picker-preview/src/components/TagPicker/TagPicker.types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export type TagPickerSize = 'medium' | 'large' | 'extra-large';
1313
* Picker Props
1414
*/
1515
export type TagPickerProps = ComponentProps<TagPickerSlots> &
16-
Pick<ComboboxProps, 'onOptionSelect' | 'positioning'> &
16+
Pick<ComboboxProps, 'onOptionSelect' | 'positioning' | 'disabled'> &
1717
Pick<Partial<TagPickerContextValue>, 'size' | 'selectedOptions' | 'appearance'> & {
1818
/**
1919
* Can contain two children including a trigger and a popover
@@ -27,7 +27,7 @@ export type TagPickerProps = ComponentProps<TagPickerSlots> &
2727
*/
2828
export type TagPickerState = ComponentState<TagPickerSlots> &
2929
Omit<ComboboxState, 'listbox' | 'root' | 'input' | 'expandIcon' | 'clearIcon' | 'components' | 'size'> &
30-
Pick<TagPickerContextValue, 'triggerRef' | 'popoverId' | 'popoverRef' | 'targetRef' | 'size'> & {
30+
Pick<TagPickerContextValue, 'triggerRef' | 'popoverId' | 'popoverRef' | 'targetRef' | 'size' | 'disabled'> & {
3131
/**
3232
* Configures the positioned menu
3333
*/

packages/react-components/react-tag-picker-preview/src/components/TagPicker/useTagPicker.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { useComboboxBaseState } from '../../utils/useComboboxBaseState';
1717
export const useTagPicker_unstable = (props: TagPickerProps): TagPickerState => {
1818
const popoverId = useId('picker-listbox');
1919
const triggerInnerRef = React.useRef<HTMLInputElement>(null);
20-
const { positioning, size = 'medium' } = props;
20+
const { positioning, size = 'medium', disabled = false } = props;
2121

2222
// Set a default set of fallback positions to try if the dropdown does not fit on screen
2323
const fallbackPositions: PositioningShorthandValue[] = ['above', 'after', 'after-top', 'before', 'before-top'];
@@ -47,9 +47,16 @@ export const useTagPicker_unstable = (props: TagPickerProps): TagPickerState =>
4747
size: 'medium',
4848
});
4949
const onOptionClickBase = state.onOptionClick;
50-
state.onOptionClick = useEventCallback(e => {
51-
onOptionClickBase(e);
52-
state.setOpen(e, false);
50+
state.onOptionClick = useEventCallback(event => {
51+
onOptionClickBase(event);
52+
state.setOpen(event, false);
53+
});
54+
const setOpenBase = state.setOpen;
55+
state.setOpen = useEventCallback((event, newValue) => {
56+
if (disabled) {
57+
return;
58+
}
59+
setOpenBase(event, newValue);
5360
});
5461

5562
const children = React.Children.toArray(props.children) as React.ReactElement[];
@@ -81,6 +88,7 @@ export const useTagPicker_unstable = (props: TagPickerProps): TagPickerState =>
8188
trigger,
8289
popover: state.open || state.hasFocus ? popover : undefined,
8390
popoverId,
91+
disabled,
8492
triggerRef: useMergedRefs(triggerInnerRef, activeParentRef),
8593
popoverRef: useMergedRefs(listboxRef, containerRef),
8694
targetRef,

packages/react-components/react-tag-picker-preview/src/components/TagPicker/useTagPickerContextValues.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export function useTagPickerContextValues(state: TagPickerState): TagPickerConte
2727
getOptionById,
2828
open,
2929
popoverId,
30+
disabled,
3031
} = state;
3132
return {
3233
activeDescendant: React.useMemo(
@@ -60,6 +61,7 @@ export function useTagPickerContextValues(state: TagPickerState): TagPickerConte
6061
getOptionById,
6162
open,
6263
popoverId,
64+
disabled,
6365
},
6466
};
6567
}

packages/react-components/react-tag-picker-preview/src/components/TagPickerInput/TagPickerInput.types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ export type TagPickerInputProps = Omit<
2222
/**
2323
* State used in rendering TagPickerInput
2424
*/
25-
export type TagPickerInputState = ComponentState<TagPickerInputSlots> & Pick<TagPickerContextValue, 'size'>;
25+
export type TagPickerInputState = ComponentState<TagPickerInputSlots> &
26+
Pick<TagPickerContextValue, 'size' | 'disabled'>;

packages/react-components/react-tag-picker-preview/src/components/TagPickerInput/useTagPickerInput.tsx

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,7 @@ import type { TagPickerInputProps, TagPickerInputState } from './TagPickerInput.
44
import { ChevronDownRegular as ChevronDownIcon } from '@fluentui/react-icons';
55
import { useActiveDescendantContext } from '@fluentui/react-aria';
66
import { useTagPickerContext_unstable } from '../../contexts/TagPickerContext';
7-
import {
8-
slot,
9-
useMergedRefs,
10-
getIntrinsicElementProps,
11-
useEventCallback,
12-
mergeCallbacks,
13-
} from '@fluentui/react-utilities';
7+
import { slot, useMergedRefs, getIntrinsicElementProps, useEventCallback } from '@fluentui/react-utilities';
148
import { useInputTriggerSlot } from '../../utils/useInputTriggerSlot';
159
import { Backspace, Enter } from '@fluentui/keyboard-keys';
1610

@@ -29,6 +23,7 @@ export const useTagPickerInput_unstable = (
2923
): TagPickerInputState => {
3024
const { controller: activeDescendantController } = useActiveDescendantContext();
3125
const size = useTagPickerContext_unstable(ctx => ctx.size);
26+
const contextDisabled = useTagPickerContext_unstable(ctx => ctx.disabled);
3227
const {
3328
triggerRef,
3429
clearSelection,
@@ -44,7 +39,7 @@ export const useTagPickerInput_unstable = (
4439
value: contextValue,
4540
} = usePickerContext();
4641

47-
const { value = contextValue, disabled } = props;
42+
const { value = contextValue, disabled = contextDisabled } = props;
4843

4944
const root = useInputTriggerSlot(
5045
{
@@ -108,22 +103,10 @@ export const useTagPickerInput_unstable = (
108103
},
109104
elementType: 'span',
110105
}),
106+
disabled,
111107
size,
112108
};
113109

114-
/* handle open/close + focus change when clicking expandIcon */
115-
const { onMouseDown: onIconMouseDown } = state.expandIcon || {};
116-
117-
const onExpandIconMouseDown = useEventCallback(
118-
mergeCallbacks(onIconMouseDown, (event: React.MouseEvent<HTMLSpanElement>) => {
119-
event.preventDefault();
120-
}),
121-
);
122-
123-
if (state.expandIcon) {
124-
state.expandIcon.onMouseDown = onExpandIconMouseDown;
125-
}
126-
127110
return state;
128111
};
129112

packages/react-components/react-tag-picker-preview/src/components/TagPickerInput/useTagPickerInputStyles.styles.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export const useTagPickerInputStyles_unstable = (state: TagPickerInputState): Ta
121121
tagPickerInputClassNames.root,
122122
styles.root,
123123
styles[state.size],
124-
// state.disabled && styles.disabled,
124+
state.disabled && styles.disabled,
125125
state.root.className,
126126
);
127127

@@ -130,7 +130,7 @@ export const useTagPickerInputStyles_unstable = (state: TagPickerInputState): Ta
130130
tagPickerInputClassNames.expandIcon,
131131
iconStyles.icon,
132132
iconStyles[state.size],
133-
// state.disabled && iconStyles.disabled,
133+
state.disabled && iconStyles.disabled,
134134
// state.showClearIcon && iconStyles.visuallyHidden,
135135
state.expandIcon.className,
136136
);

packages/react-components/react-tag-picker-preview/src/contexts/TagPickerContext.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface TagPickerContextValue
2424
popoverId: string;
2525
targetRef: React.RefObject<HTMLElement>;
2626
size: TagPickerSize;
27+
disabled: boolean;
2728
}
2829

2930
/**
@@ -46,6 +47,7 @@ export const tagPickerContextDefaultValue: TagPickerContextValue = {
4647
popoverId: '',
4748
size: 'medium',
4849
appearance: 'outline',
50+
disabled: false,
4951
};
5052

5153
const TagPickerContext = createContext<TagPickerContextValue | undefined>(undefined);
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import * as React from 'react';
2+
import {
3+
TagPicker,
4+
TagPickerList,
5+
TagPickerInput,
6+
TagPickerControl,
7+
TagPickerProps,
8+
TagPickerOption,
9+
TagPickerGroup,
10+
} from '@fluentui/react-tag-picker-preview';
11+
import { Tag, Avatar } from '@fluentui/react-components';
12+
13+
const options = [
14+
'John Doe',
15+
'Jane Doe',
16+
'Max Mustermann',
17+
'Erika Mustermann',
18+
'Pierre Dupont',
19+
'Amelie Dupont',
20+
'Mario Rossi',
21+
'Maria Rossi',
22+
];
23+
24+
export const Disabled = () => {
25+
const [selectedOptions, setSelectedOptions] = React.useState<string[]>([
26+
options[0],
27+
options[1],
28+
options[2],
29+
options[3],
30+
]);
31+
const onOptionSelect: TagPickerProps['onOptionSelect'] = (e, data) => {
32+
setSelectedOptions(data.selectedOptions);
33+
};
34+
35+
return (
36+
<div style={{ maxWidth: 400 }}>
37+
<TagPicker disabled onOptionSelect={onOptionSelect} selectedOptions={selectedOptions}>
38+
<TagPickerControl>
39+
<TagPickerGroup>
40+
{selectedOptions.map(option => (
41+
<Tag key={option} shape="rounded" media={<Avatar name={option} color="colorful" />} value={option}>
42+
{option}
43+
</Tag>
44+
))}
45+
</TagPickerGroup>
46+
<TagPickerInput />
47+
</TagPickerControl>
48+
<TagPickerList>
49+
{options
50+
.filter(option => !selectedOptions.includes(option))
51+
.map(option => (
52+
<TagPickerOption
53+
secondaryContent="Microsoft FTE"
54+
media={<Avatar name={option} color="colorful" />}
55+
value={option}
56+
key={option}
57+
>
58+
{option}
59+
</TagPickerOption>
60+
))}
61+
</TagPickerList>
62+
</TagPicker>
63+
</div>
64+
);
65+
};

packages/react-components/react-tag-picker-preview/stories/TagPicker/index.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export { Button } from './TagPickerButton.stories';
88
export { Filtering } from './TagPickerFiltering.stories';
99
export { Size } from './TagPickerSize.stories';
1010
export { Appearance } from './TagPickerAppearance.stories';
11+
export { Disabled } from './TagPickerDisabled.stories';
1112

1213
export default {
1314
title: 'Preview Components/Tag Picker',

0 commit comments

Comments
 (0)