UNPKG

@douyinfe/semi-ui

Version:

A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.

422 lines (421 loc) 15.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _isEqual2 = _interopRequireDefault(require("lodash/isEqual")); var _react = _interopRequireDefault(require("react")); var _classnames = _interopRequireDefault(require("classnames")); var _foundation = _interopRequireDefault(require("@douyinfe/semi-foundation/lib/cjs/jsonViewer/foundation")); require("@douyinfe/semi-foundation/lib/cjs/jsonViewer/jsonViewer.css"); var _constants = require("@douyinfe/semi-foundation/lib/cjs/jsonViewer/constants"); var _buttonGroup = _interopRequireDefault(require("../button/buttonGroup")); var _button = _interopRequireDefault(require("../button")); var _input = _interopRequireDefault(require("../input")); var _dragMove = _interopRequireDefault(require("../dragMove")); var _semiIcons = require("@douyinfe/semi-icons"); var _baseComponent = _interopRequireDefault(require("../_base/baseComponent")); var _reactDom = require("react-dom"); var _localeConsumer = _interopRequireDefault(require("../locale/localeConsumer")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } var __rest = void 0 && (void 0).__rest || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; const prefixCls = _constants.cssClasses.PREFIX; class JsonViewerCom extends _baseComponent.default { constructor(props) { super(props); this.isComposing = false; this.resizeObserver = null; this.resizeRafId = null; this.lastObservedWidth = null; this.searchHandler = () => { var _a; const value = (_a = this.searchInputRef.current) === null || _a === void 0 ? void 0 : _a.value; this.foundation.search(value); }; this.changeSearchOptions = key => { this.foundation.setSearchOptions(key); }; this.editorRef = /*#__PURE__*/_react.default.createRef(); this.searchInputRef = /*#__PURE__*/_react.default.createRef(); this.replaceInputRef = /*#__PURE__*/_react.default.createRef(); this.foundation = new _foundation.default(this.adapter); this.state = { searchOptions: { caseSensitive: false, wholeWord: false, regex: false }, showSearchBar: false, customRenderMap: new Map() }; } componentDidMount() { this.foundation.init(); this.setupResizeObserver(); } teardownResizeObserver() { if (this.resizeObserver) { this.resizeObserver.disconnect(); this.resizeObserver = null; } if (this.resizeRafId !== null) { cancelAnimationFrame(this.resizeRafId); this.resizeRafId = null; } this.lastObservedWidth = null; } setupResizeObserver() { var _a; // Only needed for autoWrap, since line wraps depend on container width. if (!((_a = this.props.options) === null || _a === void 0 ? void 0 : _a.autoWrap)) { this.teardownResizeObserver(); return; } const el = this.editorRef.current; if (!el || typeof ResizeObserver === 'undefined') { return; } // Avoid duplicated observers when re-init. this.teardownResizeObserver(); this.lastObservedWidth = el.getBoundingClientRect().width; this.resizeObserver = new ResizeObserver(entries => { var _a; const entry = entries && entries[0]; if (!entry) { return; } const nextWidth = (_a = entry.contentRect) === null || _a === void 0 ? void 0 : _a.width; if (typeof nextWidth !== 'number') { return; } // Only react to width changes, which affect wrapping. if (this.lastObservedWidth !== null && Math.abs(nextWidth - this.lastObservedWidth) < 0.5) { return; } this.lastObservedWidth = nextWidth; // Coalesce multiple resize events. if (this.resizeRafId !== null) { cancelAnimationFrame(this.resizeRafId); } this.resizeRafId = requestAnimationFrame(() => { var _a; this.resizeRafId = null; // Clear measured heights cache when container size changes. // NOTE: _view and _measuredHeights are internal implementation details. const jsonViewer = this.foundation.jsonViewer; if (jsonViewer && jsonViewer._view && jsonViewer._view._measuredHeights) { jsonViewer._view._measuredHeights = {}; } (_a = this.foundation.jsonViewer) === null || _a === void 0 ? void 0 : _a.layout(); }); }); this.resizeObserver.observe(el); } componentWillUnmount() { var _a, _b; this.teardownResizeObserver(); // Release the underlying editor instance to avoid leaking DOM listeners / // language workers across mount cycles. componentDidUpdate's re-init path // already calls dispose(); the unmount path was missing the symmetric call. (_b = (_a = this.foundation.jsonViewer) === null || _a === void 0 ? void 0 : _a.dispose) === null || _b === void 0 ? void 0 : _b.call(_a); super.componentWillUnmount(); } componentDidUpdate(prevProps) { var _a, _b; if (!(0, _isEqual2.default)(prevProps.options, this.props.options) || this.props.value !== prevProps.value) { this.foundation.jsonViewer.dispose(); this.foundation.init(); this.setupResizeObserver(); return; } // autoWrap toggle may require attaching/detaching observer. if (((_a = prevProps.options) === null || _a === void 0 ? void 0 : _a.autoWrap) !== ((_b = this.props.options) === null || _b === void 0 ? void 0 : _b.autoWrap)) { this.setupResizeObserver(); } } get adapter() { return Object.assign(Object.assign({}, super.adapter), { getEditorRef: () => this.editorRef.current, getSearchRef: () => this.searchInputRef.current, notifyChange: value => { var _a, _b; (_b = (_a = this.props).onChange) === null || _b === void 0 ? void 0 : _b.call(_a, value); }, notifyHover: (value, el) => { var _a, _b; const res = (_b = (_a = this.props).renderTooltip) === null || _b === void 0 ? void 0 : _b.call(_a, value, el); return res; }, notifyCustomRender: customRenderMap => { this.setState({ customRenderMap }); }, setSearchOptions: key => { this.setState({ searchOptions: Object.assign(Object.assign({}, this.state.searchOptions), { [key]: !this.state.searchOptions[key] }) }, () => { this.searchHandler(); }); }, showSearchBar: () => { this.setState({ showSearchBar: !this.state.showSearchBar }); this.setState({ searchOptions: { caseSensitive: false, wholeWord: false, regex: false } }); } }); } getValue() { return this.foundation.jsonViewer.getModel().getValue(); } format() { this.foundation.jsonViewer.format(); } search(searchText, caseSensitive, wholeWord, regex) { this.foundation.search(searchText, caseSensitive, wholeWord, regex); } getSearchResults() { return this.foundation.getSearchResults(); } prevSearch(step) { this.foundation.prevSearch(step); } nextSearch(step) { this.foundation.nextSearch(step); } replace(replaceText) { this.foundation.replace(replaceText); } replaceAll(replaceText) { this.foundation.replaceAll(replaceText); } getStyle() { const { width, height } = this.props; return { width, height }; } renderSearchBox() { return /*#__PURE__*/_react.default.createElement("div", { className: `${prefixCls}-search-bar-container`, style: { position: 'absolute', top: 20, right: 20 } }, this.renderSearchBar(), this.renderReplaceBar()); } renderSearchOptions() { const searchOptionItems = [{ key: 'caseSensitive', icon: _semiIcons.IconCaseSensitive }, { key: 'regex', icon: _semiIcons.IconRegExp }, { key: 'wholeWord', icon: _semiIcons.IconWholeWord }]; return /*#__PURE__*/_react.default.createElement("ul", { className: `${prefixCls}-search-options` }, searchOptionItems.map(_ref => { let { key, icon: Icon } = _ref; return /*#__PURE__*/_react.default.createElement("li", { key: key, className: (0, _classnames.default)(`${prefixCls}-search-options-item`, { [`${prefixCls}-search-options-item-active`]: this.state.searchOptions[key] }) }, /*#__PURE__*/_react.default.createElement(Icon, { onClick: () => this.changeSearchOptions(key) })); })); } renderSearchBar() { return /*#__PURE__*/_react.default.createElement(_localeConsumer.default, { componentName: "JsonViewer" }, (locale, localeCode) => (/*#__PURE__*/_react.default.createElement("div", { className: `${prefixCls}-search-bar` }, /*#__PURE__*/_react.default.createElement(_input.default, { placeholder: locale.search, className: `${prefixCls}-search-bar-input`, onChange: (_value, e) => { var _a; e.preventDefault(); if (!this.isComposing) { this.searchHandler(); } (_a = this.searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); }, onCompositionStart: () => { this.isComposing = true; }, onCompositionEnd: () => { var _a; this.isComposing = false; this.searchHandler(); (_a = this.searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); }, ref: this.searchInputRef }), this.renderSearchOptions(), /*#__PURE__*/_react.default.createElement(_buttonGroup.default, null, /*#__PURE__*/_react.default.createElement(_button.default, { icon: /*#__PURE__*/_react.default.createElement(_semiIcons.IconChevronLeft, null), onClick: e => { e.preventDefault(); this.foundation.prevSearch(); } }), /*#__PURE__*/_react.default.createElement(_button.default, { icon: /*#__PURE__*/_react.default.createElement(_semiIcons.IconChevronRight, null), onClick: e => { e.preventDefault(); this.foundation.nextSearch(); } })), /*#__PURE__*/_react.default.createElement(_button.default, { icon: /*#__PURE__*/_react.default.createElement(_semiIcons.IconClose, null), size: "small", theme: 'borderless', type: 'tertiary', onClick: () => this.foundation.showSearchBar() })))); } renderReplaceBar() { const { readOnly } = this.props.options; return /*#__PURE__*/_react.default.createElement(_localeConsumer.default, { componentName: "JsonViewer" }, (locale, localeCode) => (/*#__PURE__*/_react.default.createElement("div", { className: `${prefixCls}-replace-bar` }, /*#__PURE__*/_react.default.createElement(_input.default, { placeholder: locale.replace, className: `${prefixCls}-replace-bar-input`, onChange: (value, e) => { e.preventDefault(); }, ref: this.replaceInputRef }), /*#__PURE__*/_react.default.createElement(_button.default, { style: { width: 'fit-content' }, disabled: readOnly, onClick: () => { var _a; const value = (_a = this.replaceInputRef.current) === null || _a === void 0 ? void 0 : _a.value; this.foundation.replace(value); } }, locale.replace), /*#__PURE__*/_react.default.createElement(_button.default, { style: { width: 'fit-content' }, disabled: readOnly, onClick: () => { var _a; const value = (_a = this.replaceInputRef.current) === null || _a === void 0 ? void 0 : _a.value; this.foundation.replaceAll(value); } }, locale.replaceAll)))); } render() { let isDragging = false; const _a = this.props, { width, className, style, showSearch = true, limitSearchButtonBounds, renderSearchButton } = _a, rest = __rest(_a, ["width", "className", "style", "showSearch", "limitSearchButtonBounds", "renderSearchButton"]); // Default search button const defaultSearchButton = /*#__PURE__*/_react.default.createElement(_dragMove.default, { constrainer: limitSearchButtonBounds ? 'parent' : undefined, onMouseDown: () => { isDragging = false; }, onMouseMove: () => { isDragging = true; } }, /*#__PURE__*/_react.default.createElement("div", { style: { position: 'absolute', top: 0, left: width } }, !this.state.showSearchBar ? (/*#__PURE__*/_react.default.createElement(_button.default, { className: `${prefixCls}-search-bar-trigger`, onClick: e => { e.preventDefault(); if (isDragging) { e.stopPropagation(); e.preventDefault(); return; } this.foundation.showSearchBar(); }, icon: /*#__PURE__*/_react.default.createElement(_semiIcons.IconSearch, null), style: { position: 'absolute', top: 20, right: 20 } })) : this.renderSearchBox())); // Search controls for custom render const searchControls = { showSearchBar: this.state.showSearchBar, onToggleSearchBar: () => this.foundation.showSearchBar(), onSearch: (text, caseSensitive, wholeWord, regex) => { this.foundation.search(text, caseSensitive, wholeWord, regex); }, onPrevSearch: () => this.foundation.prevSearch(), onNextSearch: () => this.foundation.nextSearch(), onReplace: text => this.foundation.replace(text), onReplaceAll: text => this.foundation.replaceAll(text) }; return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", Object.assign({ style: Object.assign(Object.assign(Object.assign({}, this.getStyle()), { position: 'relative' }), style), className: className }, this.getDataAttr(rest)), /*#__PURE__*/_react.default.createElement("div", { style: Object.assign({}, this.getStyle()), ref: this.editorRef, className: (0, _classnames.default)(prefixCls, `${prefixCls}-background`) }), showSearch && (renderSearchButton ? renderSearchButton(defaultSearchButton, searchControls) : defaultSearchButton)), Array.from(this.state.customRenderMap.entries()).map(_ref2 => { let [key, value] = _ref2; // key.innerHTML = ''; return /*#__PURE__*/(0, _reactDom.createPortal)(value, key); })); } } JsonViewerCom.defaultProps = { width: 400, height: 400, value: '', options: { readOnly: false, autoWrap: true } }; var _default = exports.default = JsonViewerCom;