@wordpress/block-library
Version:
Block library for the WordPress editor.
498 lines (436 loc) • 18.8 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _element = require("@wordpress/element");
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _reactNative = require("react-native");
var _reactNativeVideo = _interopRequireDefault(require("react-native-video"));
var _dedupe = _interopRequireDefault(require("classnames/dedupe"));
var _reactNativeBridge = require("@wordpress/react-native-bridge");
var _i18n = require("@wordpress/i18n");
var _components = require("@wordpress/components");
var _blockEditor = require("@wordpress/block-editor");
var _compose = require("@wordpress/compose");
var _data = require("@wordpress/data");
var _icons = require("@wordpress/icons");
var _url = require("@wordpress/url");
var _editPost = require("@wordpress/edit-post");
var _style = _interopRequireDefault(require("./style.scss"));
var _shared = require("./shared");
var _controls = _interopRequireDefault(require("./controls"));
var _useCoverIsDark = _interopRequireDefault(require("./use-cover-is-dark"));
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
/**
* Constants
*/
const INNER_BLOCKS_TEMPLATE = [['core/paragraph', {
align: 'center',
placeholder: (0, _i18n.__)('Write title…')
}]];
const Cover = _ref => {
var _style$color, _styles$overlay;
let {
attributes,
getStylesFromColorScheme,
isParentSelected,
onFocus,
setAttributes,
openGeneralSidebar,
closeSettingsBottomSheet,
isSelected,
selectBlock,
blockWidth,
hasInnerBlocks
} = _ref;
const {
backgroundType,
dimRatio,
focalPoint,
minHeight,
url,
id,
style,
customOverlayColor,
minHeightUnit = 'px',
allowedBlocks,
templateLock,
customGradient,
gradient,
overlayColor,
isDark
} = attributes;
const [isScreenReaderEnabled, setIsScreenReaderEnabled] = (0, _element.useState)(false);
(0, _element.useEffect)(() => {
let isCurrent = true; // Sync with local media store.
(0, _reactNativeBridge.mediaUploadSync)();
const a11yInfoChangeSubscription = _reactNative.AccessibilityInfo.addEventListener('screenReaderChanged', setIsScreenReaderEnabled);
_reactNative.AccessibilityInfo.isScreenReaderEnabled().then(() => {
if (isCurrent) {
setIsScreenReaderEnabled();
}
});
return () => {
isCurrent = false;
a11yInfoChangeSubscription.remove();
};
}, []);
const convertedMinHeight = (0, _components.useConvertUnitToMobile)(minHeight || _shared.COVER_DEFAULT_HEIGHT, minHeightUnit);
const isImage = backgroundType === _blockEditor.MEDIA_TYPE_IMAGE;
const THEME_COLORS_COUNT = 4;
const colorsDefault = (0, _components.useMobileGlobalStylesColors)();
const coverDefaultPalette = (0, _element.useMemo)(() => {
return {
colors: colorsDefault.slice(0, THEME_COLORS_COUNT)
};
}, [colorsDefault]);
const gradients = (0, _components.useMobileGlobalStylesColors)('gradients');
const gradientValue = customGradient || (0, _blockEditor.getGradientValueBySlug)(gradients, gradient);
const overlayColorValue = (0, _blockEditor.getColorObjectByAttributeValues)(colorsDefault, overlayColor);
const hasBackground = !!(url || style && style.color && style.color.background || attributes.overlayColor || overlayColorValue.color || customOverlayColor || gradientValue);
const hasOnlyColorBackground = !url && (hasBackground || hasInnerBlocks);
const [isCustomColorPickerShowing, setCustomColorPickerShowing] = (0, _element.useState)(false);
const openMediaOptionsRef = (0, _element.useRef)(); // Initialize uploading flag to false, awaiting sync.
const [isUploadInProgress, setIsUploadInProgress] = (0, _element.useState)(false); // Initialize upload failure flag to true if url is local.
const [didUploadFail, setDidUploadFail] = (0, _element.useState)(id && (0, _url.getProtocol)(url) === 'file:'); // Don't show failure if upload is in progress.
const shouldShowFailure = didUploadFail && !isUploadInProgress;
const onSelectMedia = media => {
setDidUploadFail(false);
const onSelect = (0, _shared.attributesFromMedia)(setAttributes, dimRatio);
onSelect(media);
};
const onMediaPressed = () => {
if (isUploadInProgress) {
(0, _reactNativeBridge.requestImageUploadCancelDialog)(id);
} else if (shouldShowFailure) {
(0, _reactNativeBridge.requestImageFailedRetryDialog)(id);
} else if (isImage && url) {
(0, _reactNativeBridge.requestImageFullscreenPreview)(url);
}
};
const [isVideoLoading, setIsVideoLoading] = (0, _element.useState)(true);
const onVideoLoadStart = () => {
setIsVideoLoading(true);
};
const onVideoLoad = () => {
setIsVideoLoading(false);
};
const onClearMedia = (0, _element.useCallback)(() => {
setAttributes({
focalPoint: undefined,
hasParallax: undefined,
id: undefined,
url: undefined
});
closeSettingsBottomSheet();
}, [closeSettingsBottomSheet]);
function setColor(color) {
var _colorValue$slug, _ref2;
const colorValue = (0, _blockEditor.getColorObjectByColorValue)(colorsDefault, color);
setAttributes({
// Clear all related attributes (only one should be set).
overlayColor: (_colorValue$slug = colorValue === null || colorValue === void 0 ? void 0 : colorValue.slug) !== null && _colorValue$slug !== void 0 ? _colorValue$slug : undefined,
customOverlayColor: (_ref2 = !(colorValue !== null && colorValue !== void 0 && colorValue.slug) && color) !== null && _ref2 !== void 0 ? _ref2 : undefined,
gradient: undefined,
customGradient: undefined
});
}
function openColorPicker() {
selectBlock();
setCustomColorPickerShowing(true);
openGeneralSidebar();
}
const {
__unstableMarkNextChangeAsNotPersistent
} = (0, _data.useDispatch)(_blockEditor.store);
const isCoverDark = (0, _useCoverIsDark.default)(isDark, url, dimRatio, overlayColorValue === null || overlayColorValue === void 0 ? void 0 : overlayColorValue.color);
(0, _element.useEffect)(() => {
var _attributes$className;
// This side-effect should not create an undo level.
__unstableMarkNextChangeAsNotPersistent(); // Used to set a default color for its InnerBlocks
// since there's no system to inherit styles yet
// the RichText component will check if there are
// parent styles for the current block. If there are,
// it will use that color instead.
setAttributes({
isDark: isCoverDark,
childrenStyles: isCoverDark ? _style.default.defaultColor : _style.default.defaultColorLightMode
}); // Ensure that "is-light" is removed from "className" attribute if cover background is dark.
if (isCoverDark && (_attributes$className = attributes.className) !== null && _attributes$className !== void 0 && _attributes$className.includes('is-light')) {
const className = (0, _dedupe.default)(attributes.className, {
'is-light': false
});
setAttributes({
className: className !== '' ? className : undefined
});
}
}, [isCoverDark]);
const backgroundColor = getStylesFromColorScheme(_style.default.backgroundSolid, _style.default.backgroundSolidDark);
const overlayStyles = [_style.default.overlay, url && {
opacity: dimRatio / 100
}, !gradientValue && {
backgroundColor: customOverlayColor || (overlayColorValue === null || overlayColorValue === void 0 ? void 0 : overlayColorValue.color) || (style === null || style === void 0 ? void 0 : (_style$color = style.color) === null || _style$color === void 0 ? void 0 : _style$color.background) || ((_styles$overlay = _style.default.overlay) === null || _styles$overlay === void 0 ? void 0 : _styles$overlay.color)
}, // While we don't support theme colors we add a default bg color.
!overlayColorValue.color && !url ? backgroundColor : {}, isImage && isParentSelected && !isUploadInProgress && !didUploadFail && _style.default.overlaySelected];
const placeholderIconStyle = getStylesFromColorScheme(_style.default.icon, _style.default.iconDark);
const placeholderIcon = (0, _element.createElement)(_components.Icon, (0, _extends2.default)({
icon: _icons.cover
}, placeholderIconStyle));
const toolbarControls = open => (0, _element.createElement)(_blockEditor.BlockControls, {
group: "other"
}, (0, _element.createElement)(_components.ToolbarButton, {
title: (0, _i18n.__)('Edit cover media'),
icon: _icons.replace,
onClick: open
}));
const accessibilityHint = _reactNative.Platform.OS === 'ios' ? (0, _i18n.__)('Double tap to open Action Sheet to add image or video') : (0, _i18n.__)('Double tap to open Bottom Sheet to add image or video');
const addMediaButton = () => (0, _element.createElement)(_reactNative.TouchableWithoutFeedback, {
accessibilityHint: accessibilityHint,
accessibilityLabel: (0, _i18n.__)('Add image or video'),
accessibilityRole: "button",
onPress: openMediaOptionsRef.current
}, (0, _element.createElement)(_reactNative.View, {
style: _style.default.selectImageContainer
}, (0, _element.createElement)(_reactNative.View, {
style: _style.default.selectImage
}, (0, _element.createElement)(_components.Icon, (0, _extends2.default)({
size: 16,
icon: _icons.image
}, _style.default.selectImageIcon)))));
const onBottomSheetClosed = (0, _element.useCallback)(() => {
_reactNative.InteractionManager.runAfterInteractions(() => {
setCustomColorPickerShowing(false);
});
}, []);
const colorPickerControls = (0, _element.createElement)(_blockEditor.InspectorControls, null, (0, _element.createElement)(_components.BottomSheetConsumer, null, _ref3 => {
let {
shouldEnableBottomSheetScroll,
shouldEnableBottomSheetMaxHeight,
onHandleClosingBottomSheet,
onHandleHardwareButtonPress,
isBottomSheetContentScrolling
} = _ref3;
return (0, _element.createElement)(_components.ColorPicker, {
shouldEnableBottomSheetScroll: shouldEnableBottomSheetScroll,
shouldEnableBottomSheetMaxHeight: shouldEnableBottomSheetMaxHeight,
setColor: setColor,
onNavigationBack: closeSettingsBottomSheet,
onHandleClosingBottomSheet: onHandleClosingBottomSheet,
onHandleHardwareButtonPress: onHandleHardwareButtonPress,
onBottomSheetClosed: onBottomSheetClosed,
isBottomSheetContentScrolling: isBottomSheetContentScrolling,
bottomLabelText: (0, _i18n.__)('Select a color')
});
}));
const renderContent = getMediaOptions => (0, _element.createElement)(_element.Fragment, null, renderBackground(getMediaOptions), isParentSelected && hasOnlyColorBackground && addMediaButton());
const renderBackground = getMediaOptions => {
var _styles$image;
return (0, _element.createElement)(_reactNative.TouchableWithoutFeedback, {
accessible: !isParentSelected,
onPress: onMediaPressed,
disabled: !isParentSelected
}, (0, _element.createElement)(_reactNative.View, {
style: [_style.default.background, backgroundColor]
}, getMediaOptions(), isParentSelected && backgroundType === _shared.VIDEO_BACKGROUND_TYPE && toolbarControls(openMediaOptionsRef.current), (0, _element.createElement)(_blockEditor.MediaUploadProgress, {
mediaId: id,
onUpdateMediaProgress: () => {
setIsUploadInProgress(true);
},
onFinishMediaUploadWithSuccess: _ref4 => {
let {
mediaServerId,
mediaUrl
} = _ref4;
setIsUploadInProgress(false);
setDidUploadFail(false);
setAttributes({
id: mediaServerId,
url: mediaUrl,
backgroundType
});
},
onFinishMediaUploadWithFailure: () => {
setIsUploadInProgress(false);
setDidUploadFail(true);
},
onMediaUploadStateReset: () => {
setIsUploadInProgress(false);
setDidUploadFail(false);
setAttributes({
id: undefined,
url: undefined
});
}
}), _shared.IMAGE_BACKGROUND_TYPE === backgroundType && (0, _element.createElement)(_reactNative.View, {
style: _style.default.imageContainer
}, (0, _element.createElement)(_components.Image, {
editButton: false,
focalPoint: focalPoint || _components.IMAGE_DEFAULT_FOCAL_POINT,
isSelected: isParentSelected,
isUploadFailed: didUploadFail,
isUploadInProgress: isUploadInProgress,
onSelectMediaUploadOption: onSelectMedia,
openMediaOptions: openMediaOptionsRef.current,
url: url,
width: (_styles$image = _style.default.image) === null || _styles$image === void 0 ? void 0 : _styles$image.width
})), _shared.VIDEO_BACKGROUND_TYPE === backgroundType && (0, _element.createElement)(_reactNativeVideo.default, {
muted: true,
disableFocus: true,
repeat: true,
resizeMode: 'cover',
source: {
uri: url
},
onLoad: onVideoLoad,
onLoadStart: onVideoLoadStart,
style: [_style.default.background, // Hide Video component since it has black background while loading the source.
{
opacity: isVideoLoading ? 0 : 1
}]
})));
};
if (!hasBackground && !hasInnerBlocks || isCustomColorPickerShowing) {
var _styles$mediaPlacehol;
return (0, _element.createElement)(_reactNative.View, null, isCustomColorPickerShowing && colorPickerControls, (0, _element.createElement)(_blockEditor.MediaPlaceholder, {
height: (_styles$mediaPlacehol = _style.default.mediaPlaceholderEmptyStateContainer) === null || _styles$mediaPlacehol === void 0 ? void 0 : _styles$mediaPlacehol.height,
backgroundColor: customOverlayColor,
hideContent: customOverlayColor !== '' && customOverlayColor !== undefined,
icon: placeholderIcon,
labels: {
title: (0, _i18n.__)('Cover')
},
onSelect: onSelectMedia,
allowedTypes: _shared.ALLOWED_MEDIA_TYPES,
onFocus: onFocus
}, (0, _element.createElement)(_reactNative.View, {
style: _style.default.colorPaletteWrapper,
pointerEvents: isScreenReaderEnabled ? 'none' : 'auto'
}, (0, _element.createElement)(_components.BottomSheetConsumer, null, _ref5 => {
let {
shouldEnableBottomSheetScroll
} = _ref5;
return (0, _element.createElement)(_components.ColorPalette, {
customColorIndicatorStyles: _style.default.paletteColorIndicator,
customIndicatorWrapperStyles: _style.default.paletteCustomIndicatorWrapper,
setColor: setColor,
onCustomPress: openColorPicker,
defaultSettings: coverDefaultPalette,
shouldShowCustomLabel: false,
shouldShowCustomVerticalSeparator: false,
shouldEnableBottomSheetScroll: shouldEnableBottomSheetScroll
});
}))));
}
return (0, _element.createElement)(_reactNative.View, {
style: _style.default.backgroundContainer
}, isSelected && (0, _element.createElement)(_blockEditor.InspectorControls, null, (0, _element.createElement)(_controls.default, {
attributes: attributes,
didUploadFail: didUploadFail,
hasOnlyColorBackground: hasOnlyColorBackground,
isUploadInProgress: isUploadInProgress,
onClearMedia: onClearMedia,
onSelectMedia: onSelectMedia,
setAttributes: setAttributes
})), (0, _element.createElement)(_reactNative.View, {
pointerEvents: "box-none",
style: [_style.default.content, {
minHeight: convertedMinHeight
}]
}, (0, _element.createElement)(_blockEditor.InnerBlocks, {
allowedBlocks: allowedBlocks,
template: INNER_BLOCKS_TEMPLATE,
templateLock: templateLock,
templateInsertUpdatesSelection: true,
blockWidth: blockWidth
})), (0, _element.createElement)(_reactNative.View, {
pointerEvents: "none",
style: _style.default.overlayContainer
}, (0, _element.createElement)(_reactNative.View, {
style: overlayStyles
}, gradientValue && (0, _element.createElement)(_components.Gradient, {
gradientValue: gradientValue,
style: _style.default.background
}))), (0, _element.createElement)(_blockEditor.MediaUpload, {
allowedTypes: _shared.ALLOWED_MEDIA_TYPES,
isReplacingMedia: !hasOnlyColorBackground,
onSelect: onSelectMedia,
render: _ref6 => {
let {
open,
getMediaOptions
} = _ref6;
openMediaOptionsRef.current = open;
return renderContent(getMediaOptions);
}
}), isImage && url && openMediaOptionsRef.current && isParentSelected && !isUploadInProgress && !didUploadFail && (0, _element.createElement)(_reactNative.View, {
style: _style.default.imageEditButton
}, (0, _element.createElement)(_components.ImageEditingButton, {
onSelectMediaUploadOption: onSelectMedia,
openMediaOptions: openMediaOptionsRef.current,
pickerOptions: [{
destructiveButton: true,
id: 'clearMedia',
label: (0, _i18n.__)('Clear Media'),
onPress: onClearMedia,
separated: true,
value: 'clearMedia'
}],
url: url
})), shouldShowFailure && (0, _element.createElement)(_reactNative.View, {
pointerEvents: "none",
style: _style.default.uploadFailedContainer
}, (0, _element.createElement)(_reactNative.View, {
style: _style.default.uploadFailed
}, (0, _element.createElement)(_components.Icon, (0, _extends2.default)({
icon: _icons.warning
}, _style.default.uploadFailedIcon)))));
};
var _default = (0, _compose.compose)([(0, _data.withSelect)((select, _ref7) => {
var _getBlock;
let {
clientId
} = _ref7;
const {
getSelectedBlockClientId,
getBlock
} = select(_blockEditor.store);
const selectedBlockClientId = getSelectedBlockClientId();
const {
getSettings
} = select(_blockEditor.store);
const hasInnerBlocks = ((_getBlock = getBlock(clientId)) === null || _getBlock === void 0 ? void 0 : _getBlock.innerBlocks.length) > 0;
return {
settings: getSettings(),
isParentSelected: selectedBlockClientId === clientId,
hasInnerBlocks
};
}), (0, _data.withDispatch)((dispatch, _ref8) => {
let {
clientId
} = _ref8;
const {
openGeneralSidebar
} = dispatch(_editPost.store);
const {
selectBlock
} = dispatch(_blockEditor.store);
return {
openGeneralSidebar: () => openGeneralSidebar('edit-post/block'),
closeSettingsBottomSheet() {
dispatch(_editPost.store).closeGeneralSidebar();
},
selectBlock: () => selectBlock(clientId)
};
}), _compose.withPreferredColorScheme])(Cover);
exports.default = _default;
//# sourceMappingURL=edit.native.js.map