Merge branch 'trunk' into 41637/remove-survey-button

This commit is contained in:
Patricia Hillebrandt 2023-12-07 08:49:10 -03:00
commit 396f1e5169
30 changed files with 643 additions and 453 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: update
[Product Block Editor]: move Modal edittor out of the description block edit component

View File

@ -2,7 +2,7 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { createElement } from '@wordpress/element';
import { createElement, useEffect } from '@wordpress/element';
import {
BlockAttributes,
BlockInstance,
@ -19,10 +19,9 @@ import { useEntityProp } from '@wordpress/core-data';
* Internal dependencies
*/
import { ContentPreview } from '../../../components/content-preview';
import { ModalEditor } from '../../../components/modal-editor';
import { ProductEditorBlockEditProps } from '../../../types';
import ModalEditorWelcomeGuide from '../../../components/modal-editor-welcome-guide';
import { store as productEditorUiStore } from '../../../store/product-editor-ui';
import { store } from '../../../store/product-editor-ui';
/**
* Internal dependencies
@ -58,19 +57,43 @@ export function DescriptionBlockEdit( {
'description'
);
// Check if the Modal editor is open from the store.
const isModalEditorOpen = useSelect( ( select ) => {
return select( productEditorUiStore ).isModalEditorOpen();
}, [] );
// Pick Modal editor data from the store.
const { isModalEditorOpen, modalEditorBlocks, hasChanged } = useSelect(
( select ) => {
return {
isModalEditorOpen: select( store ).isModalEditorOpen(),
modalEditorBlocks: select( store ).getModalEditorBlocks(),
hasChanged: select( store ).getModalEditorContentHasChanged(),
};
},
[]
);
const { openModalEditor, closeModalEditor } =
useDispatch( productEditorUiStore );
const { openModalEditor, setModalEditorBlocks } = useDispatch( store );
// Update the description when the blocks change.
useEffect( () => {
if ( ! hasChanged ) {
return;
}
if ( ! modalEditorBlocks?.length ) {
setDescription( '' );
}
const html = serialize( clearDescriptionIfEmpty( modalEditorBlocks ) );
setDescription( html );
}, [ modalEditorBlocks, setDescription, hasChanged ] );
return (
<div { ...blockProps }>
<Button
variant="secondary"
onClick={ () => {
if ( description ) {
setModalEditorBlocks( parse( description ) );
}
openModalEditor();
recordEvent( 'product_add_description_click' );
} }
@ -80,20 +103,6 @@ export function DescriptionBlockEdit( {
: __( 'Add description', 'woocommerce' ) }
</Button>
{ isModalEditorOpen && (
<ModalEditor
initialBlocks={ parse( description ) }
onChange={ ( blocks ) => {
const html = serialize(
clearDescriptionIfEmpty( blocks )
);
setDescription( html );
} }
onClose={ closeModalEditor }
title={ __( 'Edit description', 'woocommerce' ) }
/>
) }
{ !! description.length && (
<ContentPreview content={ description } />
) }

View File

@ -6,6 +6,7 @@ import { createElement, useMemo, useLayoutEffect } from '@wordpress/element';
import { useDispatch, useSelect, select as WPSelect } from '@wordpress/data';
import { uploadMedia } from '@wordpress/media-utils';
import { PluginArea } from '@wordpress/plugins';
import { __ } from '@wordpress/i18n';
import {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore No types for this exist yet.
@ -34,6 +35,8 @@ import {
import { useConfirmUnsavedProductChanges } from '../../hooks/use-confirm-unsaved-product-changes';
import { ProductEditorContext } from '../../types';
import { PostTypeContext } from '../../contexts/post-type-context';
import { ModalEditor } from '../modal-editor';
import { store as productEditorUiStore } from '../../store/product-editor-ui';
type BlockEditorSettings = Partial<
EditorSettings & EditorBlockListSettings
@ -111,10 +114,26 @@ export function BlockEditor( {
updateEditorSettings( settings ?? {} );
}, [ productType, productId ] );
// Check if the Modal editor is open from the store.
const isModalEditorOpen = useSelect( ( select ) => {
return select( productEditorUiStore ).isModalEditorOpen();
}, [] );
const { closeModalEditor } = useDispatch( productEditorUiStore );
if ( ! blocks ) {
return null;
}
if ( isModalEditorOpen ) {
return (
<ModalEditor
onClose={ closeModalEditor }
title={ __( 'Edit description', 'woocommerce' ) }
/>
);
}
return (
<div className="woocommerce-product-block-editor">
<BlockContextProvider value={ context }>
@ -123,6 +142,7 @@ export function BlockEditor( {
onInput={ onInput }
onChange={ onChange }
settings={ settings }
useSubRegistry={ false }
>
{ /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */ }
{ /* @ts-ignore No types for this exist yet. */ }

View File

