@bpmn-io/form-js-editor 1.18.0 → 1.20.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.css +7 -1
- package/dist/assets/properties-panel.css +7 -1
- package/dist/index.cjs +522 -77
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +522 -77
- package/dist/index.es.js.map +1 -1
- package/package.json +7 -7
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var ids$1 = require('ids');
|
|
4
4
|
var formJsViewer = require('@bpmn-io/form-js-viewer');
|
|
5
5
|
var minDash = require('min-dash');
|
|
6
6
|
var classnames = require('classnames');
|
|
@@ -2890,11 +2890,35 @@ EditorActions.prototype._registerDefaultActions = function (injector) {
|
|
|
2890
2890
|
}
|
|
2891
2891
|
});
|
|
2892
2892
|
}
|
|
2893
|
+
if (copyPaste && selection) {
|
|
2894
|
+
this.register('duplicate', function () {
|
|
2895
|
+
var selectedElements = selection.get();
|
|
2896
|
+
if (selectedElements.length) {
|
|
2897
|
+
return copyPaste.duplicate(selectedElements);
|
|
2898
|
+
}
|
|
2899
|
+
});
|
|
2900
|
+
}
|
|
2893
2901
|
if (copyPaste) {
|
|
2894
2902
|
this.register('paste', function () {
|
|
2895
2903
|
copyPaste.paste();
|
|
2896
2904
|
});
|
|
2897
2905
|
}
|
|
2906
|
+
if (copyPaste && selection && rules) {
|
|
2907
|
+
this.register('cut', function () {
|
|
2908
|
+
var selectedElements = selection.get();
|
|
2909
|
+
if (!selectedElements.length) {
|
|
2910
|
+
return;
|
|
2911
|
+
}
|
|
2912
|
+
var allowed = rules.allowed('elements.delete', {
|
|
2913
|
+
elements: selectedElements
|
|
2914
|
+
});
|
|
2915
|
+
if (allowed === false) {
|
|
2916
|
+
return;
|
|
2917
|
+
}
|
|
2918
|
+
var cuttableElements = minDash.isArray(allowed) ? allowed : selectedElements;
|
|
2919
|
+
return copyPaste.cut(cuttableElements.slice());
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2898
2922
|
if (zoomScroll) {
|
|
2899
2923
|
this.register('stepZoom', function (opts) {
|
|
2900
2924
|
zoomScroll.stepZoom(opts.value);
|
|
@@ -3113,6 +3137,8 @@ const EditorExpressionLanguageModule = {
|
|
|
3113
3137
|
|
|
3114
3138
|
var KEYS_COPY = ['c', 'C'];
|
|
3115
3139
|
var KEYS_PASTE = ['v', 'V'];
|
|
3140
|
+
var KEYS_DUPLICATE = ['d', 'D'];
|
|
3141
|
+
var KEYS_CUT = ['x', 'X'];
|
|
3116
3142
|
var KEYS_REDO = ['y', 'Y'];
|
|
3117
3143
|
var KEYS_UNDO = ['z', 'Z'];
|
|
3118
3144
|
|
|
@@ -3128,7 +3154,7 @@ function hasModifier(event) {
|
|
|
3128
3154
|
* @param {KeyboardEvent} event
|
|
3129
3155
|
* @return {boolean}
|
|
3130
3156
|
*/
|
|
3131
|
-
function isCmd(event) {
|
|
3157
|
+
function isCmd$1(event) {
|
|
3132
3158
|
// ensure we don't react to AltGr
|
|
3133
3159
|
// (mapped to CTRL + ALT)
|
|
3134
3160
|
if (event.altKey) {
|
|
@@ -3160,28 +3186,42 @@ function isShift(event) {
|
|
|
3160
3186
|
* @param {KeyboardEvent} event
|
|
3161
3187
|
*/
|
|
3162
3188
|
function isCopy(event) {
|
|
3163
|
-
return isCmd(event) && isKey(KEYS_COPY, event);
|
|
3189
|
+
return isCmd$1(event) && isKey(KEYS_COPY, event);
|
|
3164
3190
|
}
|
|
3165
3191
|
|
|
3166
3192
|
/**
|
|
3167
3193
|
* @param {KeyboardEvent} event
|
|
3168
3194
|
*/
|
|
3169
3195
|
function isPaste(event) {
|
|
3170
|
-
return isCmd(event) && isKey(KEYS_PASTE, event);
|
|
3196
|
+
return isCmd$1(event) && isKey(KEYS_PASTE, event);
|
|
3197
|
+
}
|
|
3198
|
+
|
|
3199
|
+
/**
|
|
3200
|
+
* @param {KeyboardEvent} event
|
|
3201
|
+
*/
|
|
3202
|
+
function isDuplicate(event) {
|
|
3203
|
+
return isCmd$1(event) && isKey(KEYS_DUPLICATE, event);
|
|
3204
|
+
}
|
|
3205
|
+
|
|
3206
|
+
/**
|
|
3207
|
+
* @param {KeyboardEvent} event
|
|
3208
|
+
*/
|
|
3209
|
+
function isCut(event) {
|
|
3210
|
+
return isCmd$1(event) && isKey(KEYS_CUT, event);
|
|
3171
3211
|
}
|
|
3172
3212
|
|
|
3173
3213
|
/**
|
|
3174
3214
|
* @param {KeyboardEvent} event
|
|
3175
3215
|
*/
|
|
3176
3216
|
function isUndo(event) {
|
|
3177
|
-
return isCmd(event) && !isShift(event) && isKey(KEYS_UNDO, event);
|
|
3217
|
+
return isCmd$1(event) && !isShift(event) && isKey(KEYS_UNDO, event);
|
|
3178
3218
|
}
|
|
3179
3219
|
|
|
3180
3220
|
/**
|
|
3181
3221
|
* @param {KeyboardEvent} event
|
|
3182
3222
|
*/
|
|
3183
3223
|
function isRedo(event) {
|
|
3184
|
-
return isCmd(event) && (isKey(KEYS_REDO, event) || isKey(KEYS_UNDO, event) && isShift(event));
|
|
3224
|
+
return isCmd$1(event) && (isKey(KEYS_REDO, event) || isKey(KEYS_UNDO, event) && isShift(event));
|
|
3185
3225
|
}
|
|
3186
3226
|
|
|
3187
3227
|
/**
|
|
@@ -3350,7 +3390,7 @@ Keyboard.prototype.removeListener = function (listener, type) {
|
|
|
3350
3390
|
this._eventBus.off(type || KEYDOWN_EVENT, listener);
|
|
3351
3391
|
};
|
|
3352
3392
|
Keyboard.prototype.hasModifier = hasModifier;
|
|
3353
|
-
Keyboard.prototype.isCmd = isCmd;
|
|
3393
|
+
Keyboard.prototype.isCmd = isCmd$1;
|
|
3354
3394
|
Keyboard.prototype.isShift = isShift;
|
|
3355
3395
|
Keyboard.prototype.isKey = isKey;
|
|
3356
3396
|
|
|
@@ -3435,6 +3475,26 @@ KeyboardBindings.prototype.registerBindings = function (keyboard, editorActions)
|
|
|
3435
3475
|
}
|
|
3436
3476
|
});
|
|
3437
3477
|
|
|
3478
|
+
// duplicate
|
|
3479
|
+
// CTRL/CMD + D
|
|
3480
|
+
addListener('duplicate', function (context) {
|
|
3481
|
+
var event = context.keyEvent;
|
|
3482
|
+
if (isDuplicate(event)) {
|
|
3483
|
+
editorActions.trigger('duplicate');
|
|
3484
|
+
return true;
|
|
3485
|
+
}
|
|
3486
|
+
});
|
|
3487
|
+
|
|
3488
|
+
// cut
|
|
3489
|
+
// CTRL/CMD + X
|
|
3490
|
+
addListener('cut', function (context) {
|
|
3491
|
+
var event = context.keyEvent;
|
|
3492
|
+
if (isCut(event)) {
|
|
3493
|
+
editorActions.trigger('cut');
|
|
3494
|
+
return true;
|
|
3495
|
+
}
|
|
3496
|
+
});
|
|
3497
|
+
|
|
3438
3498
|
// zoom in one step
|
|
3439
3499
|
// CTRL/CMD + +
|
|
3440
3500
|
addListener('stepZoom', function (context) {
|
|
@@ -3442,7 +3502,7 @@ KeyboardBindings.prototype.registerBindings = function (keyboard, editorActions)
|
|
|
3442
3502
|
|
|
3443
3503
|
// quirk: it has to be triggered by `=` as well to work on international keyboard layout
|
|
3444
3504
|
// cf: https://github.com/bpmn-io/bpmn-js/issues/1362#issuecomment-722989754
|
|
3445
|
-
if (isKey(['+', 'Add', '='], event) && isCmd(event)) {
|
|
3505
|
+
if (isKey(['+', 'Add', '='], event) && isCmd$1(event)) {
|
|
3446
3506
|
editorActions.trigger('stepZoom', {
|
|
3447
3507
|
value: 1
|
|
3448
3508
|
});
|
|
@@ -3454,7 +3514,7 @@ KeyboardBindings.prototype.registerBindings = function (keyboard, editorActions)
|
|
|
3454
3514
|
// CTRL + -
|
|
3455
3515
|
addListener('stepZoom', function (context) {
|
|
3456
3516
|
var event = context.keyEvent;
|
|
3457
|
-
if (isKey(['-', 'Subtract'], event) && isCmd(event)) {
|
|
3517
|
+
if (isKey(['-', 'Subtract'], event) && isCmd$1(event)) {
|
|
3458
3518
|
editorActions.trigger('stepZoom', {
|
|
3459
3519
|
value: -1
|
|
3460
3520
|
});
|
|
@@ -3466,7 +3526,7 @@ KeyboardBindings.prototype.registerBindings = function (keyboard, editorActions)
|
|
|
3466
3526
|
// CTRL + 0
|
|
3467
3527
|
addListener('zoom', function (context) {
|
|
3468
3528
|
var event = context.keyEvent;
|
|
3469
|
-
if (isKey('0', event) && isCmd(event)) {
|
|
3529
|
+
if (isKey('0', event) && isCmd$1(event)) {
|
|
3470
3530
|
editorActions.trigger('zoom', {
|
|
3471
3531
|
value: 1
|
|
3472
3532
|
});
|
|
@@ -5473,6 +5533,21 @@ OpenPopupIcon.defaultProps = {
|
|
|
5473
5533
|
xmlns: "http://www.w3.org/2000/svg",
|
|
5474
5534
|
viewBox: "0 0 16 16"
|
|
5475
5535
|
};
|
|
5536
|
+
|
|
5537
|
+
/**
|
|
5538
|
+
* @typedef { {
|
|
5539
|
+
* getElementLabel: (element: object) => string,
|
|
5540
|
+
* getTypeLabel: (element: object) => string,
|
|
5541
|
+
* getElementIcon: (element: object) => import('preact').Component,
|
|
5542
|
+
* getDocumentationRef: (element: object) => string
|
|
5543
|
+
* } } HeaderProvider
|
|
5544
|
+
*/
|
|
5545
|
+
|
|
5546
|
+
/**
|
|
5547
|
+
* @param {Object} props
|
|
5548
|
+
* @param {Object} props.element,
|
|
5549
|
+
* @param {HeaderProvider} props.headerProvider
|
|
5550
|
+
*/
|
|
5476
5551
|
function Header(props) {
|
|
5477
5552
|
const {
|
|
5478
5553
|
element,
|
|
@@ -5500,11 +5575,9 @@ function Header(props) {
|
|
|
5500
5575
|
}), jsxRuntime.jsxs("div", {
|
|
5501
5576
|
class: "bio-properties-panel-header-labels",
|
|
5502
5577
|
children: [jsxRuntime.jsx("div", {
|
|
5503
|
-
title: type,
|
|
5504
5578
|
class: "bio-properties-panel-header-type",
|
|
5505
5579
|
children: type
|
|
5506
5580
|
}), label ? jsxRuntime.jsx("div", {
|
|
5507
|
-
title: label,
|
|
5508
5581
|
class: "bio-properties-panel-header-label",
|
|
5509
5582
|
children: label
|
|
5510
5583
|
}) : null]
|
|
@@ -5592,6 +5665,27 @@ function useTooltipContext(id, element) {
|
|
|
5592
5665
|
} = hooks.useContext(TooltipContext);
|
|
5593
5666
|
return getTooltipForId(id, element);
|
|
5594
5667
|
}
|
|
5668
|
+
|
|
5669
|
+
/**
|
|
5670
|
+
* @typedef {Object} TooltipProps
|
|
5671
|
+
* @property {Object} [parent] - Parent element ref for portal rendering
|
|
5672
|
+
* @property {String} [direction='right'] - Tooltip direction ( 'right', 'top')
|
|
5673
|
+
* @property {String} [position] - Custom CSS position override
|
|
5674
|
+
* @property {Number} [showDelay=250] - Delay in ms before showing tooltip on hover
|
|
5675
|
+
* @property {Number} [hideDelay=250] - Delay in ms before hiding tooltip when mouse leaves, to avoid multiple tooltips from being opened, this should be the same as showDelay
|
|
5676
|
+
* @property {*} [children] - Child elements to render inside the tooltip wrapper
|
|
5677
|
+
*/
|
|
5678
|
+
|
|
5679
|
+
/**
|
|
5680
|
+
* Tooltip wrapper that provides context-based tooltip content lookup.
|
|
5681
|
+
* All props are forwarded to the underlying Tooltip component.
|
|
5682
|
+
*
|
|
5683
|
+
* @param {TooltipProps & {
|
|
5684
|
+
* forId: String,
|
|
5685
|
+
* value?: String|Object,
|
|
5686
|
+
* element?: Object
|
|
5687
|
+
* }} props - Shared tooltip props plus wrapper-specific ones
|
|
5688
|
+
*/
|
|
5595
5689
|
function TooltipWrapper(props) {
|
|
5596
5690
|
const {
|
|
5597
5691
|
forId,
|
|
@@ -5608,35 +5702,93 @@ function TooltipWrapper(props) {
|
|
|
5608
5702
|
forId: `bio-properties-panel-${forId}`
|
|
5609
5703
|
});
|
|
5610
5704
|
}
|
|
5705
|
+
|
|
5706
|
+
/**
|
|
5707
|
+
* @param {TooltipProps & {
|
|
5708
|
+
* forId: String,
|
|
5709
|
+
* value: String|Object
|
|
5710
|
+
* }} props
|
|
5711
|
+
*/
|
|
5611
5712
|
function Tooltip(props) {
|
|
5612
5713
|
const {
|
|
5613
5714
|
forId,
|
|
5614
5715
|
value,
|
|
5615
5716
|
parent,
|
|
5616
5717
|
direction = 'right',
|
|
5617
|
-
position
|
|
5718
|
+
position,
|
|
5719
|
+
showDelay = 250,
|
|
5720
|
+
hideDelay = 250
|
|
5618
5721
|
} = props;
|
|
5619
5722
|
const [visible, setVisible] = hooks.useState(false);
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
const
|
|
5623
|
-
|
|
5723
|
+
const [tooltipPosition, setTooltipPosition] = hooks.useState(null);
|
|
5724
|
+
const [arrowOffset, setArrowOffset] = hooks.useState(null);
|
|
5725
|
+
const showTimeoutRef = hooks.useRef(null);
|
|
5726
|
+
const hideTimeoutRef = hooks.useRef(null);
|
|
5624
5727
|
const wrapperRef = hooks.useRef(null);
|
|
5625
5728
|
const tooltipRef = hooks.useRef(null);
|
|
5626
5729
|
const show = (_, delay) => {
|
|
5730
|
+
clearTimeout(showTimeoutRef.current);
|
|
5731
|
+
clearTimeout(hideTimeoutRef.current);
|
|
5627
5732
|
if (visible) return;
|
|
5628
5733
|
if (delay) {
|
|
5629
|
-
|
|
5734
|
+
showTimeoutRef.current = setTimeout(() => {
|
|
5630
5735
|
setVisible(true);
|
|
5631
|
-
},
|
|
5736
|
+
}, showDelay);
|
|
5632
5737
|
} else {
|
|
5633
5738
|
setVisible(true);
|
|
5634
5739
|
}
|
|
5635
5740
|
};
|
|
5636
|
-
const
|
|
5637
|
-
|
|
5638
|
-
|
|
5741
|
+
const handleWrapperMouseEnter = e => {
|
|
5742
|
+
show(e, true);
|
|
5743
|
+
};
|
|
5744
|
+
const hide = (delay = false) => {
|
|
5745
|
+
clearTimeout(showTimeoutRef.current);
|
|
5746
|
+
clearTimeout(hideTimeoutRef.current);
|
|
5747
|
+
if (delay) {
|
|
5748
|
+
hideTimeoutRef.current = setTimeout(() => {
|
|
5749
|
+
setVisible(false);
|
|
5750
|
+
}, hideDelay);
|
|
5751
|
+
} else {
|
|
5752
|
+
setVisible(false);
|
|
5753
|
+
}
|
|
5639
5754
|
};
|
|
5755
|
+
|
|
5756
|
+
// Cleanup timeouts on unmount
|
|
5757
|
+
hooks.useEffect(() => {
|
|
5758
|
+
return () => {
|
|
5759
|
+
clearTimeout(showTimeoutRef.current);
|
|
5760
|
+
clearTimeout(hideTimeoutRef.current);
|
|
5761
|
+
};
|
|
5762
|
+
}, []);
|
|
5763
|
+
|
|
5764
|
+
// Handle click outside to close tooltip for non-focusable elements
|
|
5765
|
+
hooks.useEffect(() => {
|
|
5766
|
+
if (!visible) return;
|
|
5767
|
+
const handleClickOutside = e => {
|
|
5768
|
+
// If clicking outside both the wrapper and tooltip, hide it
|
|
5769
|
+
if (wrapperRef.current && !wrapperRef.current.contains(e.target) && tooltipRef.current && !tooltipRef.current.contains(e.target)) {
|
|
5770
|
+
hide(false);
|
|
5771
|
+
}
|
|
5772
|
+
};
|
|
5773
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
5774
|
+
return () => {
|
|
5775
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
5776
|
+
};
|
|
5777
|
+
}, [visible, hide]);
|
|
5778
|
+
hooks.useLayoutEffect(() => {
|
|
5779
|
+
if (!visible || position) {
|
|
5780
|
+
setTooltipPosition(null);
|
|
5781
|
+
setArrowOffset(null);
|
|
5782
|
+
return;
|
|
5783
|
+
}
|
|
5784
|
+
if (!wrapperRef.current || !tooltipRef.current) return;
|
|
5785
|
+
const {
|
|
5786
|
+
tooltipPosition: newPosition,
|
|
5787
|
+
arrowOffset: newArrowOffset
|
|
5788
|
+
} = getTooltipPosition(wrapperRef.current, tooltipRef.current, direction);
|
|
5789
|
+
setTooltipPosition(newPosition);
|
|
5790
|
+
setArrowOffset(newArrowOffset);
|
|
5791
|
+
}, [visible, position]);
|
|
5640
5792
|
const handleMouseLeave = ({
|
|
5641
5793
|
relatedTarget
|
|
5642
5794
|
}) => {
|
|
@@ -5644,39 +5796,52 @@ function Tooltip(props) {
|
|
|
5644
5796
|
if (relatedTarget === wrapperRef.current || relatedTarget === tooltipRef.current || relatedTarget?.parentElement === tooltipRef.current) {
|
|
5645
5797
|
return;
|
|
5646
5798
|
}
|
|
5647
|
-
|
|
5799
|
+
const selection = window.getSelection();
|
|
5800
|
+
if (selection && selection.toString().length > 0) {
|
|
5801
|
+
// Check if selection is within tooltip content
|
|
5802
|
+
const selectionRange = selection.getRangeAt(0);
|
|
5803
|
+
if (tooltipRef.current?.contains(selectionRange.commonAncestorContainer) || tooltipRef.current?.contains(selection.anchorNode) || tooltipRef.current?.contains(selection.focusNode)) {
|
|
5804
|
+
return; // Keep tooltip open during text selection
|
|
5805
|
+
}
|
|
5806
|
+
}
|
|
5807
|
+
hide(true);
|
|
5808
|
+
};
|
|
5809
|
+
const handleTooltipMouseEnter = () => {
|
|
5810
|
+
clearTimeout(hideTimeoutRef.current);
|
|
5648
5811
|
};
|
|
5649
5812
|
const handleFocusOut = e => {
|
|
5650
5813
|
const {
|
|
5651
|
-
|
|
5814
|
+
relatedTarget
|
|
5652
5815
|
} = e;
|
|
5653
5816
|
|
|
5654
|
-
// Don't hide
|
|
5655
|
-
|
|
5656
|
-
if (target === wrapperRef.current && isHovered) {
|
|
5657
|
-
e.stopPropagation();
|
|
5817
|
+
// Don't hide if focus moved to the tooltip or another element within the wrapper
|
|
5818
|
+
if (tooltipRef.current?.contains(relatedTarget) || wrapperRef.current?.contains(relatedTarget)) {
|
|
5658
5819
|
return;
|
|
5659
5820
|
}
|
|
5660
|
-
hide();
|
|
5821
|
+
hide(false);
|
|
5661
5822
|
};
|
|
5662
5823
|
const hideTooltipViaEscape = e => {
|
|
5663
|
-
e.code === 'Escape' && hide();
|
|
5824
|
+
e.code === 'Escape' && hide(false);
|
|
5664
5825
|
};
|
|
5665
5826
|
const renderTooltip = () => {
|
|
5827
|
+
const tooltipStyle = position || (tooltipPosition ? `right: ${tooltipPosition.right}; top: ${tooltipPosition.top}px;` : undefined);
|
|
5828
|
+
const arrowStyle = arrowOffset != null ? `margin-top: ${arrowOffset}px;` : undefined;
|
|
5666
5829
|
return jsxRuntime.jsxs("div", {
|
|
5667
5830
|
class: `bio-properties-panel-tooltip ${direction}`,
|
|
5668
5831
|
role: "tooltip",
|
|
5669
5832
|
id: "bio-properties-panel-tooltip",
|
|
5670
5833
|
"aria-labelledby": forId,
|
|
5671
|
-
style:
|
|
5834
|
+
style: tooltipStyle,
|
|
5672
5835
|
ref: tooltipRef,
|
|
5673
5836
|
onClick: e => e.stopPropagation(),
|
|
5837
|
+
onMouseEnter: handleTooltipMouseEnter,
|
|
5674
5838
|
onMouseLeave: handleMouseLeave,
|
|
5675
5839
|
children: [jsxRuntime.jsx("div", {
|
|
5676
5840
|
class: "bio-properties-panel-tooltip-content",
|
|
5677
5841
|
children: value
|
|
5678
5842
|
}), jsxRuntime.jsx("div", {
|
|
5679
|
-
class: "bio-properties-panel-tooltip-arrow"
|
|
5843
|
+
class: "bio-properties-panel-tooltip-arrow",
|
|
5844
|
+
style: arrowStyle
|
|
5680
5845
|
})]
|
|
5681
5846
|
});
|
|
5682
5847
|
};
|
|
@@ -5684,7 +5849,7 @@ function Tooltip(props) {
|
|
|
5684
5849
|
class: "bio-properties-panel-tooltip-wrapper",
|
|
5685
5850
|
tabIndex: "0",
|
|
5686
5851
|
ref: wrapperRef,
|
|
5687
|
-
onMouseEnter:
|
|
5852
|
+
onMouseEnter: handleWrapperMouseEnter,
|
|
5688
5853
|
onMouseLeave: handleMouseLeave,
|
|
5689
5854
|
onFocus: show,
|
|
5690
5855
|
onBlur: handleFocusOut,
|
|
@@ -5695,11 +5860,47 @@ function Tooltip(props) {
|
|
|
5695
5860
|
|
|
5696
5861
|
// helper
|
|
5697
5862
|
|
|
5698
|
-
function getTooltipPosition(refElement) {
|
|
5863
|
+
function getTooltipPosition(refElement, tooltipElement, direction) {
|
|
5864
|
+
if (!refElement) {
|
|
5865
|
+
return {
|
|
5866
|
+
tooltipPosition: null,
|
|
5867
|
+
arrowOffset: null
|
|
5868
|
+
};
|
|
5869
|
+
}
|
|
5699
5870
|
const refPosition = refElement.getBoundingClientRect();
|
|
5700
5871
|
const right = `calc(100% - ${refPosition.x}px)`;
|
|
5701
|
-
|
|
5702
|
-
|
|
5872
|
+
let top = refPosition.top - 10;
|
|
5873
|
+
let arrowOffset = null;
|
|
5874
|
+
|
|
5875
|
+
// Ensure that the tooltip is within the viewport, adjust the top position if needed.
|
|
5876
|
+
// This is only relevant for the 'right' direction for now
|
|
5877
|
+
if (tooltipElement && direction === 'right') {
|
|
5878
|
+
const tooltipRect = tooltipElement.getBoundingClientRect();
|
|
5879
|
+
const viewportHeight = window.innerHeight;
|
|
5880
|
+
const minTop = 0;
|
|
5881
|
+
const maxTop = viewportHeight - tooltipRect.height;
|
|
5882
|
+
const originalTop = top;
|
|
5883
|
+
if (top > maxTop) {
|
|
5884
|
+
top = maxTop;
|
|
5885
|
+
}
|
|
5886
|
+
if (top < minTop) {
|
|
5887
|
+
top = minTop;
|
|
5888
|
+
}
|
|
5889
|
+
|
|
5890
|
+
// Adjust the arrow position if the tooltip had to be moved to stay within viewport
|
|
5891
|
+
if (top !== originalTop) {
|
|
5892
|
+
const defaultMarginTop = 16;
|
|
5893
|
+
const topDiff = top - originalTop;
|
|
5894
|
+
arrowOffset = defaultMarginTop - topDiff;
|
|
5895
|
+
}
|
|
5896
|
+
}
|
|
5897
|
+
return {
|
|
5898
|
+
tooltipPosition: {
|
|
5899
|
+
right,
|
|
5900
|
+
top
|
|
5901
|
+
},
|
|
5902
|
+
arrowOffset
|
|
5903
|
+
};
|
|
5703
5904
|
}
|
|
5704
5905
|
|
|
5705
5906
|
/**
|
|
@@ -5937,12 +6138,17 @@ function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky)
|
|
|
5937
6138
|
* The `callback` reference is static and can be safely used in external
|
|
5938
6139
|
* libraries or as a prop that does not cause rerendering of children.
|
|
5939
6140
|
*
|
|
6141
|
+
* The ref update is deferred to useLayoutEffect to prevent stale-closure
|
|
6142
|
+
* bugs when Chrome fires blur on elements removed during re-render.
|
|
6143
|
+
*
|
|
5940
6144
|
* @param {Function} callback function with changing reference
|
|
5941
6145
|
* @returns {Function} static function reference
|
|
5942
6146
|
*/
|
|
5943
6147
|
function useStaticCallback(callback) {
|
|
5944
6148
|
const callbackRef = hooks.useRef(callback);
|
|
5945
|
-
|
|
6149
|
+
hooks.useLayoutEffect(() => {
|
|
6150
|
+
callbackRef.current = callback;
|
|
6151
|
+
});
|
|
5946
6152
|
return hooks.useCallback((...args) => callbackRef.current(...args), []);
|
|
5947
6153
|
}
|
|
5948
6154
|
function useElementVisible(element) {
|
|
@@ -5962,6 +6168,10 @@ function useElementVisible(element) {
|
|
|
5962
6168
|
}, [element, visible]);
|
|
5963
6169
|
return visible;
|
|
5964
6170
|
}
|
|
6171
|
+
|
|
6172
|
+
/**
|
|
6173
|
+
* @param {import('../PropertiesPanel').GroupDefinition} props
|
|
6174
|
+
*/
|
|
5965
6175
|
function Group(props) {
|
|
5966
6176
|
const {
|
|
5967
6177
|
element,
|
|
@@ -6016,8 +6226,6 @@ function Group(props) {
|
|
|
6016
6226
|
class: classnames('bio-properties-panel-group-header', edited ? '' : 'empty', open ? 'open' : '', sticky && open ? 'sticky' : ''),
|
|
6017
6227
|
onClick: toggleOpen,
|
|
6018
6228
|
children: [jsxRuntime.jsx("div", {
|
|
6019
|
-
title: props.tooltip ? null : label,
|
|
6020
|
-
"data-title": label,
|
|
6021
6229
|
class: "bio-properties-panel-group-header-title",
|
|
6022
6230
|
children: jsxRuntime.jsx(TooltipWrapper, {
|
|
6023
6231
|
value: props.tooltip,
|
|
@@ -6221,9 +6429,11 @@ function PropertiesPanel$1(props) {
|
|
|
6221
6429
|
return minDash.get(layout, key, defaultValue);
|
|
6222
6430
|
};
|
|
6223
6431
|
const setLayoutForKey = (key, config) => {
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6432
|
+
setLayout(prevLayout => {
|
|
6433
|
+
const newLayout = minDash.assign({}, prevLayout);
|
|
6434
|
+
minDash.set(newLayout, key, config);
|
|
6435
|
+
return newLayout;
|
|
6436
|
+
});
|
|
6227
6437
|
};
|
|
6228
6438
|
const layoutContext = {
|
|
6229
6439
|
layout,
|
|
@@ -6422,7 +6632,6 @@ function CollapsibleEntry(props) {
|
|
|
6422
6632
|
class: "bio-properties-panel-collapsible-entry-header",
|
|
6423
6633
|
onClick: toggleOpen,
|
|
6424
6634
|
children: [jsxRuntime.jsx("div", {
|
|
6425
|
-
title: label || placeholderLabel,
|
|
6426
6635
|
class: classnames('bio-properties-panel-collapsible-entry-header-title', !label && 'empty'),
|
|
6427
6636
|
children: label || placeholderLabel
|
|
6428
6637
|
}), jsxRuntime.jsx("button", {
|
|
@@ -6458,6 +6667,10 @@ function CollapsibleEntry(props) {
|
|
|
6458
6667
|
})]
|
|
6459
6668
|
});
|
|
6460
6669
|
}
|
|
6670
|
+
|
|
6671
|
+
/**
|
|
6672
|
+
* @param {import('../PropertiesPanel').ListItemDefinition} props
|
|
6673
|
+
*/
|
|
6461
6674
|
function ListItem(props) {
|
|
6462
6675
|
const {
|
|
6463
6676
|
autoFocusEntry,
|
|
@@ -6559,8 +6772,6 @@ function ListGroup(props) {
|
|
|
6559
6772
|
class: classnames('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : '', sticky && open ? 'sticky' : ''),
|
|
6560
6773
|
onClick: hasItems ? toggleOpen : noop$6,
|
|
6561
6774
|
children: [jsxRuntime.jsx("div", {
|
|
6562
|
-
title: props.tooltip ? null : label,
|
|
6563
|
-
"data-title": label,
|
|
6564
6775
|
class: "bio-properties-panel-group-header-title",
|
|
6565
6776
|
children: jsxRuntime.jsx(TooltipWrapper, {
|
|
6566
6777
|
value: props.tooltip,
|
|
@@ -6629,6 +6840,13 @@ function getNewItemIds(newItems, oldItems) {
|
|
|
6629
6840
|
const oldIds = oldItems.map(item => item.id);
|
|
6630
6841
|
return newIds.filter(itemId => !oldIds.includes(itemId));
|
|
6631
6842
|
}
|
|
6843
|
+
|
|
6844
|
+
/**
|
|
6845
|
+
* @param {Object} props
|
|
6846
|
+
* @param {Object} props.element
|
|
6847
|
+
* @param {String} props.forId - id of the entry the description is used for
|
|
6848
|
+
* @param {String} props.value
|
|
6849
|
+
*/
|
|
6632
6850
|
function Description$1(props) {
|
|
6633
6851
|
const {
|
|
6634
6852
|
element,
|
|
@@ -6758,6 +6976,16 @@ function isEdited$8(node) {
|
|
|
6758
6976
|
function prefixId$8(id) {
|
|
6759
6977
|
return `bio-properties-panel-${id}`;
|
|
6760
6978
|
}
|
|
6979
|
+
|
|
6980
|
+
/**
|
|
6981
|
+
* Button to open popups.
|
|
6982
|
+
*
|
|
6983
|
+
* @param {Object} props
|
|
6984
|
+
* @param {Function} props.onClick - Callback to trigger when the button is clicked.
|
|
6985
|
+
* @param {string} [props.title] - Tooltip text for the button.
|
|
6986
|
+
* @param {boolean} [props.disabled] - Whether the button is disabled.
|
|
6987
|
+
* @param {string} [props.className] - Additional class names for the button.
|
|
6988
|
+
*/
|
|
6761
6989
|
function OpenPopupButton({
|
|
6762
6990
|
onClick,
|
|
6763
6991
|
title = 'Open pop-up editor'
|
|
@@ -6901,6 +7129,7 @@ const FeelEditor = React.forwardRef((props, ref) => {
|
|
|
6901
7129
|
enableGutters,
|
|
6902
7130
|
value,
|
|
6903
7131
|
onInput,
|
|
7132
|
+
onKeyDown: onKeyDownProp = noop$4,
|
|
6904
7133
|
onFeelToggle = noop$4,
|
|
6905
7134
|
onLint = noop$4,
|
|
6906
7135
|
onOpenPopup = noop$4,
|
|
@@ -6933,6 +7162,8 @@ const FeelEditor = React.forwardRef((props, ref) => {
|
|
|
6933
7162
|
* - AND the cursor is at the beginning of the input
|
|
6934
7163
|
*/
|
|
6935
7164
|
const onKeyDown = e => {
|
|
7165
|
+
// Call parent onKeyDown handler first
|
|
7166
|
+
onKeyDownProp(e);
|
|
6936
7167
|
if (e.key !== 'Backspace' || !editor) {
|
|
6937
7168
|
return;
|
|
6938
7169
|
}
|
|
@@ -7049,6 +7280,22 @@ function FeelIcon(props) {
|
|
|
7049
7280
|
children: jsxRuntime.jsx(FeelIcon$1, {})
|
|
7050
7281
|
});
|
|
7051
7282
|
}
|
|
7283
|
+
|
|
7284
|
+
/**
|
|
7285
|
+
* @param {KeyboardEvent} event
|
|
7286
|
+
* @return {boolean}
|
|
7287
|
+
*/
|
|
7288
|
+
function isCmd(event) {
|
|
7289
|
+
// ensure we don't react to AltGr
|
|
7290
|
+
// (mapped to CTRL + ALT)
|
|
7291
|
+
if (event.altKey) {
|
|
7292
|
+
return false;
|
|
7293
|
+
}
|
|
7294
|
+
return event.ctrlKey || event.metaKey;
|
|
7295
|
+
}
|
|
7296
|
+
function isCmdWithChar(event) {
|
|
7297
|
+
return isCmd(event) && event.key.length === 1 && /^[a-zA-Z]$/.test(event.key);
|
|
7298
|
+
}
|
|
7052
7299
|
function ToggleSwitch(props) {
|
|
7053
7300
|
const {
|
|
7054
7301
|
id,
|
|
@@ -7157,7 +7404,7 @@ function ToggleSwitchEntry(props) {
|
|
|
7157
7404
|
inline: inline,
|
|
7158
7405
|
tooltip: tooltip,
|
|
7159
7406
|
element: element
|
|
7160
|
-
}), jsxRuntime.jsx(Description$1, {
|
|
7407
|
+
}, element), jsxRuntime.jsx(Description$1, {
|
|
7161
7408
|
forId: id,
|
|
7162
7409
|
element: element,
|
|
7163
7410
|
value: description
|
|
@@ -7330,7 +7577,7 @@ function prefixId$6(id) {
|
|
|
7330
7577
|
const noop$2 = () => {};
|
|
7331
7578
|
|
|
7332
7579
|
/**
|
|
7333
|
-
* @typedef {'required'|'optional'|'static'} FeelType
|
|
7580
|
+
* @typedef {'required'|'optional'|'optional-default-enabled'|'static'} FeelType
|
|
7334
7581
|
*/
|
|
7335
7582
|
|
|
7336
7583
|
/**
|
|
@@ -7360,7 +7607,7 @@ function FeelTextfield(props) {
|
|
|
7360
7607
|
element,
|
|
7361
7608
|
label,
|
|
7362
7609
|
hostLanguage,
|
|
7363
|
-
onInput,
|
|
7610
|
+
onInput: commitValue,
|
|
7364
7611
|
onBlur,
|
|
7365
7612
|
onError,
|
|
7366
7613
|
placeholder,
|
|
@@ -7373,11 +7620,17 @@ function FeelTextfield(props) {
|
|
|
7373
7620
|
OptionalComponent = OptionalFeelInput,
|
|
7374
7621
|
tooltip
|
|
7375
7622
|
} = props;
|
|
7376
|
-
const [localValue, setLocalValue] = hooks.useState(value);
|
|
7623
|
+
const [localValue, setLocalValue] = hooks.useState(getInitialFeelLocalValue(feel, value));
|
|
7377
7624
|
const editorRef = useShowEntryEvent(id);
|
|
7378
7625
|
const containerRef = hooks.useRef();
|
|
7379
|
-
const
|
|
7380
|
-
|
|
7626
|
+
const onInput = hooks.useCallback(newValue => {
|
|
7627
|
+
// we don't commit empty FEEL expressions,
|
|
7628
|
+
// but instead serialize them as <undefined>
|
|
7629
|
+
const newModelValue = newValue === '' || newValue === '=' ? undefined : newValue;
|
|
7630
|
+
commitValue(newModelValue);
|
|
7631
|
+
}, [commitValue]);
|
|
7632
|
+
const feelActive = isFeelActive(feel, localValue);
|
|
7633
|
+
const feelOnlyValue = getFeelValue(localValue);
|
|
7381
7634
|
const feelLanguageContext = hooks.useContext(FeelLanguageContext);
|
|
7382
7635
|
const [focus, _setFocus] = hooks.useState(undefined);
|
|
7383
7636
|
const {
|
|
@@ -7395,13 +7648,7 @@ function FeelTextfield(props) {
|
|
|
7395
7648
|
/**
|
|
7396
7649
|
* @type { import('min-dash').DebouncedFunction }
|
|
7397
7650
|
*/
|
|
7398
|
-
const
|
|
7399
|
-
const handleInput = newValue => {
|
|
7400
|
-
// we don't commit empty FEEL expressions,
|
|
7401
|
-
// but instead serialize them as <undefined>
|
|
7402
|
-
const newModelValue = newValue === '' || newValue === '=' ? undefined : newValue;
|
|
7403
|
-
handleInputCallback(newModelValue);
|
|
7404
|
-
};
|
|
7651
|
+
const handleInput = useDebounce(onInput, debounce);
|
|
7405
7652
|
const handleFeelToggle = useStaticCallback(() => {
|
|
7406
7653
|
if (feel === 'required') {
|
|
7407
7654
|
return;
|
|
@@ -7414,7 +7661,7 @@ function FeelTextfield(props) {
|
|
|
7414
7661
|
handleInput(feelOnlyValue);
|
|
7415
7662
|
}
|
|
7416
7663
|
});
|
|
7417
|
-
const handleLocalInput = newValue => {
|
|
7664
|
+
const handleLocalInput = (newValue, useDebounce = true) => {
|
|
7418
7665
|
if (feelActive) {
|
|
7419
7666
|
newValue = '=' + newValue;
|
|
7420
7667
|
}
|
|
@@ -7422,23 +7669,33 @@ function FeelTextfield(props) {
|
|
|
7422
7669
|
return;
|
|
7423
7670
|
}
|
|
7424
7671
|
setLocalValue(newValue);
|
|
7425
|
-
|
|
7672
|
+
if (useDebounce) {
|
|
7673
|
+
handleInput(newValue);
|
|
7674
|
+
} else {
|
|
7675
|
+
onInput(newValue);
|
|
7676
|
+
}
|
|
7426
7677
|
if (!feelActive && minDash.isString(newValue) && newValue.startsWith('=')) {
|
|
7427
7678
|
// focus is behind `=` sign that will be removed
|
|
7428
7679
|
setFocus(-1);
|
|
7429
7680
|
}
|
|
7430
7681
|
};
|
|
7431
7682
|
const handleOnBlur = e => {
|
|
7683
|
+
handleInput.cancel?.();
|
|
7432
7684
|
if (e.target.type === 'checkbox') {
|
|
7433
7685
|
onInput(e.target.checked);
|
|
7434
7686
|
} else {
|
|
7435
7687
|
const trimmedValue = e.target.value.trim();
|
|
7436
|
-
|
|
7688
|
+
handleLocalInput(trimmedValue, false);
|
|
7437
7689
|
}
|
|
7438
7690
|
if (onBlur) {
|
|
7439
7691
|
onBlur(e);
|
|
7440
7692
|
}
|
|
7441
7693
|
};
|
|
7694
|
+
const handleOnKeyDown = e => {
|
|
7695
|
+
if (isCmdWithChar(e)) {
|
|
7696
|
+
handleInput.flush?.();
|
|
7697
|
+
}
|
|
7698
|
+
};
|
|
7442
7699
|
const handleLint = useStaticCallback((lint = []) => {
|
|
7443
7700
|
const syntaxError = lint.some(report => report.type === 'Syntax Error');
|
|
7444
7701
|
if (syntaxError) {
|
|
@@ -7505,12 +7762,26 @@ function FeelTextfield(props) {
|
|
|
7505
7762
|
if (feelActive || isPopupOpen) {
|
|
7506
7763
|
return;
|
|
7507
7764
|
}
|
|
7508
|
-
const
|
|
7509
|
-
if (
|
|
7765
|
+
const feelData = event.clipboardData.getData('application/FEEL');
|
|
7766
|
+
if (feelData) {
|
|
7510
7767
|
setTimeout(() => {
|
|
7511
7768
|
handleFeelToggle();
|
|
7512
7769
|
setFocus();
|
|
7513
7770
|
});
|
|
7771
|
+
return;
|
|
7772
|
+
}
|
|
7773
|
+
const input = event.target;
|
|
7774
|
+
const isFieldEmpty = !input.value;
|
|
7775
|
+
const isAllSelected = input.selectionStart === 0 && input.selectionEnd === input.value.length;
|
|
7776
|
+
if (isFieldEmpty || isAllSelected) {
|
|
7777
|
+
const textData = event.clipboardData.getData('text');
|
|
7778
|
+
const trimmedValue = textData.trim();
|
|
7779
|
+
setLocalValue(trimmedValue);
|
|
7780
|
+
handleInput(trimmedValue);
|
|
7781
|
+
if (!feelActive && minDash.isString(trimmedValue) && trimmedValue.startsWith('=')) {
|
|
7782
|
+
setFocus(trimmedValue.length - 1);
|
|
7783
|
+
}
|
|
7784
|
+
event.preventDefault();
|
|
7514
7785
|
}
|
|
7515
7786
|
};
|
|
7516
7787
|
containerRef.current.addEventListener('copy', copyHandler);
|
|
@@ -7546,11 +7817,12 @@ function FeelTextfield(props) {
|
|
|
7546
7817
|
ref: containerRef,
|
|
7547
7818
|
children: [jsxRuntime.jsx(FeelIndicator, {
|
|
7548
7819
|
active: feelActive,
|
|
7549
|
-
disabled: feel
|
|
7820
|
+
disabled: !isFeelOptional(feel) || disabled,
|
|
7550
7821
|
onClick: handleFeelToggle
|
|
7551
7822
|
}), feelActive ? jsxRuntime.jsx(FeelEditor, {
|
|
7552
7823
|
name: id,
|
|
7553
7824
|
onInput: handleLocalInput,
|
|
7825
|
+
onKeyDown: handleOnKeyDown,
|
|
7554
7826
|
contentAttributes: {
|
|
7555
7827
|
'id': prefixId$5(id),
|
|
7556
7828
|
'aria-label': label
|
|
@@ -7573,6 +7845,7 @@ function FeelTextfield(props) {
|
|
|
7573
7845
|
...props,
|
|
7574
7846
|
popupOpen: isPopupOpen,
|
|
7575
7847
|
onInput: handleLocalInput,
|
|
7848
|
+
onKeyDown: handleOnKeyDown,
|
|
7576
7849
|
onBlur: handleOnBlur,
|
|
7577
7850
|
contentAttributes: {
|
|
7578
7851
|
'id': prefixId$5(id),
|
|
@@ -7591,6 +7864,7 @@ const OptionalFeelInput = React.forwardRef((props, ref) => {
|
|
|
7591
7864
|
id,
|
|
7592
7865
|
disabled,
|
|
7593
7866
|
onInput,
|
|
7867
|
+
onKeyDown,
|
|
7594
7868
|
value,
|
|
7595
7869
|
onFocus,
|
|
7596
7870
|
onBlur,
|
|
@@ -7626,6 +7900,7 @@ const OptionalFeelInput = React.forwardRef((props, ref) => {
|
|
|
7626
7900
|
class: "bio-properties-panel-input",
|
|
7627
7901
|
onInput: e => onInput(e.target.value),
|
|
7628
7902
|
onFocus: onFocus,
|
|
7903
|
+
onKeyDown: onKeyDown,
|
|
7629
7904
|
onBlur: onBlur,
|
|
7630
7905
|
placeholder: placeholder,
|
|
7631
7906
|
value: value || ''
|
|
@@ -7999,6 +8274,87 @@ function isEdited$5(node) {
|
|
|
7999
8274
|
function prefixId$5(id) {
|
|
8000
8275
|
return `bio-properties-panel-${id}`;
|
|
8001
8276
|
}
|
|
8277
|
+
|
|
8278
|
+
/**
|
|
8279
|
+
* Determine if FEEL is optional for the configured {@link FeelType}.
|
|
8280
|
+
*
|
|
8281
|
+
* @param {FeelType} feelType
|
|
8282
|
+
*
|
|
8283
|
+
* @return {boolean}
|
|
8284
|
+
*/
|
|
8285
|
+
function isFeelOptional(feelType) {
|
|
8286
|
+
return feelType === 'optional' || feelType === 'optional-default-enabled';
|
|
8287
|
+
}
|
|
8288
|
+
|
|
8289
|
+
/**
|
|
8290
|
+
* Determine if FEEL editing is currently active.
|
|
8291
|
+
*
|
|
8292
|
+
* @param {FeelType} feelType
|
|
8293
|
+
* @param {string} localValue
|
|
8294
|
+
*
|
|
8295
|
+
* @return {boolean}
|
|
8296
|
+
*/
|
|
8297
|
+
function isFeelActive(feelType, localValue) {
|
|
8298
|
+
if (feelType === 'required') {
|
|
8299
|
+
return true;
|
|
8300
|
+
}
|
|
8301
|
+
if (minDash.isString(localValue)) {
|
|
8302
|
+
if (localValue.startsWith('=')) {
|
|
8303
|
+
return true;
|
|
8304
|
+
}
|
|
8305
|
+
}
|
|
8306
|
+
return false;
|
|
8307
|
+
}
|
|
8308
|
+
|
|
8309
|
+
/**
|
|
8310
|
+
* @template T
|
|
8311
|
+
* @param {T} value
|
|
8312
|
+
*
|
|
8313
|
+
* @return {string|T}
|
|
8314
|
+
*/
|
|
8315
|
+
function getFeelValue(value) {
|
|
8316
|
+
if (minDash.isString(value) && value.startsWith('=')) {
|
|
8317
|
+
return value.substring(1);
|
|
8318
|
+
}
|
|
8319
|
+
return value;
|
|
8320
|
+
}
|
|
8321
|
+
|
|
8322
|
+
/**
|
|
8323
|
+
* Initialize local FEEL value.
|
|
8324
|
+
*
|
|
8325
|
+
* `optional-default-enabled` starts in FEEL mode if no value or empty string is provided.
|
|
8326
|
+
*
|
|
8327
|
+
* @template T
|
|
8328
|
+
* @param {FeelType} feelType
|
|
8329
|
+
* @param {T} value
|
|
8330
|
+
*
|
|
8331
|
+
* @return {string|T}
|
|
8332
|
+
*/
|
|
8333
|
+
function getInitialFeelLocalValue(feelType, value) {
|
|
8334
|
+
if (feelType === 'optional-default-enabled' && (value === undefined || value === '')) {
|
|
8335
|
+
return '=';
|
|
8336
|
+
}
|
|
8337
|
+
return value;
|
|
8338
|
+
}
|
|
8339
|
+
|
|
8340
|
+
/**
|
|
8341
|
+
* @typedef { { value: string, label: string, disabled: boolean, children: { value: string, label: string, disabled: boolean } } } Option
|
|
8342
|
+
*/
|
|
8343
|
+
|
|
8344
|
+
/**
|
|
8345
|
+
* Provides basic select input.
|
|
8346
|
+
*
|
|
8347
|
+
* @param {object} props
|
|
8348
|
+
* @param {string} props.id
|
|
8349
|
+
* @param {string[]} props.path
|
|
8350
|
+
* @param {string} props.label
|
|
8351
|
+
* @param {Function} props.onChange
|
|
8352
|
+
* @param {Function} props.onFocus
|
|
8353
|
+
* @param {Function} props.onBlur
|
|
8354
|
+
* @param {Array<Option>} [props.options]
|
|
8355
|
+
* @param {string} props.value
|
|
8356
|
+
* @param {boolean} [props.disabled]
|
|
8357
|
+
*/
|
|
8002
8358
|
function Select(props) {
|
|
8003
8359
|
const {
|
|
8004
8360
|
id,
|
|
@@ -8164,12 +8520,13 @@ function TextArea(props) {
|
|
|
8164
8520
|
id,
|
|
8165
8521
|
label,
|
|
8166
8522
|
debounce,
|
|
8167
|
-
onInput,
|
|
8523
|
+
onInput: commitValue,
|
|
8168
8524
|
value = '',
|
|
8169
8525
|
disabled,
|
|
8170
8526
|
monospace,
|
|
8171
8527
|
onFocus,
|
|
8172
8528
|
onBlur,
|
|
8529
|
+
onPaste,
|
|
8173
8530
|
autoResize = true,
|
|
8174
8531
|
placeholder,
|
|
8175
8532
|
rows = autoResize ? 1 : 2,
|
|
@@ -8177,16 +8534,16 @@ function TextArea(props) {
|
|
|
8177
8534
|
} = props;
|
|
8178
8535
|
const [localValue, setLocalValue] = hooks.useState(value);
|
|
8179
8536
|
const ref = useShowEntryEvent(id);
|
|
8537
|
+
const onInput = hooks.useCallback(newValue => {
|
|
8538
|
+
const newModelValue = newValue === '' ? undefined : newValue;
|
|
8539
|
+
commitValue(newModelValue);
|
|
8540
|
+
}, [commitValue]);
|
|
8180
8541
|
const visible = useElementVisible(ref.current);
|
|
8181
8542
|
|
|
8182
8543
|
/**
|
|
8183
8544
|
* @type { import('min-dash').DebouncedFunction }
|
|
8184
8545
|
*/
|
|
8185
|
-
const
|
|
8186
|
-
const handleInput = newValue => {
|
|
8187
|
-
const newModelValue = newValue === '' ? undefined : newValue;
|
|
8188
|
-
handleInputCallback(newModelValue);
|
|
8189
|
-
};
|
|
8546
|
+
const handleInput = useDebounce(onInput, debounce);
|
|
8190
8547
|
const handleLocalInput = e => {
|
|
8191
8548
|
autoResize && resizeToContents(e.target);
|
|
8192
8549
|
if (e.target.value === localValue) {
|
|
@@ -8199,11 +8556,40 @@ function TextArea(props) {
|
|
|
8199
8556
|
const trimmedValue = e.target.value.trim();
|
|
8200
8557
|
|
|
8201
8558
|
// trim and commit on blur
|
|
8559
|
+
handleInput.cancel?.();
|
|
8202
8560
|
onInput(trimmedValue);
|
|
8561
|
+
setLocalValue(trimmedValue);
|
|
8203
8562
|
if (onBlur) {
|
|
8204
8563
|
onBlur(e);
|
|
8205
8564
|
}
|
|
8206
8565
|
};
|
|
8566
|
+
const handleOnPaste = e => {
|
|
8567
|
+
const input = e.target;
|
|
8568
|
+
const isFieldEmpty = !input.value;
|
|
8569
|
+
const isAllSelected = input.selectionStart === 0 && input.selectionEnd === input.value.length;
|
|
8570
|
+
|
|
8571
|
+
// Trim and handle paste if field is empty or all content is selected
|
|
8572
|
+
if (isFieldEmpty || isAllSelected) {
|
|
8573
|
+
const trimmedValue = e.clipboardData.getData('text').trim();
|
|
8574
|
+
setLocalValue(trimmedValue);
|
|
8575
|
+
handleInput(trimmedValue);
|
|
8576
|
+
if (onPaste) {
|
|
8577
|
+
onPaste(e);
|
|
8578
|
+
}
|
|
8579
|
+
e.preventDefault();
|
|
8580
|
+
return;
|
|
8581
|
+
}
|
|
8582
|
+
|
|
8583
|
+
// Allow default paste behavior for normal text editing
|
|
8584
|
+
if (onPaste) {
|
|
8585
|
+
onPaste(e);
|
|
8586
|
+
}
|
|
8587
|
+
};
|
|
8588
|
+
const handleOnKeyDown = e => {
|
|
8589
|
+
if (isCmdWithChar(e)) {
|
|
8590
|
+
handleInput.flush?.();
|
|
8591
|
+
}
|
|
8592
|
+
};
|
|
8207
8593
|
hooks.useLayoutEffect(() => {
|
|
8208
8594
|
autoResize && resizeToContents(ref.current);
|
|
8209
8595
|
}, []);
|
|
@@ -8235,7 +8621,9 @@ function TextArea(props) {
|
|
|
8235
8621
|
class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : '', autoResize ? 'auto-resize' : ''),
|
|
8236
8622
|
onInput: handleLocalInput,
|
|
8237
8623
|
onFocus: onFocus,
|
|
8624
|
+
onKeyDown: handleOnKeyDown,
|
|
8238
8625
|
onBlur: handleOnBlur,
|
|
8626
|
+
onPaste: handleOnPaste,
|
|
8239
8627
|
placeholder: placeholder,
|
|
8240
8628
|
rows: rows,
|
|
8241
8629
|
value: localValue,
|
|
@@ -8256,6 +8644,7 @@ function TextArea(props) {
|
|
|
8256
8644
|
* @param {Function} props.setValue
|
|
8257
8645
|
* @param {Function} props.onFocus
|
|
8258
8646
|
* @param {Function} props.onBlur
|
|
8647
|
+
* @param {Function} props.onPaste
|
|
8259
8648
|
* @param {number} props.rows
|
|
8260
8649
|
* @param {boolean} props.monospace
|
|
8261
8650
|
* @param {Function} [props.validate]
|
|
@@ -8276,6 +8665,7 @@ function TextAreaEntry(props) {
|
|
|
8276
8665
|
validate,
|
|
8277
8666
|
onFocus,
|
|
8278
8667
|
onBlur,
|
|
8668
|
+
onPaste,
|
|
8279
8669
|
placeholder,
|
|
8280
8670
|
autoResize,
|
|
8281
8671
|
tooltip
|
|
@@ -8311,6 +8701,7 @@ function TextAreaEntry(props) {
|
|
|
8311
8701
|
onInput: onInput,
|
|
8312
8702
|
onFocus: onFocus,
|
|
8313
8703
|
onBlur: onBlur,
|
|
8704
|
+
onPaste: onPaste,
|
|
8314
8705
|
rows: rows,
|
|
8315
8706
|
debounce: debounce,
|
|
8316
8707
|
monospace: monospace,
|
|
@@ -8344,32 +8735,57 @@ function Textfield(props) {
|
|
|
8344
8735
|
disabled = false,
|
|
8345
8736
|
id,
|
|
8346
8737
|
label,
|
|
8347
|
-
onInput,
|
|
8738
|
+
onInput: commitValue,
|
|
8348
8739
|
onFocus,
|
|
8349
8740
|
onBlur,
|
|
8741
|
+
onPaste,
|
|
8350
8742
|
placeholder,
|
|
8351
8743
|
value = '',
|
|
8352
8744
|
tooltip
|
|
8353
8745
|
} = props;
|
|
8354
8746
|
const [localValue, setLocalValue] = hooks.useState(value || '');
|
|
8355
8747
|
const ref = useShowEntryEvent(id);
|
|
8748
|
+
const onInput = hooks.useCallback(newValue => {
|
|
8749
|
+
const newModelValue = newValue === '' ? undefined : newValue;
|
|
8750
|
+
commitValue(newModelValue);
|
|
8751
|
+
}, [commitValue]);
|
|
8356
8752
|
|
|
8357
8753
|
/**
|
|
8358
8754
|
* @type { import('min-dash').DebouncedFunction }
|
|
8359
8755
|
*/
|
|
8360
|
-
const
|
|
8756
|
+
const handleInput = useDebounce(onInput, debounce);
|
|
8361
8757
|
const handleOnBlur = e => {
|
|
8362
8758
|
const trimmedValue = e.target.value.trim();
|
|
8363
8759
|
|
|
8364
8760
|
// trim and commit on blur
|
|
8761
|
+
handleInput.cancel?.();
|
|
8365
8762
|
onInput(trimmedValue);
|
|
8763
|
+
setLocalValue(trimmedValue);
|
|
8366
8764
|
if (onBlur) {
|
|
8367
8765
|
onBlur(e);
|
|
8368
8766
|
}
|
|
8369
8767
|
};
|
|
8370
|
-
const
|
|
8371
|
-
const
|
|
8372
|
-
|
|
8768
|
+
const handleOnPaste = e => {
|
|
8769
|
+
const input = e.target;
|
|
8770
|
+
const isFieldEmpty = !input.value;
|
|
8771
|
+
const isAllSelected = input.selectionStart === 0 && input.selectionEnd === input.value.length;
|
|
8772
|
+
|
|
8773
|
+
// Trim and handle paste if field is empty or all content is selected (overwrite)
|
|
8774
|
+
if (isFieldEmpty || isAllSelected) {
|
|
8775
|
+
const trimmedValue = e.clipboardData.getData('text').trim();
|
|
8776
|
+
setLocalValue(trimmedValue);
|
|
8777
|
+
handleInput(trimmedValue);
|
|
8778
|
+
if (onPaste) {
|
|
8779
|
+
onPaste(e);
|
|
8780
|
+
}
|
|
8781
|
+
e.preventDefault();
|
|
8782
|
+
return;
|
|
8783
|
+
}
|
|
8784
|
+
|
|
8785
|
+
// Allow default paste behavior for normal text editing
|
|
8786
|
+
if (onPaste) {
|
|
8787
|
+
onPaste(e);
|
|
8788
|
+
}
|
|
8373
8789
|
};
|
|
8374
8790
|
const handleLocalInput = e => {
|
|
8375
8791
|
if (e.target.value === localValue) {
|
|
@@ -8384,6 +8800,11 @@ function Textfield(props) {
|
|
|
8384
8800
|
}
|
|
8385
8801
|
setLocalValue(value);
|
|
8386
8802
|
}, [value]);
|
|
8803
|
+
const handleOnKeyDown = e => {
|
|
8804
|
+
if (isCmdWithChar(e)) {
|
|
8805
|
+
handleInput.flush?.();
|
|
8806
|
+
}
|
|
8807
|
+
};
|
|
8387
8808
|
return jsxRuntime.jsxs("div", {
|
|
8388
8809
|
class: "bio-properties-panel-textfield",
|
|
8389
8810
|
children: [jsxRuntime.jsx("label", {
|
|
@@ -8406,7 +8827,9 @@ function Textfield(props) {
|
|
|
8406
8827
|
class: "bio-properties-panel-input",
|
|
8407
8828
|
onInput: handleLocalInput,
|
|
8408
8829
|
onFocus: onFocus,
|
|
8830
|
+
onKeyDown: handleOnKeyDown,
|
|
8409
8831
|
onBlur: handleOnBlur,
|
|
8832
|
+
onPaste: handleOnPaste,
|
|
8410
8833
|
placeholder: placeholder,
|
|
8411
8834
|
value: localValue
|
|
8412
8835
|
})]
|
|
@@ -8441,6 +8864,7 @@ function TextfieldEntry(props) {
|
|
|
8441
8864
|
validate,
|
|
8442
8865
|
onFocus,
|
|
8443
8866
|
onBlur,
|
|
8867
|
+
onPaste,
|
|
8444
8868
|
placeholder,
|
|
8445
8869
|
tooltip
|
|
8446
8870
|
} = props;
|
|
@@ -8476,6 +8900,7 @@ function TextfieldEntry(props) {
|
|
|
8476
8900
|
onInput: onInput,
|
|
8477
8901
|
onFocus: onFocus,
|
|
8478
8902
|
onBlur: onBlur,
|
|
8903
|
+
onPaste: onPaste,
|
|
8479
8904
|
placeholder: placeholder,
|
|
8480
8905
|
value: value,
|
|
8481
8906
|
tooltip: tooltip,
|
|
@@ -8745,6 +9170,7 @@ function Title(props) {
|
|
|
8745
9170
|
class: "bio-properties-panel-popup__title",
|
|
8746
9171
|
children: title
|
|
8747
9172
|
}), children, showCloseButton && jsxRuntime.jsx("button", {
|
|
9173
|
+
type: "button",
|
|
8748
9174
|
title: closeButtonTooltip,
|
|
8749
9175
|
class: "bio-properties-panel-popup__close",
|
|
8750
9176
|
onClick: onClose,
|
|
@@ -8786,6 +9212,25 @@ function cancel(event) {
|
|
|
8786
9212
|
event.preventDefault();
|
|
8787
9213
|
event.stopPropagation();
|
|
8788
9214
|
}
|
|
9215
|
+
|
|
9216
|
+
/**
|
|
9217
|
+
* @typedef {Object} FeelPopupProps
|
|
9218
|
+
* @property {string} entryId
|
|
9219
|
+
* @property {Function} onInput
|
|
9220
|
+
* @property {Function} onClose
|
|
9221
|
+
* @property {string} title
|
|
9222
|
+
* @property {'feel'|'feelers'} type
|
|
9223
|
+
* @property {string} value
|
|
9224
|
+
* @property {Array} [links]
|
|
9225
|
+
* @property {Array|Object} [variables]
|
|
9226
|
+
* @property {Object} [position]
|
|
9227
|
+
* @property {string} [hostLanguage]
|
|
9228
|
+
* @property {boolean} [singleLine]
|
|
9229
|
+
* @property {HTMLElement} [sourceElement]
|
|
9230
|
+
* @property {HTMLElement|string} [tooltipContainer]
|
|
9231
|
+
* @property {Object} [eventBus]
|
|
9232
|
+
*/
|
|
9233
|
+
|
|
8789
9234
|
const FEEL_POPUP_WIDTH = 700;
|
|
8790
9235
|
const FEEL_POPUP_HEIGHT = 250;
|
|
8791
9236
|
|
|
@@ -13498,7 +13943,7 @@ function CustomPropertiesGroup(field, editField) {
|
|
|
13498
13943
|
event.stopPropagation();
|
|
13499
13944
|
return editField(field, ['properties'], removeKey(properties, key));
|
|
13500
13945
|
};
|
|
13501
|
-
const id = `property-${
|
|
13946
|
+
const id = `property-${index}`;
|
|
13502
13947
|
return {
|
|
13503
13948
|
autoFocusEntry: id + '-key',
|
|
13504
13949
|
entries: CustomValueEntry({
|
|
@@ -13880,7 +14325,7 @@ const RepeatRenderModule = {
|
|
|
13880
14325
|
repeatRenderManager: ['type', EditorRepeatRenderManager]
|
|
13881
14326
|
};
|
|
13882
14327
|
|
|
13883
|
-
const ids = new Ids([32, 36, 1]);
|
|
14328
|
+
const ids = new ids$1.Ids([32, 36, 1]);
|
|
13884
14329
|
|
|
13885
14330
|
/**
|
|
13886
14331
|
* @typedef { import('./types').Injector } Injector
|