diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 0715b1e3547e2..724b7f3db85b7 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -88,7 +88,7 @@ Display code snippets that respect your spacing and tabs. ([Source](https://gith - **Name:** core/code - **Category:** text - **Supports:** align (wide), anchor, color (background, gradients, text), interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight) -- **Attributes:** content +- **Attributes:** content, showLineNumbers ## Column diff --git a/packages/block-library/src/code/block.json b/packages/block-library/src/code/block.json index 4465c8554fc12..e9a50662437b0 100644 --- a/packages/block-library/src/code/block.json +++ b/packages/block-library/src/code/block.json @@ -12,6 +12,10 @@ "source": "rich-text", "selector": "code", "__unstablePreserveWhiteSpace": true + }, + "showLineNumbers": { + "type": "boolean", + "default": true } }, "supports": { diff --git a/packages/block-library/src/code/edit.js b/packages/block-library/src/code/edit.js index a3dbedeaf2335..6e0c522708457 100644 --- a/packages/block-library/src/code/edit.js +++ b/packages/block-library/src/code/edit.js @@ -2,8 +2,14 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { RichText, useBlockProps } from '@wordpress/block-editor'; +import { + RichText, + useBlockProps, + InspectorControls, +} from '@wordpress/block-editor'; import { createBlock, getDefaultBlockName } from '@wordpress/blocks'; +import { useState, useEffect } from '@wordpress/element'; +import { PanelBody, ToggleControl } from '@wordpress/components'; export default function CodeEdit( { attributes, @@ -13,23 +19,74 @@ export default function CodeEdit( { mergeBlocks, } ) { const blockProps = useBlockProps(); + const [ lineNumbers, setLineNumbers ] = useState( [] ); + const { content, showLineNumbers } = attributes; + + // eslint-disable-next-line no-shadow + const calculateLineNumbers = ( content ) => { + return content.split( '\n' ).map( ( _, index ) => index + 1 ); + }; + + // Update line numbers whenever the content changes + useEffect( () => { + const contentString = + typeof content === 'string' + ? content + : content.toHTMLString( { + preserveWhiteSpace: true, + } ); + setLineNumbers( calculateLineNumbers( contentString ) ); + }, [ content ] ); + return ( -
-			 setAttributes( { content } ) }
-				onRemove={ onRemove }
-				onMerge={ mergeBlocks }
-				placeholder={ __( 'Write code…' ) }
-				aria-label={ __( 'Code' ) }
-				preserveWhiteSpace
-				__unstablePastePlainText
-				__unstableOnSplitAtDoubleLineEnd={ () =>
-					insertBlocksAfter( createBlock( getDefaultBlockName() ) )
-				}
-			/>
-		
+ <> + { /* Inspector Controls */ } + + + + setAttributes( { showLineNumbers: value } ) + } + /> + + + + { /* Block Content */ } +
+ { /* Line Numbers */ } + { showLineNumbers && ( +
+ { lineNumbers.map( ( num ) => ( +
{ num }
+ ) ) } +
+ ) } + + { /* Code Content */ } +
+					 setAttributes( { content } ) }
+						onRemove={ onRemove }
+						onMerge={ mergeBlocks }
+						placeholder={ __( 'Write code…' ) }
+						aria-label={ __( 'Code' ) }
+						preserveWhiteSpace
+						__unstablePastePlainText
+						__unstableOnSplitAtDoubleLineEnd={ () =>
+							insertBlocksAfter(
+								createBlock( getDefaultBlockName() )
+							)
+						}
+					/>
+				
+
+ ); } diff --git a/packages/block-library/src/code/save.js b/packages/block-library/src/code/save.js index 977fb074c2a53..49bd834b004ea 100644 --- a/packages/block-library/src/code/save.js +++ b/packages/block-library/src/code/save.js @@ -9,21 +9,43 @@ import { RichText, useBlockProps } from '@wordpress/block-editor'; import { escape } from './utils'; export default function save( { attributes } ) { + const { content, showLineNumbers } = attributes; + + // eslint-disable-next-line no-shadow + const calculateLineNumbers = ( content ) => { + return content.split( '\n' ).map( ( _, index ) => index + 1 ); + }; + + const contentString = + typeof content === 'string' + ? content + : content.toHTMLString( { + preserveWhiteSpace: true, + } ); + + const lineNumbers = calculateLineNumbers( contentString ); + return ( -
-			
-		
+
+ { /* Conditionally render line numbers */ } + { showLineNumbers && ( +
+ { lineNumbers.map( ( num ) => ( +
{ num }
+ ) ) } +
+ ) } + + { /* Render code content */ } +
+				
+			
+
); } diff --git a/packages/block-library/src/code/style.scss b/packages/block-library/src/code/style.scss index ccc950d19b552..f3b73aeb51e72 100644 --- a/packages/block-library/src/code/style.scss +++ b/packages/block-library/src/code/style.scss @@ -16,3 +16,21 @@ /*!rtl:end:ignore*/ } } +.wp-block-code-with-line-numbers { + display: flex; +} + +.line-numbers { + padding-right: 8px; + text-align: right; + border-right: 1px solid #ddd; + color: #6a737d; + user-select: none; + margin: 1em 0; +} + +.code-content { + flex-grow: 1; + padding-left: 8px; + overflow: auto; +}