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

Add codesandbox links to our documentation #2728

Merged
merged 30 commits into from
Jun 5, 2020
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
795ed53
initial work for cs support
snide Dec 20, 2019
ab3374e
cleanup
snide Jan 2, 2020
1f1b563
Merge remote-tracking branch 'upstream/master' into demo/sandbox
snide Jan 2, 2020
c461a52
fixes for formatting and flyouts
snide Jan 2, 2020
b8816ce
remove codesanboxer, it's not needed
snide Jan 2, 2020
1707334
derp, fix yarn lock too
snide Jan 2, 2020
5a499a9
fix tree view, adjust regex
snide Jan 3, 2020
1ab85a8
make a component for code sandbox links, fix the link from the front …
snide Jan 3, 2020
2eeb0d2
don't show code sandbox demos if it has local doc imports
snide Jan 6, 2020
da51808
small fixes
snide Jan 7, 2020
d23bc4d
Merge remote-tracking branch 'upstream/master' into demo/sandbox
snide Jan 9, 2020
447dcf0
Merge remote-tracking branch 'upstream/master' into demo/sandbox
snide Jan 10, 2020
9dbce9e
better notice about icons
snide Jan 11, 2020
adcd16f
Merge remote-tracking branch 'upstream/master' into demo/sandbox
snide Jan 11, 2020
7bf2773
Fixes for examples
snide Jan 11, 2020
5da2925
with dumb hacks display toggles now work on codesanbox examples
snide Jan 12, 2020
1bce0d7
cleaned up the code to be readible and less brittle
snide Jan 12, 2020
99b56cf
fix from cleanup
snide Jan 12, 2020
a5fc03f
forgot to clean my homepage link
snide Jan 12, 2020
4bbdaa9
Merge remote-tracking branch 'upstream/master' into demo/sandbox
snide Jun 1, 2020
0daae87
fixing docs so CS links work
snide Jun 2, 2020
cf8deed
fix resizable lorem stuff
snide Jun 2, 2020
2d07371
Fix imports for codesandbox link in EuiCodeEditor
chandlerprall Jun 3, 2020
da56301
Merge branch 'master' into demo/sandbox
chandlerprall Jun 3, 2020
866a4ba
Fix import inspect/extract regex from looking at relative imports
chandlerprall Jun 4, 2020
fb429d9
replace toggle with an href link
snide Jun 4, 2020
9be85c0
Merge remote-tracking branch 'upstream/master' into demo/sandbox
snide Jun 4, 2020
bb6e08e
CS mention in PR request template
snide Jun 4, 2020
a4a1b4c
CS mention in PR request template
snide Jun 4, 2020
2788678
address greg's feedback, break up the ts import, and remove the react…
snide Jun 4, 2020
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 package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"chokidar": "^1.7.0",
"chromedriver": "2.37.0",
"circular-dependency-plugin": "^5.0.2",
"codesandbox": "^2.1.11",
"core-js": "^2.5.1",
"cross-env": "^5.2.0",
"css-loader": "^0.28.7",
Expand Down
1 change: 1 addition & 0 deletions src-docs/src/components/codesandbox/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { CodeSandboxLink } from './link';
152 changes: 152 additions & 0 deletions src-docs/src/components/codesandbox/link.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import React from 'react';
import { getParameters } from 'codesandbox/lib/api/define';
import {
cleanEuiImports,
hasDisplayToggles,
listExtraDeps,
} from '../../services';

/* HOW THE CODE SANDBOX REGEX WORKS
* Given the prop `content` we manipulate the provided source string to format
* it for use as an independent file in Code Sandbox. In order the following
* regex and magic happens:
*
* 1. A `content` prop is passed containing the src-doc example code we need to manipulate for CS.
* 2. If no content exists (like the homepage link), we'll make a hello world file bundled with EUI and call it a day.
* 3. If content exists, we build an `index.js` file with a <Demo> component based on the original content.
* 4. If content contains `DisplayToggles`, we also generate a `display_toggles.js` file alongside the `index.js` file to import.
* 5. Through regex we read the dependencies of both `content` and `display_toggles` and pass that to CS.
* 6. We pass the files and dependencies as params to CS through a POST call.
* */

const displayTogglesRawCode = require('!!raw-loader!../../views/form_controls/display_toggles');

/* 1 */
export const CodeSandboxLink = ({ children, content }) => {
/* 2 */
const defaultContent = `import ReactDOM from 'react-dom';
import '@elastic/eui/dist/eui_theme_light.css'
// import '@elastic/eui/dist/eui_theme_dark.css'
import React from 'react';

import {
EuiButton,
} from '@elastic/eui';

const Demo = () => (<EuiButton>Hello world!</EuiButton>);

ReactDOM.render(
<Demo />,
document.getElementById('root')
);
`;

/** This cleans the Demo JS example for Code Sanbox.
- Replaces relative imports with pure @elastic/eui ones
- Changes the JS example from a default export to a component const named Demo
**/
const exampleCleaned = cleanEuiImports(content)
.replace('export default', 'const Demo =')
.replace(
/(from )'(..\/)+display_toggles(\/?';)/,
"from './display_toggles';"
);

