Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
1 change: 1 addition & 0 deletions packages/eui/changelogs/upcoming/8889.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Added `showFooter` and `toolbarProps.right` props to `EuiMarkdownEditor` for more flexible layout control. ([#8889](https://github.com/elastic/eui/pull/8889))
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ exports[`EuiMarkdownEditor is rendered 1`] = `
</div>
<button
class="euiButtonEmpty emotion-euiButtonDisplay-euiButtonEmpty-s-empty-text"
data-test-subj="markdown_editor_preview_button"
type="button"
>
<span
Expand Down Expand Up @@ -214,6 +213,7 @@ exports[`EuiMarkdownEditor is rendered 1`] = `
/>
<div
class="euiMarkdownEditorFooter emotion-euiMarkdownEditorFooter"
data-test-subj="euiMarkdownEditorFooter"
>
<div
class="euiMarkdownEditorFooter__actions emotion-euiMarkdownEditorFooter__actions"
Expand Down Expand Up @@ -424,7 +424,6 @@ exports[`EuiMarkdownEditor props autoExpandPreview is rendered with false 1`] =
</div>
<button
class="euiButtonEmpty emotion-euiButtonDisplay-euiButtonEmpty-s-empty-text"
data-test-subj="markdown_editor_preview_button"
type="button"
>
<span
Expand Down Expand Up @@ -460,6 +459,7 @@ exports[`EuiMarkdownEditor props autoExpandPreview is rendered with false 1`] =
/>
<div
class="euiMarkdownEditorFooter emotion-euiMarkdownEditorFooter"
data-test-subj="euiMarkdownEditorFooter"
>
<div
class="euiMarkdownEditorFooter__actions emotion-euiMarkdownEditorFooter__actions"
Expand Down Expand Up @@ -670,7 +670,6 @@ exports[`EuiMarkdownEditor props height is rendered in full mode 1`] = `
</div>
<button
class="euiButtonEmpty emotion-euiButtonDisplay-euiButtonEmpty-s-empty-text"
data-test-subj="markdown_editor_preview_button"
type="button"
>
<span
Expand Down Expand Up @@ -706,6 +705,7 @@ exports[`EuiMarkdownEditor props height is rendered in full mode 1`] = `
/>
<div
class="euiMarkdownEditorFooter emotion-euiMarkdownEditorFooter"
data-test-subj="euiMarkdownEditorFooter"
>
<div
class="euiMarkdownEditorFooter__actions emotion-euiMarkdownEditorFooter__actions"
Expand Down Expand Up @@ -916,7 +916,6 @@ exports[`EuiMarkdownEditor props height is rendered with a custom size 1`] = `
</div>
<button
class="euiButtonEmpty emotion-euiButtonDisplay-euiButtonEmpty-s-empty-text"
data-test-subj="markdown_editor_preview_button"
type="button"
>
<span
Expand Down Expand Up @@ -952,6 +951,7 @@ exports[`EuiMarkdownEditor props height is rendered with a custom size 1`] = `
/>
<div
class="euiMarkdownEditorFooter emotion-euiMarkdownEditorFooter"
data-test-subj="euiMarkdownEditorFooter"
>
<div
class="euiMarkdownEditorFooter__actions emotion-euiMarkdownEditorFooter__actions"
Expand Down Expand Up @@ -1162,7 +1162,6 @@ exports[`EuiMarkdownEditor props maxHeight is rendered with a custom size 1`] =
</div>
<button
class="euiButtonEmpty emotion-euiButtonDisplay-euiButtonEmpty-s-empty-text"
data-test-subj="markdown_editor_preview_button"
type="button"
>
<span
Expand Down Expand Up @@ -1198,6 +1197,7 @@ exports[`EuiMarkdownEditor props maxHeight is rendered with a custom size 1`] =
/>
<div
class="euiMarkdownEditorFooter emotion-euiMarkdownEditorFooter"
data-test-subj="euiMarkdownEditorFooter"
>
<div
class="euiMarkdownEditorFooter__actions emotion-euiMarkdownEditorFooter__actions"
Expand Down Expand Up @@ -1417,7 +1417,6 @@ exports[`EuiMarkdownEditor props readOnly is set to true 1`] = `
</div>
<button
class="euiButtonEmpty emotion-euiButtonDisplay-euiButtonEmpty-s-empty-disabled-isDisabled"
data-test-subj="markdown_editor_preview_button"
disabled=""
type="button"
>
Expand Down Expand Up @@ -1454,6 +1453,7 @@ exports[`EuiMarkdownEditor props readOnly is set to true 1`] = `
/>
<div
class="euiMarkdownEditorFooter emotion-euiMarkdownEditorFooter"
data-test-subj="euiMarkdownEditorFooter"
>
<div
class="euiMarkdownEditorFooter__actions emotion-euiMarkdownEditorFooter__actions"
Expand Down
1 change: 1 addition & 0 deletions packages/eui/src/components/markdown_editor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

export type { EuiMarkdownEditorProps } from './markdown_editor';
export { EuiMarkdownEditor } from './markdown_editor';
export { EuiMarkdownEditorHelpButton } from './markdown_editor_help_button';
export {
getDefaultEuiMarkdownParsingPlugins,
getDefaultEuiMarkdownProcessingPlugins,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
* Side Public License, v 1.
*/

import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { action } from '@storybook/addon-actions';

import { EuiMarkdownEditor, EuiMarkdownEditorProps } from './markdown_editor';
import { MODE_EDITING, MODE_VIEWING } from './markdown_modes';
import { EuiButton } from '../button';

const initialContent = `## Hello world!

Expand Down Expand Up @@ -62,3 +65,25 @@ export const Errors: Story = {
errors: ['An error happened.', 'Woops, another error happened.'],
},
};

export const CustomToolbarContent: Story = {
Comment thread
mgadewoll marked this conversation as resolved.
parameters: {
controls: {
include: ['toolbarProps'],
},
},
args: {
value: initialContent,
toolbarProps: {
right: (
<EuiButton
iconType="check"
size="s"
onClick={() => action('onClick')('Validated!')}
>
Validate
</EuiButton>
),
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import React from 'react';
import { fireEvent } from '@testing-library/react';
import { cleanup, fireEvent } from '@testing-library/react';
import { shouldRenderCustomStyles } from '../../test/internal';
import { requiredProps } from '../../test/required_props';
import { render, screen } from '../../test/rtl';
Expand Down Expand Up @@ -124,22 +124,22 @@ describe('EuiMarkdownEditor', () => {
});

test('is preview rendered', () => {
const { container, getByTestSubject } = render(
const { container, getByRole } = render(
<EuiMarkdownEditor
editorId="editorId"
value="## Hello world"
onChange={() => null}
{...requiredProps}
/>
);
fireEvent.click(getByTestSubject('markdown_editor_preview_button'));
fireEvent.click(getByRole('button', { name: 'Preview' }));
expect(
container.querySelector('.euiText.euiMarkdownFormat')?.querySelector('h2')
).toHaveTextContent('Hello world');
});

test('modal with help syntax is rendered', () => {
const { baseElement, getByLabelText } = render(
const { baseElement } = render(
<EuiMarkdownEditor
editorId="editorId"
value=""
Expand All @@ -149,7 +149,7 @@ describe('EuiMarkdownEditor', () => {
);
expect(baseElement.querySelector('.euiModal')).not.toBeInTheDocument();

fireEvent.click(getByLabelText('Show markdown help'));
fireEvent.click(screen.getByLabelText('Show markdown help'));
Comment thread
mgadewoll marked this conversation as resolved.

expect(baseElement.querySelector('.euiModal')).toBeInTheDocument();
});
Expand All @@ -158,7 +158,7 @@ describe('EuiMarkdownEditor', () => {
const { parsingPlugins, processingPlugins, uiPlugins } =
getDefaultEuiMarkdownPlugins({ exclude: ['tooltip'] });

const { baseElement, getByLabelText } = render(
const { baseElement } = render(
<EuiMarkdownEditor
editorId="editorId"
value=""
Expand All @@ -169,7 +169,7 @@ describe('EuiMarkdownEditor', () => {
{...requiredProps}
/>
);
fireEvent.click(getByLabelText('Show markdown help'));
fireEvent.click(screen.getByLabelText('Show markdown help'));

expect(baseElement.querySelector('.euiModal')).not.toBeInTheDocument();
expect(baseElement.querySelector('.euiPopover')).toBeInTheDocument();
Expand All @@ -182,12 +182,13 @@ describe('EuiMarkdownEditor', () => {
onChange: jest.fn(),
};

const { getByTestSubject } = render(
<EuiMarkdownEditor {...testProps} {...requiredProps} />
);
render(<EuiMarkdownEditor {...testProps} {...requiredProps} />);

const event = { target: { value: 'sometext' } };
fireEvent.change(getByTestSubject('euiMarkdownEditorTextArea'), event);
fireEvent.change(
screen.getByTestSubject('euiMarkdownEditorTextArea'),
event
);

expect(testProps.onChange).toHaveBeenCalledTimes(1);
expect(testProps.onChange).toHaveBeenLastCalledWith(event.target.value);
Expand Down Expand Up @@ -239,11 +240,9 @@ describe('EuiMarkdownEditor', () => {
errors: testMessage,
};

const { getByLabelText } = render(
<EuiMarkdownEditor {...testProps} {...requiredProps} />
);
render(<EuiMarkdownEditor {...testProps} {...requiredProps} />);

expect(getByLabelText('Show errors')).toBeInTheDocument();
expect(screen.getByLabelText('Show errors')).toBeInTheDocument();
});

test('does not render error if error messages are empty', () => {
Expand All @@ -254,11 +253,9 @@ describe('EuiMarkdownEditor', () => {
errors: [],
};

const { queryByTestSubject } = render(
<EuiMarkdownEditor {...testProps} {...requiredProps} />
);
render(<EuiMarkdownEditor {...testProps} {...requiredProps} />);

expect(queryByTestSubject('Show errors')).not.toBeInTheDocument();
expect(screen.queryByTestSubject('Show errors')).not.toBeInTheDocument();
});
});

Expand Down Expand Up @@ -286,11 +283,9 @@ describe('EuiMarkdownEditor', () => {
document.execCommand = execCommandMock;

beforeEach(() => {
const { getByTestSubject } = render(
<EuiMarkdownEditor {...testProps} {...requiredProps} />
);
render(<EuiMarkdownEditor {...testProps} {...requiredProps} />);

const textarea = getByTestSubject(
const textarea = screen.getByTestSubject(
'euiMarkdownEditorTextArea'
) as HTMLTextAreaElement;
textarea.setSelectionRange(0, 5);
Expand Down Expand Up @@ -380,4 +375,61 @@ describe('EuiMarkdownEditor', () => {
);
});
});
describe('toolbar props', () => {
it('shows the custom toolbar component when passed', () => {
const CustomToolbarComponent = () => <div>Custom toolbar</div>;
render(
<EuiMarkdownEditor
onChange={() => null}
value="markdown test"
{...requiredProps}
toolbarProps={{ right: <CustomToolbarComponent /> }}
/>
);
expect(screen.getByText('Custom toolbar')).toBeInTheDocument();
expect(
screen.queryByRole('button', { name: 'Preview' })
).not.toBeInTheDocument();
cleanup();
render(
<EuiMarkdownEditor
onChange={() => null}
value="markdown test"
{...requiredProps}
/>
);
expect(screen.queryByText('Custom toolbar')).not.toBeInTheDocument();
expect(
screen.getByRole('button', { name: 'Preview' })
).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'Preview' }));
expect(
screen.getByRole('button', { name: 'Editor' })
).toBeInTheDocument();
});
});
it('should show footer by default and hide when showFooter is false', () => {
render(
<EuiMarkdownEditor
onChange={() => null}
value="markdown test"
{...requiredProps}
/>
);
expect(
screen.getByTestSubject('euiMarkdownEditorFooter')
).toBeInTheDocument();
cleanup();
render(
<EuiMarkdownEditor
onChange={() => null}
value="markdown test"
{...requiredProps}
showFooter={false}
/>
);
expect(
screen.queryByTestSubject('euiMarkdownEditorFooter')
).not.toBeInTheDocument();
});
});
18 changes: 16 additions & 2 deletions packages/eui/src/components/markdown_editor/markdown_editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import React, {
useRef,
forwardRef,
} from 'react';

import unified, { PluggableList, Processor } from 'unified';
import { VFileMessage } from 'vfile-message';
import classNames from 'classnames';
Expand All @@ -28,7 +27,10 @@ import { EuiModal } from '../modal';
import { EuiResizeObserver } from '../observer/resize_observer';

import MarkdownActions, { insertText } from './markdown_actions';
import { EuiMarkdownEditorToolbar } from './markdown_editor_toolbar';
import {
EuiMarkdownEditorToolbar,
EuiMarkdownEditorToolbarProps,
} from './markdown_editor_toolbar';
import {
EuiMarkdownEditorTextArea,
EuiMarkdownEditorTextAreaProps,
Expand Down Expand Up @@ -137,6 +139,14 @@ type CommonMarkdownEditorProps = Omit<
EuiMarkdownFormatProps,
'parsingPluginList' | 'processingPluginList' | 'children'
>;
/**
* Props to customize the toolbar. `right` replaces the default preview/editor toggle with custom content.
*/
toolbarProps?: {
Comment thread
mgadewoll marked this conversation as resolved.
right?: EuiMarkdownEditorToolbarProps['right'];
};
/** Controls whether the footer is shown */
showFooter?: boolean;
};

export type EuiMarkdownEditorProps = OneOf<
Expand Down Expand Up @@ -213,6 +223,8 @@ export const EuiMarkdownEditor = forwardRef<
markdownFormatProps,
placeholder,
readOnly,
toolbarProps,
showFooter = true,
...rest
},
ref
Expand Down Expand Up @@ -433,6 +445,7 @@ export const EuiMarkdownEditor = forwardRef<
}
viewMode={viewMode}
uiPlugins={toolbarPlugins}
{...toolbarProps}
/>

{isPreviewing && (
Expand Down Expand Up @@ -481,6 +494,7 @@ export const EuiMarkdownEditor = forwardRef<
selectionEnd: newSelectionPoint,
});
}}
showFooter={showFooter}
uiPlugins={toolbarPlugins}
errors={errors}
hasUnacceptedItems={hasUnacceptedItems}
Expand Down
Loading