@craftercms/studio-ui
Version:
Services, components, models & utils to build CrafterCMS authoring extensions.
125 lines (123 loc) • 4.8 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, { lazy, memo } from 'react';
import NonReactWidget from '../NonReactWidget/NonReactWidget';
import { buildFileUrl, importPlugin } from '../../services/plugin';
import { components } from '../../utils/constants';
import EmptyState from '../EmptyState/EmptyState';
import { defineMessages, useIntl } from 'react-intl';
import ErrorState from '../ErrorState';
import { isValidElementType } from 'react-is';
const messages = defineMessages({
componentNotFoundTitle: {
id: 'widgetComponent.componentNotFoundTitle',
defaultMessage: 'Component {id} not found.'
},
componentNotFoundSubtitle: {
id: 'widgetComponent.componentNotFoundSubtitle',
defaultMessage: "Check ui config & make sure you've installed the plugins that contain the desired components."
},
pluginLoadFailedMessageTitle: {
id: 'widgetComponent.pluginLoadFailedMessageTitle',
defaultMessage: 'Plugin load failed'
},
pluginLoadFailedMessageBody: {
id: 'widgetComponent.pluginLoadFailedMessageBody',
defaultMessage: 'With {info} & component id "{id}".'
}
});
const cache = {};
const Widget = memo(function (props) {
const { id, plugin, configuration } = props;
const record = components.get(id);
const { formatMessage } = useIntl();
if (record) {
if (isValidElementType(record)) {
const Component = record;
return React.createElement(Component, { ...props.defaultProps, ...configuration, ...props.overrideProps });
} else {
return React.createElement(NonReactWidget, {
widget: record,
configuration: { ...props.defaultProps, ...configuration, ...props.overrideProps }
});
}
} else if (!plugin) {
return React.createElement(EmptyState, {
title: formatMessage(messages.componentNotFoundTitle, { id }),
subtitle: formatMessage(messages.componentNotFoundSubtitle),
styles: { image: { width: 100 } }
});
} else {
let Component;
const fileUrl = buildFileUrl(plugin);
if (fileUrl in cache) {
Component = cache[fileUrl];
} else {
cache[fileUrl] = Component = lazy(() =>
importPlugin(plugin).then(
() => ({
default: function (props) {
if (components.has(id)) {
return React.createElement(Widget, { ...props });
} else {
return React.createElement(EmptyState, {
title: formatMessage(messages.componentNotFoundTitle, { id }),
subtitle: formatMessage(messages.componentNotFoundSubtitle),
styles: { image: { width: 100 } }
});
}
}
}),
(error) => {
console.error(error);
return {
default: function ({ id, plugin }) {
return React.createElement(ErrorState, {
styles: { image: { width: 100 } },
title: formatMessage(messages.pluginLoadFailedMessageTitle),
message: formatMessage(messages.pluginLoadFailedMessageBody, {
id,
info: Object.entries(plugin)
.map(([key, value]) => `${key} "${value}"`)
.join(', ')
})
});
}
};
}
)
);
}
return React.createElement(Component, { ...props });
}
});
export { Widget };
export default Widget;