// If the code example still has local doc imports after the above cleaning it's
// too complicated for code sandbox so we don't provide a link
const hasLocalImports = /(from )'((.|..)\/).*?';/.test(exampleCleaned);

if (hasLocalImports && !hasDisplayToggles(exampleCleaned)) {
return;
}

// Renders the new Demo component generically into the code sandbox page
const exampleClose = `ReactDOM.render(
<Demo />,
document.getElementById('root')
);`;
// The Code Sanbbox demo needs to import CSS at the top of the document. CS has trouble
// with our dynamic imports so we need to warn the user for now
const exampleStart = `/**
// NOTICE ABOUT ICONS
// Codesandbox has issues with the way EUI dynamically imports icons.
// As a result these demos will not render icons in them.
**/

import ReactDOM from 'react-dom';
// import '@elastic/eui/dist/eui_theme_dark.css';
import '@elastic/eui/dist/eui_theme_light.css'`;

// Concat the three pieces of the example into a single string to use for index.js
const cleanedContent = `${exampleStart}
${exampleCleaned}
${exampleClose}
`;

const indexContent = cleanedContent
? cleanedContent.replace(
/(from )'.+display_toggles';/,
"from './display_toggles';"
)
: defaultContent;
const indexContentDeps = listExtraDeps(indexContent);
let mergedDeps = indexContentDeps;

/* 4 */
if (hasDisplayToggles(indexContent)) {
const cleanedDisplayToggles = cleanEuiImports(displayTogglesRawCode);
const displayToggleDeps = listExtraDeps(cleanedDisplayToggles);

/* 5 */
mergedDeps = { ...indexContentDeps, ...displayToggleDeps };
}

const config = {
files: {
'package.json': {
content: {
dependencies: {
react: 'latest',
'react-dom': 'latest',
'react-scripts': 'latest',
moment: 'latest',
'@elastic/eui': 'latest',
'@elastic/datemath': 'latest',
...mergedDeps,
},
},
},
/* 3 */
'index.js': {
content: indexContent,
},
},
};

/* 4 */
if (hasDisplayToggles(indexContent)) {
const cleanedDisplayToggles = cleanEuiImports(displayTogglesRawCode);

config.files['display_toggles.js'] = {
content: cleanedDisplayToggles,
};
}

const params = getParameters(config);

const childWithSubmit = React.cloneElement(children, {
type: 'submit',
});

return (
<form
action="https://codesandbox.io/api/v1/sandboxes/define"
method="POST"
target="_blank"
className="eui-textRight">
{/* 6 */}
<input type="hidden" name="parameters" value={params} />
{childWithSubmit}
</form>
);
};
30 changes: 22 additions & 8 deletions src-docs/src/components/guide_section/guide_section.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ import {
EuiTextColor,
EuiTitle,
EuiLink,
EuiButtonEmpty,
} from '../../../../src/components';

import { CodeSandboxLink } from '../codesandbox';

import { cleanEuiImports } from '../../services';

