Skip to content

Commit

Permalink
fix: add ReactLivePreview (#201)
Browse files Browse the repository at this point in the history
* fix: LivePreview

* fix: add ReactLivePreview

* fix:changeset

* fix: delete .changeset/odd-icons-clap.md
  • Loading branch information
51wangping authored May 15, 2024
1 parent 864278a commit 8590b36
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/hot-bobcats-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'kubed-documents': minor
---

fix: LivePreview
6 changes: 4 additions & 2 deletions docs/lib/components/CodeBox/CodeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import styled from 'styled-components';
import Prism from './Prism';

interface CodeEditorProps {
code: string;
fontFamily?: string;
className?: string;
onChange: (code: string) => void;
}

interface StateProps {
Expand All @@ -26,9 +28,9 @@ const EditorContainer = styled.div`
}
`;

export default function CodeEditor({ fontFamily, className }: CodeEditorProps) {
export default function CodeEditor({ fontFamily, className, code, onChange }: CodeEditorProps) {
// @ts-ignore
const { code, language, onChange } = useContext(LiveContext);
const { language } = useContext(LiveContext);
const [state, setState] = useState<StateProps>({ code: code || '' });

useEffect(() => {
Expand Down
44 changes: 44 additions & 0 deletions docs/lib/components/CodeBox/ReactLivePreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { LiveProvider } from 'react-live';
import React, { useState } from 'react';
import { useTheme } from '@kubed/components';
import { Language } from 'prism-react-renderer';
import LivePreview from './LivePreview';
import CodeEditor from './CodeEditor';
import { useCodeDemo } from './use-code-demo';
import { dark, light } from './prismTheme';

interface ReactLivePreviewProps {
code: string;
language: Language;
scope: { [key: string]: any };
}
const ReactLivePreview = ({ code: originCode, language, scope }: ReactLivePreviewProps) => {
const theme = useTheme();
const prismTheme = theme.type === 'dark' ? dark : light;
const [preViewCode, setPreViewCode] = useState<string>(originCode);
const { code, noInline } = useCodeDemo({ scope, code: preViewCode });

return (
<LiveProvider
language={language}
noInline={noInline}
code={code}
scope={scope}
theme={prismTheme}
>
<div>
<LivePreview />
<CodeEditor
code={originCode}
onChange={(val) => {
setPreViewCode(val);
}}
fontFamily={theme.font.mono}
className="code-editor"
/>
</div>
</LiveProvider>
);
};

export default ReactLivePreview;
9 changes: 3 additions & 6 deletions docs/lib/components/CodeBox/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { useContext } from 'react';
import React, { useContext, useState } from 'react';
import { Language } from 'prism-react-renderer';
import { LiveProvider } from 'react-live';
import { mdx, MDXContext } from '@mdx-js/react';
import styled from 'styled-components';
import { useTheme } from '@kubed/components';
import { dark, light } from './prismTheme';
import ReactLivePreview from './ReactLivePreview';

import CodeEditor from './CodeEditor';
import Prism from './Prism';
import LivePreview from './LivePreview';

Expand Down Expand Up @@ -78,10 +78,7 @@ export default function CodeBox({
if (live) {
return (
<CodeBoxWrapper live>
<LiveProvider language={language} code={children.trim()} scope={scope} theme={prismTheme}>
<LivePreview />
<CodeEditor fontFamily={theme.font.mono} className="code-editor" />
</LiveProvider>
<ReactLivePreview language={language} code={children} scope={scope} />
</CodeBoxWrapper>
);
}
Expand Down
65 changes: 65 additions & 0 deletions docs/lib/components/CodeBox/use-code-demo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { get, cloneDeep } from 'lodash';
import * as React from 'react';

export const useCodeDemo = ({ scope, code: inputCode }) => {
let code = cloneDeep(inputCode?.trim());
let noInline = false;

const scopeKeys = Object.keys(scope);
const scopeValues = scopeKeys.map((key) => {
return { [key]: `${key}` };
});

// add 'React' to scopeValues
scopeValues.push({ React: 'React' });
// convert scopeValues to object
const imports = Object.assign({}, ...scopeValues);
code = transformCode(code, imports);
noInline = code.includes('render');
return {
code,
noInline,
};
};

const importRegex = /^(import)\s(?!type(of\s|\s)(?!from)).*?$/gm;
const exportDefaultRegex = /export\s+default\s+function\s+\w+\s*\(\s*\)\s*\{/;

export const transformCode = (code: string, imports = {}, compName = 'App') => {
let cleanedCode = code
.replace(importRegex, (match) => {
// get component name from the match ex. "import { Table } from '@nextui-org/react'"

let componentName = match.match(/\w+/g)?.[1] || '';
// replace as
componentName = componentName === 'as' ? match.match(/\w+/g)?.[2] || '' : componentName;

const matchingImport = get(imports, componentName);

if (matchingImport) {
// remove the matching import
return '';
}

// if match includes './' or '../' then remove it
if (match.includes('./') || match.includes('../')) {
return '';
}

return match;
})
.replace(exportDefaultRegex, () => {
// replace match with const Name = () => (
return `const ${compName} = () => {`;
})
.replace('export', '');

// add render(<App/>) to cleanedCode if has const App = () => {
if (cleanedCode.includes(`const App = () => {`)) {
cleanedCode = `${cleanedCode}\nrender(<${compName}/>);`;
}
// delete comments from the code
cleanedCode = cleanedCode.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '');

return cleanedCode;
};
48 changes: 47 additions & 1 deletion docs/lib/components/GlobalStyles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,53 @@ const GlobalStyles = createGlobalStyle`
html,
body {
background-color: ${({ theme }) => theme.palette.background};
//color: #242e42;
}
table {
width: 100%;
border-collapse: collapse;
th {
padding: 0 8px;
vertical-align: middle;
height: 40px;
color: ${({ theme }) => theme.palette.accents_7};
background-color: ${({ theme }) => theme.palette.accents_1};
border-radius: 0;
border-top: 1px solid ${({ theme }) => theme.palette.border};
border-bottom: 1px solid ${({ theme }) => theme.palette.border};
&:nth-child(1) {
border: 1px solid ${({ theme }) => theme.palette.border};
border-right-width: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
&:last-child {
border: 1px solid ${({ theme }) => theme.palette.border};
border-left-width: 0;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
}
thead {
tr {
text-align: left;
}
}
tbody {
tr {
transition: background-color 0.25s ease;
&:hover {
background-color: ${({ theme }) => theme.palette.accents_1};
}
}
td {
padding: 0 8px;
border-bottom: 1px solid ${({ theme }) => theme.palette.border};
height: 45px;
}
}
}
`;

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"repository": "https://github.com/kubesphere/kube-design",
"license": "MIT",
"scripts": {
"start:docs": "cd ./docs && npm run dev",
"postinstall": "npm run docs:docgen && npm run build:icons",
"syncpack": "syncpack list-mismatches",
"typecheck": "tsc --noEmit",
Expand Down

0 comments on commit 8590b36

Please sign in to comment.