Skip to content

Commit a6da3a4

Browse files
committed
fix: single place for html rendering
1 parent 7bf1245 commit a6da3a4

File tree

20 files changed

+34
-119
lines changed

20 files changed

+34
-119
lines changed

src/lib/kit/components/AccordeonCard/AccordeonCard.tsx

+3-15
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {Button, Icon, Text} from '@gravity-ui/uikit';
55
import isString from 'lodash/isString';
66

77
import {block} from '../../utils';
8+
import {HTMLContent} from '../HTMLContent';
89

910
import './AccordeonCard.scss';
1011

@@ -23,7 +24,6 @@ export interface AccordeonCardProps {
2324
titleSize?: 's' | 'm';
2425
alwaysOpen?: boolean;
2526
classNameBody?: string;
26-
renderHtml?: (text: string) => React.ReactNode;
2727
}
2828
export const AccordeonCard: React.FC<AccordeonCardProps> = ({
2929
className,
@@ -38,7 +38,6 @@ export const AccordeonCard: React.FC<AccordeonCardProps> = ({
3838
alwaysOpen,
3939
children,
4040
classNameBody,
41-
renderHtml,
4241
}) => {
4342
const accordeonRef = React.useRef<HTMLDivElement>(null);
4443
const bodyRef = React.useRef<HTMLDivElement>(null);
@@ -90,19 +89,8 @@ export const AccordeonCard: React.FC<AccordeonCardProps> = ({
9089
return null;
9190
}
9291

93-
return (
94-
<React.Fragment>
95-
{renderHtml ? (
96-
renderHtml(description)
97-
) : (
98-
<span
99-
className={b('header-content-description')}
100-
dangerouslySetInnerHTML={{__html: description}}
101-
/>
102-
)}
103-
</React.Fragment>
104-
);
105-
}, [description, renderHtml]);
92+
return <HTMLContent className={b('header-content-description')} html={description} />;
93+
}, [description]);
10694

