forked from WordPress/gutenberg
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b226cee
commit 4154e4c
Showing
27 changed files
with
1,933 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Tab | ||
|
||
Contributors: Pew Research Center, creativecoder | ||
Tags: block | ||
Tested up to: 6.7 | ||
Stable tag: 1.0.0 | ||
License: GPL-2.0-or-later | ||
License URI: https://www.gnu.org/licenses/gpl-2.0.html | ||
|
||
## Description | ||
|
||
This is an exploration at a [`core/` level block](https://github.com/WordPress/gutenberg/pull/63689/) that allows for the creation of tabbed content. Bootstrapped from work that @creativecoder was close to finishing but had to abandon due to other commitments. | ||
|
||
## Instructions | ||
|
||
This section describes how to use the block. | ||
|
||
## Frequently Asked Questions | ||
|
||
= A question that someone might have = | ||
|
||
An answer to that question. | ||
|
||
### What about foo bar? | ||
|
||
Answer to foo bar dilemma. | ||
|
||
## Screenshots | ||
|
||
1. This screen shot description corresponds to screenshot-1.(png|jpg|jpeg|gif). | ||
2. This is the second screen shot | ||
3. You can store screenshots in a .docs folder in this block directory... | ||
|
||
## Changelog | ||
|
||
= 0.1.0 = | ||
* Release | ||
|
||
## Developer Notes | ||
|
||
You may provide arbitrary sections, in the same format as the ones above. This may be of use for extremely complicated | ||
blocks where more information needs to be conveyed that doesn't fit into the categories of "description" or | ||
"installation." Arbitrary sections will be shown below the built-in sections outlined above. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { | ||
registerBlockVariation, | ||
registerBlockBindingsSource, | ||
} from '@wordpress/blocks'; | ||
|
||
export default function registerTabLabelBinding() { | ||
const allowedAttributes = [ 'content' ]; | ||
registerBlockBindingsSource( { | ||
name: 'tab/label', | ||
usesContext: [ 'tab/label' ], | ||
getValues( { bindings } ) { | ||
const values = {}; | ||
for ( const [ attributeName, source ] of Object.entries( | ||
bindings | ||
) ) { | ||
if ( allowedAttributes.includes( source.args.key ) ) { | ||
values[ attributeName ] = 'Tab Title !'; | ||
} | ||
} | ||
return values; | ||
}, | ||
} ); | ||
registerBlockVariation( 'core/paragraph', { | ||
name: 'core-tab-label', | ||
title: 'Tab: Label', | ||
category: 'design', | ||
attributes: { | ||
content: 'Tab Label', | ||
metadata: { | ||
bindings: { | ||
content: { | ||
source: 'core/tab', | ||
args: { | ||
contextKey: 'tab/label', | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} ); | ||
registerBlockVariation( 'core/heading', { | ||
name: 'core-tab-label', | ||
title: 'Tab: Label', | ||
category: 'design', | ||
attributes: { | ||
content: 'Tab Label', | ||
level: 3, | ||
metadata: { | ||
bindings: { | ||
content: { | ||
source: 'core/tab', | ||
args: { | ||
contextKey: 'tab/label', | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} ); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
{ | ||
"$schema": "https://schemas.wp.org/trunk/block.json", | ||
"apiVersion": 3, | ||
"name": "core/tab", | ||
"title": "Tab", | ||
"version": "1.0.0", | ||
"category": "design", | ||
"attributes": { | ||
"label": { | ||
"type": "string", | ||
"default": "" | ||
}, | ||
"slug": { | ||
"type": "string", | ||
"default": "" | ||
}, | ||
"tabIndex": { | ||
"type": "number" | ||
} | ||
}, | ||
"parent": [ "core/tabs" ], | ||
"supports": { | ||
"anchor": true, | ||
"html": false, | ||
"reusable": false, | ||
"color": { | ||
"background": true, | ||
"heading": true, | ||
"text": true | ||
}, | ||
"spacing": { | ||
"padding": true, | ||
"blockGap": true, | ||
"__experimentalDefaultControls": { | ||
"padding": true | ||
} | ||
}, | ||
"typography": { | ||
"fontSize": true, | ||
"__experimentalFontFamily": true, | ||
"__experimentalDefaultControls": { | ||
"fontSize": true, | ||
"__experimentalFontFamily": true | ||
} | ||
} | ||
}, | ||
"providesContext": { | ||
"tab/label": "label", | ||
"tab/slug": "slug", | ||
"tab/index": "tabIndex" | ||
}, | ||
"textdomain": "tab", | ||
"style": "wp-block-tab" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
/** | ||
* External Dependencies | ||
*/ | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { | ||
InnerBlocks, | ||
useBlockProps, | ||
useInnerBlocksProps, | ||
store as blockEditorStore, | ||
InspectorControls, | ||
} from '@wordpress/block-editor'; | ||
import { useSelect, useDispatch } from '@wordpress/data'; | ||
import { Fragment, useEffect, useMemo } from '@wordpress/element'; | ||
import { PanelBody, TextControl } from '@wordpress/components'; | ||
import { cleanForSlug } from '@wordpress/url'; | ||
|
||
/** | ||
* Generates a slug from a tab's text label. | ||
* | ||
* @param {string} label Tab label RichText value. | ||
* @param {number} tabIndex Tab index value. | ||
* | ||
* @return {string} The generated slug with HTML stripped out. | ||
*/ | ||
function slugFromLabel( label, tabIndex ) { | ||
// Get just the text content, filtering out any HTML tags from the RichText value. | ||
const htmlDocument = new window.DOMParser().parseFromString( | ||
label, | ||
'text/html' | ||
); | ||
if ( htmlDocument.body?.textContent ) { | ||
return cleanForSlug( htmlDocument.body.textContent ); | ||
} | ||
|
||
// Fall back to using the tab index if the label is empty. | ||
return `tab-panel-${ tabIndex }`; | ||
} | ||
|
||
function EditComponent( { attributes, clientId, setAttributes } ) { | ||
const { anchor, label, slug } = attributes; | ||
// Use a custom anchor, if set. Otherwise fall back to the slug generated from the label text. | ||
const tabPanelId = anchor || slug; | ||
const tabLabelId = `${ tabPanelId }--tab`; | ||
const hasChildBlocks = useSelect( | ||
( select ) => | ||
select( blockEditorStore ).getBlockOrder( clientId ).length > 0, | ||
[ clientId ] | ||
); | ||
|
||
const blockProps = useBlockProps(); | ||
|
||
const innerBlocksProps = useInnerBlocksProps( blockProps, { | ||
renderAppender: hasChildBlocks | ||
? undefined | ||
: InnerBlocks.ButtonBlockAppender, | ||
} ); | ||
|
||
return ( | ||
<Fragment> | ||
<InspectorControls> | ||
<PanelBody title="Tab Settings"> | ||
<TextControl | ||
label="Label" | ||
value={ label } | ||
onChange={ ( value ) => | ||
setAttributes( { label: value } ) | ||
} | ||
__next40pxDefaultSize | ||
__nextHasNoMarginBottom | ||
/> | ||
</PanelBody> | ||
</InspectorControls> | ||
<section | ||
{ ...innerBlocksProps } | ||
aria-labelledby={ tabLabelId } | ||
id={ tabPanelId } | ||
role="tabpanel" | ||
/> | ||
</Fragment> | ||
); | ||
} | ||
|
||
export default function Edit( { | ||
attributes, | ||
clientId, | ||
isSelected, | ||
setAttributes, | ||
} ) { | ||
const { isActive, label, tabIndex } = attributes; | ||
const { __unstableMarkNextChangeAsNotPersistent } = | ||
useDispatch( blockEditorStore ); | ||
|
||
const { hasInnerBlockSelected, blockIndex } = useSelect( | ||
( select ) => { | ||
return { | ||
hasInnerBlockSelected: | ||
select( blockEditorStore ).hasSelectedInnerBlock( | ||
clientId | ||
), | ||
blockIndex: | ||
select( blockEditorStore ).getBlockIndex( clientId ), | ||
}; | ||
}, | ||
[ clientId ] | ||
); | ||
|
||
/** | ||
* These two hooks ensure the tab block's slug and tabIndex attributes are kept in sync with the parent tabs block. | ||
*/ | ||
// Construct or update the slug when the label changes: | ||
useEffect( () => { | ||
if ( label ) { | ||
__unstableMarkNextChangeAsNotPersistent(); | ||
setAttributes( { slug: slugFromLabel( label, tabIndex ) } ); | ||
} | ||
}, [ | ||
__unstableMarkNextChangeAsNotPersistent, | ||
label, | ||
setAttributes, | ||
tabIndex, | ||
] ); | ||
|
||
// Ensure tabIndex attributes are in sync with the order relative to the root | ||
useEffect( () => { | ||
if ( blockIndex !== tabIndex ) { | ||
__unstableMarkNextChangeAsNotPersistent(); | ||
setAttributes( { tabIndex: blockIndex } ); | ||
} | ||
}, [ | ||
__unstableMarkNextChangeAsNotPersistent, | ||
blockIndex, | ||
setAttributes, | ||
tabIndex, | ||
] ); | ||
|
||
const displayEditComponent = useMemo( () => { | ||
return isActive || isSelected || hasInnerBlockSelected; | ||
}, [ isActive, hasInnerBlockSelected, isSelected ] ); | ||
|
||
// If the block is not selected, and or not active then | ||
// there is no reason to render the edit component. This saves on | ||
// memory and performance. | ||
if ( displayEditComponent ) { | ||
return ( | ||
<EditComponent | ||
attributes={ attributes } | ||
clientId={ clientId } | ||
setAttributes={ setAttributes } | ||
/> | ||
); | ||
} | ||
|
||
return <div hidden />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { SVG, Path } from '@wordpress/components'; | ||
|
||
export default ( | ||
<SVG | ||
width="24" | ||
height="24" | ||
viewBox="0 0 24 24" | ||
xmlns="http://www.w3.org/2000/svg" | ||
> | ||
<Path | ||
fillRule="evenodd" | ||
clipRule="evenodd" | ||
d="M5.5498 10.3501V6.3501H9.8498V10.3501H11.3498V6.1001C11.3498 5.40974 10.7902 4.8501 10.0998 4.8501H5.2998C4.60945 4.8501 4.0498 5.40974 4.0498 6.1001V10.3501H5.5498ZM20 12.6001H4V14.1001L20 14.1001V12.6001ZM14 17.1001H4V18.6001H14V17.1001Z" | ||
/> | ||
</SVG> | ||
); |
Oops, something went wrong.