@bpmn-io/form-js-editor 1.20.1 → 1.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/form-js-editor-base.css +1 -0
- package/dist/assets/form-js-editor.css +1 -0
- package/dist/index.cjs +207 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +207 -4
- package/dist/index.es.js.map +1 -1
- package/dist/types/FormEditor.d.ts +1 -0
- package/dist/types/features/render-injection/SlotFillManager.d.ts +85 -0
- package/dist/types/features/render-injection/index.d.ts +2 -0
- package/dist/types/features/render-injection/slot-fill/Slot.d.ts +5 -5
- package/package.json +5 -5
package/dist/index.es.js
CHANGED
|
@@ -1353,7 +1353,26 @@ const Slot = props => {
|
|
|
1353
1353
|
const fillsAndSeparators = useMemo(() => {
|
|
1354
1354
|
return buildFills(groups, fillRoot, separatorFn);
|
|
1355
1355
|
}, [groups, fillRoot, separatorFn]);
|
|
1356
|
-
|
|
1356
|
+
|
|
1357
|
+
// Framework-agnostic fills from SlotFillManager
|
|
1358
|
+
const editorContext = useContext(FormEditorContext);
|
|
1359
|
+
const slotFillManager = editorContext ? editorContext.getService('slotFillManager', false) : null;
|
|
1360
|
+
const eventBus = editorContext ? editorContext.getService('eventBus', false) : null;
|
|
1361
|
+
const [managerFills, setManagerFills] = useState([]);
|
|
1362
|
+
useEffect(() => {
|
|
1363
|
+
if (!eventBus || !slotFillManager) {
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
setManagerFills(slotFillManager.getFills(name));
|
|
1367
|
+
const onChange = () => setManagerFills(slotFillManager.getFills(name));
|
|
1368
|
+
eventBus.on('slotFillManager.changed', onChange);
|
|
1369
|
+
return () => eventBus.off('slotFillManager.changed', onChange);
|
|
1370
|
+
}, [eventBus, slotFillManager, name]);
|
|
1371
|
+
return jsxs(Fragment, {
|
|
1372
|
+
children: [fillsAndSeparators, managerFills.map(fill => jsx(FillContainer, {
|
|
1373
|
+
fill: fill
|
|
1374
|
+
}, fill.fillId))]
|
|
1375
|
+
});
|
|
1357
1376
|
};
|
|
1358
1377
|
|
|
1359
1378
|
/**
|
|
@@ -1366,6 +1385,34 @@ const FillFragment = fill => jsx(Fragment, {
|
|
|
1366
1385
|
children: fill.children
|
|
1367
1386
|
}, fill.id);
|
|
1368
1387
|
|
|
1388
|
+
/**
|
|
1389
|
+
* Mounts a single SlotFillManager fill's render callback into a DOM container.
|
|
1390
|
+
*/
|
|
1391
|
+
function FillContainer({
|
|
1392
|
+
fill
|
|
1393
|
+
}) {
|
|
1394
|
+
const containerRef = useRef(null);
|
|
1395
|
+
const cleanupRef = useRef(null);
|
|
1396
|
+
useEffect(() => {
|
|
1397
|
+
const container = containerRef.current;
|
|
1398
|
+
if (!container) {
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1401
|
+
cleanupRef.current = fill.render(container) || null;
|
|
1402
|
+
return () => {
|
|
1403
|
+
if (typeof cleanupRef.current === 'function') {
|
|
1404
|
+
cleanupRef.current();
|
|
1405
|
+
cleanupRef.current = null;
|
|
1406
|
+
}
|
|
1407
|
+
container.innerHTML = '';
|
|
1408
|
+
};
|
|
1409
|
+
}, [fill]);
|
|
1410
|
+
return jsx("div", {
|
|
1411
|
+
ref: containerRef,
|
|
1412
|
+
"data-slot-fill": fill.fillId
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1369
1416
|
/**
|
|
1370
1417
|
* Creates an array of fills, with separators inserted between groups.
|
|
1371
1418
|
*
|
|
@@ -2244,6 +2291,8 @@ function EmptyForm() {
|
|
|
2244
2291
|
children: "Drag and drop components here to start designing."
|
|
2245
2292
|
}), jsx("span", {
|
|
2246
2293
|
children: "Use the preview window to test your form."
|
|
2294
|
+
}), jsx(Slot, {
|
|
2295
|
+
name: "editor-empty-state__footer"
|
|
2247
2296
|
})]
|
|
2248
2297
|
})
|
|
2249
2298
|
});
|
|
@@ -2549,7 +2598,8 @@ function FormEditor$1() {
|
|
|
2549
2598
|
Element: Element$1,
|
|
2550
2599
|
Empty,
|
|
2551
2600
|
Row,
|
|
2552
|
-
hoverInfo: {}
|
|
2601
|
+
hoverInfo: {},
|
|
2602
|
+
applyVisibilityConditions: false
|
|
2553
2603
|
}), []);
|
|
2554
2604
|
const formContext = useMemo(() => ({
|
|
2555
2605
|
getService(type, strict = true) {
|
|
@@ -14249,9 +14299,162 @@ class RenderInjector extends SectionModuleBase {
|
|
|
14249
14299
|
}
|
|
14250
14300
|
RenderInjector.$inject = ['eventBus'];
|
|
14251
14301
|
|
|
14302
|
+
/**
|
|
14303
|
+
* Framework-agnostic service for managing slot fills.
|
|
14304
|
+
*
|
|
14305
|
+
* Fills are registered as render callbacks: `(container: HTMLElement) => (() => void) | void`.
|
|
14306
|
+
* The optional return value is a cleanup function called when the fill is removed or the slot unmounts.
|
|
14307
|
+
*
|
|
14308
|
+
* @example
|
|
14309
|
+
*
|
|
14310
|
+
* // Via config (simplest):
|
|
14311
|
+
* new FormEditor({
|
|
14312
|
+
* slots: {
|
|
14313
|
+
* 'editor-empty-state__footer': (container) => {
|
|
14314
|
+
* container.textContent = 'Hello from vanilla JS';
|
|
14315
|
+
* }
|
|
14316
|
+
* }
|
|
14317
|
+
* });
|
|
14318
|
+
*
|
|
14319
|
+
* // Via config (multiple fills per slot):
|
|
14320
|
+
* new FormEditor({
|
|
14321
|
+
* slots: {
|
|
14322
|
+
* 'editor-empty-state__footer': [
|
|
14323
|
+
* (container) => { container.textContent = 'First'; },
|
|
14324
|
+
* { render: (container) => { container.textContent = 'Second'; }, priority: 10 }
|
|
14325
|
+
* ]
|
|
14326
|
+
* }
|
|
14327
|
+
* });
|
|
14328
|
+
*
|
|
14329
|
+
* // Via service (runtime):
|
|
14330
|
+
* const slotFillManager = editor.get('slotFillManager');
|
|
14331
|
+
* slotFillManager.addFill('editor-empty-state__footer', 'my-fill', {
|
|
14332
|
+
* render: (container) => { ... },
|
|
14333
|
+
* priority: 10,
|
|
14334
|
+
* group: 'custom'
|
|
14335
|
+
* });
|
|
14336
|
+
*/
|
|
14337
|
+
class SlotFillManager {
|
|
14338
|
+
/**
|
|
14339
|
+
* @param {Object} slotsConfig
|
|
14340
|
+
* @param {import('../../core/EventBus').EventBus} eventBus
|
|
14341
|
+
*/
|
|
14342
|
+
constructor(slotsConfig, eventBus) {
|
|
14343
|
+
this._eventBus = eventBus;
|
|
14344
|
+
|
|
14345
|
+
/** @type {Array<{ slotName: string, fillId: string, render: Function, priority: number, group: string }>} */
|
|
14346
|
+
this._fills = [];
|
|
14347
|
+
this._populateFromConfig(slotsConfig);
|
|
14348
|
+
}
|
|
14349
|
+
|
|
14350
|
+
/**
|
|
14351
|
+
* Register a fill for a named slot.
|
|
14352
|
+
*
|
|
14353
|
+
* @param {string} slotName - The slot to fill.
|
|
14354
|
+
* @param {string} fillId - Unique identifier for this fill.
|
|
14355
|
+
* @param {Function|Object} options - A render callback `(container) => cleanup`, or `{ render, priority?, group? }`.
|
|
14356
|
+
*/
|
|
14357
|
+
addFill(slotName, fillId, options) {
|
|
14358
|
+
const fill = normalizeFill(slotName, fillId, options);
|
|
14359
|
+
this._fills = [...this._fills.filter(f => f.fillId !== fillId), fill];
|
|
14360
|
+
this._eventBus.fire('slotFillManager.changed');
|
|
14361
|
+
}
|
|
14362
|
+
|
|
14363
|
+
/**
|
|
14364
|
+
* Remove a fill by its ID.
|
|
14365
|
+
*
|
|
14366
|
+
* @param {string} fillId
|
|
14367
|
+
*/
|
|
14368
|
+
removeFill(fillId) {
|
|
14369
|
+
const remaining = this._fills.filter(f => f.fillId !== fillId);
|
|
14370
|
+
if (remaining.length === this._fills.length) {
|
|
14371
|
+
return;
|
|
14372
|
+
}
|
|
14373
|
+
this._fills = remaining;
|
|
14374
|
+
this._eventBus.fire('slotFillManager.changed');
|
|
14375
|
+
}
|
|
14376
|
+
|
|
14377
|
+
/**
|
|
14378
|
+
* Get fills for a given slot, sorted by group (alphabetical) then priority (descending).
|
|
14379
|
+
*
|
|
14380
|
+
* @param {string} slotName
|
|
14381
|
+
* @returns {Array<{ slotName: string, fillId: string, render: Function, priority: number, group: string }>}
|
|
14382
|
+
*/
|
|
14383
|
+
getFills(slotName) {
|
|
14384
|
+
const matching = this._fills.filter(f => f.slotName === slotName);
|
|
14385
|
+
return sortFills(matching);
|
|
14386
|
+
}
|
|
14387
|
+
|
|
14388
|
+
/**
|
|
14389
|
+
* @private
|
|
14390
|
+
*/
|
|
14391
|
+
_populateFromConfig(slotsConfig) {
|
|
14392
|
+
Object.entries(slotsConfig || {}).forEach(([slotName, value]) => {
|
|
14393
|
+
if (Array.isArray(value)) {
|
|
14394
|
+
value.forEach((entry, index) => {
|
|
14395
|
+
this.addFill(slotName, `config__${slotName}_${index}`, entry);
|
|
14396
|
+
});
|
|
14397
|
+
} else {
|
|
14398
|
+
this.addFill(slotName, `config__${slotName}`, value);
|
|
14399
|
+
}
|
|
14400
|
+
});
|
|
14401
|
+
}
|
|
14402
|
+
}
|
|
14403
|
+
SlotFillManager.$inject = ['config.slots', 'eventBus'];
|
|
14404
|
+
|
|
14405
|
+
// helpers //////////
|
|
14406
|
+
|
|
14407
|
+
/**
|
|
14408
|
+
* @param {string} slotName
|
|
14409
|
+
* @param {string} fillId
|
|
14410
|
+
* @param {Function|Object} options
|
|
14411
|
+
* @returns {{ slotName: string, fillId: string, render: Function, priority: number, group: string }}
|
|
14412
|
+
*/
|
|
14413
|
+
function normalizeFill(slotName, fillId, options) {
|
|
14414
|
+
if (typeof options === 'function') {
|
|
14415
|
+
return {
|
|
14416
|
+
slotName,
|
|
14417
|
+
fillId,
|
|
14418
|
+
render: options,
|
|
14419
|
+
priority: 0,
|
|
14420
|
+
group: 'z_default'
|
|
14421
|
+
};
|
|
14422
|
+
}
|
|
14423
|
+
const {
|
|
14424
|
+
render,
|
|
14425
|
+
priority = 0,
|
|
14426
|
+
group = 'z_default'
|
|
14427
|
+
} = options;
|
|
14428
|
+
return {
|
|
14429
|
+
slotName,
|
|
14430
|
+
fillId,
|
|
14431
|
+
render,
|
|
14432
|
+
priority,
|
|
14433
|
+
group
|
|
14434
|
+
};
|
|
14435
|
+
}
|
|
14436
|
+
|
|
14437
|
+
/**
|
|
14438
|
+
* Sort fills by group (alphabetical) then by priority (descending) within each group.
|
|
14439
|
+
*/
|
|
14440
|
+
function sortFills(fills) {
|
|
14441
|
+
const grouped = groupBy(fills, f => f.group);
|
|
14442
|
+
return Object.keys(grouped).sort().flatMap(key => grouped[key].toSorted((a, b) => b.priority - a.priority));
|
|
14443
|
+
}
|
|
14444
|
+
function groupBy(items, keyFn) {
|
|
14445
|
+
return items.reduce((groups, item) => {
|
|
14446
|
+
const key = keyFn(item);
|
|
14447
|
+
return {
|
|
14448
|
+
...groups,
|
|
14449
|
+
[key]: [...(groups[key] || []), item]
|
|
14450
|
+
};
|
|
14451
|
+
}, {});
|
|
14452
|
+
}
|
|
14453
|
+
|
|
14252
14454
|
const RenderInjectionModule = {
|
|
14253
|
-
__init__: ['renderInjector'],
|
|
14254
|
-
renderInjector: ['type', RenderInjector]
|
|
14455
|
+
__init__: ['renderInjector', 'slotFillManager'],
|
|
14456
|
+
renderInjector: ['type', RenderInjector],
|
|
14457
|
+
slotFillManager: ['type', SlotFillManager]
|
|
14255
14458
|
};
|
|
14256
14459
|
|
|
14257
14460
|
var _path;
|