@ -31,31 +31,41 @@ import { HeaderToolbar } from './header-toolbar/header-toolbar';
import { ResizableEditor } from './resizable-editor';
import { SecondarySidebar } from './secondary-sidebar/secondary-sidebar';
import { useEditorHistory } from './hooks/use-editor-history';
import { store as productEditorUiStore } from '../../store/product-editor-ui';
type IframeEditorProps = {
closeModal?: () => void;
initialBlocks?: BlockInstance[];
onChange?: ( blocks: BlockInstance[] ) => void;
onClose?: () => void;
onInput?: ( blocks: BlockInstance[] ) => void;
settings?: Partial< EditorSettings & EditorBlockListSettings > | undefined;
showBackButton?: boolean;
};
export function IframeEditor( {
closeModal = () => {},
initialBlocks = [],
onChange = () => {},
onClose,
onInput = () => {},
settings: __settings,
showBackButton = false,
}: IframeEditorProps ) {
const [ resizeObserver ] = useResizeObserver();
const [ blocks, setBlocks ] = useState< BlockInstance[] >( initialBlocks );
const [ temporalBlocks, setTemporalBlocks ] =
useState< BlockInstance[] >( initialBlocks );
// Pick the blocks from the store.
const blocks: BlockInstance[] = useSelect( ( select ) => {
return select( productEditorUiStore ).getModalEditorBlocks();
}, [] );
const { setModalEditorBlocks: setBlocks, setModalEditorContentHasChanged } =
useDispatch( productEditorUiStore );
const { appendEdit } = useEditorHistory( {
setBlocks,
} );
const {
appendEdit: tempAppendEdit,
hasRedo,
@ -127,15 +137,16 @@ export function IframeEditor( {
onSave={ () => {
appendEdit( temporalBlocks );
setBlocks( temporalBlocks );
setModalEditorContentHasChanged( true );
onChange( temporalBlocks );
closeModal();
onClose?.();
} }
onCancel={ () => {
appendEdit( blocks );
setBlocks( blocks );
onChange( blocks );
setTemporalBlocks( blocks );
closeModal();
onClose?.();
} }
/>
<div className="woocommerce-iframe-editor__main">
@ -157,7 +168,7 @@ export function IframeEditor( {
{ /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */ }
{ /* @ts-ignore */ }
<BlockEditorKeyboardShortcuts.Register />
{ onClose && (
{ showBackButton && onClose && (
<BackButton
onClick={ () => {
setTimeout( onClose, 550 );

View File

@ -3,6 +3,7 @@
*/
import { BlockInstance } from '@wordpress/blocks';
import { createElement } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import {
EditorSettings,
EditorBlockListSettings,
@ -14,11 +15,12 @@ import { useDebounce } from '@wordpress/compose';
* Internal dependencies
*/
import { IframeEditor } from '../iframe-editor';
import { store as productEditorUiStore } from '../../store/product-editor-ui';
type ModalEditorProps = {
initialBlocks?: BlockInstance[];
onChange: ( blocks: BlockInstance[] ) => void;
onClose: () => void;
onChange?: ( blocks: BlockInstance[] ) => void;
onClose?: () => void;
settings?: Partial< EditorSettings & EditorBlockListSettings > | undefined;
title: string;
};
@ -29,16 +31,19 @@ export function ModalEditor( {
onClose,
title,
}: ModalEditorProps ) {
const { closeModalEditor } = useDispatch( productEditorUiStore );
const debouncedOnChange = useDebounce( ( blocks: BlockInstance[] ) => {
onChange( blocks );
onChange?.( blocks );
}, 250 );
function handleClose() {
const blocks = debouncedOnChange.flush();
if ( blocks ) {
onChange( blocks );
onChange?.( blocks );
}
onClose();
closeModalEditor();
onClose?.();
}
return (
@ -52,7 +57,7 @@ export function ModalEditor( {
initialBlocks={ initialBlocks }
onInput={ debouncedOnChange }
onChange={ debouncedOnChange }
closeModal={ handleClose }
onClose={ handleClose }
/>
</Modal>
);

View File

@ -1,18 +1,36 @@
/**
* External dependencies
*/
import { BlockInstance } from '@wordpress/blocks';
/**
* Internal dependencies
*/
import {
ACTION_MODAL_EDITOR_CLOSE,
ACTION_MODAL_EDITOR_OPEN,
ACTION_MODAL_EDITOR_SET_BLOCKS,
ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED,
} from './constants';
const modalEditorActions = {
openModalEditor: () => ( {
type: ACTION_MODAL_EDITOR_OPEN,
} ),
closeModalEditor: () => ( {
type: ACTION_MODAL_EDITOR_CLOSE,
} ),
setModalEditorBlocks: ( blocks: BlockInstance ) => ( {
type: ACTION_MODAL_EDITOR_SET_BLOCKS,
blocks,
} ),
setModalEditorContentHasChanged: ( hasChanged: boolean ) => ( {
type: ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED,
hasChanged,
} ),
};
export default {

View File

@ -1,5 +1,8 @@
/**
* Full editor actions
*/
export const ACTION_MODAL_EDITOR_OPEN = 'MODAL_EDITOROPEN';
export const ACTION_MODAL_EDITOR_CLOSE = 'MODAL_EDITORCLOSE';
export const ACTION_MODAL_EDITOR_OPEN = 'MODAL_EDITOR_OPEN';
export const ACTION_MODAL_EDITOR_CLOSE = 'MODAL_EDITOR_CLOSE';
export const ACTION_MODAL_EDITOR_SET_BLOCKS = 'MODAL_EDITOR_SET_BLOCKS';
export const ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED =
'MODAL_EDITOR_CONTENT_HAS_CHANGED';

View File

@ -2,8 +2,10 @@
* Internal dependencies
*/
import {
ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED,
ACTION_MODAL_EDITOR_CLOSE,
ACTION_MODAL_EDITOR_OPEN,
ACTION_MODAL_EDITOR_SET_BLOCKS,
} from './constants';
import type {
ProductEditorModalEditorAction,
@ -16,6 +18,8 @@ import type {
const INITIAL_STATE: ProductEditorUIStateProps = {
modalEditor: {
isOpen: false,
blocks: [],
hasChanged: false,
},
};
@ -28,16 +32,37 @@ export default function reducer(
return {
...state,
modalEditor: {
...state.modalEditor,
isOpen: true,
},
};
case ACTION_MODAL_EDITOR_CLOSE:
return {
...state,
modalEditor: {
...state.modalEditor,
isOpen: false,
},
};
case ACTION_MODAL_EDITOR_SET_BLOCKS:
return {
...state,
modalEditor: {
...state.modalEditor,
blocks: action.blocks || [],
},
};
case ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED:
return {
...state,
modalEditor: {
...state.modalEditor,
hasChanged: action?.hasChanged || false,
},
};
}
return state;

View File

@ -1,7 +1,11 @@
/**
* External dependencies
*/
import { BlockInstance } from '@wordpress/blocks';
/**
* Internal dependencies
*/
import type { ProductEditorUIStateProps } from './types';
export default {
@ -10,4 +14,16 @@ export default {
) {
return state.modalEditor.isOpen;
},
getModalEditorBlocks: function getModalEditorBlocks(
state: ProductEditorUIStateProps
): BlockInstance[] {
return state.modalEditor.blocks;
},
getModalEditorContentHasChanged: function getModalEditorContentHasChanged(
state: ProductEditorUIStateProps
): boolean {
return !! state.modalEditor.hasChanged;
},
};

View File

@ -1,17 +1,34 @@
/**
* External dependencies
*/
import { BlockInstance } from '@wordpress/blocks';
/**
* Internal dependencies
*/
import {
ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED,
ACTION_MODAL_EDITOR_CLOSE,
ACTION_MODAL_EDITOR_OPEN,
ACTION_MODAL_EDITOR_SET_BLOCKS,
} from './constants';
export type ProductEditorUIStateProps = {
modalEditor: {
isOpen: boolean;
blocks: BlockInstance[];
hasChanged?: boolean;
};
};
export type ProductEditorModalEditorAction = {
type: typeof ACTION_MODAL_EDITOR_OPEN | typeof ACTION_MODAL_EDITOR_CLOSE;
type:
| typeof ACTION_MODAL_EDITOR_OPEN
| typeof ACTION_MODAL_EDITOR_CLOSE
| typeof ACTION_MODAL_EDITOR_SET_BLOCKS
| typeof ACTION_MODAL_EDITOR_CONTENT_HAS_CHANGED;
blocks?: BlockInstance[];
hasChanged?: boolean;
};

View File

@ -11,7 +11,7 @@ export const SYSTEM_FONT_SLUG = 'system-font';
// Generated from /wpcom/v2/sites/{site_id}/global-styles-variation/font-pairings
// TODO: Consider creating an API endpoint for this data
export const FONT_PAIRINGS = [
export const FONT_PAIRINGS_WHEN_AI_IS_OFFLINE = [
{
title: 'Inter + Inter',
version: 2,
@ -69,45 +69,6 @@ export const FONT_PAIRINGS = [
},
},
},
{
title: 'Albert Sans + Lora',
version: 2,
lookAndFeel: [ 'Contemporary', 'Bold' ] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Albert Sans',
slug: 'albert-sans',
},
{
fontFamily: 'Lora',
slug: 'lora',
},
],
},
},
},
styles: {
elements: {
heading: {
typography: {
fontFamily:
'var(--wp--preset--font-family--albert-sans)',
fontStyle: 'normal',
fontWeight: '700',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--lora)',
fontStyle: 'normal',
fontWeight: '400',
lineHeight: '1.67',
},
},
},
{
title: 'Bodoni Moda + Overpass',
version: 2,
@ -169,6 +130,277 @@ export const FONT_PAIRINGS = [
},
},
},
{
title: 'Albert Sans + Lora',
version: 2,
lookAndFeel: [ 'Contemporary', 'Bold' ] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Albert Sans',
slug: 'albert-sans',
},
{
fontFamily: 'Lora',
slug: 'lora',
},
],
},
},
},
styles: {
elements: {
heading: {
typography: {
fontFamily:
'var(--wp--preset--font-family--albert-sans)',
fontStyle: 'normal',
fontWeight: '700',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--lora)',
fontStyle: 'normal',
fontWeight: '400',
lineHeight: '1.67',
},
},
},
{
title: 'Montserrat + Arvo',
version: 2,
lookAndFeel: [ 'Contemporary', 'Bold' ] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Montserrat',
slug: 'montserrat',
},
{
fontFamily: 'Arvo',
slug: 'arvo',
},
],
},
},
},
styles: {
elements: {
button: {
typography: {
fontFamily:
'var(--wp--preset--font-family--montserrat)',
fontStyle: 'normal',
fontWeight: '500',
},
},
heading: {
typography: {
fontFamily:
'var(--wp--preset--font-family--montserrat)',
fontStyle: 'normal',
fontWeight: '700',
lineHeight: '1.4',
},
},
},
blocks: {
'core/site-title': {
typography: {
fontFamily:
'var(--wp--preset--font-family--montserrat)',
fontWeight: '700',
},
},
'core/post-navigation-link': {
typography: {
fontFamily:
'var(--wp--preset--font-family--montserrat)',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--arvo)',
fontSize: 'var(--wp--preset--font-size--small)',
fontStyle: 'normal',
fontWeight: '400',
lineHeight: '1.6',
},
},
},
{
title: 'Rubik + Inter',
version: 2,
lookAndFeel: [ 'Bold' ] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Rubik',
slug: 'rubik',
},
{
fontFamily: 'Inter',
slug: 'inter',
},
],
},
},
},
styles: {
elements: {
button: {
typography: {
fontFamily: 'var(--wp--preset--font-family--inter)',
fontWeight: '400',
lineHeight: '1',
},
},
heading: {
typography: {
fontFamily: 'var(--wp--preset--font-family--rubik)',
fontStyle: 'normal',
fontWeight: '800',
},
},
},
blocks: {
'core/site-title': {
typography: {
fontFamily: 'var(--wp--preset--font-family--rubik)',
fontWeight: '800',
},
},
'core/post-navigation-link': {
typography: {
fontFamily: 'var(--wp--preset--font-family--rubik)',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--inter)',
fontSize: 'var(--wp--preset--font-size--medium)',
fontStyle: 'normal',
fontWeight: '400',
lineHeight: '1.6',
},
},
},
{
title: 'Newsreader + Newsreader',
version: 2,
lookAndFeel: [ 'Classic' ] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Newsreader',
slug: 'newsreader',
},
],
},
},
},
styles: {
elements: {
heading: {
typography: {
fontFamily:
'var(--wp--preset--font-family--newsreader)',
fontStyle: 'normal',
fontWeight: '400',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--newsreader)',
fontSize: 'var(--wp--preset--font-size--medium)',
lineHeight: '1.67',
},
},
},
{
title: 'Cormorant + Work Sans',
version: 2,
lookAndFeel: [] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Cormorant',
slug: 'cormorant',
},
{
fontFamily: 'Work Sans',
slug: 'work-sans',
},
],
},
},
},
styles: {
elements: {
heading: {
typography: {
fontFamily: 'var(--wp--preset--font-family--cormorant)',
fontStyle: 'normal',
fontWeight: '500',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--work-sans)',
},
},
},
{
title: 'Raleway + Cormorant',
version: 2,
lookAndFeel: [ 'Classic', 'Bold' ] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Raleway',
slug: 'raleway',
},
{
fontFamily: 'Cormorant',
slug: 'cormorant',
},
],
},
},
},
styles: {
elements: {
heading: {
typography: {
fontFamily: 'var(--wp--preset--font-family--raleway)',
fontStyle: 'normal',
fontWeight: '700',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--cormorant)',
fontSize: 'var(--wp--preset--font-size--medium)',
lineHeight: '1.67',
},
},
},
];
export const FONT_PAIRINGS = [
{
title: 'Commissioner + Crimson Pro',
version: 2,
@ -232,41 +464,6 @@ export const FONT_PAIRINGS = [
},
},
},
{
title: 'Cormorant + Work Sans',
version: 2,
lookAndFeel: [] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Cormorant',
slug: 'cormorant',
},
{
fontFamily: 'Work Sans',
slug: 'work-sans',
},
],
},
},
},
styles: {
elements: {
heading: {
typography: {
fontFamily: 'var(--wp--preset--font-family--cormorant)',
fontStyle: 'normal',
fontWeight: '500',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--work-sans)',
},
},
},
{
title: 'DM Sans + IBM Plex Mono',
version: 2,
@ -403,168 +600,6 @@ export const FONT_PAIRINGS = [
},
},
},
{
title: 'Libre Franklin + EB Garamond',
version: 2,
lookAndFeel: [ 'Classic' ] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Libre Franklin',
slug: 'libre-franklin',
},
{
fontFamily: 'EB Garamond',
slug: 'eb-garamond',
},
],
},
},
},
styles: {
elements: {
button: {
typography: {
fontFamily:
'var(--wp--preset--font-family--libre-franklin)',
fontSize: 'var(--wp--preset--font-size--small)',
fontWeight: '400',
lineHeight: '1',
},
},
heading: {
typography: {
fontFamily:
'var(--wp--preset--font-family--libre-franklin)',
fontStyle: 'normal',
fontWeight: '700',
},
},
},
blocks: {
'core/site-title': {
typography: {
fontFamily:
'var(--wp--preset--font-family--libre-franklin)',
fontWeight: '500',
},
},
'core/post-navigation-link': {
typography: {
fontFamily:
'var(--wp--preset--font-family--libre-franklin)',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--eb-garamond)',
fontSize: 'var(--wp--preset--font-size--medium)',
fontStyle: 'normal',
fontWeight: '400',
lineHeight: '1.6',
},
},
},
{
title: 'Montserrat + Arvo',
version: 2,
lookAndFeel: [ 'Contemporary', 'Bold' ] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Montserrat',
slug: 'montserrat',
},
{
fontFamily: 'Arvo',
slug: 'arvo',
},
],
},
},
},
styles: {
elements: {
button: {
typography: {
fontFamily:
'var(--wp--preset--font-family--montserrat)',
fontStyle: 'normal',
fontWeight: '500',
},
},
heading: {
typography: {
fontFamily:
'var(--wp--preset--font-family--montserrat)',
fontStyle: 'normal',
fontWeight: '700',
lineHeight: '1.4',
},
},
},
blocks: {
'core/site-title': {
typography: {
fontFamily:
'var(--wp--preset--font-family--montserrat)',
fontWeight: '700',
},
},
'core/post-navigation-link': {
typography: {
fontFamily:
'var(--wp--preset--font-family--montserrat)',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--arvo)',
fontSize: 'var(--wp--preset--font-size--small)',
fontStyle: 'normal',
fontWeight: '400',
lineHeight: '1.6',
},
},
},
{
title: 'Newsreader + Newsreader',
version: 2,
lookAndFeel: [ 'Classic' ] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Newsreader',
slug: 'newsreader',
},
],
},
},
},
styles: {
elements: {
heading: {
typography: {
fontFamily:
'var(--wp--preset--font-family--newsreader)',
fontStyle: 'normal',
fontWeight: '400',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--newsreader)',
fontSize: 'var(--wp--preset--font-size--medium)',
lineHeight: '1.67',
},
},
},
{
title: 'Playfair Display + Fira Sans',
version: 2,
@ -630,6 +665,70 @@ export const FONT_PAIRINGS = [
},
},
},
{
title: 'Libre Franklin + EB Garamond',
version: 2,
lookAndFeel: [ 'Classic' ] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Libre Franklin',
slug: 'libre-franklin',
},
{
fontFamily: 'EB Garamond',
slug: 'eb-garamond',
},
],
},
},
},
styles: {
elements: {
button: {
typography: {
fontFamily:
'var(--wp--preset--font-family--libre-franklin)',
fontSize: 'var(--wp--preset--font-size--small)',
fontWeight: '400',
lineHeight: '1',
},
},
heading: {
typography: {
fontFamily:
'var(--wp--preset--font-family--libre-franklin)',
fontStyle: 'normal',
fontWeight: '700',
},
},
},
blocks: {
'core/site-title': {
typography: {
fontFamily:
'var(--wp--preset--font-family--libre-franklin)',
fontWeight: '500',
},
},
'core/post-navigation-link': {
typography: {
fontFamily:
'var(--wp--preset--font-family--libre-franklin)',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--eb-garamond)',
fontSize: 'var(--wp--preset--font-size--medium)',
fontStyle: 'normal',
fontWeight: '400',
lineHeight: '1.6',
},
},
},
{
title: 'Plus Jakarta Sans + Plus Jakarta Sans',
version: 2,
@ -663,102 +762,6 @@ export const FONT_PAIRINGS = [
},
},
},
{
title: 'Raleway + Cormorant',
version: 2,
lookAndFeel: [ 'Classic', 'Bold' ] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Raleway',
slug: 'raleway',
},
{
fontFamily: 'Cormorant',
slug: 'cormorant',
},
],
},
},
},
styles: {
elements: {
heading: {
typography: {
fontFamily: 'var(--wp--preset--font-family--raleway)',
fontStyle: 'normal',
fontWeight: '700',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--cormorant)',
fontSize: 'var(--wp--preset--font-size--medium)',
lineHeight: '1.67',
},
},
},
{
title: 'Rubik + Inter',
version: 2,
lookAndFeel: [ 'Bold' ] as Look[],
settings: {
typography: {
fontFamilies: {
theme: [
{
fontFamily: 'Rubik',
slug: 'rubik',
},
{
fontFamily: 'Inter',
slug: 'inter',
},
],
},
},
},
styles: {
elements: {
button: {
typography: {
fontFamily: 'var(--wp--preset--font-family--inter)',
fontWeight: '400',
lineHeight: '1',
},
},
heading: {
typography: {
fontFamily: 'var(--wp--preset--font-family--rubik)',
fontStyle: 'normal',
fontWeight: '800',
},
},
},
blocks: {
'core/site-title': {
typography: {
fontFamily: 'var(--wp--preset--font-family--rubik)',
fontWeight: '800',
},
},
'core/post-navigation-link': {
typography: {
fontFamily: 'var(--wp--preset--font-family--rubik)',
},
},
},
typography: {
fontFamily: 'var(--wp--preset--font-family--inter)',
fontSize: 'var(--wp--preset--font-size--medium)',
fontStyle: 'normal',
fontWeight: '400',
lineHeight: '1.6',
},
},
},
{
title: 'Rubik + Rubik',
version: 2,
@ -854,4 +857,5 @@ export const FONT_PAIRINGS = [
},
},
},
...FONT_PAIRINGS_WHEN_AI_IS_OFFLINE,
];

