From ac6197ea7154c3aa322df0f724fbbfcd1c873f3b Mon Sep 17 00:00:00 2001 From: Rostislav Wolny Date: Tue, 26 Sep 2023 16:04:49 +0200 Subject: [PATCH] Add store and main sidebar with block inspector [MAILPOET-5603] --- .../components/block-editor/block-editor.tsx | 6 +++ .../engine/components/header/header.tsx | 7 ++- .../engine/components/sidebar/sidebar.tsx | 33 +++++++++++++ .../src/email_editor_custom/engine/editor.tsx | 26 +++++++++- .../engine/store/actions.ts | 17 +++++++ .../engine/store/constants.ts | 3 ++ .../email_editor_custom/engine/store/index.ts | 3 ++ .../engine/store/initial_state.ts | 9 ++++ .../engine/store/reducer.ts | 16 +++++++ .../engine/store/selectors.ts | 8 ++++ .../email_editor_custom/engine/store/store.ts | 47 +++++++++++++++++++ .../email_editor_custom/engine/store/types.ts | 5 ++ .../assets/js/src/types/wordpress-modules.ts | 2 + 13 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 mailpoet/assets/js/src/email_editor_custom/engine/components/sidebar/sidebar.tsx create mode 100644 mailpoet/assets/js/src/email_editor_custom/engine/store/actions.ts create mode 100644 mailpoet/assets/js/src/email_editor_custom/engine/store/constants.ts create mode 100644 mailpoet/assets/js/src/email_editor_custom/engine/store/index.ts create mode 100644 mailpoet/assets/js/src/email_editor_custom/engine/store/initial_state.ts create mode 100644 mailpoet/assets/js/src/email_editor_custom/engine/store/reducer.ts create mode 100644 mailpoet/assets/js/src/email_editor_custom/engine/store/selectors.ts create mode 100644 mailpoet/assets/js/src/email_editor_custom/engine/store/store.ts create mode 100644 mailpoet/assets/js/src/email_editor_custom/engine/store/types.ts diff --git a/mailpoet/assets/js/src/email_editor_custom/engine/components/block-editor/block-editor.tsx b/mailpoet/assets/js/src/email_editor_custom/engine/components/block-editor/block-editor.tsx index 3d777ca24d..0590c9f615 100644 --- a/mailpoet/assets/js/src/email_editor_custom/engine/components/block-editor/block-editor.tsx +++ b/mailpoet/assets/js/src/email_editor_custom/engine/components/block-editor/block-editor.tsx @@ -1,6 +1,7 @@ import { BlockEditorKeyboardShortcuts, BlockEditorProvider, + BlockInspector, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore No types for this exist yet. BlockTools, @@ -10,6 +11,8 @@ import { } from '@wordpress/block-editor'; import { useState } from '@wordpress/element'; +import { Sidebar } from '../sidebar/sidebar'; + export function BlockEditor() { const [documentBlocks, updateBlocks] = useState([]); @@ -33,6 +36,9 @@ export function BlockEditor() { onChange={(blocks) => updateBlocks(blocks)} settings={{}} > + + +
{/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} {/* @ts-ignore BlockEditorKeyboardShortcuts.Register has no types */} diff --git a/mailpoet/assets/js/src/email_editor_custom/engine/components/header/header.tsx b/mailpoet/assets/js/src/email_editor_custom/engine/components/header/header.tsx index 277871cada..ef331f76fa 100644 --- a/mailpoet/assets/js/src/email_editor_custom/engine/components/header/header.tsx +++ b/mailpoet/assets/js/src/email_editor_custom/engine/components/header/header.tsx @@ -1,3 +1,6 @@ +import { PinnedItems } from '@wordpress/interface'; +import { storeName } from '../../store'; + export function Header() { return (
@@ -5,7 +8,9 @@ export function Header() {
Todo Inserter etc.
Todo Email Name
-
Todo Actions
+
+ +
); } diff --git a/mailpoet/assets/js/src/email_editor_custom/engine/components/sidebar/sidebar.tsx b/mailpoet/assets/js/src/email_editor_custom/engine/components/sidebar/sidebar.tsx new file mode 100644 index 0000000000..74780a8924 --- /dev/null +++ b/mailpoet/assets/js/src/email_editor_custom/engine/components/sidebar/sidebar.tsx @@ -0,0 +1,33 @@ +import { createSlotFill, Panel } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { ComplementaryArea } from '@wordpress/interface'; +import { ComponentProps } from 'react'; +import { storeName, mainSidebarKey } from 'email_editor_custom/engine/store'; +import { drawerRight } from '@wordpress/icons'; + +const { Slot: InspectorSlot, Fill: InspectorFill } = createSlotFill( + 'EmailEditorBlockInspector', +); + +type Props = ComponentProps; + +export function Sidebar(props: Props): JSX.Element { + return ( + Todo header} + icon={drawerRight} + scope={storeName} + smallScreenTitle={__('No title', 'mailpoet')} + isActiveByDefault + {...props} + > + + + + + ); +} + +Sidebar.InspectorFill = InspectorFill; diff --git a/mailpoet/assets/js/src/email_editor_custom/engine/editor.tsx b/mailpoet/assets/js/src/email_editor_custom/engine/editor.tsx index 9b0a3b83a5..f3d2f33939 100644 --- a/mailpoet/assets/js/src/email_editor_custom/engine/editor.tsx +++ b/mailpoet/assets/js/src/email_editor_custom/engine/editor.tsx @@ -1,17 +1,38 @@ -import { InterfaceSkeleton } from '@wordpress/interface'; +import classnames from 'classnames'; +import { useSelect } from '@wordpress/data'; +import { InterfaceSkeleton, ComplementaryArea } from '@wordpress/interface'; import { StrictMode, createRoot } from '@wordpress/element'; import { registerCoreBlocks } from '@wordpress/block-library'; import { Popover, SlotFillProvider } from '@wordpress/components'; import { ShortcutProvider } from '@wordpress/keyboard-shortcuts'; import { Header } from './components/header'; import { BlockEditor } from './components/block-editor'; +import { Sidebar } from './components/sidebar/sidebar'; +import { createStore, storeName } from './store'; function Editor() { + const { isSidebarOpened } = useSelect( + (select) => ({ + isSidebarOpened: select(storeName).isSidebarOpened(), + }), + [], + ); + + const className = classnames('interface-interface-skeleton', { + 'is-sidebar-opened': isSidebarOpened, + }); + return ( - } content={} /> + + } + content={} + sidebar={} + /> @@ -20,6 +41,7 @@ function Editor() { } export function initialize(elementId: string) { + createStore(); const container = document.getElementById(elementId); if (!container) { return; diff --git a/mailpoet/assets/js/src/email_editor_custom/engine/store/actions.ts b/mailpoet/assets/js/src/email_editor_custom/engine/store/actions.ts new file mode 100644 index 0000000000..ecfaff42da --- /dev/null +++ b/mailpoet/assets/js/src/email_editor_custom/engine/store/actions.ts @@ -0,0 +1,17 @@ +import { dispatch } from '@wordpress/data'; +import { store as interfaceStore } from '@wordpress/interface'; +import { storeName } from './constants'; + +export function toggleInserterSidebar() { + return { + type: 'TOGGLE_INSERTER_SIDEBAR', + } as const; +} + +export const openSidebar = () => { + dispatch(interfaceStore).enableComplementaryArea(storeName); +}; + +export const closeSidebar = () => { + dispatch(interfaceStore).disableComplementaryArea(storeName); +}; diff --git a/mailpoet/assets/js/src/email_editor_custom/engine/store/constants.ts b/mailpoet/assets/js/src/email_editor_custom/engine/store/constants.ts new file mode 100644 index 0000000000..30f2cfe550 --- /dev/null +++ b/mailpoet/assets/js/src/email_editor_custom/engine/store/constants.ts @@ -0,0 +1,3 @@ +export const storeName = 'email-editor/editor'; + +export const mainSidebarKey = 'email-editor/editor/main'; diff --git a/mailpoet/assets/js/src/email_editor_custom/engine/store/index.ts b/mailpoet/assets/js/src/email_editor_custom/engine/store/index.ts new file mode 100644 index 0000000000..d08c8ff609 --- /dev/null +++ b/mailpoet/assets/js/src/email_editor_custom/engine/store/index.ts @@ -0,0 +1,3 @@ +export * from './constants'; +export * from './store'; +export * from './types'; diff --git a/mailpoet/assets/js/src/email_editor_custom/engine/store/initial_state.ts b/mailpoet/assets/js/src/email_editor_custom/engine/store/initial_state.ts new file mode 100644 index 0000000000..e51decfa05 --- /dev/null +++ b/mailpoet/assets/js/src/email_editor_custom/engine/store/initial_state.ts @@ -0,0 +1,9 @@ +import { State } from './types'; + +export function getInitialState(): State { + return { + inserterSidebar: { + isOpened: false, + }, + }; +} diff --git a/mailpoet/assets/js/src/email_editor_custom/engine/store/reducer.ts b/mailpoet/assets/js/src/email_editor_custom/engine/store/reducer.ts new file mode 100644 index 0000000000..db530081b1 --- /dev/null +++ b/mailpoet/assets/js/src/email_editor_custom/engine/store/reducer.ts @@ -0,0 +1,16 @@ +import { State } from './types'; + +export function reducer(state: State, action): State { + switch (action.type) { + case 'TOGGLE_INSERTER_SIDEBAR': + return { + ...state, + inserterSidebar: { + ...state.inserterSidebar, + isOpened: !state.inserterSidebar.isOpened, + }, + }; + default: + return state; + } +} diff --git a/mailpoet/assets/js/src/email_editor_custom/engine/store/selectors.ts b/mailpoet/assets/js/src/email_editor_custom/engine/store/selectors.ts new file mode 100644 index 0000000000..967dee8012 --- /dev/null +++ b/mailpoet/assets/js/src/email_editor_custom/engine/store/selectors.ts @@ -0,0 +1,8 @@ +import { createRegistrySelector } from '@wordpress/data'; +import { store as interfaceStore } from '@wordpress/interface'; +import { storeName } from './constants'; + +export const isSidebarOpened = createRegistrySelector( + (select) => (): boolean => + !!select(interfaceStore).getActiveComplementaryArea(storeName), +); diff --git a/mailpoet/assets/js/src/email_editor_custom/engine/store/store.ts b/mailpoet/assets/js/src/email_editor_custom/engine/store/store.ts new file mode 100644 index 0000000000..3d515de8d3 --- /dev/null +++ b/mailpoet/assets/js/src/email_editor_custom/engine/store/store.ts @@ -0,0 +1,47 @@ +import { createReduxStore, register } from '@wordpress/data'; +import { + ReduxStoreConfig, + StoreDescriptor as GenericStoreDescriptor, +} from '@wordpress/data/build-types/types'; +import { controls } from '@wordpress/data-controls'; +import * as actions from './actions'; +import { storeName } from './constants'; +import { getInitialState } from './initial_state'; +import { reducer } from './reducer'; +import * as selectors from './selectors'; + +const getConfig = () => + ({ + actions, + controls, + selectors, + reducer, + initialState: getInitialState(), + } as const); + +export type EditorStoreConfig = ReturnType; + +export const createStore = () => { + const store = createReduxStore(storeName, getConfig()); + register(store); + return store; +}; + +export interface EmailEditorStore { + getActions(): EditorStoreConfig['actions']; + getSelectors(): EditorStoreConfig['selectors']; +} + +declare module '@wordpress/data' { + interface StoreMap { + [storeName]: GenericStoreDescriptor< + ReduxStoreConfig< + unknown, + ReturnType, + ReturnType + > + >; + } +} + +export { actions, selectors }; diff --git a/mailpoet/assets/js/src/email_editor_custom/engine/store/types.ts b/mailpoet/assets/js/src/email_editor_custom/engine/store/types.ts new file mode 100644 index 0000000000..cbfe98c46a --- /dev/null +++ b/mailpoet/assets/js/src/email_editor_custom/engine/store/types.ts @@ -0,0 +1,5 @@ +export type State = { + inserterSidebar: { + isOpened: boolean; + }; +}; diff --git a/mailpoet/assets/js/src/types/wordpress-modules.ts b/mailpoet/assets/js/src/types/wordpress-modules.ts index 5cd5029caf..d6d8d6dfed 100644 --- a/mailpoet/assets/js/src/types/wordpress-modules.ts +++ b/mailpoet/assets/js/src/types/wordpress-modules.ts @@ -48,9 +48,11 @@ declare module '@wordpress/edit-post' { // there are no @types/wordpress__interface yet declare module '@wordpress/interface' { import { StoreDescriptor } from '@wordpress/data/build-types/types'; + import * as interfaceActions from '@wordpress/interface/src/store/actions'; export const store: { name: 'core/interface' } & StoreDescriptor<{ reducer: () => unknown; + actions: typeof interfaceActions; selectors: { getActiveComplementaryArea: ( state: unknown,