kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
Remove AutosuggestTextarea
rodzic
9036d8a9a0
commit
ad329c33fa
|
@ -152,7 +152,6 @@
|
||||||
"react-sparklines": "^1.7.0",
|
"react-sparklines": "^1.7.0",
|
||||||
"react-sticky-box": "^2.0.0",
|
"react-sticky-box": "^2.0.0",
|
||||||
"react-swipeable-views": "^0.14.0",
|
"react-swipeable-views": "^0.14.0",
|
||||||
"react-textarea-autosize": "^8.3.4",
|
|
||||||
"react-virtuoso": "^4.3.11",
|
"react-virtuoso": "^4.3.11",
|
||||||
"redux": "^4.1.1",
|
"redux": "^4.1.1",
|
||||||
"redux-immutable": "^4.0.0",
|
"redux-immutable": "^4.0.0",
|
||||||
|
|
|
@ -1,288 +0,0 @@
|
||||||
import clsx from 'clsx';
|
|
||||||
import React from 'react';
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
import Textarea from 'react-textarea-autosize';
|
|
||||||
|
|
||||||
import { Portal } from 'soapbox/components/ui';
|
|
||||||
import AutosuggestAccount from 'soapbox/features/compose/components/autosuggest-account';
|
|
||||||
import { isRtl } from 'soapbox/utils/rtl';
|
|
||||||
import { textAtCursorMatchesToken } from 'soapbox/utils/suggestions';
|
|
||||||
|
|
||||||
import AutosuggestEmoji from './autosuggest-emoji';
|
|
||||||
|
|
||||||
import type { List as ImmutableList } from 'immutable';
|
|
||||||
import type { Emoji } from 'soapbox/features/emoji';
|
|
||||||
|
|
||||||
interface IAutosuggesteTextarea {
|
|
||||||
id?: string;
|
|
||||||
value: string;
|
|
||||||
suggestions: ImmutableList<string>;
|
|
||||||
disabled: boolean;
|
|
||||||
placeholder: string;
|
|
||||||
onSuggestionSelected: (tokenStart: number, token: string | null, value: string | undefined) => void;
|
|
||||||
onSuggestionsClearRequested: () => void;
|
|
||||||
onSuggestionsFetchRequested: (token: string | number) => void;
|
|
||||||
onChange: React.ChangeEventHandler<HTMLTextAreaElement>;
|
|
||||||
onKeyUp?: React.KeyboardEventHandler<HTMLTextAreaElement>;
|
|
||||||
onKeyDown?: React.KeyboardEventHandler<HTMLTextAreaElement>;
|
|
||||||
onPaste: (files: FileList) => void;
|
|
||||||
autoFocus: boolean;
|
|
||||||
onFocus: () => void;
|
|
||||||
onBlur?: () => void;
|
|
||||||
condensed?: boolean;
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
class AutosuggestTextarea extends ImmutablePureComponent<IAutosuggesteTextarea> {
|
|
||||||
|
|
||||||
textarea: HTMLTextAreaElement | null = null;
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
autoFocus: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
|
||||||
suggestionsHidden: true,
|
|
||||||
focused: false,
|
|
||||||
selectedSuggestion: 0,
|
|
||||||
lastToken: null,
|
|
||||||
tokenStart: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
onChange: React.ChangeEventHandler<HTMLTextAreaElement> = (e) => {
|
|
||||||
const [tokenStart, token] = textAtCursorMatchesToken(
|
|
||||||
e.target.value,
|
|
||||||
e.target.selectionStart,
|
|
||||||
['@', ':', '#'],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (token !== null && this.state.lastToken !== token) {
|
|
||||||
this.setState({ lastToken: token, selectedSuggestion: 0, tokenStart });
|
|
||||||
this.props.onSuggestionsFetchRequested(token);
|
|
||||||
} else if (token === null) {
|
|
||||||
this.setState({ lastToken: null });
|
|
||||||
this.props.onSuggestionsClearRequested();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.onChange(e);
|
|
||||||
};
|
|
||||||
|
|
||||||
onKeyDown: React.KeyboardEventHandler<HTMLTextAreaElement> = (e) => {
|
|
||||||
const { suggestions, disabled } = this.props;
|
|
||||||
const { selectedSuggestion, suggestionsHidden } = this.state;
|
|
||||||
|
|
||||||
if (disabled) {
|
|
||||||
e.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.which === 229 || (e as any).isComposing) {
|
|
||||||
// Ignore key events during text composition
|
|
||||||
// e.key may be a name of the physical key even in this case (e.x. Safari / Chrome on Mac)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (e.key) {
|
|
||||||
case 'Escape':
|
|
||||||
if (suggestions.size === 0 || suggestionsHidden) {
|
|
||||||
document.querySelector('.ui')?.parentElement?.focus();
|
|
||||||
} else {
|
|
||||||
e.preventDefault();
|
|
||||||
this.setState({ suggestionsHidden: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 'ArrowDown':
|
|
||||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 'ArrowUp':
|
|
||||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 'Enter':
|
|
||||||
case 'Tab':
|
|
||||||
// Select suggestion
|
|
||||||
if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.defaultPrevented || !this.props.onKeyDown) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.onKeyDown(e);
|
|
||||||
};
|
|
||||||
|
|
||||||
onBlur = () => {
|
|
||||||
this.setState({ suggestionsHidden: true, focused: false });
|
|
||||||
|
|
||||||
if (this.props.onBlur) {
|
|
||||||
this.props.onBlur();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onFocus = () => {
|
|
||||||
this.setState({ focused: true });
|
|
||||||
|
|
||||||
if (this.props.onFocus) {
|
|
||||||
this.props.onFocus();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onSuggestionClick: React.MouseEventHandler<HTMLDivElement> = (e) => {
|
|
||||||
const suggestion = this.props.suggestions.get(e.currentTarget.getAttribute('data-index') as any);
|
|
||||||
e.preventDefault();
|
|
||||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestion);
|
|
||||||
this.textarea?.focus();
|
|
||||||
};
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps: IAutosuggesteTextarea, nextState: any) {
|
|
||||||
// Skip updating when only the lastToken changes so the
|
|
||||||
// cursor doesn't jump around due to re-rendering unnecessarily
|
|
||||||
const lastTokenUpdated = this.state.lastToken !== nextState.lastToken;
|
|
||||||
const valueUpdated = this.props.value !== nextProps.value;
|
|
||||||
|
|
||||||
if (lastTokenUpdated && !valueUpdated) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// https://stackoverflow.com/a/35962835
|
|
||||||
return super.shouldComponentUpdate!.bind(this)(nextProps, nextState, undefined);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps: IAutosuggesteTextarea, prevState: any) {
|
|
||||||
const { suggestions } = this.props;
|
|
||||||
if (suggestions !== prevProps.suggestions && suggestions.size > 0 && prevState.suggestionsHidden && prevState.focused) {
|
|
||||||
this.setState({ suggestionsHidden: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setTextarea: React.Ref<HTMLTextAreaElement> = (c) => {
|
|
||||||
this.textarea = c;
|
|
||||||
};
|
|
||||||
|
|
||||||
onPaste: React.ClipboardEventHandler<HTMLTextAreaElement> = (e) => {
|
|
||||||
if (e.clipboardData && e.clipboardData.files.length === 1) {
|
|
||||||
this.props.onPaste(e.clipboardData.files);
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
renderSuggestion = (suggestion: string | Emoji, i: number) => {
|
|
||||||
const { selectedSuggestion } = this.state;
|
|
||||||
let inner, key;
|
|
||||||
|
|
||||||
if (typeof suggestion === 'object') {
|
|
||||||
inner = <AutosuggestEmoji emoji={suggestion} />;
|
|
||||||
key = suggestion.id;
|
|
||||||
} else if (suggestion[0] === '#') {
|
|
||||||
inner = suggestion;
|
|
||||||
key = suggestion;
|
|
||||||
} else {
|
|
||||||
inner = <AutosuggestAccount id={suggestion} />;
|
|
||||||
key = suggestion;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
role='button'
|
|
||||||
tabIndex={0}
|
|
||||||
key={key}
|
|
||||||
data-index={i}
|
|
||||||
className={clsx({
|
|
||||||
'px-4 py-2.5 text-sm text-gray-700 dark:text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800 focus:bg-gray-100 dark:focus:bg-primary-800 group': true,
|
|
||||||
'bg-gray-100 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-800': i === selectedSuggestion,
|
|
||||||
})}
|
|
||||||
onMouseDown={this.onSuggestionClick}
|
|
||||||
>
|
|
||||||
{inner}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
setPortalPosition() {
|
|
||||||
if (!this.textarea) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const { top, height, left, width } = this.textarea.getBoundingClientRect();
|
|
||||||
|
|
||||||
return {
|
|
||||||
top: top + height,
|
|
||||||
left,
|
|
||||||
width,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, children, condensed, id } = this.props;
|
|
||||||
const { suggestionsHidden } = this.state;
|
|
||||||
const style = { direction: 'ltr', minRows: 10 };
|
|
||||||
|
|
||||||
// TODO: convert to functional component and use `useLocale()` hook instead of checking placeholder text.
|
|
||||||
if (isRtl(value) || (!value && placeholder && isRtl(placeholder))) {
|
|
||||||
style.direction = 'rtl';
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
<div key='textarea'>
|
|
||||||
<div className='relative'>
|
|
||||||
<label>
|
|
||||||
<span style={{ display: 'none' }}>{placeholder}</span>
|
|
||||||
|
|
||||||
<Textarea
|
|
||||||
ref={this.setTextarea}
|
|
||||||
className={clsx('w-full resize-none border-0 px-0 text-gray-800 transition-[min-height] placeholder:text-gray-600 focus:border-0 focus:shadow-none focus:ring-0 motion-reduce:transition-none dark:bg-transparent dark:text-white dark:placeholder:text-gray-600', {
|
|
||||||
'min-h-[40px]': condensed,
|
|
||||||
'min-h-[100px]': !condensed,
|
|
||||||
})}
|
|
||||||
id={id}
|
|
||||||
disabled={disabled}
|
|
||||||
placeholder={placeholder}
|
|
||||||
autoFocus={autoFocus}
|
|
||||||
value={value}
|
|
||||||
onChange={this.onChange}
|
|
||||||
onKeyDown={this.onKeyDown}
|
|
||||||
onKeyUp={onKeyUp}
|
|
||||||
onFocus={this.onFocus}
|
|
||||||
onBlur={this.onBlur}
|
|
||||||
onPaste={this.onPaste}
|
|
||||||
style={style as any}
|
|
||||||
aria-autocomplete='list'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{children}
|
|
||||||
</div>,
|
|
||||||
|
|
||||||
<Portal key='portal'>
|
|
||||||
<div
|
|
||||||
style={this.setPortalPosition()}
|
|
||||||
className={clsx({
|
|
||||||
'fixed z-1000 shadow bg-white dark:bg-gray-900 rounded-lg py-1 space-y-0 dark:ring-2 dark:ring-primary-700 focus:outline-none': true,
|
|
||||||
hidden: suggestionsHidden || suggestions.isEmpty(),
|
|
||||||
block: !suggestionsHidden && !suggestions.isEmpty(),
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{suggestions.map(this.renderSuggestion)}
|
|
||||||
</div>
|
|
||||||
</Portal>,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AutosuggestTextarea;
|
|
|
@ -14,7 +14,6 @@ import {
|
||||||
uploadCompose,
|
uploadCompose,
|
||||||
} from 'soapbox/actions/compose';
|
} from 'soapbox/actions/compose';
|
||||||
import AutosuggestInput, { AutoSuggestion } from 'soapbox/components/autosuggest-input';
|
import AutosuggestInput, { AutoSuggestion } from 'soapbox/components/autosuggest-input';
|
||||||
import AutosuggestTextarea from 'soapbox/components/autosuggest-textarea';
|
|
||||||
import { Button, HStack, Stack } from 'soapbox/components/ui';
|
import { Button, HStack, Stack } from 'soapbox/components/ui';
|
||||||
import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container';
|
import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container';
|
||||||
import { ComposeEditor } from 'soapbox/features/ui/util/async-components';
|
import { ComposeEditor } from 'soapbox/features/ui/util/async-components';
|
||||||
|
@ -82,8 +81,6 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
spoiler,
|
spoiler,
|
||||||
spoiler_text: spoilerText,
|
spoiler_text: spoilerText,
|
||||||
privacy,
|
privacy,
|
||||||
focusDate,
|
|
||||||
caretPosition,
|
|
||||||
is_submitting: isSubmitting,
|
is_submitting: isSubmitting,
|
||||||
is_changing_upload:
|
is_changing_upload:
|
||||||
isChangingUpload,
|
isChangingUpload,
|
||||||
|
@ -104,7 +101,6 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
const firstRender = useRef(true);
|
const firstRender = useRef(true);
|
||||||
const formRef = useRef<HTMLDivElement>(null);
|
const formRef = useRef<HTMLDivElement>(null);
|
||||||
const spoilerTextRef = useRef<AutosuggestInput>(null);
|
const spoilerTextRef = useRef<AutosuggestInput>(null);
|
||||||
const autosuggestTextareaRef = useRef<AutosuggestTextarea>(null);
|
|
||||||
const editorRef = useRef<LexicalEditor>(null);
|
const editorRef = useRef<LexicalEditor>(null);
|
||||||
|
|
||||||
const { isDraggedOver } = useDraggedFiles(formRef);
|
const { isDraggedOver } = useDraggedFiles(formRef);
|
||||||
|
@ -172,11 +168,6 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
dispatch(selectComposeSuggestion(id, tokenStart, token, value, ['spoiler_text']));
|
dispatch(selectComposeSuggestion(id, tokenStart, token, value, ['spoiler_text']));
|
||||||
};
|
};
|
||||||
|
|
||||||
const setCursor = (start: number, end: number = start) => {
|
|
||||||
if (!autosuggestTextareaRef.current?.textarea) return;
|
|
||||||
autosuggestTextareaRef.current.textarea.setSelectionRange(start, end);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEmojiPick = (data: Emoji) => {
|
const handleEmojiPick = (data: Emoji) => {
|
||||||
const editor = editorRef.current;
|
const editor = editorRef.current;
|
||||||
if (!editor) return;
|
if (!editor) return;
|
||||||
|
@ -194,18 +185,9 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
spoilerTextRef.current?.input?.focus();
|
spoilerTextRef.current?.input?.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
const focusTextarea = () => {
|
|
||||||
autosuggestTextareaRef.current?.textarea?.focus();
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const length = text.length;
|
|
||||||
document.addEventListener('click', handleClick, true);
|
document.addEventListener('click', handleClick, true);
|
||||||
|
|
||||||
if (length > 0) {
|
|
||||||
setCursor(length); // Set cursor at end
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('click', handleClick, true);
|
document.removeEventListener('click', handleClick, true);
|
||||||
};
|
};
|
||||||
|
@ -213,21 +195,14 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (spoiler && firstRender.current) {
|
if (spoiler && firstRender.current) {
|
||||||
focusTextarea();
|
|
||||||
firstRender.current = false;
|
firstRender.current = false;
|
||||||
} else if (!spoiler && prevSpoiler) {
|
} else if (!spoiler && prevSpoiler) {
|
||||||
focusTextarea();
|
//
|
||||||
} else if (spoiler && !prevSpoiler) {
|
} else if (spoiler && !prevSpoiler) {
|
||||||
focusSpoilerInput();
|
focusSpoilerInput();
|
||||||
}
|
}
|
||||||
}, [spoiler]);
|
}, [spoiler]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (typeof caretPosition === 'number') {
|
|
||||||
setCursor(caretPosition);
|
|
||||||
}
|
|
||||||
}, [focusDate]);
|
|
||||||
|
|
||||||
const renderButtons = useCallback(() => (
|
const renderButtons = useCallback(() => (
|
||||||
<HStack alignItems='center' space={2}>
|
<HStack alignItems='center' space={2}>
|
||||||
{features.media && <UploadButtonContainer composeId={id} />}
|
{features.media && <UploadButtonContainer composeId={id} />}
|
||||||
|
|
28
yarn.lock
28
yarn.lock
|
@ -1051,7 +1051,7 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.12.0"
|
regenerator-runtime "^0.12.0"
|
||||||
|
|
||||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.2.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
|
"@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.2.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
|
||||||
version "7.22.15"
|
version "7.22.15"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8"
|
||||||
integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==
|
integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==
|
||||||
|
@ -7589,15 +7589,6 @@ react-swipeable-views@^0.14.0:
|
||||||
react-swipeable-views-utils "^0.14.0"
|
react-swipeable-views-utils "^0.14.0"
|
||||||
warning "^4.0.1"
|
warning "^4.0.1"
|
||||||
|
|
||||||
react-textarea-autosize@^8.3.4:
|
|
||||||
version "8.3.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.4.tgz#270a343de7ad350534141b02c9cb78903e553524"
|
|
||||||
integrity sha512-CdtmP8Dc19xL8/R6sWvtknD/eCXkQr30dtvC4VmGInhRsfF8X/ihXCq6+9l9qbxmKRiq407/7z5fxE7cVWQNgQ==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.10.2"
|
|
||||||
use-composed-ref "^1.3.0"
|
|
||||||
use-latest "^1.2.1"
|
|
||||||
|
|
||||||
react-transition-group@^2.2.1:
|
react-transition-group@^2.2.1:
|
||||||
version "2.9.0"
|
version "2.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
|
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
|
||||||
|
@ -8956,23 +8947,6 @@ url-parse@^1.5.3:
|
||||||
querystringify "^2.1.1"
|
querystringify "^2.1.1"
|
||||||
requires-port "^1.0.0"
|
requires-port "^1.0.0"
|
||||||
|
|
||||||
use-composed-ref@^1.3.0:
|
|
||||||
version "1.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.3.0.tgz#3d8104db34b7b264030a9d916c5e94fbe280dbda"
|
|
||||||
integrity sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==
|
|
||||||
|
|
||||||
use-isomorphic-layout-effect@^1.1.1:
|
|
||||||
version "1.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
|
|
||||||
integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
|
|
||||||
|
|
||||||
use-latest@^1.2.1:
|
|
||||||
version "1.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.2.1.tgz#d13dfb4b08c28e3e33991546a2cee53e14038cf2"
|
|
||||||
integrity sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==
|
|
||||||
dependencies:
|
|
||||||
use-isomorphic-layout-effect "^1.1.1"
|
|
||||||
|
|
||||||
use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0:
|
use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
|
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
|
||||||
|
|
Ładowanie…
Reference in New Issue