@bpmn-io/form-js-editor 1.15.4 → 1.15.5
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 +459 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +459 -74
- package/dist/index.es.js.map +1 -1
- package/package.json +5 -5
- package/dist/types/features/properties-panel/entries/EndpointKey.d.ts +0 -10
- package/dist/types/features/properties-panel/entries/SpacerHeightEntry.d.ts +0 -9
- package/dist/types/features/properties-panel/groups/DownloadSettings.d.ts +0 -12
package/dist/index.es.js
CHANGED
|
@@ -3108,7 +3108,7 @@ function hasModifier(event) {
|
|
|
3108
3108
|
* @param {KeyboardEvent} event
|
|
3109
3109
|
* @return {boolean}
|
|
3110
3110
|
*/
|
|
3111
|
-
function isCmd(event) {
|
|
3111
|
+
function isCmd$1(event) {
|
|
3112
3112
|
// ensure we don't react to AltGr
|
|
3113
3113
|
// (mapped to CTRL + ALT)
|
|
3114
3114
|
if (event.altKey) {
|
|
@@ -3140,28 +3140,28 @@ function isShift(event) {
|
|
|
3140
3140
|
* @param {KeyboardEvent} event
|
|
3141
3141
|
*/
|
|
3142
3142
|
function isCopy(event) {
|
|
3143
|
-
return isCmd(event) && isKey(KEYS_COPY, event);
|
|
3143
|
+
return isCmd$1(event) && isKey(KEYS_COPY, event);
|
|
3144
3144
|
}
|
|
3145
3145
|
|
|
3146
3146
|
/**
|
|
3147
3147
|
* @param {KeyboardEvent} event
|
|
3148
3148
|
*/
|
|
3149
3149
|
function isPaste(event) {
|
|
3150
|
-
return isCmd(event) && isKey(KEYS_PASTE, event);
|
|
3150
|
+
return isCmd$1(event) && isKey(KEYS_PASTE, event);
|
|
3151
3151
|
}
|
|
3152
3152
|
|
|
3153
3153
|
/**
|
|
3154
3154
|
* @param {KeyboardEvent} event
|
|
3155
3155
|
*/
|
|
3156
3156
|
function isUndo(event) {
|
|
3157
|
-
return isCmd(event) && !isShift(event) && isKey(KEYS_UNDO, event);
|
|
3157
|
+
return isCmd$1(event) && !isShift(event) && isKey(KEYS_UNDO, event);
|
|
3158
3158
|
}
|
|
3159
3159
|
|
|
3160
3160
|
/**
|
|
3161
3161
|
* @param {KeyboardEvent} event
|
|
3162
3162
|
*/
|
|
3163
3163
|
function isRedo(event) {
|
|
3164
|
-
return isCmd(event) && (isKey(KEYS_REDO, event) || isKey(KEYS_UNDO, event) && isShift(event));
|
|
3164
|
+
return isCmd$1(event) && (isKey(KEYS_REDO, event) || isKey(KEYS_UNDO, event) && isShift(event));
|
|
3165
3165
|
}
|
|
3166
3166
|
|
|
3167
3167
|
/**
|
|
@@ -3330,7 +3330,7 @@ Keyboard.prototype.removeListener = function (listener, type) {
|
|
|
3330
3330
|
this._eventBus.off(type || KEYDOWN_EVENT, listener);
|
|
3331
3331
|
};
|
|
3332
3332
|
Keyboard.prototype.hasModifier = hasModifier;
|
|
3333
|
-
Keyboard.prototype.isCmd = isCmd;
|
|
3333
|
+
Keyboard.prototype.isCmd = isCmd$1;
|
|
3334
3334
|
Keyboard.prototype.isShift = isShift;
|
|
3335
3335
|
Keyboard.prototype.isKey = isKey;
|
|
3336
3336
|
|
|
@@ -3422,7 +3422,7 @@ KeyboardBindings.prototype.registerBindings = function (keyboard, editorActions)
|
|
|
3422
3422
|
|
|
3423
3423
|
// quirk: it has to be triggered by `=` as well to work on international keyboard layout
|
|
3424
3424
|
// cf: https://github.com/bpmn-io/bpmn-js/issues/1362#issuecomment-722989754
|
|
3425
|
-
if (isKey(['+', 'Add', '='], event) && isCmd(event)) {
|
|
3425
|
+
if (isKey(['+', 'Add', '='], event) && isCmd$1(event)) {
|
|
3426
3426
|
editorActions.trigger('stepZoom', {
|
|
3427
3427
|
value: 1
|
|
3428
3428
|
});
|
|
@@ -3434,7 +3434,7 @@ KeyboardBindings.prototype.registerBindings = function (keyboard, editorActions)
|
|
|
3434
3434
|
// CTRL + -
|
|
3435
3435
|
addListener('stepZoom', function (context) {
|
|
3436
3436
|
var event = context.keyEvent;
|
|
3437
|
-
if (isKey(['-', 'Subtract'], event) && isCmd(event)) {
|
|
3437
|
+
if (isKey(['-', 'Subtract'], event) && isCmd$1(event)) {
|
|
3438
3438
|
editorActions.trigger('stepZoom', {
|
|
3439
3439
|
value: -1
|
|
3440
3440
|
});
|
|
@@ -3446,7 +3446,7 @@ KeyboardBindings.prototype.registerBindings = function (keyboard, editorActions)
|
|
|
3446
3446
|
// CTRL + 0
|
|
3447
3447
|
addListener('zoom', function (context) {
|
|
3448
3448
|
var event = context.keyEvent;
|
|
3449
|
-
if (isKey('0', event) && isCmd(event)) {
|
|
3449
|
+
if (isKey('0', event) && isCmd$1(event)) {
|
|
3450
3450
|
editorActions.trigger('zoom', {
|
|
3451
3451
|
value: 1
|
|
3452
3452
|
});
|
|
@@ -5453,6 +5453,21 @@ OpenPopupIcon.defaultProps = {
|
|
|
5453
5453
|
xmlns: "http://www.w3.org/2000/svg",
|
|
5454
5454
|
viewBox: "0 0 16 16"
|
|
5455
5455
|
};
|
|
5456
|
+
|
|
5457
|
+
/**
|
|
5458
|
+
* @typedef { {
|
|
5459
|
+
* getElementLabel: (element: object) => string,
|
|
5460
|
+
* getTypeLabel: (element: object) => string,
|
|
5461
|
+
* getElementIcon: (element: object) => import('preact').Component,
|
|
5462
|
+
* getDocumentationRef: (element: object) => string
|
|
5463
|
+
* } } HeaderProvider
|
|
5464
|
+
*/
|
|
5465
|
+
|
|
5466
|
+
/**
|
|
5467
|
+
* @param {Object} props
|
|
5468
|
+
* @param {Object} props.element,
|
|
5469
|
+
* @param {HeaderProvider} props.headerProvider
|
|
5470
|
+
*/
|
|
5456
5471
|
function Header(props) {
|
|
5457
5472
|
const {
|
|
5458
5473
|
element,
|
|
@@ -5480,11 +5495,9 @@ function Header(props) {
|
|
|
5480
5495
|
}), jsxs("div", {
|
|
5481
5496
|
class: "bio-properties-panel-header-labels",
|
|
5482
5497
|
children: [jsx("div", {
|
|
5483
|
-
title: type,
|
|
5484
5498
|
class: "bio-properties-panel-header-type",
|
|
5485
5499
|
children: type
|
|
5486
5500
|
}), label ? jsx("div", {
|
|
5487
|
-
title: label,
|
|
5488
5501
|
class: "bio-properties-panel-header-label",
|
|
5489
5502
|
children: label
|
|
5490
5503
|
}) : null]
|
|
@@ -5572,6 +5585,27 @@ function useTooltipContext(id, element) {
|
|
|
5572
5585
|
} = useContext(TooltipContext);
|
|
5573
5586
|
return getTooltipForId(id, element);
|
|
5574
5587
|
}
|
|
5588
|
+
|
|
5589
|
+
/**
|
|
5590
|
+
* @typedef {Object} TooltipProps
|
|
5591
|
+
* @property {Object} [parent] - Parent element ref for portal rendering
|
|
5592
|
+
* @property {String} [direction='right'] - Tooltip direction ( 'right', 'top')
|
|
5593
|
+
* @property {String} [position] - Custom CSS position override
|
|
5594
|
+
* @property {Number} [showDelay=250] - Delay in ms before showing tooltip on hover
|
|
5595
|
+
* @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
|
|
5596
|
+
* @property {*} [children] - Child elements to render inside the tooltip wrapper
|
|
5597
|
+
*/
|
|
5598
|
+
|
|
5599
|
+
/**
|
|
5600
|
+
* Tooltip wrapper that provides context-based tooltip content lookup.
|
|
5601
|
+
* All props are forwarded to the underlying Tooltip component.
|
|
5602
|
+
*
|
|
5603
|
+
* @param {TooltipProps & {
|
|
5604
|
+
* forId: String,
|
|
5605
|
+
* value?: String|Object,
|
|
5606
|
+
* element?: Object
|
|
5607
|
+
* }} props - Shared tooltip props plus wrapper-specific ones
|
|
5608
|
+
*/
|
|
5575
5609
|
function TooltipWrapper(props) {
|
|
5576
5610
|
const {
|
|
5577
5611
|
forId,
|
|
@@ -5588,35 +5622,93 @@ function TooltipWrapper(props) {
|
|
|
5588
5622
|
forId: `bio-properties-panel-${forId}`
|
|
5589
5623
|
});
|
|
5590
5624
|
}
|
|
5625
|
+
|
|
5626
|
+
/**
|
|
5627
|
+
* @param {TooltipProps & {
|
|
5628
|
+
* forId: String,
|
|
5629
|
+
* value: String|Object
|
|
5630
|
+
* }} props
|
|
5631
|
+
*/
|
|
5591
5632
|
function Tooltip(props) {
|
|
5592
5633
|
const {
|
|
5593
5634
|
forId,
|
|
5594
5635
|
value,
|
|
5595
5636
|
parent,
|
|
5596
5637
|
direction = 'right',
|
|
5597
|
-
position
|
|
5638
|
+
position,
|
|
5639
|
+
showDelay = 250,
|
|
5640
|
+
hideDelay = 250
|
|
5598
5641
|
} = props;
|
|
5599
5642
|
const [visible, setVisible] = useState(false);
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
const
|
|
5603
|
-
|
|
5643
|
+
const [tooltipPosition, setTooltipPosition] = useState(null);
|
|
5644
|
+
const [arrowOffset, setArrowOffset] = useState(null);
|
|
5645
|
+
const showTimeoutRef = useRef(null);
|
|
5646
|
+
const hideTimeoutRef = useRef(null);
|
|
5604
5647
|
const wrapperRef = useRef(null);
|
|
5605
5648
|
const tooltipRef = useRef(null);
|
|
5606
5649
|
const show = (_, delay) => {
|
|
5650
|
+
clearTimeout(showTimeoutRef.current);
|
|
5651
|
+
clearTimeout(hideTimeoutRef.current);
|
|
5607
5652
|
if (visible) return;
|
|
5608
5653
|
if (delay) {
|
|
5609
|
-
|
|
5654
|
+
showTimeoutRef.current = setTimeout(() => {
|
|
5610
5655
|
setVisible(true);
|
|
5611
|
-
},
|
|
5656
|
+
}, showDelay);
|
|
5612
5657
|
} else {
|
|
5613
5658
|
setVisible(true);
|
|
5614
5659
|
}
|
|
5615
5660
|
};
|
|
5616
|
-
const
|
|
5617
|
-
|
|
5618
|
-
setVisible(false);
|
|
5661
|
+
const handleWrapperMouseEnter = e => {
|
|
5662
|
+
show(e, true);
|
|
5619
5663
|
};
|
|
5664
|
+
const hide = (delay = false) => {
|
|
5665
|
+
clearTimeout(showTimeoutRef.current);
|
|
5666
|
+
clearTimeout(hideTimeoutRef.current);
|
|
5667
|
+
if (delay) {
|
|
5668
|
+
hideTimeoutRef.current = setTimeout(() => {
|
|
5669
|
+
setVisible(false);
|
|
5670
|
+
}, hideDelay);
|
|
5671
|
+
} else {
|
|
5672
|
+
setVisible(false);
|
|
5673
|
+
}
|
|
5674
|
+
};
|
|
5675
|
+
|
|
5676
|
+
// Cleanup timeouts on unmount
|
|
5677
|
+
useEffect(() => {
|
|
5678
|
+
return () => {
|
|
5679
|
+
clearTimeout(showTimeoutRef.current);
|
|
5680
|
+
clearTimeout(hideTimeoutRef.current);
|
|
5681
|
+
};
|
|
5682
|
+
}, []);
|
|
5683
|
+
|
|
5684
|
+
// Handle click outside to close tooltip for non-focusable elements
|
|
5685
|
+
useEffect(() => {
|
|
5686
|
+
if (!visible) return;
|
|
5687
|
+
const handleClickOutside = e => {
|
|
5688
|
+
// If clicking outside both the wrapper and tooltip, hide it
|
|
5689
|
+
if (wrapperRef.current && !wrapperRef.current.contains(e.target) && tooltipRef.current && !tooltipRef.current.contains(e.target)) {
|
|
5690
|
+
hide(false);
|
|
5691
|
+
}
|
|
5692
|
+
};
|
|
5693
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
5694
|
+
return () => {
|
|
5695
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
5696
|
+
};
|
|
5697
|
+
}, [visible, hide]);
|
|
5698
|
+
useLayoutEffect(() => {
|
|
5699
|
+
if (!visible || position) {
|
|
5700
|
+
setTooltipPosition(null);
|
|
5701
|
+
setArrowOffset(null);
|
|
5702
|
+
return;
|
|
5703
|
+
}
|
|
5704
|
+
if (!wrapperRef.current || !tooltipRef.current) return;
|
|
5705
|
+
const {
|
|
5706
|
+
tooltipPosition: newPosition,
|
|
5707
|
+
arrowOffset: newArrowOffset
|
|
5708
|
+
} = getTooltipPosition(wrapperRef.current, tooltipRef.current, direction);
|
|
5709
|
+
setTooltipPosition(newPosition);
|
|
5710
|
+
setArrowOffset(newArrowOffset);
|
|
5711
|
+
}, [visible, position]);
|
|
5620
5712
|
const handleMouseLeave = ({
|
|
5621
5713
|
relatedTarget
|
|
5622
5714
|
}) => {
|
|
@@ -5624,39 +5716,52 @@ function Tooltip(props) {
|
|
|
5624
5716
|
if (relatedTarget === wrapperRef.current || relatedTarget === tooltipRef.current || relatedTarget?.parentElement === tooltipRef.current) {
|
|
5625
5717
|
return;
|
|
5626
5718
|
}
|
|
5627
|
-
|
|
5719
|
+
const selection = window.getSelection();
|
|
5720
|
+
if (selection && selection.toString().length > 0) {
|
|
5721
|
+
// Check if selection is within tooltip content
|
|
5722
|
+
const selectionRange = selection.getRangeAt(0);
|
|
5723
|
+
if (tooltipRef.current?.contains(selectionRange.commonAncestorContainer) || tooltipRef.current?.contains(selection.anchorNode) || tooltipRef.current?.contains(selection.focusNode)) {
|
|
5724
|
+
return; // Keep tooltip open during text selection
|
|
5725
|
+
}
|
|
5726
|
+
}
|
|
5727
|
+
hide(true);
|
|
5728
|
+
};
|
|
5729
|
+
const handleTooltipMouseEnter = () => {
|
|
5730
|
+
clearTimeout(hideTimeoutRef.current);
|
|
5628
5731
|
};
|
|
5629
5732
|
const handleFocusOut = e => {
|
|
5630
5733
|
const {
|
|
5631
|
-
|
|
5734
|
+
relatedTarget
|
|
5632
5735
|
} = e;
|
|
5633
5736
|
|
|
5634
|
-
// Don't hide
|
|
5635
|
-
|
|
5636
|
-
if (target === wrapperRef.current && isHovered) {
|
|
5637
|
-
e.stopPropagation();
|
|
5737
|
+
// Don't hide if focus moved to the tooltip or another element within the wrapper
|
|
5738
|
+
if (tooltipRef.current?.contains(relatedTarget) || wrapperRef.current?.contains(relatedTarget)) {
|
|
5638
5739
|
return;
|
|
5639
5740
|
}
|
|
5640
|
-
hide();
|
|
5741
|
+
hide(false);
|
|
5641
5742
|
};
|
|
5642
5743
|
const hideTooltipViaEscape = e => {
|
|
5643
|
-
e.code === 'Escape' && hide();
|
|
5744
|
+
e.code === 'Escape' && hide(false);
|
|
5644
5745
|
};
|
|
5645
5746
|
const renderTooltip = () => {
|
|
5747
|
+
const tooltipStyle = position || (tooltipPosition ? `right: ${tooltipPosition.right}; top: ${tooltipPosition.top}px;` : undefined);
|
|
5748
|
+
const arrowStyle = arrowOffset != null ? `margin-top: ${arrowOffset}px;` : undefined;
|
|
5646
5749
|
return jsxs("div", {
|
|
5647
5750
|
class: `bio-properties-panel-tooltip ${direction}`,
|
|
5648
5751
|
role: "tooltip",
|
|
5649
5752
|
id: "bio-properties-panel-tooltip",
|
|
5650
5753
|
"aria-labelledby": forId,
|
|
5651
|
-
style:
|
|
5754
|
+
style: tooltipStyle,
|
|
5652
5755
|
ref: tooltipRef,
|
|
5653
5756
|
onClick: e => e.stopPropagation(),
|
|
5757
|
+
onMouseEnter: handleTooltipMouseEnter,
|
|
5654
5758
|
onMouseLeave: handleMouseLeave,
|
|
5655
5759
|
children: [jsx("div", {
|
|
5656
5760
|
class: "bio-properties-panel-tooltip-content",
|
|
5657
5761
|
children: value
|
|
5658
5762
|
}), jsx("div", {
|
|
5659
|
-
class: "bio-properties-panel-tooltip-arrow"
|
|
5763
|
+
class: "bio-properties-panel-tooltip-arrow",
|
|
5764
|
+
style: arrowStyle
|
|
5660
5765
|
})]
|
|
5661
5766
|
});
|
|
5662
5767
|
};
|
|
@@ -5664,7 +5769,7 @@ function Tooltip(props) {
|
|
|
5664
5769
|
class: "bio-properties-panel-tooltip-wrapper",
|
|
5665
5770
|
tabIndex: "0",
|
|
5666
5771
|
ref: wrapperRef,
|
|
5667
|
-
onMouseEnter:
|
|
5772
|
+
onMouseEnter: handleWrapperMouseEnter,
|
|
5668
5773
|
onMouseLeave: handleMouseLeave,
|
|
5669
5774
|
onFocus: show,
|
|
5670
5775
|
onBlur: handleFocusOut,
|
|
@@ -5675,11 +5780,47 @@ function Tooltip(props) {
|
|
|
5675
5780
|
|
|
5676
5781
|
// helper
|
|
5677
5782
|
|
|
5678
|
-
function getTooltipPosition(refElement) {
|
|
5783
|
+
function getTooltipPosition(refElement, tooltipElement, direction) {
|
|
5784
|
+
if (!refElement) {
|
|
5785
|
+
return {
|
|
5786
|
+
tooltipPosition: null,
|
|
5787
|
+
arrowOffset: null
|
|
5788
|
+
};
|
|
5789
|
+
}
|
|
5679
5790
|
const refPosition = refElement.getBoundingClientRect();
|
|
5680
5791
|
const right = `calc(100% - ${refPosition.x}px)`;
|
|
5681
|
-
|
|
5682
|
-
|
|
5792
|
+
let top = refPosition.top - 10;
|
|
5793
|
+
let arrowOffset = null;
|
|
5794
|
+
|
|
5795
|
+
// Ensure that the tooltip is within the viewport, adjust the top position if needed.
|
|
5796
|
+
// This is only relevant for the 'right' direction for now
|
|
5797
|
+
if (tooltipElement && direction === 'right') {
|
|
5798
|
+
const tooltipRect = tooltipElement.getBoundingClientRect();
|
|
5799
|
+
const viewportHeight = window.innerHeight;
|
|
5800
|
+
const minTop = 0;
|
|
5801
|
+
const maxTop = viewportHeight - tooltipRect.height;
|
|
5802
|
+
const originalTop = top;
|
|
5803
|
+
if (top > maxTop) {
|
|
5804
|
+
top = maxTop;
|
|
5805
|
+
}
|
|
5806
|
+
if (top < minTop) {
|
|
5807
|
+
top = minTop;
|
|
5808
|
+
}
|
|
5809
|
+
|
|
5810
|
+
// Adjust the arrow position if the tooltip had to be moved to stay within viewport
|
|
5811
|
+
if (top !== originalTop) {
|
|
5812
|
+
const defaultMarginTop = 16;
|
|
5813
|
+
const topDiff = top - originalTop;
|
|
5814
|
+
arrowOffset = defaultMarginTop - topDiff;
|
|
5815
|
+
}
|
|
5816
|
+
}
|
|
5817
|
+
return {
|
|
5818
|
+
tooltipPosition: {
|
|
5819
|
+
right,
|
|
5820
|
+
top
|
|
5821
|
+
},
|
|
5822
|
+
arrowOffset
|
|
5823
|
+
};
|
|
5683
5824
|
}
|
|
5684
5825
|
|
|
5685
5826
|
/**
|
|
@@ -5917,12 +6058,17 @@ function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky)
|
|
|
5917
6058
|
* The `callback` reference is static and can be safely used in external
|
|
5918
6059
|
* libraries or as a prop that does not cause rerendering of children.
|
|
5919
6060
|
*
|
|
6061
|
+
* The ref update is deferred to useLayoutEffect to prevent stale-closure
|
|
6062
|
+
* bugs when Chrome fires blur on elements removed during re-render.
|
|
6063
|
+
*
|
|
5920
6064
|
* @param {Function} callback function with changing reference
|
|
5921
6065
|
* @returns {Function} static function reference
|
|
5922
6066
|
*/
|
|
5923
6067
|
function useStaticCallback(callback) {
|
|
5924
6068
|
const callbackRef = useRef(callback);
|
|
5925
|
-
|
|
6069
|
+
useLayoutEffect(() => {
|
|
6070
|
+
callbackRef.current = callback;
|
|
6071
|
+
});
|
|
5926
6072
|
return useCallback((...args) => callbackRef.current(...args), []);
|
|
5927
6073
|
}
|
|
5928
6074
|
function useElementVisible(element) {
|
|
@@ -5942,6 +6088,10 @@ function useElementVisible(element) {
|
|
|
5942
6088
|
}, [element, visible]);
|
|
5943
6089
|
return visible;
|
|
5944
6090
|
}
|
|
6091
|
+
|
|
6092
|
+
/**
|
|
6093
|
+
* @param {import('../PropertiesPanel').GroupDefinition} props
|
|
6094
|
+
*/
|
|
5945
6095
|
function Group(props) {
|
|
5946
6096
|
const {
|
|
5947
6097
|
element,
|
|
@@ -5996,8 +6146,6 @@ function Group(props) {
|
|
|
5996
6146
|
class: classnames('bio-properties-panel-group-header', edited ? '' : 'empty', open ? 'open' : '', sticky && open ? 'sticky' : ''),
|
|
5997
6147
|
onClick: toggleOpen,
|
|
5998
6148
|
children: [jsx("div", {
|
|
5999
|
-
title: props.tooltip ? null : label,
|
|
6000
|
-
"data-title": label,
|
|
6001
6149
|
class: "bio-properties-panel-group-header-title",
|
|
6002
6150
|
children: jsx(TooltipWrapper, {
|
|
6003
6151
|
value: props.tooltip,
|
|
@@ -6201,9 +6349,11 @@ function PropertiesPanel$1(props) {
|
|
|
6201
6349
|
return get(layout, key, defaultValue);
|
|
6202
6350
|
};
|
|
6203
6351
|
const setLayoutForKey = (key, config) => {
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6352
|
+
setLayout(prevLayout => {
|
|
6353
|
+
const newLayout = assign({}, prevLayout);
|
|
6354
|
+
set$1(newLayout, key, config);
|
|
6355
|
+
return newLayout;
|
|
6356
|
+
});
|
|
6207
6357
|
};
|
|
6208
6358
|
const layoutContext = {
|
|
6209
6359
|
layout,
|
|
@@ -6402,7 +6552,6 @@ function CollapsibleEntry(props) {
|
|
|
6402
6552
|
class: "bio-properties-panel-collapsible-entry-header",
|
|
6403
6553
|
onClick: toggleOpen,
|
|
6404
6554
|
children: [jsx("div", {
|
|
6405
|
-
title: label || placeholderLabel,
|
|
6406
6555
|
class: classnames('bio-properties-panel-collapsible-entry-header-title', !label && 'empty'),
|
|
6407
6556
|
children: label || placeholderLabel
|
|
6408
6557
|
}), jsx("button", {
|
|
@@ -6438,6 +6587,10 @@ function CollapsibleEntry(props) {
|
|
|
6438
6587
|
})]
|
|
6439
6588
|
});
|
|
6440
6589
|
}
|
|
6590
|
+
|
|
6591
|
+
/**
|
|
6592
|
+
* @param {import('../PropertiesPanel').ListItemDefinition} props
|
|
6593
|
+
*/
|
|
6441
6594
|
function ListItem(props) {
|
|
6442
6595
|
const {
|
|
6443
6596
|
autoFocusEntry,
|
|
@@ -6539,8 +6692,6 @@ function ListGroup(props) {
|
|
|
6539
6692
|
class: classnames('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : '', sticky && open ? 'sticky' : ''),
|
|
6540
6693
|
onClick: hasItems ? toggleOpen : noop$6,
|
|
6541
6694
|
children: [jsx("div", {
|
|
6542
|
-
title: props.tooltip ? null : label,
|
|
6543
|
-
"data-title": label,
|
|
6544
6695
|
class: "bio-properties-panel-group-header-title",
|
|
6545
6696
|
children: jsx(TooltipWrapper, {
|
|
6546
6697
|
value: props.tooltip,
|
|
@@ -6609,6 +6760,13 @@ function getNewItemIds(newItems, oldItems) {
|
|
|
6609
6760
|
const oldIds = oldItems.map(item => item.id);
|
|
6610
6761
|
return newIds.filter(itemId => !oldIds.includes(itemId));
|
|
6611
6762
|
}
|
|
6763
|
+
|
|
6764
|
+
/**
|
|
6765
|
+
* @param {Object} props
|
|
6766
|
+
* @param {Object} props.element
|
|
6767
|
+
* @param {String} props.forId - id of the entry the description is used for
|
|
6768
|
+
* @param {String} props.value
|
|
6769
|
+
*/
|
|
6612
6770
|
function Description$1(props) {
|
|
6613
6771
|
const {
|
|
6614
6772
|
element,
|
|
@@ -6738,6 +6896,16 @@ function isEdited$8(node) {
|
|
|
6738
6896
|
function prefixId$8(id) {
|
|
6739
6897
|
return `bio-properties-panel-${id}`;
|
|
6740
6898
|
}
|
|
6899
|
+
|
|
6900
|
+
/**
|
|
6901
|
+
* Button to open popups.
|
|
6902
|
+
*
|
|
6903
|
+
* @param {Object} props
|
|
6904
|
+
* @param {Function} props.onClick - Callback to trigger when the button is clicked.
|
|
6905
|
+
* @param {string} [props.title] - Tooltip text for the button.
|
|
6906
|
+
* @param {boolean} [props.disabled] - Whether the button is disabled.
|
|
6907
|
+
* @param {string} [props.className] - Additional class names for the button.
|
|
6908
|
+
*/
|
|
6741
6909
|
function OpenPopupButton({
|
|
6742
6910
|
onClick,
|
|
6743
6911
|
title = 'Open pop-up editor'
|
|
@@ -6881,6 +7049,7 @@ const FeelEditor = forwardRef((props, ref) => {
|
|
|
6881
7049
|
enableGutters,
|
|
6882
7050
|
value,
|
|
6883
7051
|
onInput,
|
|
7052
|
+
onKeyDown: onKeyDownProp = noop$4,
|
|
6884
7053
|
onFeelToggle = noop$4,
|
|
6885
7054
|
onLint = noop$4,
|
|
6886
7055
|
onOpenPopup = noop$4,
|
|
@@ -6913,6 +7082,8 @@ const FeelEditor = forwardRef((props, ref) => {
|
|
|
6913
7082
|
* - AND the cursor is at the beginning of the input
|
|
6914
7083
|
*/
|
|
6915
7084
|
const onKeyDown = e => {
|
|
7085
|
+
// Call parent onKeyDown handler first
|
|
7086
|
+
onKeyDownProp(e);
|
|
6916
7087
|
if (e.key !== 'Backspace' || !editor) {
|
|
6917
7088
|
return;
|
|
6918
7089
|
}
|
|
@@ -7029,6 +7200,22 @@ function FeelIcon(props) {
|
|
|
7029
7200
|
children: jsx(FeelIcon$1, {})
|
|
7030
7201
|
});
|
|
7031
7202
|
}
|
|
7203
|
+
|
|
7204
|
+
/**
|
|
7205
|
+
* @param {KeyboardEvent} event
|
|
7206
|
+
* @return {boolean}
|
|
7207
|
+
*/
|
|
7208
|
+
function isCmd(event) {
|
|
7209
|
+
// ensure we don't react to AltGr
|
|
7210
|
+
// (mapped to CTRL + ALT)
|
|
7211
|
+
if (event.altKey) {
|
|
7212
|
+
return false;
|
|
7213
|
+
}
|
|
7214
|
+
return event.ctrlKey || event.metaKey;
|
|
7215
|
+
}
|
|
7216
|
+
function isCmdWithChar(event) {
|
|
7217
|
+
return isCmd(event) && event.key.length === 1 && /^[a-zA-Z]$/.test(event.key);
|
|
7218
|
+
}
|
|
7032
7219
|
function ToggleSwitch(props) {
|
|
7033
7220
|
const {
|
|
7034
7221
|
id,
|
|
@@ -7137,7 +7324,7 @@ function ToggleSwitchEntry(props) {
|
|
|
7137
7324
|
inline: inline,
|
|
7138
7325
|
tooltip: tooltip,
|
|
7139
7326
|
element: element
|
|
7140
|
-
}), jsx(Description$1, {
|
|
7327
|
+
}, element), jsx(Description$1, {
|
|
7141
7328
|
forId: id,
|
|
7142
7329
|
element: element,
|
|
7143
7330
|
value: description
|
|
@@ -7310,7 +7497,7 @@ function prefixId$6(id) {
|
|
|
7310
7497
|
const noop$2 = () => {};
|
|
7311
7498
|
|
|
7312
7499
|
/**
|
|
7313
|
-
* @typedef {'required'|'optional'|'static'} FeelType
|
|
7500
|
+
* @typedef {'required'|'optional'|'optional-default-enabled'|'static'} FeelType
|
|
7314
7501
|
*/
|
|
7315
7502
|
|
|
7316
7503
|
/**
|
|
@@ -7340,7 +7527,7 @@ function FeelTextfield(props) {
|
|
|
7340
7527
|
element,
|
|
7341
7528
|
label,
|
|
7342
7529
|
hostLanguage,
|
|
7343
|
-
onInput,
|
|
7530
|
+
onInput: commitValue,
|
|
7344
7531
|
onBlur,
|
|
7345
7532
|
onError,
|
|
7346
7533
|
placeholder,
|
|
@@ -7353,11 +7540,17 @@ function FeelTextfield(props) {
|
|
|
7353
7540
|
OptionalComponent = OptionalFeelInput,
|
|
7354
7541
|
tooltip
|
|
7355
7542
|
} = props;
|
|
7356
|
-
const [localValue, setLocalValue] = useState(value);
|
|
7543
|
+
const [localValue, setLocalValue] = useState(getInitialFeelLocalValue(feel, value));
|
|
7357
7544
|
const editorRef = useShowEntryEvent(id);
|
|
7358
7545
|
const containerRef = useRef();
|
|
7359
|
-
const
|
|
7360
|
-
|
|
7546
|
+
const onInput = useCallback(newValue => {
|
|
7547
|
+
// we don't commit empty FEEL expressions,
|
|
7548
|
+
// but instead serialize them as <undefined>
|
|
7549
|
+
const newModelValue = newValue === '' || newValue === '=' ? undefined : newValue;
|
|
7550
|
+
commitValue(newModelValue);
|
|
7551
|
+
}, [commitValue]);
|
|
7552
|
+
const feelActive = isFeelActive(feel, localValue);
|
|
7553
|
+
const feelOnlyValue = getFeelValue(localValue);
|
|
7361
7554
|
const feelLanguageContext = useContext(FeelLanguageContext);
|
|
7362
7555
|
const [focus, _setFocus] = useState(undefined);
|
|
7363
7556
|
const {
|
|
@@ -7375,13 +7568,7 @@ function FeelTextfield(props) {
|
|
|
7375
7568
|
/**
|
|
7376
7569
|
* @type { import('min-dash').DebouncedFunction }
|
|
7377
7570
|
*/
|
|
7378
|
-
const
|
|
7379
|
-
const handleInput = newValue => {
|
|
7380
|
-
// we don't commit empty FEEL expressions,
|
|
7381
|
-
// but instead serialize them as <undefined>
|
|
7382
|
-
const newModelValue = newValue === '' || newValue === '=' ? undefined : newValue;
|
|
7383
|
-
handleInputCallback(newModelValue);
|
|
7384
|
-
};
|
|
7571
|
+
const handleInput = useDebounce(onInput, debounce);
|
|
7385
7572
|
const handleFeelToggle = useStaticCallback(() => {
|
|
7386
7573
|
if (feel === 'required') {
|
|
7387
7574
|
return;
|
|
@@ -7394,7 +7581,7 @@ function FeelTextfield(props) {
|
|
|
7394
7581
|
handleInput(feelOnlyValue);
|
|
7395
7582
|
}
|
|
7396
7583
|
});
|
|
7397
|
-
const handleLocalInput = newValue => {
|
|
7584
|
+
const handleLocalInput = (newValue, useDebounce = true) => {
|
|
7398
7585
|
if (feelActive) {
|
|
7399
7586
|
newValue = '=' + newValue;
|
|
7400
7587
|
}
|
|
@@ -7402,23 +7589,33 @@ function FeelTextfield(props) {
|
|
|
7402
7589
|
return;
|
|
7403
7590
|
}
|
|
7404
7591
|
setLocalValue(newValue);
|
|
7405
|
-
|
|
7592
|
+
if (useDebounce) {
|
|
7593
|
+
handleInput(newValue);
|
|
7594
|
+
} else {
|
|
7595
|
+
onInput(newValue);
|
|
7596
|
+
}
|
|
7406
7597
|
if (!feelActive && isString(newValue) && newValue.startsWith('=')) {
|
|
7407
7598
|
// focus is behind `=` sign that will be removed
|
|
7408
7599
|
setFocus(-1);
|
|
7409
7600
|
}
|
|
7410
7601
|
};
|
|
7411
7602
|
const handleOnBlur = e => {
|
|
7603
|
+
handleInput.cancel?.();
|
|
7412
7604
|
if (e.target.type === 'checkbox') {
|
|
7413
7605
|
onInput(e.target.checked);
|
|
7414
7606
|
} else {
|
|
7415
7607
|
const trimmedValue = e.target.value.trim();
|
|
7416
|
-
|
|
7608
|
+
handleLocalInput(trimmedValue, false);
|
|
7417
7609
|
}
|
|
7418
7610
|
if (onBlur) {
|
|
7419
7611
|
onBlur(e);
|
|
7420
7612
|
}
|
|
7421
7613
|
};
|
|
7614
|
+
const handleOnKeyDown = e => {
|
|
7615
|
+
if (isCmdWithChar(e)) {
|
|
7616
|
+
handleInput.flush?.();
|
|
7617
|
+
}
|
|
7618
|
+
};
|
|
7422
7619
|
const handleLint = useStaticCallback((lint = []) => {
|
|
7423
7620
|
const syntaxError = lint.some(report => report.type === 'Syntax Error');
|
|
7424
7621
|
if (syntaxError) {
|
|
@@ -7485,12 +7682,26 @@ function FeelTextfield(props) {
|
|
|
7485
7682
|
if (feelActive || isPopupOpen) {
|
|
7486
7683
|
return;
|
|
7487
7684
|
}
|
|
7488
|
-
const
|
|
7489
|
-
if (
|
|
7685
|
+
const feelData = event.clipboardData.getData('application/FEEL');
|
|
7686
|
+
if (feelData) {
|
|
7490
7687
|
setTimeout(() => {
|
|
7491
7688
|
handleFeelToggle();
|
|
7492
7689
|
setFocus();
|
|
7493
7690
|
});
|
|
7691
|
+
return;
|
|
7692
|
+
}
|
|
7693
|
+
const input = event.target;
|
|
7694
|
+
const isFieldEmpty = !input.value;
|
|
7695
|
+
const isAllSelected = input.selectionStart === 0 && input.selectionEnd === input.value.length;
|
|
7696
|
+
if (isFieldEmpty || isAllSelected) {
|
|
7697
|
+
const textData = event.clipboardData.getData('text');
|
|
7698
|
+
const trimmedValue = textData.trim();
|
|
7699
|
+
setLocalValue(trimmedValue);
|
|
7700
|
+
handleInput(trimmedValue);
|
|
7701
|
+
if (!feelActive && isString(trimmedValue) && trimmedValue.startsWith('=')) {
|
|
7702
|
+
setFocus(trimmedValue.length - 1);
|
|
7703
|
+
}
|
|
7704
|
+
event.preventDefault();
|
|
7494
7705
|
}
|
|
7495
7706
|
};
|
|
7496
7707
|
containerRef.current.addEventListener('copy', copyHandler);
|
|
@@ -7526,11 +7737,12 @@ function FeelTextfield(props) {
|
|
|
7526
7737
|
ref: containerRef,
|
|
7527
7738
|
children: [jsx(FeelIndicator, {
|
|
7528
7739
|
active: feelActive,
|
|
7529
|
-
disabled: feel
|
|
7740
|
+
disabled: !isFeelOptional(feel) || disabled,
|
|
7530
7741
|
onClick: handleFeelToggle
|
|
7531
7742
|
}), feelActive ? jsx(FeelEditor, {
|
|
7532
7743
|
name: id,
|
|
7533
7744
|
onInput: handleLocalInput,
|
|
7745
|
+
onKeyDown: handleOnKeyDown,
|
|
7534
7746
|
contentAttributes: {
|
|
7535
7747
|
'id': prefixId$5(id),
|
|
7536
7748
|
'aria-label': label
|
|
@@ -7553,6 +7765,7 @@ function FeelTextfield(props) {
|
|
|
7553
7765
|
...props,
|
|
7554
7766
|
popupOpen: isPopupOpen,
|
|
7555
7767
|
onInput: handleLocalInput,
|
|
7768
|
+
onKeyDown: handleOnKeyDown,
|
|
7556
7769
|
onBlur: handleOnBlur,
|
|
7557
7770
|
contentAttributes: {
|
|
7558
7771
|
'id': prefixId$5(id),
|
|
@@ -7571,6 +7784,7 @@ const OptionalFeelInput = forwardRef((props, ref) => {
|
|
|
7571
7784
|
id,
|
|
7572
7785
|
disabled,
|
|
7573
7786
|
onInput,
|
|
7787
|
+
onKeyDown,
|
|
7574
7788
|
value,
|
|
7575
7789
|
onFocus,
|
|
7576
7790
|
onBlur,
|
|
@@ -7606,6 +7820,7 @@ const OptionalFeelInput = forwardRef((props, ref) => {
|
|
|
7606
7820
|
class: "bio-properties-panel-input",
|
|
7607
7821
|
onInput: e => onInput(e.target.value),
|
|
7608
7822
|
onFocus: onFocus,
|
|
7823
|
+
onKeyDown: onKeyDown,
|
|
7609
7824
|
onBlur: onBlur,
|
|
7610
7825
|
placeholder: placeholder,
|
|
7611
7826
|
value: value || ''
|
|
@@ -7979,6 +8194,87 @@ function isEdited$5(node) {
|
|
|
7979
8194
|
function prefixId$5(id) {
|
|
7980
8195
|
return `bio-properties-panel-${id}`;
|
|
7981
8196
|
}
|
|
8197
|
+
|
|
8198
|
+
/**
|
|
8199
|
+
* Determine if FEEL is optional for the configured {@link FeelType}.
|
|
8200
|
+
*
|
|
8201
|
+
* @param {FeelType} feelType
|
|
8202
|
+
*
|
|
8203
|
+
* @return {boolean}
|
|
8204
|
+
*/
|
|
8205
|
+
function isFeelOptional(feelType) {
|
|
8206
|
+
return feelType === 'optional' || feelType === 'optional-default-enabled';
|
|
8207
|
+
}
|
|
8208
|
+
|
|
8209
|
+
/**
|
|
8210
|
+
* Determine if FEEL editing is currently active.
|
|
8211
|
+
*
|
|
8212
|
+
* @param {FeelType} feelType
|
|
8213
|
+
* @param {string} localValue
|
|
8214
|
+
*
|
|
8215
|
+
* @return {boolean}
|
|
8216
|
+
*/
|
|
8217
|
+
function isFeelActive(feelType, localValue) {
|
|
8218
|
+
if (feelType === 'required') {
|
|
8219
|
+
return true;
|
|
8220
|
+
}
|
|
8221
|
+
if (isString(localValue)) {
|
|
8222
|
+
if (localValue.startsWith('=')) {
|
|
8223
|
+
return true;
|
|
8224
|
+
}
|
|
8225
|
+
}
|
|
8226
|
+
return false;
|
|
8227
|
+
}
|
|
8228
|
+
|
|
8229
|
+
/**
|
|
8230
|
+
* @template T
|
|
8231
|
+
* @param {T} value
|
|
8232
|
+
*
|
|
8233
|
+
* @return {string|T}
|
|
8234
|
+
*/
|
|
8235
|
+
function getFeelValue(value) {
|
|
8236
|
+
if (isString(value) && value.startsWith('=')) {
|
|
8237
|
+
return value.substring(1);
|
|
8238
|
+
}
|
|
8239
|
+
return value;
|
|
8240
|
+
}
|
|
8241
|
+
|
|
8242
|
+
/**
|
|
8243
|
+
* Initialize local FEEL value.
|
|
8244
|
+
*
|
|
8245
|
+
* `optional-default-enabled` starts in FEEL mode if no value or empty string is provided.
|
|
8246
|
+
*
|
|
8247
|
+
* @template T
|
|
8248
|
+
* @param {FeelType} feelType
|
|
8249
|
+
* @param {T} value
|
|
8250
|
+
*
|
|
8251
|
+
* @return {string|T}
|
|
8252
|
+
*/
|
|
8253
|
+
function getInitialFeelLocalValue(feelType, value) {
|
|
8254
|
+
if (feelType === 'optional-default-enabled' && (value === undefined || value === '')) {
|
|
8255
|
+
return '=';
|
|
8256
|
+
}
|
|
8257
|
+
return value;
|
|
8258
|
+
}
|
|
8259
|
+
|
|
8260
|
+
/**
|
|
8261
|
+
* @typedef { { value: string, label: string, disabled: boolean, children: { value: string, label: string, disabled: boolean } } } Option
|
|
8262
|
+
*/
|
|
8263
|
+
|
|
8264
|
+
/**
|
|
8265
|
+
* Provides basic select input.
|
|
8266
|
+
*
|
|
8267
|
+
* @param {object} props
|
|
8268
|
+
* @param {string} props.id
|
|
8269
|
+
* @param {string[]} props.path
|
|
8270
|
+
* @param {string} props.label
|
|
8271
|
+
* @param {Function} props.onChange
|
|
8272
|
+
* @param {Function} props.onFocus
|
|
8273
|
+
* @param {Function} props.onBlur
|
|
8274
|
+
* @param {Array<Option>} [props.options]
|
|
8275
|
+
* @param {string} props.value
|
|
8276
|
+
* @param {boolean} [props.disabled]
|
|
8277
|
+
*/
|
|
7982
8278
|
function Select(props) {
|
|
7983
8279
|
const {
|
|
7984
8280
|
id,
|
|
@@ -8144,12 +8440,13 @@ function TextArea(props) {
|
|
|
8144
8440
|
id,
|
|
8145
8441
|
label,
|
|
8146
8442
|
debounce,
|
|
8147
|
-
onInput,
|
|
8443
|
+
onInput: commitValue,
|
|
8148
8444
|
value = '',
|
|
8149
8445
|
disabled,
|
|
8150
8446
|
monospace,
|
|
8151
8447
|
onFocus,
|
|
8152
8448
|
onBlur,
|
|
8449
|
+
onPaste,
|
|
8153
8450
|
autoResize = true,
|
|
8154
8451
|
placeholder,
|
|
8155
8452
|
rows = autoResize ? 1 : 2,
|
|
@@ -8157,16 +8454,16 @@ function TextArea(props) {
|
|
|
8157
8454
|
} = props;
|
|
8158
8455
|
const [localValue, setLocalValue] = useState(value);
|
|
8159
8456
|
const ref = useShowEntryEvent(id);
|
|
8457
|
+
const onInput = useCallback(newValue => {
|
|
8458
|
+
const newModelValue = newValue === '' ? undefined : newValue;
|
|
8459
|
+
commitValue(newModelValue);
|
|
8460
|
+
}, [commitValue]);
|
|
8160
8461
|
const visible = useElementVisible(ref.current);
|
|
8161
8462
|
|
|
8162
8463
|
/**
|
|
8163
8464
|
* @type { import('min-dash').DebouncedFunction }
|
|
8164
8465
|
*/
|
|
8165
|
-
const
|
|
8166
|
-
const handleInput = newValue => {
|
|
8167
|
-
const newModelValue = newValue === '' ? undefined : newValue;
|
|
8168
|
-
handleInputCallback(newModelValue);
|
|
8169
|
-
};
|
|
8466
|
+
const handleInput = useDebounce(onInput, debounce);
|
|
8170
8467
|
const handleLocalInput = e => {
|
|
8171
8468
|
autoResize && resizeToContents(e.target);
|
|
8172
8469
|
if (e.target.value === localValue) {
|
|
@@ -8179,11 +8476,40 @@ function TextArea(props) {
|
|
|
8179
8476
|
const trimmedValue = e.target.value.trim();
|
|
8180
8477
|
|
|
8181
8478
|
// trim and commit on blur
|
|
8479
|
+
handleInput.cancel?.();
|
|
8182
8480
|
onInput(trimmedValue);
|
|
8481
|
+
setLocalValue(trimmedValue);
|
|
8183
8482
|
if (onBlur) {
|
|
8184
8483
|
onBlur(e);
|
|
8185
8484
|
}
|
|
8186
8485
|
};
|
|
8486
|
+
const handleOnPaste = e => {
|
|
8487
|
+
const input = e.target;
|
|
8488
|
+
const isFieldEmpty = !input.value;
|
|
8489
|
+
const isAllSelected = input.selectionStart === 0 && input.selectionEnd === input.value.length;
|
|
8490
|
+
|
|
8491
|
+
// Trim and handle paste if field is empty or all content is selected
|
|
8492
|
+
if (isFieldEmpty || isAllSelected) {
|
|
8493
|
+
const trimmedValue = e.clipboardData.getData('text').trim();
|
|
8494
|
+
setLocalValue(trimmedValue);
|
|
8495
|
+
handleInput(trimmedValue);
|
|
8496
|
+
if (onPaste) {
|
|
8497
|
+
onPaste(e);
|
|
8498
|
+
}
|
|
8499
|
+
e.preventDefault();
|
|
8500
|
+
return;
|
|
8501
|
+
}
|
|
8502
|
+
|
|
8503
|
+
// Allow default paste behavior for normal text editing
|
|
8504
|
+
if (onPaste) {
|
|
8505
|
+
onPaste(e);
|
|
8506
|
+
}
|
|
8507
|
+
};
|
|
8508
|
+
const handleOnKeyDown = e => {
|
|
8509
|
+
if (isCmdWithChar(e)) {
|
|
8510
|
+
handleInput.flush?.();
|
|
8511
|
+
}
|
|
8512
|
+
};
|
|
8187
8513
|
useLayoutEffect(() => {
|
|
8188
8514
|
autoResize && resizeToContents(ref.current);
|
|
8189
8515
|
}, []);
|
|
@@ -8215,7 +8541,9 @@ function TextArea(props) {
|
|
|
8215
8541
|
class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : '', autoResize ? 'auto-resize' : ''),
|
|
8216
8542
|
onInput: handleLocalInput,
|
|
8217
8543
|
onFocus: onFocus,
|
|
8544
|
+
onKeyDown: handleOnKeyDown,
|
|
8218
8545
|
onBlur: handleOnBlur,
|
|
8546
|
+
onPaste: handleOnPaste,
|
|
8219
8547
|
placeholder: placeholder,
|
|
8220
8548
|
rows: rows,
|
|
8221
8549
|
value: localValue,
|
|
@@ -8236,6 +8564,7 @@ function TextArea(props) {
|
|
|
8236
8564
|
* @param {Function} props.setValue
|
|
8237
8565
|
* @param {Function} props.onFocus
|
|
8238
8566
|
* @param {Function} props.onBlur
|
|
8567
|
+
* @param {Function} props.onPaste
|
|
8239
8568
|
* @param {number} props.rows
|
|
8240
8569
|
* @param {boolean} props.monospace
|
|
8241
8570
|
* @param {Function} [props.validate]
|
|
@@ -8256,6 +8585,7 @@ function TextAreaEntry(props) {
|
|
|
8256
8585
|
validate,
|
|
8257
8586
|
onFocus,
|
|
8258
8587
|
onBlur,
|
|
8588
|
+
onPaste,
|
|
8259
8589
|
placeholder,
|
|
8260
8590
|
autoResize,
|
|
8261
8591
|
tooltip
|
|
@@ -8291,6 +8621,7 @@ function TextAreaEntry(props) {
|
|
|
8291
8621
|
onInput: onInput,
|
|
8292
8622
|
onFocus: onFocus,
|
|
8293
8623
|
onBlur: onBlur,
|
|
8624
|
+
onPaste: onPaste,
|
|
8294
8625
|
rows: rows,
|
|
8295
8626
|
debounce: debounce,
|
|
8296
8627
|
monospace: monospace,
|
|
@@ -8324,32 +8655,57 @@ function Textfield(props) {
|
|
|
8324
8655
|
disabled = false,
|
|
8325
8656
|
id,
|
|
8326
8657
|
label,
|
|
8327
|
-
onInput,
|
|
8658
|
+
onInput: commitValue,
|
|
8328
8659
|
onFocus,
|
|
8329
8660
|
onBlur,
|
|
8661
|
+
onPaste,
|
|
8330
8662
|
placeholder,
|
|
8331
8663
|
value = '',
|
|
8332
8664
|
tooltip
|
|
8333
8665
|
} = props;
|
|
8334
8666
|
const [localValue, setLocalValue] = useState(value || '');
|
|
8335
8667
|
const ref = useShowEntryEvent(id);
|
|
8668
|
+
const onInput = useCallback(newValue => {
|
|
8669
|
+
const newModelValue = newValue === '' ? undefined : newValue;
|
|
8670
|
+
commitValue(newModelValue);
|
|
8671
|
+
}, [commitValue]);
|
|
8336
8672
|
|
|
8337
8673
|
/**
|
|
8338
8674
|
* @type { import('min-dash').DebouncedFunction }
|
|
8339
8675
|
*/
|
|
8340
|
-
const
|
|
8676
|
+
const handleInput = useDebounce(onInput, debounce);
|
|
8341
8677
|
const handleOnBlur = e => {
|
|
8342
8678
|
const trimmedValue = e.target.value.trim();
|
|
8343
8679
|
|
|
8344
8680
|
// trim and commit on blur
|
|
8681
|
+
handleInput.cancel?.();
|
|
8345
8682
|
onInput(trimmedValue);
|
|
8683
|
+
setLocalValue(trimmedValue);
|
|
8346
8684
|
if (onBlur) {
|
|
8347
8685
|
onBlur(e);
|
|
8348
8686
|
}
|
|
8349
8687
|
};
|
|
8350
|
-
const
|
|
8351
|
-
const
|
|
8352
|
-
|
|
8688
|
+
const handleOnPaste = e => {
|
|
8689
|
+
const input = e.target;
|
|
8690
|
+
const isFieldEmpty = !input.value;
|
|
8691
|
+
const isAllSelected = input.selectionStart === 0 && input.selectionEnd === input.value.length;
|
|
8692
|
+
|
|
8693
|
+
// Trim and handle paste if field is empty or all content is selected (overwrite)
|
|
8694
|
+
if (isFieldEmpty || isAllSelected) {
|
|
8695
|
+
const trimmedValue = e.clipboardData.getData('text').trim();
|
|
8696
|
+
setLocalValue(trimmedValue);
|
|
8697
|
+
handleInput(trimmedValue);
|
|
8698
|
+
if (onPaste) {
|
|
8699
|
+
onPaste(e);
|
|
8700
|
+
}
|
|
8701
|
+
e.preventDefault();
|
|
8702
|
+
return;
|
|
8703
|
+
}
|
|
8704
|
+
|
|
8705
|
+
// Allow default paste behavior for normal text editing
|
|
8706
|
+
if (onPaste) {
|
|
8707
|
+
onPaste(e);
|
|
8708
|
+
}
|
|
8353
8709
|
};
|
|
8354
8710
|
const handleLocalInput = e => {
|
|
8355
8711
|
if (e.target.value === localValue) {
|
|
@@ -8364,6 +8720,11 @@ function Textfield(props) {
|
|
|
8364
8720
|
}
|
|
8365
8721
|
setLocalValue(value);
|
|
8366
8722
|
}, [value]);
|
|
8723
|
+
const handleOnKeyDown = e => {
|
|
8724
|
+
if (isCmdWithChar(e)) {
|
|
8725
|
+
handleInput.flush?.();
|
|
8726
|
+
}
|
|
8727
|
+
};
|
|
8367
8728
|
return jsxs("div", {
|
|
8368
8729
|
class: "bio-properties-panel-textfield",
|
|
8369
8730
|
children: [jsx("label", {
|
|
@@ -8386,7 +8747,9 @@ function Textfield(props) {
|
|
|
8386
8747
|
class: "bio-properties-panel-input",
|
|
8387
8748
|
onInput: handleLocalInput,
|
|
8388
8749
|
onFocus: onFocus,
|
|
8750
|
+
onKeyDown: handleOnKeyDown,
|
|
8389
8751
|
onBlur: handleOnBlur,
|
|
8752
|
+
onPaste: handleOnPaste,
|
|
8390
8753
|
placeholder: placeholder,
|
|
8391
8754
|
value: localValue
|
|
8392
8755
|
})]
|
|
@@ -8421,6 +8784,7 @@ function TextfieldEntry(props) {
|
|
|
8421
8784
|
validate,
|
|
8422
8785
|
onFocus,
|
|
8423
8786
|
onBlur,
|
|
8787
|
+
onPaste,
|
|
8424
8788
|
placeholder,
|
|
8425
8789
|
tooltip
|
|
8426
8790
|
} = props;
|
|
@@ -8456,6 +8820,7 @@ function TextfieldEntry(props) {
|
|
|
8456
8820
|
onInput: onInput,
|
|
8457
8821
|
onFocus: onFocus,
|
|
8458
8822
|
onBlur: onBlur,
|
|
8823
|
+
onPaste: onPaste,
|
|
8459
8824
|
placeholder: placeholder,
|
|
8460
8825
|
value: value,
|
|
8461
8826
|
tooltip: tooltip,
|
|
@@ -8725,6 +9090,7 @@ function Title(props) {
|
|
|
8725
9090
|
class: "bio-properties-panel-popup__title",
|
|
8726
9091
|
children: title
|
|
8727
9092
|
}), children, showCloseButton && jsx("button", {
|
|
9093
|
+
type: "button",
|
|
8728
9094
|
title: closeButtonTooltip,
|
|
8729
9095
|
class: "bio-properties-panel-popup__close",
|
|
8730
9096
|
onClick: onClose,
|
|
@@ -8766,6 +9132,25 @@ function cancel(event) {
|
|
|
8766
9132
|
event.preventDefault();
|
|
8767
9133
|
event.stopPropagation();
|
|
8768
9134
|
}
|
|
9135
|
+
|
|
9136
|
+
/**
|
|
9137
|
+
* @typedef {Object} FeelPopupProps
|
|
9138
|
+
* @property {string} entryId
|
|
9139
|
+
* @property {Function} onInput
|
|
9140
|
+
* @property {Function} onClose
|
|
9141
|
+
* @property {string} title
|
|
9142
|
+
* @property {'feel'|'feelers'} type
|
|
9143
|
+
* @property {string} value
|
|
9144
|
+
* @property {Array} [links]
|
|
9145
|
+
* @property {Array|Object} [variables]
|
|
9146
|
+
* @property {Object} [position]
|
|
9147
|
+
* @property {string} [hostLanguage]
|
|
9148
|
+
* @property {boolean} [singleLine]
|
|
9149
|
+
* @property {HTMLElement} [sourceElement]
|
|
9150
|
+
* @property {HTMLElement|string} [tooltipContainer]
|
|
9151
|
+
* @property {Object} [eventBus]
|
|
9152
|
+
*/
|
|
9153
|
+
|
|
8769
9154
|
const FEEL_POPUP_WIDTH = 700;
|
|
8770
9155
|
const FEEL_POPUP_HEIGHT = 250;
|
|
8771
9156
|
|