@bpmn-io/properties-panel 3.47.0 → 3.48.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 +37 -11
- package/dist/index.esm.js +259 -52
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +259 -52
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1277,8 +1277,13 @@ textarea.bio-properties-panel-input {
|
|
|
1277
1277
|
transform: rotate(90deg);
|
|
1278
1278
|
}
|
|
1279
1279
|
|
|
1280
|
+
.bio-properties-panel-textarea-container {
|
|
1281
|
+
position: relative;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1280
1284
|
.bio-properties-panel-feelers-editor-container .bio-properties-panel-feelers-editor__open-popup-placeholder,
|
|
1281
|
-
.bio-properties-panel-feel-editor-container .bio-properties-panel-feel-editor__open-popup-placeholder
|
|
1285
|
+
.bio-properties-panel-feel-editor-container .bio-properties-panel-feel-editor__open-popup-placeholder,
|
|
1286
|
+
.bio-properties-panel-textarea-container .bio-properties-panel-textarea__open-popup-placeholder {
|
|
1282
1287
|
display: none;
|
|
1283
1288
|
justify-content: center;
|
|
1284
1289
|
flex-direction: column;
|
|
@@ -1298,11 +1303,22 @@ textarea.bio-properties-panel-input {
|
|
|
1298
1303
|
display: none;
|
|
1299
1304
|
}
|
|
1300
1305
|
|
|
1306
|
+
.bio-properties-panel-textarea-container.popupOpen .bio-properties-panel-input {
|
|
1307
|
+
visibility: hidden;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1301
1310
|
.bio-properties-panel-feelers-editor-container.popupOpen .bio-properties-panel-feelers-editor__open-popup-placeholder,
|
|
1302
|
-
.bio-properties-panel-feel-editor-container.popupOpen .bio-properties-panel-feel-editor__open-popup-placeholder
|
|
1311
|
+
.bio-properties-panel-feel-editor-container.popupOpen .bio-properties-panel-feel-editor__open-popup-placeholder,
|
|
1312
|
+
.bio-properties-panel-textarea-container.popupOpen .bio-properties-panel-textarea__open-popup-placeholder {
|
|
1303
1313
|
display: flex;
|
|
1304
1314
|
}
|
|
1305
1315
|
|
|
1316
|
+
.bio-properties-panel-textarea-container.popupOpen .bio-properties-panel-textarea__open-popup-placeholder {
|
|
1317
|
+
position: absolute;
|
|
1318
|
+
inset: 0;
|
|
1319
|
+
justify-content: flex-start;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1306
1322
|
.bio-properties-panel-popup {
|
|
1307
1323
|
--popup-background-color: hsla(0, 0%, 96%, 1);
|
|
1308
1324
|
--popup-header-background-color: white;
|
|
@@ -1379,6 +1395,7 @@ textarea.bio-properties-panel-input {
|
|
|
1379
1395
|
|
|
1380
1396
|
.bio-properties-panel-popup .bio-properties-panel-popup__title {
|
|
1381
1397
|
margin-left: 8px;
|
|
1398
|
+
margin-right: auto;
|
|
1382
1399
|
}
|
|
1383
1400
|
|
|
1384
1401
|
.bio-properties-panel-popup .bio-properties-panel-popup__title::first-letter {
|
|
@@ -1428,11 +1445,6 @@ textarea.bio-properties-panel-input {
|
|
|
1428
1445
|
right: 8px;
|
|
1429
1446
|
}
|
|
1430
1447
|
|
|
1431
|
-
.bio-properties-panel-feel-popup {
|
|
1432
|
-
min-height: 400px;
|
|
1433
|
-
width: fit-content;
|
|
1434
|
-
}
|
|
1435
|
-
|
|
1436
1448
|
.bio-properties-panel-feel-popup .bio-properties-panel-feel-popup__body {
|
|
1437
1449
|
display: flex;
|
|
1438
1450
|
margin: 0;
|
|
@@ -1492,7 +1504,8 @@ textarea.bio-properties-panel-input {
|
|
|
1492
1504
|
}
|
|
1493
1505
|
|
|
1494
1506
|
.bio-properties-panel-feelers-editor-container .bio-properties-panel-open-feel-popup,
|
|
1495
|
-
.bio-properties-panel-feel-container .bio-properties-panel-open-feel-popup
|
|
1507
|
+
.bio-properties-panel-feel-container .bio-properties-panel-open-feel-popup,
|
|
1508
|
+
.bio-properties-panel-textarea-container .bio-properties-panel-open-feel-popup {
|
|
1496
1509
|
position: absolute;
|
|
1497
1510
|
top: 0;
|
|
1498
1511
|
right: 0;
|
|
@@ -1507,20 +1520,24 @@ textarea.bio-properties-panel-input {
|
|
|
1507
1520
|
}
|
|
1508
1521
|
|
|
1509
1522
|
.bio-properties-panel-feelers-editor-container .bio-properties-panel-open-feel-popup svg,
|
|
1510
|
-
.bio-properties-panel-feel-container .bio-properties-panel-open-feel-popup svg
|
|
1523
|
+
.bio-properties-panel-feel-container .bio-properties-panel-open-feel-popup svg,
|
|
1524
|
+
.bio-properties-panel-textarea-container .bio-properties-panel-open-feel-popup svg {
|
|
1511
1525
|
width: 16px;
|
|
1512
1526
|
height: 16px;
|
|
1513
1527
|
}
|
|
1514
1528
|
|
|
1515
1529
|
.bio-properties-panel-feelers-editor-container:hover .bio-properties-panel-open-feel-popup,
|
|
1516
1530
|
.bio-properties-panel-feel-container:hover .bio-properties-panel-open-feel-popup,
|
|
1531
|
+
.bio-properties-panel-textarea-container:hover .bio-properties-panel-open-feel-popup,
|
|
1517
1532
|
.bio-properties-panel-feelers-editor-container:focus-within .bio-properties-panel-open-feel-popup,
|
|
1518
|
-
.bio-properties-panel-feel-container:focus-within .bio-properties-panel-open-feel-popup
|
|
1533
|
+
.bio-properties-panel-feel-container:focus-within .bio-properties-panel-open-feel-popup,
|
|
1534
|
+
.bio-properties-panel-textarea-container:focus-within .bio-properties-panel-open-feel-popup {
|
|
1519
1535
|
display: block;
|
|
1520
1536
|
}
|
|
1521
1537
|
|
|
1522
1538
|
.bio-properties-panel-feelers-editor-container .bio-properties-panel-open-feel-popup:hover,
|
|
1523
|
-
.bio-properties-panel-feel-container .bio-properties-panel-open-feel-popup:hover
|
|
1539
|
+
.bio-properties-panel-feel-container .bio-properties-panel-open-feel-popup:hover,
|
|
1540
|
+
.bio-properties-panel-textarea-container .bio-properties-panel-open-feel-popup:hover {
|
|
1524
1541
|
color: var(--feel-open-popup-hover-color);
|
|
1525
1542
|
}
|
|
1526
1543
|
|
|
@@ -1563,6 +1580,15 @@ textarea.bio-properties-panel-input {
|
|
|
1563
1580
|
text-align: center;
|
|
1564
1581
|
}
|
|
1565
1582
|
|
|
1583
|
+
.bio-properties-panel-text-popup .bio-properties-panel-input {
|
|
1584
|
+
width: 100%;
|
|
1585
|
+
height: 100%;
|
|
1586
|
+
min-height: 100%;
|
|
1587
|
+
resize: none;
|
|
1588
|
+
border: none;
|
|
1589
|
+
padding: 8px 12px;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1566
1592
|
/* Checkbox Group */
|
|
1567
1593
|
.bio-properties-panel-checkbox-group .bio-properties-panel-checkbox-group-entries > .bio-properties-panel-entry {
|
|
1568
1594
|
margin: 0;
|
package/dist/index.esm.js
CHANGED
|
@@ -4083,6 +4083,7 @@ function resizeToContents(element) {
|
|
|
4083
4083
|
function TextArea(props) {
|
|
4084
4084
|
const {
|
|
4085
4085
|
id,
|
|
4086
|
+
element,
|
|
4086
4087
|
label,
|
|
4087
4088
|
debounce,
|
|
4088
4089
|
onInput: commitValue,
|
|
@@ -4095,10 +4096,21 @@ function TextArea(props) {
|
|
|
4095
4096
|
autoResize = true,
|
|
4096
4097
|
placeholder,
|
|
4097
4098
|
rows = autoResize ? 1 : 2,
|
|
4098
|
-
tooltip
|
|
4099
|
+
tooltip,
|
|
4100
|
+
translate = translateFallback
|
|
4099
4101
|
} = props;
|
|
4100
4102
|
const [localValue, setLocalValue] = useState(value);
|
|
4101
4103
|
const ref = useShowEntryEvent(id);
|
|
4104
|
+
const containerRef = useRef();
|
|
4105
|
+
|
|
4106
|
+
// keep a live reference to the current value so callbacks captured by the
|
|
4107
|
+
// popup (frozen at open time) can compare against the latest value
|
|
4108
|
+
const localValueRef = useRef(localValue);
|
|
4109
|
+
localValueRef.current = localValue;
|
|
4110
|
+
const {
|
|
4111
|
+
eventBus
|
|
4112
|
+
} = useContext(EventContext);
|
|
4113
|
+
const [isPopupOpen, setIsPopupOpen] = useState(false);
|
|
4102
4114
|
const onInput = useCallback(newValue => {
|
|
4103
4115
|
const newModelValue = newValue === '' ? undefined : newValue;
|
|
4104
4116
|
commitValue(newModelValue);
|
|
@@ -4110,7 +4122,6 @@ function TextArea(props) {
|
|
|
4110
4122
|
*/
|
|
4111
4123
|
const handleInput = useDebounce(onInput, debounce);
|
|
4112
4124
|
const handleLocalInput = e => {
|
|
4113
|
-
autoResize && resizeToContents(e.target);
|
|
4114
4125
|
if (e.target.value === localValue) {
|
|
4115
4126
|
return;
|
|
4116
4127
|
}
|
|
@@ -4155,9 +4166,40 @@ function TextArea(props) {
|
|
|
4155
4166
|
handleInput.flush?.();
|
|
4156
4167
|
}
|
|
4157
4168
|
};
|
|
4169
|
+
const handlePopupInput = newValue => {
|
|
4170
|
+
if (newValue === localValueRef.current) {
|
|
4171
|
+
return;
|
|
4172
|
+
}
|
|
4173
|
+
setLocalValue(newValue);
|
|
4174
|
+
handleInput(newValue);
|
|
4175
|
+
};
|
|
4176
|
+
const handleOpenPopup = () => {
|
|
4177
|
+
const isOpen = eventBus.fire('propertiesPanel.openPopup', {
|
|
4178
|
+
element,
|
|
4179
|
+
entryId: id,
|
|
4180
|
+
label,
|
|
4181
|
+
onInput: handlePopupInput,
|
|
4182
|
+
sourceElement: ref.current,
|
|
4183
|
+
value: localValue
|
|
4184
|
+
});
|
|
4185
|
+
if (isOpen) {
|
|
4186
|
+
eventBus.once('propertiesPanelPopup.close', () => {
|
|
4187
|
+
handleInput.flush?.();
|
|
4188
|
+
setIsPopupOpen(false);
|
|
4189
|
+
});
|
|
4190
|
+
}
|
|
4191
|
+
setIsPopupOpen(isOpen === true);
|
|
4192
|
+
};
|
|
4193
|
+
useEffect(() => {
|
|
4194
|
+
return () => {
|
|
4195
|
+
eventBus && eventBus.fire('propertiesPanel.closePopup');
|
|
4196
|
+
};
|
|
4197
|
+
}, []);
|
|
4198
|
+
|
|
4199
|
+
// auto-resize on any value change (typing, popup edits, external updates)
|
|
4158
4200
|
useLayoutEffect(() => {
|
|
4159
4201
|
autoResize && resizeToContents(ref.current);
|
|
4160
|
-
}, []);
|
|
4202
|
+
}, [localValue]);
|
|
4161
4203
|
useLayoutEffect(() => {
|
|
4162
4204
|
visible && autoResize && resizeToContents(ref.current);
|
|
4163
4205
|
}, [visible]);
|
|
@@ -4175,25 +4217,35 @@ function TextArea(props) {
|
|
|
4175
4217
|
children: jsx(TooltipWrapper, {
|
|
4176
4218
|
value: tooltip,
|
|
4177
4219
|
forId: id,
|
|
4178
|
-
element:
|
|
4220
|
+
element: element,
|
|
4179
4221
|
children: label
|
|
4180
4222
|
})
|
|
4181
|
-
}),
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4223
|
+
}), jsxs("div", {
|
|
4224
|
+
class: classnames('bio-properties-panel-textarea-container', isPopupOpen ? 'popupOpen' : null),
|
|
4225
|
+
ref: containerRef,
|
|
4226
|
+
children: [isPopupOpen && jsx("div", {
|
|
4227
|
+
class: "bio-properties-panel-textarea__open-popup-placeholder",
|
|
4228
|
+
children: translate('Opened in editor')
|
|
4229
|
+
}), jsx("textarea", {
|
|
4230
|
+
ref: ref,
|
|
4231
|
+
id: prefixId$2(id),
|
|
4232
|
+
name: id,
|
|
4233
|
+
spellCheck: "false",
|
|
4234
|
+
class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : '', autoResize ? 'auto-resize' : ''),
|
|
4235
|
+
onInput: handleLocalInput,
|
|
4236
|
+
onFocus: onFocus,
|
|
4237
|
+
onKeyDown: handleOnKeyDown,
|
|
4238
|
+
onBlur: handleOnBlur,
|
|
4239
|
+
onPaste: handleOnPaste,
|
|
4240
|
+
placeholder: placeholder,
|
|
4241
|
+
rows: rows,
|
|
4242
|
+
value: localValue,
|
|
4243
|
+
disabled: disabled,
|
|
4244
|
+
"data-gramm": "false"
|
|
4245
|
+
}), eventBus && !disabled && jsx(OpenPopupButton, {
|
|
4246
|
+
onClick: handleOpenPopup,
|
|
4247
|
+
translate: translate
|
|
4248
|
+
})]
|
|
4197
4249
|
})]
|
|
4198
4250
|
});
|
|
4199
4251
|
}
|
|
@@ -4214,6 +4266,7 @@ function TextArea(props) {
|
|
|
4214
4266
|
* @param {boolean} props.monospace
|
|
4215
4267
|
* @param {Function} [props.validate]
|
|
4216
4268
|
* @param {boolean} [props.disabled]
|
|
4269
|
+
* @param {Function} [props.translate]
|
|
4217
4270
|
*/
|
|
4218
4271
|
function TextAreaEntry(props) {
|
|
4219
4272
|
const {
|
|
@@ -4233,7 +4286,8 @@ function TextAreaEntry(props) {
|
|
|
4233
4286
|
onPaste,
|
|
4234
4287
|
placeholder,
|
|
4235
4288
|
autoResize,
|
|
4236
|
-
tooltip
|
|
4289
|
+
tooltip,
|
|
4290
|
+
translate
|
|
4237
4291
|
} = props;
|
|
4238
4292
|
const globalError = useError(id);
|
|
4239
4293
|
const [localError, setLocalError] = useState(null);
|
|
@@ -4274,6 +4328,7 @@ function TextAreaEntry(props) {
|
|
|
4274
4328
|
placeholder: placeholder,
|
|
4275
4329
|
autoResize: autoResize,
|
|
4276
4330
|
tooltip: tooltip,
|
|
4331
|
+
translate: translate,
|
|
4277
4332
|
element: element
|
|
4278
4333
|
}, element), error && jsx("div", {
|
|
4279
4334
|
class: "bio-properties-panel-error",
|
|
@@ -4615,6 +4670,9 @@ const noop = () => {};
|
|
|
4615
4670
|
* @param {Function} [props.onPostDeactivate]
|
|
4616
4671
|
* @param {boolean} [props.returnFocus]
|
|
4617
4672
|
* @param {boolean} [props.closeOnEscape]
|
|
4673
|
+
* @param {(event: KeyboardEvent) => boolean} [props.allowFocusMove] -
|
|
4674
|
+
* Whether a Tab keypress may move focus. Return false to leave the keypress
|
|
4675
|
+
* to the focused element, e.g. an editor navigating snippet placeholders.
|
|
4618
4676
|
* @param {string} props.title
|
|
4619
4677
|
* @param {Ref} [ref]
|
|
4620
4678
|
*/
|
|
@@ -4630,6 +4688,7 @@ function PopupComponent(props, globalRef) {
|
|
|
4630
4688
|
onPostDeactivate = noop,
|
|
4631
4689
|
returnFocus = true,
|
|
4632
4690
|
closeOnEscape = true,
|
|
4691
|
+
allowFocusMove = () => true,
|
|
4633
4692
|
title
|
|
4634
4693
|
} = props;
|
|
4635
4694
|
const focusTrapRef = useRef(null);
|
|
@@ -4679,6 +4738,8 @@ function PopupComponent(props, globalRef) {
|
|
|
4679
4738
|
clickOutsideDeactivates: true,
|
|
4680
4739
|
delayInitialFocus,
|
|
4681
4740
|
fallbackFocus: popupRef.current,
|
|
4741
|
+
isKeyForward: event => isTab(event) && !event.shiftKey && allowFocusMove(event),
|
|
4742
|
+
isKeyBackward: event => isTab(event) && event.shiftKey && allowFocusMove(event),
|
|
4682
4743
|
onPostActivate,
|
|
4683
4744
|
onPostDeactivate,
|
|
4684
4745
|
returnFocusOnDeactivate: returnFocus
|
|
@@ -4698,10 +4759,10 @@ function PopupComponent(props, globalRef) {
|
|
|
4698
4759
|
children: props.children
|
|
4699
4760
|
});
|
|
4700
4761
|
}
|
|
4701
|
-
const Popup = forwardRef(PopupComponent);
|
|
4702
|
-
Popup.Title = Title;
|
|
4703
|
-
Popup.Body = Body;
|
|
4704
|
-
Popup.Footer = Footer;
|
|
4762
|
+
const Popup$1 = forwardRef(PopupComponent);
|
|
4763
|
+
Popup$1.Title = Title;
|
|
4764
|
+
Popup$1.Body = Body;
|
|
4765
|
+
Popup$1.Footer = Footer;
|
|
4705
4766
|
function Title(props) {
|
|
4706
4767
|
const {
|
|
4707
4768
|
children,
|
|
@@ -4812,6 +4873,9 @@ function Footer(props) {
|
|
|
4812
4873
|
|
|
4813
4874
|
// helpers //////////////////////
|
|
4814
4875
|
|
|
4876
|
+
function isTab(event) {
|
|
4877
|
+
return event.key === 'Tab';
|
|
4878
|
+
}
|
|
4815
4879
|
function getPopupParent(node) {
|
|
4816
4880
|
return node.closest('.bio-properties-panel-popup');
|
|
4817
4881
|
}
|
|
@@ -4839,13 +4903,13 @@ function cancel(event) {
|
|
|
4839
4903
|
*/
|
|
4840
4904
|
|
|
4841
4905
|
const FEEL_POPUP_WIDTH = 700;
|
|
4842
|
-
const FEEL_POPUP_HEIGHT =
|
|
4906
|
+
const FEEL_POPUP_HEIGHT = 400;
|
|
4843
4907
|
|
|
4844
4908
|
/**
|
|
4845
4909
|
* FEEL expression editor popup component
|
|
4846
4910
|
* @param {FeelPopupProps} props
|
|
4847
4911
|
*/
|
|
4848
|
-
function FeelPopup
|
|
4912
|
+
function FeelPopup(props) {
|
|
4849
4913
|
const {
|
|
4850
4914
|
entryId,
|
|
4851
4915
|
onInput,
|
|
@@ -4890,18 +4954,19 @@ function FeelPopup$1(props) {
|
|
|
4890
4954
|
editorRef.current.focus();
|
|
4891
4955
|
}
|
|
4892
4956
|
}, [editorRef]);
|
|
4893
|
-
return jsxs(Popup, {
|
|
4957
|
+
return jsxs(Popup$1, {
|
|
4894
4958
|
className: "bio-properties-panel-feel-popup",
|
|
4895
4959
|
position: position,
|
|
4896
4960
|
title: title,
|
|
4897
4961
|
returnFocus: false,
|
|
4898
4962
|
closeOnEscape: false,
|
|
4899
4963
|
delayInitialFocus: false,
|
|
4964
|
+
allowFocusMove: event => !isSnippetNavigation(event),
|
|
4900
4965
|
onPostDeactivate: handleSetReturnFocus,
|
|
4901
4966
|
height: FEEL_POPUP_HEIGHT,
|
|
4902
4967
|
width: FEEL_POPUP_WIDTH,
|
|
4903
4968
|
ref: popupRef,
|
|
4904
|
-
children: [jsx(Popup.Title, {
|
|
4969
|
+
children: [jsx(Popup$1.Title, {
|
|
4905
4970
|
title: title,
|
|
4906
4971
|
eventBus: eventBus,
|
|
4907
4972
|
showCloseButton: true,
|
|
@@ -4919,14 +4984,13 @@ function FeelPopup$1(props) {
|
|
|
4919
4984
|
}, index);
|
|
4920
4985
|
})
|
|
4921
4986
|
})
|
|
4922
|
-
}), jsx(Popup.Body, {
|
|
4987
|
+
}), jsx(Popup$1.Body, {
|
|
4923
4988
|
children: jsxs("div", {
|
|
4924
4989
|
onKeyDownCapture: onKeyDownCapture,
|
|
4925
4990
|
onKeyDown: onKeyDown,
|
|
4926
4991
|
class: "bio-properties-panel-feel-popup__body",
|
|
4927
4992
|
children: [type === 'feel' && jsx(FeelEditor, {
|
|
4928
4993
|
enableGutters: true,
|
|
4929
|
-
id: prefixId(entryId),
|
|
4930
4994
|
name: entryId,
|
|
4931
4995
|
onInput: onInput,
|
|
4932
4996
|
value: value,
|
|
@@ -4935,7 +4999,6 @@ function FeelPopup$1(props) {
|
|
|
4935
4999
|
ref: editorRef,
|
|
4936
5000
|
tooltipContainer: tooltipContainer
|
|
4937
5001
|
}), type === 'feelers' && jsx(TemplatingEditor, {
|
|
4938
|
-
id: prefixId(entryId),
|
|
4939
5002
|
contentAttributes: {
|
|
4940
5003
|
'aria-label': title
|
|
4941
5004
|
},
|
|
@@ -4952,14 +5015,17 @@ function FeelPopup$1(props) {
|
|
|
4952
5015
|
})]
|
|
4953
5016
|
});
|
|
4954
5017
|
}
|
|
4955
|
-
function prefixId(id) {
|
|
4956
|
-
return `bio-properties-panel-${id}`;
|
|
4957
|
-
}
|
|
4958
5018
|
function autoCompletionOpen(element) {
|
|
4959
5019
|
const editor = element.closest('.cm-editor');
|
|
4960
5020
|
return editor ? editor.querySelector('.cm-tooltip-autocomplete') : null;
|
|
4961
5021
|
}
|
|
4962
5022
|
|
|
5023
|
+
// while a snippet is active, Tab navigates its placeholders inside the editor
|
|
5024
|
+
function isSnippetNavigation(event) {
|
|
5025
|
+
const editor = event.target.closest('.cm-editor');
|
|
5026
|
+
return !!(editor && editor.querySelector('.cm-snippetField'));
|
|
5027
|
+
}
|
|
5028
|
+
|
|
4963
5029
|
function getPopupTitle({
|
|
4964
5030
|
element,
|
|
4965
5031
|
label
|
|
@@ -4980,7 +5046,102 @@ function getPopupPosition() {
|
|
|
4980
5046
|
}
|
|
4981
5047
|
|
|
4982
5048
|
/**
|
|
4983
|
-
*
|
|
5049
|
+
* @typedef {Object} TextPopupProps
|
|
5050
|
+
* @property {string} entryId
|
|
5051
|
+
* @property {Function} onInput
|
|
5052
|
+
* @property {Function} onClose
|
|
5053
|
+
* @property {string} title
|
|
5054
|
+
* @property {string} value
|
|
5055
|
+
* @property {Object} [position]
|
|
5056
|
+
* @property {HTMLElement} [sourceElement]
|
|
5057
|
+
* @property {Object} [eventBus]
|
|
5058
|
+
*/
|
|
5059
|
+
|
|
5060
|
+
const TEXT_POPUP_WIDTH = 700;
|
|
5061
|
+
const TEXT_POPUP_HEIGHT = 400;
|
|
5062
|
+
|
|
5063
|
+
/**
|
|
5064
|
+
* Plain text editor popup component.
|
|
5065
|
+
*
|
|
5066
|
+
* Intentionally kept separate from the FEEL popup: the two are expected to
|
|
5067
|
+
* diverge as we add FEEL-specific capabilities that do not apply to plain text.
|
|
5068
|
+
*
|
|
5069
|
+
* @param {TextPopupProps} props
|
|
5070
|
+
*/
|
|
5071
|
+
function TextPopup(props) {
|
|
5072
|
+
const {
|
|
5073
|
+
entryId,
|
|
5074
|
+
onInput,
|
|
5075
|
+
onClose,
|
|
5076
|
+
title,
|
|
5077
|
+
value,
|
|
5078
|
+
position,
|
|
5079
|
+
sourceElement,
|
|
5080
|
+
eventBus
|
|
5081
|
+
} = props;
|
|
5082
|
+
const editorRef = useRef();
|
|
5083
|
+
const popupRef = useRef();
|
|
5084
|
+
const handleSetReturnFocus = () => {
|
|
5085
|
+
sourceElement && sourceElement.focus();
|
|
5086
|
+
};
|
|
5087
|
+
useEffect(() => {
|
|
5088
|
+
// set focus on editor when popup is opened
|
|
5089
|
+
if (editorRef.current) {
|
|
5090
|
+
editorRef.current.focus();
|
|
5091
|
+
}
|
|
5092
|
+
}, [editorRef]);
|
|
5093
|
+
return jsxs(Popup$1, {
|
|
5094
|
+
className: "bio-properties-panel-text-popup",
|
|
5095
|
+
position: position,
|
|
5096
|
+
title: title,
|
|
5097
|
+
returnFocus: false,
|
|
5098
|
+
closeOnEscape: true,
|
|
5099
|
+
delayInitialFocus: false,
|
|
5100
|
+
onClose: onClose,
|
|
5101
|
+
onPostDeactivate: handleSetReturnFocus,
|
|
5102
|
+
height: TEXT_POPUP_HEIGHT,
|
|
5103
|
+
width: TEXT_POPUP_WIDTH,
|
|
5104
|
+
ref: popupRef,
|
|
5105
|
+
children: [jsx(Popup$1.Title, {
|
|
5106
|
+
title: title,
|
|
5107
|
+
eventBus: eventBus,
|
|
5108
|
+
showCloseButton: true,
|
|
5109
|
+
closeButtonTooltip: "Save and close",
|
|
5110
|
+
onClose: onClose,
|
|
5111
|
+
draggable: true
|
|
5112
|
+
}), jsx(Popup$1.Body, {
|
|
5113
|
+
children: jsx("textarea", {
|
|
5114
|
+
id: prefixId(entryId),
|
|
5115
|
+
name: entryId,
|
|
5116
|
+
class: "bio-properties-panel-input",
|
|
5117
|
+
ref: editorRef,
|
|
5118
|
+
onInput: e => onInput(e.target.value),
|
|
5119
|
+
value: value || '',
|
|
5120
|
+
spellCheck: "false",
|
|
5121
|
+
autoComplete: "off",
|
|
5122
|
+
"aria-label": title,
|
|
5123
|
+
"data-gramm": "false"
|
|
5124
|
+
})
|
|
5125
|
+
})]
|
|
5126
|
+
});
|
|
5127
|
+
}
|
|
5128
|
+
|
|
5129
|
+
// The in-panel field stays mounted (hidden) while the popup is open, so we
|
|
5130
|
+
// scope the popup editor id to keep it unique in the DOM.
|
|
5131
|
+
function prefixId(id) {
|
|
5132
|
+
return `bio-properties-panel-popup-${id}`;
|
|
5133
|
+
}
|
|
5134
|
+
|
|
5135
|
+
const DEFAULT_POPUP_TYPE = 'text';
|
|
5136
|
+
|
|
5137
|
+
// consumers registering via #registerProvider default to DEFAULT_PRIORITY,
|
|
5138
|
+
// so their providers take precedence over the LOW_PRIORITY built-ins.
|
|
5139
|
+
const DEFAULT_PRIORITY = 1000;
|
|
5140
|
+
const LOW_PRIORITY = 500;
|
|
5141
|
+
|
|
5142
|
+
/**
|
|
5143
|
+
* Popup manager, built as a singleton. Renders the registered provider for a
|
|
5144
|
+
* given popup type; consumers may plug in their own via #registerProvider.
|
|
4984
5145
|
*
|
|
4985
5146
|
* In order to implement a custom replacement, handle the following events:
|
|
4986
5147
|
* - `propertiesPanel.openPopup`
|
|
@@ -4993,16 +5154,19 @@ function getPopupPosition() {
|
|
|
4993
5154
|
* - `feelPopup.close` - fired before the popup is unmounted. Event context contains the DOM node of the popup as `domNode`
|
|
4994
5155
|
* - `feelPopup.closed` - fired after the popup is unmounted
|
|
4995
5156
|
*/
|
|
4996
|
-
class
|
|
5157
|
+
class Popup {
|
|
4997
5158
|
constructor(eventBus, config = {}) {
|
|
4998
5159
|
this._eventBus = eventBus;
|
|
4999
5160
|
this._config = config;
|
|
5000
5161
|
this._isOpen = false;
|
|
5001
|
-
eventBus.on('propertiesPanel.openPopup', (_, context) => {
|
|
5002
|
-
this.open(context.entryId, context, context.sourceElement);
|
|
5003
5162
|
|
|
5004
|
-
|
|
5005
|
-
|
|
5163
|
+
// built-in providers, registered at LOW_PRIORITY so consumers can
|
|
5164
|
+
// override them via #registerProvider using the default priority
|
|
5165
|
+
this.registerProvider('feel', LOW_PRIORITY, FeelPopup);
|
|
5166
|
+
this.registerProvider('feelers', LOW_PRIORITY, FeelPopup);
|
|
5167
|
+
this.registerProvider('text', LOW_PRIORITY, TextPopup);
|
|
5168
|
+
eventBus.on('propertiesPanel.openPopup', (_, context) => {
|
|
5169
|
+
return this.open(context.entryId, context, context.sourceElement);
|
|
5006
5170
|
});
|
|
5007
5171
|
eventBus.on(['propertiesPanel.closePopup', 'propertiesPanel.detach'], () => {
|
|
5008
5172
|
this.close();
|
|
@@ -5010,7 +5174,43 @@ class FeelPopup {
|
|
|
5010
5174
|
}
|
|
5011
5175
|
|
|
5012
5176
|
/**
|
|
5013
|
-
*
|
|
5177
|
+
* Register a popup provider (component) for a given type.
|
|
5178
|
+
*
|
|
5179
|
+
* A higher `priority` wins when multiple providers are registered for the
|
|
5180
|
+
* same type; the built-in providers use a low priority so consumers override
|
|
5181
|
+
* them by default.
|
|
5182
|
+
*
|
|
5183
|
+
* @param {string} type
|
|
5184
|
+
* @param {number} [priority=DEFAULT_PRIORITY]
|
|
5185
|
+
* @param {Function|import('preact').Component} provider
|
|
5186
|
+
*/
|
|
5187
|
+
registerProvider(type, priority, provider) {
|
|
5188
|
+
if (!provider) {
|
|
5189
|
+
provider = priority;
|
|
5190
|
+
priority = DEFAULT_PRIORITY;
|
|
5191
|
+
}
|
|
5192
|
+
this._eventBus.on('propertiesPanelPopup.getProviders.' + type, priority, function (event) {
|
|
5193
|
+
event.providers.push(provider);
|
|
5194
|
+
});
|
|
5195
|
+
}
|
|
5196
|
+
|
|
5197
|
+
/**
|
|
5198
|
+
* Get the popup providers registered for a type.
|
|
5199
|
+
*
|
|
5200
|
+
* @param {string} type
|
|
5201
|
+
* @return {Array<Function|import('preact').Component>}
|
|
5202
|
+
*/
|
|
5203
|
+
_getProviders(type) {
|
|
5204
|
+
const event = this._eventBus.createEvent({
|
|
5205
|
+
type: 'propertiesPanelPopup.getProviders.' + type,
|
|
5206
|
+
providers: []
|
|
5207
|
+
});
|
|
5208
|
+
this._eventBus.fire(event);
|
|
5209
|
+
return event.providers;
|
|
5210
|
+
}
|
|
5211
|
+
|
|
5212
|
+
/**
|
|
5213
|
+
* Check if the popup is open.
|
|
5014
5214
|
* @return {Boolean}
|
|
5015
5215
|
*/
|
|
5016
5216
|
isOpen() {
|
|
@@ -5018,7 +5218,7 @@ class FeelPopup {
|
|
|
5018
5218
|
}
|
|
5019
5219
|
|
|
5020
5220
|
/**
|
|
5021
|
-
* Open the
|
|
5221
|
+
* Open the popup.
|
|
5022
5222
|
*
|
|
5023
5223
|
* @param {String} entryId
|
|
5024
5224
|
* @param {Object} popupConfig
|
|
@@ -5027,7 +5227,7 @@ class FeelPopup {
|
|
|
5027
5227
|
open(entryId, popupConfig, sourceElement) {
|
|
5028
5228
|
// close before opening a new one
|
|
5029
5229
|
this.close();
|
|
5030
|
-
this._openPopup({
|
|
5230
|
+
return this._openPopup({
|
|
5031
5231
|
...popupConfig,
|
|
5032
5232
|
entryId,
|
|
5033
5233
|
sourceElement
|
|
@@ -5035,7 +5235,7 @@ class FeelPopup {
|
|
|
5035
5235
|
}
|
|
5036
5236
|
|
|
5037
5237
|
/**
|
|
5038
|
-
* Close the
|
|
5238
|
+
* Close the popup.
|
|
5039
5239
|
*/
|
|
5040
5240
|
close() {
|
|
5041
5241
|
this._closePopup();
|
|
@@ -5045,13 +5245,18 @@ class FeelPopup {
|
|
|
5045
5245
|
element,
|
|
5046
5246
|
label,
|
|
5047
5247
|
sourceElement,
|
|
5048
|
-
type
|
|
5248
|
+
type = DEFAULT_POPUP_TYPE
|
|
5049
5249
|
} = context;
|
|
5250
|
+
const component = this._getProviders(type)[0];
|
|
5251
|
+
if (!component) {
|
|
5252
|
+
return false;
|
|
5253
|
+
}
|
|
5050
5254
|
this._isOpen = true;
|
|
5051
5255
|
this._eventBus.fire('propertiesPanelPopup.open', {
|
|
5052
5256
|
container: this._config.feelPopupContainer,
|
|
5053
5257
|
config: {
|
|
5054
5258
|
...context,
|
|
5259
|
+
component,
|
|
5055
5260
|
links: this._config.getFeelPopupLinks?.(type) || [],
|
|
5056
5261
|
onClose: () => {
|
|
5057
5262
|
this._closePopup();
|
|
@@ -5068,6 +5273,7 @@ class FeelPopup {
|
|
|
5068
5273
|
})
|
|
5069
5274
|
}
|
|
5070
5275
|
});
|
|
5276
|
+
return true;
|
|
5071
5277
|
}
|
|
5072
5278
|
_closePopup() {
|
|
5073
5279
|
if (this._isOpen) {
|
|
@@ -5076,9 +5282,9 @@ class FeelPopup {
|
|
|
5076
5282
|
}
|
|
5077
5283
|
}
|
|
5078
5284
|
}
|
|
5079
|
-
|
|
5285
|
+
Popup.$inject = ['eventBus', 'config.propertiesPanel'];
|
|
5080
5286
|
|
|
5081
|
-
class
|
|
5287
|
+
class PopupRenderer {
|
|
5082
5288
|
constructor(eventBus) {
|
|
5083
5289
|
this._eventBus = eventBus;
|
|
5084
5290
|
this._container = null;
|
|
@@ -5104,7 +5310,8 @@ class FeelPopupRenderer {
|
|
|
5104
5310
|
// a custom renderer would have to use that context provider as well to have
|
|
5105
5311
|
// access to the event bus and other services
|
|
5106
5312
|
this._emit('feelPopup.open');
|
|
5107
|
-
|
|
5313
|
+
const Component = config.component;
|
|
5314
|
+
render(jsx(Component, {
|
|
5108
5315
|
...config,
|
|
5109
5316
|
eventBus: this._eventBus
|
|
5110
5317
|
}), element);
|
|
@@ -5128,7 +5335,7 @@ class FeelPopupRenderer {
|
|
|
5128
5335
|
this._eventBus.fire(event, context);
|
|
5129
5336
|
}
|
|
5130
5337
|
}
|
|
5131
|
-
|
|
5338
|
+
PopupRenderer.$inject = ['eventBus'];
|
|
5132
5339
|
|
|
5133
5340
|
// helpers /////////////////
|
|
5134
5341
|
|
|
@@ -5146,8 +5353,8 @@ function getContainer(container) {
|
|
|
5146
5353
|
|
|
5147
5354
|
var index = {
|
|
5148
5355
|
__init__: ['feelPopup', 'feelPopupRenderer'],
|
|
5149
|
-
feelPopup: ['type',
|
|
5150
|
-
feelPopupRenderer: ['type',
|
|
5356
|
+
feelPopup: ['type', Popup],
|
|
5357
|
+
feelPopupRenderer: ['type', PopupRenderer]
|
|
5151
5358
|
};
|
|
5152
5359
|
|
|
5153
5360
|
export { Arrow as ArrowIcon, CheckboxEntry, CheckboxGroup, Close as CloseIcon, CollapsibleEntry, Create as CreateIcon, index$1 as DebounceInputModule, Delete as DeleteIcon, DescriptionContext, Description as DescriptionEntry, Drag as DragIcon, DropdownButton, ErrorsContext, EventContext, ExternalLink as ExternalLinkIcon, FeelCheckboxEntry, FeelEntry, Feel as FeelIcon, FeelLanguageContext, FeelNumberEntry, index as FeelPopupModule, FeelTemplatingEntry, FeelTextAreaEntry, FeelToggleSwitchEntry, Group, Header, HeaderButton, JsonEditorEntry, Launch as LaunchIcon, LayoutContext, List as ListEntry, ListGroup, ListItem, NumberFieldEntry, OpenPopup as OpenPopupIcon, Placeholder, PropertiesPanel, LayoutContext as PropertiesPanelContext, SelectEntry, Simple as SimpleEntry, TemplatingEntry, TextAreaEntry, TextfieldEntry as TextFieldEntry, ToggleSwitchEntry, TooltipContext, TooltipWrapper as TooltipEntry, isEdited$9 as isCheckboxEntryEdited, isEdited$5 as isFeelEntryEdited, isEdited$8 as isJsonEditorEntryEdited, isEdited$6 as isNumberFieldEntryEdited, isEdited$3 as isSelectEntryEdited, isEdited$2 as isSimpleEntryEdited, isEdited$4 as isTemplatingEntryEdited, isEdited$1 as isTextAreaEntryEdited, isEdited as isTextFieldEntryEdited, isEdited$7 as isToggleSwitchEntryEdited, useDebounce, useDescriptionContext, useElementVisible, useError, useErrors, useEvent, useKeyFactory, useLayoutState, usePrevious, useShowEntryEvent, useStaticCallback, useStickyIntersectionObserver, useTooltipContext };
|