Skip to content

Commit

Permalink
feat(Textarea): add feature flag textareaUseSafari17Workaround (#3352)
Browse files Browse the repository at this point in the history
  • Loading branch information
lossir authored Jan 25, 2024
1 parent f9ba1bc commit e40c88b
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 10 deletions.
37 changes: 27 additions & 10 deletions packages/react-ui/components/Textarea/Textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,23 @@ import { ThemeContext } from '../../lib/theming/ThemeContext';
import { Theme } from '../../lib/theming/Theme';
import { RenderLayer } from '../../internal/RenderLayer';
import { ResizeDetector } from '../../internal/ResizeDetector';
import { isIE11 } from '../../lib/client';
import { isIE11, isSafari17 } from '../../lib/client';
import { CommonProps, CommonWrapper, CommonWrapperRestProps } from '../../internal/CommonWrapper';
import { isTestEnv } from '../../lib/currentEnvironment';
import { cx } from '../../lib/theming/Emotion';
import { rootNode, TSetRootNode } from '../../lib/rootNode';
import { createPropsGetter } from '../../lib/createPropsGetter';
import { SizeProp } from '../../lib/types/props';
import {
getFullReactUIFlagsContext,
ReactUIFeatureFlags,
ReactUIFeatureFlagsContext,
} from '../../lib/featureFlagsContext';

import { getTextAreaHeight } from './TextareaHelpers';
import { styles } from './Textarea.styles';
import { TextareaCounter, TextareaCounterRef } from './TextareaCounter';
import { TextareaWithSafari17Workaround } from './TextareaWithSafari17Workaround';

/**
* @deprecated use SizeProp
Expand Down Expand Up @@ -204,6 +210,7 @@ export class Textarea extends React.Component<TextareaProps, TextareaState> {
};

private getProps = createPropsGetter(Textarea.defaultProps);
private featureFlags!: ReactUIFeatureFlags;

private getRootSizeClassName() {
switch (this.getProps().size) {
Expand Down Expand Up @@ -295,16 +302,23 @@ export class Textarea extends React.Component<TextareaProps, TextareaState> {

public render() {
return (
<ThemeContext.Consumer>
{(theme) => {
this.theme = theme;
<ReactUIFeatureFlagsContext.Consumer>
{(flags) => {
this.featureFlags = getFullReactUIFlagsContext(flags);
return (
<CommonWrapper rootNodeRef={this.setRootNode} {...this.props}>
{this.renderMain}
</CommonWrapper>
<ThemeContext.Consumer>
{(theme) => {
this.theme = theme;
return (
<CommonWrapper rootNodeRef={this.setRootNode} {...this.props}>
{this.renderMain}
</CommonWrapper>
);
}}
</ThemeContext.Consumer>
);
}}
</ThemeContext.Consumer>
</ReactUIFeatureFlagsContext.Consumer>
);
}

Expand Down Expand Up @@ -436,6 +450,9 @@ export class Textarea extends React.Component<TextareaProps, TextareaState> {
/>
);

const Component =
this.featureFlags.textareaUseSafari17Workaround && isSafari17 ? TextareaWithSafari17Workaround : 'textarea';

return (
<RenderLayer
onFocusOutside={this.handleCloseCounterHelp}
Expand All @@ -451,7 +468,7 @@ export class Textarea extends React.Component<TextareaProps, TextareaState> {
>
{placeholderPolyfill}
<ResizeDetector onResize={this.reflowCounter}>
<textarea
<Component
{...textareaProps}
className={textareaClassNames}
style={textareaStyle}
Expand All @@ -465,7 +482,7 @@ export class Textarea extends React.Component<TextareaProps, TextareaState> {
disabled={disabled}
>
{this.props.children}
</textarea>
</Component>
</ResizeDetector>
{fakeTextarea}
{counter}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';

import { forwardRefAndName } from '../../lib/forwardRefAndName';

/**
* React textarea behaves incorrectly on first rendered in Safari version 17.*
* Reproduce: https://codesandbox.io/p/sandbox/textarea-and-textarea-safari-bug-9v95vz
*/
export const TextareaWithSafari17Workaround = forwardRefAndName<
HTMLTextAreaElement,
React.TextareaHTMLAttributes<HTMLTextAreaElement>
>('TextareaWithSafari17Workaround', (props, ref) => {
const [firstRender, setFirstRender] = React.useState(true);

React.useEffect(() => {
firstRender && setFirstRender(false);
}, []);

return <textarea {...props} value={firstRender ? '' : props.value} ref={ref} />;
});
2 changes: 2 additions & 0 deletions packages/react-ui/lib/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ export const isMobile =
'ontouchstart' in globalObject.document.documentElement;

export const isIOS = /(ip[ao]d|iphone)/gi.test(userAgent);

export const isSafari17 = isSafari && userAgent.includes('version/17');
26 changes: 26 additions & 0 deletions packages/react-ui/lib/featureFlagsContext/FEATUREFLAGSCONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,32 @@ const getItems = () => {};
</ReactUIFeatureFlagsContext.Provider>
```

### textareaUseSafari17Workaround

В браузере Safari версии 17.* возник баг в реактовом элементе `<textarea />`. Баг не позволяет нормально вводить текст в пустые строки.
Но только если эти пустые строки были при монтировании элемента.
Если пустые строки добавить сразу после монтирования, то проблема не наблюдается.

Мы можем купировать этот баг на своей стороне, но только в рамках контрола `Textarea`.
Также баг могут поправить на стороне Safari или React, из-за чего уже наше обходное решение может вызвать другой баг.
Поэтому лучше добавить возможность выключить в любой момент наше обходное решение.

Обходное решение само отслеживает Safari версии 17.*, и применяется только для него.

```jsx harmony
import { Textarea, ReactUIFeatureFlagsContext } from '@skbkontur/react-ui';

const [value, setValue] = React.useState('1\n\n\n\n2');

<ReactUIFeatureFlagsContext.Provider value={{ textareaUseSafari17Workaround: true }}>
<Textarea
value={value}
onValueChange={setValue}
rows={5}
/>
</ReactUIFeatureFlagsContext.Provider>
```

## Объект со всеми флагами

Чтобы получить объект со всеми флагами, необходимо применить вспомогательную функцию getFullValidationsFlagsContext к объекту заданных флагов:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import React from 'react';

export interface ReactUIFeatureFlags {
tokenInputRemoveWhitespaceFromDefaultDelimiters?: boolean;
textareaUseSafari17Workaround?: boolean;
}

export const reactUIFeatureFlagsDefault: ReactUIFeatureFlags = {
tokenInputRemoveWhitespaceFromDefaultDelimiters: false,
textareaUseSafari17Workaround: false,
};

export const ReactUIFeatureFlagsContext = React.createContext<ReactUIFeatureFlags>(reactUIFeatureFlagsDefault);
Expand Down

0 comments on commit e40c88b

Please sign in to comment.