Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QuickEdit: Add Featured Image Control #64496

Merged
merged 51 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
785085b
Page Edit View: Implement Featured image page field
gigitux Aug 14, 2024
dd7e0a3
Merge branch 'trunk' of github.com:WordPress/gutenberg into add/page-…
gigitux Aug 14, 2024
77f2217
Merge branch 'trunk' of github.com:WordPress/gutenberg into add/page-…
gigitux Aug 21, 2024
433e45f
Merge branch 'trunk' of github.com:WordPress/gutenberg into add/page-…
gigitux Aug 21, 2024
f890963
improve flow and style
gigitux Aug 22, 2024
c32622e
fix list layout
gigitux Aug 22, 2024
9a39fe6
improve design
gigitux Aug 23, 2024
5419b0a
remove not necessary style
gigitux Aug 23, 2024
68ef300
Merge branch 'trunk' of github.com:WordPress/gutenberg into add/page-…
gigitux Aug 26, 2024
cd923f8
improve style
gigitux Aug 27, 2024
94335a4
improve default image control
gigitux Aug 27, 2024
030a28d
Merge branch 'trunk' of github.com:WordPress/gutenberg into add/page-…
gigitux Aug 27, 2024
baf7a82
fix style
gigitux Aug 29, 2024
4095dab
remove not necessary configuration
gigitux Aug 29, 2024
23d8695
Merge branch 'trunk' of github.com:WordPress/gutenberg into add/page-…
gigitux Aug 29, 2024
ec715ed
format _z-index.scss file
gigitux Aug 29, 2024
ea29690
improve style
gigitux Aug 29, 2024
106af4d
remove not necessary code
gigitux Aug 29, 2024
cc46724
Merge branch 'trunk' of github.com:WordPress/gutenberg into add/page-…
gigitux Aug 29, 2024
b11e923
Merge branch 'trunk' of github.com:WordPress/gutenberg into add/page-…
gigitux Sep 9, 2024
c6dffd7
fix focus
gigitux Sep 9, 2024
3c262d6
remove image field type
gigitux Sep 9, 2024
c053a9a
add comment
gigitux Sep 9, 2024
57faa8f
fix warning
gigitux Sep 9, 2024
d2eeb0e
fix image for deleted pages
gigitux Sep 9, 2024
05f0d1a
remove filename
gigitux Sep 10, 2024
c4db3b9
add border-radius
gigitux Sep 10, 2024
cd9fe2f
Merge branch 'trunk' of github.com:WordPress/gutenberg into add/page-…
gigitux Sep 18, 2024
8356977
migrate featured image to fields package
gigitux Sep 18, 2024
e27dec1
fix CSS
gigitux Sep 19, 2024
a187591
remove not necessary changes
gigitux Sep 19, 2024
8815e5a
fix type
gigitux Sep 19, 2024
a461d85
remove empty space
gigitux Sep 19, 2024
fcc2e6e
fix z-index gallery
gigitux Sep 19, 2024
577f836
fix overlapping and style
gigitux Sep 19, 2024
a3449c4
improve codestyle
gigitux Sep 19, 2024
2366429
Merge branch 'trunk' of github.com:WordPress/gutenberg into add/page-…
gigitux Sep 20, 2024
1b84ac0
use same placeholder style grid/list layout
gigitux Sep 20, 2024
6ca01ff
fix tsconfig
gigitux Sep 20, 2024
8e612d4
Merge branch 'trunk' of github.com:WordPress/gutenberg into add/page-…
gigitux Oct 22, 2024
c448c49
add type
gigitux Oct 22, 2024
2b595c2
remove mediaField from layout table
gigitux Oct 22, 2024
9cc6d80
update type
gigitux Oct 22, 2024
01a57a8
use text as type
gigitux Oct 22, 2024
7b1e40a
use media-utils package
gigitux Oct 22, 2024
6592d36
fix tsconfig
gigitux Oct 22, 2024
c2994e0
remove view prop
gigitux Oct 22, 2024
b039310
revert changes
gigitux Oct 22, 2024
42f90f4
generate package-lock.json
gigitux Oct 22, 2024
ea8e941
Merge branch 'trunk' of github.com:WordPress/gutenberg into add/page-…
gigitux Oct 23, 2024
e77b93b
generate package-lock.json
gigitux Oct 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions packages/base-styles/_z-index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ $z-layers: (

// Ensure footer stays above the preview field.
".dataviews-footer": 2,

// Needs to be below media library (.media-model) that has a z-index of 160000.
".components-popover.components-dropdown__content.dataforms-layouts-panel__field-dropdown": 160000 - 10,
);

