UNPKG

@atlaskit/editor-plugin-media

Version:

Media plugin for @atlaskit/editor-core

224 lines (220 loc) 11.7 kB
import _classCallCheck from "@babel/runtime/helpers/classCallCheck"; import _createClass from "@babel/runtime/helpers/createClass"; import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized"; import _inherits from "@babel/runtime/helpers/inherits"; import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn"; import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral"; var _templateObject, _templateObject2, _templateObject3, _templateObject4, _templateObject5, _templateObject6; function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } /** @jsx jsx */ import React from 'react'; import { css, jsx } from '@emotion/react'; import { injectIntl } from 'react-intl-next'; import { withAnalyticsEvents } from '@atlaskit/analytics-next'; import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, fireAnalyticsEvent } from '@atlaskit/editor-common/analytics'; import { escape, ToolTipContent } from '@atlaskit/editor-common/keymaps'; import { PanelTextInput } from '@atlaskit/editor-common/ui'; import { FloatingToolbarButton as Button } from '@atlaskit/editor-common/ui'; import { RECENT_SEARCH_WIDTH_IN_PX } from '@atlaskit/editor-common/ui'; import { ErrorMessage } from '@atlaskit/editor-common/ui'; import { relativeFontSizeToBase16 } from '@atlaskit/editor-shared-styles'; import ChevronLeftLargeIcon from '@atlaskit/icon/glyph/chevron-left-large'; import CrossCircleIcon from '@atlaskit/icon/glyph/cross-circle'; import { N100, N30, N80, R400 } from '@atlaskit/theme/colors'; import { closeMediaAltTextMenu, updateAltText } from '../commands'; import { messages } from '../messages'; export var CONTAINER_WIDTH_IN_PX = RECENT_SEARCH_WIDTH_IN_PX; export var MAX_ALT_TEXT_LENGTH = 510; // double tweet length var supportText = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n color: ", ";\n font-size: ", ";\n padding: ", " ", ";\n line-height: 20px;\n border-top: 1px solid ", ";\n margin: 0;\n"])), "var(--ds-text-subtlest, ".concat(N100, ")"), relativeFontSizeToBase16(12), "var(--ds-space-150, 12px)", "var(--ds-space-500, 40px)", "var(--ds-border, ".concat(N30, ")")); var container = css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n width: ", "px;\n display: flex;\n flex-direction: column;\n overflow: auto;\n line-height: 2;\n"])), CONTAINER_WIDTH_IN_PX); var inputWrapper = css(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n display: flex;\n line-height: 0;\n padding: 5px 0;\n align-items: center;\n"]))); var validationWrapper = css(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\n display: flex;\n line-height: 0;\n padding: ", " ", "\n ", " 0;\n margin: 0 ", " 0 ", ";\n border-top: 1px solid ", ";\n align-items: start;\n flex-direction: column;\n"])), "var(--ds-space-150, 12px)", "var(--ds-space-300, 24px)", "var(--ds-space-150, 12px)", "var(--ds-space-150, 12px)", "var(--ds-space-500, 40px)", "var(--ds-border-danger, ".concat(R400, ")")); var buttonWrapper = css(_templateObject5 || (_templateObject5 = _taggedTemplateLiteral(["\n display: flex;\n padding: ", " ", ";\n"])), "var(--ds-space-050, 4px)", "var(--ds-space-100, 8px)"); var clearText = css(_templateObject6 || (_templateObject6 = _taggedTemplateLiteral(["\n color: ", ";\n"])), "var(--ds-icon-subtle, ".concat(N80, ")")); // eslint-disable-next-line @repo/internal/react/no-class-components export var AltTextEditComponent = /*#__PURE__*/function (_React$Component) { _inherits(AltTextEditComponent, _React$Component); var _super = _createSuper(AltTextEditComponent); function AltTextEditComponent(props) { var _this; _classCallCheck(this, AltTextEditComponent); _this = _super.call(this, props); _defineProperty(_assertThisInitialized(_this), "state", { showClearTextButton: Boolean(_this.props.value), validationErrors: _this.props.value ? _this.getValidationErrors(_this.props.value) : [], lastValue: _this.props.value }); _defineProperty(_assertThisInitialized(_this), "closeMediaAltTextMenu", function () { var view = _this.props.view; closeMediaAltTextMenu(view.state, view.dispatch); }); _defineProperty(_assertThisInitialized(_this), "dispatchCancelEvent", function (event) { var _this$props = _this.props, view = _this$props.view, onEscape = _this$props.onEscape; // We need to pass down the ESCAPE keymap // because when we focus on the Toolbar, Prosemirror blur, // making all keyboard shortcuts not working view.someProp('handleKeyDown', function (fn) { return fn(view, event); }); onEscape === null || onEscape === void 0 || onEscape(); }); _defineProperty(_assertThisInitialized(_this), "updateAltText", function (newAltText) { var view = _this.props.view; var newValue = newAltText.length === 0 ? '' : newAltText; updateAltText(newValue)(view.state, view.dispatch); }); _defineProperty(_assertThisInitialized(_this), "handleOnChange", function (newAltText) { var _this$state; var validationErrors = _this.getValidationErrors(newAltText); if (((_this$state = _this.state) === null || _this$state === void 0 || (_this$state = _this$state.validationErrors) === null || _this$state === void 0 ? void 0 : _this$state.length) !== (validationErrors === null || validationErrors === void 0 ? void 0 : validationErrors.length)) { // If number of errors was changed we need to reset attribute to get new SR announcement if (_this.errorsListRef) { var _this$errorsListRef; var errorsArea = (_this$errorsListRef = _this.errorsListRef) === null || _this$errorsListRef === void 0 ? void 0 : _this$errorsListRef.current; errorsArea === null || errorsArea === void 0 || errorsArea.removeAttribute('aria-live'); errorsArea === null || errorsArea === void 0 || errorsArea.setAttribute('aria-live', 'assertive'); } } _this.setState({ showClearTextButton: Boolean(newAltText), validationErrors: validationErrors, lastValue: newAltText }, function () { if (!validationErrors || !validationErrors.length) { _this.updateAltText(newAltText); } }); }); _defineProperty(_assertThisInitialized(_this), "handleOnBlur", function () { // Handling the trimming onBlur() because PanelTextInput doesn't sync // defaultValue properly during unmount var value = _this.props.value; var newValue = (_this.state.lastValue || value || '').trim(); _this.handleOnChange(newValue); }); _defineProperty(_assertThisInitialized(_this), "handleClearText", function () { _this.handleOnChange(''); }); var createAnalyticsEvent = props.createAnalyticsEvent; _this.fireCustomAnalytics = fireAnalyticsEvent(createAnalyticsEvent); _this.errorsListRef = /*#__PURE__*/React.createRef(); return _this; } _createClass(AltTextEditComponent, [{ key: "componentDidMount", value: function componentDidMount() { this.prevValue = this.props.value; } }, { key: "componentWillUnmount", value: function componentWillUnmount() { this.fireAnalytics(ACTION.CLOSED); if (!this.prevValue && this.props.value) { this.fireAnalytics(ACTION.ADDED); } if (this.prevValue && !this.props.value) { this.fireAnalytics(ACTION.CLEARED); } if (this.prevValue && this.prevValue !== this.props.value) { this.fireAnalytics(ACTION.EDITED); } } }, { key: "getValidationErrors", value: function getValidationErrors(value) { var altTextValidator = this.props.altTextValidator; if (value && typeof altTextValidator === 'function') { return altTextValidator(value) || []; } return []; } }, { key: "render", value: function render() { var formatMessage = this.props.intl.formatMessage; var showClearTextButton = this.state.showClearTextButton; var backButtonMessage = formatMessage(messages.back); var backButtonMessageComponent = jsx(ToolTipContent, { description: backButtonMessage, keymap: escape, shortcutOverride: "Esc" }); var errorsList = (this.state.validationErrors || []).map(function (error, index) { return jsx(ErrorMessage, { key: index }, error); }); var hasErrors = !!errorsList.length; return jsx("div", { css: container }, jsx("section", { css: inputWrapper }, jsx("div", { css: buttonWrapper }, jsx(Button, { title: formatMessage(messages.back), icon: jsx(ChevronLeftLargeIcon, { label: formatMessage(messages.back) }), tooltipContent: backButtonMessageComponent, onClick: this.closeMediaAltTextMenu })), jsx(PanelTextInput, { testId: "alt-text-input", ariaLabel: formatMessage(messages.placeholder), describedById: "".concat(hasErrors ? 'errors-list' : '', " support-text"), placeholder: formatMessage(messages.placeholder), defaultValue: this.state.lastValue, onCancel: this.dispatchCancelEvent, onChange: this.handleOnChange, onBlur: this.handleOnBlur, onSubmit: this.closeMediaAltTextMenu, maxLength: MAX_ALT_TEXT_LENGTH, ariaRequired: true, ariaInvalid: hasErrors, autoFocus: true }), showClearTextButton && jsx("div", { css: buttonWrapper }, jsx(Button, { testId: "alt-text-clear-button", title: formatMessage(messages.clear), icon: jsx("span", { css: clearText }, jsx(CrossCircleIcon, { label: formatMessage(messages.clear) })), tooltipContent: formatMessage(messages.clear), onClick: this.handleClearText }))), hasErrors && jsx("section", { id: "errors-list", ref: this.errorsListRef, "aria-live": "assertive", css: validationWrapper }, errorsList), jsx("p", { css: supportText, id: "support-text" }, formatMessage(messages.supportText))); } }, { key: "fireAnalytics", value: function fireAnalytics(actionType) { var createAnalyticsEvent = this.props.createAnalyticsEvent; if (createAnalyticsEvent && this.fireCustomAnalytics) { this.fireCustomAnalytics({ payload: { action: actionType, actionSubject: ACTION_SUBJECT.MEDIA, actionSubjectId: ACTION_SUBJECT_ID.ALT_TEXT, eventType: EVENT_TYPE.TRACK } }); } } }]); return AltTextEditComponent; }(React.Component); export default withAnalyticsEvents()(injectIntl(AltTextEditComponent));