Skip to content

Commit

Permalink
[EuiMarkdownFormat/Editor] Allow configuring default plugins (#7985)
Browse files Browse the repository at this point in the history
Co-authored-by: Cee Chen <[email protected]>
  • Loading branch information
hsk11 and cee-chen committed Aug 29, 2024
1 parent 3bfc961 commit 23bef2b
Show file tree
Hide file tree
Showing 12 changed files with 434 additions and 114 deletions.
5 changes: 5 additions & 0 deletions packages/eui/changelogs/upcoming/7985.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- Updated `getDefaultEuiMarkdownPlugins` to support the following new default plugin configurations:
- `parsingConfig.linkValidator`, which allows configuring `allowRelative` and `allowProtocols`
- `parsingConfig.emoji`, which allows configuring emoticon parsing
- `processingConfig.linkProps`, which allows configuring rendered links with any props that `EuiLink` accepts
- See our **Markdown plugins** documentation for example `EuiMarkdownFormat` and `EuiMarkdownEditor` usage
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ const locationPathname = location.pathname;

export const markdownContent = `**Links starting with http:, https:, mailto:, and / are valid:**
* https://elastic.com
* http://elastic.com
* https://elastic.co
* http://elastic.co
* https link to [elastic.co](https://elastic.co)
* http link to [elastic.co](http://elastic.co)
* relative link to [eui doc's homepage](${locationPathname})
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';

import {
EuiMarkdownFormat,
getDefaultEuiMarkdownPlugins,
} from '../../../../src';

export const markdownContent = `
- :cry: Automatic emoji formatting has been excluded from this markdown.
- In the example below, only \`https:\` and \`mailto:\` protocols should turn into links.
- Links should open in a new tab.
https://elastic.co
http://elastic.co
[email protected]
`;

export default () => {
const { processingPlugins, parsingPlugins } = getDefaultEuiMarkdownPlugins({
exclude: ['emoji'],
processingConfig: {
linkProps: { target: '_blank' },
},
parsingConfig: {
linkValidator: { allowProtocols: ['https:', 'mailto:'] },
},
});

return (
<EuiMarkdownFormat
processingPluginList={processingPlugins}
parsingPluginList={parsingPlugins}
>
{markdownContent}
</EuiMarkdownFormat>
);
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { Fragment } from 'react';
import React from 'react';
import { Link } from 'react-router-dom';

import { GuideSectionTypes } from '../../components';

Expand All @@ -14,13 +15,18 @@ import {
EuiLink,
} from '../../../../src/components';

import { Link } from 'react-router-dom';
import {
DefaultPluginsConfig,
DefaultParsingPluginsConfig,
DefaultProcessingPluginsConfig,
EuiMarkdownLinkValidatorOptions,
} from './markdown_plugin_props';

import MarkdownEditorWithPlugins from './markdown_editor_with_plugins';
const markdownEditorWithPluginsSource = require('!!raw-loader!./markdown_editor_with_plugins');

const linkValidationSource = require('!!raw-loader!./markdown_link_validation');
import LinkValidation from './markdown_link_validation';
const pluginConfigSource = require('!!raw-loader!./markdown_plugin_config');
import PluginConfig from './markdown_plugin_config';

const pluginSnippet = `<EuiMarkdownEditor
uiPlugin={myPluginUI}
Expand Down Expand Up @@ -293,11 +299,7 @@ export const MarkdownPluginExample = {
These plugin definitions can be obtained by calling{' '}
<EuiCode>getDefaultEuiMarkdownParsingPlugins</EuiCode>,{' '}
<EuiCode>getDefaultEuiMarkdownProcessingPlugins</EuiCode>, and{' '}
<EuiCode>getDefaultEuiMarkdownUiPlugins</EuiCode> respectively. Each
of these three functions take an optional configuration object with
an <EuiCode>exclude</EuiCode> key, an array of EUI-defaulted plugins
to disable. Currently the only option this configuration can take is{' '}
<EuiCode>&apos;tooltip&apos;</EuiCode>.
<EuiCode>getDefaultEuiMarkdownUiPlugins</EuiCode> respectively.
</p>
</>
),
Expand All @@ -306,56 +308,73 @@ export const MarkdownPluginExample = {
source: [
{
type: GuideSectionTypes.JS,
code: linkValidationSource,
code: pluginConfigSource,
},
],
title: 'Link validation & security',
title: 'Configuring the default plugins',
text: (
<Fragment>
<>
<p>
To enhance user and application security, the default behavior
removes links to URLs that aren&apos;t relative (beginning with{' '}
<EuiCode>/</EuiCode>) and don&apos;t use the{' '}
<EuiCode>https:</EuiCode>, <EuiCode>http:</EuiCode>, or{' '}
<EuiCode>mailto:</EuiCode> protocols. This validation can be further
configured or removed altogether.
The above plugin utils, as well as{' '}
<EuiCode>getDefaultEuiMarkdownPlugins</EuiCode>, accept an optional
configuration object of:
<ul>
<li>
<EuiCode>exclude</EuiCode>: an array of default plugins to{' '}
<Link to="/editors-syntax/markdown-editor#unregistering-plugins">
unregister
</Link>
</li>
<li>
<EuiCode>parsingConfig</EuiCode>: allows overriding the
configuration of any default parsing plugin
</li>
<li>
<EuiCode>processingConfig</EuiCode>: currently only accepts a{' '}
<EuiCode>linkProps</EuiCode> key, which accepts any prop that{' '}
<Link to="/navigation/link">EuiLink</Link> accepts
</li>
</ul>
</p>
<p>
In this example only <EuiCode>https:</EuiCode> and{' '}
<EuiCode>mailto:</EuiCode> links are allowed.
The below example has the <EuiCode>emoji</EuiCode> plugin excluded,
and custom configuration on the link validator parsing plugin and
link processing plugin. See the <strong>Props</strong> table for all
plugin config options.
</p>
</Fragment>
</>
),
snippet: [
`// customize what link protocols are allowed
const parsingPlugins = [
...getDefaultEuiMarkdownParsingPlugins({
// Exclude the default validation plugin - we're configuring our own
exclude: ['linkValidator'],
}),
[
euiMarkdownLinkValidator,
{
// Customize what link protocols are allowed
allowProtocols: ['https:', 'mailto:'],
},
]
];
snippet: `const { parsingPlugins, processingPlugins } = getDefaultEuiMarkdownPlugins({
// Exclude plugins as necessary
exclude: ['emoji'],
parsingConfig: {
// Customize what link protocols are allowed
linkValidator: { allowProtocols: ['https:', 'mailto:'] },
},
processingConfig: {
// Configure all links to open in new tabs/windows
linkProps: { target: '_blank' },
},
});
// Pass the customized parsing plugins to your markdown component
<EuiMarkdownFormat parsingPlugins={parsingPlugins} />
`,
],
demo: <LinkValidation />,
// Pass the customized plugins to your markdown component
<EuiMarkdownFormat
parsingPluginList={parsingPlugins}
processingPluginList={processingPlugins}
/>`,
demo: <PluginConfig />,
props: {
DefaultPluginsConfig,
DefaultParsingPluginsConfig,
DefaultProcessingPluginsConfig,
EuiMarkdownLinkValidatorOptions,
},
},
{
title: 'Plugin development',
wrapText: false,
text: (
<>
<EuiTitle>
<h2>Plugin development</h2>
</EuiTitle>
<EuiSpacer size="m" />
<EuiText>
<p>
An <strong>EuiMarkdown plugin</strong> is comprised of three major
Expand All @@ -374,7 +393,7 @@ const parsingPlugins = [
/>
<EuiHorizontalRule margin="xl" />
<EuiTitle>
<h3>uiPlugin</h3>
<h3 id="uiPlugin">uiPlugin</h3>
</EuiTitle>
<EuiSpacer />
<EuiCodeBlock size="s" language="javascript">
Expand All @@ -388,11 +407,11 @@ const parsingPlugins = [
/>
<EuiHorizontalRule margin="xl" />
<EuiTitle>
<h3>parsingPluginList</h3>
<h3 id="parsingPluginList">parsingPluginList</h3>
</EuiTitle>
<EuiSpacer />
<EuiText>
<Fragment>
<>
<p>
<a
href="https://www.npmjs.com/package/remark-parse"
Expand Down Expand Up @@ -440,7 +459,7 @@ const parsingPlugins = [
elements, and do not have a locate method. They can consume as
much input text as desired, across multiple lines.
</p>
</Fragment>
</>
</EuiText>
<EuiSpacer />
<EuiCodeBlock
Expand Down Expand Up @@ -495,7 +514,7 @@ const parsingList = getDefaultEuiMarkdownParsingPlugins();
parsingList.push(EmojiMarkdownParser);`}</EuiCodeBlock>
<EuiHorizontalRule margin="xl" />
<EuiTitle>
<h3>processingPluginList</h3>
<h3 id="processingPluginList">processingPluginList</h3>
</EuiTitle>
<EuiSpacer />
<EuiText>
Expand Down Expand Up @@ -533,7 +552,7 @@ processingList[1][1].components.emojiPlugin = EmojiMarkdownRenderer;`}
],
title: 'Putting it all together: a simple chart plugin',
text: (
<Fragment>
<>
<p>
The below example takes the concepts from above to construct a
simple chart embed that is initiated from a new button in the editor
Expand All @@ -545,7 +564,7 @@ processingList[1][1].components.emojiPlugin = EmojiMarkdownRenderer;`}
list. The editor manages additional controls through the{' '}
<EuiCode>uiPlugins</EuiCode> prop.
</p>
</Fragment>
</>
),
props: {
EuiMarkdownEditor,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { FunctionComponent } from 'react';

import type {
ExcludableDefaultPlugins,
DefaultParsingPluginsConfig as DefaultParsingPluginsConfigProps,
DefaultProcessingPluginsConfig as DefaultProcessingPluginsConfigProps,
} from '../../../../src/components/markdown_editor/plugins/markdown_default_plugins';

import type { EuiMarkdownLinkValidatorOptions as EuiMarkdownLinkValidatorOptionsProps } from '../../../../src/components/markdown_editor';

export const DefaultPluginsConfig: FunctionComponent<{
exclude?: ExcludableDefaultPlugins;
parsingConfig?: DefaultParsingPluginsConfigProps;
processingConfig?: DefaultProcessingPluginsConfigProps;
}> = () => null;

export const DefaultParsingPluginsConfig: FunctionComponent<
DefaultParsingPluginsConfigProps
> = () => null;

export const DefaultProcessingPluginsConfig: FunctionComponent<
DefaultProcessingPluginsConfigProps
> = () => null;

export const EuiMarkdownLinkValidatorOptions: FunctionComponent<
EuiMarkdownLinkValidatorOptionsProps
> = () => null;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`EuiMarkdownFormat renders 1`] = `
<div
aria-label="aria-label"
class="euiText euiMarkdownFormat testClass1 testClass2 emotion-euiText-m-euiTextColor-default-euiMarkdownFormat-m-default-euiTestCss"
data-test-subj="test subject string"
>
<p>
<strong>
Hello world
</strong>
</p>
</div>
`;
Loading

0 comments on commit 23bef2b

Please sign in to comment.