MCPcopy Create free account
hub / github.com/adobe/react-spectrum / useTokenField

Function useTokenField

packages/react-aria/src/tokenfield/useTokenField.ts:99–595  ·  view source on GitHub ↗
(
  props: AriaTokenFieldProps<T>,
  state: TokenFieldState,
  ref: RefObject<HTMLDivElement | null>
)

Source from the content-addressed store, hash-verified

97 * @param state - State for the token field, as returned by `useTokenFieldState`.
98 */
99export function useTokenField<T extends TokenFieldValue = TokenFieldValue>(
100 props: AriaTokenFieldProps<T>,
101 state: TokenFieldState,
102 ref: RefObject<HTMLDivElement | null>
103): TokenFieldAria {
104 let {
105 role = 'textbox',
106 allowsNewlines: multiline = false,
107 isReadOnly = false,
108 isDisabled = false,
109 'aria-details': ariaDetails
110 } = props;
111
112 let {value} = state;
113 let {locale} = useLocale();
114 let graphemeSegmenter = useMemo(
115 () => new Intl.Segmenter(locale, {granularity: 'grapheme'}),
116 [locale]
117 );
118 let wordSegmenter = useMemo(() => new Intl.Segmenter(locale, {granularity: 'word'}), [locale]);
119
120 let dropPosition = useRef<Position | null>(null);
121 let transferredData = useRef<TokenFieldSegment[] | null>(null);
122
123 let nextValue = useRef<TokenFieldValue | null>(null);
124 let apply = (fn: (value: TokenFieldValue) => TokenFieldValue) => {
125 state.setValue(value => {
126 let newValue = fn(value);
127 nextValue.current = newValue;
128 return newValue;
129 });
130 };
131
132 // Composition events are not cancelable. The browser will mutate the DOM, making it out of sync with React.
133 // To account for this, we prevent React from re-rendering during composition, and track DOM mutations performed
134 // by the browser. When composition ends, we revert the DOM to its original state, and re-render with React.
135 // Mutating the DOM in any way during composition breaks the IME, causing composition to end unexpectedly.
136 // During composition, we still emit updates via onChange to ensure that things like autocomplete work,
137 // but we don't actually re-render to the DOM unless the value changes from what we expect (e.g. inserting a completion).
138 let mutationTracker = useMutationTracker(ref);
139 let startComposition = useCallback(() => {
140 mutationTracker.start();
141 state.setComposing(true);
142 }, [state, mutationTracker]);
143 let stopComposition = useCallback(() => {
144 mutationTracker.stop();
145 state.setComposing(false);
146 }, [state, mutationTracker]);
147
148 useEvent(ref, 'compositionstart', () => {
149 startComposition();
150
151 let range = window.getSelection()?.getRangeAt(0);
152 if (range) {
153 let [start, end] = rangeToPositions(ref.current!, range);
154
155 // Normalize the range to ensure it is not inside a token, otherwise the browser
156 // will attempt to insert the composed text into the token instead of replacing it.

Callers 1

TokenField.tsxFile · 0.90

Calls 15

useLocaleFunction · 0.90
useEventFunction · 0.90
getActiveElementFunction · 0.90
getOwnerDocumentFunction · 0.90
announceFunction · 0.90
useKeyboardFunction · 0.90
useFocusableFunction · 0.90
useFieldFunction · 0.90
setInteractionModalityFunction · 0.90
mergePropsFunction · 0.90
useMutationTrackerFunction · 0.85
rangeToPositionsFunction · 0.85

Tested by

no test coverage detected