View File

@ -7,15 +7,16 @@
import { __experimentalGrid as Grid, Spinner } from '@wordpress/components';
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
import { useSelect } from '@wordpress/data';
import { useMemo } from '@wordpress/element';
import { useContext, useMemo } from '@wordpress/element';
/**
* Internal dependencies
*/
import { FONT_PAIRINGS } from './constants';
import { FONT_PAIRINGS, FONT_PAIRINGS_WHEN_AI_IS_OFFLINE } from './constants';
import { VariationContainer } from '../variation-container';
import { FontPairingVariationPreview } from './preview';
import { Look } from '~/customize-store/design-with-ai/types';
import { CustomizeStoreContext } from '~/customize-store/assembler-hub';
export const FontPairing = () => {
const { aiSuggestions, isLoading } = useSelect( ( select ) => {
@ -31,14 +32,17 @@ export const FontPairing = () => {
};
} );
const { context } = useContext( CustomizeStoreContext );
const aiOnline = context.aiOnline;
const fontPairings = useMemo(
() =>
aiSuggestions?.lookAndFeel
aiOnline && aiSuggestions?.lookAndFeel
? FONT_PAIRINGS.filter( ( font ) =>
font.lookAndFeel.includes( aiSuggestions?.lookAndFeel )
)
: FONT_PAIRINGS,
[ aiSuggestions ]
: FONT_PAIRINGS_WHEN_AI_IS_OFFLINE,
[ aiOnline, aiSuggestions?.lookAndFeel ]
);
if ( isLoading ) {

View File

@ -4,7 +4,7 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { createInterpolateElement } from '@wordpress/element';
import { createInterpolateElement, useContext } from '@wordpress/element';
import { Link } from '@woocommerce/components';
import { recordEvent } from '@woocommerce/tracks';
@ -14,55 +14,63 @@ import { recordEvent } from '@woocommerce/tracks';
import { SidebarNavigationScreen } from './sidebar-navigation-screen';
import { ADMIN_URL } from '~/utils/admin-settings';
import { FontPairing } from './global-styles';
import { CustomizeStoreContext } from '..';
export const SidebarNavigationScreenTypography = () => {
const { context } = useContext( CustomizeStoreContext );
const aiOnline = context.aiOnline;
const label = aiOnline
? __(
"AI has selected a font pairing that's the best fit for your business. If you'd like to change them, select a new option below now, or later in <EditorLink>Editor</EditorLink> | <StyleLink>Styles</StyleLink>.",
'woocommerce'
)
: __(
'Select the pair of fonts that best suits your brand. The larger font will be used for headings, and the smaller for supporting content. You can change your font at any time in <EditorLink>Editor</EditorLink> | <StyleLink>Styles</StyleLink>.',
'woocommerce'
);
return (
<SidebarNavigationScreen
title={ __( 'Change your font', 'woocommerce' ) }
description={ createInterpolateElement(
__(
"AI has selected a font pairing that's the best fit for your business. If you'd like to change them, select a new option below now, or later in <EditorLink>Editor</EditorLink> | <StyleLink>Styles</StyleLink>.",
'woocommerce'
description={ createInterpolateElement( label, {
EditorLink: (
<Link
onClick={ () => {
recordEvent(
'customize_your_store_assembler_hub_editor_link_click',
{
source: 'typography',
}
);
window.open(
`${ ADMIN_URL }site-editor.php`,
'_blank'
);
return false;
} }
href=""
/>
),
{
EditorLink: (
<Link
onClick={ () => {
recordEvent(
'customize_your_store_assembler_hub_editor_link_click',
{
source: 'typography',
}
);
window.open(
`${ ADMIN_URL }site-editor.php`,
'_blank'
);
return false;
} }
href=""
/>
),
StyleLink: (
<Link
onClick={ () => {
recordEvent(
'customize_your_store_assembler_hub_style_link_click',
{
source: 'typography',
}
);
window.open(
`${ ADMIN_URL }site-editor.php?path=%2Fwp_global_styles&canvas=edit`,
'_blank'
);
return false;
} }
href=""
/>
),
}
) }
StyleLink: (
<Link
onClick={ () => {
recordEvent(
'customize_your_store_assembler_hub_style_link_click',
{
source: 'typography',
}
);
window.open(
`${ ADMIN_URL }site-editor.php?path=%2Fwp_global_styles`,
'_blank'
);
return false;
} }
href=""
/>
),
} ) }
content={
<div className="woocommerce-customize-store_sidebar-typography-content">
<FontPairing />

View File

@ -99,7 +99,10 @@ const loaderSteps = [
];
// Make the loader last longer and provide a smoother progress by duplicating the steps.
const createAugmentedSteps = ( steps: typeof loaderSteps ) => {
const createAugmentedSteps = (
steps: typeof loaderSteps,
numOfDupes: number
) => {
// Duplicate each step, so we can animate each one
// (e.g. each step will be duplicated 3 times, and each duplicate will
// have different progress)
@ -112,8 +115,7 @@ const createAugmentedSteps = ( steps: typeof loaderSteps ) => {
if ( ! nextItem ) return [ item ];
// If there is a next item, we're not at the end of the array
// so return the current item, plus two duplicates
const numOfDupes = 2;
// so return the current item, plus duplicates
const duplicates = [ item ];
const progressIncreaseBy =
( nextItem.progress - item.progress ) / numOfDupes;
@ -149,7 +151,10 @@ export const ApiCallLoader = () => {
preload( openingTheDoors );
}, [] );
const augmentedSteps = createAugmentedSteps( loaderSteps.slice( 0, -1 ) );
const augmentedSteps = createAugmentedSteps(
loaderSteps.slice( 0, -1 ),
10
);
return (
<Loader>
@ -182,7 +187,7 @@ export const ApiCallLoader = () => {
export const AssembleHubLoader = () => {
// Show the last two steps of the loader so that the last frame is the shortest time possible
const augmentedSteps = createAugmentedSteps( loaderSteps.slice( -2 ) );
const augmentedSteps = createAugmentedSteps( loaderSteps.slice( -2 ), 10 );
const [ progress, setProgress ] = useState( augmentedSteps[ 0 ].progress );

View File

@ -473,15 +473,21 @@ const saveAiResponseToOption = ( context: designWithAiStateMachineContext ) => {
} );
};
const resetPatterns = () => async () => {
const resetPatternsAndProducts = () => async () => {
await dispatch( OPTIONS_STORE_NAME ).updateOptions( {
woocommerce_blocks_allow_ai_connection: 'yes',
} );
return await apiFetch( {
path: '/wc/private/ai/patterns',
method: 'DELETE',
} );
return Promise.all( [
apiFetch( {
path: '/wc/private/ai/patterns',
method: 'DELETE',
} ),
apiFetch( {
path: '/wc/private/ai/products',
method: 'DELETE',
} ),
] );
};
export const services = {
@ -491,5 +497,5 @@ export const services = {
updateStorePatterns,
saveAiResponseToOption,
installAndActivateTheme,
resetPatterns,
resetPatternsAndProducts,
};

View File

@ -355,7 +355,7 @@ export const designWithAiStateMachineDefinition = createMachine(
cond: 'isAiOnline',
},
{
target: 'resetPatterns',
target: 'resetPatternsAndProducts',
},
],
},
@ -373,9 +373,9 @@ export const designWithAiStateMachineDefinition = createMachine(
},
},
},
resetPatterns: {
resetPatternsAndProducts: {
invoke: {
src: 'resetPatterns',
src: 'resetPatternsAndProducts',
onDone: {
target: 'success',
},

View File

@ -12,6 +12,6 @@
.progress-bar.smooth-transition {
.woocommerce-onboarding-progress-bar__filler {
transition: width linear 1s;
transition: width linear 2s;
}
}

View File

@ -38,6 +38,6 @@
.progress-bar.smooth-transition {
.woocommerce-onboarding-progress-bar__filler {
transition: width linear 1s;
transition: width linear 2s;
}
}

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Added missing CSS class on the empty-orders notice CTA in the My Account > Orders page

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
CSY: Update copy when AI is offline.

View File

@ -0,0 +1,4 @@
Significance: minor
Type: fix
Format postcode before validation on the shortcode cart shipping calculator

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
CYS: Reset products when the AI is offline.

View File

@ -0,0 +1,5 @@
Significance: patch
Type: dev
Comment: Simply changes a value in a doc block.

View File

@ -0,0 +1,4 @@
Significance: major
Type: update
FlexSlider "fade" animations always use CSS3 transitions.

View File

@ -0,0 +1,4 @@
Significance: patch
Type: enhancement
Make CYS loading sequence smoother

View File

@ -720,12 +720,16 @@
});
}
} else { // FADE:
// if (!touch) calls slider.wrapup() on fade animation end; if (touch) calls slider.wrapup() immediately
if (!touch) {
slider.slides.eq(slider.currentSlide).css({"zIndex": 1}).animate({"opacity": 0}, slider.vars.animationSpeed, slider.vars.easing);
slider.slides.eq(target).css({"zIndex": 2}).animate({"opacity": 1}, slider.vars.animationSpeed, slider.vars.easing, slider.wrapup);
} else {
slider.slides.eq(slider.currentSlide).css({ "opacity": 0, "zIndex": 1 });
slider.slides.eq(target).css({ "opacity": 1, "zIndex": 2 });
slider.slides.eq(slider.currentSlide).off("transitionend");
slider.slides.eq(target).off("transitionend").on("transitionend", slider.wrapup);
}
slider.slides.eq(slider.currentSlide).css({ "opacity": 0, "zIndex": 1 });
slider.slides.eq(target).css({ "opacity": 1, "zIndex": 2 });
if (touch) {
slider.wrapup(dimension);
}
}
@ -896,12 +900,15 @@
}
if (type === "init") {
if (!touch) {
//slider.slides.eq(slider.currentSlide).fadeIn(slider.vars.animationSpeed, slider.vars.easing);
// Every "opacity" change before outerWidth() does NOT get animated; every "opacity" change after outerWidth() becomes a fadeIn
if (slider.vars.fadeFirstSlide == false) {
slider.slides.css({ "opacity": 0, "display": "block", "zIndex": 1 }).eq(slider.currentSlide).css({"zIndex": 2}).css({"opacity": 1});
slider.slides.outerWidth();
} else {
slider.slides.css({ "opacity": 0, "display": "block", "zIndex": 1 }).eq(slider.currentSlide).css({"zIndex": 2}).animate({"opacity": 1},slider.vars.animationSpeed,slider.vars.easing);
slider.slides.css({ "opacity": 0, "display": "block", "zIndex": 1 }).outerWidth();
slider.slides.eq(slider.currentSlide).css({"zIndex": 2}).css({"opacity": 1});
}
slider.slides.css({ "transition": "opacity " + slider.vars.animationSpeed / 1000 + "s " + easing });
} else {
slider.slides.css({ "opacity": 0, "display": "block", "transition": "opacity " + slider.vars.animationSpeed / 1000 + "s ease", "zIndex": 1 }).eq(slider.currentSlide).css({ "opacity": 1, "zIndex": 2});
}

View File

@ -31,12 +31,14 @@ class WC_Shortcode_Cart {
$address['postcode'] = isset( $_POST['calc_shipping_postcode'] ) ? wc_clean( wp_unslash( $_POST['calc_shipping_postcode'] ) ) : ''; // WPCS: input var ok, CSRF ok, sanitization ok.
$address['city'] = isset( $_POST['calc_shipping_city'] ) ? wc_clean( wp_unslash( $_POST['calc_shipping_city'] ) ) : ''; // WPCS: input var ok, CSRF ok, sanitization ok.
if ( $address['postcode'] ) {
$address['postcode'] = wc_format_postcode( $address['postcode'], $address['country'] );
}
$address = apply_filters( 'woocommerce_cart_calculate_shipping_address', $address );
if ( $address['postcode'] && ! WC_Validation::is_postcode( $address['postcode'], $address['country'] ) ) {
throw new Exception( __( 'Please enter a valid postcode / ZIP.', 'woocommerce' ) );
} elseif ( $address['postcode'] ) {
$address['postcode'] = wc_format_postcode( $address['postcode'], $address['country'] );
}
if ( $address['country'] ) {

View File

@ -2003,9 +2003,7 @@ function wc_remove_number_precision_deep( $value ) {
* - an instance which will be used directly as the logger
* In either case, the class or instance *must* implement WC_Logger_Interface.
*
* @see WC_Logger_Interface
*
* @return WC_Logger
* @return WC_Logger_Interface
*/
function wc_get_logger() {
static $logger = null;

View File

@ -14,7 +14,7 @@
*
* @see https://woo.com/document/template-structure/
* @package WooCommerce\Templates
* @version 7.8.0
* @version 8.5.0
*/
defined( 'ABSPATH' ) || exit;
@ -97,7 +97,7 @@ do_action( 'woocommerce_before_account_orders', $has_orders ); ?>
<?php else : ?>
<?php wc_print_notice( esc_html__( 'No order has been made yet.', 'woocommerce' ) . ' <a class="woocommerce-Button button' . esc_attr( $wp_button_class ) . '" href="' . esc_url( apply_filters( 'woocommerce_return_to_shop_redirect', wc_get_page_permalink( 'shop' ) ) ) . '">' . esc_html__( 'Browse products', 'woocommerce' ) . '</a>', 'notice' ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment ?>
<?php wc_print_notice( esc_html__( 'No order has been made yet.', 'woocommerce' ) . ' <a class="woocommerce-Button wc-forward button' . esc_attr( $wp_button_class ) . '" href="' . esc_url( apply_filters( 'woocommerce_return_to_shop_redirect', wc_get_page_permalink( 'shop' ) ) ) . '">' . esc_html__( 'Browse products', 'woocommerce' ) . '</a>', 'notice' ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment ?>
<?php endif; ?>

View File

@ -26283,7 +26283,6 @@ packages:
/flow-parser@0.223.3:
resolution: {integrity: sha512-9KxxDKSB22ovMpSULbOL/QAQGPN6M0YMS3PubQvB0jVc4W7QP6VhasIVic7MzKcJSh0BAVs4J6SZjoH0lDDNlg==}
engines: {node: '>=0.4.0'}
dev: true
/flush-write-stream@1.1.1:
resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==}
@ -31875,7 +31874,7 @@ packages:
'@babel/register': 7.22.15(@babel/core@7.23.5)
babel-core: 7.0.0-bridge.0(@babel/core@7.23.5)
chalk: 4.1.2
flow-parser: 0.206.0
flow-parser: 0.223.3
graceful-fs: 4.2.11
micromatch: 4.0.5
neo-async: 2.6.2