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

converts EuiCode and EuiCodeBlock to TypeScript #2835

Merged
merged 11 commits into from
Feb 19, 2020
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## [`master`](https://github.com/elastic/eui/tree/master)

- Converted `EuiCode` and `EuiCodeBlock` and to Typescript ([#2835](https://github.com/elastic/eui/pull/2835))
- Converted `EuiFilePicker` to TypeScript ([#2832](https://github.com/elastic/eui/issues/2832))
- Exported `EuiSelectOptionProps` type ([#2830](https://github.com/elastic/eui/pull/2830))
- Added `paperClip` glyph to `EuiIcon` ([#2845](https://github.com/elastic/eui/pull/2845))
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
"@types/enzyme": "^3.1.13",
"@types/lodash": "^4.14.116",
"@types/numeral": "^0.0.25",
"@types/react-virtualized": "^9.18.7",
"@types/react-beautiful-dnd": "^10.1.0",
"@types/react-virtualized": "^9.18.7",
dimitropoulos marked this conversation as resolved.
Show resolved Hide resolved
"chroma-js": "^2.0.4",
"classnames": "^2.2.5",
"highlight.js": "^9.12.0",
Expand Down Expand Up @@ -85,6 +85,7 @@
"@svgr/core": "5.0.1",
"@svgr/plugin-svgo": "^4.0.3",
"@types/classnames": "^2.2.6",
"@types/highlight.js": "^9.12.3",
"@types/jest": "^24.0.6",
"@types/react": "^16.9.11",
"@types/react-dom": "^16.9.4",
Expand Down
2 changes: 1 addition & 1 deletion scripts/jest/polyfills/mutation_observer.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ var MutationNotifier = /** @class */ (function (_super) {
__extends(MutationNotifier, _super);
function MutationNotifier() {
var _this = _super.call(this) || this;
_this.setMaxListeners(150); // bump this as needed - some tests do not perform the unmounting lifecycle
_this.setMaxListeners(294); // bump this as needed - some tests do not perform the unmounting lifecycle
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is suspicious to me, but it's all that worked to get past the pre-commit hook. Any deeper insight is appreciated.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely agree, I'll take a deeper look at this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: at the time I made this PR this change was necessary on master as well

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very interesting; can you provide some details on your setup:

  • operating system & version
  • yarn version (and confirm you used yarn to install EUI's dependencies, not npm)
  • confirm the jest package used comes from eui/node_modules/jest and not a global install

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

λ $ uname -a
Linux dimitri 5.3.0-26-generic #28-Ubuntu SMP Wed Dec 18 05:37:46 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

λ $ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 19.10
Release:        19.10
Codename:       eoan

λ $ yarn --version
1.21.1

λ $ jest

Command 'jest' not found, did you mean:

  command 'test' from deb coreutils (8.30-3ubuntu2)

Try: sudo apt install <deb name>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would you like me to remove the commit where I upped the count or shall we just leave it in?

return _this;
}
MutationNotifier.getInstance = function () {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react';
import { mount } from 'enzyme';
import { mount, ReactWrapper } from 'enzyme';
import { requiredProps } from '../../test/required_props';

import { EuiCodeBlockImpl } from './_code_block';

function snapshotCodeBlock(component) {
function snapshotCodeBlock(component: ReactWrapper) {
// Get the Portal's sibling and return its html
const renderedHtml = component.find('Portal + *').html();
const container = document.createElement('div');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { Component } from 'react';
import React, { Component, KeyboardEvent, CSSProperties } from 'react';
import { createPortal } from 'react-dom';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import hljs from 'highlight.js';

Expand All @@ -15,45 +14,85 @@ import { EuiFocusTrap } from '../focus_trap';
import { keyCodes } from '../../services';
import { EuiI18n } from '../i18n';
import { EuiInnerText } from '../inner_text';
import { keysOf } from '../common';
import { FontSize, PaddingSize } from './code';

const fontSizeToClassNameMap = {
s: 'euiCodeBlock--fontSmall',
m: 'euiCodeBlock--fontMedium',
l: 'euiCodeBlock--fontLarge',
};

export const FONT_SIZES = Object.keys(fontSizeToClassNameMap);
export const FONT_SIZES = keysOf(fontSizeToClassNameMap);

const paddingSizeToClassNameMap = {
const paddingSizeToClassNameMap: { [paddingSize in PaddingSize]: string } = {
none: '',
s: 'euiCodeBlock--paddingSmall',
m: 'euiCodeBlock--paddingMedium',
l: 'euiCodeBlock--paddingLarge',
};

export const PADDING_SIZES = Object.keys(paddingSizeToClassNameMap);
export const PADDING_SIZES = keysOf(paddingSizeToClassNameMap);

interface Props {
dimitropoulos marked this conversation as resolved.
Show resolved Hide resolved
className?: string;
fontSize: FontSize;

/**
* Displays the passed code in an inline format. Also removes any margins set.
*/
inline?: boolean;

/**
* Displays an icon button to copy the code snippet to the clipboard.
*/
isCopyable: boolean;

/**
* Sets the syntax highlighting for a specific language
*/
language?: string;
overflowHeight?: number;
paddingSize: PaddingSize;
transparentBackground: boolean;
}

interface State {
dimitropoulos marked this conversation as resolved.
Show resolved Hide resolved
isFullScreen: boolean;
}

/**
* This is the base component extended by EuiCode and EuiCodeBlock. These components
* share the same propTypes definition with EuiCodeBlockImpl.
* This is the base component extended by EuiCode and EuiCodeBlock.
* These components share the same propTypes definition with EuiCodeBlockImpl.
*/
export class EuiCodeBlockImpl extends Component {
codeTarget = document.createElement('div');
export class EuiCodeBlockImpl extends Component<Props, State> {
static defaultProps = {
transparentBackground: false,
paddingSize: 'l',
fontSize: 's',
isCopyable: false,
};

constructor(props) {
constructor(props: Props) {
super(props);

this.state = {
isFullScreen: false,
};
}

codeTarget = document.createElement('div');
code: HTMLElement | null = null;
codeFullScreen: HTMLElement | null = null;

highlight = () => {
// because React maintains a mapping between its Virtual DOM representation and the actual
// DOM elements (including text nodes), and hljs modifies the DOM structure which leads
// to React updating detached nodes, we render to a document fragment and
// copy from that fragment into the target elements
// (https://github.com/elastic/eui/issues/2322)
/**
* because React maintains a mapping between its Virtual DOM representation and the actual
* DOM elements (including text nodes), and hljs modifies the DOM structure which leads
* to React updating detached nodes, we render to a document fragment and
* copy from that fragment into the target elements
* (https://github.com/elastic/eui/issues/2322)
*/
const html = this.codeTarget.innerHTML;

if (this.code) {
Expand All @@ -64,15 +103,17 @@ export class EuiCodeBlockImpl extends Component {
}

if (this.props.language) {
hljs.highlightBlock(this.code);
if (this.code) {
dimitropoulos marked this conversation as resolved.
Show resolved Hide resolved
hljs.highlightBlock(this.code);
}

if (this.codeFullScreen) {
hljs.highlightBlock(this.codeFullScreen);
}
}
};

onKeyDown = event => {
onKeyDown = (event: KeyboardEvent<HTMLElement>) => {
dimitropoulos marked this conversation as resolved.
Show resolved Hide resolved
if (event.keyCode === keyCodes.ESCAPE) {
event.preventDefault();
event.stopPropagation();
Expand Down Expand Up @@ -128,7 +169,7 @@ export class EuiCodeBlockImpl extends Component {

const codeClasses = classNames('euiCodeBlock__code', language);

const optionalStyles = {};
const optionalStyles: CSSProperties = {};

if (overflowHeight) {
optionalStyles.maxHeight = overflowHeight;
Expand Down Expand Up @@ -158,14 +199,14 @@ export class EuiCodeBlockImpl extends Component {
);
}

function getCopyButton(textToCopy) {
let copyButton;
const getCopyButton = (textToCopy?: string) => {
chandlerprall marked this conversation as resolved.
Show resolved Hide resolved
let copyButton: JSX.Element | undefined;

if (isCopyable) {
if (isCopyable && textToCopy) {
dimitropoulos marked this conversation as resolved.
Show resolved Hide resolved
copyButton = (
<div className="euiCodeBlock__copyButton">
<EuiI18n token="euiCodeBlock.copyButton" default="Copy">
{copyButton => (
{(copyButton: string) => (
<EuiCopy textToCopy={textToCopy}>
{copy => (
<EuiButtonIcon
Expand All @@ -184,9 +225,9 @@ export class EuiCodeBlockImpl extends Component {
}

return copyButton;
}
};

let fullScreenButton;
let fullScreenButton: JSX.Element | undefined;

if (!inline && overflowHeight) {
fullScreenButton = (
Expand All @@ -196,7 +237,7 @@ export class EuiCodeBlockImpl extends Component {
'euiCodeBlock.fullscreenExpand',
]}
defaults={['Collapse', 'Expand']}>
{([fullscreenCollapse, fullscreenExpand]) => (
{([fullscreenCollapse, fullscreenExpand]: string[]) => (
chandlerprall marked this conversation as resolved.
Show resolved Hide resolved
<EuiButtonIcon
className="euiCodeBlock__fullScreenButton"
size="s"
Expand All @@ -212,7 +253,7 @@ export class EuiCodeBlockImpl extends Component {
);
}

function getCodeBlockControls(textToCopy) {
const getCodeBlockControls = (textToCopy?: string) => {
let codeBlockControls;
const copyButton = getCopyButton(textToCopy);

Expand All @@ -226,17 +267,13 @@ export class EuiCodeBlockImpl extends Component {
}

return codeBlockControls;
}
};

const getFullScreenDisplay = codeBlockControls => {
const getFullScreenDisplay = (codeBlockControls?: JSX.Element) => {
let fullScreenDisplay;

if (this.state.isFullScreen) {
{
/*
Force fullscreen to use large font and padding.
*/
}
// Force fullscreen to use large font and padding.
dimitropoulos marked this conversation as resolved.
Show resolved Hide resolved
const fullScreenClasses = classNames(
'euiCodeBlock',
fontSizeToClassNameMap[fontSize],
Expand Down Expand Up @@ -299,34 +336,3 @@ export class EuiCodeBlockImpl extends Component {
);
}
}

EuiCodeBlockImpl.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
paddingSize: PropTypes.oneOf(PADDING_SIZES),

/**
* Sets the syntax highlighting for a specific language
*/
language: PropTypes.string,
overflowHeight: PropTypes.number,
fontSize: PropTypes.oneOf(FONT_SIZES),
transparentBackground: PropTypes.bool,

/**
* Displays the passed code in an inline format. Also removes any margins set.
*/
inline: PropTypes.bool,

/**
* Displays an icon button to copy the code snippet to the clipboard.
*/
isCopyable: PropTypes.bool,
};

EuiCodeBlockImpl.defaultProps = {
transparentBackground: false,
paddingSize: 'l',
fontSize: 's',
isCopyable: false,
};
14 changes: 0 additions & 14 deletions src/components/code/code.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react';
import { mount } from 'enzyme';
import { mount, ReactWrapper } from 'enzyme';
import { requiredProps } from '../../test/required_props';

import { EuiCode } from './code';

function snapshotCodeBlock(component) {
function snapshotCodeBlock(component: ReactWrapper) {
// Get the Portal's sibling and return its html
const renderedHtml = component.find('Portal + *').html();
const container = document.createElement('div');
Expand Down
36 changes: 36 additions & 0 deletions src/components/code/code.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { CommonProps } from '../common';

import React, { FunctionComponent, HTMLAttributes } from 'react';

import { EuiCodeBlockImpl } from './_code_block';

export type FontSize = 's' | 'm' | 'l';
export type PaddingSize = 'none' | 's' | 'm' | 'l';

export interface EuiCodeSharedProps {
paddingSize?: PaddingSize;

/**
* Sets the syntax highlighting for a specific language
* @see http://highlightjs.readthedocs.io/en/latest/css-classes-reference.html#language-names-and-aliases
* for options
*/
language?: string;
overflowHeight?: number;
fontSize?: FontSize;
transparentBackground?: boolean;
isCopyable?: boolean;
}

interface Props extends EuiCodeSharedProps {
inline?: true;
}

export type EuiCodeProps = CommonProps & Props & HTMLAttributes<HTMLElement>;

export const EuiCode: FunctionComponent<EuiCodeProps> = ({
inline,
...rest
}) => {
return <EuiCodeBlockImpl inline={true} {...rest} />;
};
14 changes: 0 additions & 14 deletions src/components/code/code_block.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
import { mount } from 'enzyme';
import { mount, ReactWrapper } from 'enzyme';
import html from 'html';
import { requiredProps } from '../../test/required_props';

import { EuiCodeBlock } from './code_block';
import { FONT_SIZES, PADDING_SIZES } from './_code_block';

function snapshotCodeBlock(component) {
function snapshotCodeBlock(component: ReactWrapper) {
// Get the Portal's sibling and return its html
const renderedHtml = component.find('Portal + *').html();
const container = document.createElement('div');
Expand Down
Loading