@bpmn-io/form-js-editor 1.20.1 → 1.21.0
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 +205 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +205 -3
- 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.cjs
CHANGED
|
@@ -1373,7 +1373,26 @@ const Slot = props => {
|
|
|
1373
1373
|
const fillsAndSeparators = hooks.useMemo(() => {
|
|
1374
1374
|
return buildFills(groups, fillRoot, separatorFn);
|
|
1375
1375
|
}, [groups, fillRoot, separatorFn]);
|
|
1376
|
-
|
|
1376
|
+
|
|
1377
|
+
// Framework-agnostic fills from SlotFillManager
|
|
1378
|
+
const editorContext = hooks.useContext(FormEditorContext);
|
|
1379
|
+
const slotFillManager = editorContext ? editorContext.getService('slotFillManager', false) : null;
|
|
1380
|
+
const eventBus = editorContext ? editorContext.getService('eventBus', false) : null;
|
|
1381
|
+
const [managerFills, setManagerFills] = hooks.useState([]);
|
|
1382
|
+
hooks.useEffect(() => {
|
|
1383
|
+
if (!eventBus || !slotFillManager) {
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
setManagerFills(slotFillManager.getFills(name));
|
|
1387
|
+
const onChange = () => setManagerFills(slotFillManager.getFills(name));
|
|
1388
|
+
eventBus.on('slotFillManager.changed', onChange);
|
|
1389
|
+
return () => eventBus.off('slotFillManager.changed', onChange);
|
|
1390
|
+
}, [eventBus, slotFillManager, name]);
|
|
1391
|
+
return jsxRuntime.jsxs(preact.Fragment, {
|
|
1392
|
+
children: [fillsAndSeparators, managerFills.map(fill => jsxRuntime.jsx(FillContainer, {
|
|
1393
|
+
fill: fill
|
|
1394
|
+
}, fill.fillId))]
|
|
1395
|
+
});
|
|
1377
1396
|
};
|
|
1378
1397
|
|
|
1379
1398
|
/**
|
|
@@ -1386,6 +1405,34 @@ const FillFragment = fill => jsxRuntime.jsx(preact.Fragment, {
|
|
|
1386
1405
|
children: fill.children
|
|
1387
1406
|
}, fill.id);
|
|
1388
1407
|
|
|
1408
|
+
/**
|
|
1409
|
+
* Mounts a single SlotFillManager fill's render callback into a DOM container.
|
|
1410
|
+
*/
|
|
1411
|
+
function FillContainer({
|
|
1412
|
+
fill
|
|
1413
|
+
}) {
|
|
1414
|
+
const containerRef = hooks.useRef(null);
|
|
1415
|
+
const cleanupRef = hooks.useRef(null);
|
|
1416
|
+
hooks.useEffect(() => {
|
|
1417
|
+
const container = containerRef.current;
|
|
1418
|
+
if (!container) {
|
|
1419
|
+
return;
|
|
1420
|
+
}
|
|
1421
|
+
cleanupRef.current = fill.render(container) || null;
|
|
1422
|
+
return () => {
|
|
1423
|
+
if (typeof cleanupRef.current === 'function') {
|
|
1424
|
+
cleanupRef.current();
|
|
1425
|
+
cleanupRef.current = null;
|
|
1426
|
+
}
|
|
1427
|
+
container.innerHTML = '';
|
|
1428
|
+
};
|
|
1429
|
+
}, [fill]);
|
|
1430
|
+
return jsxRuntime.jsx("div", {
|
|
1431
|
+
ref: containerRef,
|
|
1432
|
+
"data-slot-fill": fill.fillId
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1389
1436
|
/**
|
|
1390
1437
|
* Creates an array of fills, with separators inserted between groups.
|
|
1391
1438
|
*
|
|
@@ -2264,6 +2311,8 @@ function EmptyForm() {
|
|
|
2264
2311
|
children: "Drag and drop components here to start designing."
|
|
2265
2312
|
}), jsxRuntime.jsx("span", {
|
|
2266
2313
|
children: "Use the preview window to test your form."
|
|
2314
|
+
}), jsxRuntime.jsx(Slot, {
|
|
2315
|
+
name: "editor-empty-state__footer"
|
|
2267
2316
|
})]
|
|
2268
2317
|
})
|
|
2269
2318
|
});
|
|
@@ -14269,9 +14318,162 @@ class RenderInjector extends SectionModuleBase {
|
|
|
14269
14318
|
}
|
|
14270
14319
|
RenderInjector.$inject = ['eventBus'];
|
|
14271
14320
|
|
|
14321
|
+
/**
|
|
14322
|
+
* Framework-agnostic service for managing slot fills.
|
|
14323
|
+
*
|
|
14324
|
+
* Fills are registered as render callbacks: `(container: HTMLElement) => (() => void) | void`.
|
|
14325
|
+
* The optional return value is a cleanup function called when the fill is removed or the slot unmounts.
|
|
14326
|
+
*
|
|
14327
|
+
* @example
|
|
14328
|
+
*
|
|
14329
|
+
* // Via config (simplest):
|
|
14330
|
+
* new FormEditor({
|
|
14331
|
+
* slots: {
|
|
14332
|
+
* 'editor-empty-state__footer': (container) => {
|
|
14333
|
+
* container.textContent = 'Hello from vanilla JS';
|
|
14334
|
+
* }
|
|
14335
|
+
* }
|
|
14336
|
+
* });
|
|
14337
|
+
*
|
|
14338
|
+
* // Via config (multiple fills per slot):
|
|
14339
|
+
* new FormEditor({
|
|
14340
|
+
* slots: {
|
|
14341
|
+
* 'editor-empty-state__footer': [
|
|
14342
|
+
* (container) => { container.textContent = 'First'; },
|
|
14343
|
+
* { render: (container) => { container.textContent = 'Second'; }, priority: 10 }
|
|
14344
|
+
* ]
|
|
14345
|
+
* }
|
|
14346
|
+
* });
|
|
14347
|
+
*
|
|
14348
|
+
* // Via service (runtime):
|
|
14349
|
+
* const slotFillManager = editor.get('slotFillManager');
|
|
14350
|
+
* slotFillManager.addFill('editor-empty-state__footer', 'my-fill', {
|
|
14351
|
+
* render: (container) => { ... },
|
|
14352
|
+
* priority: 10,
|
|
14353
|
+
* group: 'custom'
|
|
14354
|
+
* });
|
|
14355
|
+
*/
|
|
14356
|
+
class SlotFillManager {
|
|
14357
|
+
/**
|
|
14358
|
+
* @param {Object} slotsConfig
|
|
14359
|
+
* @param {import('../../core/EventBus').EventBus} eventBus
|
|
14360
|
+
*/
|
|
14361
|
+
constructor(slotsConfig, eventBus) {
|
|
14362
|
+
this._eventBus = eventBus;
|
|
14363
|
+
|
|
14364
|
+
/** @type {Array<{ slotName: string, fillId: string, render: Function, priority: number, group: string }>} */
|
|
14365
|
+
this._fills = [];
|
|
14366
|
+
this._populateFromConfig(slotsConfig);
|
|
14367
|
+
}
|
|
14368
|
+
|
|
14369
|
+
/**
|
|
14370
|
+
* Register a fill for a named slot.
|
|
14371
|
+
*
|
|
14372
|
+
* @param {string} slotName - The slot to fill.
|
|
14373
|
+
* @param {string} fillId - Unique identifier for this fill.
|
|
14374
|
+
* @param {Function|Object} options - A render callback `(container) => cleanup`, or `{ render, priority?, group? }`.
|
|
14375
|
+
*/
|
|
14376
|
+
addFill(slotName, fillId, options) {
|
|
14377
|
+
const fill = normalizeFill(slotName, fillId, options);
|
|
14378
|
+
this._fills = [...this._fills.filter(f => f.fillId !== fillId), fill];
|
|
14379
|
+
this._eventBus.fire('slotFillManager.changed');
|
|
14380
|
+
}
|
|
14381
|
+
|
|
14382
|
+
/**
|
|
14383
|
+
* Remove a fill by its ID.
|
|
14384
|
+
*
|
|
14385
|
+
* @param {string} fillId
|
|
14386
|
+
*/
|
|
14387
|
+
removeFill(fillId) {
|
|
14388
|
+
const remaining = this._fills.filter(f => f.fillId !== fillId);
|
|
14389
|
+
if (remaining.length === this._fills.length) {
|
|
14390
|
+
return;
|
|
14391
|
+
}
|
|
14392
|
+
this._fills = remaining;
|
|
14393
|
+
this._eventBus.fire('slotFillManager.changed');
|
|
14394
|
+
}
|
|
14395
|
+
|
|
14396
|
+
/**
|
|
14397
|
+
* Get fills for a given slot, sorted by group (alphabetical) then priority (descending).
|
|
14398
|
+
*
|
|
14399
|
+
* @param {string} slotName
|
|
14400
|
+
* @returns {Array<{ slotName: string, fillId: string, render: Function, priority: number, group: string }>}
|
|
14401
|
+
*/
|
|
14402
|
+
getFills(slotName) {
|
|
14403
|
+
const matching = this._fills.filter(f => f.slotName === slotName);
|
|
14404
|
+
return sortFills(matching);
|
|
14405
|
+
}
|
|
14406
|
+
|
|
14407
|
+
/**
|
|
14408
|
+
* @private
|
|
14409
|
+
*/
|
|
14410
|
+
_populateFromConfig(slotsConfig) {
|
|
14411
|
+
Object.entries(slotsConfig || {}).forEach(([slotName, value]) => {
|
|
14412
|
+
if (Array.isArray(value)) {
|
|
14413
|
+
value.forEach((entry, index) => {
|
|
14414
|
+
this.addFill(slotName, `config__${slotName}_${index}`, entry);
|
|
14415
|
+
});
|
|
14416
|
+
} else {
|
|
14417
|
+
this.addFill(slotName, `config__${slotName}`, value);
|
|
14418
|
+
}
|
|
14419
|
+
});
|
|
14420
|
+
}
|
|
14421
|
+
}
|
|
14422
|
+
SlotFillManager.$inject = ['config.slots', 'eventBus'];
|
|
14423
|
+
|
|
14424
|
+
// helpers //////////
|
|
14425
|
+
|
|
14426
|
+
/**
|
|
14427
|
+
* @param {string} slotName
|
|
14428
|
+
* @param {string} fillId
|
|
14429
|
+
* @param {Function|Object} options
|
|
14430
|
+
* @returns {{ slotName: string, fillId: string, render: Function, priority: number, group: string }}
|
|
14431
|
+
*/
|
|
14432
|
+
function normalizeFill(slotName, fillId, options) {
|
|
14433
|
+
if (typeof options === 'function') {
|
|
14434
|
+
return {
|
|
14435
|
+
slotName,
|
|
14436
|
+
fillId,
|
|
14437
|
+
render: options,
|
|
14438
|
+
priority: 0,
|
|
14439
|
+
group: 'z_default'
|
|
14440
|
+
};
|
|
14441
|
+
}
|
|
14442
|
+
const {
|
|
14443
|
+
render,
|
|
14444
|
+
priority = 0,
|
|
14445
|
+
group = 'z_default'
|
|
14446
|
+
} = options;
|
|
14447
|
+
return {
|
|
14448
|
+
slotName,
|
|
14449
|
+
fillId,
|
|
14450
|
+
render,
|
|
14451
|
+
priority,
|
|
14452
|
+
group
|
|
14453
|
+
};
|
|
14454
|
+
}
|
|
14455
|
+
|
|
14456
|
+
/**
|
|
14457
|
+
* Sort fills by group (alphabetical) then by priority (descending) within each group.
|
|
14458
|
+
*/
|
|
14459
|
+
function sortFills(fills) {
|
|
14460
|
+
const grouped = groupBy(fills, f => f.group);
|
|
14461
|
+
return Object.keys(grouped).sort().flatMap(key => grouped[key].toSorted((a, b) => b.priority - a.priority));
|
|
14462
|
+
}
|
|
14463
|
+
function groupBy(items, keyFn) {
|
|
14464
|
+
return items.reduce((groups, item) => {
|
|
14465
|
+
const key = keyFn(item);
|
|
14466
|
+
return {
|
|
14467
|
+
...groups,
|
|
14468
|
+
[key]: [...(groups[key] || []), item]
|
|
14469
|
+
};
|
|
14470
|
+
}, {});
|
|
14471
|
+
}
|
|
14472
|
+
|
|
14272
14473
|
const RenderInjectionModule = {
|
|
14273
|
-
__init__: ['renderInjector'],
|
|
14274
|
-
renderInjector: ['type', RenderInjector]
|
|
14474
|
+
__init__: ['renderInjector', 'slotFillManager'],
|
|
14475
|
+
renderInjector: ['type', RenderInjector],
|
|
14476
|
+
slotFillManager: ['type', SlotFillManager]
|
|
14275
14477
|
};
|
|
14276
14478
|
|
|
14277
14479
|
var _path;
|