import React from 'react'; import classNames from 'classnames'; import JsonViewerFoundation, { JsonViewerOptions, JsonViewerAdapter, } from '@douyinfe/semi-foundation/jsonViewer/foundation'; import '@douyinfe/semi-foundation/jsonViewer/jsonViewer.scss'; import { cssClasses } from '@douyinfe/semi-foundation/jsonViewer/constants'; import ButtonGroup from '../button/buttonGroup'; import Button from '../button'; import Input from '../input'; import DragMove from '../dragMove'; import { IconCaseSensitive, IconChevronLeft, IconChevronRight, IconClose, IconRegExp, IconSearch, IconWholeWord, } from '@douyinfe/semi-icons'; import BaseComponent, { BaseProps } from '../_base/baseComponent'; import { createPortal } from 'react-dom'; import { isEqual } from "lodash"; import LocaleConsumer from '../locale/localeConsumer'; import { Locale } from '../locale/interface'; const prefixCls = cssClasses.PREFIX; export type { JsonViewerOptions }; export interface JsonViewerProps extends BaseProps { value: string; width: number | string; height: number | string; showSearch?: boolean; className?: string; style?: React.CSSProperties; onChange?: (value: string) => void; renderTooltip?: (value: string, el: HTMLElement) => HTMLElement; options?: JsonViewerOptions } export interface JsonViewerState { searchOptions: SearchOptions; showSearchBar: boolean; customRenderMap: Map } interface SearchOptions { caseSensitive: boolean; wholeWord: boolean; regex: boolean } class JsonViewerCom extends BaseComponent { static defaultProps: Partial = { width: 400, height: 400, value: '', options: { readOnly: false, autoWrap: true } }; private editorRef: React.RefObject; private searchInputRef: React.RefObject; private replaceInputRef: React.RefObject; private isComposing: boolean = false; foundation: JsonViewerFoundation; constructor(props: JsonViewerProps) { super(props); this.editorRef = React.createRef(); this.searchInputRef = React.createRef(); this.replaceInputRef = React.createRef(); this.foundation = new JsonViewerFoundation(this.adapter); this.state = { searchOptions: { caseSensitive: false, wholeWord: false, regex: false, }, showSearchBar: false, customRenderMap: new Map(), }; } componentDidMount() { this.foundation.init(); } componentDidUpdate(prevProps: JsonViewerProps): void { if (!isEqual(prevProps.options, this.props.options) || this.props.value !== prevProps.value) { this.foundation.jsonViewer.dispose(); this.foundation.init(); } } get adapter(): JsonViewerAdapter { return { ...super.adapter, getEditorRef: () => this.editorRef.current, getSearchRef: () => this.searchInputRef.current, notifyChange: value => { this.props.onChange?.(value); }, notifyHover: (value, el) => { const res = this.props.renderTooltip?.(value, el); return res; }, notifyCustomRender: (customRenderMap) => { this.setState({ customRenderMap }); }, setSearchOptions: (key: string) => { this.setState( { searchOptions: { ...this.state.searchOptions, [key]: !this.state.searchOptions[key], }, }, () => { this.searchHandler(); } ); }, showSearchBar: () => { this.setState({ showSearchBar: !this.state.showSearchBar }); }, }; } getValue() { return this.foundation.jsonViewer.getModel().getValue(); } format() { this.foundation.jsonViewer.format(); } getStyle() { const { width, height } = this.props; return { width, height, }; } searchHandler = () => { const value = this.searchInputRef.current?.value; this.foundation.search(value); }; changeSearchOptions = (key: string) => { this.foundation.setSearchOptions(key); }; renderSearchBox() { return (
{this.renderSearchBar()} {this.renderReplaceBar()}
); } renderSearchOptions() { const searchOptionItems = [ { key: 'caseSensitive', icon: IconCaseSensitive, }, { key: 'regex', icon: IconRegExp, }, { key: 'wholeWord', icon: IconWholeWord, }, ]; return (
    {searchOptionItems.map(({ key, icon: Icon }) => (
  • this.changeSearchOptions(key)} />
  • ))}
); } renderSearchBar() { return ( {(locale: Locale['JsonViewer'], localeCode: Locale['code']) => (
{ e.preventDefault(); if (!this.isComposing) { this.searchHandler(); } this.searchInputRef.current?.focus(); }} onCompositionStart={() => { this.isComposing = true; }} onCompositionEnd={() => { this.isComposing = false; this.searchHandler(); this.searchInputRef.current?.focus(); }} ref={this.searchInputRef} /> {this.renderSearchOptions()}
)}
); } renderReplaceBar() { const { readOnly } = this.props.options; return ( {(locale: Locale['JsonViewer'], localeCode: Locale['code']) => (
{ e.preventDefault(); }} ref={this.replaceInputRef} />
)}
); } render() { let isDragging = false; const { width, className, style, showSearch = true, ...rest } = this.props; return ( <>
{showSearch && ( { isDragging = false; }} onMouseMove={() => { isDragging = true; }} >
{!this.state.showSearchBar ? (
)}
{Array.from(this.state.customRenderMap.entries()).map(([key, value]) => { // key.innerHTML = ''; return createPortal(value, key); })} ); } } export default JsonViewerCom;