@atlaskit/editor-plugin-media
Version:
Media plugin for @atlaskit/editor-core
224 lines (220 loc) • 11.7 kB
JavaScript
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));