Skip to content

Commit

Permalink
converts EuiCode and EuiCodeBlock to TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
dimitropoulos committed Feb 7, 2020
1 parent 064e7c8 commit d4781e7
Show file tree
Hide file tree
Showing 17 changed files with 146 additions and 163 deletions.
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",
"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
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,11 @@ console.log(some);
exports[`EuiCodeBlock props overflowHeight is rendered 1`] = `
<div
class="euiCodeBlock euiCodeBlock--fontSmall euiCodeBlock--paddingLarge euiCodeBlock--hasControls"
style="max-height: 200px;"
style="max-height: 200;"
>
<pre
class="euiCodeBlock__pre"
style="max-height: 200px;"
style="max-height: 200;"
>
<code
class="euiCodeBlock__code"
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 @@ -16,44 +15,86 @@ import { keyCodes } from '../../services';
import { EuiI18n } from '../i18n';
import { EuiInnerText } from '../inner_text';

const fontSizeToClassNameMap = {
type FontSize = 's' | 'm' | 'l';
const fontSizeToClassNameMap: { [fontSize in FontSize]: string } = {
s: 'euiCodeBlock--fontSmall',
m: 'euiCodeBlock--fontMedium',
l: 'euiCodeBlock--fontLarge',
};

export const FONT_SIZES = Object.keys(fontSizeToClassNameMap);
export const FONT_SIZES = Object.keys(fontSizeToClassNameMap) as FontSize[];

const paddingSizeToClassNameMap = {
type PaddingSize = 's' | 'm' | 'l' | 'none';
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 = Object.keys(
paddingSizeToClassNameMap
) as PaddingSize[];

interface Props {
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 {
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 +105,17 @@ export class EuiCodeBlockImpl extends Component {
}

if (this.props.language) {
hljs.highlightBlock(this.code);
if (this.code) {
hljs.highlightBlock(this.code);
}

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

onKeyDown = event => {
onKeyDown = (event: KeyboardEvent<HTMLElement>) => {
if (event.keyCode === keyCodes.ESCAPE) {
event.preventDefault();
event.stopPropagation();
Expand Down Expand Up @@ -128,10 +171,10 @@ export class EuiCodeBlockImpl extends Component {

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

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

if (overflowHeight) {
optionalStyles.maxHeight = overflowHeight;
optionalStyles.maxHeight = String(overflowHeight);
}

const codeSnippet = (
Expand All @@ -158,14 +201,14 @@ export class EuiCodeBlockImpl extends Component {
);
}

function getCopyButton(textToCopy) {
let copyButton;
const getCopyButton = (textToCopy?: string) => {
let copyButton: JSX.Element | undefined;

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

return copyButton;
}
};

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

if (!inline && overflowHeight) {
fullScreenButton = (
Expand All @@ -196,7 +239,7 @@ export class EuiCodeBlockImpl extends Component {
'euiCodeBlock.fullscreenExpand',
]}
defaults={['Collapse', 'Expand']}>
{([fullscreenCollapse, fullscreenExpand]) => (
{([fullscreenCollapse, fullscreenExpand]: string[]) => (
<EuiButtonIcon
className="euiCodeBlock__fullScreenButton"
size="s"
Expand All @@ -212,7 +255,7 @@ export class EuiCodeBlockImpl extends Component {
);
}

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

Expand All @@ -226,17 +269,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.
const fullScreenClasses = classNames(
'euiCodeBlock',
fontSizeToClassNameMap[fontSize],
Expand Down Expand Up @@ -299,34 +338,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
39 changes: 39 additions & 0 deletions src/components/code/code.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { CommonProps } from '../common';

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

import { EuiCodeBlockImpl } from './_code_block';

/**
* There isn't a specific type for the <code> element, and MDN says that it only supports the HTMLElement interface.
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/code
* */
export type HTMLCodeElement = HTMLElement;

type FontSize = 's' | 'm' | 'l';
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;
}

export interface EuiCodeProps extends EuiCodeSharedProps {
inline?: true;
}

type Props = CommonProps & EuiCodeProps & HTMLAttributes<HTMLCodeElement>;

export const EuiCode: FunctionComponent<Props> = ({ 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

0 comments on commit d4781e7

Please sign in to comment.