@elastic/eui
Version:
Elastic UI Component Library
111 lines (103 loc) • 5.92 kB
JavaScript
;
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.tabularCopyMarkers = exports.onTabularCopy = exports.noCopyBoundsRegex = exports.OverrideCopiedTabularContent = exports.CHARS = void 0;
var _react = _interopRequireWildcard(require("react"));
var _react2 = require("@emotion/react");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
/**
* Clipboard text cleaning logic
*/
// Special visually hidden unicode characters that we use to manually clean content
// and force our own newlines/horizontal tabs
var CHARS = exports.CHARS = {
NEWLINE: '↵',
TAB: '↦',
// Use multiple characters to reduce the chances of consumers also using these characters
TABULAR_CONTENT_BOUND: '𐘂𐘂',
NO_COPY_BOUND: '✄𐘗'
};
// This regex finds all content between two bounds
var noCopyBoundsRegex = exports.noCopyBoundsRegex = new RegExp("".concat(CHARS.NO_COPY_BOUND, "[^").concat(CHARS.NO_COPY_BOUND, "]*").concat(CHARS.NO_COPY_BOUND), 'gs');
var hasCharsToReplace = function hasCharsToReplace(text) {
for (var _i = 0, _Object$values = Object.values(CHARS); _i < _Object$values.length; _i++) {
var char = _Object$values[_i];
if (text.indexOf(char) >= 0) return true;
}
return false;
};
// Strip all existing newlines and replace our special hidden characters
// with the desired spacing needed to paste cleanly into a spreadsheet
var onTabularCopy = exports.onTabularCopy = function onTabularCopy(event) {
var _window$getSelection;
if (!event.clipboardData) return;
var selectedText = (_window$getSelection = window.getSelection()) === null || _window$getSelection === void 0 ? void 0 : _window$getSelection.toString();
if (!selectedText || !hasCharsToReplace(selectedText)) return;
var amendedText = selectedText.split(CHARS.TABULAR_CONTENT_BOUND).map(function (text) {
return hasCharsToReplace(text) ? text.replace(/\r?\n/g, '') // remove all other newlines generated by content or block display
.replaceAll(CHARS.NEWLINE, '\n') // insert newline for each table/grid row
.replace(/\t/g, '') // remove tabs generated by content or automatically by <td> elements
.replaceAll(CHARS.TAB, "\t") // insert horizontal tab for each table/grid cell
.replace(noCopyBoundsRegex, '') // remove text that should not be copied (e.g. screen reader instructions)
: text;
}).join('');
event.clipboardData.setData('text/plain', amendedText);
event.preventDefault();
};
/**
* JSX utils for rendering the hidden marker characters
*/
var VisuallyHide = function VisuallyHide(_ref) {
var children = _ref.children,
_ref$type = _ref.type,
type = _ref$type === void 0 ? 'true' : _ref$type;
return (
// Hides the characters to both sighted user and screen readers
// Sadly, we can't use `hidden` as that hides the chars from the clipboard as well
(0, _react2.jsx)("span", {
className: "euiScreenReaderOnly",
"aria-hidden": true,
"data-tabular-copy-marker": type
}, children)
);
};
var tabularCopyMarkers = exports.tabularCopyMarkers = {
hiddenTab: (0, _react2.jsx)(VisuallyHide, {
type: "tab"
}, CHARS.TAB),
hiddenNewline: (0, _react2.jsx)(VisuallyHide, {
type: "newline"
}, CHARS.NEWLINE),
hiddenWrapperBoundary: (0, _react2.jsx)(VisuallyHide, {
type: "boundary"
}, CHARS.TABULAR_CONTENT_BOUND),
hiddenNoCopyBoundary: (0, _react2.jsx)(VisuallyHide, {
type: "no-copy"
}, CHARS.NO_COPY_BOUND)
};
/**
* Wrapper setup around table/grid tabular content we want to override/clean up on copy
*/
var OverrideCopiedTabularContent = exports.OverrideCopiedTabularContent = function OverrideCopiedTabularContent(_ref2) {
var children = _ref2.children;
(0, _react.useEffect)(function () {
// Chrome and webkit browsers work perfectly when passing `onTabularCopy` to a React
// `onCopy` prop, but sadly Firefox does not if copying more than just the table/grid
// (e.g. Ctrl+A). So we have to set up a global window event listener
window.document.addEventListener('copy', onTabularCopy);
// Note: Since onCopy is static, we don't have to worry about duplicate
// event listeners - it's automatically handled by the browser. See:
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Multiple_identical_event_listeners
}, []);
return (0, _react2.jsx)(_react.default.Fragment, null, tabularCopyMarkers.hiddenWrapperBoundary, children, tabularCopyMarkers.hiddenWrapperBoundary);
};