10795
return (
10896
<div ref={accordeonRef} className={b({empty: Boolean(emptyBody)}, className)}>

src/lib/kit/components/Card/Card.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ export interface CardProps {
2323
alwaysOpen?: boolean;
2424
disableHeaderToggle?: boolean;
2525
checkEmptyBody?: boolean;
26-
renderHtml?: (html: string) => React.ReactNode;
2726
}
2827

2928
export const Card: React.FC<CardProps> = ({
@@ -37,7 +36,6 @@ export const Card: React.FC<CardProps> = ({
3736
disableHeaderToggle,
3837
checkEmptyBody,
3938
children,
40-
renderHtml,
4139
}) => {
4240
const containerRef = React.useRef<HTMLDivElement>(null);
4341
const titleRef = React.useRef<HTMLDivElement>(null);
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,29 @@
11
import React from 'react';
22

3+
import {isFunction} from 'lodash';
4+
5+
import {useRenderHtml as useRenderHtmlForm} from '../../../core/components/Form/hooks/useRenderHtml';
6+
import {useRenderHtml as useRenderHtmlView} from '../../../core/components/View/hooks/useRenderHtml';
7+
38
interface HTMLContentProps {
49
html: string;
10+
className?: string;
511
}
612

7-
export const HTMLContent: React.FC<HTMLContentProps> = ({html}) => {
8-
return <div dangerouslySetInnerHTML={{__html: html}} />;
13+
export const HTMLContent: React.FC<HTMLContentProps> = ({html, className}) => {
14+
const renderHtmlForm = useRenderHtmlForm();
15+
const renderHtmlView = useRenderHtmlView();
16+
17+
const content = React.useMemo(() => {
18+
if (renderHtmlForm && isFunction(renderHtmlForm)) {
19+
return renderHtmlForm(html);
20+
}
21+
if (renderHtmlView && isFunction(renderHtmlView)) {
22+
return renderHtmlView(html);
23+
}
24+
25+
return <div className={className} dangerouslySetInnerHTML={{__html: html}} />;
26+
}, [className, html, renderHtmlForm, renderHtmlView]);
27+
28+
return <React.Fragment>{content}</React.Fragment>;
929
};

src/lib/kit/components/Inputs/TextContent/TextContent.tsx

+3-14
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import {isEmpty} from 'lodash';
55
import cloneDeep from 'lodash/cloneDeep';
66

77
import type {StringIndependentInput, StringSpec} from '../../../../core';
8-
import {useRenderHtml} from '../../../../core/components/Form/hooks/useRenderHtml';
98
import {block} from '../../../utils';
9+
import {HTMLContent} from '../../HTMLContent';
1010
import {LazyLoader} from '../../LazyLoader';
1111

1212
import {loadIcon} from './utils';
@@ -19,14 +19,12 @@ export interface TextContentComponentProps {
1919
spec: StringSpec;
2020
value?: string;
2121
Layout?: React.FC<{spec: StringSpec; children: React.ReactElement}>;
22-
renderHtml?: ReturnType<typeof useRenderHtml>;
2322
}
2423

2524
export const TextContentComponent: React.FC<TextContentComponentProps> = ({
2625
spec,
2726
value,
2827
Layout,
29-
renderHtml,
3028
}) => {
3129
const {textContentParams, layoutDescription} = spec.viewSpec;
3230

@@ -43,7 +41,7 @@ export const TextContentComponent: React.FC<TextContentComponentProps> = ({
4341
<LazyLoader component={loadIcon(textContentParams?.icon)} />
4442
) : undefined;
4543

46-
let content = renderHtml ? renderHtml(text) : <span dangerouslySetInnerHTML={{__html: text}} />;
44+
let content = <HTMLContent html={text} />;
4745

4846
if (textContentParams?.themeAlert) {
4947
const titleAlert =
@@ -114,8 +112,6 @@ export const TextContent: StringIndependentInput = ({
114112
meta,
115113
layoutProps,
116114
}) => {
117-
const renderHtml = useRenderHtml();
118-
119115
const WrappedLayout = React.useMemo(() => {
120116
if (Layout) {
121117
const Component: TextContentComponentProps['Layout'] = (props) => {
@@ -137,12 +133,5 @@ export const TextContent: StringIndependentInput = ({
137133
return undefined;
138134
}, [Layout, layoutProps, input, arrayInput, meta, name]);
139135

140-
return (
141-
<TextContentComponent
142-
spec={spec}
143-
value={input.value}
144-
Layout={WrappedLayout}
145-
renderHtml={renderHtml}
146-
/>
147-
);
136+
return <TextContentComponent spec={spec} value={input.value} Layout={WrappedLayout} />;
148137
};

src/lib/kit/components/Layouts/Accordeon/Accordeon.tsx

-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import type {TextProps} from '@gravity-ui/uikit';
44

55
import type {ArrayLayoutProps, ObjectLayoutProps} from '../../../../core';
66
import {isArrayItem} from '../../../../core';
7-
import {useRenderHtml} from '../../../../core/components/Form/hooks/useRenderHtml';
87
import {ErrorWrapper} from '../../../components';
98
import {useErrorChecker} from '../../../hooks';
109
import {RemoveButton} from '../../RemoveButton';
@@ -25,8 +24,6 @@ export const Accordeon = <
2524
meta,
2625
children,
2726
}: T): JSX.Element => {
28-
const renderHtml = useRenderHtml();
29-
3027
const {variantTitle} = spec.viewSpec.layoutProps || {};
3128

3229
const [open, setOpen] = React.useState(Boolean(spec.viewSpec?.layoutOpen));
@@ -57,7 +54,6 @@ export const Accordeon = <
5754
hideInsteadOfDestroy
5855
withBranchView
5956
variantTitle={variantTitle}
60-
renderHtml={renderHtml}
6157
>
6258
<ErrorWrapper name={name} meta={meta} withoutChildErrorStyles>
6359
{children}

src/lib/kit/components/Layouts/AccordeonCard/AccordeonCardForm.tsx

-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import React from 'react';
22

33
import type {ArrayLayoutProps, ObjectLayoutProps} from '../../../../core';
44
import {isArrayItem} from '../../../../core';
5-
import {useRenderHtml} from '../../../../core/components/Form/hooks/useRenderHtml';
65
import {useErrorChecker} from '../../../hooks';
76
import {block} from '../../../utils';
87
import {AccordeonCard} from '../../AccordeonCard';
@@ -20,8 +19,6 @@ export const AccordeonCardForm = <T extends ArrayLayoutProps | ObjectLayoutProps
2019
children,
2120
meta,
2221
}: T): JSX.Element => {
23-
const renderHtml = useRenderHtml();
24-
2522
const [open, setOpen] = React.useState(Boolean(spec.viewSpec?.layoutOpen));
2623

2724
const onDrop = React.useCallback(() => {
@@ -48,7 +45,6 @@ export const AccordeonCardForm = <T extends ArrayLayoutProps | ObjectLayoutProps
4845
open={open}
4946
onToggle={setOpen}
5047
headerActionsTemplate={removeButton}
51-
renderHtml={renderHtml}
5248
>
5349
<ErrorWrapper name={name} meta={meta} withoutChildErrorStyles>
5450
{children}

src/lib/kit/components/Layouts/CardAccordeon.tsx

-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import React from 'react';
22

33
import type {FieldValue, LayoutProps, Spec} from '../../../core';
44
import {isArrayItem} from '../../../core';
5-
import {useRenderHtml} from '../../../core/components/Form/hooks/useRenderHtml';
65
import {Card, ErrorWrapper} from '../../components';
76
import {useErrorChecker} from '../../hooks';
87
import {RemoveButton} from '../RemoveButton';
@@ -14,8 +13,6 @@ export const CardAccordeon = <T extends FieldValue, S extends Spec>({
1413
meta,
1514
children,
1615
}: LayoutProps<T, undefined, undefined, S>) => {
17-
const renderHtml = useRenderHtml();
18-
1916
const [open, setOpen] = React.useState(Boolean(spec.viewSpec?.layoutOpen));
2017

2118
const onToggle = React.useCallback(() => setOpen((f) => !f), [setOpen]);
@@ -43,7 +40,6 @@ export const CardAccordeon = <T extends FieldValue, S extends Spec>({
4340
actions={removeButton}
4441
open={open}
4542
onToggle={onToggle}
46-
renderHtml={renderHtml}
4743
>
4844
<ErrorWrapper name={name} meta={meta} withoutChildErrorStyles>
4945
{children}

src/lib/kit/components/Layouts/CardSection.tsx

-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import React from 'react';
22

33
import type {FieldValue, LayoutProps, Spec} from '../../../core';
44
import {isArrayItem} from '../../../core';
5-
import {useRenderHtml} from '../../../core/components/Form/hooks/useRenderHtml';
65
import {Card, ErrorWrapper} from '../../components';
76
import {RemoveButton} from '../RemoveButton';
87

@@ -13,8 +12,6 @@ export const CardSection = <T extends FieldValue, S extends Spec>({
1312
meta,
1413
children,
1514
}: LayoutProps<T, undefined, undefined, S>) => {
16-
const renderHtml = useRenderHtml();
17-
1815
const removeButton = React.useMemo(() => {
1916
if (!isArrayItem(name) && (spec.required || !input.value)) {
2017
return null;
@@ -30,7 +27,6 @@ export const CardSection = <T extends FieldValue, S extends Spec>({
3027
description={spec.viewSpec.layoutDescription}
3128
actions={removeButton}
3229
alwaysOpen
33-
renderHtml={renderHtml}
3430
>
3531
<ErrorWrapper name={name} meta={meta} withoutChildErrorStyles>
3632
{children}

src/lib/kit/components/Layouts/Column/Column.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {Button, HelpMark, Icon, Text} from '@gravity-ui/uikit';
55

66
import type {FieldValue, LayoutProps, Spec, StringSpec} from '../../../../core';
77
import {isArrayItem, isArraySpec, isObjectSpec, withGenerateButton} from '../../../../core';
8-
import {useRenderHtml} from '../../../../core/components/Form/hooks/useRenderHtml';
98
import {ErrorWrapper, GenerateRandomValueButton} from '../../../components';
109
import {COMMON_POPOVER_PLACEMENT} from '../../../constants/common';
1110
import {block} from '../../../utils';
@@ -26,7 +25,6 @@ const ColumnBase = <T extends FieldValue, S extends Spec>({
2625
}: LayoutProps<T, undefined, undefined, S> & ColumnProps) => {
2726
const arrayItem = React.useMemo(() => isArrayItem(name), [name]);
2827
const generateButton = React.useMemo(() => withGenerateButton(spec), [spec]);
29-
const renderHtml = useRenderHtml();
3028

3129
return (
3230
<div className={b()}>

src/lib/kit/components/Layouts/Row/Row.tsx

+2-16
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {Button, HelpMark, Icon, Text} from '@gravity-ui/uikit';
55

66
import type {FieldValue, LayoutProps, Spec, StringSpec} from '../../../../core';
77
import {isArrayItem, isArraySpec, isObjectSpec, withGenerateButton} from '../../../../core';
8-
import {useRenderHtml} from '../../../../core/components/Form/hooks/useRenderHtml';
98
import {ErrorWrapper, GenerateRandomValueButton} from '../../../components';
109
import {COMMON_POPOVER_PLACEMENT} from '../../../constants/common';
1110
import {block} from '../../../utils';
@@ -27,29 +26,16 @@ const RowBase = <T extends FieldValue, S extends Spec>({
2726
verboseDescription,
2827
children,
2928
}: LayoutProps<T, undefined, undefined, S> & RowProps) => {
30-
const renderHtml = useRenderHtml();
31-
3229
const arrayItem = React.useMemo(() => isArrayItem(name), [name]);
3330
const generateButton = React.useMemo(() => withGenerateButton(spec), [spec]);
3431

3532
const verboseDescriptionContent = React.useMemo(() => {
3633
if (verboseDescription && spec.viewSpec.layoutDescription) {
37-
return (
38-
<React.Fragment>
39-
{renderHtml ? (
40-
renderHtml(spec.viewSpec.layoutDescription)
41-
) : (
42-
<div
43-
className={b('description')}
44-
dangerouslySetInnerHTML={{__html: spec.viewSpec.layoutDescription}}
45-
/>
46-
)}
47-
</React.Fragment>
48-
);
34+
return <HTMLContent html={spec.viewSpec.layoutDescription} />;
4935
}
5036

5137
return null;
52-
}, [renderHtml, spec.viewSpec.layoutDescription, verboseDescription]);
38+
}, [spec.viewSpec.layoutDescription, verboseDescription]);
5339

5440
return (
5541
<div className={b()}>

src/lib/kit/components/Layouts/Section/Section.tsx

+1-12
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import type {
1414
ViewLayoutProps,
1515
} from '../../../../core';
1616
import {isArrayItem, isArraySpec, isObjectSpec} from '../../../../core';
17-
import {useRenderHtml} from '../../../../core/components/Form/hooks/useRenderHtml';
1817
import {block} from '../../../utils';
1918
import {HTMLContent} from '../../HTMLContent';
2019
import {RemoveButton} from '../../RemoveButton';
@@ -48,7 +47,6 @@ const SectionBase = <
4847
children,
4948
...restProps
5049
}: (LayoutProps<D, undefined, SectionLayoutProps, S> | ViewLayoutProps<T, S>) & SectionProps) => {
51-
const renderHtml = useRenderHtml();
5250
const input = (restProps as FieldRenderProps<D>).input as
5351
| FieldRenderProps<D>['input']
5452
| undefined;
@@ -109,16 +107,7 @@ const SectionBase = <
109107
let description: React.ReactNode;
110108
if (spec.viewSpec.layoutDescription && !ignoreDescription) {
111109
if (descriptionAsSubtitle) {
112-
description = renderHtml ? (
113-
renderHtml(spec.viewSpec.layoutDescription)
114-
) : (
115-
<div
116-
className={b('description')}
117-
dangerouslySetInnerHTML={{
118-
__html: spec.viewSpec.layoutDescription,
119-
}}
120-
/>
121-
);
110+
description = <HTMLContent html={spec.viewSpec.layoutDescription} />;
122111
} else {
123112
description = (
124113
<Text className={b('note')}>

src/lib/kit/components/SimpleVerticalAccordeon/SimpleVerticalAccordeon.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ interface SimpleVerticalAccordeonProps {
2929
withBranchView?: boolean;
3030
viewLayout?: boolean;
3131
variantTitle?: TextProps['variant'];
32-
renderHtml?: (text: string) => React.ReactNode;
3332
}
3433

3534
interface SimpleVerticalAccordeonState {
@@ -199,7 +198,7 @@ export class SimpleVerticalAccordeon extends React.Component<
199198
}
200199

201200
private getTooltip() {
202-
const {note, renderHtml} = this.props;
201+
const {note} = this.props;
203202

204203
return note ? (
205204
<Text className={b('tooltip')}>

src/lib/kit/components/TogglerCard/TogglerCard.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ interface TogglerCardProps {
1717
onClick: () => void;
1818
disabled?: boolean;
1919
selected: boolean;
20-
renderHtml?: (html: string) => React.ReactNode;
2120
}
2221

2322
export const TogglerCard: React.FC<TogglerCardProps> = ({
@@ -27,7 +26,6 @@ export const TogglerCard: React.FC<TogglerCardProps> = ({
2726
onClick,
2827
disabled,
2928
selected,
30-
renderHtml,
3129
}) => {
3230
return (
3331
<Card

src/lib/kit/components/ViewLayouts/ViewAccordeon/ViewAccordeon.tsx

-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import isBoolean from 'lodash/isBoolean';
55

66
import type {ArrayValue, ObjectValue, Spec, ViewLayoutProps} from '../../../../core';
77
import {useDynamicFormsCtx} from '../../../../core';
8-
import {useRenderHtml} from '../../../../core/components/View/hooks/useRenderHtml';
98
import {isNotEmptyValue} from '../../../utils';
109
import {SimpleVerticalAccordeon} from '../../SimpleVerticalAccordeon';
1110

@@ -21,7 +20,6 @@ export const ViewAccordeon = <
2120
spec,
2221
children,
2322
}: T): JSX.Element | null => {
24-
const renderHtml = useRenderHtml();
2523
const {showLayoutDescription} = useDynamicFormsCtx();
2624

2725
const [open, setOpen] = React.useState(
@@ -49,7 +47,6 @@ export const ViewAccordeon = <
4947
withBranchView
5048
viewLayout
5149
variantTitle={variantTitle}
52-
renderHtml={renderHtml}
5350
>
5451
{children}
5552
</SimpleVerticalAccordeon>

0 commit comments

Comments
 (0)