feat: Custom Extension Components

This commit is contained in:
Javier Mendiara 2022-11-17 19:42:45 +01:00
parent 3d410b6002
commit 0fc00b2a1f
2 changed files with 49 additions and 7 deletions

View File

@ -4,14 +4,21 @@ import { ExtensionValue, FieldLabel } from '../../common-elements/fields';
import styled from '../../styled-components';
import { OptionsContext } from '../OptionsProvider';
import { AppStore } from '../../services';
import { StyledMarkdownBlock } from '../Markdown/styled.elements';
import { OptionsContext } from '../OptionsProvider';
import { StoreConsumer } from '../StoreBuilder';
const Extension = styled(StyledMarkdownBlock)`
margin: 2px 0;
`;
export interface ExtensionComponentMeta {
component: React.ComponentType;
propsSelector: (store?: AppStore) => any;
props?: object;
}
export interface ExtensionsProps {
extensions: {
[k: string]: any;
@ -19,6 +26,39 @@ export interface ExtensionsProps {
}
export class Extensions extends React.PureComponent<ExtensionsProps> {
renderExtensionComponent(key: string, meta: ExtensionComponentMeta) {
const exts = this.props.extensions;
return (
<StoreConsumer>
{store => (
<meta.component
{...{
...meta.props,
...meta.propsSelector(store),
...{
[key]: exts[key],
},
}}
/>
)}
</StoreConsumer>
);
}
renderSimpleExtension(key: string) {
const exts = this.props.extensions;
return (
<>
<FieldLabel> {key.substring(2)}: </FieldLabel>{' '}
<ExtensionValue>
{typeof exts[key] === 'string' ? exts[key] : JSON.stringify(exts[key])}
</ExtensionValue>
</>
);
}
render() {
const exts = this.props.extensions;
return (
@ -28,10 +68,9 @@ export class Extensions extends React.PureComponent<ExtensionsProps> {
{options.showExtensions &&
Object.keys(exts).map(key => (
<Extension key={key}>
<FieldLabel> {key.substring(2)}: </FieldLabel>{' '}
<ExtensionValue>
{typeof exts[key] === 'string' ? exts[key] : JSON.stringify(exts[key])}
</ExtensionValue>
{options.extensionsComponents[key]
? this.renderExtensionComponent(key, options.extensionsComponents[key])
: this.renderSimpleExtension(key)}
</Extension>
))}
</>

View File

@ -1,7 +1,7 @@
import defaultTheme, { ResolvedThemeInterface, resolveTheme, ThemeInterface } from '../theme';
import { querySelector } from '../utils/dom';
import { isArray, isNumeric, mergeObjects } from '../utils/helpers';
import { ExtensionComponentMeta } from '../components/Fields/Extensions';
import { setRedocLabels } from './Labels';
import { SideNavStyleEnum } from './types';
import type { LabelsConfigRaw, MDXComponentMeta } from './types';
@ -30,6 +30,7 @@ export interface RedocRawOptions {
hideSingleRequestSampleTab?: boolean | string;
menuToggle?: boolean | string;
jsonSampleExpandLevel?: number | string | 'all';
extensionsComponents?: Record<string, ExtensionComponentMeta>;
hideSchemaTitles?: boolean | string;
simpleOneOfTypeLabel?: boolean | string;
payloadSampleIdx?: number;
@ -234,6 +235,7 @@ export class RedocNormalizedOptions {
menuToggle: boolean;
jsonSampleExpandLevel: number;
enumSkipQuotes: boolean;
extensionsComponents: Record<string, ExtensionComponentMeta>;
hideSchemaTitles: boolean;
simpleOneOfTypeLabel: boolean;
payloadSampleIdx: number;
@ -321,6 +323,7 @@ export class RedocNormalizedOptions {
this.allowedMdComponents = raw.allowedMdComponents || {};
this.expandDefaultServerVariables = argValueToBoolean(raw.expandDefaultServerVariables);
this.extensionsComponents = raw.extensionsComponents || {};
this.maxDisplayedEnumValues = argValueToNumber(raw.maxDisplayedEnumValues);
const ignoreNamedSchemas = isArray(raw.ignoreNamedSchemas)
? raw.ignoreNamedSchemas