WordPress Gutenberg Register Multiple Custom Blocks - wordpress

I am trying to create several custom blocks within Gutenberg. It is only allowing me to register one at a time.
I have tried combining recipe_card_block() and first_block() but that doesn't help.
Both blocks work correctly individually. If I remove recipe_card_block(), first_block() will appear in the inserter (and vice versa). However, when both are present only the first one will show up. Changing the order in which they are registered affects which one appears.
It seems to me they are somehow overwriting each other, but I don't see how that's happening.
Here is the code in functions.php.
function recipe_card_block(){
wp_register_script(
'recipe-card-script', // name of script
get_template_directory_uri() . '/js/recipe-card.js', // path to script
array( 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components' ) // dependencies
);
wp_register_style(
'recipe-card-style',
get_template_directory_uri() . '/css/recipe-card-style.css',
array( 'wp-edit-blocks' )
);
register_block_type('gadam/recipe-card', array(
'editor_script' => 'recipe-card-script', // default script / script to define behavior within the editor
'style' => 'recipe-card-style' // default styles
) );
}
add_action( 'init', 'recipe_card_block' );
function first_block(){
wp_register_script(
'first-block-script', // name of script
get_template_directory_uri() . '/js/first-block.js', // path to script
array( 'wp-blocks', 'wp-element', 'wp-editor' ) // dependencies
);
// styles for editor view
wp_register_style(
'first-block-editor-style',
get_template_directory_uri() . '/css/first-block-editor-style.css',
array( 'wp-edit-blocks' )
);
// default styles
wp_register_style(
'first-block-style',
get_template_directory_uri() . '/css/first-block-style.css',
array( 'wp-edit-blocks' )
);
register_block_type('gadam/first-block', array(
'editor_script' => 'first-block-script', // default script / script to define behavior within the editor
'editor_style' => 'first-block-editor-style', // styles for editor view
'style' => 'first-block-style' // default styles
) );
}
add_action( 'init', 'first_block' );
This is the code in first-block.js
const { registerBlockType } = wp.blocks;
const { RichText, BlockControls, InspectorControls, AlignmentToolbar, FontSizePicker } = wp.editor;
const { Fragment } = wp.element;
registerBlockType( 'gadam/first-block', {
title: 'First Block',
icon: 'welcome-learn-more',
category: 'custom-blocks',
attributes: {
content: {
type: 'string',
source: 'html',
selector: 'p'
},
alignment: {
type: 'string'
},
fontSize: {
type: 'number',
default: 18
}
},
edit( { attributes, className, setAttributes } ) {
const { content, alignment, fontSize } = attributes;
const fontSizes = [
{
name: 'Small',
slug: 'small',
size: 14
},
{
name: 'Normal',
slug: 'normal',
size: 18
},
{
name: 'Large',
slug: 'large',
size: 24
}
];
function onChangeContent( newContent ) {
setAttributes( { content: newContent } );
}
function onChangeAlignment( newAlignment ) {
setAttributes( { alignment: newAlignment } );
}
function onChangeFontSize( newFontSize ) {
setAttributes( { fontSize: newFontSize } );
}
return (
<Fragment>
<BlockControls>
<AlignmentToolbar
value={ alignment }
onChange={ onChangeAlignment }
/>
</BlockControls>
<InspectorControls>
<AlignmentToolbar
value={ alignment }
onChange={ onChangeAlignment }
/>
<FontSizePicker
fontSizes={ fontSizes }
value={ fontSize }
onChange={ onChangeFontSize }
/>
</InspectorControls>
<RichText
key="editable"
tagName="p"
className={ className }
style={ { textAlign: alignment, fontSize: fontSize } }
onChange={ onChangeContent }
value={ content }
/>
</Fragment>
);
},
save( { attributes } ) {
const { content, alignment, fontSize } = attributes;
const baseClass = 'wp-block-gadam-first-block';
return (
<div class="container">
<div class={ baseClass }>
<RichText.Content
style={ { textAlign: alignment, fontSize: fontSize } }
value={ content }
tagName="p"
/>
</div>
</div>
);
},
} );
And finally, this is recipe-card.js
const { registerBlockType } = wp.blocks;
const { RichText, BlockControls, InspectorControls, AlignmentToolbar, FontSizePicker } = wp.editor;
const { Fragment } = wp.element;
registerBlockType( 'gadam/recipe-card', {
title: 'Recipe Card',
icon: 'index-card',
category: 'custom-blocks',
attributes: {
content: {
type: 'string',
source: 'html',
selector: 'p'
},
alignment: {
type: 'string'
},
fontSize: {
type: 'number',
default: 18
}
},
edit( { attributes, className, setAttributes } ) {
const { content, alignment, fontSize } = attributes;
const fontSizes = [
{
name: 'Small',
slug: 'small',
size: 14
},
{
name: 'Normal',
slug: 'normal',
size: 18
},
{
name: 'Large',
slug: 'large',
size: 24
}
];
function onChangeContent( newContent ) {
setAttributes( { content: newContent } );
}
function onChangeAlignment( newAlignment ) {
setAttributes( { alignment: newAlignment } );
}
function onChangeFontSize( newFontSize ) {
setAttributes( { fontSize: newFontSize } );
}
return (
<Fragment>
<BlockControls>
<AlignmentToolbar
value={ alignment }
onChange={ onChangeAlignment }
/>
</BlockControls>
<InspectorControls>
<AlignmentToolbar
value={ alignment }
onChange={ onChangeAlignment }
/>
<FontSizePicker
fontSizes={ fontSizes }
value={ fontSize }
onChange={ onChangeFontSize }
/>
</InspectorControls>
<RichText
key="editable"
tagName="p"
className={ className }
style={ { textAlign: alignment, fontSize: fontSize } }
onChange={ onChangeContent }
value={ content }
/>
</Fragment>
);
},
save( { attributes } ) {
const { content, alignment, fontSize } = attributes;
const baseClass = 'wp-block-gadam-recipe-card';
return (
<div class="container">
<div class={ baseClass }>
<RichText.Content
style={ { textAlign: alignment, fontSize: fontSize } }
value={ content }
tagName="p"
/>
</div>
</div>
);
},
} );

For anyone who may come across this in the future:
Look at the top of the two js files I posted. The constants declared in one file are shared by all subsequently registered blocks. So what's happening is when I register first-block the constants are defined. When I register recipe-card it tries to define the constants at the top of the file, but they were already defined by first-block.
The code for recipe-card.js should remove the constants that are already defined by first-block.
registerBlockType( 'gadam/recipe-card', {
title: 'Recipe Card',
icon: 'index-card',
category: 'custom-blocks',
attributes: {
content: {
type: 'string',
source: 'html',
selector: 'p'
},
alignment: {
type: 'string'
},
fontSize: {
type: 'number',
default: 18
}
},
edit( { attributes, className, setAttributes } ) {
const { content, alignment, fontSize } = attributes;
const fontSizes = [
{
name: 'Small',
slug: 'small',
size: 14
},
{
name: 'Normal',
slug: 'normal',
size: 18
},
{
name: 'Large',
slug: 'large',
size: 24
}
];
function onChangeContent( newContent ) {
setAttributes( { content: newContent } );
}
function onChangeAlignment( newAlignment ) {
setAttributes( { alignment: newAlignment } );
}
function onChangeFontSize( newFontSize ) {
setAttributes( { fontSize: newFontSize } );
}
return (
<Fragment>
<BlockControls>
<AlignmentToolbar
value={ alignment }
onChange={ onChangeAlignment }
/>
</BlockControls>
<InspectorControls>
<AlignmentToolbar
value={ alignment }
onChange={ onChangeAlignment }
/>
<FontSizePicker
fontSizes={ fontSizes }
value={ fontSize }
onChange={ onChangeFontSize }
/>
</InspectorControls>
<RichText
key="editable"
tagName="p"
className={ className }
style={ { textAlign: alignment, fontSize: fontSize } }
onChange={ onChangeContent }
value={ content }
/>
</Fragment>
);
},
save( { attributes } ) {
const { content, alignment, fontSize } = attributes;
const baseClass = 'wp-block-gadam-recipe-card';
return (
<div class="container">
<div class={ baseClass }>
<RichText.Content
style={ { textAlign: alignment, fontSize: fontSize } }
value={ content }
tagName="p"
/>
</div>
</div>
);
},
} );

Related

React table header width is changing when there is no data (after filtering)

I am working on a react-table that has sort and filter functionalities. When I filter and there is no data to be returned (empty table), the headers' widths are not staying fixed, they get reduced accordingly to the length of the header title. This is happening because when there is no data, tbody is completely empty, thus there are no cells that the headers can use for defining their widths.
You can see that in the schema when I am rendering each cell, I am assigning it a class. I use that class in the stylesheet to give the cells a specific width. I want all the cells to have a fixed width of 140px, and only the summary cell (task type) to have a fixed width of 360px. This works great for the cells, and when there is data the headers follow the cell widths.
See the picture (I had to cover the data due to privacy + I am showing only one row) - in reality, it has more. You can see in the picture that the header widths are matching the cells' widths.
Now, as soon as I filter the data out, and the filter input does not match any of the data, the headers get reduced to a width that depends on the length of the header titles. See picture:
The best comparison would be the following pictures of both headers placed on top of each other:
I tried many things: from using the useBlock/Absolute/FlexLayout Hooks to assigning the widths in the schema instead of via a CSS class, to playing around with CSS and trying out different options, but so far nothing works.
I would be thankful for any tips and suggestions.
Here is the code for the table UI:
const TaskManagerTable = (props) => {
const {columns, data} = props;
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable({
columns,
data,
},
useFilters,
useSortBy,
);
return (
<>
<table className={CLASS_NAMES.TABLE}{...getTableProps()}>
<thead className={CLASS_NAMES.TABLE_HEAD}>
{headerGroups.map(headerGroup => {
const {key, ...restHeaderGroupProps} = headerGroup.getHeaderGroupProps()
return (
<tr className={CLASS_NAMES.HEADER_ROW} key={key} {...restHeaderGroupProps}>
{headerGroup.headers.map(column => {
const {key, ...restColumn} = column.getHeaderProps();
return (
<th className={CLASS_NAMES.HEADER_CELL} key={key} {...restColumn}
style={{
cursor: column.canSort ? 'pointer' : 'auto',
}}
>
{column.render('Header')}
<span className={CLASS_NAMES.SORT} {...column.getHeaderProps(column.getSortByToggleProps())}>
{column.isSorted ?
<div className={CLASS_NAMES.ICON_SORTED}>
<SortIcon dir={column.isSortedDesc ? 'desc' : 'asc'} onClick={_.noop} />
</div>
: column.canSort
? <div className={CLASS_NAMES.ICON_CAN_SORT}>
<SortIcon dir={column.isSortedDesc ? 'desc' : 'asc'} onClick={_.noop} />
</div> : ''
}
</span>
<span className={CLASS_NAMES.FILTER}>
{column.canFilter ? column.render('Filter') : null}
</span>
</th>
)
})}
</tr>
)
})}
</thead>
<tbody {...getTableBodyProps}>
{rows.map(row => {
prepareRow(row)
const {key, ...restRowProps} = row.getRowProps();
return (
<tr key={key} {...restRowProps}>
{row.cells.map(cell => {
const {key, ...restCellProps} = cell.getCellProps();
return (
<td key={key} {...restCellProps}>
{cell.render('Cell')}
</td>
);
})}
</tr>
)
})}
</tbody>
</table>
</>
)
};
TaskManagerTable.propTypes = {
columns: PropTypes.array,
data: PropTypes.array,
};
const mapDispatchToProps = {};
export default connect(null, mapDispatchToProps)(TaskManagerTable);
Here is the schema:
export default [
{
Header: 'ID',
accessor: 'key',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const key = _.get(row, 'original.key');
return (
<div className={CLASS_NAMES.ID_CELL}>
{key}
</div>
)
}
},
{
Header: 'Category',
accessor: 'category',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const category = _.get(row, 'original.category');
return (
<div className={CLASS_NAMES.CATEGORY_CELL}>
{category}
</div>
)
}
},
{
Header: 'Subcategory',
accessor: 'subCategory',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const subCategory = _.get(row, 'original.subCategory');
return (
<div className={CLASS_NAMES.SUBCATEGORY_CELL}>
{subCategory}
</div>
)
}
},
{
Header: 'Task Title',
accessor: 'summary',
className: 'summary',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const summary = _.get(row, 'original.summary');
return (
<div className={CLASS_NAMES.SUMMARY_CELL}>
{summary}
</div>
)
}
},
{
Header: 'Priority',
accessor: 'priority',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const priority = _.get(row, 'original.priority');
return (
<div className={CLASS_NAMES.PRIORITY_CELL}>
{priority}
</div>
)
}
},
{
Header: 'Status',
accessor: 'status',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const status = _.get(row, 'original.status');
return (
<div className={CLASS_NAMES.STATUS_CELL}>
{status}
</div>
)
}
},
{
Header: 'Task Type',
accessor: 'type',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
}
]
And finally here is the SCSS:
table {
width: 100%;
thead {
position: sticky;
top: 0;
background-color: white;
tr {
text-align: left;
text-transform: uppercase;
color: #91a4c3;
font-weight: 400;
font-size: 12px;
th {
padding-left: 10px;
padding-bottom: 10px;
.sort-container {
margin-left: 25px;
position: absolute;
}
.filter-container {
margin-left: 30px;
position: absolute;
}
.icon-can-sort, .filter-component-hide {
display: none;
}
.filter-component-show {
display: block;
}
&:hover {
.icon-can-sort, .filter-component-hide {
display: block;
}
}
#include relative();
:nth-child(4) {
min-width: 360px;
}
}
}
}
tbody {
overflow-y: auto;
#include scrollBar();
tr {
box-shadow: 0px 1px 5px 0 rgba(104, 105, 111, 0.09);
height: 45px;
color: #6a7097;
text-transform: capitalize;
td {
padding-left: 10px;
}
.id-cell,
.category-cell,
.subcategory-cell,
.priority-cell,
.status-cell,
.type-cell,
{
min-width: 140px;
}
.summary-cell {
min-width: 360px;
}
}
}
}

