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

Function useTokenField

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

Source from the content-addressed store, hash-verified

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

Tested by

no test coverage detected