Skip to content

Commit 2d6f9c4

Browse files
committed
docs: add docs
1 parent 0c1ab85 commit 2d6f9c4

File tree

12 files changed

+119
-60
lines changed

12 files changed

+119
-60
lines changed

docs/lib.md

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ This component serves as the primary entry point for drawing dynamic forms.
2121
| destroyOnUnregister | `boolean` | | If true, the value of a field will be destroyed when that field is unregistered. Defaults to true |
2222
| generateRandomValue | `function` | | Function that is necessary to generate a random value |
2323
| storeSubscriber | `(storeValue: FieldValue) => void` | | Subscriber function will be called when internal store of dynamic field is changed |
24+
| renderHtml | `function` | | Function for custom rendering of HTML and markdown content in descriptions |
2425

2526
### Controller
2627

@@ -48,6 +49,7 @@ This component serves as the primary entry point for creating an overview of for
4849
| Link | `React.ComponentType<{value: FormValue; link: Spec['viewSpec']['link'];}>` | | [Component](./spec.md#link) for converting values to links |
4950
| Monaco | `React.ComponentType<MonacoEditorProps>` | | [MonacoEditor](https://github.com/react-monaco-editor/react-monaco-editor) component for Monaco [Input](./config.md#inputs) |
5051
| showLayoutDescription | boolean | | enable to show viewSpec.layoutDescription hint |
52+
| renderHtml | `function` | | Function for custom rendering of HTML and markdown content in descriptions |
5153

5254
### ViewController
5355

docs/renderHtml.md

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# renderHtml
2+
3+
## Description
4+
5+
`renderHtml` is an optional property intended for custom rendering of HTML and markdown content in descriptions.
6+
This property is useful when you need to render formatted text (markdown or HTML) keeping it consistent with your project's design and styling.
7+
8+
Type of the property:
9+
10+
```ts
11+
renderHtml?: (text: string) => React.ReactNode;
12+
```
13+
14+
---
15+
16+
## How to use renderHtml?
17+
18+
To use this prop, pass your custom render function to the [DynamicField](./lib.md#dynamicfield) or [DynamicView](./lib.md#dynamicview) components.
19+
20+
Example for [DynamicField](./lib.md#dynamicfield):
21+
22+
```tsx
23+
// Use any third-party library or your custom implementation for HTML rendering
24+
const renderHtml = (text: string) => {
25+
return <div dangerouslySetInnerHTML={{__html: text}} />;
26+
};
27+
28+
export const MyForm = () => {
29+
return <DynamicField name="input" spec={spec} config={dynamicConfig} renderHtml={renderHtml} />;
30+
};
31+
```
32+
33+
Example for [DynamicView](./lib.md#dynamicview):
34+
35+
```tsx
36+
const renderHtml = (text: string) => {
37+
return <div dangerouslySetInnerHTML={{__html: text}} />;
38+
};
39+
40+
export const MyView = () => {
41+
return (
42+
<DynamicView value={value} spec={spec} config={dynamicViewConfig} renderHtml={renderHtml} />
43+
);
44+
};
45+
```
46+
47+
---
48+
49+
### Tips for using renderHtml:
50+
51+
- You can use any third-party libraries (for example, `@gravity-ui/markdown-editor`, `@diplodoc/transform`, etc.) to ensure safer and more effective rendering of markdown or HTML content.
52+
- If your custom components (for instance, custom layout or custom input components) also require markdown or HTML rendering capabilities, be sure to leverage the built-in hook `useRenderHtml()` for convenient access to the rendering function within child components.

rsbuild.config.ts

-7
This file was deleted.

src/lib/core/components/Form/DynamicField.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,16 @@ export const DynamicField: React.FC<DynamicFieldProps> = ({
8080
__mirror,
8181
}),
8282
[
83+
tools,
84+
shared,
8385
config,
8486
Monaco,
87+
__mirror,
8588
generateRandomValue,
86-
tools,
89+
mutatorsStore,
8790
mutateDFState,
8891
store,
89-
shared,
90-
mutatorsStore,
9192
renderHtml,
92-
__mirror,
9393
],
9494
);
9595

src/lib/core/components/View/DynamicView.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export const DynamicView = ({
4848
shared,
4949
renderHtml,
5050
}),
51-
[config, value, showLayoutDescription, Link, Monaco, shared, renderHtml],
51+
[config, value, Link, Monaco, showLayoutDescription, shared, renderHtml],
5252
);
5353

5454
if (isCorrectSpec(spec) && isCorrectViewConfig(config)) {

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

+20-10
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,25 @@ export const AccordeonCard: React.FC<AccordeonCardProps> = ({
8585
return 'subheader-1';
8686
}, [titleSize]);
8787

88+
const descriptionContent = React.useMemo(() => {
89+
if (!description) {
90+
return null;
91+
}
92+
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]);
106+
88107
return (
89108
<div ref={accordeonRef} className={b({empty: Boolean(emptyBody)}, className)}>
90109
<div
@@ -96,16 +115,7 @@ export const AccordeonCard: React.FC<AccordeonCardProps> = ({
96115
>
97116
<div className={b('header-content')}>
98117
<Text variant={currentHeaderVariant}>{header}</Text>
99-
{description ? (
100-
renderHtml ? (
101-
renderHtml(description)
102-
) : (
103-
<span
104-
className={b('header-content-description')}
105-
dangerouslySetInnerHTML={{__html: description}}
106-
/>
107-
)
108-
) : null}
118+
{descriptionContent}
109119
</div>
110120
{!emptyBody && !alwaysOpen ? (
111121
<div className={b('header-toggle-btn')} onClick={preventEvent}>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ 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';
89
import {block} from '../../../utils';
910
import {LazyLoader} from '../../LazyLoader';
10-
import {useRenderHtml} from '../../../../core/components/Form/hooks/useRenderHtml';
1111

1212
import {loadIcon} from './utils';
1313

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

+2-11
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ export const Accordeon = <
2525
meta,
2626
children,
2727
}: T): JSX.Element => {
28-
const {variantTitle} = spec.viewSpec.layoutProps || {};
2928
const renderHtml = useRenderHtml();
3029

30+
const {variantTitle} = spec.viewSpec.layoutProps || {};
31+
3132
const [open, setOpen] = React.useState(Boolean(spec.viewSpec?.layoutOpen));
3233

3334
const onDrop = React.useCallback(() => {
@@ -43,16 +44,6 @@ export const Accordeon = <
4344
return <RemoveButton name={name} onDrop={onDrop} />;
4445
}, [spec.required, input.value, onDrop, name]);
4546

46-
/* const note = React.useMemo(() => {
47-
if (!spec.viewSpec.layoutDescription) {
48-
return '';
49-
}
50-
51-
return renderHtml
52-
? renderHtml(spec.viewSpec.layoutDescription)
53-
: spec.viewSpec.layoutDescription;
54-
}, [spec.viewSpec.layoutDescription, renderHtml]);
55-
*/
5647
useErrorChecker({name, meta, open, setOpen});
5748

5849
return (

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

+20-10
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,25 @@ const RowBase = <T extends FieldValue, S extends Spec>({
3131
const arrayItem = React.useMemo(() => isArrayItem(name), [name]);
3232
const generateButton = React.useMemo(() => withGenerateButton(spec), [spec]);
3333

34+
const verboseDescriptionContent = React.useMemo(() => {
35+
if (verboseDescription && spec.viewSpec.layoutDescription) {
36+
return (
37+
<React.Fragment>
38+
{renderHtml ? (
39+
renderHtml(spec.viewSpec.layoutDescription)
40+
) : (
41+
<div
42+
className={b('description')}
43+
dangerouslySetInnerHTML={{__html: spec.viewSpec.layoutDescription}}
44+
/>
45+
)}
46+
</React.Fragment>
47+
);
48+
}
49+
50+
return null;
51+
}, [renderHtml, spec.viewSpec.layoutDescription, verboseDescription]);
52+
3453
return (
3554
<div className={b()}>
3655
<div className={b('left')}>
@@ -86,16 +105,7 @@ const RowBase = <T extends FieldValue, S extends Spec>({
86105
</Button>
87106
) : null}
88107
</div>
89-
{verboseDescription && spec.viewSpec.layoutDescription ? (
90-
renderHtml ? (
91-
renderHtml(spec.viewSpec.layoutDescription)
92-
) : (
93-
<div
94-
className={b('description')}
95-
dangerouslySetInnerHTML={{__html: spec.viewSpec.layoutDescription}}
96-
/>
97-
)
98-
) : null}
108+
{verboseDescriptionContent}
99109
</div>
100110
</div>
101111
);

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

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const ViewAccordeonCard = <T extends ArrayViewLayoutProps | ObjectViewLay
1414
children,
1515
}: T): JSX.Element | null => {
1616
const renderHtml = useRenderHtml();
17+
1718
const [open, setOpen] = React.useState(
1819
isBoolean(spec.viewSpec.layoutOpen) ? spec.viewSpec.layoutOpen : true,
1920
);

src/stories/CustomRenderHtml.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {Meta, Markdown} from '@storybook/addon-docs';
22

3-
import Config from '../../docs/config.md?raw';
3+
import Config from '../../docs/renderHtml.md?raw';
44

55
<Meta title="Other/CustomRenderHtml" />
66

src/stories/CustomRenderHtml.stories.tsx

+15-15
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,6 @@ const spec: ObjectSpec = {
2020
type: SpecTypes.Object,
2121
required: true,
2222
properties: {
23-
alert: {
24-
type: SpecTypes.String,
25-
viewSpec: {
26-
type: 'text_content',
27-
textContentParams: {
28-
text: '### Introduction to Web Technologies\n Markdown is **incredibly useful** for quick documentation. It allows you to: \n\n _Format text easily_\n\n -Create lists-\n\n -Add links <div class="important-note"> <h3>Important HTML Section</h3> <p>This section uses HTML for more complex formatting needs that Markdown doesnt support natively.</p> </div>',
29-
themeAlert: 'info',
30-
icon: '',
31-
},
32-
},
33-
},
3423
row: {
3524
type: SpecTypes.Boolean,
3625
viewSpec: {
@@ -45,9 +34,20 @@ const spec: ObjectSpec = {
4534
viewSpec: {
4635
type: 'base',
4736
layout: 'row_verbose',
48-
layoutTitle: 'Row Verbose description html',
37+
layoutTitle: 'Row Verbose',
4938
placeholder: 'placeholder text',
50-
layoutDescription: '<code>Row Verbose description html</code>',
39+
layoutDescription: '`Row Verbose description md`',
40+
},
41+
},
42+
alert: {
43+
type: SpecTypes.String,
44+
viewSpec: {
45+
type: 'text_content',
46+
textContentParams: {
47+
text: '### Introduction to Web Technologies\n Markdown is **incredibly useful** for quick documentation. It allows you to: \n\n _Format text easily_\n\n -Create lists-\n\n -Add links <div class="important-note"> <h3>Important HTML Section</h3> <p>This section uses HTML for more complex formatting needs that Markdown doesnt support natively.</p> </div>',
48+
themeAlert: 'info',
49+
icon: '',
50+
},
5151
},
5252
},
5353
},
@@ -68,10 +68,10 @@ const spec: ObjectSpec = {
6868
viewSpec: {
6969
type: 'base',
7070
layout: 'column',
71-
layoutTitle: 'Name',
71+
layoutTitle: 'column',
7272
placeholder: 'placeholder text',
7373
layoutDescription:
74-
"<a href='https://github.com/gravity-ui/dynamic-forms' target='__blank'>Link html Dynamic Forms</a>",
74+
'[Link html Dynamic Forms](https://github.com/gravity-ui/dynamic-forms)',
7575
},
7676
},
7777
},

0 commit comments

Comments
 (0)