@atlaskit/editor-plugin-find-replace
Version:
find replace plugin for @atlaskit/editor-core
275 lines (274 loc) • 10.8 kB
JavaScript
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import React, { useState, useRef, useEffect } from 'react';
import { injectIntl } from 'react-intl';
import Button from '@atlaskit/button/new';
import { ACTION, ACTION_SUBJECT, EVENT_TYPE, TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
import { findReplaceMessages as messages } from '@atlaskit/editor-common/messages';
import { ValidMessage } from '@atlaskit/form';
import ChevronDownIcon from '@atlaskit/icon/core/chevron-down';
import ChevronUpIcon from '@atlaskit/icon/core/chevron-up';
// eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- to be migrated to @atlaskit/primitives/compiled – go/akcss
import { Box, Inline, Text, xcss } from '@atlaskit/primitives';
import Textfield from '@atlaskit/textfield';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { FindReplaceTooltipButton } from './FindReplaceTooltipButton';
var replaceContainerStyles = xcss({
padding: 'space.100'
});
var replaceWithLabelStyle = xcss({
paddingBottom: 'space.050'
});
var actionButtonContainerStyles = xcss({
paddingTop: 'space.200'
});
var actionButtonParentInlineStyles = xcss({
justifyContent: 'space-between',
flexDirection: 'row-reverse'
});
var actionButtonParentInlineStylesNew = xcss({
justifyContent: 'space-between',
flexDirection: 'row-reverse',
flexWrap: 'wrap'
});
var actionButtonInlineStyles = xcss({
gap: 'space.075'
});
var closeButtonInlineStyles = xcss({
marginRight: 'auto'
});
var Replace = function Replace(_ref) {
var canReplace = _ref.canReplace,
initialReplaceText = _ref.replaceText,
onReplace = _ref.onReplace,
onReplaceAll = _ref.onReplaceAll,
onReplaceTextfieldRefSet = _ref.onReplaceTextfieldRefSet,
onArrowUp = _ref.onArrowUp,
onCancel = _ref.onCancel,
count = _ref.count,
onFindNext = _ref.onFindNext,
onFindPrev = _ref.onFindPrev,
dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent,
setFindTyped = _ref.setFindTyped,
findTyped = _ref.findTyped,
focusToolbarButton = _ref.focusToolbarButton,
formatMessage = _ref.intl.formatMessage;
var _useState = useState(initialReplaceText || ''),
_useState2 = _slicedToArray(_useState, 2),
replaceText = _useState2[0],
setReplaceText = _useState2[1];
var _useState3 = useState(false),
_useState4 = _slicedToArray(_useState3, 2),
isComposing = _useState4[0],
setIsComposing = _useState4[1];
var _useState5 = useState(false),
_useState6 = _slicedToArray(_useState5, 2),
isHelperMessageVisible = _useState6[0],
setIsHelperMessageVisible = _useState6[1];
var _useState7 = useState(false),
_useState8 = _slicedToArray(_useState7, 2),
fakeSuccessReplacementMessageUpdate = _useState8[0],
setFakeSuccessReplacementMessageUpdate = _useState8[1];
var _useState9 = useState(0),
_useState0 = _slicedToArray(_useState9, 2),
replaceCount = _useState0[0],
setReplaceCount = _useState0[1];
var replaceTextfieldRef = useRef(null);
var successReplacementMessageRef = useRef(null);
var replaceWith = formatMessage(messages.replaceWith);
var replaceAll = formatMessage(messages.replaceAll);
var findPrevious = formatMessage(messages.findPrevious);
var closeFindReplaceDialog = formatMessage(messages.closeFindReplaceDialog);
useEffect(function () {
onReplaceTextfieldRefSet(replaceTextfieldRef);
}, [onReplaceTextfieldRefSet]);
useEffect(function () {
setReplaceText(initialReplaceText || '');
}, [initialReplaceText]);
var skipWhileComposing = function skipWhileComposing(fn) {
if (!isComposing) {
fn();
}
};
var triggerSuccessReplacementMessageUpdate = function triggerSuccessReplacementMessageUpdate(currentReplaceCount) {
if (replaceCount === currentReplaceCount) {
setFakeSuccessReplacementMessageUpdate(!fakeSuccessReplacementMessageUpdate);
}
if (successReplacementMessageRef.current) {
var ariaLiveRegion = successReplacementMessageRef.current.querySelector('[aria-live="polite"]');
ariaLiveRegion === null || ariaLiveRegion === void 0 || ariaLiveRegion.removeAttribute('aria-live');
ariaLiveRegion === null || ariaLiveRegion === void 0 || ariaLiveRegion.setAttribute('aria-live', 'polite');
}
};
var handleReplaceClick = function handleReplaceClick() {
return skipWhileComposing(function () {
onReplace({
triggerMethod: TRIGGER_METHOD.BUTTON,
replaceText: replaceText
});
triggerSuccessReplacementMessageUpdate(1);
setIsHelperMessageVisible(true);
setReplaceCount(1);
setFindTyped(false);
});
};
var handleReplaceChange = function handleReplaceChange(event) {
return skipWhileComposing(function () {
updateReplaceValue(event.target.value);
});
};
var updateReplaceValue = function updateReplaceValue(text) {
if (dispatchAnalyticsEvent) {
dispatchAnalyticsEvent({
eventType: EVENT_TYPE.TRACK,
action: ACTION.CHANGED_REPLACEMENT_TEXT,
actionSubject: ACTION_SUBJECT.FIND_REPLACE_DIALOG
});
}
setReplaceText(text);
};
var handleReplaceKeyDown = function handleReplaceKeyDown(event) {
return skipWhileComposing(function () {
if (event.key === 'Enter') {
onReplace({
triggerMethod: TRIGGER_METHOD.KEYBOARD,
replaceText: replaceText
});
} else if (event.key === 'ArrowUp') {
onArrowUp();
}
});
};
var handleReplaceAllClick = function handleReplaceAllClick() {
return skipWhileComposing(function () {
onReplaceAll({
replaceText: replaceText
});
setIsHelperMessageVisible(true);
if (count.totalReplaceable && expValEquals('platform_editor_find_and_replace_improvements', 'isEnabled', true)) {
triggerSuccessReplacementMessageUpdate(count.totalReplaceable);
setReplaceCount(count.totalReplaceable);
} else {
triggerSuccessReplacementMessageUpdate(count.total);
setReplaceCount(count.total);
}
setFindTyped(false);
});
};
var handleCompositionStart = function handleCompositionStart() {
setIsComposing(true);
};
var handleCompositionEnd = function handleCompositionEnd(event) {
setIsComposing(false);
// type for React.CompositionEvent doesn't set type for target correctly
updateReplaceValue(event.target.value);
};
var clearSearch = function clearSearch() {
onCancel({
triggerMethod: TRIGGER_METHOD.BUTTON
});
focusToolbarButton();
};
var handleFindNextClick = function handleFindNextClick() {
if (!isComposing) {
onFindNext({
triggerMethod: TRIGGER_METHOD.BUTTON
});
}
};
var handleFindPrevClick = function handleFindPrevClick() {
if (!isComposing) {
onFindPrev({
triggerMethod: TRIGGER_METHOD.BUTTON
});
}
};
var resultsReplace = formatMessage(messages.replaceSuccess, {
numberOfMatches: replaceCount
});
return /*#__PURE__*/React.createElement(Box, {
xcss: replaceContainerStyles
}, /*#__PURE__*/React.createElement(Box, {
xcss: replaceWithLabelStyle
}, /*#__PURE__*/React.createElement(Text, {
id: "replace-text-field-label",
size: "medium",
weight: "bold",
color: "color.text.subtle"
}, replaceWith)), /*#__PURE__*/React.createElement(Textfield, {
name: "replace",
"aria-labelledby": "replace-text-field-label",
testId: "replace-field",
appearance: "standard",
defaultValue: replaceText,
ref: replaceTextfieldRef,
autoComplete: "off",
onChange: handleReplaceChange,
onKeyDown: handleReplaceKeyDown,
onCompositionStart: handleCompositionStart,
onCompositionEnd: handleCompositionEnd
}), isHelperMessageVisible && !findTyped && /*#__PURE__*/React.createElement("div", {
ref: successReplacementMessageRef
}, /*#__PURE__*/React.createElement(ValidMessage, {
testId: "message-success-replacement"
}, fakeSuccessReplacementMessageUpdate ?
// @ts-ignore - TS1501 TypeScript 5.9.2 upgrade
resultsReplace.replace(/ /, "\xA0") : resultsReplace)), /*#__PURE__*/React.createElement(Box, {
xcss: actionButtonContainerStyles
}, /*#__PURE__*/React.createElement(Inline, {
xcss: expValEquals('platform_editor_find_and_replace_improvements', 'isEnabled', true) ? [actionButtonInlineStyles, actionButtonParentInlineStylesNew] : [actionButtonInlineStyles, actionButtonParentInlineStyles]
}, /*#__PURE__*/React.createElement(Inline, {
xcss: actionButtonInlineStyles
}, /*#__PURE__*/React.createElement(FindReplaceTooltipButton, {
title: formatMessage(messages.findNext)
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
icon: function icon(iconProps) {
return /*#__PURE__*/React.createElement(ChevronDownIcon, {
label: iconProps.label,
size: "small"
});
},
iconLabel: formatMessage(messages.findNext),
keymapDescription: 'Enter',
onClick: handleFindNextClick,
disabled: count.total <= 1
}), /*#__PURE__*/React.createElement(FindReplaceTooltipButton, {
title: findPrevious
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
icon: function icon(iconProps) {
return /*#__PURE__*/React.createElement(ChevronUpIcon, {
label: iconProps.label,
size: "small"
});
},
iconLabel: findPrevious,
keymapDescription: 'Shift Enter',
onClick: handleFindPrevClick,
disabled: count.total <= 1
}), /*#__PURE__*/React.createElement(Button, {
testId: 'Replace',
id: "replace-button",
onClick: handleReplaceClick,
isDisabled: !canReplace
}, formatMessage(messages.replace)), /*#__PURE__*/React.createElement(Button, {
appearance: "primary",
testId: replaceAll,
id: "replaceAll-button",
onClick: handleReplaceAllClick,
isDisabled: expValEquals('platform_editor_find_and_replace_improvements', 'isEnabled', true) ? count.totalReplaceable === 0 : !canReplace
}, replaceAll)), expValEquals('platform_editor_find_and_replace_improvements', 'isEnabled', true) ? /*#__PURE__*/React.createElement(Inline, {
xcss: closeButtonInlineStyles
}, /*#__PURE__*/React.createElement(Button, {
appearance: "subtle",
testId: closeFindReplaceDialog,
onClick: clearSearch
}, closeFindReplaceDialog)) : /*#__PURE__*/React.createElement(Button, {
appearance: "subtle",
testId: closeFindReplaceDialog,
onClick: clearSearch
}, closeFindReplaceDialog))));
};
// eslint-disable-next-line @typescript-eslint/ban-types
var _default_1 = injectIntl(Replace);
export default _default_1;