function markup(text) {
const regex = /(#[a-zA-Z]+)|(`[^`]+`)/g;
return text.split(regex).map((token, index) => {
Expand Down Expand Up @@ -376,18 +381,13 @@ export class GuideSection extends Component {
const { code } = this.props.source.find(
sourceObject => sourceObject.type === name
);
const npmImports = code
.replace(/(from )'(..\/)+src\/components(\/?';)/, "from '@elastic/eui';")
.replace(
/(from )'(..\/)+src\/services(\/?';)/,
"from '@elastic/eui/lib/services';"
)
.replace(/(from )'(..\/)+src\/components\/.*?';/, "from '@elastic/eui';");
const cleanedExampleCode = cleanEuiImports(code);

return (
<div key={name} ref={name}>
{name === 'javascript' ? this.renderCodeSandBoxButton() : null}
<EuiCodeBlock language={codeClass} overflowHeight={400}>
{npmImports}
{cleanedExampleCode}
</EuiCodeBlock>
</div>
);
Expand Down Expand Up @@ -424,6 +424,20 @@ export class GuideSection extends Component {
);
}

renderCodeSandBoxButton() {
return (
<Fragment>
<EuiSpacer size="s" />
<CodeSandboxLink content={this.props.source[0].code}>
<EuiButtonEmpty size="xs" iconType="logoCodesandbox">
Try out this demo on Code Sandbox
</EuiButtonEmpty>
</CodeSandboxLink>
<EuiSpacer size="s" />
</Fragment>
);
}

render() {
const chrome = this.renderChrome();

Expand Down
6 changes: 6 additions & 0 deletions src-docs/src/services/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,10 @@ export { renderToHtml } from './string/render_to_html';

export { translateUsingPseudoLocale } from './string/pseudo_locale_translator';

export {
cleanEuiImports,
hasDisplayToggles,
listExtraDeps,
} from './string/clean_imports';

export { registerTheme, applyTheme } from './theme/theme';
27 changes: 27 additions & 0 deletions src-docs/src/services/string/clean_imports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export const hasDisplayToggles = code => {
return /DisplayToggles/.test(code);
};

export const cleanEuiImports = code => {
return code
.replace(/(from )'(..\/)+src\/components(\/?';)/, "from '@elastic/eui';")
.replace(
/(from )'(..\/)+src\/services(\/?';)/,
"from '@elastic/eui/lib/services';"
);
};

export const listExtraDeps = code => {
return [
...code.matchAll(
// Match anything not directly calling eui (like lib dirs)
/(import)(?!.*elastic\/eui)\s.*?'(?<import>[^.].*?)'/g
chandlerprall marked this conversation as resolved.
Show resolved Hide resolved
),
]
.map(x => x.groups.import)
.reduce((deps, dep) => {
// Hack because the docs are locked to a specific version of React Router
deps[dep] = dep === 'react-router' ? '^3.2.5' : 'latest';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Couldn't think of a way to pull this from package.json automatically?

Copy link
Contributor

Choose a reason for hiding this comment

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

const pkg = require('../../../../package.json'); at the top of the file
and then replace '^3.2.5' with pkg.devDependencies['react-router']

return deps;
}, {});
};
14 changes: 7 additions & 7 deletions src-docs/src/views/facet/facet_layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
EuiSpacer,
} from '../../../../src/components';

import { VISUALIZATION_COLORS } from '../../../../src/services/color/visualization_colors';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we deprecate this now that we have real palettes?

Copy link
Contributor

Choose a reason for hiding this comment

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

I thought about that too as I was messing with the palettes and I don't think it makes sense to have two ways to export the viz palette.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Cool. I'll add it to our list then. They are definitely duplicative, and the new one is a more reliable method of pulling those values.

import { euiPaletteColorBlind } from '../../../../src/services';

export default class extends Component {
constructor(props) {
Expand All @@ -29,42 +29,42 @@ export default class extends Component {
id: 'facet0',
label: 'Simple, no icon',
quantity: 6,
iconColor: VISUALIZATION_COLORS[0],
iconColor: euiPaletteColorBlind[0],
onClick: this.facet0Clicked,
},
{
id: 'facet1',
label: 'Label or color indicator',
quantity: 60,
iconColor: VISUALIZATION_COLORS[1],
iconColor: euiPaletteColorBlind[1],
onClick: this.facet1Clicked,
},
{
id: 'facet2',
label: 'Disable all others',
quantity: 600,
iconColor: VISUALIZATION_COLORS[2],
iconColor: euiPaletteColorBlind[2],
onClick: this.facet2Clicked,
},
{
id: 'facet3',
label: 'Avatars instead of icons',
quantity: 60,
iconColor: VISUALIZATION_COLORS[3],
iconColor: euiPaletteColorBlind[3],
onClick: this.facet3Clicked,
},
{
id: 'facet4',
label: 'Show all as loading',
quantity: 6,
iconColor: VISUALIZATION_COLORS[4],
iconColor: euiPaletteColorBlind[4],
onClick: this.facet4Clicked,
},
{
id: 'facet5',
label: 'Just here to show truncation of really long labels',
quantity: 0,
iconColor: VISUALIZATION_COLORS[5],
iconColor: euiPaletteColorBlind[5],
},
];
}
Expand Down
8 changes: 6 additions & 2 deletions src-docs/src/views/flex/flex_group.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import React from 'react';

import { EuiFlexGroup, EuiFlexItem } from '../../../../src/components/flex';
import { EuiSpacer } from '../../../../src/components/spacer';
import {
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
// @ts-ignore
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gotta follow up on why this was needed.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this is necessary

Copy link
Contributor

Choose a reason for hiding this comment

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

^^ Can delete now?

} from '../../../../src/components';

export default () => (
<EuiFlexGroup>
Expand Down
2 changes: 1 addition & 1 deletion src-docs/src/views/flyout/flyout.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
EuiCodeBlock,
} from '../../../../src/components';

export class Flyout extends Component {
export default class extends Component {
constructor(props) {
super(props);

Expand Down
Loading