@atlaskit/editor-plugin-card
Version:
Card plugin for @atlaskit/editor-core
275 lines (272 loc) • 12.3 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireWildcard(require("react"));
var _react2 = require("@emotion/react");
var _debounce = _interopRequireDefault(require("lodash/debounce"));
var _reactIntlNext = require("react-intl-next");
var _messages = require("@atlaskit/editor-common/messages");
var _whitespace = require("@atlaskit/editor-common/whitespace");
var _customize = _interopRequireDefault(require("@atlaskit/icon/core/customize"));
var _utils = require("./utils");
var _excluded = ["children", "isSelected", "isVisible", "testId", "url"];
/* eslint-disable @atlaskit/design-system/no-nested-styles */
/* eslint-disable @atlaskit/design-system/prefer-primitives */
/**
* @jsxRuntime classic
* @jsx jsx
*/
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
var DEBOUNCE_IN_MS = 5;
var ESTIMATED_MIN_WIDTH_IN_PX = 16;
var PADDING_IN_PX = 4;
var ICON_WIDTH_IN_PX = 14;
var ICON_AND_LABEL_CLASSNAME = 'ak-editor-card-overlay-icon-and-label';
var OVERLAY_LABEL_CLASSNAME = 'ak-editor-card-overlay-label';
var OVERLAY_GRADIENT_CLASSNAME = 'ak-editor-card-overlay-gradient';
var OVERLAY_MARKER_CLASSNAME = 'ak-editor-card-overlay-marker';
var TEXT_NODE_SELECTOR = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'].join(',');
var SMART_LINK_BACKGROUND_COLOR = "var(--ds-surface-raised, #FFFFFF)";
var SMART_LINK_ACTIVE_COLOR = "var(--ds-background-selected, #E9F2FE)";
var getGradientWithColor = function getGradientWithColor(color) {
return "linear-gradient(270deg, ".concat(color, " 0%, rgba(255, 255, 255, 0.00) 100%)");
};
var containerStyles = (0, _react2.css)({
position: 'relative',
// eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
lineHeight: 'normal',
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-selectors -- Ignored via go/DSP-18766
':active': (0, _defineProperty2.default)((0, _defineProperty2.default)({}, ".".concat(ICON_AND_LABEL_CLASSNAME), {
background: SMART_LINK_ACTIVE_COLOR
}), ".".concat(OVERLAY_GRADIENT_CLASSNAME), {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
background: getGradientWithColor(SMART_LINK_ACTIVE_COLOR)
})
});
var overlayStyles = (0, _react2.css)({
// Set default styling to be invisible but available in dom for width calculation.
visibility: 'hidden',
position: 'absolute',
display: 'inline-flex',
justifyContent: 'flex-end',
alignItems: 'center',
verticalAlign: 'text-top',
height: '1lh',
'@supports not (height: 1lh)': {
height: '1.2em'
},
overflow: 'hidden',
// EDM-1717: box-shadow Safari fix bring load wrapper zIndex to 1
zIndex: 2,
pointerEvents: 'none'
});
var showOverlayStyles = (0, _react2.css)({
position: 'relative',
visibility: 'visible'
});
var iconStyles = (0, _react2.css)({
// Position icon in the middle
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766
span: {
display: 'flex'
}
});
var labelStyles = (0, _react2.css)({
font: "var(--ds-font-body, normal 400 14px/20px \"Atlassian Sans\", ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu, \"Helvetica Neue\", sans-serif)",
fontWeight: "var(--ds-font-weight-semibold, 600)",
width: 'max-content'
});
var iconAndLabelStyles = (0, _react2.css)({
display: 'flex',
alignItems: 'center',
height: '100%',
gap: "var(--ds-space-050, 4px)",
paddingRight: "var(--ds-space-050, 4px)",
// Margin to avoid the background covering the link border
marginRight: "var(--ds-space-025, 2px)",
background: SMART_LINK_BACKGROUND_COLOR,
color: "var(--ds-text-subtlest, #6B6E76)"
});
var overflowingContainerStyles = (0, _react2.css)({
display: 'flex',
flexDirection: 'row-reverse',
alignItems: 'center',
width: 'max-content',
height: '100%'
});
var gradientStyles = (0, _react2.css)({
width: '2.5rem',
height: '100%',
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
background: getGradientWithColor(SMART_LINK_BACKGROUND_COLOR)
});
var InlineCardOverlay = function InlineCardOverlay(_ref) {
var children = _ref.children,
_ref$isSelected = _ref.isSelected,
isSelected = _ref$isSelected === void 0 ? false : _ref$isSelected,
_ref$isVisible = _ref.isVisible,
isVisible = _ref$isVisible === void 0 ? false : _ref$isVisible,
_ref$testId = _ref.testId,
testId = _ref$testId === void 0 ? 'inline-card-overlay' : _ref$testId,
url = _ref.url,
props = (0, _objectWithoutProperties2.default)(_ref, _excluded);
var _useState = (0, _react.useState)(false),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
showOverlay = _useState2[0],
setShowOverlay = _useState2[1];
var _useState3 = (0, _react.useState)(true),
_useState4 = (0, _slicedToArray2.default)(_useState3, 2),
showLabel = _useState4[0],
setShowLabel = _useState4[1];
var _useState5 = (0, _react.useState)(undefined),
_useState6 = (0, _slicedToArray2.default)(_useState5, 2),
availableWidth = _useState6[0],
setAvailableWidth = _useState6[1];
var maxOverlayWidth = (0, _react.useRef)(0);
var minOverlayWidth = (0, _react.useRef)(ESTIMATED_MIN_WIDTH_IN_PX);
var parentWidth = (0, _react.useRef)(0);
var containerRef = (0, _react.useRef)(null);
var setVisibility = (0, _react.useCallback)(function () {
if (!containerRef.current || !maxOverlayWidth.current) {
return;
}
var marker = (0, _utils.getChildElement)(containerRef, ".".concat(OVERLAY_MARKER_CLASSNAME));
if (!marker) {
return;
}
try {
var oneLine = (0, _utils.isOneLine)(containerRef.current, marker);
// Get the width of the available space to display overlay.
// This is the width of the inline link itself. If the inline
// is wrapped to the next line, this is width of the last line.
var _availableWidth = (0, _utils.getInlineCardAvailableWidth)(containerRef.current, marker) - PADDING_IN_PX - (
// Always leave at least the icon visible
oneLine ? ICON_WIDTH_IN_PX + PADDING_IN_PX : 0);
setAvailableWidth(_availableWidth);
var canShowLabel = _availableWidth > maxOverlayWidth.current;
setShowLabel(canShowLabel);
var canShowOverlay = _availableWidth > minOverlayWidth.current && !isSelected;
setShowOverlay(canShowOverlay);
} catch (_unused) {
// If something goes wrong, hide the overlay all together.
setShowOverlay(false);
}
}, [isSelected]);
(0, _react.useLayoutEffect)(function () {
// Using useLayoutEffect here.
// 1) We want all to be able to determine whether to display label before
// the overlay becomes visible.
// 2) We need to wait for the refs to be assigned to be able to do determine
// the width of the overlay.
if (!containerRef.current) {
return;
}
// This should run only once
if (!maxOverlayWidth.current) {
var iconAndLabel = (0, _utils.getChildElement)(containerRef, ".".concat(ICON_AND_LABEL_CLASSNAME));
var _label = (0, _utils.getChildElement)(containerRef, ".".concat(OVERLAY_LABEL_CLASSNAME));
if (iconAndLabel && _label) {
// Set overlay max (label + icon) and min (icon only) width.
var _getOverlayWidths = (0, _utils.getOverlayWidths)(iconAndLabel, _label),
max = _getOverlayWidths.max,
min = _getOverlayWidths.min;
maxOverlayWidth.current = max;
minOverlayWidth.current = min;
}
}
if (isVisible) {
setVisibility();
}
}, [setVisibility, isVisible]);
(0, _react.useEffect)(function () {
var _containerRef$current;
// Find the closest block parent to observe size change
var parent = containerRef === null || containerRef === void 0 || (_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.closest(TEXT_NODE_SELECTOR);
if (!parent) {
return;
}
var updateOverlay = (0, _debounce.default)(function (entries) {
var _entries$;
if (!isVisible) {
return;
}
var size = entries === null || entries === void 0 || (_entries$ = entries[0]) === null || _entries$ === void 0 || (_entries$ = _entries$.contentBoxSize) === null || _entries$ === void 0 || (_entries$ = _entries$[0]) === null || _entries$ === void 0 ? void 0 : _entries$.inlineSize;
if (!size) {
return;
}
if (!parentWidth.current) {
parentWidth.current = size;
}
if (parentWidth.current === size) {
return;
}
parentWidth.current = size;
setVisibility();
}, DEBOUNCE_IN_MS);
var observer = new ResizeObserver(updateOverlay);
observer.observe(parent);
return function () {
observer.disconnect();
};
}, [isVisible, setVisibility]);
var intl = (0, _reactIntlNext.useIntl)();
var label = intl.formatMessage(_messages.cardMessages.inlineOverlay);
return (
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
(0, _react2.jsx)("span", (0, _extends2.default)({}, props, {
css: containerStyles,
ref: containerRef
}), children, isVisible && (0, _react2.jsx)(_react.default.Fragment, null, (0, _react2.jsx)("span", {
"aria-hidden": "true",
className: OVERLAY_MARKER_CLASSNAME
}, _whitespace.ZERO_WIDTH_JOINER), (0, _react2.jsx)("a", {
css: [overlayStyles, showOverlay && showOverlayStyles],
style: {
// eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage/preview
marginLeft: availableWidth && -availableWidth,
width: availableWidth
},
"data-testid": testId,
href: url,
onClick: function onClick(e) {
return e.preventDefault();
},
tabIndex: -1
}, (0, _react2.jsx)("span", {
css: overflowingContainerStyles
}, (0, _react2.jsx)("span", {
css: iconAndLabelStyles
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
,
className: ICON_AND_LABEL_CLASSNAME
}, (0, _react2.jsx)("span", {
css: iconStyles
}, (0, _react2.jsx)(_customize.default, {
label: label,
testId: "".concat(testId, "-icon")
})), showLabel && (0, _react2.jsx)("span", {
css: labelStyles
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
,
className: OVERLAY_LABEL_CLASSNAME,
"data-testid": "".concat(testId, "-label")
}, label)), (0, _react2.jsx)("span", {
css: gradientStyles
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
,
className: OVERLAY_GRADIENT_CLASSNAME,
"data-testid": "".concat(testId, "-gradient")
})))))
);
};
var _default = exports.default = InlineCardOverlay;