diff --git a/packages/form-js-editor/src/features/properties-panel/PropertiesPanel.js b/packages/form-js-editor/src/features/properties-panel/PropertiesPanel.js
index 50314ac4f..80cf47467 100644
--- a/packages/form-js-editor/src/features/properties-panel/PropertiesPanel.js
+++ b/packages/form-js-editor/src/features/properties-panel/PropertiesPanel.js
@@ -3,80 +3,37 @@ import { PropertiesPanel as BasePropertiesPanel } from '@bpmn-io/properties-pane
import {
useCallback,
useMemo,
- useState,
- useLayoutEffect
} from 'preact/hooks';
import { reduce, isArray } from 'min-dash';
-
-import { FormPropertiesPanelContext } from './context';
-
import { PropertiesPanelHeaderProvider } from './PropertiesPanelHeaderProvider';
import { PropertiesPanelPlaceholderProvider } from './PropertiesPanelPlaceholderProvider';
+import { useService } from './hooks';
-export function PropertiesPanel(props) {
- const {
- eventBus,
- getProviders,
- injector
- } = props;
+export function PropertiesPanel() {
- const formEditor = injector.get('formEditor');
- const modeling = injector.get('modeling');
- const selectionModule = injector.get('selection');
- const propertiesPanelConfig = injector.get('config.propertiesPanel') || {};
+ const eventBus = useService('eventBus');
+ const modeling = useService('modeling');
+ const selection = useService('selection');
+ const formEditor = useService('formEditor');
+ const propertiesPanelConfig = useService('config.propertiesPanel') || {};
+ const propertiesProviderRegistry = useService('propertiesProviderRegistry');
const {
feelPopupContainer
} = propertiesPanelConfig;
- const [ state , setState ] = useState({ selectedFormField: selectionModule.get() || formEditor._getState().schema });
-
- const selectedFormField = state.selectedFormField;
-
- const refresh = useCallback((field) => {
-
- // TODO(skaiir): rework state management, re-rendering the whole properties panel is not the way to go
- // https://github.com/bpmn-io/form-js/issues/686
- setState({ selectedFormField: selectionModule.get() || formEditor._getState().schema });
-
- // notify interested parties on property panel updates
- eventBus.fire('propertiesPanel.updated', {
- formField: field
- });
-
- }, [ eventBus, formEditor, selectionModule ]);
-
-
- useLayoutEffect(() => {
-
- /**
- * TODO(pinussilvestrus): update with actual updated element,
- * once we have a proper updater/change support
- */
- eventBus.on('changed', refresh);
- eventBus.on('import.done', refresh);
- eventBus.on('selection.changed', refresh);
-
- return () => {
- eventBus.off('changed', refresh);
- eventBus.off('import.done', refresh);
- eventBus.off('selection.changed', refresh);
- };
- }, [ eventBus, refresh ]);
-
- const getService = (type, strict = true) => injector.get(type, strict);
-
- const propertiesPanelContext = { getService };
-
const onFocus = () => eventBus.fire('propertiesPanel.focusin');
const onBlur = () => eventBus.fire('propertiesPanel.focusout');
const editField = useCallback((formField, key, value) => modeling.editFormField(formField, key, value), [ modeling ]);
- // retrieve groups for selected form field
- const providers = getProviders(selectedFormField);
+ const selectedFormField = selection.get() || formEditor._getState().schema;
+
+ const providers = useMemo(() => {
+ return propertiesProviderRegistry.getProviders(selectedFormField);
+ }, [ propertiesProviderRegistry, selectedFormField ]);
const groups = useMemo(() => {
return reduce(providers, function(groups, provider) {
@@ -93,13 +50,13 @@ export function PropertiesPanel(props) {
}, [ providers, selectedFormField, editField ]);
return (
-
-
+
);
}
\ No newline at end of file
diff --git a/packages/form-js-editor/src/features/properties-panel/PropertiesPanelModule.js b/packages/form-js-editor/src/features/properties-panel/PropertiesPanelModule.js
deleted file mode 100644
index 7deef8984..000000000
--- a/packages/form-js-editor/src/features/properties-panel/PropertiesPanelModule.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { SectionModuleBase } from '../SectionModuleBase';
-
-export class PropertiesPanelModule extends SectionModuleBase {
- constructor(eventBus) { super(eventBus, 'propertiesPanel'); }
-}
-
-PropertiesPanelModule.$inject = [ 'eventBus' ];
\ No newline at end of file
diff --git a/packages/form-js-editor/src/features/properties-panel/PropertiesPanelRenderer.js b/packages/form-js-editor/src/features/properties-panel/PropertiesPanelRenderer.js
index eae163820..e14f3412d 100644
--- a/packages/form-js-editor/src/features/properties-panel/PropertiesPanelRenderer.js
+++ b/packages/form-js-editor/src/features/properties-panel/PropertiesPanelRenderer.js
@@ -1,145 +1,7 @@
-import { PropertiesPanel } from './PropertiesPanel';
+import { SectionModuleBase } from '../SectionModuleBase';
-import {
- render
-} from 'preact';
-
-import {
- domify,
- query as domQuery
-} from 'min-dom';
-
-const DEFAULT_PRIORITY = 1000;
-
-/**
- * @typedef { { parent: Element } } PropertiesPanelConfig
- * @typedef { import('../../core/EventBus').EventBus } EventBus
- * @typedef { import('../../types').Injector } Injector
- * @typedef { { getGroups: ({ formField, editFormField }) => ({ groups}) => Array } } PropertiesProvider
- */
-
-/**
- * @param {PropertiesPanelConfig} propertiesPanelConfig
- * @param {Injector} injector
- * @param {EventBus} eventBus
- */
-export class PropertiesPanelRenderer {
-
- constructor(propertiesPanelConfig, injector, eventBus) {
- const {
- parent
- } = propertiesPanelConfig || {};
-
- this._eventBus = eventBus;
- this._injector = injector;
-
- this._container = domify('');
-
- if (parent) {
- this.attachTo(parent);
- }
-
- this._eventBus.once('formEditor.rendered', 500, () => {
- this._render();
- });
- }
-
-
- /**
- * Attach the properties panel to a parent node.
- *
- * @param {HTMLElement} container
- */
- attachTo(container) {
- if (!container) {
- throw new Error('container required');
- }
-
- if (typeof container === 'string') {
- container = domQuery(container);
- }
-
- // (1) detach from old parent
- this.detach();
-
- // (2) append to parent container
- container.appendChild(this._container);
-
- // (3) notify interested parties
- this._eventBus.fire('propertiesPanel.attach');
- }
-
- /**
- * Detach the properties panel from its parent node.
- */
- detach() {
- const parentNode = this._container.parentNode;
-
- if (parentNode) {
- parentNode.removeChild(this._container);
-
- this._eventBus.fire('propertiesPanel.detach');
- }
- }
-
- _render() {
- render(
- ,
- this._container
- );
-
- this._eventBus.fire('propertiesPanel.rendered');
- }
-
- _destroy() {
- if (this._container) {
- render(null, this._container);
-
- this._eventBus.fire('propertiesPanel.destroyed');
- }
- }
-
- /**
- * Register a new properties provider to the properties panel.
- *
- * @param {PropertiesProvider} provider
- * @param {Number} [priority]
- */
- registerProvider(provider, priority) {
-
- if (!priority) {
- priority = DEFAULT_PRIORITY;
- }
-
- if (typeof provider.getGroups !== 'function') {
- console.error(
- 'Properties provider does not implement #getGroups(element) API'
- );
-
- return;
- }
-
- this._eventBus.on('propertiesPanel.getProviders', priority, function(event) {
- event.providers.push(provider);
- });
-
- this._eventBus.fire('propertiesPanel.providersChanged');
- }
-
- _getProviders() {
- const event = this._eventBus.createEvent({
- type: 'propertiesPanel.getProviders',
- providers: []
- });
-
- this._eventBus.fire(event);
-
- return event.providers;
- }
+export class PropertiesPanelRenderer extends SectionModuleBase {
+ constructor(eventBus) { super(eventBus, 'propertiesPanel'); }
}
-PropertiesPanelRenderer.$inject = [ 'config.propertiesPanel', 'injector', 'eventBus' ];
\ No newline at end of file
+PropertiesPanelRenderer.$inject = [ 'eventBus' ];
\ No newline at end of file
diff --git a/packages/form-js-editor/src/features/properties-panel/PropertiesProvider.js b/packages/form-js-editor/src/features/properties-panel/PropertiesProvider.js
index f73c18f55..13988b9ab 100644
--- a/packages/form-js-editor/src/features/properties-panel/PropertiesProvider.js
+++ b/packages/form-js-editor/src/features/properties-panel/PropertiesProvider.js
@@ -15,9 +15,9 @@ import {
import { hasEntryConfigured } from './Util';
export class PropertiesProvider {
- constructor(propertiesPanel, injector) {
+ constructor(propertiesProviderRegistry, injector) {
this._injector = injector;
- propertiesPanel.registerProvider(this);
+ propertiesProviderRegistry.registerProvider(this);
}
_filterVisibleEntries(groups, field, getService) {
@@ -85,4 +85,4 @@ export class PropertiesProvider {
}
}
-PropertiesProvider.$inject = [ 'propertiesPanel', 'injector' ];
\ No newline at end of file
+PropertiesProvider.$inject = [ 'propertiesProviderRegistry', 'injector' ];
\ No newline at end of file
diff --git a/packages/form-js-editor/src/features/properties-panel/PropertiesProviderRegistry.js b/packages/form-js-editor/src/features/properties-panel/PropertiesProviderRegistry.js
new file mode 100644
index 000000000..4489a08b0
--- /dev/null
+++ b/packages/form-js-editor/src/features/properties-panel/PropertiesProviderRegistry.js
@@ -0,0 +1,56 @@
+const DEFAULT_PRIORITY = 1000;
+
+/**
+ * @typedef { import('../../core/EventBus').EventBus } EventBus
+ * @typedef { { getGroups: ({ formField, editFormField }) => ({ groups}) => Array } } PropertiesProvider
+ */
+
+/**
+ * @param {EventBus} eventBus
+ */
+export class PropertiesProviderRegistry {
+
+ constructor(eventBus) {
+ this._eventBus = eventBus;
+ }
+
+ /**
+ * Register a new properties provider to the properties panel.
+ *
+ * @param {PropertiesProvider} provider
+ * @param {Number} [priority]
+ */
+ registerProvider(provider, priority) {
+
+ if (!priority) {
+ priority = DEFAULT_PRIORITY;
+ }
+
+ if (typeof provider.getGroups !== 'function') {
+ console.error(
+ 'Properties provider does not implement #getGroups(element) API'
+ );
+
+ return;
+ }
+
+ this._eventBus.on('propertiesPanel.getProviders', priority, function(event) {
+ event.providers.push(provider);
+ });
+
+ this._eventBus.fire('propertiesPanel.providersChanged');
+ }
+
+ getProviders() {
+ const event = this._eventBus.createEvent({
+ type: 'propertiesPanel.getProviders',
+ providers: []
+ });
+
+ this._eventBus.fire(event);
+
+ return event.providers;
+ }
+}
+
+PropertiesProviderRegistry.$inject = [ 'eventBus' ];
\ No newline at end of file
diff --git a/packages/form-js-editor/src/features/properties-panel/context/FormPropertiesPanelContext.js b/packages/form-js-editor/src/features/properties-panel/context/FormPropertiesPanelContext.js
deleted file mode 100644
index d82e5bf59..000000000
--- a/packages/form-js-editor/src/features/properties-panel/context/FormPropertiesPanelContext.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { createContext } from 'preact';
-
-/**
- * @param {string} type
- * @param {boolean} [strict]
- *
- * @returns {any}
- */
-function getService(type, strict) {}
-
-export const FormPropertiesPanelContext = createContext({
- getService
-});
diff --git a/packages/form-js-editor/src/features/properties-panel/context/index.js b/packages/form-js-editor/src/features/properties-panel/context/index.js
deleted file mode 100644
index 833d0fb3b..000000000
--- a/packages/form-js-editor/src/features/properties-panel/context/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { FormPropertiesPanelContext } from './FormPropertiesPanelContext';
\ No newline at end of file
diff --git a/packages/form-js-editor/src/features/properties-panel/hooks/index.js b/packages/form-js-editor/src/features/properties-panel/hooks/index.js
index 42d3b01d0..bb2448fbe 100644
--- a/packages/form-js-editor/src/features/properties-panel/hooks/index.js
+++ b/packages/form-js-editor/src/features/properties-panel/hooks/index.js
@@ -1,2 +1,2 @@
export { useVariables } from './useVariables';
-export { useService } from './usePropertiesPanelService';
\ No newline at end of file
+export { useService } from './useService';
\ No newline at end of file
diff --git a/packages/form-js-editor/src/features/properties-panel/hooks/usePropertiesPanelService.js b/packages/form-js-editor/src/features/properties-panel/hooks/usePropertiesPanelService.js
deleted file mode 100644
index 7ea0335d5..000000000
--- a/packages/form-js-editor/src/features/properties-panel/hooks/usePropertiesPanelService.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import {
- useContext
-} from 'preact/hooks';
-
-import { FormPropertiesPanelContext } from '../context';
-
-
-export function useService(type, strict) {
- const {
- getService
- } = useContext(FormPropertiesPanelContext);
-
- return getService(type, strict);
-}
\ No newline at end of file
diff --git a/packages/form-js-editor/src/features/properties-panel/hooks/useService.js b/packages/form-js-editor/src/features/properties-panel/hooks/useService.js
new file mode 100644
index 000000000..c415a72fa
--- /dev/null
+++ b/packages/form-js-editor/src/features/properties-panel/hooks/useService.js
@@ -0,0 +1 @@
+export { useService } from '../../../render/hooks';
\ No newline at end of file
diff --git a/packages/form-js-editor/src/features/properties-panel/hooks/useVariables.js b/packages/form-js-editor/src/features/properties-panel/hooks/useVariables.js
index ed85bff07..cb86aa0bf 100644
--- a/packages/form-js-editor/src/features/properties-panel/hooks/useVariables.js
+++ b/packages/form-js-editor/src/features/properties-panel/hooks/useVariables.js
@@ -1,5 +1,5 @@
import { getSchemaVariables } from '@bpmn-io/form-js-viewer';
-import { useService } from './usePropertiesPanelService';
+import { useService } from './useService';
/**
* Retrieve list of variables from the form schema.
diff --git a/packages/form-js-editor/src/features/properties-panel/index.js b/packages/form-js-editor/src/features/properties-panel/index.js
index 906666564..99c09cdb0 100644
--- a/packages/form-js-editor/src/features/properties-panel/index.js
+++ b/packages/form-js-editor/src/features/properties-panel/index.js
@@ -1,4 +1,5 @@
import { PropertiesPanelRenderer } from './PropertiesPanelRenderer';
+import { PropertiesProviderRegistry } from './PropertiesProviderRegistry';
import { PropertiesProvider } from './PropertiesProvider';
import { FeelPopupModule } from '@bpmn-io/properties-panel';
@@ -9,5 +10,6 @@ export const PropertiesPanelModule = {
],
__init__: [ 'propertiesPanel', 'propertiesProvider' ],
propertiesPanel: [ 'type', PropertiesPanelRenderer ],
- propertiesProvider: [ 'type', PropertiesProvider ]
+ propertiesProvider: [ 'type', PropertiesProvider ],
+ propertiesProviderRegistry: [ 'type', PropertiesProviderRegistry ]
};
\ No newline at end of file
diff --git a/packages/form-js-editor/src/render/components/FormEditor.js b/packages/form-js-editor/src/render/components/FormEditor.js
index c059fd588..0ea648bb6 100644
--- a/packages/form-js-editor/src/render/components/FormEditor.js
+++ b/packages/form-js-editor/src/render/components/FormEditor.js
@@ -31,6 +31,7 @@ import { DeleteIcon, DraggableIcon } from './icons';
import { ModularSection } from './ModularSection';
import { Palette, collectPaletteEntries, getPaletteIcon } from '../../features/palette/components/Palette';
import { InjectedRendersRoot } from '../../features/render-injection/components/InjectedRendersRoot';
+import { PropertiesPanel } from '../../features/properties-panel/PropertiesPanel';
import { SlotFillRoot } from '../../features/render-injection/slot-fill';
@@ -341,9 +342,7 @@ export function FormEditor() {
eventBus = useService('eventBus'),
formEditor = useService('formEditor'),
injector = useService('injector'),
- selection = useService('selection'),
- propertiesPanel = useService('propertiesPanel'),
- propertiesPanelConfig = useService('config.propertiesPanel');
+ selection = useService('selection');
const { schema, properties } = formEditor._getState();
@@ -351,8 +350,6 @@ export function FormEditor() {
const formContainerRef = useRef(null);
- const propertiesPanelRef = useRef(null);
-
const [ , setSelection ] = useState(schema);
const [ hasInitialized, setHasInitialized ] = useState(false);
@@ -494,15 +491,6 @@ export function FormEditor() {
const onReset = useCallback(() => {}, []);
- // attach default properties panel
- const hasDefaultPropertiesPanel = defaultPropertiesPanel(propertiesPanelConfig);
-
- useEffect(() => {
- if (hasDefaultPropertiesPanel) {
- propertiesPanel.attachTo(propertiesPanelRef.current);
- }
- }, [ propertiesPanelRef, propertiesPanel, hasDefaultPropertiesPanel ]);
-
return (
@@ -522,7 +510,9 @@ export function FormEditor() {
- { hasDefaultPropertiesPanel && }
+
+
+
@@ -623,10 +613,6 @@ function findPaletteEntry(type, formFields) {
return collectPaletteEntries(formFields).find(entry => entry.type === type);
}
-function defaultPropertiesPanel(propertiesPanelConfig) {
- return !(propertiesPanelConfig && propertiesPanelConfig.parent);
-}
-
function getRemoveButtonTitle(formField, formFields) {
const entry = findPaletteEntry(formField.type, formFields);
diff --git a/packages/form-js-playground/test/custom/editor.js b/packages/form-js-playground/test/custom/editor.js
index f659dd821..2eef5f420 100644
--- a/packages/form-js-playground/test/custom/editor.js
+++ b/packages/form-js-playground/test/custom/editor.js
@@ -7,8 +7,8 @@ import {
class CustomPropertiesProvider {
- constructor(propertiesPanel) {
- propertiesPanel.registerProvider(this, 500);
+ constructor(propertiesProviderRegistry) {
+ propertiesProviderRegistry.registerProvider(this, 500);
}
getGroups(field, editField) {
@@ -31,7 +31,7 @@ class CustomPropertiesProvider {
}
}
-CustomPropertiesProvider.$inject = [ 'propertiesPanel' ];
+CustomPropertiesProvider.$inject = [ 'propertiesProviderRegistry' ];
function RangeEntries(field, editField) {