Skip to content

Commit

Permalink
Adding attributes block to product block editor. (#38051)
Browse files Browse the repository at this point in the history
  • Loading branch information
joelclimbsthings committed May 3, 2023
1 parent 94599a1 commit 3679f01
Show file tree
Hide file tree
Showing 52 changed files with 308 additions and 226 deletions.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,4 @@
Significance: minor
Type: add

Adding attributes components, block and styles.
3 changes: 2 additions & 1 deletion packages/js/product-editor/package.json
Expand Up @@ -35,7 +35,7 @@
"@woocommerce/components": "workspace:*",
"@woocommerce/currency": "workspace:*",
"@woocommerce/customer-effort-score": "workspace:*",
"@woocommerce/data": "workspace:^4.1.0",
"@woocommerce/data": "workspace:*",
"@woocommerce/experimental": "workspace:*",
"@woocommerce/navigation": "workspace:^8.1.0",
"@woocommerce/number": "workspace:*",
Expand Down Expand Up @@ -89,6 +89,7 @@
"@types/wordpress__keycodes": "^2.3.1",
"@types/wordpress__media-utils": "^3.0.0",
"@types/wordpress__plugins": "^3.0.0",
"@types/wordpress__rich-text": "^3.4.6",
"@woocommerce/eslint-plugin": "workspace:*",
"@woocommerce/internal-js-tests": "workspace:*",
"@woocommerce/internal-style-build": "workspace:*",
Expand Down
26 changes: 26 additions & 0 deletions packages/js/product-editor/src/blocks/attributes/block.json
@@ -0,0 +1,26 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "woocommerce/product-attributes-field",
"title": "Product attributes",
"category": "widgets",
"description": "The product attributes.",
"keywords": [ "products", "attributes" ],
"textdomain": "default",
"attributes": {
"name": {
"type": "string",
"__experimentalRole": "content"
}
},
"supports": {
"align": false,
"html": false,
"multiple": false,
"reusable": false,
"inserter": false,
"lock": false,
"__experimentalToolbar": false
},
"editorStyle": "file:./editor.css"
}
35 changes: 35 additions & 0 deletions packages/js/product-editor/src/blocks/attributes/edit.tsx
@@ -0,0 +1,35 @@
/**
* External dependencies
*/
import { createElement } from '@wordpress/element';
import { ProductAttribute } from '@woocommerce/data';
import { useBlockProps } from '@wordpress/block-editor';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore No types for this exist yet.
// eslint-disable-next-line @woocommerce/dependency-group
import { useEntityProp, useEntityId } from '@wordpress/core-data';

/**
* Internal dependencies
*/
import { Attributes as AttributesContainer } from '../../components/attributes/attributes';

export function Edit() {
const [ entityAttributes, setEntityAttributes ] = useEntityProp<
ProductAttribute[]
>( 'postType', 'product', 'attributes' );

const productId = useEntityId( 'postType', 'product' );

const blockProps = useBlockProps();

return (
<div { ...blockProps }>
<AttributesContainer
productId={ productId }
value={ entityAttributes }
onChange={ setEntityAttributes }
/>
</div>
);
}
21 changes: 21 additions & 0 deletions packages/js/product-editor/src/blocks/attributes/editor.scss
@@ -0,0 +1,21 @@
.wp-block-woocommerce-product-images-field {
.woocommerce-image-gallery {
margin-top: $gap-largest;
}
.woocommerce-media-uploader {
text-align: left;
}
.woocommerce-media-uploader__label {
display: none;
}
.woocommerce-sortable {
margin-top: 0;
padding: 0;
}

&:not(.has-images) {
.woocommerce-sortable {
display: none;
}
}
}
22 changes: 22 additions & 0 deletions packages/js/product-editor/src/blocks/attributes/index.ts
@@ -0,0 +1,22 @@
/**
* Internal dependencies
*/
import { initBlock } from '../../utils';
import metadata from './block.json';
import { Edit } from './edit';

const { name } = metadata;

export { metadata, name };

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

export const init = () =>
initBlock( {
name,
metadata: metadata as never,
settings,
} );
1 change: 1 addition & 0 deletions packages/js/product-editor/src/blocks/index.ts
Expand Up @@ -17,3 +17,4 @@ export { init as initSummary } from './summary';
export { init as initTab } from './tab';
export { init as initInventoryQuantity } from './inventory-quantity';
export { init as initToggle } from './toggle';
export { init as attributesInit } from './attributes';
Expand Up @@ -2,32 +2,32 @@
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import {
useState,
createElement,
Fragment,
createInterpolateElement,
} from '@wordpress/element';
import { Button } from '@wordpress/components';
import { ProductAttribute } from '@woocommerce/data';
import {
Sortable,
__experimentalSelectControlMenuSlot as SelectControlMenuSlot,
Link,
} from '@woocommerce/components';
import interpolateComponents from '@automattic/interpolate-components';
import { getAdminLink } from '@woocommerce/settings';

/**
* Internal dependencies
*/
import './attribute-field.scss';
import { EditAttributeModal } from './edit-attribute-modal';
import { EnhancedProductAttribute } from '~/products/hooks/use-product-attributes';
import { EnhancedProductAttribute } from '../../hooks/use-product-attributes';
import {
getAttributeId,
getAttributeKey,
reorderSortableProductAttributePositions,
} from './utils';
import { AttributeEmptyState } from '../attribute-empty-state';
import {
AttributeListItem,
NewAttributeListItem,
} from '../attribute-list-item';
import { AttributeListItem } from '../attribute-list-item';
import { NewAttributeModal } from './new-attribute-modal';

