UNPKG

@mapbox/mr-ui

Version:

UI components for Mapbox projects

148 lines (147 loc) 6.01 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = Copiable; var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _classnames = _interopRequireDefault(require("classnames")); var _copyButton = _interopRequireDefault(require("../copy-button")); var _popover = _interopRequireDefault(require("../popover")); var _osKey = _interopRequireDefault(require("os-key")); var _select = _interopRequireDefault(require("select")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (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 && Object.prototype.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; } const DISABLE_CLICK_TO_SELECT_THRESHOLD = 640; const FEEDBACK_TIME = 2000; function getCopyKeys(ua) { const keys = (0, _osKey.default)(ua); if (!keys) return; if (keys.primaryMeta) { // ⌘+C return `${keys.meta.symbol}+C`; } else { // Ctrl+C return `${keys.ctrl.abbreviation}+C`; } } /** * Make some text easily copiable. * * Comes with a [CopyButton](#copybutton) that you can click to automatically * copy the text. * * Also, on wider viewports a click on the text will automatically select it * all, so you can easily copy with your favorite keyboard shortcut. */ function Copiable(_ref) { let { value, focusTrapPaused, onCopy, truncated = false } = _ref; const textEl = (0, _react.useRef)(null); const showCopyButton = (0, _react.useRef)(_copyButton.default.isCopySupported()); const [copyTooltipActive, setCopyTooltipActive] = (0, _react.useState)(false); (0, _react.useEffect)(() => { let timer; if (copyTooltipActive) { timer = setTimeout(() => { setCopyTooltipActive(false); }, FEEDBACK_TIME); } return () => clearTimeout(timer); }, [copyTooltipActive]); const handleTextFocus = () => { if (typeof window === 'undefined') return; if (window.innerWidth < DISABLE_CLICK_TO_SELECT_THRESHOLD) return; (0, _select.default)(() => textEl.current); setCopyTooltipActive(true); }; const handleTextBlur = event => { if (!textEl.current.contains(event.relatedTarget)) { setCopyTooltipActive(false); } }; const renderCopyButton = /*#__PURE__*/_react.default.createElement("div", { className: "absolute top right px6 py6" }, /*#__PURE__*/_react.default.createElement(_copyButton.default, { text: value, block: true, focusTrapPaused: focusTrapPaused, onCopy: onCopy })); const renderCopyHintText = () => { if (typeof window === 'undefined') return; return /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement("span", { className: "txt-kbd" }, getCopyKeys(window.navigator.userAgent)), ' ', "to copy"); }; const textClasses = (0, _classnames.default)('my3 txt-mono txt-s mr24', { 'txt-truncate': truncated }); const textStyle = {}; if (!truncated) { textStyle.wordWrap = 'break-word'; textStyle.overflowWrap = 'break-word'; } return /*#__PURE__*/_react.default.createElement("div", { className: "relative clearfix bg-darken5 round" }, showCopyButton.current && renderCopyButton, /*#__PURE__*/_react.default.createElement(_popover.default, { content: /*#__PURE__*/_react.default.createElement("div", { className: "txt-s" }, showCopyButton.current && renderCopyHintText), active: copyTooltipActive, placement: "top", alignment: "center", hideWhenAnchorIsOffscreen: true, "aria-label": "Copy the selected text", padding: "small" }, /*#__PURE__*/_react.default.createElement("div", { tabIndex: -1, ref: textEl, onFocus: handleTextFocus, onBlur: handleTextBlur, className: "py6 px12", "data-testid": "copiable-text-el" }, /*#__PURE__*/_react.default.createElement("div", { className: textClasses, style: textStyle }, value)))); } Copiable.propTypes = { /** * The text that will be displayed and copied. */ value: _propTypes.default.string.isRequired, /** * If `true`, this will allow interaction with elements outside of the * modal container. You normally don't want to set this, but it can be * useful for nesting different components that are displaced to other * parts of the DOM. */ focusTrapPaused: _propTypes.default.bool, /** * If `false` (default), the text will be overflow to multiple lines, * and words longer than a single line (e.g. long access tokens or URLs) * will be broken to enforce wrapping. * * If `true`, the Copiable's text will be truncated to a single line * of text. **Only set this to `true` if you know that your target * browsers support the copy button!** Some browsers will not effectively * copy text that is truncated by CSS, so the risk is that some of your * users might have *no way* to view and copy all the text if the copy * button does not work for them. * * Horizontal scrolling is not an option because of things end up getting * pretty gross across browsers. */ truncated: _propTypes.default.bool, /** * Invoked when the button is clicked. * Passed one argument: the `text` prop. */ onCopy: _propTypes.default.func };