@craftercms/studio-ui
Version:
Services, components, models & utils to build CrafterCMS authoring extensions.
207 lines (205 loc) • 7.55 kB
JavaScript
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useState } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import List from '@mui/material/List';
import MenuItem from '@mui/material/MenuItem';
import Menu from '@mui/material/Menu';
import { getHostToGuestBus } from '../../utils/subjects';
import {
componentDragEnded,
componentDragStarted,
contentTypeDropTargetsRequest,
pushIcePanelPage,
setContentTypeFilter,
setPreviewEditMode
} from '../../state/actions/preview';
import { nnou, reversePluckProps } from '../../utils/object';
import { DraggablePanelListItem } from '../DraggablePanelListItem/DraggablePanelListItem';
import { useDispatch } from 'react-redux';
import { SuspenseWithEmptyState } from '../Suspencified/Suspencified';
import { batchActions } from '../../state/actions/misc';
import { createToolsPanelPage, createWidgetDescriptor } from '../../utils/state';
import { useSelection } from '../../hooks/useSelection';
import { useSelectorResource } from '../../hooks/useSelectorResource';
const translations = defineMessages({
previewComponentsPanelTitle: {
id: 'previewComponentsPanel.title',
defaultMessage: 'Add Components'
},
browse: {
id: 'previewComponentsPanel.browse',
defaultMessage: 'Browse existing'
},
listDropTargets: {
id: 'previewComponentsPanel.listDropTargets',
defaultMessage: 'List drop targets'
},
listInPageInstances: {
id: 'previewComponentsPanel.listInPageInstances',
defaultMessage: 'Instances on this page'
}
});
export function PreviewComponentsPanel() {
const resource = useSelectorResource((state) => state.contentTypes, {
shouldRenew: (source, resource) => resource.complete,
shouldResolve: (source) => !source.isFetching && nnou(source.byId),
shouldReject: (source) => nnou(source.error),
errorSelector: (source) => source.error,
resultSelector: (source) =>
Object.values(reversePluckProps(source.byId, '/component/level-descriptor')).filter(
(contentType) => contentType.type === 'component'
)
});
return React.createElement(
React.Fragment,
null,
React.createElement(
SuspenseWithEmptyState,
{
resource: resource,
loadingStateProps: {
title: React.createElement(FormattedMessage, {
id: 'componentsPanel.suspenseStateMessage',
defaultMessage: 'Retrieving Page Model'
})
},
withEmptyStateProps: {
emptyStateProps: {
title: React.createElement(FormattedMessage, {
id: 'componentsPanel.emptyStateMessage',
defaultMessage: 'No components found'
}),
subtitle: React.createElement(FormattedMessage, {
id: 'componentsPanel.emptyComponentsSubtitle',
defaultMessage: 'Communicate with your developers to create the required components in the system.'
})
}
}
},
React.createElement(ComponentsPanelUI, { resource: resource })
)
);
}
export const ComponentsPanelUI = (props) => {
const { resource } = props;
const componentTypes = resource.read();
const dispatch = useDispatch();
const { formatMessage } = useIntl();
const editMode = useSelection((state) => state.preview.editMode);
const hostToGuest$ = getHostToGuestBus();
const [menuContext, setMenuContext] = useState();
const onDragStart = (contentType) => {
if (!editMode) {
dispatch(setPreviewEditMode({ editMode: true }));
}
hostToGuest$.next({ type: componentDragStarted.type, payload: contentType });
};
const onDragEnd = () => hostToGuest$.next({ type: componentDragEnded.type });
const onMenuClose = () => setMenuContext(null);
const onBrowseSharedInstancesClicked = () => {
dispatch(
batchActions([
setContentTypeFilter(menuContext.contentType.id),
pushIcePanelPage(
createToolsPanelPage(
{ id: 'previewBrowseComponentsPanel.title' },
[createWidgetDescriptor({ id: 'craftercms.components.PreviewBrowseComponentsPanel' })],
'icePanel'
)
)
])
);
};
const onListInPageInstancesClick = () => {
dispatch(
batchActions([
setContentTypeFilter(menuContext.contentType.id),
pushIcePanelPage(
createToolsPanelPage(
{ id: 'previewInPageInstancesPanel.title' },
[createWidgetDescriptor({ id: 'craftercms.components.PreviewInPageInstancesPanel' })],
'icePanel'
)
)
])
);
};
const onListDropTargetsClick = () => {
dispatch(
pushIcePanelPage(
createToolsPanelPage(
{ id: 'previewDropTargetsPanel.title', defaultMessage: 'Component Drop Targets' },
[createWidgetDescriptor({ id: 'craftercms.components.PreviewDropTargetsPanel' })],
'icePanel'
)
)
);
hostToGuest$.next({
type: contentTypeDropTargetsRequest.type,
payload: menuContext.contentType.id
});
};
return React.createElement(
React.Fragment,
null,
React.createElement(
List,
null,
componentTypes.map((contentType) =>
React.createElement(DraggablePanelListItem, {
key: contentType.id,
primaryText: contentType.name,
secondaryText: contentType.id,
onDragStart: () => onDragStart(contentType),
onDragEnd: onDragEnd,
onMenu: (anchor) => setMenuContext({ anchor, contentType })
})
)
),
React.createElement(
Menu,
{
open: !!menuContext,
anchorEl: menuContext === null || menuContext === void 0 ? void 0 : menuContext.anchor,
onClose: onMenuClose
},
React.createElement(
MenuItem,
{ onClick: onListInPageInstancesClick },
formatMessage(translations.listInPageInstances)
),
React.createElement(MenuItem, { onClick: onBrowseSharedInstancesClicked }, formatMessage(translations.browse)),
React.createElement(MenuItem, { onClick: onListDropTargetsClick }, formatMessage(translations.listDropTargets))
)
);
};
export default PreviewComponentsPanel;