| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 | 
							- 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";
 
- 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<HTMLElement, React.ReactNode>
 
- }
 
- interface SearchOptions {
 
-     caseSensitive: boolean;
 
-     wholeWord: boolean;
 
-     regex: boolean
 
- }
 
- class JsonViewerCom extends BaseComponent<JsonViewerProps, JsonViewerState> {
 
-     static defaultProps: Partial<JsonViewerProps> = {
 
-         width: 400,
 
-         height: 400,
 
-         value: '',
 
-         options: {
 
-             readOnly: false,
 
-             autoWrap: true
 
-         }
 
-     };
 
-     private editorRef: React.RefObject<HTMLDivElement>;
 
-     private searchInputRef: React.RefObject<HTMLInputElement>;
 
-     private replaceInputRef: React.RefObject<HTMLInputElement>;
 
-     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<JsonViewerProps, JsonViewerState> {
 
-         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 (
 
-             <div className={`${prefixCls}-search-bar-container`} style={{ position: 'absolute', top: 20, right: 20 }}>
 
-                 {this.renderSearchBar()}
 
-                 {this.renderReplaceBar()}
 
-             </div>
 
-         );
 
-     }
 
-     renderSearchOptions() {
 
-         const searchOptionItems = [
 
-             {
 
-                 key: 'caseSensitive',
 
-                 icon: IconCaseSensitive,
 
-             },
 
-             {
 
-                 key: 'regex',
 
-                 icon: IconRegExp,
 
-             },
 
-             {
 
-                 key: 'wholeWord',
 
-                 icon: IconWholeWord,
 
-             },
 
-         ];
 
-         return (
 
-             <ul className={`${prefixCls}-search-options`}>
 
-                 {searchOptionItems.map(({ key, icon: Icon }) => (
 
-                     <li
 
-                         key={key}
 
-                         className={classNames(`${prefixCls}-search-options-item`, {
 
-                             [`${prefixCls}-search-options-item-active`]: this.state.searchOptions[key],
 
-                         })}
 
-                     >
 
-                         <Icon onClick={() => this.changeSearchOptions(key)} />
 
-                     </li>
 
-                 ))}
 
-             </ul>
 
-         );
 
-     }
 
-     renderSearchBar() {
 
-         return (
 
-             <div className={`${prefixCls}-search-bar`}>
 
-                 <Input
 
-                     placeholder="查找"
 
-                     className={`${prefixCls}-search-bar-input`}
 
-                     onChange={(_value, e) => {
 
-                         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()}
 
-                 <ButtonGroup>
 
-                     <Button
 
-                         icon={<IconChevronLeft />}
 
-                         onClick={e => {
 
-                             e.preventDefault();
 
-                             this.foundation.prevSearch();
 
-                         }}
 
-                     />
 
-                     <Button
 
-                         icon={<IconChevronRight />}
 
-                         onClick={e => {
 
-                             e.preventDefault();
 
-                             this.foundation.nextSearch();
 
-                         }}
 
-                     />
 
-                 </ButtonGroup>
 
-                 <Button
 
-                     icon={<IconClose />}
 
-                     size="small"
 
-                     theme={'borderless'}
 
-                     type={'tertiary'}
 
-                     onClick={() => this.foundation.showSearchBar()}
 
-                 />
 
-             </div>
 
-         );
 
-     }
 
-     renderReplaceBar() {
 
-         const { readOnly } = this.props.options;
 
-         return (
 
-             <div className={`${prefixCls}-replace-bar`}>
 
-                 <Input
 
-                     placeholder="替换"
 
-                     className={`${prefixCls}-replace-bar-input`}
 
-                     onChange={(value, e) => {
 
-                         e.preventDefault();
 
-                     }}
 
-                     ref={this.replaceInputRef}
 
-                 />
 
-                 <Button
 
-                     disabled={readOnly}
 
-                     onClick={() => {
 
-                         const value = this.replaceInputRef.current?.value;
 
-                         this.foundation.replace(value);
 
-                     }}
 
-                 >
 
-                     替换
 
-                 </Button>
 
-                 <Button
 
-                     disabled={readOnly}
 
-                     onClick={() => {
 
-                         const value = this.replaceInputRef.current?.value;
 
-                         this.foundation.replaceAll(value);
 
-                     }}
 
-                 >
 
-                     全部替换
 
-                 </Button>
 
-             </div>
 
-         );
 
-     }
 
-     render() {
 
-         let isDragging = false;
 
-         const { width, className, style, showSearch = true, ...rest } = this.props;
 
-         return (
 
-             <>
 
-                 <div style={{ ...this.getStyle(), position: 'relative', ...style }} className={className} {...this.getDataAttr(rest)}>
 
-                     <div
 
-                         style={{ ...this.getStyle(), padding: '12px 0' }}
 
-                         ref={this.editorRef}
 
-                         className={classNames(prefixCls, `${prefixCls}-background`)}
 
-                     ></div>
 
-                     {showSearch && (
 
-                         <DragMove
 
-                             onMouseDown={() => {
 
-                                 isDragging = false;
 
-                             }}
 
-                             onMouseMove={() => {
 
-                                 isDragging = true;
 
-                             }}
 
-                         >
 
-                             <div style={{ position: 'absolute', top: 0, left: width }}>
 
-                                 {!this.state.showSearchBar ? (
 
-                                     <Button
 
-                                         className={`${prefixCls}-search-bar-trigger`}
 
-                                         onClick={e => {
 
-                                             e.preventDefault();
 
-                                             if (isDragging) {
 
-                                                 e.stopPropagation();
 
-                                                 e.preventDefault();
 
-                                                 return;
 
-                                             }
 
-                                             this.foundation.showSearchBar();
 
-                                         }}
 
-                                         icon={<IconSearch />}
 
-                                         style={{ position: 'absolute', top: 20, right: 20 }}
 
-                                     />
 
-                                 ) : (
 
-                                     this.renderSearchBox()
 
-                                 )}
 
-                             </div>
 
-                         </DragMove>
 
-                     )}
 
-                 </div>
 
-                 {Array.from(this.state.customRenderMap.entries()).map(([key, value]) => {
 
-                     // key.innerHTML = '';
 
-                     return createPortal(value, key);
 
-                 })}
 
-             </>
 
-         );
 
-     }
 
- }
 
- export default JsonViewerCom;
 
 
  |