UNPKG

@progress/kendo-react-editor

Version:

React Editor enables users to create rich text content through a WYSIWYG interface. KendoReact Editor package

276 lines (275 loc) 10.9 kB
/** * @license *------------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the package root for more information *------------------------------------------------------------------------------------------- */ import * as t from "react"; import { Button as x } from "@progress/kendo-react-buttons"; import { Window as K } from "@progress/kendo-react-dialogs"; import { TabStrip as O, TabStripTab as y } from "@progress/kendo-react-layout"; import { registerForLocalization as U, provideLocalizationService as B } from "@progress/kendo-react-intl"; import { messages as l } from "../messages/index.mjs"; import { EditorToolsSettings as P } from "../config/toolsSettings.mjs"; import { formatString as q } from "../tools/utils.mjs"; import { TextSelection as E, find as V, replace as j, replaceAll as H, findAll as _, selectedLineTextOnly as $, textHighlightKey as G } from "@progress/kendo-editor-common"; import { IconWrap as T } from "@progress/kendo-react-common"; import { Checkbox as C, Input as M } from "@progress/kendo-react-inputs"; import { Form as b, FormElement as w, FieldWrapper as F } from "@progress/kendo-react-form"; import { Error as J } from "@progress/kendo-react-labels"; import { chevronLeftIcon as Q, chevronRightIcon as X } from "@progress/kendo-svg-icons"; const Y = 13, Z = 27, ee = P.findAndReplace; let te = class extends t.Component { constructor(s) { super(s), this.onTabSelect = (e) => { this.setState({ selectedTab: e.selected }); }, this.onClose = () => { const e = this.props.view, a = e.state, c = a.tr.setSelection( E.create(a.doc, a.selection.from, a.selection.to) ); e.updateState(a.apply(c)), e.focus(), this.props.onClose.call(void 0); }, this.matchesMessage = (e) => { const a = this.state.matches, c = this.state.nextMatch; let i = 0, o = 0; if (a && c) { const n = a.findIndex((r) => r.eq(c)); i = n === -1 ? a.length : n + 1, o = a.length; } return q(e, i, o); }, this.onFindNext = () => { this.onFind(); }, this.onFindPrev = () => { this.onFind(!0); }, this.onFind = (e = !1) => { const a = this.props.view, { searchText: c, matchCase: i, matchCyclic: o, matchWord: n, useRegExp: r } = this.state, h = { text: c, matchWord: n, matchCase: i, useRegExp: r, backward: e, matchCyclic: o }, m = V(a.state, h); if (m) { const g = a.state.tr.setSelection(m); g.scrollIntoView(), a.updateState(a.state.apply(g)), this.setState({ nextMatch: m }); } }, this.onReplace = () => { const e = this.props.view, a = e.state.selection, { replaceText: c } = this.state; if (!a.empty) { const i = a.from, o = i + c.length, n = j(a, c, e.state.tr); n.setSelection(E.create(n.doc, i, o)), n.scrollIntoView(), e.dispatch(n), this.setNextState({}); } }, this.onReplaceAll = () => { const e = this.props.view, { searchText: a, replaceText: c, matchCase: i, matchWord: o, useRegExp: n } = this.state, r = { text: a, matchWord: o, matchCase: i, useRegExp: n }, h = H(e.state, c, r); h && e.dispatch(h), this.setNextState({}); }, this.onKeyDown = (e) => { e.keyCode === Y ? this.onFindNext() : e.keyCode === Z && this.onClose(); }, this.onMatchCaseChecked = (e) => this.setNextState({ matchCase: e.value }), this.onMatchWordChecked = (e) => this.setNextState({ matchWord: e.value }), this.onMatchCyclicChecked = (e) => this.setNextState({ matchCyclic: e.value }), this.onUseRegExpChecked = (e) => this.setNextState({ useRegExp: e.value }), this.onSearchChange = (e) => this.setNextState({ searchText: e.target.value }), this.onReplaceChange = (e) => this.setNextState({ replaceText: e.target.value }), this.setNextState = (e) => { const a = { ...this.state, ...e, matches: void 0, nextMatch: void 0, error: void 0 }, c = this.props.view; if (a.searchText) { const { searchText: i, matchWord: o, matchCase: n, useRegExp: r, matchCyclic: h } = a, m = { text: i, matchWord: o, matchCase: n, useRegExp: r }, g = c.state.selection; let d = []; try { d = _(c.state.doc, m); } catch (p) { p instanceof SyntaxError && (a.error = this.settings.messages.findReplaceInvalidRegExp), this.setState(a); return; } const f = (p) => !p && d[0] || d.find((u) => u.from >= g.from) || h && d[0] || void 0; this.setState((p) => ({ ...a, matches: d, nextMatch: f(p.searchText) })); } else this.setState(a); }, this.state = { selectedTab: 0, searchText: $(s.view.state), replaceText: "", matchCase: !1, matchWord: !1, matchCyclic: !1, useRegExp: !1 }; } get settings() { return this.props.settings || ee; } /** * @hidden */ componentDidUpdate(s, e) { const a = this.props.view, { matches: c = [], nextMatch: i } = this.state; if (e.nextMatch !== i) { const o = a.state, n = o.tr, r = []; c.forEach((h) => { r.push({ from: h.from, to: h.to, attrs: { class: i && h.eq(i) ? "k-text-selected" : "k-text-highlighted" } }); }), n.setMeta(G, r), n.setSelection(i || E.create(o.doc, o.selection.from)), a.dispatch(n); } } /** * @hidden */ render() { const s = B(this), { findReplaceDialogTitle: e, findReplaceTabFind: a, findReplaceTabReplace: c, findReplaceFindWhat: i, findReplaceReplaceWith: o, findReplaceReplace: n, findReplaceReplaceAll: r, findReplaceMatchCase: h, findReplaceMatchWord: m, findReplaceMatchCyclic: g, findReplaceUseRegExp: d, findReplacePrevMatch: f, findReplaceNextMatch: p, findReplaceMatches: u } = this.settings.messages, { matchCase: N, matchWord: W, matchCyclic: L, useRegExp: A, searchText: z, replaceText: D, nextMatch: S } = this.state, R = /* @__PURE__ */ t.createElement("div", { className: "k-search-options" }, /* @__PURE__ */ t.createElement("span", null, /* @__PURE__ */ t.createElement( C, { id: "match-case", checked: N, onChange: this.onMatchCaseChecked, label: s.toLanguageString( h, l[h] ) } )), /* @__PURE__ */ t.createElement("span", null, /* @__PURE__ */ t.createElement( C, { id: "match-whole", checked: W, onChange: this.onMatchWordChecked, label: s.toLanguageString( m, l[m] ) } )), /* @__PURE__ */ t.createElement("span", null, /* @__PURE__ */ t.createElement( C, { id: "match-cyclic", checked: L, onChange: this.onMatchCyclicChecked, label: s.toLanguageString( g, l[g] ) } )), /* @__PURE__ */ t.createElement("span", null, /* @__PURE__ */ t.createElement( C, { id: "regular-expression", checked: A, onChange: this.onUseRegExpChecked, label: s.toLanguageString( d, l[d] ) } ))), v = /* @__PURE__ */ t.createElement("div", { className: "k-matches-container" }, /* @__PURE__ */ t.createElement(x, { fillMode: "flat", themeColor: "primary", onClick: this.onFindPrev }, /* @__PURE__ */ t.createElement(T, { name: "chevron-left", icon: Q }), s.toLanguageString(f, l[f])), /* @__PURE__ */ t.createElement("span", null, this.matchesMessage( s.toLanguageString(u, l[u]) )), /* @__PURE__ */ t.createElement(x, { fillMode: "flat", themeColor: "primary", onClick: this.onFindNext }, s.toLanguageString(p, l[p]), /* @__PURE__ */ t.createElement(T, { name: "chevron-right", icon: X }))), k = /* @__PURE__ */ t.createElement( b, { render: () => /* @__PURE__ */ t.createElement(w, { horizontal: !0 }, /* @__PURE__ */ t.createElement(F, null, /* @__PURE__ */ t.createElement("label", { htmlFor: "findWhat", className: "k-form-label" }, s.toLanguageString( i, l[i] )), /* @__PURE__ */ t.createElement("div", { className: "k-form-field-wrap" }, /* @__PURE__ */ t.createElement( M, { id: "findWhat", type: "text", value: z, onChange: this.onSearchChange, onFocus: this.onSearchChange, onKeyDown: this.onKeyDown, autoFocus: !0 } ), this.state.error && /* @__PURE__ */ t.createElement(J, null, s.toLanguageString( this.state.error, l[this.state.error] ))))) } ), I = /* @__PURE__ */ t.createElement( b, { render: () => /* @__PURE__ */ t.createElement(w, { horizontal: !0 }, /* @__PURE__ */ t.createElement(F, null, /* @__PURE__ */ t.createElement("label", { htmlFor: "replaceWith", className: "k-form-label" }, s.toLanguageString( o, l[o] )), /* @__PURE__ */ t.createElement("div", { className: "k-form-field-wrap" }, /* @__PURE__ */ t.createElement( M, { id: "replaceWith", type: "text", value: D, onChange: this.onReplaceChange } )))) } ); return /* @__PURE__ */ t.createElement( K, { title: s.toLanguageString(e, l[e]), onClose: this.onClose, style: { width: "auto", height: "auto", userSelect: "none" }, resizable: !1, minimizeButton: () => null, maximizeButton: () => null }, /* @__PURE__ */ t.createElement( O, { selected: this.state.selectedTab, className: "k-editor-find-replace", onSelect: this.onTabSelect, animation: !1 }, /* @__PURE__ */ t.createElement( y, { title: s.toLanguageString(a, l[a]) }, k, R, v ), /* @__PURE__ */ t.createElement( y, { title: s.toLanguageString( c, l[c] ) }, k, I, /* @__PURE__ */ t.createElement("div", { className: "k-actions k-hstack k-justify-content-end" }, /* @__PURE__ */ t.createElement(x, { disabled: !S, onClick: this.onReplace }, s.toLanguageString( n, l[n] )), /* @__PURE__ */ t.createElement(x, { disabled: !S, onClick: this.onReplaceAll }, s.toLanguageString( r, l[r] ))), R, v ) ) ); } }; U(te); export { te as FindAndReplaceDialog };