Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
patrykkopycinski committed Aug 24, 2021
1 parent b45447f commit e1f0cd6
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 105 deletions.
89 changes: 15 additions & 74 deletions x-pack/plugins/cases/public/components/markdown_editor/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,22 @@ import React, {
memo,
forwardRef,
useCallback,
useEffect,
useMemo,
useRef,
useState,
useImperativeHandle,
ElementRef,
} from 'react';
import { some } from 'lodash';
import { PluggableList } from 'unified';
import { EuiMarkdownAstNode, EuiMarkdownEditor, EuiMarkdownEditorUiPlugin } from '@elastic/eui';
import {
EuiMarkdownEditor,
EuiMarkdownEditorProps,
EuiMarkdownAstNode,
EuiMarkdownEditorUiPlugin,
} from '@elastic/eui';
import { ContextShape } from '@elastic/eui/src/components/markdown_editor/markdown_context';
import useDebounce from 'react-use/lib/useDebounce';
import { usePlugins } from './use_plugins';
import { CommentEditorContext } from './context';
import { PREFIX } from './plugins/lens/constants';
import { useLensButtonToggle } from './plugins/lens/use_lens_button_toggle';

interface MarkdownEditorProps {
Expand All @@ -48,17 +49,21 @@ export interface MarkdownEditorRef {

const MarkdownEditorComponent = forwardRef<MarkdownEditorRef, MarkdownEditorProps>(
({ ariaLabel, dataTestSubj, editorId, height, onChange, value }, ref) => {
const astRef = useRef(null);
const astRef = useRef<EuiMarkdownAstNode | undefined>(undefined);
const [markdownErrorMessages, setMarkdownErrorMessages] = useState([]);
const onParse = useCallback((err, { messages, ast }) => {
const onParse: EuiMarkdownEditorProps['onParse'] = useCallback((err, { messages, ast }) => {
setMarkdownErrorMessages(err ? [err] : messages);
astRef.current = ast;
}, []);
const { parsingPlugins, processingPlugins, uiPlugins } = usePlugins();
const editorRef = useRef<EuiMarkdownEditorRef>(null);
const { enableLensButton, disableLensButton } = useLensButtonToggle();
const [lensNodeSelected, setLensNodeSelected] = useState(false);
const lensPluginAvailable = useRef(false);

useLensButtonToggle({
astRef,
uiPlugins,
editorRef: ref as React.MutableRefObject<MarkdownEditorRef>,
value,
});

const commentEditorContextValue = useMemo(
() => ({
Expand All @@ -68,10 +73,6 @@ const MarkdownEditorComponent = forwardRef<MarkdownEditorRef, MarkdownEditorProp
[editorId, value]
);

useEffect(() => {
lensPluginAvailable.current = some(uiPlugins, ['name', 'lens']);
}, [uiPlugins]);

// @ts-expect-error
useImperativeHandle(ref, () => {
if (!editorRef.current) {
Expand All @@ -86,66 +87,6 @@ const MarkdownEditorComponent = forwardRef<MarkdownEditorRef, MarkdownEditorProp
};
});

useDebounce(
() => {
if (lensNodeSelected || !value.includes(PREFIX)) {
// @ts-expect-error
enableLensButton({ editorRef: ref?.current! });
} else {
// @ts-expect-error
disableLensButton({ editorRef: ref?.current! });
}
},
100,
[value, lensNodeSelected]
);

// Copied from https://github.com/elastic/eui/blob/master/src/components/markdown_editor/markdown_editor.tsx#L279
useEffect(() => {
if (
editorRef.current?.textarea == null ||
astRef.current == null ||
!lensPluginAvailable.current
) {
return;
}

const getCursorNode = () => {
const { selectionStart } = editorRef.current?.textarea!;

let node: EuiMarkdownAstNode = astRef.current!;

outer: while (true) {
if (node.children) {
for (let i = 0; i < node.children.length; i++) {
const child = node.children[i];
if (
child.position.start.offset < selectionStart &&
selectionStart < child.position.end.offset
) {
if (child.type === 'text') break outer; // don't dive into `text` nodes
node = child;
continue outer;
}
}
}
break;
}

setLensNodeSelected(node.type === 'lens');
};

const textarea = editorRef.current?.textarea;

textarea.addEventListener('keyup', getCursorNode);
textarea.addEventListener('mouseup', getCursorNode);

return () => {
textarea.removeEventListener('keyup', getCursorNode);
textarea.removeEventListener('mouseup', getCursorNode);
};
}, [editorRef.current?.textarea]);

return (
<CommentEditorContext.Provider value={commentEditorContextValue}>
<EuiMarkdownEditor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
import { plugin } from './plugin';
import { LensParser } from './parser';
import { LensMarkDownRenderer } from './processor';
import { ADD_VISUALIZATION } from './translations';
import { VISUALIZATION } from './translations';

export { plugin, LensParser as parser, LensMarkDownRenderer as renderer, ADD_VISUALIZATION };
export { plugin, LensParser as parser, LensMarkDownRenderer as renderer, VISUALIZATION };
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { ModalContainer } from './modal_container';
import type { EmbeddablePackageState } from '../../../../../../../../src/plugins/embeddable/public';
import { SavedObjectFinderUi } from './saved_objects_finder';
import { useLensDraftComment } from './use_lens_draft_comment';
import { ADD_VISUALIZATION } from './translations';
import { VISUALIZATION } from './translations';

const BetaBadgeWrapper = styled.span`
display: inline-flex;
Expand Down Expand Up @@ -374,7 +374,7 @@ export const LensEditor = React.memo(LensEditorComponent);
export const plugin = {
name: ID,
button: {
label: ADD_VISUALIZATION,
label: VISUALIZATION,
iconType: 'lensApp',
},
helpText: (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

import { i18n } from '@kbn/i18n';

export const ADD_VISUALIZATION = i18n.translate(
'xpack.cases.markdownEditor.plugins.lens.addVisualizationButtonLabel',
export const VISUALIZATION = i18n.translate(
'xpack.cases.markdownEditor.plugins.lens.visualizationButtonLabel',
{
defaultMessage: 'Add visualization',
defaultMessage: 'Visualization',
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,59 @@
* 2.0.
*/

import { useCallback } from 'react';
import { ADD_VISUALIZATION } from './translations';
import { some } from 'lodash';
import useDebounce from 'react-use/lib/useDebounce';
import { ContextShape } from '@elastic/eui/src/components/markdown_editor/markdown_context';
import { useCallback, useEffect, useRef, useState } from 'react';
import { EuiMarkdownAstNode, EuiMarkdownEditorUiPlugin } from '@elastic/eui';
import { VISUALIZATION } from './translations';
import { PREFIX } from './constants';

const DISABLED_CLASSNAME = 'euiButtonIcon-isDisabled';

export const useLensButtonToggle = () => {
const enableLensButton = useCallback(({ editorRef }) => {
if (editorRef && editorRef.textarea && editorRef.toolbar) {
const lensPluginButton = editorRef.toolbar?.querySelector(
`[aria-label="${ADD_VISUALIZATION}"]`
interface MarkdownEditorRef {
textarea: HTMLTextAreaElement | null;
replaceNode: ContextShape['replaceNode'];
toolbar: HTMLDivElement | null;
}

interface UseLensButtonToggleProps {
astRef?: React.MutableRefObject<EuiMarkdownAstNode | undefined>;
uiPlugins?: EuiMarkdownEditorUiPlugin[] | undefined;
editorRef?: React.MutableRefObject<MarkdownEditorRef | null>;
value?: string;
}

export const useLensButtonToggle = ({
astRef,
editorRef,
uiPlugins,
value,
}: UseLensButtonToggleProps) => {
const lensPluginAvailable = useRef(false);
const [lensNodeSelected, setLensNodeSelected] = useState(false);

const enableLensButton = useCallback(() => {
if (editorRef?.current?.textarea && editorRef.current?.toolbar) {
const lensPluginButton = editorRef.current?.toolbar?.querySelector(
`[aria-label="${VISUALIZATION}"]`
);

if (lensPluginButton) {
const isDisabled = lensPluginButton.className.includes(DISABLED_CLASSNAME);

if (isDisabled) {
const buttonStyle = lensPluginButton.getAttribute('style');
if (isDisabled && buttonStyle) {
lensPluginButton.className = lensPluginButton.className.replace(DISABLED_CLASSNAME, '');
lensPluginButton.setAttribute(
'style',
lensPluginButton.getAttribute('style').replace('pointer-events: none;', '')
);
lensPluginButton.setAttribute('style', buttonStyle.replace('pointer-events: none;', ''));
}
}
}
}, []);
}, [editorRef]);

const disableLensButton = useCallback(({ editorRef }) => {
if (editorRef && editorRef.textarea && editorRef.toolbar) {
const lensPluginButton = editorRef.toolbar?.querySelector(
`[aria-label="${ADD_VISUALIZATION}"]`
const disableLensButton = useCallback(() => {
if (editorRef?.current?.textarea && editorRef.current.toolbar) {
const lensPluginButton = editorRef.current.toolbar?.querySelector(
`[aria-label="${VISUALIZATION}"]`
);

if (lensPluginButton) {
Expand All @@ -46,7 +69,67 @@ export const useLensButtonToggle = () => {
}
}
}
}, []);
}, [editorRef]);

useEffect(() => {
lensPluginAvailable.current = some(uiPlugins, ['name', 'lens']);
}, [uiPlugins]);

useDebounce(
() => {
if (lensNodeSelected || !value?.includes(PREFIX)) {
enableLensButton();
} else {
disableLensButton();
}
},
100,
[value, lensNodeSelected]
);

// Copied from https://github.com/elastic/eui/blob/master/src/components/markdown_editor/markdown_editor.tsx#L279
useEffect(() => {
if (
editorRef?.current?.textarea == null ||
astRef?.current == null ||
!lensPluginAvailable.current
) {
return;
}

const getCursorNode = () => {
const { selectionStart } = editorRef.current?.textarea!;

let node: EuiMarkdownAstNode = astRef.current!;

outer: while (true) {
if (node.children) {
for (let i = 0; i < node.children.length; i++) {
const child = node.children[i];
if (
child.position.start.offset < selectionStart &&
selectionStart < child.position.end.offset
) {
if (child.type === 'text') break outer; // don't dive into `text` nodes
node = child;
continue outer;
}
}
}
break;
}

setLensNodeSelected(node.type === 'lens');
};

const textarea = editorRef.current?.textarea;

textarea.addEventListener('keyup', getCursorNode);
textarea.addEventListener('mouseup', getCursorNode);

return { enableLensButton, disableLensButton };
return () => {
textarea.removeEventListener('keyup', getCursorNode);
textarea.removeEventListener('mouseup', getCursorNode);
};
}, [astRef, editorRef]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useCallback, useEffect, useState } from 'react';
import { first } from 'rxjs/operators';
import { useKibana } from '../../../../common/lib/kibana';
import { DRAFT_COMMENT_STORAGE_ID } from './constants';
import { ADD_VISUALIZATION } from './translations';
import { VISUALIZATION } from './translations';

interface DraftComment {
commentId: string;
Expand Down Expand Up @@ -51,9 +51,7 @@ export const useLensDraftComment = () => {

const openLensModal = useCallback(({ editorRef }) => {
if (editorRef && editorRef.textarea && editorRef.toolbar) {
const lensPluginButton = editorRef.toolbar?.querySelector(
`[aria-label="${ADD_VISUALIZATION}"]`
);
const lensPluginButton = editorRef.toolbar?.querySelector(`[aria-label="${VISUALIZATION}"]`);
if (lensPluginButton) {
lensPluginButton.click();
}
Expand Down

0 comments on commit e1f0cd6

Please sign in to comment.