@bpmn-io/properties-panel 3.7.1 → 3.9.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/properties-panel.css +1 -1
- package/dist/index.esm.js +102 -25
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +101 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1237,7 +1237,7 @@ textarea.bio-properties-panel-input {
|
|
|
1237
1237
|
--feel-popup-close-background-color: hsla(219, 99%, 53%, 1);
|
|
1238
1238
|
--feel-popup-gutters-background-color: hsla(0, 0%, 90%, 1);
|
|
1239
1239
|
|
|
1240
|
-
position:
|
|
1240
|
+
position: fixed;
|
|
1241
1241
|
display: flex;
|
|
1242
1242
|
flex: auto;
|
|
1243
1243
|
flex-direction: column;
|
package/dist/index.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useContext, useState, useRef, useEffect, useMemo, useCallback, useLayoutEffect } from '../preact/hooks';
|
|
2
|
-
import { isFunction,
|
|
2
|
+
import { isFunction, isString, isArray, get, assign, set, sortBy, find, isNumber, debounce } from 'min-dash';
|
|
3
3
|
import { createPortal, forwardRef } from '../preact/compat';
|
|
4
4
|
import { jsx, jsxs, Fragment } from '../preact/jsx-runtime';
|
|
5
5
|
import { createContext, createElement } from '../preact';
|
|
@@ -649,20 +649,24 @@ function Group(props) {
|
|
|
649
649
|
|
|
650
650
|
// set edited state depending on all entries
|
|
651
651
|
useEffect(() => {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
652
|
+
// TODO(@barmac): replace with CSS when `:has()` is supported in all major browsers, or rewrite as in https://github.com/camunda/camunda-modeler/issues/3815#issuecomment-1733038161
|
|
653
|
+
const scheduled = requestAnimationFrame(() => {
|
|
654
|
+
const hasOneEditedEntry = entries.find(entry => {
|
|
655
|
+
const {
|
|
656
|
+
id,
|
|
657
|
+
isEdited
|
|
658
|
+
} = entry;
|
|
659
|
+
const entryNode = query(`[data-entry-id="${id}"]`);
|
|
660
|
+
if (!isFunction(isEdited) || !entryNode) {
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
const inputNode = query('.bio-properties-panel-input', entryNode);
|
|
664
|
+
return isEdited(inputNode);
|
|
665
|
+
});
|
|
666
|
+
setEdited(hasOneEditedEntry);
|
|
663
667
|
});
|
|
664
|
-
|
|
665
|
-
}, [entries]);
|
|
668
|
+
return () => cancelAnimationFrame(scheduled);
|
|
669
|
+
}, [entries, setEdited]);
|
|
666
670
|
|
|
667
671
|
// set error state depending on all entries
|
|
668
672
|
const allErrors = useErrors();
|
|
@@ -1096,7 +1100,11 @@ function createDragger(fn, dragPreview) {
|
|
|
1096
1100
|
// (2) setup drag listeners
|
|
1097
1101
|
|
|
1098
1102
|
// attach drag + cleanup event
|
|
1099
|
-
|
|
1103
|
+
// we need to do this to make sure we track cursor
|
|
1104
|
+
// movements before we reach other drag event handlers,
|
|
1105
|
+
// e.g. in child containers.
|
|
1106
|
+
document.addEventListener('dragover', onDrag, true);
|
|
1107
|
+
document.addEventListener('dragenter', preventDefault, true);
|
|
1100
1108
|
document.addEventListener('dragend', onEnd);
|
|
1101
1109
|
document.addEventListener('drop', preventDefault);
|
|
1102
1110
|
}
|
|
@@ -1110,7 +1118,8 @@ function createDragger(fn, dragPreview) {
|
|
|
1110
1118
|
return fn.call(self, event, delta);
|
|
1111
1119
|
}
|
|
1112
1120
|
function onEnd() {
|
|
1113
|
-
document.removeEventListener('dragover', onDrag);
|
|
1121
|
+
document.removeEventListener('dragover', onDrag, true);
|
|
1122
|
+
document.removeEventListener('dragenter', preventDefault, true);
|
|
1114
1123
|
document.removeEventListener('dragend', onEnd);
|
|
1115
1124
|
document.removeEventListener('drop', preventDefault);
|
|
1116
1125
|
}
|
|
@@ -1142,8 +1151,9 @@ const noop$3 = () => {};
|
|
|
1142
1151
|
* @param {boolean} [props.returnFocus]
|
|
1143
1152
|
* @param {boolean} [props.closeOnEscape]
|
|
1144
1153
|
* @param {string} props.title
|
|
1154
|
+
* @param {Ref} [ref]
|
|
1145
1155
|
*/
|
|
1146
|
-
function
|
|
1156
|
+
function PopupComponent(props, globalRef) {
|
|
1147
1157
|
const {
|
|
1148
1158
|
container,
|
|
1149
1159
|
className,
|
|
@@ -1159,7 +1169,9 @@ function Popup(props) {
|
|
|
1159
1169
|
title
|
|
1160
1170
|
} = props;
|
|
1161
1171
|
const focusTrapRef = useRef(null);
|
|
1162
|
-
const
|
|
1172
|
+
const localRef = useRef(null);
|
|
1173
|
+
const popupRef = globalRef || localRef;
|
|
1174
|
+
const containerNode = useMemo(() => getContainerNode(container), [container]);
|
|
1163
1175
|
const handleKeydown = event => {
|
|
1164
1176
|
// do not allow keyboard events to bubble
|
|
1165
1177
|
event.stopPropagation();
|
|
@@ -1219,8 +1231,9 @@ function Popup(props) {
|
|
|
1219
1231
|
class: classnames('bio-properties-panel-popup', className),
|
|
1220
1232
|
style: style,
|
|
1221
1233
|
children: props.children
|
|
1222
|
-
}),
|
|
1234
|
+
}), containerNode || document.body);
|
|
1223
1235
|
}
|
|
1236
|
+
const Popup = forwardRef(PopupComponent);
|
|
1224
1237
|
Popup.Title = Title;
|
|
1225
1238
|
Popup.Body = Body;
|
|
1226
1239
|
Popup.Footer = Footer;
|
|
@@ -1229,6 +1242,7 @@ function Title(props) {
|
|
|
1229
1242
|
children,
|
|
1230
1243
|
className,
|
|
1231
1244
|
draggable,
|
|
1245
|
+
emit = () => {},
|
|
1232
1246
|
title,
|
|
1233
1247
|
...rest
|
|
1234
1248
|
} = props;
|
|
@@ -1241,7 +1255,8 @@ function Title(props) {
|
|
|
1241
1255
|
});
|
|
1242
1256
|
const dragPreviewRef = useRef();
|
|
1243
1257
|
const titleRef = useRef();
|
|
1244
|
-
const onMove =
|
|
1258
|
+
const onMove = (event, delta) => {
|
|
1259
|
+
cancel(event);
|
|
1245
1260
|
const {
|
|
1246
1261
|
x: dx,
|
|
1247
1262
|
y: dy
|
|
@@ -1253,20 +1268,33 @@ function Title(props) {
|
|
|
1253
1268
|
const popupParent = getPopupParent(titleRef.current);
|
|
1254
1269
|
popupParent.style.top = newPosition.y + 'px';
|
|
1255
1270
|
popupParent.style.left = newPosition.x + 'px';
|
|
1256
|
-
|
|
1271
|
+
|
|
1272
|
+
// notify interested parties
|
|
1273
|
+
emit('dragover', {
|
|
1274
|
+
newPosition,
|
|
1275
|
+
delta
|
|
1276
|
+
});
|
|
1277
|
+
};
|
|
1257
1278
|
const onMoveStart = event => {
|
|
1258
1279
|
// initialize drag handler
|
|
1259
1280
|
const onDragStart = createDragger(onMove, dragPreviewRef.current);
|
|
1260
1281
|
onDragStart(event);
|
|
1282
|
+
event.stopPropagation();
|
|
1261
1283
|
const popupParent = getPopupParent(titleRef.current);
|
|
1262
1284
|
const bounds = popupParent.getBoundingClientRect();
|
|
1263
1285
|
context.current.startPosition = {
|
|
1264
1286
|
x: bounds.left,
|
|
1265
1287
|
y: bounds.top
|
|
1266
1288
|
};
|
|
1289
|
+
|
|
1290
|
+
// notify interested parties
|
|
1291
|
+
emit('dragstart');
|
|
1267
1292
|
};
|
|
1268
1293
|
const onMoveEnd = () => {
|
|
1269
1294
|
context.current.newPosition = null;
|
|
1295
|
+
|
|
1296
|
+
// notify interested parties
|
|
1297
|
+
emit('dragend');
|
|
1270
1298
|
};
|
|
1271
1299
|
return jsxs("div", {
|
|
1272
1300
|
class: classnames('bio-properties-panel-popup__header', draggable && 'draggable', className),
|
|
@@ -1319,12 +1347,26 @@ function Footer(props) {
|
|
|
1319
1347
|
function getPopupParent(node) {
|
|
1320
1348
|
return node.closest('.bio-properties-panel-popup');
|
|
1321
1349
|
}
|
|
1350
|
+
function cancel(event) {
|
|
1351
|
+
event.preventDefault();
|
|
1352
|
+
event.stopPropagation();
|
|
1353
|
+
}
|
|
1354
|
+
function getContainerNode(node) {
|
|
1355
|
+
if (typeof node === 'string') {
|
|
1356
|
+
return query(node);
|
|
1357
|
+
}
|
|
1358
|
+
return node;
|
|
1359
|
+
}
|
|
1322
1360
|
|
|
1323
1361
|
const FEEL_POPUP_WIDTH = 700;
|
|
1324
1362
|
const FEEL_POPUP_HEIGHT = 250;
|
|
1325
1363
|
|
|
1326
1364
|
/**
|
|
1327
|
-
* FEEL popup component, built as a singleton.
|
|
1365
|
+
* FEEL popup component, built as a singleton. Emits lifecycle events as follows:
|
|
1366
|
+
* - `feelPopup.open` - fired before the popup is mounted
|
|
1367
|
+
* - `feelPopup.opened` - fired after the popup is mounted. Event context contains the DOM node of the popup
|
|
1368
|
+
* - `feelPopup.close` - fired before the popup is unmounted. Event context contains the DOM node of the popup
|
|
1369
|
+
* - `feelPopup.closed` - fired after the popup is unmounted
|
|
1328
1370
|
*/
|
|
1329
1371
|
function FEELPopupRoot(props) {
|
|
1330
1372
|
const {
|
|
@@ -1347,17 +1389,21 @@ function FEELPopupRoot(props) {
|
|
|
1347
1389
|
const isOpen = useCallback(() => {
|
|
1348
1390
|
return !!open;
|
|
1349
1391
|
}, [open]);
|
|
1392
|
+
useUpdateEffect(() => {
|
|
1393
|
+
if (!open) {
|
|
1394
|
+
emit('closed');
|
|
1395
|
+
}
|
|
1396
|
+
}, [open]);
|
|
1350
1397
|
const handleOpen = (entryId, config, _sourceElement) => {
|
|
1351
1398
|
setSource(entryId);
|
|
1352
1399
|
setPopupConfig(config);
|
|
1353
1400
|
setOpen(true);
|
|
1354
1401
|
setSourceElement(_sourceElement);
|
|
1355
|
-
emit('
|
|
1402
|
+
emit('open');
|
|
1356
1403
|
};
|
|
1357
1404
|
const handleClose = () => {
|
|
1358
1405
|
setOpen(false);
|
|
1359
1406
|
setSource(null);
|
|
1360
|
-
emit('closed');
|
|
1361
1407
|
};
|
|
1362
1408
|
const feelPopupContext = {
|
|
1363
1409
|
open: handleOpen,
|
|
@@ -1400,6 +1446,7 @@ function FEELPopupRoot(props) {
|
|
|
1400
1446
|
onClose: handleClose,
|
|
1401
1447
|
container: popupContainer,
|
|
1402
1448
|
sourceElement: sourceElement,
|
|
1449
|
+
emit: emit,
|
|
1403
1450
|
...popupConfig
|
|
1404
1451
|
}), props.children]
|
|
1405
1452
|
});
|
|
@@ -1418,9 +1465,11 @@ function FeelPopupComponent(props) {
|
|
|
1418
1465
|
tooltipContainer,
|
|
1419
1466
|
type,
|
|
1420
1467
|
value,
|
|
1421
|
-
variables
|
|
1468
|
+
variables,
|
|
1469
|
+
emit
|
|
1422
1470
|
} = props;
|
|
1423
1471
|
const editorRef = useRef();
|
|
1472
|
+
const popupRef = useRef();
|
|
1424
1473
|
const isAutoCompletionOpen = useRef(false);
|
|
1425
1474
|
const handleSetReturnFocus = () => {
|
|
1426
1475
|
sourceElement && sourceElement.focus();
|
|
@@ -1443,9 +1492,18 @@ function FeelPopupComponent(props) {
|
|
|
1443
1492
|
}
|
|
1444
1493
|
}
|
|
1445
1494
|
};
|
|
1495
|
+
useEffect(() => {
|
|
1496
|
+
emit('opened', {
|
|
1497
|
+
domNode: popupRef.current
|
|
1498
|
+
});
|
|
1499
|
+
return () => emit('close', {
|
|
1500
|
+
domNode: popupRef.current
|
|
1501
|
+
});
|
|
1502
|
+
}, []);
|
|
1446
1503
|
return jsxs(Popup, {
|
|
1447
1504
|
container: container,
|
|
1448
1505
|
className: "bio-properties-panel-feel-popup",
|
|
1506
|
+
emit: emit,
|
|
1449
1507
|
position: position,
|
|
1450
1508
|
title: title,
|
|
1451
1509
|
onClose: onClose
|
|
@@ -1458,8 +1516,10 @@ function FeelPopupComponent(props) {
|
|
|
1458
1516
|
onPostDeactivate: handleSetReturnFocus,
|
|
1459
1517
|
height: FEEL_POPUP_HEIGHT,
|
|
1460
1518
|
width: FEEL_POPUP_WIDTH,
|
|
1519
|
+
ref: popupRef,
|
|
1461
1520
|
children: [jsx(Popup.Title, {
|
|
1462
1521
|
title: title,
|
|
1522
|
+
emit: emit,
|
|
1463
1523
|
draggable: true
|
|
1464
1524
|
}), jsx(Popup.Body, {
|
|
1465
1525
|
children: jsxs("div", {
|
|
@@ -1510,6 +1570,23 @@ function autoCompletionOpen(element) {
|
|
|
1510
1570
|
return element.closest('.cm-editor').querySelector('.cm-tooltip-autocomplete');
|
|
1511
1571
|
}
|
|
1512
1572
|
|
|
1573
|
+
/**
|
|
1574
|
+
* This hook behaves like useEffect, but does not trigger on the first render.
|
|
1575
|
+
*
|
|
1576
|
+
* @param {Function} effect
|
|
1577
|
+
* @param {Array} deps
|
|
1578
|
+
*/
|
|
1579
|
+
function useUpdateEffect(effect, deps) {
|
|
1580
|
+
const isMounted = useRef(false);
|
|
1581
|
+
useEffect(() => {
|
|
1582
|
+
if (isMounted.current) {
|
|
1583
|
+
return effect();
|
|
1584
|
+
} else {
|
|
1585
|
+
isMounted.current = true;
|
|
1586
|
+
}
|
|
1587
|
+
}, deps);
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1513
1590
|
function ToggleSwitch(props) {
|
|
1514
1591
|
const {
|
|
1515
1592
|
id,
|