Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EuiMarkdownFormat/Editor] Allow configuring default plugins #7985

Merged
merged 8 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
someone@elastic.co
`;

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
Loading