Add store and main sidebar with block inspector

[MAILPOET-5603]
This commit is contained in:
Rostislav Wolny
2023-09-26 16:04:49 +02:00
committed by Aschepikov
parent 07576b9f79
commit ac6197ea71
13 changed files with 179 additions and 3 deletions

View File

@@ -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={{}}
>
<Sidebar.InspectorFill>
<BlockInspector />
</Sidebar.InspectorFill>
<div className="editor-styles-wrapper">
{/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
{/* @ts-ignore BlockEditorKeyboardShortcuts.Register has no types */}

View File

@@ -1,3 +1,6 @@
import { PinnedItems } from '@wordpress/interface';
import { storeName } from '../../store';
export function Header() {
return (
<div className="edit-post-header">
@@ -5,7 +8,9 @@ export function Header() {
<div className="edit-post-header-toolbar">Todo Inserter etc.</div>
<div className="edit-post-header__center">Todo Email Name</div>
</div>
<div className="edit-post-header__settings">Todo Actions</div>
<div className="edit-post-header__settings">
<PinnedItems.Slot scope={storeName} />
</div>
</div>
);
}

View File

@@ -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<typeof ComplementaryArea>;
export function Sidebar(props: Props): JSX.Element {
return (
<ComplementaryArea
identifier={mainSidebarKey}
className="edit-post-sidebar"
header={<h2>Todo header</h2>}
icon={drawerRight}
scope={storeName}
smallScreenTitle={__('No title', 'mailpoet')}
isActiveByDefault
{...props}
>
<Panel header={__('Inspector')}>
<InspectorSlot bubblesVirtually />
</Panel>
</ComplementaryArea>
);
}
Sidebar.InspectorFill = InspectorFill;

View File

@@ -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 (
<StrictMode>
<ShortcutProvider>
<SlotFillProvider>
<InterfaceSkeleton header={<Header />} content={<BlockEditor />} />
<Sidebar />
<InterfaceSkeleton
className={className}
header={<Header />}
content={<BlockEditor />}
sidebar={<ComplementaryArea.Slot scope={storeName} />}
/>
<Popover.Slot />
</SlotFillProvider>
</ShortcutProvider>
@@ -20,6 +41,7 @@ function Editor() {
}
export function initialize(elementId: string) {
createStore();
const container = document.getElementById(elementId);
if (!container) {
return;

View File

@@ -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);
};

View File

@@ -0,0 +1,3 @@
export const storeName = 'email-editor/editor';
export const mainSidebarKey = 'email-editor/editor/main';

View File

@@ -0,0 +1,3 @@
export * from './constants';
export * from './store';
export * from './types';

View File

@@ -0,0 +1,9 @@
import { State } from './types';
export function getInitialState(): State {
return {
inserterSidebar: {
isOpened: false,
},
};
}

View File

@@ -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;
}
}

View File

@@ -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),
);

View File

@@ -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<typeof getConfig>;
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<EmailEditorStore['getActions']>,
ReturnType<EmailEditorStore['getSelectors']>
>
>;
}
}
export { actions, selectors };

View File

@@ -0,0 +1,5 @@
export type State = {
inserterSidebar: {
isOpened: boolean;
};
};

View File

@@ -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,