diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/attributes.js b/assets/js/atomic/blocks/product-elements/add-to-cart/attributes.ts
similarity index 100%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/attributes.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/attributes.ts
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/block.js b/assets/js/atomic/blocks/product-elements/add-to-cart/block.tsx
similarity index 85%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/block.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/block.tsx
index 7baba132098..50190e77eb9 100644
--- a/assets/js/atomic/blocks/product-elements/add-to-cart/block.js
+++ b/assets/js/atomic/blocks/product-elements/add-to-cart/block.tsx
@@ -23,36 +23,16 @@ import {
GroupedProductForm,
} from './product-types';
-/**
- * Product Add to Form Block Component.
- *
- * @param {Object} props Incoming props.
- * @param {string} [props.className] CSS Class name for the component.
- * @param {boolean} [props.showFormElements] Should form elements be shown?
- * @return {*} The component.
- */
-const Block = ( { className, showFormElements } ) => {
- const { product } = useProductDataContext();
- const componentClass = classnames(
- className,
- 'wc-block-components-product-add-to-cart',
- {
- 'wc-block-components-product-add-to-cart--placeholder':
- isEmpty( product ),
- }
- );
-
- return (
-
-
-
- );
-};
+interface Props {
+ /**
+ * CSS Class name for the component.
+ */
+ className?: string;
+ /**
+ * Whether or not to show form elements.
+ */
+ showFormElements?: boolean;
+}
/**
* Renders the add to cart form using useAddToCartFormContext.
@@ -79,6 +59,32 @@ const AddToCartForm = () => {
return ;
};
+/**
+ * Product Add to Form Block Component.
+ */
+const Block = ( { className, showFormElements }: Props ) => {
+ const { product } = useProductDataContext();
+ const componentClass = classnames(
+ className,
+ 'wc-block-components-product-add-to-cart',
+ {
+ 'wc-block-components-product-add-to-cart--placeholder':
+ isEmpty( product ),
+ }
+ );
+
+ return (
+
+
+
+ );
+};
+
Block.propTypes = {
className: PropTypes.string,
};
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/constants.js b/assets/js/atomic/blocks/product-elements/add-to-cart/constants.tsx
similarity index 100%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/constants.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/constants.tsx
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/frontend.js b/assets/js/atomic/blocks/product-elements/add-to-cart/frontend.ts
similarity index 100%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/frontend.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/frontend.ts
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/index.js b/assets/js/atomic/blocks/product-elements/add-to-cart/index.ts
similarity index 100%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/index.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/index.ts
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/external.js b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/external.tsx
similarity index 100%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/product-types/external.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/product-types/external.tsx
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/grouped/group-list/index.js b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/grouped/group-list/index.tsx
similarity index 100%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/product-types/grouped/group-list/index.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/product-types/grouped/group-list/index.tsx
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/grouped/index.js b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/grouped/index.tsx
similarity index 100%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/product-types/grouped/index.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/product-types/grouped/index.tsx
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/index.js b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/index.ts
similarity index 100%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/product-types/index.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/product-types/index.ts
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/simple.js b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/simple.tsx
similarity index 95%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/product-types/simple.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/product-types/simple.tsx
index ce3670bcd36..8dc707ef27d 100644
--- a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/simple.js
+++ b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/simple.tsx
@@ -13,6 +13,7 @@ import { AddToCartButton, QuantityInput, ProductUnavailable } from '../shared';
* Simple Product Add To Cart Form
*/
const Simple = () => {
+ // @todo Add types for `useAddToCartFormContext`
const {
product,
quantity,
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/index.js b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/index.tsx
similarity index 96%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/index.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/index.tsx
index 4cc5e9e16fd..8aeb00f67ac 100644
--- a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/index.js
+++ b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/index.tsx
@@ -18,6 +18,7 @@ import VariationAttributes from './variation-attributes';
* Variable Product Add To Cart Form
*/
const Variable = () => {
+ // @todo Add types for `useAddToCartFormContext`
const {
product,
quantity,
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/types.ts b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/types.ts
new file mode 100644
index 00000000000..0704b3ca06d
--- /dev/null
+++ b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/types.ts
@@ -0,0 +1,17 @@
+/**
+ * External dependencies
+ */
+import { Dictionary } from '@woocommerce/types';
+
+export type AttributesMap = Record<
+ string,
+ { id: number; attributes: Dictionary }
+>;
+
+export interface VariationParam {
+ id: number;
+ variation: {
+ attribute: string;
+ value: string;
+ }[];
+}
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/attribute-picker.js b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/attribute-picker.tsx
similarity index 83%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/attribute-picker.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/attribute-picker.tsx
index 6482dde7e43..0a0a48a629e 100644
--- a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/attribute-picker.js
+++ b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/attribute-picker.tsx
@@ -3,6 +3,8 @@
*/
import { useState, useEffect, useMemo } from '@wordpress/element';
import { useShallowEqual } from '@woocommerce/base-hooks';
+import type { SelectControl } from '@wordpress/components';
+import { Dictionary, ProductResponseAttributeItem } from '@woocommerce/types';
/**
* Internal dependencies
@@ -13,21 +15,27 @@ import {
getActiveSelectControlOptions,
getDefaultAttributes,
} from './utils';
+import { AttributesMap, VariationParam } from '../types';
+
+interface Props {
+ attributes: Record< string, ProductResponseAttributeItem >;
+ setRequestParams: ( param: VariationParam ) => void;
+ variationAttributes: AttributesMap;
+}
/**
* AttributePicker component.
- *
- * @param {*} props Component props.
*/
const AttributePicker = ( {
attributes,
variationAttributes,
setRequestParams,
-} ) => {
+}: Props ) => {
const currentAttributes = useShallowEqual( attributes );
const currentVariationAttributes = useShallowEqual( variationAttributes );
const [ variationId, setVariationId ] = useState( 0 );
- const [ selectedAttributes, setSelectedAttributes ] = useState( {} );
+ const [ selectedAttributes, setSelectedAttributes ] =
+ useState< Dictionary >( {} );
const [ hasSetDefaults, setHasSetDefaults ] = useState( false );
// Get options for each attribute picker.
@@ -99,7 +107,11 @@ const AttributePicker = ( {
{
setSelectedAttributes( {
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/attribute-select-control.js b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/attribute-select-control.tsx
similarity index 90%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/attribute-select-control.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/attribute-select-control.tsx
index 5bbf0fb89e7..52d419bae36 100644
--- a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/attribute-select-control.js
+++ b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/attribute-select-control.tsx
@@ -4,12 +4,18 @@
import { __ } from '@wordpress/i18n';
import { decodeEntities } from '@wordpress/html-entities';
import { SelectControl } from 'wordpress-components';
+import type { SelectControl as SelectControlType } from '@wordpress/components';
import { useEffect } from 'react';
import classnames from 'classnames';
import { ValidationInputError } from '@woocommerce/blocks-checkout';
import { VALIDATION_STORE_KEY } from '@woocommerce/block-data';
import { useDispatch, useSelect } from '@wordpress/data';
+interface Props extends SelectControlType.Props< string > {
+ attributeName: string;
+ errorMessage?: string;
+}
+
// Default option for select boxes.
const selectAnOption = {
value: '',
@@ -18,19 +24,17 @@ const selectAnOption = {
/**
* VariationAttributeSelect component.
- *
- * @param {*} props Component props.
*/
const AttributeSelectControl = ( {
attributeName,
options = [],
value = '',
- onChange = () => {},
+ onChange = () => void 0,
errorMessage = __(
'Please select a value.',
'woo-gutenberg-products-block'
),
-} ) => {
+}: Props ) => {
const errorId = attributeName;
const { setValidationErrors, clearValidationError } =
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/index.js b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/index.tsx
similarity index 66%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/index.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/index.tsx
index 18e0b5eb4df..a83497dacc2 100644
--- a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/index.js
+++ b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/index.tsx
@@ -1,3 +1,8 @@
+/**
+ * External dependencies
+ */
+import { ProductResponseItem } from '@woocommerce/types';
+
/**
* Internal dependencies
*/
@@ -5,19 +10,20 @@ import './style.scss';
import AttributePicker from './attribute-picker';
import { getAttributes, getVariationAttributes } from './utils';
+interface Props {
+ dispatchers: { setRequestParams: () => void };
+ product: ProductResponseItem;
+}
+
/**
* VariationAttributes component.
- *
- * @param {Object} props Incoming props
- * @param {Object} props.product Product
- * @param {Object} props.dispatchers An object where values are dispatching functions.
*/
-const VariationAttributes = ( { product, dispatchers } ) => {
+const VariationAttributes = ( { dispatchers, product }: Props ) => {
const attributes = getAttributes( product.attributes );
const variationAttributes = getVariationAttributes( product.variations );
if (
Object.keys( attributes ).length === 0 ||
- variationAttributes.length === 0
+ Object.keys( variationAttributes ).length === 0
) {
return null;
}
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/test/index.js b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/test/index.ts
similarity index 95%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/test/index.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/test/index.ts
index cfc4490dbc8..d859338da97 100644
--- a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/test/index.js
+++ b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/test/index.ts
@@ -1,3 +1,8 @@
+/**
+ * External dependencies
+ */
+import { ProductResponseAttributeItem } from '@woocommerce/types';
+
/**
* Internal dependencies
*/
@@ -10,7 +15,7 @@ import {
getDefaultAttributes,
} from '../utils';
-const rawAttributeData = [
+const rawAttributeData: ProductResponseAttributeItem[] = [
{
id: 1,
name: 'Color',
@@ -40,7 +45,7 @@ const rawAttributeData = [
{
id: 0,
name: 'Logo',
- taxonomy: null,
+ taxonomy: 'pa_logo',
has_variations: true,
terms: [
{
@@ -60,7 +65,7 @@ const rawAttributeData = [
{
id: 0,
name: 'Non-variable attribute',
- taxonomy: null,
+ taxonomy: 'pa_non-variable-attribute',
has_variations: false,
terms: [
{
@@ -227,7 +232,7 @@ describe( 'Testing utils', () => {
Logo: {
id: 0,
name: 'Logo',
- taxonomy: null,
+ taxonomy: 'pa_logo',
has_variations: true,
terms: [
{
@@ -471,8 +476,11 @@ describe( 'Testing utils', () => {
} );
it( 'should return an empty object if given unexpected values', () => {
+ // @ts-expect-error Expected TS Error as we are checking how the function does with *unexpected values*.
expect( getDefaultAttributes( [] ) ).toStrictEqual( {} );
+ // @ts-expect-error Ditto above.
expect( getDefaultAttributes( null ) ).toStrictEqual( {} );
+ // @ts-expect-error Ditto above.
expect( getDefaultAttributes( undefined ) ).toStrictEqual( {} );
} );
} );
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/utils.js b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/utils.ts
similarity index 62%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/utils.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/utils.ts
index 6914d664612..15b452ff594 100644
--- a/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/utils.js
+++ b/assets/js/atomic/blocks/product-elements/add-to-cart/product-types/variable/variation-attributes/utils.ts
@@ -3,14 +3,25 @@
*/
import { keyBy } from 'lodash';
import { decodeEntities } from '@wordpress/html-entities';
-import { isObject } from '@woocommerce/types';
+import {
+ Dictionary,
+ isObject,
+ ProductResponseAttributeItem,
+ ProductResponseTermItem,
+ ProductResponseVariationsItem,
+} from '@woocommerce/types';
+
+/**
+ * Internal dependencies
+ */
+import { AttributesMap } from '../types';
/**
* Key an array of attributes by name,
- *
- * @param {Object} attributes Attributes array.
*/
-export const getAttributes = ( attributes ) => {
+export const getAttributes = (
+ attributes?: ProductResponseAttributeItem[] | null
+) => {
return attributes
? keyBy(
Object.values( attributes ).filter(
@@ -26,15 +37,18 @@ export const getAttributes = ( attributes ) => {
*
* Note, each item is keyed by the variation ID with an id: prefix. This is to prevent the object
* being reordered when iterated.
- *
- * @param {Object} variations List of Variation objects and attributes keyed by variation ID.
*/
-export const getVariationAttributes = ( variations ) => {
+export const getVariationAttributes = (
+ /**
+ * List of Variation objects and attributes keyed by variation ID.
+ */
+ variations?: ProductResponseVariationsItem[] | null
+) => {
if ( ! variations ) {
return {};
}
- const attributesMap = {};
+ const attributesMap: AttributesMap = {};
variations.forEach( ( { id, attributes } ) => {
attributesMap[ `id:${ id }` ] = {
@@ -42,7 +56,7 @@ export const getVariationAttributes = ( variations ) => {
attributes: attributes.reduce( ( acc, { name, value } ) => {
acc[ name ] = value;
return acc;
- }, {} ),
+ }, {} as Dictionary ),
};
} );
@@ -55,20 +69,28 @@ export const getVariationAttributes = ( variations ) => {
* Allows an attribute to be excluded by name. This is used to filter displayed options for
* individual attribute selects.
*
- * @param {Object} attributes List of attribute names and terms.
- * @param {Object} variationAttributes Attributes for each variation keyed by variation ID.
- * @param {Object} selectedAttributes Attribute Name Value pairs of current selections by the user.
- * @return {Array} List of matching variation IDs.
+ * @return List of matching variation IDs.
*/
export const getVariationsMatchingSelectedAttributes = (
- attributes,
- variationAttributes,
- selectedAttributes
+ /**
+ * List of attribute names and terms.
+ *
+ * As returned from {@link getAttributes()}.
+ */
+ attributes: Record< string, ProductResponseAttributeItem >,
+ /**
+ * Attributes for each variation keyed by variation ID.
+ *
+ * As returned from {@link getVariationAttributes()}.
+ */
+ variationAttributes: AttributesMap,
+ /**
+ * Attribute Name Value pairs of current selections by the user.
+ */
+ selectedAttributes: Record< string, string | null >
) => {
const variationIds = Object.values( variationAttributes ).map(
- ( { id: variationId } ) => {
- return variationId;
- }
+ ( { id } ) => id
);
// If nothing is selected yet, just return all variations.
@@ -105,15 +127,25 @@ export const getVariationsMatchingSelectedAttributes = (
/**
* Given a list of variations and a list of attribute values, returns the first matched variation ID.
*
- * @param {Object} attributes List of attribute names and terms.
- * @param {Object} variationAttributes Attributes for each variation keyed by variation ID.
- * @param {Object} selectedAttributes Attribute Name Value pairs of current selections by the user.
- * @return {number} Variation ID.
+ * @return Variation ID.
*/
export const getVariationMatchingSelectedAttributes = (
- attributes,
- variationAttributes,
- selectedAttributes
+ /**
+ * List of attribute names and terms.
+ *
+ * As returned from {@link getAttributes()}.
+ */
+ attributes: Record< string, ProductResponseAttributeItem >,
+ /**
+ * Attributes for each variation keyed by variation ID.
+ *
+ * As returned from {@link getVariationAttributes()}.
+ */
+ variationAttributes: AttributesMap,
+ /**
+ * Attribute Name Value pairs of current selections by the user.
+ */
+ selectedAttributes: Dictionary
) => {
const matchingVariationIds = getVariationsMatchingSelectedAttributes(
attributes,
@@ -127,13 +159,18 @@ export const getVariationMatchingSelectedAttributes = (
* Given a list of terms, filter them and return valid options for the select boxes.
*
* @see getActiveSelectControlOptions
- * @param {Object} attributeTerms List of attribute term objects.
- * @param {?Array} validAttributeTerms Valid values if selections have been made already.
- * @return {Array} Value/Label pairs of select box options.
+ *
+ * @return Value/Label pairs of select box options.
*/
const getValidSelectControlOptions = (
- attributeTerms,
- validAttributeTerms = null
+ /**
+ * List of attribute term objects.
+ */
+ attributeTerms: ProductResponseTermItem[],
+ /**
+ * Valid values if selections have been made already.
+ */
+ validAttributeTerms: Array< string | null > | null = null
) => {
return Object.values( attributeTerms )
.map( ( { name, slug } ) => {
@@ -156,17 +193,30 @@ const getValidSelectControlOptions = (
* Given a list of terms, filter them and return active options for the select boxes. This factors in
* which options should be hidden due to current selections.
*
- * @param {Object} attributes List of attribute names and terms.
- * @param {Object} variationAttributes Attributes for each variation keyed by variation ID.
- * @param {Object} selectedAttributes Attribute Name Value pairs of current selections by the user.
- * @return {Object} Select box options.
+ * @return Select box options.
*/
export const getActiveSelectControlOptions = (
- attributes,
- variationAttributes,
- selectedAttributes
+ /**
+ * List of attribute names and terms.
+ *
+ * As returned from {@link getAttributes()}.
+ */
+ attributes: Record< string, ProductResponseAttributeItem >,
+ /**
+ * Attributes for each variation keyed by variation ID.
+ *
+ * As returned from {@link getVariationAttributes()}.
+ */
+ variationAttributes: AttributesMap,
+ /**
+ * Attribute Name Value pairs of current selections by the user.
+ */
+ selectedAttributes: Dictionary
) => {
- const options = {};
+ const options: Record<
+ string,
+ Array< { label: string; value: string } | null >
+ > = {};
const attributeNames = Object.keys( attributes );
const hasSelectedAttributes =
Object.values( selectedAttributes ).filter( Boolean ).length > 0;
@@ -211,30 +261,35 @@ export const getActiveSelectControlOptions = (
/**
* Return the default values of the given attributes in a format ready to be set in state.
*
- * @param {Object} attributes List of attribute names and terms.
- * @return {Object} Default attributes.
+ * @return Default attributes.
*/
-export const getDefaultAttributes = ( attributes = {} ) => {
+export const getDefaultAttributes = (
+ /**
+ * List of attribute names and terms.
+ *
+ * As returned from {@link getAttributes()}.
+ */
+ attributes: Record< string, ProductResponseAttributeItem >
+) => {
if ( ! isObject( attributes ) ) {
return {};
}
const attributeNames = Object.keys( attributes );
- const defaultsToSet = {};
if ( attributeNames.length === 0 ) {
- return defaultsToSet;
+ return {};
}
- attributeNames.forEach( ( attributeName ) => {
- const currentAttribute = attributes[ attributeName ];
- const defaultValue = currentAttribute.terms.filter(
- ( term ) => term.default
- );
- if ( defaultValue.length > 0 ) {
- defaultsToSet[ currentAttribute.name ] = defaultValue[ 0 ]?.slug;
+ const attributesEntries = Object.values( attributes );
+
+ return attributesEntries.reduce( ( acc, curr ) => {
+ const defaultValues = curr.terms.filter( ( term ) => term.default );
+
+ if ( defaultValues.length > 0 ) {
+ acc[ curr.name ] = defaultValues[ 0 ]?.slug;
}
- } );
- return defaultsToSet;
+ return acc;
+ }, {} as Dictionary );
};
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/shared/add-to-cart-button.js b/assets/js/atomic/blocks/product-elements/add-to-cart/shared/add-to-cart-button.tsx
similarity index 77%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/shared/add-to-cart-button.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/shared/add-to-cart-button.tsx
index 27c4aa24aea..d36e7da5f2d 100644
--- a/assets/js/atomic/blocks/product-elements/add-to-cart/shared/add-to-cart-button.js
+++ b/assets/js/atomic/blocks/product-elements/add-to-cart/shared/add-to-cart-button.tsx
@@ -2,7 +2,7 @@
* External dependencies
*/
import { __, _n, sprintf } from '@wordpress/i18n';
-import Button from '@woocommerce/base-components/button';
+import Button, { ButtonProps } from '@woocommerce/base-components/button';
import { Icon, check } from '@wordpress/icons';
import { useState, useEffect } from '@wordpress/element';
import { useAddToCartFormContext } from '@woocommerce/base-context';
@@ -12,10 +12,84 @@ import {
} from '@woocommerce/base-context/hooks';
import { useInnerBlockLayoutContext } from '@woocommerce/shared-context';
+type LinkProps = Pick< ButtonProps, 'className' | 'href' | 'onClick' | 'text' >;
+
+interface ButtonComponentProps
+ extends Pick< ButtonProps, 'className' | 'onClick' > {
+ /**
+ * Whether the button is disabled or not.
+ */
+ isDisabled: boolean;
+ /**
+ * Whether processing is done.
+ */
+ isDone: boolean;
+ /**
+ * Whether processing action is occurring.
+ */
+ isProcessing: ButtonProps[ 'showSpinner' ];
+ /**
+ * Quantity of said item currently in the cart.
+ */
+ quantityInCart: number;
+}
+
+/**
+ * Button component for non-purchasable products.
+ */
+const LinkComponent = ( { className, href, text, onClick }: LinkProps ) => {
+ return (
+
+ );
+};
+
+/**
+ * Button for purchasable products.
+ */
+const ButtonComponent = ( {
+ className,
+ quantityInCart,
+ isProcessing,
+ isDisabled,
+ isDone,
+ onClick,
+}: ButtonComponentProps ) => {
+ return (
+
+ );
+};
+
/**
* Add to Cart Form Button Component.
*/
const AddToCartButton = () => {
+ // @todo Add types for `useAddToCartFormContext`
const {
showFormElements,
productIsPurchasable,
@@ -104,69 +178,4 @@ const AddToCartButton = () => {
);
};
-/**
- * Button component for non-purchasable products.
- *
- * @param {Object} props Incoming props.
- * @param {string} props.className Css classnames.
- * @param {string} props.href Link for button.
- * @param {string} props.text Text content for button.
- * @param {function():any} props.onClick Callback to execute when button is clicked.
- */
-const LinkComponent = ( { className, href, text, onClick } ) => {
- return (
-
- );
-};
-
-/**
- * Button for purchasable products.
- *
- * @param {Object} props Incoming props for component
- * @param {string} props.className Incoming css class name.
- * @param {number} props.quantityInCart Quantity of item in cart.
- * @param {boolean} props.isProcessing Whether processing action is occurring.
- * @param {boolean} props.isDisabled Whether the button is disabled or not.
- * @param {boolean} props.isDone Whether processing is done.
- * @param {function():any} props.onClick Callback to execute when button is clicked.
- */
-const ButtonComponent = ( {
- className,
- quantityInCart,
- isProcessing,
- isDisabled,
- isDone,
- onClick,
-} ) => {
- return (
-
- );
-};
-
export default AddToCartButton;
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/shared/index.js b/assets/js/atomic/blocks/product-elements/add-to-cart/shared/index.ts
similarity index 100%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/shared/index.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/shared/index.ts
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/shared/product-unavailable.js b/assets/js/atomic/blocks/product-elements/add-to-cart/shared/product-unavailable.tsx
similarity index 100%
rename from assets/js/atomic/blocks/product-elements/add-to-cart/shared/product-unavailable.js
rename to assets/js/atomic/blocks/product-elements/add-to-cart/shared/product-unavailable.tsx
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/shared/quantity-input.js b/assets/js/atomic/blocks/product-elements/add-to-cart/shared/quantity-input.js
deleted file mode 100644
index c846567ea54..00000000000
--- a/assets/js/atomic/blocks/product-elements/add-to-cart/shared/quantity-input.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * External dependencies
- */
-import { useDebouncedCallback } from 'use-debounce';
-
-/**
- * Quantity Input Component.
- *
- * @param {Object} props Incoming props for component
- * @param {boolean} props.disabled Whether input is disabled or not.
- * @param {number} props.min Minimum value for input.
- * @param {number} props.max Maximum value for input.
- * @param {number} props.step Step attribute for input.
- * @param {number} props.value Value for input.
- * @param {function():any} props.onChange Function to call on input change event.
- */
-const QuantityInput = ( { disabled, min, max, step = 1, value, onChange } ) => {
- const hasMaximum = typeof max !== 'undefined';
-
- /**
- * The goal of this function is to normalize what was inserted,
- * but after the customer has stopped typing.
- *
- * It's important to wait before normalizing or we end up with
- * a frustrating experience, for example, if the minimum is 2 and
- * the customer is trying to type "10", premature normalizing would
- * always kick in at "1" and turn that into 2.
- *
- * Copied from
- */
- const normalizeQuantity = useDebouncedCallback( ( initialValue ) => {
- // We copy the starting value.
- let newValue = initialValue;
-
- // We check if we have a maximum value, and select the lowest between what was inserted and the maximum.
- if ( hasMaximum ) {
- newValue = Math.min(
- newValue,
- // the maximum possible value in step increments.
- Math.floor( max / step ) * step
- );
- }
-
- // Select the biggest between what's inserted, the the minimum value in steps.
- newValue = Math.max( newValue, Math.ceil( min / step ) * step );
-
- // We round off the value to our steps.
- newValue = Math.floor( newValue / step ) * step;
-
- // Only commit if the value has changed
- if ( newValue !== initialValue ) {
- onChange( newValue );
- }
- }, 300 );
-
- return (
- {
- onChange( e.target.value );
- normalizeQuantity( e.target.value );
- } }
- />
- );
-};
-
-export default QuantityInput;
diff --git a/assets/js/atomic/blocks/product-elements/add-to-cart/shared/quantity-input.tsx b/assets/js/atomic/blocks/product-elements/add-to-cart/shared/quantity-input.tsx
new file mode 100644
index 00000000000..a9c1e257ec4
--- /dev/null
+++ b/assets/js/atomic/blocks/product-elements/add-to-cart/shared/quantity-input.tsx
@@ -0,0 +1,85 @@
+/**
+ * External dependencies
+ */
+import { useDebouncedCallback } from 'use-debounce';
+
+type JSXInputProps = JSX.IntrinsicElements[ 'input' ];
+
+interface QuantityInputProps extends Omit< JSXInputProps, 'onChange' > {
+ max: number;
+ min: number;
+ onChange: ( val: number | string ) => void;
+ step: number;
+}
+
+/**
+ * Quantity Input Component.
+ */
+const QuantityInput = ( {
+ disabled,
+ min,
+ max,
+ step = 1,
+ value,
+ onChange,
+}: QuantityInputProps ) => {
+ const hasMaximum = typeof max !== 'undefined';
+
+ /**
+ * The goal of this function is to normalize what was inserted,
+ * but after the customer has stopped typing.
+ *
+ * It's important to wait before normalizing or we end up with
+ * a frustrating experience, for example, if the minimum is 2 and
+ * the customer is trying to type "10", premature normalizing would
+ * always kick in at "1" and turn that into 2.
+ *
+ * Copied from
+ */
+ const normalizeQuantity = useDebouncedCallback< ( val: number ) => void >(
+ ( initialValue ) => {
+ // We copy the starting value.
+ let newValue = initialValue;
+
+ // We check if we have a maximum value, and select the lowest between what was inserted and the maximum.
+ if ( hasMaximum ) {
+ newValue = Math.min(
+ newValue,
+ // the maximum possible value in step increments.
+ Math.floor( max / step ) * step
+ );
+ }
+
+ // Select the biggest between what's inserted, the the minimum value in steps.
+ newValue = Math.max( newValue, Math.ceil( min / step ) * step );
+
+ // We round off the value to our steps.
+ newValue = Math.floor( newValue / step ) * step;
+
+ // Only commit if the value has changed
+ if ( newValue !== initialValue ) {
+ onChange?.( newValue );
+ }
+ },
+ 300
+ );
+
+ return (
+ {
+ onChange?.( e.target.value );
+ normalizeQuantity( Number( e.target.value ) );
+ } }
+ />
+ );
+};
+
+export default QuantityInput;
diff --git a/assets/js/base/components/button/index.tsx b/assets/js/base/components/button/index.tsx
index 223f44ae363..4caf1498e58 100644
--- a/assets/js/base/components/button/index.tsx
+++ b/assets/js/base/components/button/index.tsx
@@ -2,7 +2,7 @@
* External dependencies
*/
import { Button as WPButton } from 'wordpress-components';
-import type { ReactNode } from 'react';
+import type { Button as WPButtonType } from '@wordpress/components';
import classNames from 'classnames';
import Spinner from '@woocommerce/base-components/spinner';
@@ -11,39 +11,21 @@ import Spinner from '@woocommerce/base-components/spinner';
*/
import './style.scss';
-export interface ButtonProps extends WPButton.ButtonProps {
- /**
- * Component wrapper classname
- *
- * @default 'wc-block-components-button'
- */
- className?: string;
+export interface ButtonProps
+ extends Omit< WPButtonType.ButtonProps, 'variant' > {
/**
* Show spinner
*
* @default false
*/
- showSpinner?: boolean;
- /**
- * Button content
- */
- children?: ReactNode;
- /**
- * Button state
- */
- disabled?: boolean;
- /**
- * Event handler triggered when the button is clicked
- */
- onClick?: ( e: React.MouseEvent< HTMLButtonElement, MouseEvent > ) => void;
- /**
- * Button type
- */
- type?: 'button' | 'input' | 'submit';
+ showSpinner?: boolean | undefined;
/**
* Button variant
*/
variant?: 'text' | 'contained' | 'outlined';
+}
+
+export interface AnchorProps extends Omit< ButtonProps, 'href' > {
/**
* Button href
*/
diff --git a/assets/js/types/type-defs/product-response.ts b/assets/js/types/type-defs/product-response.ts
index f875cf42eee..f19d0e1df7b 100644
--- a/assets/js/types/type-defs/product-response.ts
+++ b/assets/js/types/type-defs/product-response.ts
@@ -31,6 +31,7 @@ export interface ProductResponseImageItem {
}
export interface ProductResponseTermItem {
+ default?: boolean;
id: number;
name: string;
slug: string;
diff --git a/assets/js/types/type-defs/utils.ts b/assets/js/types/type-defs/utils.ts
index f23dd1e23c2..cc698db9fcf 100644
--- a/assets/js/types/type-defs/utils.ts
+++ b/assets/js/types/type-defs/utils.ts
@@ -1,3 +1,5 @@
+export type Dictionary = Record< string, string >;
+
/**
* Allow for the entire object to be passed, with only some properties
* required.
diff --git a/package-lock.json b/package-lock.json
index 85743d3f825..3d098dba675 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -71,6 +71,7 @@
"@types/react-dom": "18.0.9",
"@types/wordpress__block-editor": "6.0.6",
"@types/wordpress__blocks": "11.0.7",
+ "@types/wordpress__components": "^23.0.0",
"@types/wordpress__core-data": "^2.4.5",
"@types/wordpress__data": "^6.0.1",
"@types/wordpress__data-controls": "2.2.0",
@@ -11329,20 +11330,175 @@
}
},
"node_modules/@types/wordpress__components": {
- "version": "19.3.2",
+ "version": "23.0.0",
+ "resolved": "https://registry.npmjs.org/@types/wordpress__components/-/wordpress__components-23.0.0.tgz",
+ "integrity": "sha512-60S432ZMp9mIv74n+J91fZPFphnSZa6r8r1/QuoNeUHXIFPw3c28hL0kDl3i0GYvYTGlTkbvhGgUJvJA0GMW6g==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@types/react": "*",
"@types/tinycolor2": "*",
"@types/wordpress__components": "*",
"@types/wordpress__notices": "*",
"@types/wordpress__rich-text": "*",
- "@wordpress/element": "^4.1.0",
+ "@wordpress/element": "^5.0.0",
"downshift": "^6.0.15",
"re-resizable": "^6.4.0"
}
},
+ "node_modules/@types/wordpress__components/node_modules/@types/react": {
+ "version": "18.0.26",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz",
+ "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==",
+ "dev": true,
+ "dependencies": {
+ "@types/prop-types": "*",
+ "@types/scheduler": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@types/wordpress__components/node_modules/@wordpress/element": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-5.0.0.tgz",
+ "integrity": "sha512-u1DhVIdb6VEe8wzxKCrLfRWbeFLrlhYTFSOY6yrtl2z9vr9bCdlLp9aAppTxLNUs8cFcdoCEMpakVRYFyfZwTQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/runtime": "^7.16.0",
+ "@types/react": "^18.0.21",
+ "@types/react-dom": "^18.0.6",
+ "@wordpress/escape-html": "^2.23.0",
+ "change-case": "^4.1.2",
+ "is-plain-object": "^5.0.0",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@types/wordpress__components/node_modules/change-case": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz",
+ "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==",
+ "dev": true,
+ "dependencies": {
+ "camel-case": "^4.1.2",
+ "capital-case": "^1.0.4",
+ "constant-case": "^3.0.4",
+ "dot-case": "^3.0.4",
+ "header-case": "^2.0.4",
+ "no-case": "^3.0.4",
+ "param-case": "^3.0.4",
+ "pascal-case": "^3.1.2",
+ "path-case": "^3.0.4",
+ "sentence-case": "^3.0.4",
+ "snake-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/@types/wordpress__components/node_modules/constant-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz",
+ "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==",
+ "dev": true,
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case": "^2.0.2"
+ }
+ },
+ "node_modules/@types/wordpress__components/node_modules/dot-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
+ "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
+ "dev": true,
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/@types/wordpress__components/node_modules/path-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz",
+ "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==",
+ "dev": true,
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/@types/wordpress__components/node_modules/react": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
+ "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+ "dev": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/@types/wordpress__components/node_modules/react-dom": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
+ "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
+ "dev": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.0"
+ },
+ "peerDependencies": {
+ "react": "^18.2.0"
+ }
+ },
+ "node_modules/@types/wordpress__components/node_modules/scheduler": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
+ "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
+ "dev": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "node_modules/@types/wordpress__components/node_modules/sentence-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz",
+ "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==",
+ "dev": true,
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case-first": "^2.0.2"
+ }
+ },
+ "node_modules/@types/wordpress__components/node_modules/snake-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
+ "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
+ "dev": true,
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/@types/wordpress__components/node_modules/upper-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz",
+ "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/@types/wordpress__components/node_modules/upper-case-first": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz",
+ "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/@types/wordpress__core-data": {
"version": "2.4.5",
"dev": true,
@@ -15470,9 +15626,9 @@
}
},
"node_modules/@wordpress/escape-html": {
- "version": "2.22.0",
- "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.22.0.tgz",
- "integrity": "sha512-GUo6VLugIZxen1rdYuotvz6Vqa+5fNtVelNjXLwDqRu0iY2RXeoTux9V5bZWXPnGb54ryqfYmR4gH6F8xZhWzQ==",
+ "version": "2.23.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.23.0.tgz",
+ "integrity": "sha512-QmMGJVEoVu3+s46Ya7saYZI8D1jPOKN18eFJX21y59/99tAVvmcWWz0k0uTO5bciDQ7R6ACm9AJS6RiZycODkg==",
"dependencies": {
"@babel/runtime": "^7.16.0"
},
@@ -57842,7 +57998,9 @@
}
},
"@types/wordpress__components": {
- "version": "19.3.2",
+ "version": "23.0.0",
+ "resolved": "https://registry.npmjs.org/@types/wordpress__components/-/wordpress__components-23.0.0.tgz",
+ "integrity": "sha512-60S432ZMp9mIv74n+J91fZPFphnSZa6r8r1/QuoNeUHXIFPw3c28hL0kDl3i0GYvYTGlTkbvhGgUJvJA0GMW6g==",
"dev": true,
"requires": {
"@types/react": "*",
@@ -57850,9 +58008,156 @@
"@types/wordpress__components": "*",
"@types/wordpress__notices": "*",
"@types/wordpress__rich-text": "*",
- "@wordpress/element": "^4.1.0",
+ "@wordpress/element": "^5.0.0",
"downshift": "^6.0.15",
"re-resizable": "^6.4.0"
+ },
+ "dependencies": {
+ "@types/react": {
+ "version": "18.0.26",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz",
+ "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==",
+ "dev": true,
+ "requires": {
+ "@types/prop-types": "*",
+ "@types/scheduler": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "@wordpress/element": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-5.0.0.tgz",
+ "integrity": "sha512-u1DhVIdb6VEe8wzxKCrLfRWbeFLrlhYTFSOY6yrtl2z9vr9bCdlLp9aAppTxLNUs8cFcdoCEMpakVRYFyfZwTQ==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.16.0",
+ "@types/react": "^18.0.21",
+ "@types/react-dom": "^18.0.6",
+ "@wordpress/escape-html": "^2.23.0",
+ "change-case": "^4.1.2",
+ "is-plain-object": "^5.0.0",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ }
+ },
+ "change-case": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz",
+ "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==",
+ "dev": true,
+ "requires": {
+ "camel-case": "^4.1.2",
+ "capital-case": "^1.0.4",
+ "constant-case": "^3.0.4",
+ "dot-case": "^3.0.4",
+ "header-case": "^2.0.4",
+ "no-case": "^3.0.4",
+ "param-case": "^3.0.4",
+ "pascal-case": "^3.1.2",
+ "path-case": "^3.0.4",
+ "sentence-case": "^3.0.4",
+ "snake-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "constant-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz",
+ "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==",
+ "dev": true,
+ "requires": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case": "^2.0.2"
+ }
+ },
+ "dot-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
+ "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
+ "dev": true,
+ "requires": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "path-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz",
+ "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==",
+ "dev": true,
+ "requires": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "react": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
+ "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "react-dom": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
+ "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.0"
+ }
+ },
+ "scheduler": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
+ "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "sentence-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz",
+ "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==",
+ "dev": true,
+ "requires": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case-first": "^2.0.2"
+ }
+ },
+ "snake-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
+ "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
+ "dev": true,
+ "requires": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "upper-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz",
+ "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==",
+ "dev": true,
+ "requires": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "upper-case-first": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz",
+ "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==",
+ "dev": true,
+ "requires": {
+ "tslib": "^2.0.3"
+ }
+ }
}
},
"@types/wordpress__core-data": {
@@ -60777,9 +61082,9 @@
}
},
"@wordpress/escape-html": {
- "version": "2.22.0",
- "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.22.0.tgz",
- "integrity": "sha512-GUo6VLugIZxen1rdYuotvz6Vqa+5fNtVelNjXLwDqRu0iY2RXeoTux9V5bZWXPnGb54ryqfYmR4gH6F8xZhWzQ==",
+ "version": "2.23.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.23.0.tgz",
+ "integrity": "sha512-QmMGJVEoVu3+s46Ya7saYZI8D1jPOKN18eFJX21y59/99tAVvmcWWz0k0uTO5bciDQ7R6ACm9AJS6RiZycODkg==",
"requires": {
"@babel/runtime": "^7.16.0"
}
diff --git a/package.json b/package.json
index b469a1ac539..5c268ed0c69 100644
--- a/package.json
+++ b/package.json
@@ -123,6 +123,7 @@
"@types/react-dom": "18.0.9",
"@types/wordpress__block-editor": "6.0.6",
"@types/wordpress__blocks": "11.0.7",
+ "@types/wordpress__components": "^23.0.0",
"@types/wordpress__core-data": "^2.4.5",
"@types/wordpress__data": "^6.0.1",
"@types/wordpress__data-controls": "2.2.0",