type AttributeControlProps = {
Expand Down Expand Up @@ -67,9 +67,9 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {
uiStrings = {
newAttributeModalTitle: undefined,
emptyStateSubtitle: undefined,
newAttributeListItemLabel: undefined,
newAttributeListItemLabel: __( 'Add attributes', 'woocommerce' ),
globalAttributeHelperMessage: __(
`You can change the attribute's name in {{link}}Attributes{{/link}}.`,
`You can change the attribute's name in <link>Attributes</link>.`,
'woocommerce'
),
},
Expand Down Expand Up @@ -160,30 +160,6 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {
closeEditModal( updatedAttribute );
};

if ( ! value.length ) {
return (
<>
<AttributeEmptyState
addNewLabel={ uiStrings.newAttributeModalTitle }
onNewClick={ () => openNewModal() }
subtitle={ uiStrings.emptyStateSubtitle }
/>
{ isNewModalVisible && (
<NewAttributeModal
onCancel={ () => {
closeNewModal();
onNewModalCancel();
} }
onAdd={ handleAdd }
selectedAttributeIds={ [] }
title={ uiStrings.newAttributeModalTitle }
/>
) }
<SelectControlMenuSlot />
</>
);
}

const sortedAttributes = value.sort( ( a, b ) => a.position - b.position );

const attributeKeyValues = value.reduce(
Expand All @@ -203,37 +179,44 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {

return (
<div className="woocommerce-attribute-field">
<Sortable
onOrderChange={ ( items ) => {
const itemPositions = items.reduce(
( positions, { props }, index ) => {
positions[ getAttributeKey( props.attribute ) ] =
index;
return positions;
},
{} as Record< number | string, number >
);
onChange(
reorderSortableProductAttributePositions(
itemPositions,
attributeKeyValues
)
);
} }
<Button
variant="secondary"
className="woocommerce-add-attribute-list-item__add-button"
onClick={ openNewModal }
>
{ sortedAttributes.map( ( attr ) => (
<AttributeListItem
attribute={ attr }
key={ getAttributeId( attr ) }
onEditClick={ () => openEditModal( attr ) }
onRemoveClick={ () => handleRemove( attr ) }
/>
) ) }
</Sortable>
<NewAttributeListItem
label={ uiStrings.newAttributeListItemLabel }
onClick={ () => openNewModal() }
/>
{ uiStrings.newAttributeListItemLabel }
</Button>
{ Boolean( value.length ) && (
<Sortable
onOrderChange={ ( items ) => {
const itemPositions = items.reduce(
( positions, { props }, index ) => {
positions[
getAttributeKey( props.attribute )
] = index;
return positions;
},
{} as Record< number | string, number >
);
onChange(
reorderSortableProductAttributePositions(
itemPositions,
attributeKeyValues
)
);
} }
>
{ sortedAttributes.map( ( attr ) => (
<AttributeListItem
attribute={ attr }
key={ getAttributeId( attr ) }
onEditClick={ () => openEditModal( attr ) }
onRemoveClick={ () => handleRemove( attr ) }
/>
) ) }
</Sortable>
) }

{ isNewModalVisible && (
<NewAttributeModal
title={ uiStrings.newAttributeModalTitle }
Expand All @@ -253,9 +236,9 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {
__( 'Edit %s', 'woocommerce' ),
currentAttribute.name
) }
globalAttributeHelperMessage={ interpolateComponents( {
mixedString: uiStrings.globalAttributeHelperMessage,
components: {
globalAttributeHelperMessage={ createInterpolateElement(
uiStrings.globalAttributeHelperMessage,
{
link: (
<Link
href={ getAdminLink(
Expand All @@ -267,8 +250,8 @@ export const AttributeControl: React.FC< AttributeControlProps > = ( {
<></>
</Link>
),
},
} ) }
}
) }
onCancel={ () => {
closeEditModal( currentAttribute );
onEditModalCancel( currentAttribute );
Expand Down
@@ -1,5 +1,6 @@
.woocommerce-attribute-field {
width: 100%;
font-size: 13px;

.woocommerce-sortable {
margin: 0;
Expand All @@ -12,4 +13,23 @@
background: none;
border-top: 0;
}

.woocommerce-add-attribute-list-item__add-button {
margin-bottom: $gap;
}

}

.wp-block-woocommerce-product-attributes-field {

.woocommerce-sortable {
padding: 0;
}

.woocommerce-list-item {
background: none;
border: none;
border-bottom: 1px solid $gray-200;
padding-left: 0;
}
}
Expand Up @@ -8,7 +8,7 @@ import {
CheckboxControl,
TextControl,
} from '@wordpress/components';
import { useState } from '@wordpress/element';
import { useState, createElement } from '@wordpress/element';
import { __experimentalTooltip as Tooltip } from '@woocommerce/components';

/**
Expand All @@ -20,8 +20,6 @@ import {
} from '../attribute-term-input-field';
import { EnhancedProductAttribute } from '../../hooks/use-product-attributes';

import './edit-attribute-modal.scss';

type EditAttributeModalProps = {
title?: string;
nameLabel?: string;
Expand Down
Expand Up @@ -2,7 +2,7 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import { useState, createElement, Fragment } from '@wordpress/element';
import { trash } from '@wordpress/icons';
import {
Form,
Expand All @@ -20,13 +20,12 @@ import {
/**
* Internal dependencies
*/
import './new-attribute-modal.scss';
import { AttributeInputField } from '../attribute-input-field';
import {
AttributeTermInputField,
CustomAttributeTermInputField,
} from '../attribute-term-input-field';
import { EnhancedProductAttribute } from '~/products/hooks/use-product-attributes';
import { EnhancedProductAttribute } from '../../hooks/use-product-attributes';
import { getProductAttributeObject } from './utils';

type NewAttributeModalProps = {
Expand Down

0 comments on commit 3679f01

Please sign in to comment.