-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RNMobile - Cover Block: First iteration #19722
Changes from 10 commits
51f8935
c4bdb88
ac30632
e507dcd
970c666
419abf9
cd3baae
7cee335
dcc1875
eb6fc3b
96ca747
e06c903
a4dfbdd
5305373
e71ee48
21eb57c
a61cbb6
d7875e6
63767ef
4f7d25a
225e2bb
7a9341c
ad28977
b4b9a68
b343b2c
8bebf5e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { View } from 'react-native'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __ } from '@wordpress/i18n'; | ||
import { | ||
Icon, | ||
ImageWithFocalPoint, | ||
PanelBody, | ||
RangeControl, | ||
} from '@wordpress/components'; | ||
import { | ||
InnerBlocks, | ||
InspectorControls, | ||
MEDIA_TYPE_IMAGE, | ||
MediaPlaceholder, | ||
withColors, | ||
} from '@wordpress/block-editor'; | ||
import { compose, withPreferredColorScheme } from '@wordpress/compose'; | ||
import { withSelect } from '@wordpress/data'; | ||
import { useState, useEffect } from '@wordpress/element'; | ||
import { cover as icon } from '@wordpress/icons'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import styles from './style.scss'; | ||
import { onCoverSelectMedia } from './edit.js'; | ||
import { COVER_MIN_HEIGHT, IMAGE_BACKGROUND_TYPE, VIDEO_BACKGROUND_TYPE } from './shared'; | ||
|
||
/** | ||
* Constants | ||
*/ | ||
const ALLOWED_MEDIA_TYPES = [ MEDIA_TYPE_IMAGE ]; | ||
const INNER_BLOCKS_TEMPLATE = [ | ||
[ 'core/paragraph', { | ||
align: 'center', | ||
fontSize: 'large', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a bit concerned about this, since we still can't render or change font sizes from the app. This might lead to the user publishing something quite different from what they're seeing on mobile. This is specially worse if they add more than one paragraph, since the first one will be large by default and the second won't, but they would look the same inside the app. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I didn't think about that 😱 good catch! For now, I'm removing setting the attribute as default until we support font sizes 5305373 |
||
placeholder: __( 'Write title…' ), | ||
} ], | ||
]; | ||
const COVER_MAX_HEIGHT = 1000; | ||
const COVER_DEFAULT_HEIGHT = 300; | ||
|
||
const Cover = ( { | ||
attributes, | ||
isAncestorSelected, | ||
isParentSelected, | ||
isSelected, | ||
onFocus, | ||
overlayColor, | ||
setAttributes, | ||
} ) => { | ||
const { | ||
backgroundType, | ||
dimRatio, | ||
focalPoint, | ||
gradientValue, | ||
minHeight, | ||
url, | ||
} = attributes; | ||
const [ containerSize, setContainerSize ] = useState( null ); | ||
const CONTAINER_HEIGHT = minHeight || COVER_DEFAULT_HEIGHT; | ||
|
||
// 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. | ||
useEffect( () => { | ||
setAttributes( { childrenStyles: styles.defaultColor } ); | ||
}, [ setAttributes ] ); | ||
|
||
const onSelectMedia = ( media ) => { | ||
const onSelect = onCoverSelectMedia( setAttributes ); | ||
onSelect( media ); | ||
}; | ||
|
||
const onHeightChange = ( value ) => { | ||
if ( minHeight || value !== COVER_DEFAULT_HEIGHT ) { | ||
setAttributes( { minHeight: value } ); | ||
} | ||
}; | ||
|
||
const onOpactiyChange = ( value ) => { | ||
setAttributes( { dimRatio: value } ); | ||
}; | ||
|
||
const onContainerLayout = ( event ) => { | ||
const { height, width } = event.nativeEvent.layout; | ||
setContainerSize( { width, height } ); | ||
}; | ||
|
||
const getOpacity = () => { | ||
// Set opacity to 1 while video support is not available | ||
if ( VIDEO_BACKGROUND_TYPE === backgroundType ) { | ||
return 1; | ||
} | ||
|
||
if ( url ) { | ||
return dimRatio !== 0 ? dimRatio / 100 : 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting, how is this different than just doing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I seriously can't recall why I did this 😆 but yeah no need for that, updated it here e06c903 (sorry this commit has more changes due to prettier formatting) |
||
} | ||
|
||
return url ? 0.5 : 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup no need for this, updated it e06c903#diff-b17d53802519ed746057fb2ee4a915edR111 |
||
}; | ||
|
||
const getOverlayStyles = () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For this and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After a few changes, I updated it to be in a const within There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still not sure why it is a function, since it's only called once from within the same component. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right! Didn't see it in your first comment sorry about that! Updated ad28977#diff-b17d53802519ed746057fb2ee4a915edR113 |
||
return [ | ||
styles.overlay, | ||
{ | ||
backgroundColor: overlayColor && overlayColor.color ? overlayColor.color : styles.overlay.color, | ||
opacity: getOpacity(), | ||
}, | ||
]; | ||
}; | ||
|
||
const placeholderIcon = <Icon icon={ icon } { ...styles.icon } />; | ||
|
||
const controls = ( | ||
<InspectorControls> | ||
<PanelBody title={ __( 'Dimensions' ) } > | ||
<RangeControl | ||
label={ __( 'Minimum height in pixels' ) } | ||
minimumValue={ COVER_MIN_HEIGHT } | ||
maximumValue={ COVER_MAX_HEIGHT } | ||
separatorType={ 'none' } | ||
value={ CONTAINER_HEIGHT } | ||
onChange={ onHeightChange } | ||
style={ styles.rangeCellContainer } | ||
/> | ||
</PanelBody> | ||
{ url ? | ||
<PanelBody title={ __( 'Overlay' ) } > | ||
<RangeControl | ||
label={ __( 'Background Opacity' ) } | ||
minimumValue={ 0 } | ||
maximumValue={ 100 } | ||
separatorType={ 'none' } | ||
value={ dimRatio } | ||
onChange={ onOpactiyChange } | ||
style={ styles.rangeCellContainer } | ||
/> | ||
</PanelBody> : null } | ||
</InspectorControls> | ||
); | ||
|
||
const hasBackground = !! ( url || overlayColor.color || gradientValue ); | ||
|
||
const containerStyles = { | ||
...( isParentSelected || isAncestorSelected ? styles.denseMediaPadding : styles.regularMediaPadding ), | ||
...( isSelected && styles.innerPadding ), | ||
}; | ||
|
||
if ( ! hasBackground ) { | ||
return <MediaPlaceholder | ||
icon={ placeholderIcon } | ||
labels={ { | ||
title: __( 'Cover' ), | ||
} } | ||
onSelect={ onSelectMedia } | ||
onlyMediaLibrary={ true } | ||
allowedTypes={ ALLOWED_MEDIA_TYPES } | ||
onFocus={ onFocus } | ||
/>; | ||
} | ||
|
||
return ( | ||
<View style={ containerStyles }> | ||
{ controls } | ||
<View | ||
onLayout={ onContainerLayout } | ||
style={ [ styles.backgroundContainer ] }> | ||
<View style={ [ styles.content, { minHeight: CONTAINER_HEIGHT } ] } > | ||
<InnerBlocks | ||
template={ INNER_BLOCKS_TEMPLATE } | ||
/> | ||
</View> | ||
|
||
<View style={ getOverlayStyles() } /> | ||
|
||
{ IMAGE_BACKGROUND_TYPE === backgroundType && ( | ||
<ImageWithFocalPoint | ||
containerSize={ containerSize } | ||
contentHeight={ containerSize ? containerSize.height : CONTAINER_HEIGHT } | ||
focalPoint={ focalPoint } | ||
url={ url } | ||
/> | ||
) } | ||
</View> | ||
</View> | ||
); | ||
}; | ||
|
||
export default compose( [ | ||
withColors( { overlayColor: 'background-color' } ), | ||
withSelect( ( select, { clientId } ) => { | ||
const { | ||
getSelectedBlockClientId, | ||
getBlockRootClientId, | ||
getBlockParents, | ||
} = select( 'core/block-editor' ); | ||
|
||
const parents = getBlockParents( clientId, true ); | ||
|
||
const selectedBlockClientId = getSelectedBlockClientId(); | ||
const isParentSelected = selectedBlockClientId && selectedBlockClientId === getBlockRootClientId( clientId ); | ||
const isAncestorSelected = selectedBlockClientId && parents.includes( selectedBlockClientId ); | ||
|
||
return { | ||
isSelected: selectedBlockClientId === clientId, | ||
isParentSelected, | ||
isAncestorSelected, | ||
}; | ||
} ), | ||
withPreferredColorScheme, | ||
] )( Cover ); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
.icon { | ||
fill: $gray-dark; | ||
height: 24px; | ||
width: 24px; | ||
} | ||
|
||
.innerPadding { | ||
padding: $block-selected-to-content; | ||
} | ||
|
||
.regularMediaPadding { | ||
padding: $block-edge-to-content; | ||
} | ||
|
||
.denseMediaPadding { | ||
padding: $block-media-container-to-content; | ||
} | ||
|
||
.backgroundContainer { | ||
overflow: hidden; | ||
width: 100%; | ||
position: relative; | ||
} | ||
|
||
.content { | ||
justify-content: center; | ||
width: 100%; | ||
z-index: 3; | ||
} | ||
|
||
.overlay { | ||
width: 100%; | ||
height: 100%; | ||
z-index: 2; | ||
color: $black; | ||
position: absolute; | ||
} | ||
|
||
.defaultColor { | ||
color: $white; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is OK, but I'm wondering if it'd be better to extract this logic to a shared
utils
file instead, and have aattributesFromMedia
function there.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is better to extract it, especially since the web file is kinda big already. a4dfbdd thanks for the name suggestion!