Is there a way to hide scrollbar in Material UI Table sticky header?

I have a Material-UI Table with a fixed header in a React project (reference: https://material-ui.com/components/tables/#fixed-header). I would like to hide the scrollbar in the table header (which overlaps it), while still showing it in the table body.
I have mostly tried changing the overflow property in the TableContainer, Table, TableHead, and TableBody components, though with poor results. Searching around a bit, it seemed that this problem could be solved setting the display property of the aforementioned components to block. However, this approach let me only move the scrollbar from the TableContainer component to the Table component, not solving the issue and messing up the table layout.
Edit
Working example:
Wanted Beahviour
If you are using makeStyles from material ui like the example you can add :
const useStyles = makeStyles({
root: {
width: '100%',
},
container: {
scrollbarWidth: "none" /* Firefox */,
maxHeight: 440,
"&::-webkit-scrollbar": {
display: "none"
} /* Chrome */
}
});
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { styled } from '#mui/material/styles';
import TableCell from '#mui/material/TableCell';
import Paper from '#mui/material/Paper';
import { AutoSizer, Column, Table } from 'react-virtualized';
const classes = {
flexContainer: 'ReactVirtualizedDemo-flexContainer',
tableRow: 'ReactVirtualizedDemo-tableRow',
tableRowHover: 'ReactVirtualizedDemo-tableRowHover',
tableCell: 'ReactVirtualizedDemo-tableCell',
noClick: 'ReactVirtualizedDemo-noClick',
};
const styles = ({ theme }) => ({
// temporary right-to-left patch, waiting for
// https://github.com/bvaughn/react-virtualized/issues/454
'& .ReactVirtualized__Table__headerRow': {
...(theme.direction === 'rtl' && {
paddingLeft: '0 !important',
}),
...(theme.direction !== 'rtl' && {
paddingRight: undefined,
}),
},
[`& .${classes.flexContainer}`]: {
display: 'flex',
alignItems: 'center',
boxSizing: 'border-box',
},
[`& .${classes.tableRow}`]: {
cursor: 'pointer',
},
[`& .${classes.tableRowHover}`]: {
'&:hover': {
backgroundColor: theme.palette.grey[200],
},
},
[`& .${classes.tableCell}`]: {
flex: 1,
},
[`& .${classes.noClick}`]: {
cursor: 'initial',
},
});
class MuiVirtualizedTable extends React.PureComponent {
static defaultProps = {
headerHeight: 48,
rowHeight: 48,
};
getRowClassName = ({ index }) => {
const { onRowClick } = this.props;
return clsx(classes.tableRow, classes.flexContainer, {
[classes.tableRowHover]: index !== -1 && onRowClick != null,
});
};
cellRenderer = ({ cellData, columnIndex }) => {
const { columns, rowHeight, onRowClick } = this.props;
return (
<TableCell
component="div"
className={clsx(classes.tableCell, classes.flexContainer, {
[classes.noClick]: onRowClick == null,
})}
variant="body"
style={{ height: rowHeight }}
align={
(columnIndex != null && columns[columnIndex].numeric) || false
? 'right'
: 'left'
}
>
{cellData}
</TableCell>
);
};
headerRenderer = ({ label, columnIndex }) => {
const { headerHeight, columns } = this.props;
return (
<TableCell
component="div"
className={clsx(classes.tableCell, classes.flexContainer, classes.noClick)}
variant="head"
style={{ height: headerHeight }}
align={columns[columnIndex].numeric || false ? 'right' : 'left'}
>
<span>{label}</span>
</TableCell>
);
};
render() {
const { columns, rowHeight, headerHeight, ...tableProps } = this.props;
return (
<AutoSizer>
{({ height, width }) => (
<Table
height={height}
width={width}
rowHeight={rowHeight}
gridStyle={{
direction: 'inherit',
}}
headerHeight={headerHeight}
{...tableProps}
rowClassName={this.getRowClassName}
>
{columns.map(({ dataKey, ...other }, index) => {
return (
<Column
key={dataKey}
headerRenderer={(headerProps) =>
this.headerRenderer({
...headerProps,
columnIndex: index,
})
}
className={classes.flexContainer}
cellRenderer={this.cellRenderer}
dataKey={dataKey}
{...other}
/>
);
})}
</Table>
)}
</AutoSizer>
);
}
}
MuiVirtualizedTable.propTypes = {
columns: PropTypes.arrayOf(
PropTypes.shape({
dataKey: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
numeric: PropTypes.bool,
width: PropTypes.number.isRequired,
}),
).isRequired,
headerHeight: PropTypes.number,
onRowClick: PropTypes.func,
rowHeight: PropTypes.number,
};
const VirtualizedTable = styled(MuiVirtualizedTable)(styles);
// ---
const sample = [
['Frozen yoghurt', 159, 6.0, 24, 4.0],
['Ice cream sandwich', 237, 9.0, 37, 4.3],
['Eclair', 262, 16.0, 24, 6.0],
['Cupcake', 305, 3.7, 67, 4.3],
['Gingerbread', 356, 16.0, 49, 3.9],
];
function createData(id, dessert, calories, fat, carbs, protein) {
return { id, dessert, calories, fat, carbs, protein };
}
const rows = [];
for (let i = 0; i < 200; i += 1) {
const randomSelection = sample[Math.floor(Math.random() * sample.length)];
rows.push(createData(i, ...randomSelection));
}
export default function ReactVirtualizedTable() {
return (
<Paper style={{ height: 400, width: '100%' }}>
<VirtualizedTable
rowCount={rows.length}
rowGetter={({ index }) => rows[index]}
columns={[
{
width: 200,
label: 'Dessert',
dataKey: 'dessert',
},
{
width: 120,
label: 'Calories\u00A0(g)',
dataKey: 'calories',
numeric: true,
},
{
width: 120,
label: 'Fat\u00A0(g)',
dataKey: 'fat',
numeric: true,
},
{
width: 120,
label: 'Carbs\u00A0(g)',
dataKey: 'carbs',
numeric: true,
},
{
width: 120,
label: 'Protein\u00A0(g)',
dataKey: 'protein',
numeric: true,
},
]}
/>
</Paper>
);
}
enter link description here

Inline style with Media query in Gutenberg block

I have a custom Gutenberg block which has a media uploader in the editor and renders a div with a background image on the front end. I want to use the full image as background on desktop and the thumbnail as background on mobile. Is it possible to use the useMediaQuery hook to achieve this? Any guidance will be greatly appreciated.
Below is my code:
const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { MediaUploadCheck, MediaUpload } = wp.blockEditor;
const { useMediaQuery } = wp.compose;
registerBlockType( 'blockset/test', {
title: __( 'test' ),
attributes: {
imgUrl: { type: 'string', default: '' },
imgMoUrl: { type: 'string', default: '' },
},
edit: (props) {
return (
<div className="content">
<span>Choose a Hero Image</span>
<MediaUploadCheck>
<MediaUpload
onSelect={ ( img ) => {
props.setAttributes( {
imgUrl: img.url,
imgMoUrl: img.sizes.thumbnail.url : '',
} );
} }
render={ ( { open } ) => {
return props.attributes.imgUrl !== ''? (
<div className={ 'hero__preview' }>
<figure className={ 'image' }>
<img
src={ props.attributes.imgUrl }
/>
</figure>
<Button
className={ 'hero__button' }
onClick={ open }
>
Select a New Image
</Button>
</div>
) : (
<div className={ 'hero__container' }>
<p className={ 'hero__description' }>
Pick a hero image from the media library.
</p>
<Button
className={ 'hero__button' }
onClick={ open }
>
Open Media Library
</Button>
</div>
);
} }
/>
</MediaUploadCheck>
</div>
);
},
save( props ) {
const isMobile = useMediaQuery( 'max-width:767px' )
const imgURL = isMobile ? props.attributes.imgMoUrl : props.attributes.imgUrl
return (
<div
className="background-image"
style={ { backgroundImage: `url(${ imgURL })` } }
></div>
);
},
} );
Solved this issue by using the tag.
<style dangerouslySetInnerHTML={ { __html: `
.background-image {background-image: url(${ props.attributes.imgUrl });}
#media (max-width: 767px) {
.background-image {background-image: url(${ props.attributes.imgMoUrl });}
}
` } }></style>

Material-Button changing disabled button style

How can you change the style of a disabled button in Material-UI using themes ?
The following code doesn't work
const theme = createMuiTheme({
props: {
// Name of the component
MuiButtonBase: {
// The default props to change
disableRipple: true // No more ripple, on the whole application !
}
},
overrides: {
MuiButton: {
text: {
color: "red"
},
disabled: {
text: {
color: "blue"
}
}
}
}
});
function DefaultProps() {
return (
<ThemeProvider theme={theme}>
<Button disabled>Change default props</Button>
</ThemeProvider>
);
}
The following works:
const theme = createMuiTheme({
props: {
// Name of the component
MuiButtonBase: {
// The default props to change
disableRipple: true // No more ripple, on the whole application !
}
},
overrides: {
MuiButton: {
root: {
color: "red",
'&$disabled': {
color: "blue"
}
},
}
}
});

Wordpress Gutenberg block

I have a problem with a custom block which send me an error when I reload the edition page.
I don't understand what the problem is. In regards of the error, actual and expected are the same.
Here the error :
Block validation: Block validation failed for namespace/nottomiss ({object}).
Expected:
<div class="wp-block-utopiales-nottomiss"><p>label test</p><p>label test</p></div>
Actual:
<div class="wp-block-utopiales-nottomiss"><p>label test</p><p>title test</p></div>
Here my code :
const { registerBlockType } = wp.blocks;
const { __ } = wp.i18n;
const { PanelBody, TextControl } = wp.components;
const { BlockControls, InspectorControls, RichText } = wp.editor;
const { createElement, Fragment } = wp.element
registerBlockType( 'namespace/nottomiss', {
title: __( 'Nottomiss' ),
description: __('My description'),
icon: 'star-filled',
category: 'widgets',
supports: { align: true, alignWide: true },
attributes: {
label: {
type: 'string',
source: 'html',
selector: 'p',
},
title: {
type: 'string',
source: 'html',
selector: 'p',
},
},
edit: function( props ) {
const { label, title } = props.attributes;
function onChangeLabel( newLabel ) {
props.setAttributes( { label: newLabel } );
}
function onChangeTitle( newTitle ) {
props.setAttributes( { title: newTitle } );
}
return (
<Fragment>
<BlockControls>
</BlockControls>
<InspectorControls>
<PanelBody title={ __( 'List' ) }>
</PanelBody>
</InspectorControls>
<RichText
identifier="label"
tagName="p"
placeholder=""
value={ label }
onChange={ onChangeLabel }
/>
<RichText
identifier="title"
tagName="p"
placeholder=""
value={ title }
onChange={ onChangeTitle }
/>
</Fragment>
);
},
save: function( props ) {
const { label, title } = props.attributes;
return (
<div>
<RichText.Content
tagName="p"
value={ label }
/>
<RichText.Content
tagName="p"
value={ title }
/>
</div>
);
},
} );
Thanks in advance for your answer,
The selectors are how the editor pulls the data from the saved html, and currently your selectors aren't targeting the content. You could change your selectors to something like this:
attributes: {
label: {
type: 'string',
source: 'html',
selector: '.label'
},
title: {
type: 'string',
source: 'html',
selector: '.title'
}
}
And you could change your save function to this:
save: function(props) {
const { label, title } = props.attributes
return (
<div>
<div className="label">
<RichText.Content
value={ label }
/>
</div>
<div className="title">
<RichText.Content
value={ title }
/>
</div>
</div>
)
}

Resources