@gechiui/block-editor
Version:
443 lines (391 loc) • 14.3 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.OnCaretVerticalPositionChange = exports.BlockList = void 0;
var _element = require("@gechiui/element");
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _lodash = require("lodash");
var _reactNative = require("react-native");
var _data = require("@gechiui/data");
var _compose = require("@gechiui/compose");
var _blocks = require("@gechiui/blocks");
var _components = require("@gechiui/components");
var _i18n = require("@gechiui/i18n");
var _style = _interopRequireDefault(require("./style.scss"));
var _blockListAppender = _interopRequireDefault(require("../block-list-appender"));
var _blockListItem = _interopRequireDefault(require("./block-list-item"));
var _store = require("../../store");
/**
* External dependencies
*/
/**
* GeChiUI dependencies
*/
/**
* Internal dependencies
*/
const BlockListContext = (0, _element.createContext)();
const OnCaretVerticalPositionChange = (0, _element.createContext)();
exports.OnCaretVerticalPositionChange = OnCaretVerticalPositionChange;
const stylesMemo = {};
const getStyles = (isRootList, isStackedHorizontally, horizontalAlignment) => {
if (isRootList) {
return;
}
const styleName = `${isStackedHorizontally}-${horizontalAlignment}`;
if (stylesMemo[styleName]) {
return stylesMemo[styleName];
}
const computedStyles = [isStackedHorizontally && _style.default.horizontal, horizontalAlignment && _style.default[`is-aligned-${horizontalAlignment}`], _style.default.overflowVisible];
stylesMemo[styleName] = computedStyles;
return computedStyles;
};
class BlockList extends _element.Component {
constructor() {
super(...arguments);
this.extraData = {
parentWidth: this.props.parentWidth,
renderFooterAppender: this.props.renderFooterAppender,
renderAppender: this.props.renderAppender,
onDeleteBlock: this.props.onDeleteBlock,
contentStyle: this.props.contentStyle
};
this.renderItem = this.renderItem.bind(this);
this.renderBlockListFooter = this.renderBlockListFooter.bind(this);
this.onCaretVerticalPositionChange = this.onCaretVerticalPositionChange.bind(this);
this.scrollViewInnerRef = this.scrollViewInnerRef.bind(this);
this.addBlockToEndOfPost = this.addBlockToEndOfPost.bind(this);
this.shouldFlatListPreventAutomaticScroll = this.shouldFlatListPreventAutomaticScroll.bind(this);
this.shouldShowInnerBlockAppender = this.shouldShowInnerBlockAppender.bind(this);
this.renderEmptyList = this.renderEmptyList.bind(this);
this.getExtraData = this.getExtraData.bind(this);
this.onLayout = this.onLayout.bind(this);
this.state = {
blockWidth: this.props.blockWidth || 0
};
}
addBlockToEndOfPost(newBlock) {
this.props.insertBlock(newBlock, this.props.blockCount);
}
onCaretVerticalPositionChange(targetId, caretY, previousCaretY) {
_components.KeyboardAwareFlatList.handleCaretVerticalPositionChange(this.scrollViewRef, targetId, caretY, previousCaretY);
}
scrollViewInnerRef(ref) {
this.scrollViewRef = ref;
}
shouldFlatListPreventAutomaticScroll() {
return this.props.isBlockInsertionPointVisible;
}
shouldShowInnerBlockAppender() {
const {
blockClientIds,
renderAppender
} = this.props;
return renderAppender && blockClientIds.length > 0;
}
renderEmptyList() {
return (0, _element.createElement)(EmptyListComponentCompose, {
rootClientId: this.props.rootClientId,
renderAppender: this.props.renderAppender,
renderFooterAppender: this.props.renderFooterAppender
});
}
getExtraData() {
const {
parentWidth,
renderFooterAppender,
onDeleteBlock,
contentStyle,
renderAppender,
gridProperties
} = this.props;
const {
blockWidth
} = this.state;
if (this.extraData.parentWidth !== parentWidth || this.extraData.renderFooterAppender !== renderFooterAppender || this.extraData.onDeleteBlock !== onDeleteBlock || this.extraData.contentStyle !== contentStyle || this.extraData.renderAppender !== renderAppender || this.extraData.blockWidth !== blockWidth || this.extraData.gridProperties !== gridProperties) {
this.extraData = {
parentWidth,
renderFooterAppender,
onDeleteBlock,
contentStyle,
renderAppender,
blockWidth,
gridProperties
};
}
return this.extraData;
}
onLayout(_ref) {
let {
nativeEvent
} = _ref;
const {
layout
} = nativeEvent;
const {
blockWidth
} = this.state;
const {
isRootList,
maxWidth
} = this.props;
const layoutWidth = Math.floor(layout.width);
if (isRootList && blockWidth !== layoutWidth) {
this.setState({
blockWidth: Math.min(layoutWidth, maxWidth)
});
} else if (!isRootList && !blockWidth) {
this.setState({
blockWidth: Math.min(layoutWidth, maxWidth)
});
}
}
render() {
const {
isRootList
} = this.props; // Use of Context to propagate the main scroll ref to its children e.g InnerBlocks
const blockList = isRootList ? (0, _element.createElement)(BlockListContext.Provider, {
value: this.scrollViewRef
}, this.renderList()) : (0, _element.createElement)(BlockListContext.Consumer, null, ref => this.renderList({
parentScrollRef: ref
}));
return (0, _element.createElement)(OnCaretVerticalPositionChange.Provider, {
value: this.onCaretVerticalPositionChange
}, blockList);
}
renderList() {
let extraProps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
const {
clearSelectedBlock,
blockClientIds,
title,
header,
isReadOnly,
isRootList,
horizontal,
marginVertical = _style.default.defaultBlock.marginTop,
marginHorizontal = _style.default.defaultBlock.marginLeft,
isFloatingToolbarVisible,
isStackedHorizontally,
horizontalAlignment,
contentResizeMode,
blockWidth
} = this.props;
const {
parentScrollRef
} = extraProps;
const {
blockToolbar,
blockBorder,
headerToolbar,
floatingToolbar
} = _style.default;
const containerStyle = {
flex: isRootList ? 1 : 0,
// We set negative margin in the parent to remove the edge spacing between parent block and child block in ineer blocks
marginVertical: isRootList ? 0 : -marginVertical,
marginHorizontal: isRootList ? 0 : -marginHorizontal
};
const isContentStretch = contentResizeMode === 'stretch';
const isMultiBlocks = blockClientIds.length > 1;
const {
isWider
} = _components.alignmentHelpers;
return (0, _element.createElement)(_reactNative.View, {
style: containerStyle,
onAccessibilityEscape: clearSelectedBlock,
onLayout: this.onLayout,
testID: "block-list-wrapper"
}, (0, _element.createElement)(_components.KeyboardAwareFlatList, (0, _extends2.default)({}, _reactNative.Platform.OS === 'android' ? {
removeClippedSubviews: false
} : {}, {
// Disable clipping on Android to fix focus losing. See https://github.com/gechiui-mobile/gutenberg-mobile/pull/741#issuecomment-472746541
accessibilityLabel: "block-list",
autoScroll: this.props.autoScroll,
innerRef: ref => {
this.scrollViewInnerRef(parentScrollRef || ref);
},
extraScrollHeight: blockToolbar.height + blockBorder.width,
inputAccessoryViewHeight: headerToolbar.height + (isFloatingToolbarVisible ? floatingToolbar.height : 0),
keyboardShouldPersistTaps: "always",
scrollViewStyle: [{
flex: isRootList ? 1 : 0
}, !isRootList && _style.default.overflowVisible],
extraData: this.getExtraData(),
scrollEnabled: isRootList,
contentContainerStyle: [horizontal && _style.default.horizontalContentContainer, isWider(blockWidth, 'medium') && (isContentStretch && isMultiBlocks ? _style.default.horizontalContentContainerStretch : _style.default.horizontalContentContainerCenter)],
style: getStyles(isRootList, isStackedHorizontally, horizontalAlignment),
data: blockClientIds,
keyExtractor: _lodash.identity,
renderItem: this.renderItem,
shouldPreventAutomaticScroll: this.shouldFlatListPreventAutomaticScroll,
title: title,
ListHeaderComponent: header,
ListEmptyComponent: !isReadOnly && this.renderEmptyList,
ListFooterComponent: this.renderBlockListFooter
})), this.shouldShowInnerBlockAppender() && (0, _element.createElement)(_reactNative.View, {
style: {
marginHorizontal: marginHorizontal - _style.default.innerAppender.marginLeft
}
}, (0, _element.createElement)(_blockListAppender.default, {
rootClientId: this.props.rootClientId,
renderAppender: this.props.renderAppender,
showSeparator: true
})));
}
renderItem(_ref2) {
let {
item: clientId
} = _ref2;
const {
contentResizeMode,
contentStyle,
onAddBlock,
onDeleteBlock,
rootClientId,
isStackedHorizontally,
blockClientIds,
parentWidth,
marginVertical = _style.default.defaultBlock.marginTop,
marginHorizontal = _style.default.defaultBlock.marginLeft,
gridProperties
} = this.props;
const {
blockWidth
} = this.state;
return (0, _element.createElement)(_blockListItem.default, {
isStackedHorizontally: isStackedHorizontally,
rootClientId: rootClientId,
clientId: clientId,
parentWidth: parentWidth,
contentResizeMode: contentResizeMode,
contentStyle: contentStyle,
onAddBlock: onAddBlock,
marginVertical: marginVertical,
marginHorizontal: marginHorizontal,
onDeleteBlock: onDeleteBlock,
shouldShowInnerBlockAppender: this.shouldShowInnerBlockAppender,
blockWidth: blockWidth,
gridProperties: gridProperties,
items: blockClientIds
});
}
renderBlockListFooter() {
const paragraphBlock = (0, _blocks.createBlock)('core/paragraph');
const {
isReadOnly,
withFooter = true,
renderFooterAppender
} = this.props;
if (!isReadOnly && withFooter) {
return (0, _element.createElement)(_element.Fragment, null, (0, _element.createElement)(_reactNative.TouchableWithoutFeedback, {
accessibilityLabel: (0, _i18n.__)('Add paragraph block'),
testID: (0, _i18n.__)('Add paragraph block'),
onPress: () => {
this.addBlockToEndOfPost(paragraphBlock);
}
}, (0, _element.createElement)(_reactNative.View, {
style: _style.default.blockListFooter
})));
} else if (renderFooterAppender) {
return renderFooterAppender();
}
return null;
}
}
exports.BlockList = BlockList;
var _default = (0, _compose.compose)([(0, _data.withSelect)((select, _ref3) => {
let {
rootClientId,
orientation,
filterInnerBlocks
} = _ref3;
const {
getBlockCount,
getBlockOrder,
getSelectedBlockClientId,
isBlockInsertionPointVisible,
getSettings
} = select(_store.store);
const isStackedHorizontally = orientation === 'horizontal';
const selectedBlockClientId = getSelectedBlockClientId();
let blockClientIds = getBlockOrder(rootClientId); // Display only block which fulfill the condition in passed `filterInnerBlocks` function
if (filterInnerBlocks) {
blockClientIds = filterInnerBlocks(blockClientIds);
}
const {
maxWidth
} = getSettings();
const isReadOnly = getSettings().readOnly;
const blockCount = getBlockCount();
const hasRootInnerBlocks = !!blockCount;
const isFloatingToolbarVisible = !!selectedBlockClientId && hasRootInnerBlocks;
return {
blockClientIds,
blockCount,
isBlockInsertionPointVisible: _reactNative.Platform.OS === 'ios' && isBlockInsertionPointVisible(),
isReadOnly,
isRootList: rootClientId === undefined,
isFloatingToolbarVisible,
isStackedHorizontally,
maxWidth
};
}), (0, _data.withDispatch)(dispatch => {
const {
insertBlock,
replaceBlock,
clearSelectedBlock
} = dispatch(_store.store);
return {
clearSelectedBlock,
insertBlock,
replaceBlock
};
}), _compose.withPreferredColorScheme])(BlockList);
exports.default = _default;
class EmptyListComponent extends _element.Component {
render() {
const {
shouldShowInsertionPoint,
rootClientId,
renderAppender,
renderFooterAppender
} = this.props;
if (renderFooterAppender) {
return null;
}
return (0, _element.createElement)(_reactNative.View, {
style: _style.default.defaultAppender
}, (0, _element.createElement)(_components.ReadableContentView, {
align: renderAppender ? _components.WIDE_ALIGNMENTS.alignments.full : undefined
}, (0, _element.createElement)(_blockListAppender.default, {
rootClientId: rootClientId,
renderAppender: renderAppender,
showSeparator: shouldShowInsertionPoint
})));
}
}
const EmptyListComponentCompose = (0, _compose.compose)([(0, _data.withSelect)((select, _ref4) => {
let {
rootClientId,
orientation
} = _ref4;
const {
getBlockOrder,
getBlockInsertionPoint,
isBlockInsertionPointVisible
} = select(_store.store);
const isStackedHorizontally = orientation === 'horizontal';
const blockClientIds = getBlockOrder(rootClientId);
const insertionPoint = getBlockInsertionPoint();
const blockInsertionPointIsVisible = isBlockInsertionPointVisible();
const shouldShowInsertionPoint = !isStackedHorizontally && blockInsertionPointIsVisible && insertionPoint.rootClientId === rootClientId && ( // if list is empty, show the insertion point (via the default appender)
blockClientIds.length === 0 || // or if the insertion point is right before the denoted block
!blockClientIds[insertionPoint.index]);
return {
shouldShowInsertionPoint
};
})])(EmptyListComponent);
//# sourceMappingURL=index.native.js.map