Skip to content

Commit

Permalink
feat: replace values in Source
Browse files Browse the repository at this point in the history
  • Loading branch information
atanasster committed Feb 22, 2020
1 parent 45ea08b commit 1a90295
Show file tree
Hide file tree
Showing 33 changed files with 1,440 additions and 186 deletions.
2 changes: 2 additions & 0 deletions blocks/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
"@component-controls/specification": "^0.6.0",
"copy-to-clipboard": "^3.2.1",
"global": "^4.3.2",
"js-string-escape": "^1.0.1",
"polished": "^3.4.4",
"prettier": "^1.19.1",
"prism-react-renderer": "^1.0.2",
"qs": "^6.9.1",
"react": "^16.8.3",
Expand Down
4 changes: 4 additions & 0 deletions blocks/core/src/ControlsTable/PropEditorRow.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/** @jsx jsx */
/* eslint react/jsx-key: 0 */
import { jsx } from 'theme-ui';

import React from 'react';
import { Flex } from 'theme-ui';
import {
Expand Down
154 changes: 153 additions & 1 deletion blocks/core/src/Source/Source.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';

import { ControlTypes } from '@component-controls/specification';
import { Source, SourceProps, themes } from './Source';

export default {
Expand Down Expand Up @@ -74,3 +74,155 @@ export const sample = () => {
},
},
};

export const props = () => {
return (
<Source
args={[{ value: 'props' }]}
>{`export const story = props => (<Source {...props} />)`}</Source>
);
};

const code = `
export const story = ({ height, weight, style: { border, color }}) => (
<Source
height={height}
weight={weight}
border={border}
color={color}
/>);
`;

export const multiProps = () => {
return (
<Source
args={[
{ value: 'height' },
{ value: 'weight' },
{ value: 'border' },
{ value: 'color' },
]}
>
{code}
</Source>
);
};

export const noPrettier = () => {
return (
<Source
prettier={null}
args={[
{ value: 'height' },
{ value: 'weight' },
{ value: 'border' },
{ value: 'color' },
]}
>
{code}
</Source>
);
};

export const prettierFormatting = () => {
return (
<Source
prettier={{
tabWidth: 4,
bracketSpacing: false,
printWidth: 40,
}}
args={[
{ value: 'height' },
{ value: 'weight' },
{ value: 'border' },
{ value: 'color' },
]}
>
{code}
</Source>
);
};

export const controlsValues = () => {
return (
<Source
prettier={null}
args={[
{
loc: {
end: {
column: 43,
line: 0,
},
start: {
column: 30,
line: 0,
},
},
name: undefined,
value: [
{
loc: {
end: {
column: 36,
line: 0,
},
start: {
column: 32,
line: 0,
},
},
name: 'name',
usage: [
{
end: {
column: 65,
line: 0,
},
start: {
column: 61,
line: 0,
},
},
],
value: 'name',
},
{
loc: {
end: {
column: 41,
line: 0,
},
start: {
column: 38,
line: 0,
},
},
name: 'age',
usage: [
{
end: {
column: 75,
line: 0,
},
start: {
column: 72,
line: 0,
},
},
],
value: 'age',
},
],
},
]}
controls={{
name: { type: ControlTypes.TEXT, value: 'Sam', defaultValue: 'Tom' },
age: { type: ControlTypes.NUMBER, value: 19, defaultValue: 18 },
}}
>
{` export const myStory = ({ name, age }) => <Story name={name} age={age} />;`}
</Source>
);
};
124 changes: 116 additions & 8 deletions blocks/core/src/Source/Source.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
/* eslint-disable react/jsx-key */
/** @jsx jsx */
/* eslint react/jsx-key: 0 */
import { jsx } from 'theme-ui';
import React, { FC, MouseEvent } from 'react';
import { StoryArguments } from '@component-controls/specification';
import { LoadedComponentControls } from '@component-controls/core';

