UNPKG

@atlaskit/editor-plugin-media

Version:

Media plugin for @atlaskit/editor-core

213 lines (209 loc) 11.6 kB
import { activateVideoControls, bindKeymapWithCommand, decreaseMediaSize, enter, increaseMediaSize, insertNewLine, moveDown, moveLeft, moveRight, tab, undo } from '@atlaskit/editor-common/keymaps'; import { mediaResizeAnnouncerMessMessages as mediaResizeAnnouncerMess } from '@atlaskit/editor-common/media'; import { calcMediaSingleMaxWidth, MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH } from '@atlaskit/editor-common/media-single'; import { GapCursorSelection, Side } from '@atlaskit/editor-common/selection'; import { keymap } from '@atlaskit/editor-prosemirror/keymap'; import { NodeSelection } from '@atlaskit/editor-prosemirror/state'; import { akEditorDefaultLayoutWidth } from '@atlaskit/editor-shared-styles'; import { insertAndSelectCaptionFromMediaSinglePos, selectCaptionFromMediaSinglePos } from '../pm-plugins/commands/captions'; import { stateKey } from '../pm-plugins/plugin-key'; import { updateMediaSingleWidth } from '../ui/toolbar/commands'; import { calcNewLayout, getSelectedMediaSingle } from '../ui/toolbar/utils'; function keymapPlugin(options, editorAnalyticsAPI, editorSelectionAPI, widthPlugin, getIntl) { const list = {}; // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion bindKeymapWithCommand(undo.common, ignoreLinksInSteps, list); if (options !== null && options !== void 0 && options.allowCaptions) { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion bindKeymapWithCommand(moveDown.common, insertAndSelectCaption(editorAnalyticsAPI), list); // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion bindKeymapWithCommand(tab.common, insertAndSelectCaption(editorAnalyticsAPI), list); // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion bindKeymapWithCommand(moveLeft.common, arrowLeftFromMediaSingle(editorSelectionAPI), list); // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion bindKeymapWithCommand(moveRight.common, arrowRightFromMediaSingle(editorSelectionAPI), list); } // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion bindKeymapWithCommand(insertNewLine.common, splitMediaGroup, list); // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion bindKeymapWithCommand(enter.common, splitMediaGroup, list); if (options !== null && options !== void 0 && options.allowPixelResizing) { bindKeymapWithCommand( // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion increaseMediaSize.common, handleMediaIncrease(editorAnalyticsAPI, widthPlugin, options, getIntl), list); bindKeymapWithCommand( // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion decreaseMediaSize.common, handleMediaDecrease(editorAnalyticsAPI, widthPlugin, options, getIntl), list); } // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion bindKeymapWithCommand(activateVideoControls.common, focusPlayButton, list); return keymap(list); } const ignoreLinksInSteps = state => { const mediaPluginState = stateKey.getState(state); mediaPluginState.ignoreLinks = true; return false; }; const splitMediaGroup = state => { const mediaPluginState = stateKey.getState(state); return mediaPluginState.splitMediaGroup(); }; const focusPlayButton = state => { var _stateKey$getState; const videoControlsWrapperRef = (_stateKey$getState = stateKey.getState(state)) === null || _stateKey$getState === void 0 ? void 0 : _stateKey$getState.element; if (videoControlsWrapperRef) { const firstButton = videoControlsWrapperRef === null || videoControlsWrapperRef === void 0 ? void 0 : videoControlsWrapperRef.querySelector('button, [tabindex]:not([tabindex="-1"])'); firstButton === null || firstButton === void 0 ? void 0 : firstButton.focus(); } return true; }; const validationMaxMin = (newWidth, maxWidth, minWidth, validation) => { let newWidthValidated; if (newWidth > maxWidth) { newWidthValidated = maxWidth; validation = 'greater-than-max'; } else if (newWidth < minWidth) { newWidthValidated = minWidth; validation = 'less-than-min'; } else { newWidthValidated = newWidth; validation = 'valid'; } return { newWidthValidated, validation }; }; const createAnnouncer = (action, mediaWidth, changeAmount, validation, getIntl) => { const announcerContainer = document.getElementById('media-announcer') || document.createElement('div'); const intl = getIntl(); if (!announcerContainer.id) { announcerContainer.id = 'media-announcer'; announcerContainer.setAttribute('role', 'status'); announcerContainer.setAttribute('aria-live', 'polite'); announcerContainer.setAttribute('aria-atomic', 'true'); // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any const style = announcerContainer.style; style.position = 'absolute'; style.width = '1px'; style.height = '1px'; style.marginTop = '-1px'; style.opacity = '0'; style.overflow = 'hidden'; document.body.appendChild(announcerContainer); } else { const newMediaWidth = mediaWidth + changeAmount; if (validation === 'greater-than-max') { announcerContainer.textContent = intl.formatMessage(mediaResizeAnnouncerMess.MediaWidthIsMax); } else if (validation === 'less-than-min') { announcerContainer.textContent = intl.formatMessage(mediaResizeAnnouncerMess.MediaWidthIsMin); } else { announcerContainer.textContent = intl.formatMessage(action === 'increased' ? mediaResizeAnnouncerMess.DefaultMediaWidthIncreased : mediaResizeAnnouncerMess.DefaultMediaWidthDecreased, { newMediaWidth }); } } }; const handleMediaSizeChange = (editorAnalyticsAPI, widthPlugin, options, changeAmount, action, getIntl) => (state, dispatch) => { var _getSelectedMediaSing, _getSelectedMediaSing2, _getSelectedMediaSing3, _widthPlugin$sharedSt, _widthPlugin$sharedSt2, _getSelectedMediaSing4, _getSelectedMediaSing5, _getSelectedMediaSing6; const { selection } = state; if (!(selection instanceof NodeSelection && selection.node.type.name === 'mediaSingle')) { return false; } const mediaWidth = (_getSelectedMediaSing = getSelectedMediaSingle(state)) === null || _getSelectedMediaSing === void 0 ? void 0 : (_getSelectedMediaSing2 = _getSelectedMediaSing.node) === null || _getSelectedMediaSing2 === void 0 ? void 0 : (_getSelectedMediaSing3 = _getSelectedMediaSing2.attrs) === null || _getSelectedMediaSing3 === void 0 ? void 0 : _getSelectedMediaSing3.width; const contentWidth = (widthPlugin === null || widthPlugin === void 0 ? void 0 : (_widthPlugin$sharedSt = widthPlugin.sharedState.currentState()) === null || _widthPlugin$sharedSt === void 0 ? void 0 : _widthPlugin$sharedSt.lineLength) || akEditorDefaultLayoutWidth; const mediaPluginState = stateKey.getState(state); const maxWidthForNestedNode = mediaPluginState.currentMaxWidth; const minWidth = MEDIA_SINGLE_DEFAULT_MIN_PIXEL_WIDTH; // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any let maxWidth = maxWidthForNestedNode; const currentMaxWidth = (widthPlugin === null || widthPlugin === void 0 ? void 0 : (_widthPlugin$sharedSt2 = widthPlugin.sharedState.currentState()) === null || _widthPlugin$sharedSt2 === void 0 ? void 0 : _widthPlugin$sharedSt2.width) || maxWidth; if (maxWidth === undefined && maxWidthForNestedNode === undefined) { var _widthPlugin$sharedSt3; maxWidth = options !== null && options !== void 0 && options.fullWidthEnabled ? widthPlugin === null || widthPlugin === void 0 ? void 0 : (_widthPlugin$sharedSt3 = widthPlugin.sharedState.currentState()) === null || _widthPlugin$sharedSt3 === void 0 ? void 0 : _widthPlugin$sharedSt3.lineLength : calcMediaSingleMaxWidth(currentMaxWidth, options === null || options === void 0 ? void 0 : options.editorAppearance); } const validation = 'valid'; const newWidth = mediaWidth + changeAmount; if (options !== null && options !== void 0 && options.fullWidthEnabled) { var _widthPlugin$sharedSt4; maxWidth = widthPlugin === null || widthPlugin === void 0 ? void 0 : (_widthPlugin$sharedSt4 = widthPlugin.sharedState.currentState()) === null || _widthPlugin$sharedSt4 === void 0 ? void 0 : _widthPlugin$sharedSt4.lineLength; } else if (maxWidthForNestedNode === undefined) { maxWidth = calcMediaSingleMaxWidth(currentMaxWidth, options === null || options === void 0 ? void 0 : options.editorAppearance); } const { newWidthValidated, validation: validationResult } = validationMaxMin(newWidth, maxWidth, minWidth, validation); const newLayout = calcNewLayout(newWidthValidated, (_getSelectedMediaSing4 = getSelectedMediaSingle(state)) === null || _getSelectedMediaSing4 === void 0 ? void 0 : (_getSelectedMediaSing5 = _getSelectedMediaSing4.node) === null || _getSelectedMediaSing5 === void 0 ? void 0 : (_getSelectedMediaSing6 = _getSelectedMediaSing5.attrs) === null || _getSelectedMediaSing6 === void 0 ? void 0 : _getSelectedMediaSing6.layout, contentWidth, options === null || options === void 0 ? void 0 : options.fullWidthEnabled); updateMediaSingleWidth(editorAnalyticsAPI)(newWidthValidated, validationResult, 'keyboard', newLayout)(state, dispatch); createAnnouncer(action, mediaWidth, changeAmount, validationResult, getIntl); return true; }; const handleMediaIncrease = (editorAnalyticsAPI, widthPlugin, options, getIntl) => handleMediaSizeChange(editorAnalyticsAPI, widthPlugin, options, 1, 'increased', getIntl); const handleMediaDecrease = (editorAnalyticsAPI, widthPlugin, options, getIntl) => handleMediaSizeChange(editorAnalyticsAPI, widthPlugin, options, -1, 'decreased', getIntl); const insertAndSelectCaption = editorAnalyticsAPI => (state, dispatch) => { const { selection, schema } = state; if (selection instanceof NodeSelection && selection.node.type === schema.nodes.mediaSingle && schema.nodes.caption) { if (dispatch) { const { from, node } = selection; if (!insertAndSelectCaptionFromMediaSinglePos(editorAnalyticsAPI)(from, node)(state, dispatch)) { selectCaptionFromMediaSinglePos(from, node)(state, dispatch); } } return true; } return false; }; const arrowLeftFromMediaSingle = editorSelectionAPI => (state, dispatch) => { const { selection } = state; if (editorSelectionAPI && selection instanceof NodeSelection && selection.node.type.name === 'mediaSingle') { const tr = editorSelectionAPI.selectNearNode({ selectionRelativeToNode: undefined, selection: new GapCursorSelection(state.doc.resolve(selection.from), Side.LEFT) })(state); if (dispatch) { dispatch(tr); } return true; } return false; }; const arrowRightFromMediaSingle = editorSelectionAPI => (state, dispatch) => { const { selection } = state; if (editorSelectionAPI && selection instanceof NodeSelection && selection.node.type.name === 'mediaSingle') { const tr = editorSelectionAPI.selectNearNode({ selectionRelativeToNode: undefined, selection: new GapCursorSelection(state.doc.resolve(selection.to), Side.RIGHT) })(state); if (dispatch) { dispatch(tr); } return true; } return false; }; export default keymapPlugin;