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

List Custom Fields for New Product Editor #45360

Merged
merged 16 commits into from Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/js/product-editor/changelog/add-44169-list
@@ -0,0 +1,4 @@
Significance: minor
Type: add

Create woocommerce/product-custom-fields block
1 change: 1 addition & 0 deletions packages/js/product-editor/src/blocks/index.ts
@@ -1,4 +1,5 @@
export { init as initCatalogVisibility } from './product-fields/catalog-visibility';
export { init as initCustomFields } from './product-fields/custom-fields';
export { init as initCustomFieldsToogle } from './product-fields/custom-fields-toggle';
export { init as initCheckbox } from './generic/checkbox';
export { init as initCollapsible } from './generic/collapsible';
Expand Down
Expand Up @@ -22,6 +22,5 @@
"lock": false,
"__experimentalToolbar": false
},
"usesContext": [ "postType" ],
"editorStyle": "file:./editor.css"
}
@@ -1,10 +1,14 @@
/**
* External dependencies
*/
import { Spinner, ToggleControl } from '@wordpress/components';
import { createElement } from '@wordpress/element';
import { useWooBlockProps } from '@woocommerce/block-templates';
import { recordEvent } from '@woocommerce/tracks';
import { Spinner, ToggleControl } from '@wordpress/components';
import { createElement, useMemo } from '@wordpress/element';
import {
// @ts-expect-error no exported member.
useInnerBlocksProps,
} from '@wordpress/block-editor';

/**
* Internal dependencies
Expand All @@ -21,17 +25,25 @@ export function Edit( {
}: ProductEditorBlockEditProps< CustomFieldsToggleBlockAttributes > ) {
const { label, _templateBlockId } = attributes;
const blockProps = useWooBlockProps( attributes );
const innerBlockProps = useInnerBlocksProps(
{
className:
'wp-block-woocommerce-product-custom-fields-toggle-field__inner-blocks',
},
{ templateLock: 'all' }
);

const { isLoading, metaboxhiddenProduct, saveMetaboxhiddenProduct } =
useMetaboxHiddenProduct();

function isChecked() {
const isChecked = useMemo( () => {
return (
metaboxhiddenProduct &&
! metaboxhiddenProduct.some(
( value ) => value === METABOX_HIDDEN_VALUE
)
);
}
}, [ metaboxhiddenProduct ] );

async function handleChange( checked: boolean ) {
const values = checked
Expand All @@ -51,14 +63,18 @@ export function Edit( {

return (
<div { ...blockProps }>
<ToggleControl
label={ label }
checked={ isChecked() }
disabled={ isLoading }
onChange={ handleChange }
/>
<div className="wp-block-woocommerce-product-custom-fields-toggle-field__content">
<ToggleControl
label={ label }
checked={ isChecked }
disabled={ isLoading }
onChange={ handleChange }
/>

{ isLoading && <Spinner /> }
</div>

{ isLoading && <Spinner /> }
{ isChecked && <div { ...innerBlockProps } /> }
</div>
);
}
@@ -1,9 +1,15 @@
.wp-block-woocommerce-product-custom-fields-toggle-field {
display: flex;
gap: $grid-unit;
align-items: center;
&__content {
display: flex;
gap: $grid-unit;
align-items: center;

.components-spinner {
margin: 0;
.components-spinner {
margin: 0;
}
}

&__inner-blocks {
margin-top: $grid-unit-60;
}
}
@@ -0,0 +1,27 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "woocommerce/product-custom-fields",
"title": "Product custom fields control",
"category": "woocommerce",
"description": "The product custom fields.",
"keywords": [ "products", "custom", "fields" ],
"textdomain": "default",
"attributes": {
"name": {
"type": "string",
"__experimentalRole": "content"
}
},
"supports": {
"align": false,
"html": false,
"multiple": true,
"reusable": true,
"inserter": false,
"lock": false,
"__experimentalToolbar": false
},
"usesContext": [ "postType" ],
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that we can remove this.

"editorStyle": "file:./editor.css"
}
@@ -0,0 +1,24 @@
/**
* External dependencies
*/
import { createElement } from '@wordpress/element';
import { useWooBlockProps } from '@woocommerce/block-templates';

/**
* Internal dependencies
*/
import { CustomFields } from '../../../components/custom-fields';
import { ProductEditorBlockEditProps } from '../../../types';
import { CustomFieldsBlockAttributes } from './types';

export function Edit( {
attributes,
}: ProductEditorBlockEditProps< CustomFieldsBlockAttributes > ) {
const blockProps = useWooBlockProps( attributes );

return (
<div { ...blockProps }>
<CustomFields />
</div>
);
}
@@ -0,0 +1,2 @@
.wp-block-woocommerce-product-custom-fields-field {
}
@@ -0,0 +1,23 @@
/**
* Internal dependencies
*/
import blockConfiguration from './block.json';
import { Edit } from './edit';
import { registerProductEditorBlockType } from '../../../utils';

