@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
JavaScript
/**
* @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
};