From 5900cf69ec81c3fa7c446499769929eda0a7b3ce Mon Sep 17 00:00:00 2001 From: Luigi Teschio Date: Tue, 3 Dec 2024 10:48:09 +0100 Subject: [PATCH] Move `duplicateTemplatePart` action to the `@wordpress/fields` package (#65390) Co-authored-by: gigitux Co-authored-by: youknowriad Co-authored-by: oandregal --- packages/base-styles/_z-index.scss | 2 +- .../post-actions/set-as-homepage.js | 17 ++- .../convert-to-template-part.js | 2 +- .../editor/src/dataviews/actions/utils.ts | 64 --------- .../src/dataviews/store/private-actions.ts | 4 +- packages/editor/src/dataviews/types.ts | 88 ------------ packages/editor/src/private-apis.js | 2 +- packages/editor/src/style.scss | 1 - packages/fields/README.md | 25 ++++ .../src}/actions/duplicate-template-part.tsx | 12 +- packages/fields/src/actions/index.ts | 1 + packages/fields/src/actions/rename-post.tsx | 9 +- packages/fields/src/actions/reset-post.tsx | 13 +- packages/fields/src/actions/utils.ts | 18 +-- .../create-template-part-modal/index.tsx} | 130 +++++++++++++----- .../create-template-part-modal/style.scss | 14 +- .../create-template-part-modal/test/utils.js | 0 .../create-template-part-modal/utils.js | 23 ++-- packages/fields/src/index.ts | 3 +- packages/fields/src/style.scss | 1 + packages/fields/src/types.ts | 3 + packages/fields/tsconfig.json | 1 + 22 files changed, 185 insertions(+), 248 deletions(-) delete mode 100644 packages/editor/src/dataviews/actions/utils.ts delete mode 100644 packages/editor/src/dataviews/types.ts rename packages/{editor/src/dataviews => fields/src}/actions/duplicate-template-part.tsx (87%) rename packages/{editor/src/components/create-template-part-modal/index.js => fields/src/components/create-template-part-modal/index.tsx} (52%) rename packages/{editor => fields}/src/components/create-template-part-modal/style.scss (69%) rename packages/{editor => fields}/src/components/create-template-part-modal/test/utils.js (100%) rename packages/{editor => fields}/src/components/create-template-part-modal/utils.js (86%) diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss index 167af583ed9ddb..c2ee8f698c2c80 100644 --- a/packages/base-styles/_z-index.scss +++ b/packages/base-styles/_z-index.scss @@ -123,7 +123,7 @@ $z-layers: ( // Should be above the popover (dropdown) ".reusable-blocks-menu-items__convert-modal": 1000001, ".patterns-menu-items__convert-modal": 1000001, - ".editor-create-template-part-modal": 1000001, + ".fields-create-template-part-modal": 1000001, ".block-editor-block-lock-modal": 1000001, ".block-editor-template-part__selection-modal": 1000001, ".block-editor-block-rename-modal": 1000001, diff --git a/packages/editor/src/components/post-actions/set-as-homepage.js b/packages/editor/src/components/post-actions/set-as-homepage.js index 0366a52482f2a8..70bdeeeefe70fb 100644 --- a/packages/editor/src/components/post-actions/set-as-homepage.js +++ b/packages/editor/src/components/post-actions/set-as-homepage.js @@ -12,11 +12,20 @@ import { import { useDispatch, useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; import { store as noticesStore } from '@wordpress/notices'; +import { decodeEntities } from '@wordpress/html-entities'; -/** - * Internal dependencies - */ -import { getItemTitle } from '../../dataviews/actions/utils'; +const getItemTitle = ( item ) => { + if ( typeof item.title === 'string' ) { + return decodeEntities( item.title ); + } + if ( item.title && 'rendered' in item.title ) { + return decodeEntities( item.title.rendered ); + } + if ( item.title && 'raw' in item.title ) { + return decodeEntities( item.title.raw ); + } + return ''; +}; const SetAsHomepageModal = ( { items, closeModal } ) => { const [ item ] = items; diff --git a/packages/editor/src/components/template-part-menu-items/convert-to-template-part.js b/packages/editor/src/components/template-part-menu-items/convert-to-template-part.js index 4ae15d1dd178c0..9ce11772a34b7a 100644 --- a/packages/editor/src/components/template-part-menu-items/convert-to-template-part.js +++ b/packages/editor/src/components/template-part-menu-items/convert-to-template-part.js @@ -13,7 +13,7 @@ import { symbolFilled } from '@wordpress/icons'; /** * Internal dependencies */ -import CreateTemplatePartModal from '../create-template-part-modal'; +import { CreateTemplatePartModal } from '@wordpress/fields'; export default function ConvertToTemplatePart( { clientIds, blocks } ) { const [ isModalOpen, setIsModalOpen ] = useState( false ); diff --git a/packages/editor/src/dataviews/actions/utils.ts b/packages/editor/src/dataviews/actions/utils.ts deleted file mode 100644 index 33a2be16397f3f..00000000000000 --- a/packages/editor/src/dataviews/actions/utils.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * WordPress dependencies - */ -import { decodeEntities } from '@wordpress/html-entities'; - -/** - * Internal dependencies - */ -import { - TEMPLATE_ORIGINS, - TEMPLATE_PART_POST_TYPE, - TEMPLATE_POST_TYPE, -} from '../../store/constants'; - -import type { Post, TemplatePart, Template } from '../types'; - -export function isTemplate( post: Post ): post is Template { - return post.type === TEMPLATE_POST_TYPE; -} - -export function isTemplatePart( post: Post ): post is TemplatePart { - return post.type === TEMPLATE_PART_POST_TYPE; -} - -export function isTemplateOrTemplatePart( - p: Post -): p is Template | TemplatePart { - return p.type === TEMPLATE_POST_TYPE || p.type === TEMPLATE_PART_POST_TYPE; -} - -export function getItemTitle( item: Post ) { - if ( typeof item.title === 'string' ) { - return decodeEntities( item.title ); - } - if ( 'rendered' in item.title ) { - return decodeEntities( item.title.rendered ); - } - if ( 'raw' in item.title ) { - return decodeEntities( item.title.raw ); - } - return ''; -} - -/** - * Check if a template is removable. - * - * @param template The template entity to check. - * @return Whether the template is removable. - */ -export function isTemplateRemovable( template: Template | TemplatePart ) { - if ( ! template ) { - return false; - } - // In patterns list page we map the templates parts to a different object - // than the one returned from the endpoint. This is why we need to check for - // two props whether is custom or has a theme file. - return ( - [ template.source, template.source ].includes( - TEMPLATE_ORIGINS.custom - ) && - ! Boolean( template.type === 'wp_template' && template?.plugin ) && - ! template.has_theme_file - ); -} diff --git a/packages/editor/src/dataviews/store/private-actions.ts b/packages/editor/src/dataviews/store/private-actions.ts index 9e8d184e34d3a4..e61ade7e830364 100644 --- a/packages/editor/src/dataviews/store/private-actions.ts +++ b/packages/editor/src/dataviews/store/private-actions.ts @@ -8,9 +8,9 @@ import { doAction } from '@wordpress/hooks'; /** * Internal dependencies */ -import type { PostType } from '../types'; import { store as editorStore } from '../../store'; import { unlock } from '../../lock-unlock'; +import type { PostType } from '@wordpress/fields'; import { viewPost, viewPostRevisions, @@ -24,6 +24,7 @@ import { renamePost, resetPost, deletePost, + duplicateTemplatePart, featuredImageField, dateField, parentField, @@ -34,7 +35,6 @@ import { authorField, titleField, } from '@wordpress/fields'; -import duplicateTemplatePart from '../actions/duplicate-template-part'; export function registerEntityAction< Item >( kind: string, diff --git a/packages/editor/src/dataviews/types.ts b/packages/editor/src/dataviews/types.ts deleted file mode 100644 index 9549e6c4aa374d..00000000000000 --- a/packages/editor/src/dataviews/types.ts +++ /dev/null @@ -1,88 +0,0 @@ -type PostStatus = - | 'publish' - | 'draft' - | 'pending' - | 'private' - | 'future' - | 'auto-draft' - | 'trash'; - -export interface CommonPost { - status?: PostStatus; - title: string | { rendered: string } | { raw: string }; - content: string | { raw: string; rendered: string }; - type: string; - id: string | number; - blocks?: Object[]; - _links?: Links; -} - -interface Links { - 'predecessor-version'?: { href: string; id: number }[]; - 'version-history'?: { href: string; count: number }[]; - [ key: string ]: { href: string }[] | undefined; -} - -export interface BasePost extends CommonPost { - comment_status?: 'open' | 'closed'; - excerpt?: string | { raw: string; rendered: string }; - meta?: Record< string, any >; - parent?: number; - password?: string; - template?: string; - format?: string; - featured_media?: number; - menu_order?: number; - ping_status?: 'open' | 'closed'; - link?: string; -} - -export interface Template extends CommonPost { - type: 'wp_template'; - is_custom: boolean; - source: string; - origin: string; - plugin?: string; - has_theme_file: boolean; - id: string; -} - -export interface TemplatePart extends CommonPost { - type: 'wp_template_part'; - source: string; - origin: string; - has_theme_file: boolean; - id: string; - area: string; -} - -export interface Pattern extends CommonPost { - slug: string; - title: { raw: string }; - wp_pattern_sync_status: string; -} - -export type Post = Template | TemplatePart | Pattern | BasePost; - -export type PostWithPermissions = Post & { - permissions: { - delete: boolean; - update: boolean; - }; -}; - -export interface PostType { - slug: string; - viewable: boolean; - supports?: { - 'page-attributes'?: boolean; - title?: boolean; - revisions?: boolean; - thumbnail?: boolean; - comments?: boolean; - author?: boolean; - }; -} - -// Will be unnecessary after typescript 5.0 upgrade. -export type CoreDataError = { message?: string; code?: string }; diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index 2699858b3164f6..11083eb6ab8a45 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -10,7 +10,6 @@ import { lock } from './lock-unlock'; import { EntitiesSavedStatesExtensible } from './components/entities-saved-states'; import EditorContentSlotFill from './components/editor-interface/content-slot-fill'; import BackButton from './components/header/back-button'; -import CreateTemplatePartModal from './components/create-template-part-modal'; import Editor from './components/editor'; import PluginPostExcerpt from './components/post-excerpt/plugin'; import PostCardPanel from './components/post-card-panel'; @@ -24,6 +23,7 @@ import { mergeBaseAndUserConfigs, GlobalStylesProvider, } from './components/global-styles-provider'; +import { CreateTemplatePartModal } from '@wordpress/fields'; import { registerCoreBlockBindingsSources } from './bindings/api'; import { getTemplateInfo } from './utils/get-template-info'; diff --git a/packages/editor/src/style.scss b/packages/editor/src/style.scss index 1504211a51e899..1a8103ae2b16c4 100644 --- a/packages/editor/src/style.scss +++ b/packages/editor/src/style.scss @@ -3,7 +3,6 @@ @import "./components/autocompleters/style.scss"; @import "./components/collab-sidebar/style.scss"; @import "./components/collapsible-block-toolbar/style.scss"; -@import "./components/create-template-part-modal/style.scss"; @import "./components/block-settings-menu/style.scss"; @import "./components/blog-title/style.scss"; @import "./components/document-bar/style.scss"; diff --git a/packages/fields/README.md b/packages/fields/README.md index e6cf6d3007ed97..6723611d2d9686 100644 --- a/packages/fields/README.md +++ b/packages/fields/README.md @@ -18,10 +18,23 @@ npm install @wordpress/fields --save Author field for BasePost. +### BasePostWithEmbeddedAuthor + +Undocumented declaration. + ### commentStatusField Comment status field for BasePost. +### CreateTemplatePartModal + +A React component that renders a modal for creating a template part. The modal displays a title and the contents for creating the template part. This component should not live in this package, it should be moved to a dedicated package responsible for managing template. + +_Parameters_ + +- _props_ `Object`: The component props. +- _props.modalTitle_ `{ modalTitle: string; } & CreateTemplatePartModalContentsProps[ 'modalTitle' ]`: + ### dateField Date field for BasePost. @@ -42,6 +55,14 @@ Undocumented declaration. Undocumented declaration. +### duplicateTemplatePart + +This action is used to duplicate a template part. + +_Type_ + +- `Action< TemplatePart >` + ### exportPattern Undocumented declaration. @@ -70,6 +91,10 @@ This field is used to display the post password. Undocumented declaration. +### PostType + +Undocumented declaration. + ### renamePost Undocumented declaration. diff --git a/packages/editor/src/dataviews/actions/duplicate-template-part.tsx b/packages/fields/src/actions/duplicate-template-part.tsx similarity index 87% rename from packages/editor/src/dataviews/actions/duplicate-template-part.tsx rename to packages/fields/src/actions/duplicate-template-part.tsx index 5f576ecdb58639..44fcbad21f0733 100644 --- a/packages/editor/src/dataviews/actions/duplicate-template-part.tsx +++ b/packages/fields/src/actions/duplicate-template-part.tsx @@ -12,15 +12,17 @@ import type { Action } from '@wordpress/dataviews'; /** * Internal dependencies */ -import { TEMPLATE_PART_POST_TYPE } from '../../store/constants'; -import { CreateTemplatePartModalContents } from '../../components/create-template-part-modal'; -import { getItemTitle } from './utils'; import type { Post, TemplatePart } from '../types'; +import { CreateTemplatePartModalContents } from '../components/create-template-part-modal'; +import { getItemTitle } from './utils'; +/** + * This action is used to duplicate a template part. + */ const duplicateTemplatePart: Action< TemplatePart > = { id: 'duplicate-template-part', label: _x( 'Duplicate', 'action label' ), - isEligible: ( item ) => item.type === TEMPLATE_PART_POST_TYPE, + isEligible: ( item ) => item.type === 'wp_template_part', modalHeader: _x( 'Duplicate template part', 'action label' ), RenderModal: ( { items, closeModal } ) => { const [ item ] = items; @@ -61,7 +63,7 @@ const duplicateTemplatePart: Action< TemplatePart > = { onCreate={ onTemplatePartSuccess } onError={ closeModal } confirmLabel={ _x( 'Duplicate', 'action label' ) } - closeModal={ closeModal } + closeModal={ closeModal ?? ( () => {} ) } /> ); }, diff --git a/packages/fields/src/actions/index.ts b/packages/fields/src/actions/index.ts index 08e22836e68fd1..fc662206775316 100644 --- a/packages/fields/src/actions/index.ts +++ b/packages/fields/src/actions/index.ts @@ -13,3 +13,4 @@ export { default as permanentlyDeletePost } from './permanently-delete-post'; export { default as restorePost } from './restore-post'; export { default as trashPost } from './trash-post'; export { default as deletePost } from './delete-post'; +export { default as duplicateTemplatePart } from './duplicate-template-part'; diff --git a/packages/fields/src/actions/rename-post.tsx b/packages/fields/src/actions/rename-post.tsx index da1fd46669f0df..5203328b46de53 100644 --- a/packages/fields/src/actions/rename-post.tsx +++ b/packages/fields/src/actions/rename-post.tsx @@ -26,9 +26,6 @@ import { isTemplateRemovable, isTemplate, isTemplatePart, - TEMPLATE_ORIGINS, - TEMPLATE_PART_POST_TYPE, - TEMPLATE_POST_TYPE, } from './utils'; import type { CoreDataError, PostWithPermissions } from '../types'; @@ -45,8 +42,8 @@ const renamePost: Action< PostWithPermissions > = { // Templates, template parts and patterns have special checks for renaming. if ( ! [ - TEMPLATE_POST_TYPE, - TEMPLATE_PART_POST_TYPE, + 'wp_template', + 'wp_template_part', ...Object.values( PATTERN_TYPES ), ].includes( post.type ) ) { @@ -64,7 +61,7 @@ const renamePost: Action< PostWithPermissions > = { if ( isTemplatePart( post ) ) { return ( - post.source === TEMPLATE_ORIGINS.custom && + post.source === 'custom' && ! post?.has_theme_file && post.permissions?.update ); diff --git a/packages/fields/src/actions/reset-post.tsx b/packages/fields/src/actions/reset-post.tsx index 105d7b283b8334..3e6b2e29b68b65 100644 --- a/packages/fields/src/actions/reset-post.tsx +++ b/packages/fields/src/actions/reset-post.tsx @@ -22,12 +22,7 @@ import apiFetch from '@wordpress/api-fetch'; /** * Internal dependencies */ -import { - getItemTitle, - isTemplateOrTemplatePart, - TEMPLATE_ORIGINS, - TEMPLATE_POST_TYPE, -} from './utils'; +import { getItemTitle, isTemplateOrTemplatePart } from './utils'; import type { CoreDataError, Template, TemplatePart } from '../types'; const isTemplateRevertable = ( @@ -38,7 +33,7 @@ const isTemplateRevertable = ( } return ( - templateOrTemplatePart.source === TEMPLATE_ORIGINS.custom && + templateOrTemplatePart.source === 'custom' && ( Boolean( templateOrTemplatePart?.plugin ) || templateOrTemplatePart?.has_theme_file ) ); @@ -186,7 +181,7 @@ const resetPostAction: Action< Template | TemplatePart > = { isEligible: ( item ) => { return ( isTemplateOrTemplatePart( item ) && - item?.source === TEMPLATE_ORIGINS.custom && + item?.source === 'custom' && ( Boolean( item.type === 'wp_template' && item?.plugin ) || item?.has_theme_file ) ); @@ -231,7 +226,7 @@ const resetPostAction: Action< Template | TemplatePart > = { ); } catch ( error ) { let fallbackErrorMessage; - if ( items[ 0 ].type === TEMPLATE_POST_TYPE ) { + if ( items[ 0 ].type === 'wp_template' ) { fallbackErrorMessage = items.length === 1 ? __( diff --git a/packages/fields/src/actions/utils.ts b/packages/fields/src/actions/utils.ts index 8f990fb1168fcc..efd389405b5be8 100644 --- a/packages/fields/src/actions/utils.ts +++ b/packages/fields/src/actions/utils.ts @@ -8,26 +8,18 @@ import { decodeEntities } from '@wordpress/html-entities'; */ import type { Post, TemplatePart, Template } from '../types'; -export const TEMPLATE_POST_TYPE = 'wp_template'; -export const TEMPLATE_PART_POST_TYPE = 'wp_template_part'; -export const TEMPLATE_ORIGINS = { - custom: 'custom', - theme: 'theme', - plugin: 'plugin', -}; - export function isTemplate( post: Post ): post is Template { - return post.type === TEMPLATE_POST_TYPE; + return post.type === 'wp_template'; } export function isTemplatePart( post: Post ): post is TemplatePart { - return post.type === TEMPLATE_PART_POST_TYPE; + return post.type === 'wp_template_part'; } export function isTemplateOrTemplatePart( p: Post ): p is Template | TemplatePart { - return p.type === TEMPLATE_POST_TYPE || p.type === TEMPLATE_PART_POST_TYPE; + return p.type === 'wp_template' || p.type === 'wp_template_part'; } export function getItemTitle( item: Post ): string { @@ -57,9 +49,7 @@ export function isTemplateRemovable( template: Template | TemplatePart ) { // than the one returned from the endpoint. This is why we need to check for // two props whether is custom or has a theme file. return ( - [ template.source, template.source ].includes( - TEMPLATE_ORIGINS.custom - ) && + [ template.source, template.source ].includes( 'custom' ) && ! Boolean( template.type === 'wp_template' && template?.plugin ) && ! template.has_theme_file ); diff --git a/packages/editor/src/components/create-template-part-modal/index.js b/packages/fields/src/components/create-template-part-modal/index.tsx similarity index 52% rename from packages/editor/src/components/create-template-part-modal/index.js rename to packages/fields/src/components/create-template-part-modal/index.tsx index 660439ded2300f..03b39a8fdcdf39 100644 --- a/packages/editor/src/components/create-template-part-modal/index.js +++ b/packages/fields/src/components/create-template-part-modal/index.tsx @@ -1,7 +1,6 @@ /** * WordPress dependencies */ -import { useSelect, useDispatch } from '@wordpress/data'; import { Icon, BaseControl, @@ -16,34 +15,57 @@ import { __experimentalHStack as HStack, __experimentalVStack as VStack, } from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; -import { useState } from '@wordpress/element'; import { useInstanceId } from '@wordpress/compose'; -import { store as noticesStore } from '@wordpress/notices'; import { store as coreStore } from '@wordpress/core-data'; -import { check } from '@wordpress/icons'; +import { useDispatch, useSelect } from '@wordpress/data'; +import { useState } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { + check, + footer as footerIcon, + header as headerIcon, + sidebar as sidebarIcon, + symbolFilled as symbolFilledIcon, +} from '@wordpress/icons'; +import { store as noticesStore } from '@wordpress/notices'; +// @ts-ignore import { serialize } from '@wordpress/blocks'; /** * Internal dependencies */ import { - TEMPLATE_PART_POST_TYPE, - TEMPLATE_PART_AREA_DEFAULT_CATEGORY, -} from '../../store/constants'; -import { - useExistingTemplateParts, - getUniqueTemplatePartTitle, getCleanTemplatePartSlug, + getUniqueTemplatePartTitle, + useExistingTemplateParts, } from './utils'; +type CreateTemplatePartModalContentsProps = { + defaultArea?: string; + blocks: any[]; + confirmLabel?: string; + closeModal: () => void; + onCreate: ( templatePart: any ) => void; + onError?: () => void; + defaultTitle?: string; +}; + +/** + * A React component that renders a modal for creating a template part. The modal displays a title and the contents for creating the template part. + * This component should not live in this package, it should be moved to a dedicated package responsible for managing template. + * @param {Object} props The component props. + * @param props.modalTitle + */ export default function CreateTemplatePartModal( { modalTitle, ...restProps -} ) { +}: { + modalTitle: string; +} & CreateTemplatePartModalContentsProps ) { const defaultModalTitle = useSelect( ( select ) => - select( coreStore ).getPostType( TEMPLATE_PART_POST_TYPE )?.labels + // @ts-ignore + select( coreStore ).getPostType( 'wp_template_part' )?.labels ?.add_new_item, [] ); @@ -51,24 +73,49 @@ export default function CreateTemplatePartModal( { + { /* @ts-ignore */ } ); } +const getTemplatePartIcon = ( iconName: string ) => { + if ( 'header' === iconName ) { + return headerIcon; + } else if ( 'footer' === iconName ) { + return footerIcon; + } else if ( 'sidebar' === iconName ) { + return sidebarIcon; + } + return symbolFilledIcon; +}; + +/** + * A React component that renders the content of a model for creating a template part. + * This component should not live in this package; it should be moved to a dedicated package responsible for managing template. + * + * @param {Object} props - The component props. + * @param {string} [props.defaultArea=uncategorized] - The default area for the template part. + * @param {Array} [props.blocks=[]] - The blocks to be included in the template part. + * @param {string} [props.confirmLabel='Add'] - The label for the confirm button. + * @param {Function} props.closeModal - Function to close the modal. + * @param {Function} props.onCreate - Function to call when the template part is successfully created. + * @param {Function} [props.onError] - Function to call when there is an error creating the template part. + * @param {string} [props.defaultTitle=''] - The default title for the template part. + */ export function CreateTemplatePartModalContents( { - defaultArea = TEMPLATE_PART_AREA_DEFAULT_CATEGORY, + defaultArea = 'uncategorized', blocks = [], confirmLabel = __( 'Add' ), closeModal, onCreate, onError, defaultTitle = '', -} ) { +}: CreateTemplatePartModalContentsProps ) { const { createErrorNotice } = useDispatch( noticesStore ); const { saveEntityRecord } = useDispatch( coreStore ); const existingTemplateParts = useExistingTemplateParts(); @@ -78,12 +125,22 @@ export function CreateTemplatePartModalContents( { const [ isSubmitting, setIsSubmitting ] = useState( false ); const instanceId = useInstanceId( CreateTemplatePartModal ); - const templatePartAreas = useSelect( - ( select ) => - select( coreStore ).getEntityRecord( 'root', '__unstableBase' ) - ?.default_template_part_areas || [], - [] - ); + const defaultTemplatePartAreas = useSelect( ( select ) => { + const areas = + // @ts-expect-error getEntityRecord is not typed with unstableBase as argument. + select( coreStore ).getEntityRecord< { + default_template_part_areas: Array< { + area: string; + label: string; + icon: string; + description: string; + } >; + } >( 'root', '__unstableBase' )?.default_template_part_areas || []; + + return areas.map( ( item ) => { + return { ...item, icon: getTemplatePartIcon( item.icon ) }; + } ); + }, [] ); async function createTemplatePart() { if ( ! title || isSubmitting ) { @@ -100,7 +157,7 @@ export function CreateTemplatePartModalContents( { const templatePart = await saveEntityRecord( 'postType', - TEMPLATE_PART_POST_TYPE, + 'wp_template_part', { slug: cleanSlug, title: uniqueTitle, @@ -114,7 +171,10 @@ export function CreateTemplatePartModalContents( { // TODO: Add a success notice? } catch ( error ) { const errorMessage = - error.message && error.code !== 'unknown_error' + error instanceof Error && + 'code' in error && + error.message && + error.code !== 'unknown_error' ? error.message : __( 'An error occurred while creating the template part.' @@ -146,34 +206,38 @@ export function CreateTemplatePartModalContents( { + value && typeof value === 'string' + ? setArea( value ) + : () => void 0 + } checked={ area } > - { templatePartAreas.map( + { defaultTemplatePartAreas.map( ( { icon, label, area: value, description } ) => ( - + { label }
{ description }
- + { area === value && ( ) } diff --git a/packages/editor/src/components/create-template-part-modal/style.scss b/packages/fields/src/components/create-template-part-modal/style.scss similarity index 69% rename from packages/editor/src/components/create-template-part-modal/style.scss rename to packages/fields/src/components/create-template-part-modal/style.scss index be15e8d76d536e..fedc0326648c2e 100644 --- a/packages/editor/src/components/create-template-part-modal/style.scss +++ b/packages/fields/src/components/create-template-part-modal/style.scss @@ -1,13 +1,13 @@ -.editor-create-template-part-modal { - z-index: z-index(".editor-create-template-part-modal"); +.fields-create-template-part-modal { + z-index: z-index(".fields-create-template-part-modal"); } -.editor-create-template-part-modal__area-radio-group { +.fields-create-template-part-modal__area-radio-group { width: 100%; border: $border-width solid $gray-700; border-radius: $radius-small; - .components-button.editor-create-template-part-modal__area-radio { + .components-button.fields-create-template-part-modal__area-radio { display: block; width: 100%; height: 100%; @@ -40,12 +40,12 @@ color: $gray-900; cursor: auto; - .editor-create-template-part-modal__option-label div { + .fields-create-template-part-modal__option-label div { color: $gray-600; } } - .editor-create-template-part-modal__option-label { + .fields-create-template-part-modal__option-label { padding-top: $grid-unit-05; white-space: normal; @@ -55,7 +55,7 @@ } } - .editor-create-template-part-modal__checkbox { + .fields-create-template-part-modal__checkbox { margin-left: auto; min-width: $grid-unit-30; } diff --git a/packages/editor/src/components/create-template-part-modal/test/utils.js b/packages/fields/src/components/create-template-part-modal/test/utils.js similarity index 100% rename from packages/editor/src/components/create-template-part-modal/test/utils.js rename to packages/fields/src/components/create-template-part-modal/test/utils.js diff --git a/packages/editor/src/components/create-template-part-modal/utils.js b/packages/fields/src/components/create-template-part-modal/utils.js similarity index 86% rename from packages/editor/src/components/create-template-part-modal/utils.js rename to packages/fields/src/components/create-template-part-modal/utils.js index 02f24cf17d2be9..9ecf3efd03f918 100644 --- a/packages/editor/src/components/create-template-part-modal/utils.js +++ b/packages/fields/src/components/create-template-part-modal/utils.js @@ -12,19 +12,20 @@ import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies */ -import { TEMPLATE_PART_POST_TYPE } from '../../store/constants'; export const useExistingTemplateParts = () => { - return useSelect( - ( select ) => - select( coreStore ).getEntityRecords( - 'postType', - TEMPLATE_PART_POST_TYPE, - { - per_page: -1, - } - ), - [] + return ( + useSelect( + ( select ) => + select( coreStore ).getEntityRecords( + 'postType', + 'wp_template_part', + { + per_page: -1, + } + ), + [] + ) ?? [] ); }; diff --git a/packages/fields/src/index.ts b/packages/fields/src/index.ts index 41879a86e76bed..1658c9d8c51eee 100644 --- a/packages/fields/src/index.ts +++ b/packages/fields/src/index.ts @@ -1,3 +1,4 @@ export * from './fields'; export * from './actions'; -export type * from './types'; +export { default as CreateTemplatePartModal } from './components/create-template-part-modal'; +export type { BasePostWithEmbeddedAuthor, PostType } from './types'; diff --git a/packages/fields/src/style.scss b/packages/fields/src/style.scss index 1639f455ba093e..05cf5652248777 100644 --- a/packages/fields/src/style.scss +++ b/packages/fields/src/style.scss @@ -1,2 +1,3 @@ +@import "./components/create-template-part-modal/style.scss"; @import "./fields/slug/style.scss"; @import "./fields/featured-image/style.scss"; diff --git a/packages/fields/src/types.ts b/packages/fields/src/types.ts index e457ec699554cd..1b251d125b1be8 100644 --- a/packages/fields/src/types.ts +++ b/packages/fields/src/types.ts @@ -97,6 +97,9 @@ export interface PostType { 'page-attributes'?: boolean; title?: boolean; revisions?: boolean; + author?: string; + thumbnail?: string; + comments?: string; }; } diff --git a/packages/fields/tsconfig.json b/packages/fields/tsconfig.json index 5c4b91e88f895a..531afb5bb2d873 100644 --- a/packages/fields/tsconfig.json +++ b/packages/fields/tsconfig.json @@ -12,6 +12,7 @@ { "path": "../components" }, { "path": "../compose" }, { "path": "../core-data" }, + { "path": "../block-editor" }, { "path": "../data" }, { "path": "../dataviews" }, { "path": "../date" },