@wordpress/block-library
Version:
Block library for the WordPress editor.
495 lines (486 loc) • 19.8 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _reactNative = require("react-native");
var _reactNativeVideo = _interopRequireDefault(require("react-native-video"));
var _clsx = _interopRequireDefault(require("clsx"));
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 _element = require("@wordpress/element");
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"));
var _jsxRuntime = require("react/jsx-runtime");
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
// eslint-disable-next-line no-restricted-imports
/**
* Internal dependencies
*/
/**
* Constants
*/const INNER_BLOCKS_TEMPLATE = [['core/paragraph', {
align: 'center',
placeholder: (0, _i18n.__)('Write title…')
}]];
function useIsScreenReaderEnabled() {
const [isScreenReaderEnabled, setIsScreenReaderEnabled] = (0, _element.useState)(false);
(0, _element.useEffect)(() => {
let mounted = true;
const changeListener = _reactNative.AccessibilityInfo.addEventListener('screenReaderChanged', enabled => setIsScreenReaderEnabled(enabled));
_reactNative.AccessibilityInfo.isScreenReaderEnabled().then(screenReaderEnabled => {
if (mounted && screenReaderEnabled) {
setIsScreenReaderEnabled(screenReaderEnabled);
}
});
return () => {
mounted = false;
changeListener.remove();
};
}, []);
return isScreenReaderEnabled;
}
const Cover = ({
attributes,
getStylesFromColorScheme,
isParentSelected,
onFocus,
setAttributes,
openGeneralSidebar,
closeSettingsBottomSheet,
isSelected,
selectBlock,
blockWidth,
hasInnerBlocks
}) => {
const {
backgroundType,
dimRatio,
focalPoint,
minHeight,
url,
id,
style,
customOverlayColor,
minHeightUnit = 'px',
allowedBlocks,
templateLock,
customGradient,
gradient,
overlayColor,
isDark
} = attributes;
const isScreenReaderEnabled = useIsScreenReaderEnabled();
(0, _element.useEffect)(() => {
// Sync with local media store.
(0, _reactNativeBridge.mediaUploadSync)();
}, []);
const globalStyles = (0, _blockEditor.useGlobalStyles)();
const convertedMinHeight = (0, _components.useConvertUnitToMobile)(minHeight || _shared.COVER_DEFAULT_HEIGHT, minHeightUnit, globalStyles);
const isImage = backgroundType === _blockEditor.MEDIA_TYPE_IMAGE;
const THEME_COLORS_COUNT = 4;
const colorsDefault = (0, _blockEditor.useMobileGlobalStylesColors)();
const coverDefaultPalette = (0, _element.useMemo)(() => {
return {
colors: colorsDefault.slice(0, THEME_COLORS_COUNT)
};
}, [colorsDefault]);
const gradients = (0, _blockEditor.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 mediaAttributes = (0, _shared.attributesFromMedia)(media);
setAttributes({
...mediaAttributes,
focalPoint: undefined,
useFeaturedImage: undefined,
dimRatio: dimRatio === 100 ? 50 : dimRatio,
isDark: undefined
});
};
const onUpdateMediaProgress = (0, _element.useCallback)(payload => {
const {
mediaUrl,
state
} = payload;
setIsUploadInProgress(true);
if (isUploadInProgress && isImage && mediaUrl && !state) {
setAttributes({
url: mediaUrl
});
}
}, [isImage, isUploadInProgress, setAttributes]);
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]);
const onAddMediaButtonPress = (0, _element.useCallback)(() => {
if (openMediaOptionsRef?.current) {
openMediaOptionsRef.current();
}
}, []);
function setColor(color) {
var _colorValue$slug, _ref;
const colorValue = (0, _blockEditor.getColorObjectByColorValue)(colorsDefault, color);
setAttributes({
// Clear all related attributes (only one should be set).
overlayColor: (_colorValue$slug = colorValue?.slug) !== null && _colorValue$slug !== void 0 ? _colorValue$slug : undefined,
customOverlayColor: (_ref = !colorValue?.slug && color) !== null && _ref !== void 0 ? _ref : 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?.color);
(0, _element.useEffect)(() => {
// 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?.includes('is-light')) {
const className = (0, _clsx.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?.color || style?.color?.background || _style.default.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 = /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Icon, {
icon: _icons.cover,
...placeholderIconStyle
});
const toolbarControls = open => /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.BlockControls, {
group: "other",
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_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 = () => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableWithoutFeedback, {
accessibilityHint: accessibilityHint,
accessibilityLabel: (0, _i18n.__)('Add image or video'),
accessibilityRole: "button",
onPress: onAddMediaButtonPress,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: _style.default.selectImageContainer,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: _style.default.selectImage,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Icon, {
size: 16,
icon: _icons.image,
..._style.default.selectImageIcon
})
})
})
});
const onBottomSheetClosed = (0, _element.useCallback)(() => {
_reactNative.InteractionManager.runAfterInteractions(() => {
setCustomColorPickerShowing(false);
});
}, []);
const selectedColorText = getStylesFromColorScheme(_style.default.selectedColorText, _style.default.selectedColorTextDark);
const bottomLabelText = customOverlayColor ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
style: selectedColorText,
children: customOverlayColor.toUpperCase()
}) : (0, _i18n.__)('Select a color');
const colorPickerControls = /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, {
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.BottomSheetConsumer, {
children: ({
shouldEnableBottomSheetScroll,
shouldEnableBottomSheetMaxHeight,
onHandleClosingBottomSheet,
onHandleHardwareButtonPress,
isBottomSheetContentScrolling
}) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ColorPicker, {
shouldEnableBottomSheetScroll: shouldEnableBottomSheetScroll,
shouldEnableBottomSheetMaxHeight: shouldEnableBottomSheetMaxHeight,
setColor: setColor,
onNavigationBack: closeSettingsBottomSheet,
onHandleClosingBottomSheet: onHandleClosingBottomSheet,
onHandleHardwareButtonPress: onHandleHardwareButtonPress,
onBottomSheetClosed: onBottomSheetClosed,
isBottomSheetContentScrolling: isBottomSheetContentScrolling,
bottomLabelText: bottomLabelText
})
})
});
const renderContent = getMediaOptions => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [renderBackground(getMediaOptions), isParentSelected && hasOnlyColorBackground && addMediaButton()]
});
const renderBackground = getMediaOptions => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableWithoutFeedback, {
accessible: !isParentSelected,
onPress: onMediaPressed,
disabled: !isParentSelected,
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
style: [_style.default.background, backgroundColor],
children: [getMediaOptions(), isParentSelected && backgroundType === _shared.VIDEO_BACKGROUND_TYPE && toolbarControls(openMediaOptionsRef.current), /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.MediaUploadProgress, {
mediaId: id,
onUpdateMediaProgress: onUpdateMediaProgress,
onFinishMediaUploadWithSuccess: ({
mediaServerId,
mediaUrl
}) => {
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 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: _style.default.imageContainer,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_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: _style.default.image?.width
})
}), _shared.VIDEO_BACKGROUND_TYPE === backgroundType && /*#__PURE__*/(0, _jsxRuntime.jsx)(_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) {
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
children: [isCustomColorPickerShowing && colorPickerControls, /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.MediaPlaceholder, {
height: _style.default.mediaPlaceholderEmptyStateContainer?.height,
backgroundColor: customOverlayColor,
hideContent: customOverlayColor !== '' && customOverlayColor !== undefined,
icon: placeholderIcon,
labels: {
title: (0, _i18n.__)('Cover')
},
onSelect: onSelectMedia,
allowedTypes: _shared.ALLOWED_MEDIA_TYPES,
onFocus: onFocus,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: _style.default.colorPaletteWrapper,
pointerEvents: isScreenReaderEnabled ? 'none' : 'auto',
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.BottomSheetConsumer, {
children: ({
shouldEnableBottomSheetScroll
}) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ColorPalette, {
enableCustomColor: true,
customColorIndicatorStyles: _style.default.paletteColorIndicator,
customIndicatorWrapperStyles: _style.default.paletteCustomIndicatorWrapper,
setColor: setColor,
onCustomPress: openColorPicker,
defaultSettings: coverDefaultPalette,
shouldShowCustomLabel: false,
shouldShowCustomVerticalSeparator: false,
shouldEnableBottomSheetScroll: shouldEnableBottomSheetScroll
})
})
})
})]
});
}
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
style: _style.default.backgroundContainer,
children: [isSelected && /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, {
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_controls.default, {
attributes: attributes,
didUploadFail: didUploadFail,
hasOnlyColorBackground: hasOnlyColorBackground,
isUploadInProgress: isUploadInProgress,
onClearMedia: onClearMedia,
onSelectMedia: onSelectMedia,
setAttributes: setAttributes
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
pointerEvents: "box-none",
style: [_style.default.content, {
minHeight: convertedMinHeight
}],
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InnerBlocks, {
allowedBlocks: allowedBlocks,
template: INNER_BLOCKS_TEMPLATE,
templateLock: templateLock,
templateInsertUpdatesSelection: true,
blockWidth: blockWidth
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
pointerEvents: "none",
style: _style.default.overlayContainer,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: overlayStyles,
children: gradientValue && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Gradient, {
gradientValue: gradientValue,
style: _style.default.background
})
})
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.MediaUpload, {
allowedTypes: _shared.ALLOWED_MEDIA_TYPES,
isReplacingMedia: !hasOnlyColorBackground,
onSelect: onSelectMedia,
render: ({
open,
getMediaOptions
}) => {
openMediaOptionsRef.current = open;
return renderContent(getMediaOptions);
}
}), isImage && url && openMediaOptionsRef.current && isParentSelected && !isUploadInProgress && !didUploadFail && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: _style.default.imageEditButton,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_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 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
pointerEvents: "none",
style: _style.default.uploadFailedContainer,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: _style.default.uploadFailed,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Icon, {
icon: _icons.cautionFilled,
..._style.default.uploadFailedIcon
})
})
})]
});
};
var _default = exports.default = (0, _compose.compose)([(0, _data.withSelect)((select, {
clientId
}) => {
const {
getSelectedBlockClientId,
getBlock
} = select(_blockEditor.store);
const selectedBlockClientId = getSelectedBlockClientId();
const hasInnerBlocks = getBlock(clientId)?.innerBlocks.length > 0;
return {
isParentSelected: selectedBlockClientId === clientId,
hasInnerBlocks
};
}), (0, _data.withDispatch)((dispatch, {
clientId
}) => {
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);
//# sourceMappingURL=edit.native.js.map