@atlaskit/editor-plugin-media
Version:
Media plugin for @atlaskit/editor-core
266 lines (262 loc) • 11.1 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
/**
* @jsxRuntime classic
* @jsx jsx
*/
import React from 'react';
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports
import { css, jsx } from '@emotion/react';
import { injectIntl } from 'react-intl';
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 { altTextMessages as messages } from '@atlaskit/editor-common/media';
import { areToolbarFlagsEnabled } from '@atlaskit/editor-common/toolbar-flag-check';
import { RECENT_SEARCH_WIDTH_IN_PX as CONTAINER_WIDTH_IN_PX, FloatingToolbarButton as Button, ErrorMessage, PanelTextInput } from '@atlaskit/editor-common/ui';
import { relativeFontSizeToBase16 } from '@atlaskit/editor-shared-styles';
import ChevronLeftLargeIcon from '@atlaskit/icon/core/chevron-left';
import CrossCircleIcon from '@atlaskit/icon/core/cross-circle';
import { closeMediaAltTextMenu, closeMediaAltTextMenuAndSave } from '../commands';
export const MAX_ALT_TEXT_LENGTH = 510; // double tweet length
const supportTextStyles = css({
color: "var(--ds-text-subtlest, #6B6E76)",
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
fontSize: relativeFontSizeToBase16(12),
padding: `${"var(--ds-space-150, 12px)"} ${"var(--ds-space-500, 40px)"}`,
// eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
lineHeight: '20px',
borderTop: `${"var(--ds-border-width, 1px)"} solid ${"var(--ds-border, #0B120E24)"}`,
margin: 0
});
const containerStyles = css({
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
width: `${CONTAINER_WIDTH_IN_PX}px`,
display: 'flex',
flexDirection: 'column',
overflow: 'auto',
// eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
lineHeight: 2
});
const inputWrapperStyles = css({
display: 'flex',
// eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
lineHeight: 0,
padding: `${"var(--ds-space-075, 6px)"} 0`,
alignItems: 'center'
});
const validationWrapperStyles = css({
display: 'flex',
// eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
lineHeight: 0,
padding: `${"var(--ds-space-150, 12px)"} ${"var(--ds-space-300, 24px)"} ${"var(--ds-space-150, 12px)"} 0`,
margin: `0 ${"var(--ds-space-150, 12px)"} 0 ${"var(--ds-space-500, 40px)"}`,
borderTop: `${"var(--ds-border-width, 1px)"} solid ${"var(--ds-border-danger, #E2483D)"}`,
alignItems: 'start',
flexDirection: 'column'
});
const buttonWrapperStyles = css({
display: 'flex',
padding: `${"var(--ds-space-050, 4px)"} ${"var(--ds-space-100, 8px)"}`
});
const clearTextStyles = css({
color: "var(--ds-icon-subtle, #505258)"
});
// eslint-disable-next-line @repo/internal/react/no-class-components
export class AltTextEditComponent extends React.Component {
constructor(props) {
super(props);
_defineProperty(this, "state", {
showClearTextButton: Boolean(this.props.value),
validationErrors: this.props.value ? this.getValidationErrors(this.props.value) : [],
lastValue: this.props.value
});
_defineProperty(this, "closeMediaAltTextMenu", () => {
const {
view
} = this.props;
if (this.state.validationErrors.length === 0) {
closeMediaAltTextMenuAndSave(this.state.lastValue || '')(view.state, view.dispatch);
} else {
closeMediaAltTextMenu(view.state, view.dispatch);
}
});
_defineProperty(this, "closeMediaAltTextMenuAndSetFocus", () => {
var _this$props$onEnter, _this$props;
this.closeMediaAltTextMenu();
(_this$props$onEnter = (_this$props = this.props).onEnter) === null || _this$props$onEnter === void 0 ? void 0 : _this$props$onEnter.call(_this$props);
});
_defineProperty(this, "dispatchCancelEvent", event => {
const {
view,
onEscape
} = this.props;
// We need to pass down the ESCAPE keymap
// because when we focus on the Toolbar, Prosemirror blur,
// making all keyboard shortcuts not working
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
view.someProp('handleKeyDown', fn => fn(view, event));
onEscape === null || onEscape === void 0 ? void 0 : onEscape();
});
_defineProperty(this, "handleOnChange", newAltText => {
var _this$state, _this$state$validatio;
const validationErrors = this.getValidationErrors(newAltText);
if (((_this$state = this.state) === null || _this$state === void 0 ? void 0 : (_this$state$validatio = _this$state.validationErrors) === null || _this$state$validatio === void 0 ? void 0 : _this$state$validatio.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;
const errorsArea = (_this$errorsListRef = this.errorsListRef) === null || _this$errorsListRef === void 0 ? void 0 : _this$errorsListRef.current;
errorsArea === null || errorsArea === void 0 ? void 0 : errorsArea.removeAttribute('aria-live');
errorsArea === null || errorsArea === void 0 ? void 0 : errorsArea.setAttribute('aria-live', 'assertive');
}
}
this.setState({
showClearTextButton: Boolean(newAltText),
validationErrors,
lastValue: newAltText
});
});
_defineProperty(this, "handleOnBlur", e => {
var _this$props$areAnyNew;
// prevent other selection transaction gets triggered
e.stopPropagation();
if ((_this$props$areAnyNew = this.props.areAnyNewToolbarFlagsEnabled) !== null && _this$props$areAnyNew !== void 0 ? _this$props$areAnyNew : areToolbarFlagsEnabled()) {
this.closeMediaAltTextMenuAndSetFocus();
} else {
this.closeMediaAltTextMenu();
}
});
_defineProperty(this, "handleClearText", () => {
this.handleOnChange('');
});
const {
createAnalyticsEvent
} = props;
this.fireCustomAnalytics = fireAnalyticsEvent(createAnalyticsEvent);
this.errorsListRef = /*#__PURE__*/React.createRef();
}
componentDidMount() {
this.prevValue = this.props.value;
}
componentWillUnmount() {
this.fireAnalytics(ACTION.CLOSED);
if (!this.prevValue && this.state.lastValue) {
this.fireAnalytics(ACTION.ADDED);
}
if (this.prevValue && !this.state.lastValue) {
this.fireAnalytics(ACTION.CLEARED);
}
if (this.prevValue && this.prevValue !== this.state.lastValue) {
this.fireAnalytics(ACTION.EDITED);
}
}
getValidationErrors(value) {
const {
altTextValidator
} = this.props;
if (value && typeof altTextValidator === 'function') {
return altTextValidator(value) || [];
}
return [];
}
render() {
var _this$props$areAnyNew2, _this$props$areAnyNew3, _this$props$areAnyNew4;
const {
intl: {
formatMessage
}
} = this.props;
const {
showClearTextButton
} = this.state;
const backButtonMessage = formatMessage(messages.back);
const backButtonMessageComponent = jsx(ToolTipContent, {
description: backButtonMessage,
keymap: escape,
shortcutOverride: "Esc"
});
const errorsList = (this.state.validationErrors || []).map(function (error, index) {
// Ignored via go/ees005
// eslint-disable-next-line react/no-array-index-key
return jsx(ErrorMessage, {
key: index
}, error);
});
const hasErrors = !!errorsList.length;
const onSubmit = ((_this$props$areAnyNew2 = this.props.areAnyNewToolbarFlagsEnabled) !== null && _this$props$areAnyNew2 !== void 0 ? _this$props$areAnyNew2 : areToolbarFlagsEnabled()) ? this.closeMediaAltTextMenuAndSetFocus : this.closeMediaAltTextMenu;
return jsx("div", {
css: containerStyles
}, jsx("section", {
css: inputWrapperStyles
}, jsx("div", {
css: buttonWrapperStyles
}, jsx(Button, {
title: formatMessage(messages.back),
icon: jsx(ChevronLeftLargeIcon, {
label: formatMessage(messages.back),
size: "small"
}),
tooltipContent: backButtonMessageComponent,
onClick: this.closeMediaAltTextMenu,
areAnyNewToolbarFlagsEnabled: (_this$props$areAnyNew3 = this.props.areAnyNewToolbarFlagsEnabled) !== null && _this$props$areAnyNew3 !== void 0 ? _this$props$areAnyNew3 : areToolbarFlagsEnabled()
})), jsx(PanelTextInput, {
testId: "alt-text-input",
ariaLabel: formatMessage(messages.placeholder),
describedById: `${hasErrors ? 'errors-list' : ''} support-text`,
placeholder: formatMessage(messages.placeholder),
defaultValue: this.state.lastValue,
onCancel: this.dispatchCancelEvent,
onChange: this.handleOnChange,
onBlur: this.handleOnBlur,
onSubmit: onSubmit,
maxLength: MAX_ALT_TEXT_LENGTH,
ariaRequired: true,
ariaInvalid: hasErrors,
autoFocus: true
}), showClearTextButton && jsx("div", {
css: buttonWrapperStyles
}, jsx(Button, {
testId: "alt-text-clear-button",
title: formatMessage(messages.clear),
icon: jsx("span", {
css: clearTextStyles
}, jsx(CrossCircleIcon, {
label: formatMessage(messages.clear)
})),
tooltipContent: formatMessage(messages.clear),
onClick: this.handleClearText,
areAnyNewToolbarFlagsEnabled: (_this$props$areAnyNew4 = this.props.areAnyNewToolbarFlagsEnabled) !== null && _this$props$areAnyNew4 !== void 0 ? _this$props$areAnyNew4 : areToolbarFlagsEnabled()
}))), hasErrors && jsx("section", {
id: "errors-list",
ref: this.errorsListRef,
"aria-live": "assertive",
css: validationWrapperStyles
}, errorsList), jsx("p", {
css: supportTextStyles,
id: "support-text"
}, formatMessage(messages.supportText)));
}
fireAnalytics(actionType) {
const {
createAnalyticsEvent,
nodeType,
mediaType
} = this.props;
if (createAnalyticsEvent && this.fireCustomAnalytics) {
this.fireCustomAnalytics({
payload: {
action: actionType,
actionSubject: ACTION_SUBJECT.MEDIA,
actionSubjectId: ACTION_SUBJECT_ID.ALT_TEXT,
eventType: EVENT_TYPE.TRACK,
attributes: {
type: nodeType,
mediaType
}
}
});
}
}
}
const _default_1 = withAnalyticsEvents()(injectIntl(AltTextEditComponent));
export default _default_1;