const { name, ...metadata } = blockConfiguration;

export { metadata, name };

export const settings = {
example: {},
edit: Edit,
};

export function init() {
return registerProductEditorBlockType( {
name,
metadata: metadata as never,
settings: settings as never,
} );
}
@@ -0,0 +1,8 @@
/**
* External dependencies
*/
import { BlockAttributes } from '@wordpress/blocks';

export interface CustomFieldsBlockAttributes extends BlockAttributes {
label: string;
}
1 change: 1 addition & 0 deletions packages/js/product-editor/src/blocks/style.scss
@@ -1,6 +1,7 @@
@import "product-fields/attributes/editor.scss";
@import "product-fields/description/editor.scss";
@import "product-fields/catalog-visibility/editor.scss";
@import "product-fields/custom-fields/editor.scss";
@import "product-fields/custom-fields-toggle/editor.scss";
@import "product-fields/downloads/editor.scss";
@import "product-fields/images/editor.scss";
Expand Down
@@ -0,0 +1,55 @@
/**
* External dependencies
*/
import { createElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import classNames from 'classnames';

/**
* Internal dependencies
*/
import { useCustomFields } from '../../hooks/use-custom-fields';
import { EmptyState } from './empty-state';
import type { CustomFieldsProps } from './types';

export function CustomFields( { className, ...props }: CustomFieldsProps ) {
const { customFields } = useCustomFields();

if ( customFields.length === 0 ) {
return <EmptyState />;
}

return (
<table
{ ...props }
className={ classNames(
'woocommerce-product-custom-fields__table',
className
) }
>
<thead>
<tr className="woocommerce-product-custom-fields__table-row">
<th>{ __( 'Name', 'woocommerce' ) }</th>
<th>{ __( 'Value', 'woocommerce' ) }</th>
<th>{ __( 'Actions', 'woocommerce' ) }</th>
</tr>
</thead>
<tbody>
{ customFields.map( ( customField ) => (
<tr
className="woocommerce-product-custom-fields__table-row"
key={ customField.id ?? customField.key }
>
<td className="woocommerce-product-custom-fields__table-datacell">
{ customField.key }
</td>
<td className="woocommerce-product-custom-fields__table-datacell">
{ customField.value }
</td>
<td className="woocommerce-product-custom-fields__table-datacell"></td>
</tr>
) ) }
</tbody>
</table>
);
}
@@ -0,0 +1,54 @@
/**
* External dependencies
*/
import { createElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/

export function EmptyState(
props: React.DetailedHTMLProps<
React.HTMLAttributes< HTMLDivElement >,
HTMLDivElement
>
) {
return (
<div
{ ...props }
role="none"
className="woocommerce-product-custom-fields__empty-state"
>
<div className="woocommerce-product-custom-fields__empty-state-row">
<div>{ __( 'Custom field 1', 'woocommerce' ) }</div>
<div>
<div className="woocommerce-product-custom-fields__empty-state-name" />
</div>
<div>
<div className="woocommerce-product-custom-fields__empty-state-actions" />
</div>
</div>

<div className="woocommerce-product-custom-fields__empty-state-row">
<div>{ __( 'Custom field 2', 'woocommerce' ) }</div>
<div>
<div className="woocommerce-product-custom-fields__empty-state-name" />
</div>
<div>
<div className="woocommerce-product-custom-fields__empty-state-actions" />
</div>
</div>

<div className="woocommerce-product-custom-fields__empty-state-row">
<div>{ __( 'Custom field 3', 'woocommerce' ) }</div>
<div>
<div className="woocommerce-product-custom-fields__empty-state-name" />
</div>
<div>
<div className="woocommerce-product-custom-fields__empty-state-actions" />
</div>
</div>
</div>
);
}
@@ -0,0 +1 @@
export * from './empty-state';
@@ -0,0 +1,58 @@
.woocommerce-product-custom-fields__empty-state {
@mixin skeleton {
background-color: $gray-200;
border-radius: $grid-unit-05;
width: $grid-unit-30;
height: $grid-unit;
}

border: 1px dashed $gray-400;
padding: 0 $grid-unit-30;
border-radius: 2px;

&-row {
display: grid;
grid-template-columns: 1.5fr 1fr 0.5fr;
height: $grid-unit-80;
align-items: center;
border-top: 1px solid $gray-100;

&:first-child {
border-top: none;

.woocommerce-product-custom-fields__empty-state-name {
width: 140px;
}
}

&:nth-child(2) {
opacity: 0.7;

.woocommerce-product-custom-fields__empty-state-name {
width: 75px;
}
}

&:nth-child(3) {
opacity: 0.5;

.woocommerce-product-custom-fields__empty-state-name {
width: 114px;
}
}

:last-child {
display: flex;
justify-content: flex-end;
}
}

&-name {
@include skeleton();
}

&-actions {
@include skeleton();
width: $grid-unit-60;
}
}
@@ -0,0 +1,2 @@
export * from './custom-fields';
export * from './types';