diff --git a/playground/docs.tsx b/playground/docs.tsx index dc863c3..c77f925 100644 --- a/playground/docs.tsx +++ b/playground/docs.tsx @@ -135,8 +135,7 @@ const Docs: React.FC = props => { const diff7 = React.useMemo(() => differ.diff(before7, after7), [differ, before7, after7]); const openInPlayground = (l: unknown, r: unknown) => { - updateInitialValues(JSON.stringify(l, null, 2), JSON.stringify(r, null, 2)); - props.onSwitch(); + updateInitialValues('playground', JSON.stringify(l, null, 2), JSON.stringify(r, null, 2)); }; const viewerCommonProps: Partial = { diff --git a/playground/generated-code.tsx b/playground/generated-code.tsx index d27a293..49f11e0 100644 --- a/playground/generated-code.tsx +++ b/playground/generated-code.tsx @@ -16,7 +16,9 @@ const GeneratedCode: React.FC = ({ code }) => { }, [code]); return ( -
+    
+
+    
); }; diff --git a/playground/index.tsx b/playground/index.tsx index b6e402d..2b88bc5 100644 --- a/playground/index.tsx +++ b/playground/index.tsx @@ -3,16 +3,23 @@ import ReactDOM from 'react-dom'; import Playground from './playground'; import Docs from './docs'; +import MarshallerTest from './marshaller-test'; import '../src/viewer.less'; import './index.less'; +import { updateInitialValues, useInitialValues } from './initial-values'; const Index: React.FC = () => { - const [usePlayground, setUsePlayground] = React.useState(true); + const { page } = useInitialValues(); - return usePlayground - ? setUsePlayground(false)} /> - : setUsePlayground(true)} />; + switch (page) { + case 'marshaller-test': + return ; + case 'docs': + return updateInitialValues('playground', '', '')} />; + default: + return updateInitialValues('docs', '', '')} />; + } }; ReactDOM.render(, document.getElementById('root')); diff --git a/playground/initial-values.ts b/playground/initial-values.ts index ded2750..6e87d54 100644 --- a/playground/initial-values.ts +++ b/playground/initial-values.ts @@ -4,6 +4,7 @@ const getValue = () => { const hash = window.location.hash ? window.location.hash.slice(1) : ''; const query = new URLSearchParams(hash); return { + page: query.get('page') || 'playground', l: query.get('l') || '', r: query.get('r') || '', }; @@ -15,22 +16,26 @@ export const useInitialValues = () => { React.useEffect(() => { const hashChange = () => { const newValue = getValue(); - if (initialValues.l !== newValue.l || initialValues.r !== newValue.r) { - setInitialValues(newValue); + for (const key in newValue) { + if (initialValues[key] !== newValue[key]) { + setInitialValues(newValue); + break; + } } }; window.addEventListener('hashchange', hashChange); return () => { window.removeEventListener('hashchange', hashChange); }; - }, []); + }, [initialValues]); return initialValues; }; -export const updateInitialValues = (l: string, r: string) => { +export const updateInitialValues = (page: string, l: string, r: string) => { const hash = window.location.hash ? window.location.hash.slice(1) : ''; const query = new URLSearchParams(hash); + query.set('page', page); query.set('l', l); query.set('r', r); window.location.hash = query.toString(); diff --git a/playground/marshaller-test.tsx b/playground/marshaller-test.tsx new file mode 100644 index 0000000..592b565 --- /dev/null +++ b/playground/marshaller-test.tsx @@ -0,0 +1,445 @@ +/* eslint-disable max-len, react/no-unescaped-entities */ + +import React from 'react'; +import debounce from 'lodash/debounce'; + +import { Differ, Marshaller, MarshallerConfig } from '../src'; +import type { DifferOptions, InlineDiffOptions } from '../src'; + +import GeneratedCode from './generated-code'; +import Label from './label'; +import { updateInitialValues, useInitialValues } from './initial-values'; + +import '../src/viewer-monokai.less'; +import './playground.less'; + +const MarshallerTest: React.FC = () => { + // differ props + const [detectCircular] = React.useState(true); + const [maxDepth, setMaxDepth] = React.useState(Infinity); + const [showModifications, setShowModifications] = React.useState(true); + const [arrayDiffMethod, setArrayDiffMethod] = React.useState('lcs'); + const [ignoreCase, setIgnoreCase] = React.useState(false); + const [ignoreCaseForKey, setIgnoreCaseForKey] = React.useState(false); + const [recursiveEqual, setRecursiveEqual] = React.useState(true); + const [preserveKeyOrder, setPreserveKeyOrder] = React.useState(undefined); + + // viewer props + const [indent, setIndent] = React.useState(4); + const [highlightInlineDiff, setHighlightInlineDiff] = React.useState(true); + const [inlineDiffMode, setInlineDiffMode] = React.useState('word'); + const [inlineDiffSeparator, setInlineDiffSeparator] = React.useState(' '); + const [hideUnchangedLines, setHideUnchangedLines] = React.useState(true); + const [syntaxHighlight, setSyntaxHighlight] = React.useState(false); + + const differOptions = React.useMemo(() => ({ + detectCircular, + maxDepth, + showModifications, + arrayDiffMethod, + ignoreCase, + ignoreCaseForKey, + recursiveEqual, + preserveKeyOrder, + }), [ + detectCircular, + maxDepth, + showModifications, + arrayDiffMethod, + ignoreCase, + ignoreCaseForKey, + recursiveEqual, + preserveKeyOrder, + ]); + const differ = React.useMemo(() => new Differ(differOptions), [differOptions]); + const [diff, setDiff] = React.useState(differ.diff('', '')); + const [fullscreen, setFullscreen] = React.useState(false); + const [showHTMLSource, setShowHTMLSource] = React.useState(false); + const [error, setError] = React.useState(''); + + const _triggerDiff = (before: string, after: string) => { + try { + const result = differ.diff( + JSON.parse(String(before || 'null')), + JSON.parse(String(after || 'null')), + ); + setError(''); + setDiff(result); + } catch (e) { + setError(e.message); + console.error(e); // eslint-disable-line no-console + } + }; + const triggerDiff = React.useCallback(debounce(_triggerDiff, 500), [differ]); + + const inlineDiffOptions = React.useMemo(() => ({ + mode: inlineDiffMode, + wordSeparator: inlineDiffSeparator, + }), [inlineDiffMode, inlineDiffSeparator]); + const viewerOptions: Omit = React.useMemo(() => ({ + indent, + lineNumbers: true, + highlightInlineDiff, + inlineDiffOptions, + hideUnchangedLines, + syntaxHighlight: syntaxHighlight ? { theme: 'monokai' } : false, + }), [ + indent, + highlightInlineDiff, + inlineDiffOptions, + hideUnchangedLines, + syntaxHighlight, + ]); + + // inputs + const { l, r } = useInitialValues(); + const beforeRef = React.useRef(l || ''); + const afterRef = React.useRef(r || ''); + const beforeInputRef = React.useRef(null); + const afterInputRef = React.useRef(null); + const setBefore = (value: string, diff: boolean) => { + beforeRef.current = value; + updateInitialValues('marshaller-test', beforeRef.current, afterRef.current); + if (diff) { + triggerDiff(beforeRef.current, afterRef.current); + } + }; + const setAfter = (value: string, diff: boolean) => { + afterRef.current = value; + updateInitialValues('marshaller-test', beforeRef.current, afterRef.current); + if (diff) { + triggerDiff(beforeRef.current, afterRef.current); + } + }; + const clearAll = () => { + beforeRef.current = ''; + afterRef.current = ''; + updateInitialValues('marshaller-test', '', ''); + }; + const beautify = () => { + let before = ''; + let after = ''; + try { + if (beforeRef) { + before = JSON.stringify(JSON.parse(beforeRef.current || 'null'), null, 2); + } + if (afterRef) { + after = JSON.stringify(JSON.parse(afterRef.current || 'null'), null, 2); + } + } catch (e) { + setError(e.message); + console.error(e); // eslint-disable-line no-console + } + if (before || after) { + beforeInputRef.current!.value = before; + afterInputRef.current!.value = after; + setBefore(before, false); + setAfter(after, false); + updateInitialValues('marshaller-test', before, after); + } + }; + React.useEffect(() => { + if (l !== beforeRef.current || r !== afterRef.current) { + setBefore(l || '', false); + setAfter(r || '', false); + triggerDiff(l, r); + } + }, [l, r]); + React.useEffect(() => { + _triggerDiff(beforeRef.current, afterRef.current); + }, [differOptions]); + + return ( +
+
+
Marshaller Test
+
+
+ DIFFER CONFIGURATION +
+
+
+ VIEWER CONFIGURATION +
+
+ +