From f9943a645c30105ed4e7e11a312c258c95c5b25c Mon Sep 17 00:00:00 2001 From: Manzoor Wani Date: Tue, 13 Oct 2026 17:42:01 +0530 Subject: [PATCH 1/7] Block Editor: Convert the block edit context and shared component hooks to TypeScript --- .../block-context/{index.jsx => index.tsx} | 19 ++----- .../src/components/block-context/types.ts | 12 ++++ .../block-edit/{context.js => context.ts} | 5 +- .../src/components/block-edit/types.ts | 27 +++++++++ .../block-editing-mode/{index.js => index.ts} | 7 +-- .../components/block-editing-mode/types.ts | 1 + .../src/components/block-icon/index.jsx | 41 -------------- .../src/components/block-icon/index.tsx | 56 +++++++++++++++++++ .../src/components/block-icon/types.ts | 8 +++ .../{use-block-refs.js => use-block-refs.ts} | 33 ++++++----- .../src/components/global-styles/types.ts | 7 +++ .../global-styles/{utils.js => utils.ts} | 36 ++++++------ .../use-settings/{index.js => index.ts} | 5 +- 13 files changed, 164 insertions(+), 93 deletions(-) rename packages/block-editor/src/components/block-context/{index.jsx => index.tsx} (58%) create mode 100644 packages/block-editor/src/components/block-context/types.ts rename packages/block-editor/src/components/block-edit/{context.js => context.ts} (86%) create mode 100644 packages/block-editor/src/components/block-edit/types.ts rename packages/block-editor/src/components/block-editing-mode/{index.js => index.ts} (93%) create mode 100644 packages/block-editor/src/components/block-editing-mode/types.ts delete mode 100644 packages/block-editor/src/components/block-icon/index.jsx create mode 100644 packages/block-editor/src/components/block-icon/index.tsx create mode 100644 packages/block-editor/src/components/block-icon/types.ts rename packages/block-editor/src/components/block-list/use-block-props/{use-block-refs.js => use-block-refs.ts} (63%) create mode 100644 packages/block-editor/src/components/global-styles/types.ts rename packages/block-editor/src/components/global-styles/{utils.js => utils.ts} (74%) rename packages/block-editor/src/components/use-settings/{index.js => index.ts} (89%) diff --git a/packages/block-editor/src/components/block-context/index.jsx b/packages/block-editor/src/components/block-context/index.tsx similarity index 58% rename from packages/block-editor/src/components/block-context/index.jsx rename to packages/block-editor/src/components/block-context/index.tsx index 66dfbc98dd09ab..c60727574b6c30 100644 --- a/packages/block-editor/src/components/block-context/index.jsx +++ b/packages/block-editor/src/components/block-context/index.tsx @@ -1,18 +1,8 @@ // @ts-check import { createContext, useContext, useMemo } from '@wordpress/element'; +import type { BlockContextProviderProps } from './types'; -/** @typedef {React.ReactNode} ReactNode */ - -/** - * @typedef BlockContextProviderProps - * - * @property {Record} value Context value to merge with current - * value. - * @property {ReactNode} children Component children. - */ - -/** @type {React.Context>} */ -const Context = createContext( {} ); +const Context = createContext< Record< string, unknown > >( {} ); Context.displayName = 'BlockContext'; /** @@ -22,7 +12,10 @@ Context.displayName = 'BlockContext'; * * @param {BlockContextProviderProps} props */ -export function BlockContextProvider( { value, children } ) { +export function BlockContextProvider( { + value, + children, +}: BlockContextProviderProps ) { const context = useContext( Context ); const nextValue = useMemo( () => ( { ...context, ...value } ), diff --git a/packages/block-editor/src/components/block-context/types.ts b/packages/block-editor/src/components/block-context/types.ts new file mode 100644 index 00000000000000..a74793da7b88ee --- /dev/null +++ b/packages/block-editor/src/components/block-context/types.ts @@ -0,0 +1,12 @@ +import type { ReactNode } from 'react'; + +export interface BlockContextProviderProps { + /** + * Context value to merge with current value. + */ + value: Record< string, unknown >; + /** + * Component children. + */ + children: ReactNode; +} diff --git a/packages/block-editor/src/components/block-edit/context.js b/packages/block-editor/src/components/block-edit/context.ts similarity index 86% rename from packages/block-editor/src/components/block-edit/context.js rename to packages/block-editor/src/components/block-edit/context.ts index 41678a31e87245..d078329fa37b65 100644 --- a/packages/block-editor/src/components/block-edit/context.js +++ b/packages/block-editor/src/components/block-edit/context.ts @@ -1,4 +1,5 @@ import { createContext, useContext } from '@wordpress/element'; +import type { BlockEditContextValue } from './types'; export const mayDisplayControlsKey = Symbol( 'mayDisplayControls' ); export const mayDisplayParentControlsKey = Symbol( 'mayDisplayParentControls' ); @@ -13,7 +14,7 @@ export const isInListViewBlockSupportTreeKey = Symbol( 'isInListViewBlockSupportTree' ); -export const DEFAULT_BLOCK_EDIT_CONTEXT = { +export const DEFAULT_BLOCK_EDIT_CONTEXT: BlockEditContextValue = { name: '', isSelected: false, }; @@ -28,7 +29,7 @@ export { Provider as BlockEditContextProvider }; /** * A hook that returns the block edit context. * - * @return {Object} Block edit context + * @return Block edit context */ export function useBlockEditContext() { return useContext( Context ); diff --git a/packages/block-editor/src/components/block-edit/types.ts b/packages/block-editor/src/components/block-edit/types.ts new file mode 100644 index 00000000000000..c7c62f6bbc5bb0 --- /dev/null +++ b/packages/block-editor/src/components/block-edit/types.ts @@ -0,0 +1,27 @@ +import type { BlockEditingMode } from '../block-editing-mode'; +import type { + mayDisplayControlsKey, + mayDisplayParentControlsKey, + mayDisplayPatternEditingControlsKey, + blockEditingModeKey, + blockBindingsKey, + isPreviewModeKey, + isMultiSelectedKey, + isInListViewBlockSupportTreeKey, +} from './context'; + +export interface BlockEditContextValue { + name: string; + isSelected?: boolean; + clientId?: string; + layout?: Record< string, unknown > | null; + __unstableLayoutClassNames?: string; + [ mayDisplayControlsKey ]?: boolean; + [ mayDisplayParentControlsKey ]?: boolean; + [ mayDisplayPatternEditingControlsKey ]?: boolean; + [ blockEditingModeKey ]?: BlockEditingMode; + [ blockBindingsKey ]?: Record< string, unknown > | null; + [ isPreviewModeKey ]?: boolean; + [ isMultiSelectedKey ]?: boolean; + [ isInListViewBlockSupportTreeKey ]?: boolean; +} diff --git a/packages/block-editor/src/components/block-editing-mode/index.js b/packages/block-editor/src/components/block-editing-mode/index.ts similarity index 93% rename from packages/block-editor/src/components/block-editing-mode/index.js rename to packages/block-editor/src/components/block-editing-mode/index.ts index 4808603cac98f5..eead153deb7ea2 100644 --- a/packages/block-editor/src/components/block-editing-mode/index.js +++ b/packages/block-editor/src/components/block-editing-mode/index.ts @@ -5,10 +5,9 @@ import { useBlockEditContext, blockEditingModeKey, } from '../block-edit/context'; +import type { BlockEditingMode } from './types'; -/** - * @typedef {'disabled'|'contentOnly'|'default'} BlockEditingMode - */ +export type { BlockEditingMode }; /** * Allows a block to restrict the user interface that is displayed for editing @@ -40,7 +39,7 @@ import { * * @return {BlockEditingMode} The current editing mode. */ -export function useBlockEditingMode( mode ) { +export function useBlockEditingMode( mode?: BlockEditingMode | null ) { const context = useBlockEditContext(); const { clientId = '' } = context; const registry = useRegistry(); diff --git a/packages/block-editor/src/components/block-editing-mode/types.ts b/packages/block-editor/src/components/block-editing-mode/types.ts new file mode 100644 index 00000000000000..343b4f5a4fd960 --- /dev/null +++ b/packages/block-editor/src/components/block-editing-mode/types.ts @@ -0,0 +1 @@ +export type BlockEditingMode = 'disabled' | 'contentOnly' | 'default'; diff --git a/packages/block-editor/src/components/block-icon/index.jsx b/packages/block-editor/src/components/block-icon/index.jsx deleted file mode 100644 index 4c529774c7b931..00000000000000 --- a/packages/block-editor/src/components/block-icon/index.jsx +++ /dev/null @@ -1,41 +0,0 @@ -import clsx from 'clsx'; -import { Icon as WCIcon } from '@wordpress/components'; -import { blockDefault } from '@wordpress/icons'; -import { memo } from '@wordpress/element'; - -function BlockIcon( { icon, showColors = false, className, context } ) { - if ( icon?.src === 'block-default' ) { - icon = { - src: blockDefault, - }; - } - - const renderedIcon = ( - - ); - const style = showColors - ? { - backgroundColor: icon && icon.background, - color: icon && icon.foreground, - } - : {}; - - return ( - - { renderedIcon } - - ); -} - -/** - * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/block-icon/README.md - */ -export default memo( BlockIcon ); diff --git a/packages/block-editor/src/components/block-icon/index.tsx b/packages/block-editor/src/components/block-icon/index.tsx new file mode 100644 index 00000000000000..acbd0b0cd21ec9 --- /dev/null +++ b/packages/block-editor/src/components/block-icon/index.tsx @@ -0,0 +1,56 @@ +import clsx from 'clsx'; +import { Icon as WCIcon } from '@wordpress/components'; +import type { IconType } from '@wordpress/components'; +import { blockDefault } from '@wordpress/icons'; +import { memo } from '@wordpress/element'; +import type { CSSProperties } from 'react'; +import type { BlockTypeIconDescriptor } from '@wordpress/blocks'; +import type { BlockIconProps } from './types'; + +function BlockIcon( { + icon, + showColors = false, + className, + context, +}: BlockIconProps ) { + if ( ( icon as BlockTypeIconDescriptor )?.src === 'block-default' ) { + icon = { + src: blockDefault, + }; + } + + const renderedIcon = ( + + ); + const style = showColors + ? { + backgroundColor: + icon && ( icon as BlockTypeIconDescriptor ).background, + color: icon && ( icon as BlockTypeIconDescriptor ).foreground, + } + : {}; + + return ( + + { renderedIcon } + + ); +} + +/** + * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/block-icon/README.md + */ +export default memo( BlockIcon ); diff --git a/packages/block-editor/src/components/block-icon/types.ts b/packages/block-editor/src/components/block-icon/types.ts new file mode 100644 index 00000000000000..8fa3579d3c4645 --- /dev/null +++ b/packages/block-editor/src/components/block-icon/types.ts @@ -0,0 +1,8 @@ +import type { BlockTypeIcon } from '@wordpress/blocks'; + +export interface BlockIconProps { + icon?: BlockTypeIcon | null; + showColors?: boolean; + className?: string; + context?: string; +} diff --git a/packages/block-editor/src/components/block-list/use-block-props/use-block-refs.js b/packages/block-editor/src/components/block-list/use-block-props/use-block-refs.ts similarity index 63% rename from packages/block-editor/src/components/block-list/use-block-props/use-block-refs.js rename to packages/block-editor/src/components/block-list/use-block-props/use-block-refs.ts index ed4cc83a4a1856..8c584b02f64899 100644 --- a/packages/block-editor/src/components/block-list/use-block-props/use-block-refs.js +++ b/packages/block-editor/src/components/block-list/use-block-props/use-block-refs.ts @@ -1,18 +1,18 @@ +import type { Ref, RefCallback } from 'react'; import { useContext, useState, useLayoutEffect } from '@wordpress/element'; import { useRefEffect } from '@wordpress/compose'; import { BlockRefs } from '../../provider/block-refs-provider'; -/** @typedef {import('@wordpress/element').RefCallback} RefCallback */ -/** @typedef {import('@wordpress/element').Ref} Ref */ - /** * Provides a ref to the BlockRefs context. * - * @param {string} clientId The client ID of the element ref. + * @param clientId The client ID of the element ref. * - * @return {RefCallback} Ref callback. + * @return Ref callback. */ -export function useBlockRefProvider( clientId ) { +export function useBlockRefProvider( + clientId: string +): RefCallback< Element > { const { refsMap } = useContext( BlockRefs ); return useRefEffect( ( element ) => { @@ -23,7 +23,7 @@ export function useBlockRefProvider( clientId ) { ); } -function assignRef( ref, value ) { +function assignRef( ref: Ref< Element | null >, value: Element | null ) { if ( typeof ref === 'function' ) { ref( value ); } else if ( ref ) { @@ -35,10 +35,13 @@ function assignRef( ref, value ) { * Tracks the DOM element for the block identified by `clientId` and assigns it to the `ref` * whenever it changes. * - * @param {string} clientId The client ID to track. - * @param {Ref} ref The ref object/callback to assign to. + * @param clientId The client ID to track. + * @param ref The ref object/callback to assign to. */ -export function useBlockElementRef( clientId, ref ) { +export function useBlockElementRef( + clientId: string, + ref: Ref< Element | null > +) { const { refsMap } = useContext( BlockRefs ); useLayoutEffect( () => { assignRef( ref, refsMap.get( clientId ) ); @@ -56,12 +59,14 @@ export function useBlockElementRef( clientId, ref ) { * Return the element for a given client ID. Updates whenever the element * changes, becomes available, or disappears. * - * @param {string} clientId The client ID to an element for. + * @param clientId The client ID to an element for. * - * @return {Element|null} The block's wrapper element. + * @return The block's wrapper element. */ -export function useBlockElement( clientId ) { - const [ blockElement, setBlockElement ] = useState( null ); +export function useBlockElement( clientId: string ) { + const [ blockElement, setBlockElement ] = useState< Element | null >( + null + ); useBlockElementRef( clientId, setBlockElement ); return blockElement; } diff --git a/packages/block-editor/src/components/global-styles/types.ts b/packages/block-editor/src/components/global-styles/types.ts new file mode 100644 index 00000000000000..2d7d8ace263818 --- /dev/null +++ b/packages/block-editor/src/components/global-styles/types.ts @@ -0,0 +1,7 @@ +import type { ComponentProps } from 'react'; +import type { Dropdown } from '@wordpress/components'; + +export type ToolsPanelPopoverProps = Pick< + NonNullable< ComponentProps< typeof Dropdown >[ 'popoverProps' ] >, + 'placement' | 'offset' | 'shift' +>; diff --git a/packages/block-editor/src/components/global-styles/utils.js b/packages/block-editor/src/components/global-styles/utils.ts similarity index 74% rename from packages/block-editor/src/components/global-styles/utils.js rename to packages/block-editor/src/components/global-styles/utils.ts index 6a73cb78a2cf22..5ebcf44f5ff1cd 100644 --- a/packages/block-editor/src/components/global-styles/utils.js +++ b/packages/block-editor/src/components/global-styles/utils.ts @@ -1,12 +1,16 @@ import { useViewportMatch } from '@wordpress/compose'; import { createContext, useContext } from '@wordpress/element'; +import type { ToolsPanelPopoverProps } from './types'; /** * Popover props for ToolsPanel dropdown menus (`dropdown`) and item popovers * (`item`). Defaults to the editor sidebar; consumers rendering the panels * elsewhere provide their own values. */ -export const ToolsPanelPopoverPropsContext = createContext( { +export const ToolsPanelPopoverPropsContext = createContext< { + dropdown: ToolsPanelPopoverProps; + item: ToolsPanelPopoverProps; +} >( { dropdown: { placement: 'left-start', // Inner sidebar width (248px) - button width (24px) - border (1px) + padding (16px) + spacing (20px) @@ -26,17 +30,10 @@ export function useToolsPanelDropdownMenuProps() { return ! isMobile ? { popoverProps: dropdown } : {}; } -/** - * @typedef {Pick< - * NonNullable['popoverProps']>, - * 'placement' | 'offset' | 'shift' - * >} ToolsPanelPopoverProps - */ - /** * Popover props for a tools panel item. * - * @return {ToolsPanelPopoverProps} Popover props for a tools panel item. + * @return Popover props for a tools panel item. */ export function useToolsPanelItemPopoverProps() { return useContext( ToolsPanelPopoverPropsContext ).item; @@ -54,12 +51,15 @@ export function useToolsPanelItemPopoverProps() { * // merged is '.a > .x, .a .y, .b .c > .x, .b .c .y' * ``` * - * @param {string} scope Selector to scope to. - * @param {string} selector Original selector. + * @param scope Selector to scope to. + * @param selector Original selector. * - * @return {string} Scoped selector. + * @return Scoped selector. */ -export function scopeSelector( scope, selector ) { +export function scopeSelector( + scope: string | null | undefined, + selector: string +) { if ( ! scope || ! selector ) { return selector; } @@ -67,7 +67,7 @@ export function scopeSelector( scope, selector ) { const scopes = scope.split( ',' ); const selectors = selector.split( ',' ); - const selectorsScoped = []; + const selectorsScoped: string[] = []; scopes.forEach( ( outer ) => { selectors.forEach( ( inner ) => { selectorsScoped.push( `${ outer.trim() } ${ inner.trim() }` ); @@ -86,11 +86,13 @@ export function scopeSelector( scope, selector ) { * Lives here rather than beside its siblings in `hooks/duotone` because that * module imports the filters panel, so the panel cannot import back from it. * - * @param {string|string[]|undefined} duotone A duotone style value. + * @param duotone A duotone style value. * - * @return {string|undefined} The preset slug, if the value references one. + * @return The preset slug, if the value references one. */ -export function getDuotoneSlugFromPreset( duotone ) { +export function getDuotoneSlugFromPreset( + duotone: string | string[] | undefined +): string | undefined { if ( typeof duotone !== 'string' ) { return undefined; } diff --git a/packages/block-editor/src/components/use-settings/index.js b/packages/block-editor/src/components/use-settings/index.ts similarity index 89% rename from packages/block-editor/src/components/use-settings/index.js rename to packages/block-editor/src/components/use-settings/index.ts index 0598bc2f8d9a68..1f23f524e926cf 100644 --- a/packages/block-editor/src/components/use-settings/index.js +++ b/packages/block-editor/src/components/use-settings/index.ts @@ -17,7 +17,7 @@ import { unlock } from '../../lock-unlock'; * const [ fixed, sticky ] = useSettings( 'position.fixed', 'position.sticky' ); * ``` */ -export function useSettings( ...paths ) { +export function useSettings( ...paths: string[] ): unknown[] { const { clientId = null } = useBlockEditContext(); return useSelect( ( select ) => @@ -44,10 +44,11 @@ export function useSettings( ...paths ) { * const isEnabled = useSetting( 'typography.dropCap' ); * ``` */ -export function useSetting( path ) { +export function useSetting( path: string ) { deprecated( 'wp.blockEditor.useSetting', { since: '6.5', alternative: 'wp.blockEditor.useSettings', + // @ts-expect-error `deprecated` has no `note` option, so this is ignored. note: 'The new useSettings function can retrieve multiple settings at once, with better performance.', } ); From 8aa1a1eba64771bcea27191f429a997a8fc00fd8 Mon Sep 17 00:00:00 2001 From: Manzoor Wani Date: Tue, 13 Oct 2026 17:45:39 +0530 Subject: [PATCH 2/7] Block Editor: Convert the spacing size utils and Global Styles inheritance to TypeScript --- .../inheritance/{index.jsx => index.tsx} | 58 +++++++-------- .../global-styles/inheritance/types.ts | 47 ++++++++++++ .../components/spacing-sizes-control/types.ts | 9 +++ .../{utils.js => utils.ts} | 73 ++++++++++++------- 4 files changed, 130 insertions(+), 57 deletions(-) rename packages/block-editor/src/components/global-styles/inheritance/{index.jsx => index.tsx} (72%) create mode 100644 packages/block-editor/src/components/global-styles/inheritance/types.ts create mode 100644 packages/block-editor/src/components/spacing-sizes-control/types.ts rename packages/block-editor/src/components/spacing-sizes-control/{utils.js => utils.ts} (75%) diff --git a/packages/block-editor/src/components/global-styles/inheritance/index.jsx b/packages/block-editor/src/components/global-styles/inheritance/index.tsx similarity index 72% rename from packages/block-editor/src/components/global-styles/inheritance/index.jsx rename to packages/block-editor/src/components/global-styles/inheritance/index.tsx index 59e4aaa20fe0b8..47f428ca45a160 100644 --- a/packages/block-editor/src/components/global-styles/inheritance/index.jsx +++ b/packages/block-editor/src/components/global-styles/inheritance/index.tsx @@ -6,6 +6,12 @@ import { } from '@wordpress/components'; import { reset as resetIcon } from '@wordpress/icons'; import { __ } from '@wordpress/i18n'; +import type { MouseEvent } from 'react'; +import type { ClassValue } from 'clsx'; +import type { + InheritanceResetButtonProps, + InheritanceToolsPanelItemProps, +} from './types'; /** * Whether the inspector marks up which controls are showing an inherited @@ -23,10 +29,11 @@ import { __ } from '@wordpress/i18n'; * down as a prop, and `undefined` would trigger a receiving component's own * default parameter. * - * @return {boolean} Whether the indicator treatment is enabled. + * @return Whether the indicator treatment is enabled. */ export const isGlobalStylesInheritanceIndicatorUIEnabled = () => - !! window.__experimentalGlobalStylesInheritanceUI; + !! ( window as { __experimentalGlobalStylesInheritanceUI?: boolean } ) + .__experimentalGlobalStylesInheritanceUI; /** * Returns props to spread onto a wrapping `` @@ -51,20 +58,20 @@ export const isGlobalStylesInheritanceIndicatorUIEnabled = () => * … * > * - * @param {boolean} isInherited Control is inheriting at rest. - * @param {boolean} hasLocalOverride Local override is set AND - * there is an inherited value - * being overridden. - * @param {string|Array|Object} [baseClassName] Optional className(s) to fold - * into the returned `className`. + * @param isInherited Control is inheriting at rest. + * @param hasLocalOverride Local override is set AND + * there is an inherited value + * being overridden. + * @param [baseClassName] Optional className(s) to fold + * into the returned `className`. * - * @return {{ className?: string, isInherited: boolean, hasLocalOverride: boolean }} Props for the wrapping + * @return Props for the wrapping * `InheritanceToolsPanelItem`. */ export function getInheritanceProps( - isInherited, - hasLocalOverride, - baseClassName + isInherited: unknown, + hasLocalOverride: unknown, + baseClassName?: ClassValue ) { const inheritedOnly = !! isInherited && ! hasLocalOverride; const className = clsx( baseClassName, { @@ -89,13 +96,12 @@ export function getInheritanceProps( * override so the control falls back to its inherited value — the same * action the `ToolsPanel` menu performs via `onDeselect`. * - * @param {Object} props - * @param {Function} props.onResetToInherited Reset handler. - * @param {string} [props.className] Optional className for the button. - * - * @return {Element} The reset button. + * @return The reset button. */ -export function InheritanceResetButton( { onResetToInherited, className } ) { +export function InheritanceResetButton( { + onResetToInherited, + className, +}: InheritanceResetButtonProps ) { return ( // Intentionally small (14×14) circular control; exempt from the // 40px default-size enforcement rule. @@ -110,7 +116,7 @@ export function InheritanceResetButton( { onResetToInherited, className } ) { 'has-local-override-from-global-styles__reset', className ) } - onClick={ ( event ) => { + onClick={ ( event: MouseEvent ) => { // Prevent the click from reaching any wrapping // `