@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.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
|
});
|
|
@@ -14249,9 +14298,162 @@ class RenderInjector extends SectionModuleBase {
|
|
|
14249
14298
|
}
|
|
14250
14299
|
RenderInjector.$inject = ['eventBus'];
|
|
14251
14300
|
|
|
14301
|
+
/**
|
|
14302
|
+
* Framework-agnostic service for managing slot fills.
|
|
14303
|
+
*
|
|
14304
|
+
* Fills are registered as render callbacks: `(container: HTMLElement) => (() => void) | void`.
|
|
14305
|
+
* The optional return value is a cleanup function called when the fill is removed or the slot unmounts.
|
|
14306
|
+
*
|
|
14307
|
+
* @example
|
|
14308
|
+
*
|
|
14309
|
+
* // Via config (simplest):
|
|
14310
|
+
* new FormEditor({
|
|
14311
|
+
* slots: {
|
|
14312
|
+
* 'editor-empty-state__footer': (container) => {
|
|
14313
|
+
* container.textContent = 'Hello from vanilla JS';
|
|
14314
|
+
* }
|
|
14315
|
+
* }
|
|
14316
|
+
* });
|
|
14317
|
+
*
|
|
14318
|
+
* // Via config (multiple fills per slot):
|
|
14319
|
+
* new FormEditor({
|
|
14320
|
+
* slots: {
|
|
14321
|
+
* 'editor-empty-state__footer': [
|
|
14322
|
+
* (container) => { container.textContent = 'First'; },
|
|
14323
|
+
* { render: (container) => { container.textContent = 'Second'; }, priority: 10 }
|
|
14324
|
+
* ]
|
|
14325
|
+
* }
|
|
14326
|
+
* });
|
|
14327
|
+
*
|
|
14328
|
+
* // Via service (runtime):
|
|
14329
|
+
* const slotFillManager = editor.get('slotFillManager');
|
|
14330
|
+
* slotFillManager.addFill('editor-empty-state__footer', 'my-fill', {
|
|
14331
|
+
* render: (container) => { ... },
|
|
14332
|
+
* priority: 10,
|
|
14333
|
+
* group: 'custom'
|
|
14334
|
+
* });
|
|
14335
|
+
*/
|
|
14336
|
+
class SlotFillManager {
|
|
14337
|
+
/**
|
|
14338
|
+
* @param {Object} slotsConfig
|
|
14339
|
+
* @param {import('../../core/EventBus').EventBus} eventBus
|
|
14340
|
+
*/
|
|
14341
|
+
constructor(slotsConfig, eventBus) {
|
|
14342
|
+
this._eventBus = eventBus;
|
|
14343
|
+
|
|
14344
|
+
/** @type {Array<{ slotName: string, fillId: string, render: Function, priority: number, group: string }>} */
|
|
14345
|
+
this._fills = [];
|
|
14346
|
+
this._populateFromConfig(slotsConfig);
|
|
14347
|
+
}
|
|
14348
|
+
|
|
14349
|
+
/**
|
|
14350
|
+
* Register a fill for a named slot.
|
|
14351
|
+
*
|
|
14352
|
+
* @param {string} slotName - The slot to fill.
|
|
14353
|
+
* @param {string} fillId - Unique identifier for this fill.
|
|
14354
|
+
* @param {Function|Object} options - A render callback `(container) => cleanup`, or `{ render, priority?, group? }`.
|
|
14355
|
+
*/
|
|
14356
|
+
addFill(slotName, fillId, options) {
|
|
14357
|
+
const fill = normalizeFill(slotName, fillId, options);
|
|
14358
|
+
this._fills = [...this._fills.filter(f => f.fillId !== fillId), fill];
|
|
14359
|
+
this._eventBus.fire('slotFillManager.changed');
|
|
14360
|
+
}
|
|
14361
|
+
|
|
14362
|
+
/**
|
|
14363
|
+
* Remove a fill by its ID.
|
|
14364
|
+
*
|
|
14365
|
+
* @param {string} fillId
|
|
14366
|
+
*/
|
|
14367
|
+
removeFill(fillId) {
|
|
14368
|
+
const remaining = this._fills.filter(f => f.fillId !== fillId);
|
|
14369
|
+
if (remaining.length === this._fills.length) {
|
|
14370
|
+
return;
|
|
14371
|
+
}
|
|
14372
|
+
this._fills = remaining;
|
|
14373
|
+
this._eventBus.fire('slotFillManager.changed');
|
|
14374
|
+
}
|
|
14375
|
+
|
|
14376
|
+
/**
|
|
14377
|
+
* Get fills for a given slot, sorted by group (alphabetical) then priority (descending).
|
|
14378
|
+
*
|
|
14379
|
+
* @param {string} slotName
|
|
14380
|
+
* @returns {Array<{ slotName: string, fillId: string, render: Function, priority: number, group: string }>}
|
|
14381
|
+
*/
|
|
14382
|
+
getFills(slotName) {
|
|
14383
|
+
const matching = this._fills.filter(f => f.slotName === slotName);
|
|
14384
|
+
return sortFills(matching);
|
|
14385
|
+
}
|
|
14386
|
+
|
|
14387
|
+
/**
|
|
14388
|
+
* @private
|
|
14389
|
+
*/
|
|
14390
|
+
_populateFromConfig(slotsConfig) {
|
|
14391
|
+
Object.entries(slotsConfig || {}).forEach(([slotName, value]) => {
|
|
14392
|
+
if (Array.isArray(value)) {
|
|
14393
|
+
value.forEach((entry, index) => {
|
|
14394
|
+
this.addFill(slotName, `config__${slotName}_${index}`, entry);
|
|
14395
|
+
});
|
|
14396
|
+
} else {
|
|
14397
|
+
this.addFill(slotName, `config__${slotName}`, value);
|
|
14398
|
+
}
|
|
14399
|
+
});
|
|
14400
|
+
}
|
|
14401
|
+
}
|
|
14402
|
+
SlotFillManager.$inject = ['config.slots', 'eventBus'];
|
|
14403
|
+
|
|
14404
|
+
// helpers //////////
|
|
14405
|
+
|
|
14406
|
+
/**
|
|
14407
|
+
* @param {string} slotName
|
|
14408
|
+
* @param {string} fillId
|
|
14409
|
+
* @param {Function|Object} options
|
|
14410
|
+
* @returns {{ slotName: string, fillId: string, render: Function, priority: number, group: string }}
|
|
14411
|
+
*/
|
|
14412
|
+
function normalizeFill(slotName, fillId, options) {
|
|
14413
|
+
if (typeof options === 'function') {
|
|
14414
|
+
return {
|
|
14415
|
+
slotName,
|
|
14416
|
+
fillId,
|
|
14417
|
+
render: options,
|
|
14418
|
+
priority: 0,
|
|
14419
|
+
group: 'z_default'
|
|
14420
|
+
};
|
|
14421
|
+
}
|
|
14422
|
+
const {
|
|
14423
|
+
render,
|
|
14424
|
+
priority = 0,
|
|
14425
|
+
group = 'z_default'
|
|
14426
|
+
} = options;
|
|
14427
|
+
return {
|
|
14428
|
+
slotName,
|
|
14429
|
+
fillId,
|
|
14430
|
+
render,
|
|
14431
|
+
priority,
|
|
14432
|
+
group
|
|
14433
|
+
};
|
|
14434
|
+
}
|
|
14435
|
+
|
|
14436
|
+
/**
|
|
14437
|
+
* Sort fills by group (alphabetical) then by priority (descending) within each group.
|
|
14438
|
+
*/
|
|
14439
|
+
function sortFills(fills) {
|
|
14440
|
+
const grouped = groupBy(fills, f => f.group);
|
|
14441
|
+
return Object.keys(grouped).sort().flatMap(key => grouped[key].toSorted((a, b) => b.priority - a.priority));
|
|
14442
|
+
}
|
|
14443
|
+
function groupBy(items, keyFn) {
|
|
14444
|
+
return items.reduce((groups, item) => {
|
|
14445
|
+
const key = keyFn(item);
|
|
14446
|
+
return {
|
|
14447
|
+
...groups,
|
|
14448
|
+
[key]: [...(groups[key] || []), item]
|
|
14449
|
+
};
|
|
14450
|
+
}, {});
|
|
14451
|
+
}
|
|
14452
|
+
|
|
14252
14453
|
const RenderInjectionModule = {
|
|
14253
|
-
__init__: ['renderInjector'],
|
|
14254
|
-
renderInjector: ['type', RenderInjector]
|
|
14454
|
+
__init__: ['renderInjector', 'slotFillManager'],
|
|
14455
|
+
renderInjector: ['type', RenderInjector],
|
|
14456
|
+
slotFillManager: ['type', SlotFillManager]
|
|
14255
14457
|
};
|
|
14256
14458
|
|
|
14257
14459
|
var _path;
|