import { Options } from 'prettier';
import prettier from 'prettier/standalone';
import parserBabel from 'prettier/parser-babylon';
import Highlight, {
defaultProps,
Language,
Expand All @@ -18,8 +26,10 @@ import ultramin from 'prism-react-renderer/themes/ultramin';
import vsDark from 'prism-react-renderer/themes/vsDark';
import { Styled } from 'theme-ui';
import copy from 'copy-to-clipboard';
import { transparentize } from 'polished';
import { ActionBar } from '../ActionBar';
import { BlockContainer } from '../BlockContainer';
import { getArgumentNames, mergeControlValues } from './argument-utils';

export type ThemeType =
| 'nightowl-light'
Expand Down Expand Up @@ -48,6 +58,7 @@ export const themes: {
dracula,
'shades-of-purple': shadesOfPurple,
};

export interface SourceProps {
children?: string;
language?: Language;
Expand All @@ -57,16 +68,42 @@ export interface SourceProps {
* componnet will not have a thmme selection option
*/
theme?: ThemeType;
/**
* options for the prettier integration
* if set to false, will utrn prettier off
*/
prettier?: null | Options;
/**
* a list of story arguments accepted by Source
* this is used to syntax-highlight the arguments
* and their usage
*/
args?: StoryArguments;

/**
* any control values to render in place of props in the editor
*/
controls?: LoadedComponentControls;
}

export const Source: FC<SourceProps> = ({
children = '',
language = 'jsx',
theme: parentTheme,
prettier: prettierOptions,
args,
controls,
}) => {
const [themeName, setThemeName] = React.useState<ThemeType>(
parentTheme || 'nightowl-light',
);

const [showMerged, setShowMerged] = React.useState<boolean>(
!!controls && !!args,
);
const parameters: string[] | undefined = args
? getArgumentNames(args)
: undefined;
let prismTheme = themes[themeName] || defaultProps.theme;
const [copied, setCopied] = React.useState(false);

Expand All @@ -77,6 +114,7 @@ export const Source: FC<SourceProps> = ({
setThemeName(themeKeys[newIdx] as ThemeType);
};

const onMergeValues = () => setShowMerged(!showMerged);
const onCopy = (e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
setCopied(true);
Expand All @@ -88,13 +126,39 @@ export const Source: FC<SourceProps> = ({
if (parentTheme === undefined) {
actions.push({ title: themeName, onClick: onRotateTheme });
}
if (controls && args) {
actions.push({ title: 'values', onClick: onMergeValues });
}

actions.push({ title: copied ? 'Copied' : 'Copy', onClick: onCopy });
let colorIdx = 0;
const colorRoll = parameters
? parameters.map(() => {
const style = prismTheme.styles[colorIdx];
const color: string =
style.style.color || prismTheme.plain.color || '#fff';
colorIdx = colorIdx < prismTheme.styles.length - 1 ? colorIdx + 1 : 0;
return color;
})
: [];
let code = typeof children === 'string' ? children : '';
if (showMerged && args && controls) {
code = mergeControlValues(code, args, controls);
}
const source =
prettierOptions !== null
? prettier.format(code, {
parser: 'babel',
plugins: [parserBabel],
...prettierOptions,
})
: code;
return (
<BlockContainer>
<Highlight
{...defaultProps}
theme={prismTheme}
code={typeof children === 'string' ? children : ''}
code={source}
language={language}
>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
Expand All @@ -104,12 +168,56 @@ export const Source: FC<SourceProps> = ({
>
{tokens.map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span
{...getTokenProps({ token, key })}
sx={{ display: 'inline-block' }}
/>
))}
{line.map((token, key) => {
const paramIdx = parameters
? parameters.indexOf(token.content.trim())
: -1;
const isParameterDefiinition =
paramIdx > -1 && token.types.indexOf('parameter') > -1;
const isParameterUsage =
paramIdx > -1 &&
((token.types.indexOf('attr-value') > -1 &&
token.types.indexOf('spread') > -1) ||
(token.types.indexOf('tag') > -1 &&
token.types.indexOf('script') > -1));
const isParam = isParameterDefiinition || isParameterUsage;
if (isParam) {
const splitToken = getTokenProps({
token,
key,
}).children.split(/(\s+)/);
console.log(splitToken);
return splitToken.map(s =>
s.trim().length ? (
<span
{...getTokenProps({ token, key })}
sx={{
display: 'inline-block',
backgroundColor: transparentize(
0.8,
colorRoll[paramIdx],
),
paddingLeft: 1,
paddingRight: 1,
border: `1px solid ${colorRoll[paramIdx]}`,
}}
>
{s}
</span>
) : (
s
),
);
}
return (
<span
{...getTokenProps({ token, key })}
sx={{
display: 'inline-block',
}}
/>
);
})}
</div>
))}
</Styled.pre>
Expand Down
Loading

0 comments on commit 1a90295

Please sign in to comment.