@function z-index( $key ) {
Expand Down
36 changes: 35 additions & 1 deletion packages/core-data/src/entity-types/attachment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,40 @@ import type {

import type { BaseEntityRecords as _BaseEntityRecords } from './base-entity-records';

interface MediaDetails {
width: number;
height: number;
file: string;
filesize: number;
sizes: { [ key: string ]: Size };
image_meta: ImageMeta;
original_image?: string;
}
interface ImageMeta {
aperture: string;
credit: string;
camera: string;
caption: string;
created_timestamp: string;
copyright: string;
focal_length: string;
iso: string;
shutter_speed: string;
title: string;
orientation: string;
keywords: any[];
}

interface Size {
file: string;
width: number;
height: number;
filesize?: number;
mime_type: string;
source_url: string;
uncropped?: boolean;
}

declare module './base-entity-records' {
export namespace BaseEntityRecords {
export interface Attachment< C extends Context > {
Expand Down Expand Up @@ -124,7 +158,7 @@ declare module './base-entity-records' {
/**
* Details about the media file, specific to its type.
*/
media_details: Record< string, string >;
media_details: MediaDetails;
/**
* The ID for the associated post of the attachment.
*/
Expand Down
3 changes: 3 additions & 0 deletions packages/dataviews/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,6 @@ export const sortIcons = {
export const LAYOUT_TABLE = 'table';
export const LAYOUT_GRID = 'grid';
export const LAYOUT_LIST = 'list';

// Form layouts.
export const LAYOUT_PANEL = 'panel';
3 changes: 2 additions & 1 deletion packages/dataviews/src/dataforms-layouts/panel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { closeSmall } from '@wordpress/icons';
import { normalizeFields } from '../../normalize-fields';
import { getVisibleFields } from '../get-visible-fields';
import type { DataFormProps, NormalizedField } from '../../types';
import { LAYOUT_PANEL } from '../../constants';

interface FormFieldProps< Item > {
data: Item;
Expand Down Expand Up @@ -110,7 +111,7 @@ function FormField< Item >( {
) }
onClick={ onToggle }
>
<field.render item={ data } />
<field.render item={ data } view={ LAYOUT_PANEL } />
Copy link
Member

@oandregal oandregal Sep 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How this looks like in the regular panel? Can we update the storybook to see how fields of this type behave in both layouts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change does not affect the appearance of the current fields in different views. The primary goal is to pass this information to the field, enabling it to adjust its layout based on the view property.

</Button>
) }
renderContent={ ( { onClose } ) => (
Expand Down
15 changes: 11 additions & 4 deletions packages/dataviews/src/dataviews-layouts/grid/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import SingleSelectionCheckbox from '../../components/dataviews-selection-checkb
import { useHasAPossibleBulkAction } from '../../components/dataviews-bulk-actions';
import type { Action, NormalizedField, ViewGridProps } from '../../types';
import type { SetSelection } from '../../private-types';
import { LAYOUT_GRID } from '../../constants';

interface GridItemProps< Item > {
selection: string[];
Expand Down Expand Up @@ -54,10 +55,10 @@ function GridItem< Item >( {
const id = getItemId( item );
const isSelected = selection.includes( id );
const renderedMediaField = mediaField?.render ? (
<mediaField.render item={ item } />
<mediaField.render item={ item } view={ LAYOUT_GRID } />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why adding a view to the render function is necessary? I'd like us to avoid this if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the layout, the field has a different UI:

const component = getComponentToDisplay( { item, title, url, onClick } )[
view
];

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me clarify:

People are going to be able to register data views layouts independently from fields, meaning ideally the rendering of fields is universal and shouldn't be dependent on the layout type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I favor the universal approach, I'm afraid that it will not be very flexible. In the case of the featured image field, we have major differents between panel and the rest of the layouts:

Type Image Without Image
Panel image image
Grid image image
Table image image
List image image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will have a similar issue even with the new layout.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it's a difficult constraint, but I think we should think of this constraint as a good thing and instead try to solve it in a way that doesn't require knowledge about the layout.

There seem to be one main difference:

  • In a form, in addition to the thumbnail, we show either "logo-1.jpg" or "Choose an image".
  • In dataviews, it's always just a thumbnail.

So what does this difference mean for the "field" abstraction.

  • First, I would argue that we can start (potentially merge this PR) by using just the thumbnail in the form like all the other usage in dataviews.
  • Second, if we do want to make this discussion, I think I'd ask myself the question: What is the prop that would make sense for a field to define this distinction. A prop that new layouts could decide to use or not. For instance something like size could make sense or something like isDetailed ... And then a layout or a DataForm, could decide to say, I render all the fields with a "small" size, or I render all the fields with "details", from there a Field could decide what it means for them to change size or to show details. A field might decide that it has no impact on them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First, I would argue that we can start (potentially merge this PR) by using just the thumbnail in the form like all the other usage in dataviews.

I'm going to proceed with this approach, given that the second one looks like not strictly related to this field control, and it needs further discussion.

Copy link
Contributor Author

@gigitux gigitux Oct 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the PR with commit c2994e0 to no longer rely on the view prop. The main downside of this approach is that the click event is no longer configured for the grid view. So when the user clicks on the image, the editor isn't opened anymore:

Before After
Screen.Capture.on.2024-10-22.at.15-50-03.mp4
Screen.Capture.on.2024-10-22.at.15-51-08.mp4

Additionally, even though the field no longer relies on the view prop, setting the correct image dimensions still requires using the CSS cascade:

https://github.com/WordPress/gutenberg/blob/c2994e0ab6850e23b284d1a82ad7b4608b13311d/packages/fields/src/fields/featured-image/style.scss#L73-L96

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second, if we do want to make this discussion, I think I'd ask myself the question: What is the prop that would make sense for a field to define this distinction. A prop that new layouts could decide to use or not. For instance something like size could make sense or something like isDetailed ... And then a layout or a DataForm, could decide to say, I render all the fields with a "small" size, or I render all the fields with "details", from there a Field could decide what it means for them to change size or to show details. A field might decide that it has no impact on them.

I created a dedicated issue for this topic: #66336

) : null;
const renderedPrimaryField = primaryField?.render ? (
<primaryField.render item={ item } />
<primaryField.render item={ item } view={ LAYOUT_GRID } />
) : null;
return (
<VStack
Expand Down Expand Up @@ -115,7 +116,10 @@ function GridItem< Item >( {
key={ field.id }
className="dataviews-view-grid__field-value"
>
<field.render item={ item } />
<field.render
item={ item }
view={ LAYOUT_GRID }
/>
</FlexItem>
);
} ) }
Expand Down Expand Up @@ -151,7 +155,10 @@ function GridItem< Item >( {
className="dataviews-view-grid__field-value"
style={ { maxHeight: 'none' } }
>
<field.render item={ item } />
<field.render
item={ item }
view={ LAYOUT_GRID }
/>
</FlexItem>
</>
</Flex>
Expand Down
10 changes: 7 additions & 3 deletions packages/dataviews/src/dataviews-layouts/list/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
ActionModal,
} from '../../components/dataviews-item-actions';
import type { Action, NormalizedField, ViewListProps } from '../../types';
import { LAYOUT_LIST } from '../../constants';

interface ListViewItemProps< Item > {
actions: Action< Item >[];
Expand Down Expand Up @@ -176,13 +177,13 @@ function ListItem< Item >( {
}, [ actions, item ] );

const renderedMediaField = mediaField?.render ? (
<mediaField.render item={ item } />
<mediaField.render item={ item } view={ LAYOUT_LIST } />
) : (
<div className="dataviews-view-list__media-placeholder"></div>
);

const renderedPrimaryField = primaryField?.render ? (
<primaryField.render item={ item } />
<primaryField.render item={ item } view={ LAYOUT_LIST } />
) : null;

const usedActions = eligibleActions?.length > 0 && (
Expand Down Expand Up @@ -280,7 +281,10 @@ function ListItem< Item >( {
{ field.label }
</VisuallyHidden>
<span className="dataviews-view-list__field-value">
<field.render item={ item } />
<field.render
item={ item }
view={ LAYOUT_LIST }
/>
</span>
</div>
) ) }
Expand Down
4 changes: 2 additions & 2 deletions packages/dataviews/src/dataviews-layouts/table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { useEffect, useId, useRef, useState } from '@wordpress/element';
*/
import SingleSelectionCheckbox from '../../components/dataviews-selection-checkbox';
import ItemActions from '../../components/dataviews-item-actions';
import { sortValues } from '../../constants';
import { LAYOUT_TABLE, sortValues } from '../../constants';
import {
useSomeItemHasAPossibleBulkAction,
useHasAPossibleBulkAction,
Expand Down Expand Up @@ -110,7 +110,7 @@ function TableColumnField< Item >( {
primaryField?.id === field.id,
} ) }
>
<field.render { ...{ item } } />
<field.render { ...{ item } } view={ LAYOUT_TABLE } />
</div>
);
}
Expand Down
19 changes: 17 additions & 2 deletions packages/dataviews/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import type { ReactElement, ComponentType } from 'react';
* Internal dependencies
*/
import type { SetSelection } from './private-types';
import type {
LAYOUT_GRID,
LAYOUT_LIST,
LAYOUT_PANEL,
LAYOUT_TABLE,
} from './constants';

export type SortDirection = 'asc' | 'desc';

Expand Down Expand Up @@ -106,7 +112,7 @@ export type Field< Item > = {
/**
* Callback used to render the field. Defaults to `field.getValue`.
*/
render?: ComponentType< { item: Item } >;
render?: ComponentType< DataViewRenderFieldProps< Item > >;

/**
* Callback used to render an edit control for the field.
Expand Down Expand Up @@ -159,7 +165,7 @@ export type NormalizedField< Item > = Field< Item > & {
label: string;
header: string | ReactElement;
getValue: ( args: { item: Item } ) => any;
render: ComponentType< { item: Item } >;
render: ComponentType< DataViewRenderFieldProps< Item > >;
Edit: ComponentType< DataFormControlProps< Item > >;
sort: ( a: Item, b: Item, direction: SortDirection ) => number;
isValid: ( item: Item, context?: ValidationContext ) => boolean;
Expand All @@ -181,6 +187,15 @@ export type DataFormControlProps< Item > = {
hideLabelFromVision?: boolean;
};

export type DataViewRenderFieldProps< Item > = {
item: Item;
view:
| typeof LAYOUT_LIST
| typeof LAYOUT_GRID
| typeof LAYOUT_TABLE
| typeof LAYOUT_PANEL;
};

/**
* The filters applied to the dataset.
*/
Expand Down
1 change: 1 addition & 0 deletions packages/edit-site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@wordpress/editor": "file:../editor",
"@wordpress/element": "file:../element",
"@wordpress/escape-html": "file:../escape-html",
"@wordpress/fields": "file:../fields",
"@wordpress/hooks": "file:../hooks",
"@wordpress/html-entities": "file:../html-entities",
"@wordpress/i18n": "file:../i18n",
Expand Down
10 changes: 8 additions & 2 deletions packages/edit-site/src/components/post-edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,19 @@ function PostEditForm( { postType, postId } ) {
);
const form = {
type: 'panel',
fields: [ 'title', 'status', 'date', 'author', 'comment_status' ],
fields: [
'featured_media',
'title',
'author',
'date',
'comment_status',
],
};
const onChange = ( edits ) => {
for ( const id of ids ) {
if (
edits.status !== 'future' &&
record.status === 'future' &&
record?.status === 'future' &&
new Date( record.date ) > new Date()
) {
edits.date = null;
Expand Down
55 changes: 3 additions & 52 deletions packages/edit-site/src/components/post-fields/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import clsx from 'clsx';
*/
import { __, sprintf } from '@wordpress/i18n';
import { decodeEntities } from '@wordpress/html-entities';
import { featuredImageField } from '@wordpress/fields';
import {
createInterpolateElement,
useMemo,
Expand All @@ -33,11 +34,9 @@ import { useEntityRecords, store as coreStore } from '@wordpress/core-data';
import {
LAYOUT_GRID,
LAYOUT_TABLE,
LAYOUT_LIST,
OPERATOR_IS_ANY,
} from '../../utils/constants';
import { default as Link, useLink } from '../routes/link';
import Media from '../media';
import { default as Link } from '../routes/link';

// See https://github.com/WordPress/gutenberg/issues/55886
// We do not support custom statutes at the moment.
Expand Down Expand Up @@ -81,46 +80,6 @@ const getFormattedDate = ( dateToDisplay ) =>
getDate( dateToDisplay )
);

function FeaturedImage( { item, viewType } ) {
const isDisabled = item.status === 'trash';
const { onClick } = useLink( {
postId: item.id,
postType: item.type,
canvas: 'edit',
} );
const hasMedia = !! item.featured_media;
const size =
viewType === LAYOUT_GRID
? [ 'large', 'full', 'medium', 'thumbnail' ]
: [ 'thumbnail', 'medium', 'large', 'full' ];
const media = hasMedia ? (
<Media
className="edit-site-post-list__featured-image"
id={ item.featured_media }
size={ size }
/>
) : null;
const renderButton = viewType !== LAYOUT_LIST && ! isDisabled;
return (
<div
className={ `edit-site-post-list__featured-image-wrapper is-layout-${ viewType }` }
>
{ renderButton ? (
<button
className="edit-site-post-list__featured-image-button"
type="button"
onClick={ onClick }
aria-label={ item.title?.rendered || __( '(no title)' ) }
>
{ media }
</button>
) : (
media
) }
</div>
);
}

function PostStatusField( { item } ) {
const status = STATUSES.find( ( { value } ) => value === item.status );
const label = status?.label || item.status;
Expand Down Expand Up @@ -190,15 +149,7 @@ function usePostFields( viewType ) {

const fields = useMemo(
() => [
{
id: 'featured-image',
label: __( 'Featured Image' ),
getValue: ( { item } ) => item.featured_media,
render: ( { item } ) => (
<FeaturedImage item={ item } viewType={ viewType } />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two questions:

  1. Was there a reason to change the order here?
  2. What was the reason for inlining the render function instead of keeping the FeaturedImage component?

),
enableSorting: false,
},
featuredImageField,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that we're moving the dataviews fields to the fields package one by one 👍 and fixing them (removing dependencies...)

{
label: __( 'Title' ),
id: 'title',
Expand Down
3 changes: 3 additions & 0 deletions packages/edit-site/src/components/post-fields/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.components-popover.components-dropdown__content.dataforms-layouts-panel__field-dropdown {
z-index: z-index(".components-popover.components-dropdown__content.dataforms-layouts-panel__field-dropdown");
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ export const defaultLayouts = {
layout: {
primaryField: 'title',
styles: {
'featured-image': {
width: '1%',
},
youknowriad marked this conversation as resolved.
Show resolved Hide resolved
title: {
maxWidth: 300,
},
Expand All @@ -42,14 +39,14 @@ export const defaultLayouts = {
},
[ LAYOUT_GRID ]: {
layout: {
mediaField: 'featured-image',
mediaField: 'featured_media',
primaryField: 'title',
},
},
[ LAYOUT_LIST ]: {
layout: {
primaryField: 'title',
mediaField: 'featured-image',
mediaField: 'featured_media',
},
},
};
Expand Down
2 changes: 2 additions & 0 deletions packages/edit-site/src/style.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import "../../dataviews/src/style.scss";
@import "../../fields/src/fields/featured-image/style.scss";

@import "./components/add-new-template/style.scss";
@import "./components/block-editor/style.scss";
Expand Down Expand Up @@ -30,6 +31,7 @@
@import "./components/editor-canvas-container/style.scss";
@import "./components/post-edit/style.scss";
@import "./components/post-list/style.scss";
@import "./components/post-fields/style.scss";
@import "./components/resizable-frame/style.scss";
@import "./hooks/push-changes-to-global-styles/style.scss";
@import "./components/global-styles/font-library-modal/style.scss";
Expand Down
Loading
Loading