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

View File

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