UNPKG

@atlaskit/editor-plugin-card

Version:

Card plugin for @atlaskit/editor-core

419 lines (412 loc) 18.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireDefault(require("react")); var _react2 = require("@emotion/react"); var _ui = require("@atlaskit/editor-common/ui"); var _state = require("@atlaskit/editor-prosemirror/state"); var _utils = require("@atlaskit/editor-prosemirror/utils"); var _editorSharedStyles = require("@atlaskit/editor-shared-styles"); var _platformFeatureFlags = require("@atlaskit/platform-feature-flags"); var _smartCard = require("@atlaskit/smart-card"); var _experiments = require("@atlaskit/tmp-editor-statsig/experiments"); function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } /** * @jsxRuntime classic * @jsx jsx */ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports // eslint-disable-next-line @repo/internal/react/no-class-components var ResizableEmbedCard = exports.default = /*#__PURE__*/function (_React$Component) { function ResizableEmbedCard() { var _this; (0, _classCallCheck2.default)(this, ResizableEmbedCard); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _callSuper(this, ResizableEmbedCard, [].concat(args)); (0, _defineProperty2.default)(_this, "state", { offsetLeft: _this.calcOffsetLeft() }); (0, _defineProperty2.default)(_this, "calcNewSize", function (newWidth, stop) { var _this$props = _this.props, layout = _this$props.layout, state = _this$props.view.state; var newPct = (0, _ui.calcPctFromPx)(newWidth, _this.props.lineLength) * 100; _this.setState({ resizedPctWidth: newPct }); var newLayout = (0, _utils.hasParentNodeOfType)(state.schema.nodes.table)(state.selection) ? layout : _this.calcUnwrappedLayout(newPct, newWidth); if (newPct <= 100) { if (_this.wrappedLayout && (stop ? newPct !== 100 : true)) { newLayout = layout; } return { width: newPct, layout: newLayout }; } else { return { width: _this.props.pctWidth || null, layout: newLayout }; } }); (0, _defineProperty2.default)(_this, "calcUnwrappedLayout", function (pct, width) { if (pct <= 100) { return 'center'; } if (width <= _this.wideLayoutWidth) { return 'wide'; } return 'full-width'; }); (0, _defineProperty2.default)(_this, "calcColumnLeftOffset", function () { var offsetLeft = _this.state.offsetLeft; return _this.insideInlineLike ? (0, _ui.calcColumnsFromPx)(offsetLeft, _this.props.lineLength, _this.props.gridSize) : 0; }); (0, _defineProperty2.default)(_this, "calcPxWidth", function (useLayout) { var _this$props2 = _this.props, layout = _this$props2.layout, pctWidth = _this$props2.pctWidth, lineLength = _this$props2.lineLength, containerWidth = _this$props2.containerWidth, fullWidthMode = _this$props2.fullWidthMode, getPos = _this$props2.getPos, state = _this$props2.view.state; var resizedPctWidth = _this.state.resizedPctWidth; var pos = typeof getPos === 'function' ? getPos() : undefined; return (0, _ui.calcMediaPxWidth)({ origWidth: _editorSharedStyles.DEFAULT_EMBED_CARD_WIDTH, origHeight: _editorSharedStyles.DEFAULT_EMBED_CARD_HEIGHT, pctWidth: pctWidth, state: state, containerWidth: { width: containerWidth, lineLength: lineLength }, isFullWidthModeEnabled: fullWidthMode, layout: useLayout || layout, pos: pos, resizedPctWidth: resizedPctWidth }); }); (0, _defineProperty2.default)(_this, "handleResizeStart", function () { var _this$props3 = _this.props, view = _this$props3.view, getPos = _this$props3.getPos; if (typeof getPos === 'function') { var pos = getPos(); if (typeof pos === 'number') { var tr = view.state.tr.setSelection(_state.NodeSelection.create(view.state.doc, pos)); tr.setMeta('scrollIntoView', false); view.dispatch(tr); } } }); (0, _defineProperty2.default)(_this, "highlights", function (newWidth, snapPoints) { var snapWidth = (0, _ui.snapTo)(newWidth, snapPoints); var _this$props$view$stat = _this.props.view.state.schema.nodes, layoutColumn = _this$props$view$stat.layoutColumn, table = _this$props$view$stat.table, expand = _this$props$view$stat.expand, nestedExpand = _this$props$view$stat.nestedExpand, bodiedSyncBlock = _this$props$view$stat.bodiedSyncBlock; // Hide resizing guideline when embed is nested if (_this.$pos && !!(0, _utils.findParentNodeOfTypeClosestToPos)(_this.$pos, (0, _experiments.editorExperiment)('platform_synced_block', true) ? [layoutColumn, table, expand, nestedExpand, bodiedSyncBlock] : [layoutColumn, table, expand, nestedExpand])) { return []; } if (snapWidth > _this.wideLayoutWidth) { return ['full-width']; } var _this$props4 = _this.props, layout = _this$props4.layout, lineLength = _this$props4.lineLength, gridSize = _this$props4.gridSize; var columns = (0, _ui.calcColumnsFromPx)(snapWidth, lineLength, gridSize); var columnWidth = Math.round(columns); var highlight = []; if (layout === 'wrap-left' || layout === 'align-start') { highlight.push(0, columnWidth); } else if (layout === 'wrap-right' || layout === 'align-end') { highlight.push(gridSize, gridSize - columnWidth); } else if (_this.insideInlineLike) { highlight.push(Math.round(columns + _this.calcColumnLeftOffset())); } else { highlight.push(Math.floor((gridSize - columnWidth) / 2), Math.ceil((gridSize + columnWidth) / 2)); } return highlight; }); return _this; } (0, _inherits2.default)(ResizableEmbedCard, _React$Component); return (0, _createClass2.default)(ResizableEmbedCard, [{ key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { var offsetLeft = this.calcOffsetLeft(); if (offsetLeft !== this.state.offsetLeft && offsetLeft >= 0) { this.setState({ offsetLeft: offsetLeft }); } if (this.props.layout !== prevProps.layout) { this.checkLayout(prevProps.layout, this.props.layout); } } }, { key: "wrappedLayout", get: function get() { return _ui.wrappedLayouts.indexOf(this.props.layout) > -1; } /** * When returning to center layout from a wrapped/aligned layout, it might actually * be wide or full-width */ }, { key: "checkLayout", value: function checkLayout(oldLayout, newLayout) { var resizedPctWidth = this.state.resizedPctWidth; if (_ui.wrappedLayouts.indexOf(oldLayout) > -1 && newLayout === 'center' && resizedPctWidth) { var layout = this.calcUnwrappedLayout(resizedPctWidth, this.calcPxWidth(newLayout)); this.props.updateSize(resizedPctWidth, layout); } } }, { key: "$pos", get: function get() { if (typeof this.props.getPos !== 'function') { return null; } var pos = this.props.getPos(); if (Number.isNaN(pos) || typeof pos !== 'number') { return null; } // need to pass view because we may not get updated props in time return this.props.view.state.doc.resolve(pos); } /** * The maxmimum number of grid columns this node can resize to. */ }, { key: "gridWidth", get: function get() { var gridSize = this.props.gridSize; return !(this.wrappedLayout || this.insideInlineLike) ? gridSize / 2 : gridSize; } }, { key: "calcOffsetLeft", value: function calcOffsetLeft() { var offsetLeft = 0; if (this.wrapper && this.insideInlineLike) { var currentNode = this.wrapper; var boundingRect = currentNode.getBoundingClientRect(); var pmRect = this.props.view.dom.getBoundingClientRect(); offsetLeft = boundingRect.left - pmRect.left; } return offsetLeft; } }, { key: "wideLayoutWidth", get: function get() { var lineLength = this.props.lineLength; if (lineLength) { return Math.ceil(lineLength * _editorSharedStyles.breakoutWideScaleRatio); } else { return _editorSharedStyles.akEditorWideLayoutWidth; } } // check if is inside of a table }, { key: "isNestedInTable", value: function isNestedInTable() { var table = this.props.view.state.schema.nodes.table; if (!this.$pos) { return false; } return !!(0, _utils.findParentNodeOfTypeClosestToPos)(this.$pos, table); } }, { key: "calcSnapPoints", value: function calcSnapPoints() { var offsetLeft = this.state.offsetLeft; var _this$props5 = this.props, containerWidth = _this$props5.containerWidth, lineLength = _this$props5.lineLength; var snapTargets = []; for (var i = 0; i < this.gridWidth; i++) { snapTargets.push((0, _ui.calcPxFromColumns)(i, lineLength, this.gridWidth) - offsetLeft); } // full width snapTargets.push(lineLength - offsetLeft); var minimumWidth = (0, _ui.calcPxFromColumns)(this.wrappedLayout || this.insideInlineLike ? 1 : 2, lineLength, this.props.gridSize); var snapPoints = snapTargets.filter(function (width) { return width >= minimumWidth; }); var $pos = this.$pos; if (!$pos) { return snapPoints; } var isTopLevel = $pos.parent.type.name === 'doc'; if (isTopLevel) { snapPoints.push(this.wideLayoutWidth); var fullWidthPoint = containerWidth - _editorSharedStyles.akEditorBreakoutPadding; if (fullWidthPoint > this.wideLayoutWidth) { snapPoints.push(fullWidthPoint); } } return snapPoints; } }, { key: "insideInlineLike", get: function get() { var $pos = this.$pos; if (!$pos) { return false; } var listItem = this.props.view.state.schema.nodes.listItem; return !!(0, _utils.findParentNodeOfTypeClosestToPos)($pos, [listItem]); } }, { key: "getHeightDefiningComponent", value: /** * Previously height of the box was controlled with paddingTop/paddingBottom trick inside Wrapper. * It allowed height to be defined by a given percent ratio and so absolute value was defined by actual width. * Also, it was part of styled component, which was fine because it was static through out life time of component. * * Now, two things changed: * 1. If `height` is present we take it as actual height of the box, and hence we don't need * (or even can't have, due to lack of width value) paddingTop trick. * 2. Since `height` can be changing through out life time of a component, we can't have it as part of styled component, * and hence we use `style` prop. */ function getHeightDefiningComponent() { var _this$props6 = this.props, height = _this$props6.height, aspectRatio = _this$props6.aspectRatio; var heightDefiningStyles; if (height) { heightDefiningStyles = { height: "".concat(height, "px") }; } else { // paddingBottom css trick defines ratio of `iframe height (y) + header (32)` to `width (x)`, // where is `aspectRatio` defines iframe aspectRatio alone // So, visually: // // x // ┌──────────┐ // │ header │ 32 // ├──────────┤ // │ │ // │ iframe │ y // │ │ // └──────────┘ // // aspectRatio = x / y // paddingBottom = (y + 32) / x // which can be achieved with css calc() as (1 / (x/y)) * 100)% + 32px heightDefiningStyles = { paddingBottom: "calc(".concat((1 / aspectRatio * 100).toFixed(3), "% + ").concat(_smartCard.embedHeaderHeight, "px)") }; } return (0, _react2.jsx)("span", { "data-testid": 'resizable-embed-card-height-definer', style: _objectSpread({ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 display: 'block', /* Fixes extra padding problem in Firefox */ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop, @atlaskit/design-system/use-tokens-typography -- Ignored via go/DSP-18766 fontSize: 0, // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop, @atlaskit/design-system/use-tokens-typography -- Ignored via go/DSP-18766 lineHeight: 0 }, heightDefiningStyles) }); } }, { key: "render", value: function render() { var _this2 = this; var _this$props7 = this.props, layout = _this$props7.layout, pctWidth = _this$props7.pctWidth, containerWidth = _this$props7.containerWidth, fullWidthMode = _this$props7.fullWidthMode, isResizeDisabled = _this$props7.isResizeDisabled, children = _this$props7.children; var resizerProps = { width: this.calcPxWidth(), innerPadding: _editorSharedStyles.akEditorMediaResizeHandlerPadding }; var enable = {}; _ui.handleSides.forEach(function (side) { if (isResizeDisabled) { enable[side] = false; return; } var oppositeSide = side === 'left' ? 'right' : 'left'; enable[side] = ['full-width', 'wide', 'center'].concat("wrap-".concat(oppositeSide)).concat("align-".concat(_ui.imageAlignmentMap[oppositeSide])).indexOf(layout) > -1; if (side === 'left' && _this2.insideInlineLike) { enable[side] = false; } }); var nestedInTableHandleStyles = function nestedInTableHandleStyles(isNestedInTable) { if (!isNestedInTable) { return; } return { left: { left: "calc(".concat("var(--ds-space-negative-025, -2px)", " * 0.5)"), paddingLeft: '0px' }, right: { right: "calc(".concat("var(--ds-space-negative-025, -2px)", " * 0.5)"), paddingRight: '0px' } }; }; /* eslint-disable @atlaskit/design-system/consistent-css-prop-usage */ return (0, _react2.jsx)("div", { "data-testid": "resizable-embed-card-spacing" }, (0, _react2.jsx)("div", { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 css: (0, _ui.wrapperStyle)({ layout: layout, isResized: !!pctWidth, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 containerWidth: containerWidth || _editorSharedStyles.DEFAULT_EMBED_CARD_WIDTH, fullWidthMode: fullWidthMode }) }, (0, _react2.jsx)(_ui.Resizer // Ignored via go/ees005 // eslint-disable-next-line react/jsx-props-no-spreading , (0, _extends2.default)({}, this.props, { enable: enable, calcNewSize: this.calcNewSize, snapPoints: this.calcSnapPoints(), scaleFactor: !this.wrappedLayout && !this.insideInlineLike ? 2 : 1, highlights: this.highlights, nodeType: "embed", onResizeStart: (0, _experiments.editorExperiment)('platform_synced_block', true) && (0, _platformFeatureFlags.fg)('platform_synced_block_patch_9') ? this.handleResizeStart : undefined, handleStyles: nestedInTableHandleStyles(this.isNestedInTable()) // Ignored via go/ees005 // eslint-disable-next-line react/jsx-props-no-spreading }, resizerProps), children, this.getHeightDefiningComponent()))); /* eslint-enable @atlaskit/design-system/consistent-css-prop-usage */ } }]); }(_react.default.Component); (0, _defineProperty2.default)(ResizableEmbedCard, "defaultProps", { aspectRatio: _editorSharedStyles.DEFAULT_EMBED_CARD_WIDTH / _editorSharedStyles.DEFAULT_EMBED_CARD_HEIGHT });