From ce556118f02aac7c5226b73c45e513b7f364c3f4 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Mon, 4 Dec 2023 22:42:08 +0900 Subject: [PATCH 01/12] Components: Move kebabCase() function from block-editor package and mark it as private API --- packages/block-editor/src/utils/object.js | 33 +------ .../block-editor/src/utils/test/object.js | 97 +------------------ packages/components/src/private-apis.ts | 2 + packages/components/src/utils/strings.ts | 31 ++++++ packages/components/src/utils/test/strings.js | 97 ++++++++++++++++++- 5 files changed, 135 insertions(+), 125 deletions(-) diff --git a/packages/block-editor/src/utils/object.js b/packages/block-editor/src/utils/object.js index 5238056426417..160ead75f272e 100644 --- a/packages/block-editor/src/utils/object.js +++ b/packages/block-editor/src/utils/object.js @@ -1,37 +1,14 @@ /** - * External dependencies + * WordPress dependencies */ -import { paramCase } from 'change-case'; +import { privateApis as componentsPrivateApis } from '@wordpress/components'; /** - * Converts any string to kebab case. - * Backwards compatible with Lodash's `_.kebabCase()`. - * Backwards compatible with `_wp_to_kebab_case()`. - * - * @see https://lodash.com/docs/4.17.15#kebabCase - * @see https://developer.wordpress.org/reference/functions/_wp_to_kebab_case/ - * - * @param {string} str String to convert. - * @return {string} Kebab-cased string + * Internal dependencies */ -export function kebabCase( str ) { - let input = str; - if ( typeof str !== 'string' ) { - input = str?.toString?.() ?? ''; - } +import { unlock } from '../lock-unlock'; - // See https://github.com/lodash/lodash/blob/b185fcee26b2133bd071f4aaca14b455c2ed1008/lodash.js#L4970 - input = input.replace( /['\u2019]/, '' ); - - return paramCase( input, { - splitRegexp: [ - /(?!(?:1ST|2ND|3RD|[4-9]TH)(?![a-z]))([a-z0-9])([A-Z])/g, // fooBar => foo-bar, 3Bar => 3-bar - /(?!(?:1st|2nd|3rd|[4-9]th)(?![a-z]))([0-9])([a-z])/g, // 3bar => 3-bar - /([A-Za-z])([0-9])/g, // Foo3 => foo-3, foo3 => foo-3 - /([A-Z])([A-Z][a-z])/g, // FOOBar => foo-bar - ], - } ); -} +export const { kebabCase } = unlock( componentsPrivateApis ); /** * Immutably sets a value inside an object. Like `lodash#set`, but returning a diff --git a/packages/block-editor/src/utils/test/object.js b/packages/block-editor/src/utils/test/object.js index 87f01375df311..28f2fc7381cd8 100644 --- a/packages/block-editor/src/utils/test/object.js +++ b/packages/block-editor/src/utils/test/object.js @@ -1,102 +1,7 @@ /** * Internal dependencies */ -import { kebabCase, setImmutably } from '../object'; - -describe( 'kebabCase', () => { - it( 'separates lowercase letters, followed by uppercase letters', () => { - expect( kebabCase( 'fooBar' ) ).toEqual( 'foo-bar' ); - } ); - - it( 'separates numbers, followed by uppercase letters', () => { - expect( kebabCase( '123FOO' ) ).toEqual( '123-foo' ); - } ); - - it( 'separates numbers, followed by lowercase characters', () => { - expect( kebabCase( '123bar' ) ).toEqual( '123-bar' ); - } ); - - it( 'separates uppercase letters, followed by numbers', () => { - expect( kebabCase( 'FOO123' ) ).toEqual( 'foo-123' ); - } ); - - it( 'separates lowercase letters, followed by numbers', () => { - expect( kebabCase( 'foo123' ) ).toEqual( 'foo-123' ); - } ); - - it( 'separates uppercase groups from capitalized groups', () => { - expect( kebabCase( 'FOOBar' ) ).toEqual( 'foo-bar' ); - } ); - - it( 'removes any non-dash special characters', () => { - expect( - kebabCase( 'foo±§!@#$%^&*()-_=+/?.>,<\\|{}[]`~\'";:bar' ) - ).toEqual( 'foo-bar' ); - } ); - - it( 'removes any spacing characters', () => { - expect( kebabCase( ' foo \t \n \r \f \v bar ' ) ).toEqual( 'foo-bar' ); - } ); - - it( 'groups multiple dashes into a single one', () => { - expect( kebabCase( 'foo---bar' ) ).toEqual( 'foo-bar' ); - } ); - - it( 'returns an empty string unchanged', () => { - expect( kebabCase( '' ) ).toEqual( '' ); - } ); - - it( 'returns an existing kebab case string unchanged', () => { - expect( kebabCase( 'foo-123-bar' ) ).toEqual( 'foo-123-bar' ); - } ); - - it( 'returns an empty string if any nullish type is passed', () => { - expect( kebabCase( undefined ) ).toEqual( '' ); - expect( kebabCase( null ) ).toEqual( '' ); - } ); - - it( 'converts any unexpected non-nullish type to a string', () => { - expect( kebabCase( 12345 ) ).toEqual( '12345' ); - expect( kebabCase( [] ) ).toEqual( '' ); - expect( kebabCase( {} ) ).toEqual( 'object-object' ); - } ); - - /** - * Should cover all test cases of `_wp_to_kebab_case()`. - * - * @see https://developer.wordpress.org/reference/functions/_wp_to_kebab_case/ - * @see https://github.com/WordPress/wordpress-develop/blob/76376fdbc3dc0b3261de377dffc350677345e7ba/tests/phpunit/tests/functions/wpToKebabCase.php#L35-L62 - */ - it.each( [ - [ 'white', 'white' ], - [ 'white+black', 'white-black' ], - [ 'white:black', 'white-black' ], - [ 'white*black', 'white-black' ], - [ 'white.black', 'white-black' ], - [ 'white black', 'white-black' ], - [ 'white black', 'white-black' ], - [ 'white-to-black', 'white-to-black' ], - [ 'white2white', 'white-2-white' ], - [ 'white2nd', 'white-2nd' ], - [ 'white2ndcolor', 'white-2-ndcolor' ], - [ 'white2ndColor', 'white-2nd-color' ], - [ 'white2nd_color', 'white-2nd-color' ], - [ 'white23color', 'white-23-color' ], - [ 'white23', 'white-23' ], - [ '23color', '23-color' ], - [ 'white4th', 'white-4th' ], - [ 'font2xl', 'font-2-xl' ], - [ 'whiteToWhite', 'white-to-white' ], - [ 'whiteTOwhite', 'white-t-owhite' ], - [ 'WHITEtoWHITE', 'whit-eto-white' ], - [ 42, '42' ], - [ "i've done", 'ive-done' ], - [ '#ffffff', 'ffffff' ], - [ '$ffffff', 'ffffff' ], - ] )( 'converts %s properly to %s', ( input, expected ) => { - expect( kebabCase( input ) ).toEqual( expected ); - } ); -} ); +import { setImmutably } from '../object'; describe( 'setImmutably', () => { describe( 'handling falsy values properly', () => { diff --git a/packages/components/src/private-apis.ts b/packages/components/src/private-apis.ts index fb4679dbc3423..793d4bf09a2d3 100644 --- a/packages/components/src/private-apis.ts +++ b/packages/components/src/private-apis.ts @@ -42,6 +42,7 @@ import { import { ComponentsContext } from './context/context-system-provider'; import Theme from './theme'; import Tabs from './tabs'; +import { kebabCase } from './utils/strings'; export const { lock, unlock } = __dangerousOptInToUnstableAPIsOnlyForCoreModules( @@ -81,4 +82,5 @@ lock( privateApis, { DropdownMenuSeparatorV2Ariakit, DropdownMenuItemLabelV2Ariakit, DropdownMenuItemHelpTextV2Ariakit, + kebabCase, } ); diff --git a/packages/components/src/utils/strings.ts b/packages/components/src/utils/strings.ts index e4d1d8f73bda1..8b73de1b9c76c 100644 --- a/packages/components/src/utils/strings.ts +++ b/packages/components/src/utils/strings.ts @@ -2,6 +2,7 @@ * External dependencies */ import removeAccents from 'remove-accents'; +import { paramCase } from 'change-case'; const ALL_UNICODE_DASH_CHARACTERS = new RegExp( `[${ [ @@ -71,6 +72,36 @@ export const normalizeTextString = ( value: string ): string => { .replace( ALL_UNICODE_DASH_CHARACTERS, '-' ); }; +/** + * Converts any string to kebab case. + * Backwards compatible with Lodash's `_.kebabCase()`. + * Backwards compatible with `_wp_to_kebab_case()`. + * + * @see https://lodash.com/docs/4.17.15#kebabCase + * @see https://developer.wordpress.org/reference/functions/_wp_to_kebab_case/ + * + * @param {string} str String to convert. + * @return {string} Kebab-cased string + */ +export function kebabCase( str: any ) { + let input = str; + if ( typeof str !== 'string' ) { + input = str?.toString?.() ?? ''; + } + + // See https://github.com/lodash/lodash/blob/b185fcee26b2133bd071f4aaca14b455c2ed1008/lodash.js#L4970 + input = input.replace( /['\u2019]/, '' ); + + return paramCase( input, { + splitRegexp: [ + /(?!(?:1ST|2ND|3RD|[4-9]TH)(?![a-z]))([a-z0-9])([A-Z])/g, // fooBar => foo-bar, 3Bar => 3-bar + /(?!(?:1st|2nd|3rd|[4-9]th)(?![a-z]))([0-9])([a-z])/g, // 3bar => 3-bar + /([A-Za-z])([0-9])/g, // Foo3 => foo-3, foo3 => foo-3 + /([A-Z])([A-Z][a-z])/g, // FOOBar => foo-bar + ], + } ); +} + /** * Escapes the RegExp special characters. * diff --git a/packages/components/src/utils/test/strings.js b/packages/components/src/utils/test/strings.js index 43682a0e2853f..2c7d9641260f5 100644 --- a/packages/components/src/utils/test/strings.js +++ b/packages/components/src/utils/test/strings.js @@ -1,7 +1,102 @@ /** * Internal dependencies */ -import { normalizeTextString } from '../strings'; +import { kebabCase, normalizeTextString } from '../strings'; + +describe( 'kebabCase', () => { + it( 'separates lowercase letters, followed by uppercase letters', () => { + expect( kebabCase( 'fooBar' ) ).toEqual( 'foo-bar' ); + } ); + + it( 'separates numbers, followed by uppercase letters', () => { + expect( kebabCase( '123FOO' ) ).toEqual( '123-foo' ); + } ); + + it( 'separates numbers, followed by lowercase characters', () => { + expect( kebabCase( '123bar' ) ).toEqual( '123-bar' ); + } ); + + it( 'separates uppercase letters, followed by numbers', () => { + expect( kebabCase( 'FOO123' ) ).toEqual( 'foo-123' ); + } ); + + it( 'separates lowercase letters, followed by numbers', () => { + expect( kebabCase( 'foo123' ) ).toEqual( 'foo-123' ); + } ); + + it( 'separates uppercase groups from capitalized groups', () => { + expect( kebabCase( 'FOOBar' ) ).toEqual( 'foo-bar' ); + } ); + + it( 'removes any non-dash special characters', () => { + expect( + kebabCase( 'foo±§!@#$%^&*()-_=+/?.>,<\\|{}[]`~\'";:bar' ) + ).toEqual( 'foo-bar' ); + } ); + + it( 'removes any spacing characters', () => { + expect( kebabCase( ' foo \t \n \r \f \v bar ' ) ).toEqual( 'foo-bar' ); + } ); + + it( 'groups multiple dashes into a single one', () => { + expect( kebabCase( 'foo---bar' ) ).toEqual( 'foo-bar' ); + } ); + + it( 'returns an empty string unchanged', () => { + expect( kebabCase( '' ) ).toEqual( '' ); + } ); + + it( 'returns an existing kebab case string unchanged', () => { + expect( kebabCase( 'foo-123-bar' ) ).toEqual( 'foo-123-bar' ); + } ); + + it( 'returns an empty string if any nullish type is passed', () => { + expect( kebabCase( undefined ) ).toEqual( '' ); + expect( kebabCase( null ) ).toEqual( '' ); + } ); + + it( 'converts any unexpected non-nullish type to a string', () => { + expect( kebabCase( 12345 ) ).toEqual( '12345' ); + expect( kebabCase( [] ) ).toEqual( '' ); + expect( kebabCase( {} ) ).toEqual( 'object-object' ); + } ); + + /** + * Should cover all test cases of `_wp_to_kebab_case()`. + * + * @see https://developer.wordpress.org/reference/functions/_wp_to_kebab_case/ + * @see https://github.com/WordPress/wordpress-develop/blob/76376fdbc3dc0b3261de377dffc350677345e7ba/tests/phpunit/tests/functions/wpToKebabCase.php#L35-L62 + */ + it.each( [ + [ 'white', 'white' ], + [ 'white+black', 'white-black' ], + [ 'white:black', 'white-black' ], + [ 'white*black', 'white-black' ], + [ 'white.black', 'white-black' ], + [ 'white black', 'white-black' ], + [ 'white black', 'white-black' ], + [ 'white-to-black', 'white-to-black' ], + [ 'white2white', 'white-2-white' ], + [ 'white2nd', 'white-2nd' ], + [ 'white2ndcolor', 'white-2-ndcolor' ], + [ 'white2ndColor', 'white-2nd-color' ], + [ 'white2nd_color', 'white-2nd-color' ], + [ 'white23color', 'white-23-color' ], + [ 'white23', 'white-23' ], + [ '23color', '23-color' ], + [ 'white4th', 'white-4th' ], + [ 'font2xl', 'font-2-xl' ], + [ 'whiteToWhite', 'white-to-white' ], + [ 'whiteTOwhite', 'white-t-owhite' ], + [ 'WHITEtoWHITE', 'whit-eto-white' ], + [ 42, '42' ], + [ "i've done", 'ive-done' ], + [ '#ffffff', 'ffffff' ], + [ '$ffffff', 'ffffff' ], + ] )( 'converts %s properly to %s', ( input, expected ) => { + expect( kebabCase( input ) ).toEqual( expected ); + } ); +} ); describe( 'normalizeTextString', () => { it( 'should normalize hyphen-like characters to hyphens', () => { From dae26b9e6429e9b21eb3efd03a066a692b20c245 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Mon, 4 Dec 2023 22:47:00 +0900 Subject: [PATCH 02/12] Update changelog --- packages/components/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 3b22c45f91993..b5f69d172bb04 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -4,6 +4,7 @@ ### Enhancements +- Move `kebabCase()` function from `block-editor` package and mark it as private API ([#56758](https://github.com/WordPress/gutenberg/pull/56758)). - `FormToggle`: fix sass deprecation warning ([#56672](https://github.com/WordPress/gutenberg/pull/56672)). - `QueryControls`: Add opt-in prop for 40px default size ([#56576](https://github.com/WordPress/gutenberg/pull/56576)). - `CheckboxControl`: Add option to not render label ([#56158](https://github.com/WordPress/gutenberg/pull/56158)). From 11fe4d1cf93060164af27035e2ef719c23fe3ec5 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Mon, 4 Dec 2023 23:47:57 +0900 Subject: [PATCH 03/12] Fix native app test --- packages/components/src/lock-unlock.js | 10 ++++++++++ packages/components/src/private-apis.native.js | 13 +++++++++++++ packages/components/src/private-apis.ts | 7 +------ 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 packages/components/src/lock-unlock.js create mode 100644 packages/components/src/private-apis.native.js diff --git a/packages/components/src/lock-unlock.js b/packages/components/src/lock-unlock.js new file mode 100644 index 0000000000000..1525ece158072 --- /dev/null +++ b/packages/components/src/lock-unlock.js @@ -0,0 +1,10 @@ +/** + * WordPress dependencies + */ +import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis'; + +export const { lock, unlock } = + __dangerousOptInToUnstableAPIsOnlyForCoreModules( + 'I know using unstable features means my theme or plugin will inevitably break in the next version of WordPress.', + '@wordpress/components' + ); diff --git a/packages/components/src/private-apis.native.js b/packages/components/src/private-apis.native.js new file mode 100644 index 0000000000000..451534f92fd68 --- /dev/null +++ b/packages/components/src/private-apis.native.js @@ -0,0 +1,13 @@ +/** + * Internal dependencies + */ +import { kebabCase } from './utils/strings'; +import { lock } from './lock-unlock'; + +/** + * Private @wordpress/block-editor APIs. + */ +export const privateApis = {}; +lock( privateApis, { + kebabCase, +} ); diff --git a/packages/components/src/private-apis.ts b/packages/components/src/private-apis.ts index 793d4bf09a2d3..ba0048407574e 100644 --- a/packages/components/src/private-apis.ts +++ b/packages/components/src/private-apis.ts @@ -43,12 +43,7 @@ import { ComponentsContext } from './context/context-system-provider'; import Theme from './theme'; import Tabs from './tabs'; import { kebabCase } from './utils/strings'; - -export const { lock, unlock } = - __dangerousOptInToUnstableAPIsOnlyForCoreModules( - 'I know using unstable features means my theme or plugin will inevitably break in the next version of WordPress.', - '@wordpress/components' - ); +import { lock } from './lock-unlock'; export const privateApis = {}; lock( privateApis, { From b96c143e6f5a213670a3778172ec4a73a85108a7 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Tue, 5 Dec 2023 00:31:07 +0900 Subject: [PATCH 04/12] Try to fix native app test --- packages/components/src/index.native.js | 3 +++ packages/components/src/lock-unlock.js | 10 ---------- packages/components/src/private-apis.native.js | 13 ------------- packages/components/src/private-apis.ts | 7 ++++++- 4 files changed, 9 insertions(+), 24 deletions(-) delete mode 100644 packages/components/src/lock-unlock.js delete mode 100644 packages/components/src/private-apis.native.js diff --git a/packages/components/src/index.native.js b/packages/components/src/index.native.js index 6c793499102e1..b73294fe808dd 100644 --- a/packages/components/src/index.native.js +++ b/packages/components/src/index.native.js @@ -142,3 +142,6 @@ export { useMobileGlobalStylesColors, useEditorColorScheme, } from './mobile/global-styles-context/utils'; + +// Private APIs. +export { privateApis } from './private-apis'; diff --git a/packages/components/src/lock-unlock.js b/packages/components/src/lock-unlock.js deleted file mode 100644 index 1525ece158072..0000000000000 --- a/packages/components/src/lock-unlock.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * WordPress dependencies - */ -import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis'; - -export const { lock, unlock } = - __dangerousOptInToUnstableAPIsOnlyForCoreModules( - 'I know using unstable features means my theme or plugin will inevitably break in the next version of WordPress.', - '@wordpress/components' - ); diff --git a/packages/components/src/private-apis.native.js b/packages/components/src/private-apis.native.js deleted file mode 100644 index 451534f92fd68..0000000000000 --- a/packages/components/src/private-apis.native.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Internal dependencies - */ -import { kebabCase } from './utils/strings'; -import { lock } from './lock-unlock'; - -/** - * Private @wordpress/block-editor APIs. - */ -export const privateApis = {}; -lock( privateApis, { - kebabCase, -} ); diff --git a/packages/components/src/private-apis.ts b/packages/components/src/private-apis.ts index ba0048407574e..793d4bf09a2d3 100644 --- a/packages/components/src/private-apis.ts +++ b/packages/components/src/private-apis.ts @@ -43,7 +43,12 @@ import { ComponentsContext } from './context/context-system-provider'; import Theme from './theme'; import Tabs from './tabs'; import { kebabCase } from './utils/strings'; -import { lock } from './lock-unlock'; + +export const { lock, unlock } = + __dangerousOptInToUnstableAPIsOnlyForCoreModules( + 'I know using unstable features means my theme or plugin will inevitably break in the next version of WordPress.', + '@wordpress/components' + ); export const privateApis = {}; lock( privateApis, { From ec98c5244533109dce6b3512fa038f78ec3dde50 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Tue, 5 Dec 2023 00:55:01 +0900 Subject: [PATCH 05/12] Try to fix mobile app test --- packages/components/src/lock-unlock.js | 10 ++++++++++ packages/components/src/private-apis.native.js | 13 +++++++++++++ packages/components/src/private-apis.ts | 7 +------ 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 packages/components/src/lock-unlock.js create mode 100644 packages/components/src/private-apis.native.js diff --git a/packages/components/src/lock-unlock.js b/packages/components/src/lock-unlock.js new file mode 100644 index 0000000000000..1525ece158072 --- /dev/null +++ b/packages/components/src/lock-unlock.js @@ -0,0 +1,10 @@ +/** + * WordPress dependencies + */ +import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis'; + +export const { lock, unlock } = + __dangerousOptInToUnstableAPIsOnlyForCoreModules( + 'I know using unstable features means my theme or plugin will inevitably break in the next version of WordPress.', + '@wordpress/components' + ); diff --git a/packages/components/src/private-apis.native.js b/packages/components/src/private-apis.native.js new file mode 100644 index 0000000000000..659de19f39137 --- /dev/null +++ b/packages/components/src/private-apis.native.js @@ -0,0 +1,13 @@ +/** + * Internal dependencies + */ +import { kebabCase } from './utils/strings'; +import { lock } from './lock-unlock'; + +/** + * Private @wordpress/components APIs. + */ +export const privateApis = {}; +lock( privateApis, { + kebabCase, +} ); diff --git a/packages/components/src/private-apis.ts b/packages/components/src/private-apis.ts index 793d4bf09a2d3..ba0048407574e 100644 --- a/packages/components/src/private-apis.ts +++ b/packages/components/src/private-apis.ts @@ -43,12 +43,7 @@ import { ComponentsContext } from './context/context-system-provider'; import Theme from './theme'; import Tabs from './tabs'; import { kebabCase } from './utils/strings'; - -export const { lock, unlock } = - __dangerousOptInToUnstableAPIsOnlyForCoreModules( - 'I know using unstable features means my theme or plugin will inevitably break in the next version of WordPress.', - '@wordpress/components' - ); +import { lock } from './lock-unlock'; export const privateApis = {}; lock( privateApis, { From faa563b80b3e5e991b9023625624b47b62cf483a Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Tue, 5 Dec 2023 15:37:12 +0200 Subject: [PATCH 06/12] Try importing kebabCase directly from components --- .../block-editor/src/components/colors/utils.js | 9 ++++++++- .../src/components/colors/with-colors.js | 4 +++- .../src/components/font-sizes/utils.js | 8 +++++++- .../global-styles/use-global-styles-output.js | 14 +++++++++----- packages/block-editor/src/hooks/font-family.js | 4 +++- packages/block-editor/src/hooks/layout.js | 4 +++- .../block-editor/src/hooks/use-typography-props.js | 8 +++++++- packages/block-editor/src/private-apis.js | 2 -- packages/block-editor/src/private-apis.native.js | 2 -- packages/block-editor/src/utils/object.js | 12 ------------ .../font-library-modal/collection-font-variant.js | 9 +++++++-- .../font-library-modal/library-font-variant.js | 9 +++++++-- 12 files changed, 54 insertions(+), 31 deletions(-) diff --git a/packages/block-editor/src/components/colors/utils.js b/packages/block-editor/src/components/colors/utils.js index 1c1947bfc947c..d6d51ad001363 100644 --- a/packages/block-editor/src/components/colors/utils.js +++ b/packages/block-editor/src/components/colors/utils.js @@ -5,10 +5,15 @@ import { colord, extend } from 'colord'; import namesPlugin from 'colord/plugins/names'; import a11yPlugin from 'colord/plugins/a11y'; +/** + * WordPress dependencies + */ +import { privateApis as componentsPrivateApis } from '@wordpress/components'; + /** * Internal dependencies */ -import { kebabCase } from '../../utils/object'; +import { unlock } from '../../lock-unlock'; extend( [ namesPlugin, a11yPlugin ] ); @@ -70,6 +75,8 @@ export function getColorClassName( colorContextName, colorSlug ) { return undefined; } + const { kebabCase } = unlock( componentsPrivateApis ); + return `has-${ kebabCase( colorSlug ) }-${ colorContextName }`; } diff --git a/packages/block-editor/src/components/colors/with-colors.js b/packages/block-editor/src/components/colors/with-colors.js index 5946ca90d8bbd..33079f8b409d6 100644 --- a/packages/block-editor/src/components/colors/with-colors.js +++ b/packages/block-editor/src/components/colors/with-colors.js @@ -3,6 +3,7 @@ */ import { useMemo, Component } from '@wordpress/element'; import { compose, createHigherOrderComponent } from '@wordpress/compose'; +import { privateApis as componentsPrivateApis } from '@wordpress/components'; /** * Internal dependencies @@ -14,7 +15,7 @@ import { getMostReadableColor, } from './utils'; import { useSettings } from '../use-settings'; -import { kebabCase } from '../../utils/object'; +import { unlock } from '../../lock-unlock'; /** * Capitalizes the first letter in a string. @@ -79,6 +80,7 @@ const withEditorColorPalette = () => * @return {Component} The component that can be used as a HOC. */ function createColorHOC( colorTypes, withColorPalette ) { + const { kebabCase } = unlock( componentsPrivateApis ); const colorMap = colorTypes.reduce( ( colorObject, colorType ) => { return { ...colorObject, diff --git a/packages/block-editor/src/components/font-sizes/utils.js b/packages/block-editor/src/components/font-sizes/utils.js index 2f874f6665f8f..dff28c7a770d4 100644 --- a/packages/block-editor/src/components/font-sizes/utils.js +++ b/packages/block-editor/src/components/font-sizes/utils.js @@ -1,7 +1,12 @@ +/** + * WordPress dependencies + */ +import { privateApis as componentsPrivateApis } from '@wordpress/components'; + /** * Internal dependencies */ -import { kebabCase } from '../../utils/object'; +import { unlock } from '../../lock-unlock'; /** * Returns the font size object based on an array of named font sizes and the namedFontSize and customFontSize values. @@ -64,5 +69,6 @@ export function getFontSizeClass( fontSizeSlug ) { return; } + const { kebabCase } = unlock( componentsPrivateApis ); return `has-${ kebabCase( fontSizeSlug ) }-font-size`; } diff --git a/packages/block-editor/src/components/global-styles/use-global-styles-output.js b/packages/block-editor/src/components/global-styles/use-global-styles-output.js index 7e99eca355b52..1cd63ef4d03f0 100644 --- a/packages/block-editor/src/components/global-styles/use-global-styles-output.js +++ b/packages/block-editor/src/components/global-styles/use-global-styles-output.js @@ -11,6 +11,7 @@ import { import { useSelect } from '@wordpress/data'; import { useContext, useMemo } from '@wordpress/element'; import { getCSSRules } from '@wordpress/style-engine'; +import { privateApis as componentsPrivateApis } from '@wordpress/components'; /** * Internal dependencies @@ -32,12 +33,9 @@ import { getDuotoneFilter } from '../duotone/utils'; import { getGapCSSValue } from '../../hooks/gap'; import { store as blockEditorStore } from '../../store'; import { LAYOUT_DEFINITIONS } from '../../layouts/definitions'; -import { - getValueFromObjectPath, - kebabCase, - setImmutably, -} from '../../utils/object'; +import { getValueFromObjectPath, setImmutably } from '../../utils/object'; import BlockContext from '../block-context'; +import { unlock } from '../../lock-unlock'; // List of block support features that can have their related styles // generated under their own feature level selector rather than the block's. @@ -72,6 +70,8 @@ function compileStyleValue( uncompiledValue ) { * @return {Array} An array of style declarations. */ function getPresetsDeclarations( blockPresets = {}, mergedSettings ) { + const { kebabCase } = unlock( componentsPrivateApis ); + return PRESET_METADATA.reduce( ( declarations, { path, valueKey, valueFunc, cssVarInfix } ) => { const presetByOrigin = getValueFromObjectPath( @@ -116,6 +116,8 @@ function getPresetsDeclarations( blockPresets = {}, mergedSettings ) { * @return {string} CSS declarations for the preset classes. */ function getPresetsClasses( blockSelector = '*', blockPresets = {} ) { + const { kebabCase } = unlock( componentsPrivateApis ); + return PRESET_METADATA.reduce( ( declarations, { path, cssVarInfix, classes } ) => { if ( ! classes ) { @@ -180,6 +182,7 @@ function getPresetsSvgFilters( blockPresets = {} ) { } function flattenTree( input = {}, prefix, token ) { + const { kebabCase } = unlock( componentsPrivateApis ); let result = []; Object.keys( input ).forEach( ( key ) => { const newKey = prefix + kebabCase( key.replace( '/', '-' ) ); @@ -321,6 +324,7 @@ export function getStylesDeclarations( tree = {}, isTemplate = true ) { + const { kebabCase } = unlock( componentsPrivateApis ); const isRoot = ROOT_BLOCK_SELECTOR === selector; const output = Object.entries( STYLE_PROPERTY ).reduce( ( diff --git a/packages/block-editor/src/hooks/font-family.js b/packages/block-editor/src/hooks/font-family.js index 0988b285564d3..5aab45d2fd6ad 100644 --- a/packages/block-editor/src/hooks/font-family.js +++ b/packages/block-editor/src/hooks/font-family.js @@ -4,13 +4,14 @@ import { addFilter } from '@wordpress/hooks'; import { hasBlockSupport } from '@wordpress/blocks'; import TokenList from '@wordpress/token-list'; +import { privateApis as componentsPrivateApis } from '@wordpress/components'; /** * Internal dependencies */ import { shouldSkipSerialization } from './utils'; import { TYPOGRAPHY_SUPPORT_KEY } from './typography'; -import { kebabCase } from '../utils/object'; +import { unlock } from '../lock-unlock'; export const FONT_FAMILY_SUPPORT_KEY = 'typography.__experimentalFontFamily'; @@ -67,6 +68,7 @@ function addSaveProps( props, blockType, attributes ) { // Use TokenList to dedupe classes. const classes = new TokenList( props.className ); + const { kebabCase } = unlock( componentsPrivateApis ); classes.add( `has-${ kebabCase( attributes?.fontFamily ) }-font-family` ); const newClassName = classes.value; props.className = newClassName ? newClassName : undefined; diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index 9b35c3dcd6076..45f2c5c0367b0 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -15,6 +15,7 @@ import { ButtonGroup, ToggleControl, PanelBody, + privateApis as componentsPrivateApis, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; @@ -27,8 +28,8 @@ import { useSettings } from '../components/use-settings'; import { getLayoutType, getLayoutTypes } from '../layouts'; import { useBlockEditingMode } from '../components/block-editing-mode'; import { LAYOUT_DEFINITIONS } from '../layouts/definitions'; -import { kebabCase } from '../utils/object'; import { useBlockSettings, useStyleOverride } from './utils'; +import { unlock } from '../lock-unlock'; const layoutBlockSupportKey = 'layout'; @@ -48,6 +49,7 @@ function hasLayoutBlockSupport( blockName ) { * @return { Array } Array of CSS classname strings. */ export function useLayoutClasses( blockAttributes = {}, blockName = '' ) { + const { kebabCase } = unlock( componentsPrivateApis ); const rootPaddingAlignment = useSelect( ( select ) => { const { getSettings } = select( blockEditorStore ); return getSettings().__experimentalFeatures diff --git a/packages/block-editor/src/hooks/use-typography-props.js b/packages/block-editor/src/hooks/use-typography-props.js index 1ed02d4a5835f..14f5874c1422c 100644 --- a/packages/block-editor/src/hooks/use-typography-props.js +++ b/packages/block-editor/src/hooks/use-typography-props.js @@ -3,6 +3,11 @@ */ import classnames from 'classnames'; +/** + * WordPress dependencies + */ +import { privateApis as componentsPrivateApis } from '@wordpress/components'; + /** * Internal dependencies */ @@ -12,7 +17,7 @@ import { getTypographyFontSizeValue, getFluidTypographyOptionsFromSettings, } from '../components/global-styles/typography-utils'; -import { kebabCase } from '../utils/object'; +import { unlock } from '../lock-unlock'; /* * This utility is intended to assist where the serialization of the typography @@ -29,6 +34,7 @@ import { kebabCase } from '../utils/object'; * @return {Object} Typography block support derived CSS classes & styles. */ export function getTypographyClassesAndStyles( attributes, settings ) { + const { kebabCase } = unlock( componentsPrivateApis ); let typographyStyles = attributes?.style?.typography || {}; const fluidTypographySettings = getFluidTypographyOptionsFromSettings( settings ); diff --git a/packages/block-editor/src/private-apis.js b/packages/block-editor/src/private-apis.js index b1d499ae09946..57b0ca2e048b6 100644 --- a/packages/block-editor/src/private-apis.js +++ b/packages/block-editor/src/private-apis.js @@ -5,7 +5,6 @@ import * as globalStyles from './components/global-styles'; import { ExperimentalBlockEditorProvider } from './components/provider'; import { lock } from './lock-unlock'; import { getRichTextValues } from './components/rich-text/get-rich-text-values'; -import { kebabCase } from './utils/object'; import ResizableBoxPopover from './components/resizable-box-popover'; import { ComposedPrivateInserter as PrivateInserter } from './components/inserter'; import { PrivateListView } from './components/list-view'; @@ -37,7 +36,6 @@ lock( privateApis, { ExperimentalBlockEditorProvider, getDuotoneFilter, getRichTextValues, - kebabCase, PrivateInserter, PrivateListView, ResizableBoxPopover, diff --git a/packages/block-editor/src/private-apis.native.js b/packages/block-editor/src/private-apis.native.js index 17676f634b1ca..5555e00477e7b 100644 --- a/packages/block-editor/src/private-apis.native.js +++ b/packages/block-editor/src/private-apis.native.js @@ -3,7 +3,6 @@ */ import * as globalStyles from './components/global-styles'; import { ExperimentalBlockEditorProvider } from './components/provider'; -import { kebabCase } from './utils/object'; import { lock } from './lock-unlock'; /** @@ -12,6 +11,5 @@ import { lock } from './lock-unlock'; export const privateApis = {}; lock( privateApis, { ...globalStyles, - kebabCase, ExperimentalBlockEditorProvider, } ); diff --git a/packages/block-editor/src/utils/object.js b/packages/block-editor/src/utils/object.js index 160ead75f272e..8f6c82a9c3991 100644 --- a/packages/block-editor/src/utils/object.js +++ b/packages/block-editor/src/utils/object.js @@ -1,15 +1,3 @@ -/** - * WordPress dependencies - */ -import { privateApis as componentsPrivateApis } from '@wordpress/components'; - -/** - * Internal dependencies - */ -import { unlock } from '../lock-unlock'; - -export const { kebabCase } = unlock( componentsPrivateApis ); - /** * Immutably sets a value inside an object. Like `lodash#set`, but returning a * new object. Treats nullish initial values as empty objects. Clones any diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/collection-font-variant.js b/packages/edit-site/src/components/global-styles/font-library-modal/collection-font-variant.js index 8c2b36d3adee9..6108ca7669c5b 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/collection-font-variant.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/collection-font-variant.js @@ -1,14 +1,18 @@ /** * WordPress dependencies */ -import { CheckboxControl, Flex } from '@wordpress/components'; +import { + CheckboxControl, + Flex, + privateApis as componentsPrivateApis, +} from '@wordpress/components'; /** * Internal dependencies */ import { getFontFaceVariantName } from './utils'; import FontFaceDemo from './font-demo'; -import { kebabCase } from '../../../../../block-editor/src/utils/object'; +import { unlock } from '../../../lock-unlock'; function CollectionFontVariant( { face, @@ -25,6 +29,7 @@ function CollectionFontVariant( { }; const displayName = font.name + ' ' + getFontFaceVariantName( face ); + const { kebabCase } = unlock( componentsPrivateApis ); const checkboxId = kebabCase( `${ font.slug }-${ getFontFaceVariantName( face ) }` ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/library-font-variant.js b/packages/edit-site/src/components/global-styles/font-library-modal/library-font-variant.js index 010f3efdbeb91..d74a5f74f019b 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/library-font-variant.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/library-font-variant.js @@ -2,7 +2,11 @@ * WordPress dependencies */ import { useContext } from '@wordpress/element'; -import { CheckboxControl, Flex } from '@wordpress/components'; +import { + CheckboxControl, + Flex, + privateApis as componentsPrivateApis, +} from '@wordpress/components'; /** * Internal dependencies @@ -10,7 +14,7 @@ import { CheckboxControl, Flex } from '@wordpress/components'; import { getFontFaceVariantName } from './utils'; import { FontLibraryContext } from './context'; import FontFaceDemo from './font-demo'; -import { kebabCase } from '../../../../../block-editor/src/utils/object'; +import { unlock } from '../../../lock-unlock'; function LibraryFontVariant( { face, font } ) { const { isFontActivated, toggleActivateFont } = @@ -34,6 +38,7 @@ function LibraryFontVariant( { face, font } ) { }; const displayName = font.name + ' ' + getFontFaceVariantName( face ); + const { kebabCase } = unlock( componentsPrivateApis ); const checkboxId = kebabCase( `${ font.slug }-${ getFontFaceVariantName( face ) }` ); From 9e512d61cc9116a4589338ff086edcda368efe84 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Tue, 5 Dec 2023 15:42:11 +0200 Subject: [PATCH 07/12] Fix another import --- packages/block-library/src/embed/util.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/embed/util.js b/packages/block-library/src/embed/util.js index a7a6ea219f277..c591c5d19e2d2 100644 --- a/packages/block-library/src/embed/util.js +++ b/packages/block-library/src/embed/util.js @@ -7,7 +7,7 @@ import memoize from 'memize'; /** * WordPress dependencies */ -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; +import { privateApis as componentsPrivateApis } from '@wordpress/components'; import { renderToString } from '@wordpress/element'; import { createBlock, @@ -23,7 +23,6 @@ import { ASPECT_RATIOS, WP_EMBED_TYPE } from './constants'; import { unlock } from '../lock-unlock'; const { name: DEFAULT_EMBED_BLOCK } = metadata; -const { kebabCase } = unlock( blockEditorPrivateApis ); /** @typedef {import('@wordpress/blocks').WPBlockVariation} WPBlockVariation */ @@ -283,6 +282,7 @@ export const getAttributesFromPreview = memoize( // If we got a provider name from the API, use it for the slug, otherwise we use the title, // because not all embed code gives us a provider name. const { html, provider_name: providerName } = preview; + const { kebabCase } = unlock( componentsPrivateApis ); const providerNameSlug = kebabCase( ( providerName || title ).toLowerCase() ); From b6ec1ff8cba78b031313704559514d73fea875e7 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sat, 9 Dec 2023 20:22:18 +0900 Subject: [PATCH 08/12] Move changelog entry to Internal section --- packages/components/CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index b5f69d172bb04..b28fdbb92c9af 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -4,7 +4,6 @@ ### Enhancements -- Move `kebabCase()` function from `block-editor` package and mark it as private API ([#56758](https://github.com/WordPress/gutenberg/pull/56758)). - `FormToggle`: fix sass deprecation warning ([#56672](https://github.com/WordPress/gutenberg/pull/56672)). - `QueryControls`: Add opt-in prop for 40px default size ([#56576](https://github.com/WordPress/gutenberg/pull/56576)). - `CheckboxControl`: Add option to not render label ([#56158](https://github.com/WordPress/gutenberg/pull/56158)). @@ -13,6 +12,10 @@ - `ToggleGroupControl`: react correctly to external controlled updates ([#56678](https://github.com/WordPress/gutenberg/pull/56678)). +### Internal + +- Move `kebabCase()` function from `block-editor` package and mark it as private API ([#56758](https://github.com/WordPress/gutenberg/pull/56758)). + ## 25.13.0 (2023-11-29) ### Enhancements From 5625a86eaf7c99877c7332decd39d7ce5203078e Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sat, 9 Dec 2023 20:40:44 +0900 Subject: [PATCH 09/12] Change the argument type of kebabCase function to unknown --- packages/components/src/utils/strings.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/components/src/utils/strings.ts b/packages/components/src/utils/strings.ts index 8b73de1b9c76c..a1d192942a394 100644 --- a/packages/components/src/utils/strings.ts +++ b/packages/components/src/utils/strings.ts @@ -83,11 +83,8 @@ export const normalizeTextString = ( value: string ): string => { * @param {string} str String to convert. * @return {string} Kebab-cased string */ -export function kebabCase( str: any ) { - let input = str; - if ( typeof str !== 'string' ) { - input = str?.toString?.() ?? ''; - } +export function kebabCase( str: unknown ) { + let input = str?.toString?.() ?? ''; // See https://github.com/lodash/lodash/blob/b185fcee26b2133bd071f4aaca14b455c2ed1008/lodash.js#L4970 input = input.replace( /['\u2019]/, '' ); From c48080d34b5147a965898549169e8a577bd61ce4 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sat, 9 Dec 2023 21:07:32 +0900 Subject: [PATCH 10/12] Fix lint error --- packages/block-editor/src/hooks/layout.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index c557b511264a7..54824558cb703 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -350,6 +350,7 @@ function BlockWithLayoutStyles( { block: BlockListBlock, props } ) { : layout || defaultBlockLayout || {}; const layoutClasses = useLayoutClasses( attributes, name ); + const { kebabCase } = unlock( componentsPrivateApis ); const selectorPrefix = `wp-container-${ kebabCase( name ) }-layout-`; // Higher specificity to override defaults from theme.json. const selector = `.${ selectorPrefix }${ id }.${ selectorPrefix }${ id }`; From 8db901f66b691882be617d2d852e6f96bbdb7746 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Tue, 12 Dec 2023 18:21:19 +0900 Subject: [PATCH 11/12] Merge duplicate Internal sections --- packages/components/CHANGELOG.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 4015c27d01bf0..1e7d9e1acc2ad 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -21,6 +21,7 @@ ### Internal - `DropdownMenuV2Ariakit`: prevent prefix collapsing if all radios or checkboxes are unselected ([#56720](https://github.com/WordPress/gutenberg/pull/56720)). +- Move `kebabCase()` function from `block-editor` package and mark it as private API ([#56758](https://github.com/WordPress/gutenberg/pull/56758)). ### Experimental @@ -30,10 +31,6 @@ - `Tabs`: improve focus handling in controlled mode ([#56658](https://github.com/WordPress/gutenberg/pull/56658)). -### Internal - -- Move `kebabCase()` function from `block-editor` package and mark it as private API ([#56758](https://github.com/WordPress/gutenberg/pull/56758)). - ## 25.13.0 (2023-11-29) ### Enhancements From 102e9851b1610a60c1b6b8b5944c511b68b8cd85 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Wed, 13 Dec 2023 11:22:14 +0900 Subject: [PATCH 12/12] Remove type info in the JSDoc comment --- packages/components/src/utils/strings.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/components/src/utils/strings.ts b/packages/components/src/utils/strings.ts index a1d192942a394..bb43a5e53a405 100644 --- a/packages/components/src/utils/strings.ts +++ b/packages/components/src/utils/strings.ts @@ -80,8 +80,8 @@ export const normalizeTextString = ( value: string ): string => { * @see https://lodash.com/docs/4.17.15#kebabCase * @see https://developer.wordpress.org/reference/functions/_wp_to_kebab_case/ * - * @param {string} str String to convert. - * @return {string} Kebab-cased string + * @param str String to convert. + * @return Kebab-cased string */ export function kebabCase( str: unknown ) { let input = str?.toString?.() ?? ''; @@ -102,9 +102,9 @@ export function kebabCase( str: unknown ) { /** * Escapes the RegExp special characters. * - * @param {string} string Input string. + * @param string Input string. * - * @return {string} Regex-escaped string. + * @return Regex-escaped string. */ export function escapeRegExp( string: string ): string { return string.replace( /[\\^$.*+?()[\]{}|]/g, '\\$&' );