@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.cjs
CHANGED
|
@@ -3128,7 +3128,7 @@ function hasModifier(event) {
|
|
|
3128
3128
|
* @param {KeyboardEvent} event
|
|
3129
3129
|
* @return {boolean}
|
|
3130
3130
|
*/
|
|
3131
|
-
function isCmd(event) {
|
|
3131
|
+
function isCmd$1(event) {
|
|
3132
3132
|
// ensure we don't react to AltGr
|
|
3133
3133
|
// (mapped to CTRL + ALT)
|
|
3134
3134
|
if (event.altKey) {
|
|
@@ -3160,28 +3160,28 @@ function isShift(event) {
|
|
|
3160
3160
|
* @param {KeyboardEvent} event
|
|
3161
3161
|
*/
|
|
3162
3162
|
function isCopy(event) {
|
|
3163
|
-
return isCmd(event) && isKey(KEYS_COPY, event);
|
|
3163
|
+
return isCmd$1(event) && isKey(KEYS_COPY, event);
|
|
3164
3164
|
}
|
|
3165
3165
|
|
|
3166
3166
|
/**
|
|
3167
3167
|
* @param {KeyboardEvent} event
|
|
3168
3168
|
*/
|
|
3169
3169
|
function isPaste(event) {
|
|
3170
|
-
return isCmd(event) && isKey(KEYS_PASTE, event);
|
|
3170
|
+
return isCmd$1(event) && isKey(KEYS_PASTE, event);
|
|
3171
3171
|
}
|
|
3172
3172
|
|
|
3173
3173
|
/**
|
|
3174
3174
|
* @param {KeyboardEvent} event
|
|
3175
3175
|
*/
|
|
3176
3176
|
function isUndo(event) {
|
|
3177
|
-
return isCmd(event) && !isShift(event) && isKey(KEYS_UNDO, event);
|
|
3177
|
+
return isCmd$1(event) && !isShift(event) && isKey(KEYS_UNDO, event);
|
|
3178
3178
|
}
|
|
3179
3179
|
|
|
3180
3180
|
/**
|
|
3181
3181
|
* @param {KeyboardEvent} event
|
|
3182
3182
|
*/
|
|
3183
3183
|
function isRedo(event) {
|
|
3184
|
-
return isCmd(event) && (isKey(KEYS_REDO, event) || isKey(KEYS_UNDO, event) && isShift(event));
|
|
3184
|
+
return isCmd$1(event) && (isKey(KEYS_REDO, event) || isKey(KEYS_UNDO, event) && isShift(event));
|
|
3185
3185
|
}
|
|
3186
3186
|
|
|
3187
3187
|
/**
|
|
@@ -3350,7 +3350,7 @@ Keyboard.prototype.removeListener = function (listener, type) {
|
|
|
3350
3350
|
this._eventBus.off(type || KEYDOWN_EVENT, listener);
|
|
3351
3351
|
};
|
|
3352
3352
|
Keyboard.prototype.hasModifier = hasModifier;
|
|
3353
|
-
Keyboard.prototype.isCmd = isCmd;
|
|
3353
|
+
Keyboard.prototype.isCmd = isCmd$1;
|
|
3354
3354
|
Keyboard.prototype.isShift = isShift;
|
|
3355
3355
|
Keyboard.prototype.isKey = isKey;
|
|
3356
3356
|
|
|
@@ -3442,7 +3442,7 @@ KeyboardBindings.prototype.registerBindings = function (keyboard, editorActions)
|
|
|
3442
3442
|
|
|
3443
3443
|
// quirk: it has to be triggered by `=` as well to work on international keyboard layout
|
|
3444
3444
|
// cf: https://github.com/bpmn-io/bpmn-js/issues/1362#issuecomment-722989754
|
|
3445
|
-
if (isKey(['+', 'Add', '='], event) && isCmd(event)) {
|
|
3445
|
+
if (isKey(['+', 'Add', '='], event) && isCmd$1(event)) {
|
|
3446
3446
|
editorActions.trigger('stepZoom', {
|
|
3447
3447
|
value: 1
|
|
3448
3448
|
});
|
|
@@ -3454,7 +3454,7 @@ KeyboardBindings.prototype.registerBindings = function (keyboard, editorActions)
|
|
|
3454
3454
|
// CTRL + -
|
|
3455
3455
|
addListener('stepZoom', function (context) {
|
|
3456
3456
|
var event = context.keyEvent;
|
|
3457
|
-
if (isKey(['-', 'Subtract'], event) && isCmd(event)) {
|
|
3457
|
+
if (isKey(['-', 'Subtract'], event) && isCmd$1(event)) {
|
|
3458
3458
|
editorActions.trigger('stepZoom', {
|
|
3459
3459
|
value: -1
|
|
3460
3460
|
});
|
|
@@ -3466,7 +3466,7 @@ KeyboardBindings.prototype.registerBindings = function (keyboard, editorActions)
|
|
|
3466
3466
|
// CTRL + 0
|
|
3467
3467
|
addListener('zoom', function (context) {
|
|
3468
3468
|
var event = context.keyEvent;
|
|
3469
|
-
if (isKey('0', event) && isCmd(event)) {
|
|
3469
|
+
if (isKey('0', event) && isCmd$1(event)) {
|
|
3470
3470
|
editorActions.trigger('zoom', {
|
|
3471
3471
|
value: 1
|
|
3472
3472
|
});
|
|
@@ -5473,6 +5473,21 @@ OpenPopupIcon.defaultProps = {
|
|
|
5473
5473
|
xmlns: "http://www.w3.org/2000/svg",
|
|
5474
5474
|
viewBox: "0 0 16 16"
|
|
5475
5475
|
};
|
|
5476
|
+
|
|
5477
|
+
/**
|
|
5478
|
+
* @typedef { {
|
|
5479
|
+
* getElementLabel: (element: object) => string,
|
|
5480
|
+
* getTypeLabel: (element: object) => string,
|
|
5481
|
+
* getElementIcon: (element: object) => import('preact').Component,
|
|
5482
|
+
* getDocumentationRef: (element: object) => string
|
|
5483
|
+
* } } HeaderProvider
|
|
5484
|
+
*/
|
|
5485
|
+
|
|
5486
|
+
/**
|
|
5487
|
+
* @param {Object} props
|
|
5488
|
+
* @param {Object} props.element,
|
|
5489
|
+
* @param {HeaderProvider} props.headerProvider
|
|
5490
|
+
*/
|
|
5476
5491
|
function Header(props) {
|
|
5477
5492
|
const {
|
|
5478
5493
|
element,
|
|
@@ -5500,11 +5515,9 @@ function Header(props) {
|
|
|
5500
5515
|
}), jsxRuntime.jsxs("div", {
|
|
5501
5516
|
class: "bio-properties-panel-header-labels",
|
|
5502
5517
|
children: [jsxRuntime.jsx("div", {
|
|
5503
|
-
title: type,
|
|
5504
5518
|
class: "bio-properties-panel-header-type",
|
|
5505
5519
|
children: type
|
|
5506
5520
|
}), label ? jsxRuntime.jsx("div", {
|
|
5507
|
-
title: label,
|
|
5508
5521
|
class: "bio-properties-panel-header-label",
|
|
5509
5522
|
children: label
|
|
5510
5523
|
}) : null]
|
|
@@ -5592,6 +5605,27 @@ function useTooltipContext(id, element) {
|
|
|
5592
5605
|
} = hooks.useContext(TooltipContext);
|
|
5593
5606
|
return getTooltipForId(id, element);
|
|
5594
5607
|
}
|
|
5608
|
+
|
|
5609
|
+
/**
|
|
5610
|
+
* @typedef {Object} TooltipProps
|
|
5611
|
+
* @property {Object} [parent] - Parent element ref for portal rendering
|
|
5612
|
+
* @property {String} [direction='right'] - Tooltip direction ( 'right', 'top')
|
|
5613
|
+
* @property {String} [position] - Custom CSS position override
|
|
5614
|
+
* @property {Number} [showDelay=250] - Delay in ms before showing tooltip on hover
|
|
5615
|
+
* @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
|
|
5616
|
+
* @property {*} [children] - Child elements to render inside the tooltip wrapper
|
|
5617
|
+
*/
|
|
5618
|
+
|
|
5619
|
+
/**
|
|
5620
|
+
* Tooltip wrapper that provides context-based tooltip content lookup.
|
|
5621
|
+
* All props are forwarded to the underlying Tooltip component.
|
|
5622
|
+
*
|
|
5623
|
+
* @param {TooltipProps & {
|
|
5624
|
+
* forId: String,
|
|
5625
|
+
* value?: String|Object,
|
|
5626
|
+
* element?: Object
|
|
5627
|
+
* }} props - Shared tooltip props plus wrapper-specific ones
|
|
5628
|
+
*/
|
|
5595
5629
|
function TooltipWrapper(props) {
|
|
5596
5630
|
const {
|
|
5597
5631
|
forId,
|
|
@@ -5608,35 +5642,93 @@ function TooltipWrapper(props) {
|
|
|
5608
5642
|
forId: `bio-properties-panel-${forId}`
|
|
5609
5643
|
});
|
|
5610
5644
|
}
|
|
5645
|
+
|
|
5646
|
+
/**
|
|
5647
|
+
* @param {TooltipProps & {
|
|
5648
|
+
* forId: String,
|
|
5649
|
+
* value: String|Object
|
|
5650
|
+
* }} props
|
|
5651
|
+
*/
|
|
5611
5652
|
function Tooltip(props) {
|
|
5612
5653
|
const {
|
|
5613
5654
|
forId,
|
|
5614
5655
|
value,
|
|
5615
5656
|
parent,
|
|
5616
5657
|
direction = 'right',
|
|
5617
|
-
position
|
|
5658
|
+
position,
|
|
5659
|
+
showDelay = 250,
|
|
5660
|
+
hideDelay = 250
|
|
5618
5661
|
} = props;
|
|
5619
5662
|
const [visible, setVisible] = hooks.useState(false);
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
const
|
|
5623
|
-
|
|
5663
|
+
const [tooltipPosition, setTooltipPosition] = hooks.useState(null);
|
|
5664
|
+
const [arrowOffset, setArrowOffset] = hooks.useState(null);
|
|
5665
|
+
const showTimeoutRef = hooks.useRef(null);
|
|
5666
|
+
const hideTimeoutRef = hooks.useRef(null);
|
|
5624
5667
|
const wrapperRef = hooks.useRef(null);
|
|
5625
5668
|
const tooltipRef = hooks.useRef(null);
|
|
5626
5669
|
const show = (_, delay) => {
|
|
5670
|
+
clearTimeout(showTimeoutRef.current);
|
|
5671
|
+
clearTimeout(hideTimeoutRef.current);
|
|
5627
5672
|
if (visible) return;
|
|
5628
5673
|
if (delay) {
|
|
5629
|
-
|
|
5674
|
+
showTimeoutRef.current = setTimeout(() => {
|
|
5630
5675
|
setVisible(true);
|
|
5631
|
-
},
|
|
5676
|
+
}, showDelay);
|
|
5632
5677
|
} else {
|
|
5633
5678
|
setVisible(true);
|
|
5634
5679
|
}
|
|
5635
5680
|
};
|
|
5636
|
-
const
|
|
5637
|
-
|
|
5638
|
-
setVisible(false);
|
|
5681
|
+
const handleWrapperMouseEnter = e => {
|
|
5682
|
+
show(e, true);
|
|
5639
5683
|
};
|
|
5684
|
+
const hide = (delay = false) => {
|
|
5685
|
+
clearTimeout(showTimeoutRef.current);
|
|
5686
|
+
clearTimeout(hideTimeoutRef.current);
|
|
5687
|
+
if (delay) {
|
|
5688
|
+
hideTimeoutRef.current = setTimeout(() => {
|
|
5689
|
+
setVisible(false);
|
|
5690
|
+
}, hideDelay);
|
|
5691
|
+
} else {
|
|
5692
|
+
setVisible(false);
|
|
5693
|
+
}
|
|
5694
|
+
};
|
|
5695
|
+
|
|
5696
|
+
// Cleanup timeouts on unmount
|
|
5697
|
+
hooks.useEffect(() => {
|
|
5698
|
+
return () => {
|
|
5699
|
+
clearTimeout(showTimeoutRef.current);
|
|
5700
|
+
clearTimeout(hideTimeoutRef.current);
|
|
5701
|
+
};
|
|
5702
|
+
}, []);
|
|
5703
|
+
|
|
5704
|
+
// Handle click outside to close tooltip for non-focusable elements
|
|
5705
|
+
hooks.useEffect(() => {
|
|
5706
|
+
if (!visible) return;
|
|
5707
|
+
const handleClickOutside = e => {
|
|
5708
|
+
// If clicking outside both the wrapper and tooltip, hide it
|
|
5709
|
+
if (wrapperRef.current && !wrapperRef.current.contains(e.target) && tooltipRef.current && !tooltipRef.current.contains(e.target)) {
|
|
5710
|
+
hide(false);
|
|
5711
|
+
}
|
|
5712
|
+
};
|
|
5713
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
5714
|
+
return () => {
|
|
5715
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
5716
|
+
};
|
|
5717
|
+
}, [visible, hide]);
|
|
5718
|
+
hooks.useLayoutEffect(() => {
|
|
5719
|
+
if (!visible || position) {
|
|
5720
|
+
setTooltipPosition(null);
|
|
5721
|
+
setArrowOffset(null);
|
|
5722
|
+
return;
|
|
5723
|
+
}
|
|
5724
|
+
if (!wrapperRef.current || !tooltipRef.current) return;
|
|
5725
|
+
const {
|
|
5726
|
+
tooltipPosition: newPosition,
|
|
5727
|
+
arrowOffset: newArrowOffset
|
|
5728
|
+
} = getTooltipPosition(wrapperRef.current, tooltipRef.current, direction);
|
|
5729
|
+
setTooltipPosition(newPosition);
|
|
5730
|
+
setArrowOffset(newArrowOffset);
|
|
5731
|
+
}, [visible, position]);
|
|
5640
5732
|
const handleMouseLeave = ({
|
|
5641
5733
|
relatedTarget
|
|
5642
5734
|
}) => {
|
|
@@ -5644,39 +5736,52 @@ function Tooltip(props) {
|
|
|
5644
5736
|
if (relatedTarget === wrapperRef.current || relatedTarget === tooltipRef.current || relatedTarget?.parentElement === tooltipRef.current) {
|
|
5645
5737
|
return;
|
|
5646
5738
|
}
|
|
5647
|
-
|
|
5739
|
+
const selection = window.getSelection();
|
|
5740
|
+
if (selection && selection.toString().length > 0) {
|
|
5741
|
+
// Check if selection is within tooltip content
|
|
5742
|
+
const selectionRange = selection.getRangeAt(0);
|
|
5743
|
+
if (tooltipRef.current?.contains(selectionRange.commonAncestorContainer) || tooltipRef.current?.contains(selection.anchorNode) || tooltipRef.current?.contains(selection.focusNode)) {
|
|
5744
|
+
return; // Keep tooltip open during text selection
|
|
5745
|
+
}
|
|
5746
|
+
}
|
|
5747
|
+
hide(true);
|
|
5748
|
+
};
|
|
5749
|
+
const handleTooltipMouseEnter = () => {
|
|
5750
|
+
clearTimeout(hideTimeoutRef.current);
|
|
5648
5751
|
};
|
|
5649
5752
|
const handleFocusOut = e => {
|
|
5650
5753
|
const {
|
|
5651
|
-
|
|
5754
|
+
relatedTarget
|
|
5652
5755
|
} = e;
|
|
5653
5756
|
|
|
5654
|
-
// Don't hide
|
|
5655
|
-
|
|
5656
|
-
if (target === wrapperRef.current && isHovered) {
|
|
5657
|
-
e.stopPropagation();
|
|
5757
|
+
// Don't hide if focus moved to the tooltip or another element within the wrapper
|
|
5758
|
+
if (tooltipRef.current?.contains(relatedTarget) || wrapperRef.current?.contains(relatedTarget)) {
|
|
5658
5759
|
return;
|
|
5659
5760
|
}
|
|
5660
|
-
hide();
|
|
5761
|
+
hide(false);
|
|
5661
5762
|
};
|
|
5662
5763
|
const hideTooltipViaEscape = e => {
|
|
5663
|
-
e.code === 'Escape' && hide();
|
|
5764
|
+
e.code === 'Escape' && hide(false);
|
|
5664
5765
|
};
|
|
5665
5766
|
const renderTooltip = () => {
|
|
5767
|
+
const tooltipStyle = position || (tooltipPosition ? `right: ${tooltipPosition.right}; top: ${tooltipPosition.top}px;` : undefined);
|
|
5768
|
+
const arrowStyle = arrowOffset != null ? `margin-top: ${arrowOffset}px;` : undefined;
|
|
5666
5769
|
return jsxRuntime.jsxs("div", {
|
|
5667
5770
|
class: `bio-properties-panel-tooltip ${direction}`,
|
|
5668
5771
|
role: "tooltip",
|
|
5669
5772
|
id: "bio-properties-panel-tooltip",
|
|
5670
5773
|
"aria-labelledby": forId,
|
|
5671
|
-
style:
|
|
5774
|
+
style: tooltipStyle,
|
|
5672
5775
|
ref: tooltipRef,
|
|
5673
5776
|
onClick: e => e.stopPropagation(),
|
|
5777
|
+
onMouseEnter: handleTooltipMouseEnter,
|
|
5674
5778
|
onMouseLeave: handleMouseLeave,
|
|
5675
5779
|
children: [jsxRuntime.jsx("div", {
|
|
5676
5780
|
class: "bio-properties-panel-tooltip-content",
|
|
5677
5781
|
children: value
|
|
5678
5782
|
}), jsxRuntime.jsx("div", {
|
|
5679
|
-
class: "bio-properties-panel-tooltip-arrow"
|
|
5783
|
+
class: "bio-properties-panel-tooltip-arrow",
|
|
5784
|
+
style: arrowStyle
|
|
5680
5785
|
})]
|
|
5681
5786
|
});
|
|
5682
5787
|
};
|
|
@@ -5684,7 +5789,7 @@ function Tooltip(props) {
|
|
|
5684
5789
|
class: "bio-properties-panel-tooltip-wrapper",
|
|
5685
5790
|
tabIndex: "0",
|
|
5686
5791
|
ref: wrapperRef,
|
|
5687
|
-
onMouseEnter:
|
|
5792
|
+
onMouseEnter: handleWrapperMouseEnter,
|
|
5688
5793
|
onMouseLeave: handleMouseLeave,
|
|
5689
5794
|
onFocus: show,
|
|
5690
5795
|
onBlur: handleFocusOut,
|
|
@@ -5695,11 +5800,47 @@ function Tooltip(props) {
|
|
|
5695
5800
|
|
|
5696
5801
|
// helper
|
|
5697
5802
|
|
|
5698
|
-
function getTooltipPosition(refElement) {
|
|
5803
|
+
function getTooltipPosition(refElement, tooltipElement, direction) {
|
|
5804
|
+
if (!refElement) {
|
|
5805
|
+
return {
|
|
5806
|
+
tooltipPosition: null,
|
|
5807
|
+
arrowOffset: null
|
|
5808
|
+
};
|
|
5809
|
+
}
|
|
5699
5810
|
const refPosition = refElement.getBoundingClientRect();
|
|
5700
5811
|
const right = `calc(100% - ${refPosition.x}px)`;
|
|
5701
|
-
|
|
5702
|
-
|
|
5812
|
+
let top = refPosition.top - 10;
|
|
5813
|
+
let arrowOffset = null;
|
|
5814
|
+
|
|
5815
|
+
// Ensure that the tooltip is within the viewport, adjust the top position if needed.
|
|
5816
|
+
// This is only relevant for the 'right' direction for now
|
|
5817
|
+
if (tooltipElement && direction === 'right') {
|
|
5818
|
+
const tooltipRect = tooltipElement.getBoundingClientRect();
|
|
5819
|
+
const viewportHeight = window.innerHeight;
|
|
5820
|
+
const minTop = 0;
|
|
5821
|
+
const maxTop = viewportHeight - tooltipRect.height;
|
|
5822
|
+
const originalTop = top;
|
|
5823
|
+
if (top > maxTop) {
|
|
5824
|
+
top = maxTop;
|
|
5825
|
+
}
|
|
5826
|
+
if (top < minTop) {
|
|
5827
|
+
top = minTop;
|
|
5828
|
+
}
|
|
5829
|
+
|
|
5830
|
+
// Adjust the arrow position if the tooltip had to be moved to stay within viewport
|
|
5831
|
+
if (top !== originalTop) {
|
|
5832
|
+
const defaultMarginTop = 16;
|
|
5833
|
+
const topDiff = top - originalTop;
|
|
5834
|
+
arrowOffset = defaultMarginTop - topDiff;
|
|
5835
|
+
}
|
|
5836
|
+
}
|
|
5837
|
+
return {
|
|
5838
|
+
tooltipPosition: {
|
|
5839
|
+
right,
|
|
5840
|
+
top
|
|
5841
|
+
},
|
|
5842
|
+
arrowOffset
|
|
5843
|
+
};
|
|
5703
5844
|
}
|
|
5704
5845
|
|
|
5705
5846
|
/**
|
|
@@ -5937,12 +6078,17 @@ function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky)
|
|
|
5937
6078
|
* The `callback` reference is static and can be safely used in external
|
|
5938
6079
|
* libraries or as a prop that does not cause rerendering of children.
|
|
5939
6080
|
*
|
|
6081
|
+
* The ref update is deferred to useLayoutEffect to prevent stale-closure
|
|
6082
|
+
* bugs when Chrome fires blur on elements removed during re-render.
|
|
6083
|
+
*
|
|
5940
6084
|
* @param {Function} callback function with changing reference
|
|
5941
6085
|
* @returns {Function} static function reference
|
|
5942
6086
|
*/
|
|
5943
6087
|
function useStaticCallback(callback) {
|
|
5944
6088
|
const callbackRef = hooks.useRef(callback);
|
|
5945
|
-
|
|
6089
|
+
hooks.useLayoutEffect(() => {
|
|
6090
|
+
callbackRef.current = callback;
|
|
6091
|
+
});
|
|
5946
6092
|
return hooks.useCallback((...args) => callbackRef.current(...args), []);
|
|
5947
6093
|
}
|
|
5948
6094
|
function useElementVisible(element) {
|
|
@@ -5962,6 +6108,10 @@ function useElementVisible(element) {
|
|
|
5962
6108
|
}, [element, visible]);
|
|
5963
6109
|
return visible;
|
|
5964
6110
|
}
|
|
6111
|
+
|
|
6112
|
+
/**
|
|
6113
|
+
* @param {import('../PropertiesPanel').GroupDefinition} props
|
|
6114
|
+
*/
|
|
5965
6115
|
function Group(props) {
|
|
5966
6116
|
const {
|
|
5967
6117
|
element,
|
|
@@ -6016,8 +6166,6 @@ function Group(props) {
|
|
|
6016
6166
|
class: classnames('bio-properties-panel-group-header', edited ? '' : 'empty', open ? 'open' : '', sticky && open ? 'sticky' : ''),
|
|
6017
6167
|
onClick: toggleOpen,
|
|
6018
6168
|
children: [jsxRuntime.jsx("div", {
|
|
6019
|
-
title: props.tooltip ? null : label,
|
|
6020
|
-
"data-title": label,
|
|
6021
6169
|
class: "bio-properties-panel-group-header-title",
|
|
6022
6170
|
children: jsxRuntime.jsx(TooltipWrapper, {
|
|
6023
6171
|
value: props.tooltip,
|
|
@@ -6221,9 +6369,11 @@ function PropertiesPanel$1(props) {
|
|
|
6221
6369
|
return minDash.get(layout, key, defaultValue);
|
|
6222
6370
|
};
|
|
6223
6371
|
const setLayoutForKey = (key, config) => {
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6372
|
+
setLayout(prevLayout => {
|
|
6373
|
+
const newLayout = minDash.assign({}, prevLayout);
|
|
6374
|
+
minDash.set(newLayout, key, config);
|
|
6375
|
+
return newLayout;
|
|
6376
|
+
});
|
|
6227
6377
|
};
|
|
6228
6378
|
const layoutContext = {
|
|
6229
6379
|
layout,
|
|
@@ -6422,7 +6572,6 @@ function CollapsibleEntry(props) {
|
|
|
6422
6572
|
class: "bio-properties-panel-collapsible-entry-header",
|
|
6423
6573
|
onClick: toggleOpen,
|
|
6424
6574
|
children: [jsxRuntime.jsx("div", {
|
|
6425
|
-
title: label || placeholderLabel,
|
|
6426
6575
|
class: classnames('bio-properties-panel-collapsible-entry-header-title', !label && 'empty'),
|
|
6427
6576
|
children: label || placeholderLabel
|
|
6428
6577
|
}), jsxRuntime.jsx("button", {
|
|
@@ -6458,6 +6607,10 @@ function CollapsibleEntry(props) {
|
|
|
6458
6607
|
})]
|
|
6459
6608
|
});
|
|
6460
6609
|
}
|
|
6610
|
+
|
|
6611
|
+
/**
|
|
6612
|
+
* @param {import('../PropertiesPanel').ListItemDefinition} props
|
|
6613
|
+
*/
|
|
6461
6614
|
function ListItem(props) {
|
|
6462
6615
|
const {
|
|
6463
6616
|
autoFocusEntry,
|
|
@@ -6559,8 +6712,6 @@ function ListGroup(props) {
|
|
|
6559
6712
|
class: classnames('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : '', sticky && open ? 'sticky' : ''),
|
|
6560
6713
|
onClick: hasItems ? toggleOpen : noop$6,
|
|
6561
6714
|
children: [jsxRuntime.jsx("div", {
|
|
6562
|
-
title: props.tooltip ? null : label,
|
|
6563
|
-
"data-title": label,
|
|
6564
6715
|
class: "bio-properties-panel-group-header-title",
|
|
6565
6716
|
children: jsxRuntime.jsx(TooltipWrapper, {
|
|
6566
6717
|
value: props.tooltip,
|
|
@@ -6629,6 +6780,13 @@ function getNewItemIds(newItems, oldItems) {
|
|
|
6629
6780
|
const oldIds = oldItems.map(item => item.id);
|
|
6630
6781
|
return newIds.filter(itemId => !oldIds.includes(itemId));
|
|
6631
6782
|
}
|
|
6783
|
+
|
|
6784
|
+
/**
|
|
6785
|
+
* @param {Object} props
|
|
6786
|
+
* @param {Object} props.element
|
|
6787
|
+
* @param {String} props.forId - id of the entry the description is used for
|
|
6788
|
+
* @param {String} props.value
|
|
6789
|
+
*/
|
|
6632
6790
|
function Description$1(props) {
|
|
6633
6791
|
const {
|
|
6634
6792
|
element,
|
|
@@ -6758,6 +6916,16 @@ function isEdited$8(node) {
|
|
|
6758
6916
|
function prefixId$8(id) {
|
|
6759
6917
|
return `bio-properties-panel-${id}`;
|
|
6760
6918
|
}
|
|
6919
|
+
|
|
6920
|
+
/**
|
|
6921
|
+
* Button to open popups.
|
|
6922
|
+
*
|
|
6923
|
+
* @param {Object} props
|
|
6924
|
+
* @param {Function} props.onClick - Callback to trigger when the button is clicked.
|
|
6925
|
+
* @param {string} [props.title] - Tooltip text for the button.
|
|
6926
|
+
* @param {boolean} [props.disabled] - Whether the button is disabled.
|
|
6927
|
+
* @param {string} [props.className] - Additional class names for the button.
|
|
6928
|
+
*/
|
|
6761
6929
|
function OpenPopupButton({
|
|
6762
6930
|
onClick,
|
|
6763
6931
|
title = 'Open pop-up editor'
|
|
@@ -6901,6 +7069,7 @@ const FeelEditor = React.forwardRef((props, ref) => {
|
|
|
6901
7069
|
enableGutters,
|
|
6902
7070
|
value,
|
|
6903
7071
|
onInput,
|
|
7072
|
+
onKeyDown: onKeyDownProp = noop$4,
|
|
6904
7073
|
onFeelToggle = noop$4,
|
|
6905
7074
|
onLint = noop$4,
|
|
6906
7075
|
onOpenPopup = noop$4,
|
|
@@ -6933,6 +7102,8 @@ const FeelEditor = React.forwardRef((props, ref) => {
|
|
|
6933
7102
|
* - AND the cursor is at the beginning of the input
|
|
6934
7103
|
*/
|
|
6935
7104
|
const onKeyDown = e => {
|
|
7105
|
+
// Call parent onKeyDown handler first
|
|
7106
|
+
onKeyDownProp(e);
|
|
6936
7107
|
if (e.key !== 'Backspace' || !editor) {
|
|
6937
7108
|
return;
|
|
6938
7109
|
}
|
|
@@ -7049,6 +7220,22 @@ function FeelIcon(props) {
|
|
|
7049
7220
|
children: jsxRuntime.jsx(FeelIcon$1, {})
|
|
7050
7221
|
});
|
|
7051
7222
|
}
|
|
7223
|
+
|
|
7224
|
+
/**
|
|
7225
|
+
* @param {KeyboardEvent} event
|
|
7226
|
+
* @return {boolean}
|
|
7227
|
+
*/
|
|
7228
|
+
function isCmd(event) {
|
|
7229
|
+
// ensure we don't react to AltGr
|
|
7230
|
+
// (mapped to CTRL + ALT)
|
|
7231
|
+
if (event.altKey) {
|
|
7232
|
+
return false;
|
|
7233
|
+
}
|
|
7234
|
+
return event.ctrlKey || event.metaKey;
|
|
7235
|
+
}
|
|
7236
|
+
function isCmdWithChar(event) {
|
|
7237
|
+
return isCmd(event) && event.key.length === 1 && /^[a-zA-Z]$/.test(event.key);
|
|
7238
|
+
}
|
|
7052
7239
|
function ToggleSwitch(props) {
|
|
7053
7240
|
const {
|
|
7054
7241
|
id,
|
|
@@ -7157,7 +7344,7 @@ function ToggleSwitchEntry(props) {
|
|
|
7157
7344
|
inline: inline,
|
|
7158
7345
|
tooltip: tooltip,
|
|
7159
7346
|
element: element
|
|
7160
|
-
}), jsxRuntime.jsx(Description$1, {
|
|
7347
|
+
}, element), jsxRuntime.jsx(Description$1, {
|
|
7161
7348
|
forId: id,
|
|
7162
7349
|
element: element,
|
|
7163
7350
|
value: description
|
|
@@ -7330,7 +7517,7 @@ function prefixId$6(id) {
|
|
|
7330
7517
|
const noop$2 = () => {};
|
|
7331
7518
|
|
|
7332
7519
|
/**
|
|
7333
|
-
* @typedef {'required'|'optional'|'static'} FeelType
|
|
7520
|
+
* @typedef {'required'|'optional'|'optional-default-enabled'|'static'} FeelType
|
|
7334
7521
|
*/
|
|
7335
7522
|
|
|
7336
7523
|
/**
|
|
@@ -7360,7 +7547,7 @@ function FeelTextfield(props) {
|
|
|
7360
7547
|
element,
|
|
7361
7548
|
label,
|
|
7362
7549
|
hostLanguage,
|
|
7363
|
-
onInput,
|
|
7550
|
+
onInput: commitValue,
|
|
7364
7551
|
onBlur,
|
|
7365
7552
|
onError,
|
|
7366
7553
|
placeholder,
|
|
@@ -7373,11 +7560,17 @@ function FeelTextfield(props) {
|
|
|
7373
7560
|
OptionalComponent = OptionalFeelInput,
|
|
7374
7561
|
tooltip
|
|
7375
7562
|
} = props;
|
|
7376
|
-
const [localValue, setLocalValue] = hooks.useState(value);
|
|
7563
|
+
const [localValue, setLocalValue] = hooks.useState(getInitialFeelLocalValue(feel, value));
|
|
7377
7564
|
const editorRef = useShowEntryEvent(id);
|
|
7378
7565
|
const containerRef = hooks.useRef();
|
|
7379
|
-
const
|
|
7380
|
-
|
|
7566
|
+
const onInput = hooks.useCallback(newValue => {
|
|
7567
|
+
// we don't commit empty FEEL expressions,
|
|
7568
|
+
// but instead serialize them as <undefined>
|
|
7569
|
+
const newModelValue = newValue === '' || newValue === '=' ? undefined : newValue;
|
|
7570
|
+
commitValue(newModelValue);
|
|
7571
|
+
}, [commitValue]);
|
|
7572
|
+
const feelActive = isFeelActive(feel, localValue);
|
|
7573
|
+
const feelOnlyValue = getFeelValue(localValue);
|
|
7381
7574
|
const feelLanguageContext = hooks.useContext(FeelLanguageContext);
|
|
7382
7575
|
const [focus, _setFocus] = hooks.useState(undefined);
|
|
7383
7576
|
const {
|
|
@@ -7395,13 +7588,7 @@ function FeelTextfield(props) {
|
|
|
7395
7588
|
/**
|
|
7396
7589
|
* @type { import('min-dash').DebouncedFunction }
|
|
7397
7590
|
*/
|
|
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
|
-
};
|
|
7591
|
+
const handleInput = useDebounce(onInput, debounce);
|
|
7405
7592
|
const handleFeelToggle = useStaticCallback(() => {
|
|
7406
7593
|
if (feel === 'required') {
|
|
7407
7594
|
return;
|
|
@@ -7414,7 +7601,7 @@ function FeelTextfield(props) {
|
|
|
7414
7601
|
handleInput(feelOnlyValue);
|
|
7415
7602
|
}
|
|
7416
7603
|
});
|
|
7417
|
-
const handleLocalInput = newValue => {
|
|
7604
|
+
const handleLocalInput = (newValue, useDebounce = true) => {
|
|
7418
7605
|
if (feelActive) {
|
|
7419
7606
|
newValue = '=' + newValue;
|
|
7420
7607
|
}
|
|
@@ -7422,23 +7609,33 @@ function FeelTextfield(props) {
|
|
|
7422
7609
|
return;
|
|
7423
7610
|
}
|
|
7424
7611
|
setLocalValue(newValue);
|
|
7425
|
-
|
|
7612
|
+
if (useDebounce) {
|
|
7613
|
+
handleInput(newValue);
|
|
7614
|
+
} else {
|
|
7615
|
+
onInput(newValue);
|
|
7616
|
+
}
|
|
7426
7617
|
if (!feelActive && minDash.isString(newValue) && newValue.startsWith('=')) {
|
|
7427
7618
|
// focus is behind `=` sign that will be removed
|
|
7428
7619
|
setFocus(-1);
|
|
7429
7620
|
}
|
|
7430
7621
|
};
|
|
7431
7622
|
const handleOnBlur = e => {
|
|
7623
|
+
handleInput.cancel?.();
|
|
7432
7624
|
if (e.target.type === 'checkbox') {
|
|
7433
7625
|
onInput(e.target.checked);
|
|
7434
7626
|
} else {
|
|
7435
7627
|
const trimmedValue = e.target.value.trim();
|
|
7436
|
-
|
|
7628
|
+
handleLocalInput(trimmedValue, false);
|
|
7437
7629
|
}
|
|
7438
7630
|
if (onBlur) {
|
|
7439
7631
|
onBlur(e);
|
|
7440
7632
|
}
|
|
7441
7633
|
};
|
|
7634
|
+
const handleOnKeyDown = e => {
|
|
7635
|
+
if (isCmdWithChar(e)) {
|
|
7636
|
+
handleInput.flush?.();
|
|
7637
|
+
}
|
|
7638
|
+
};
|
|
7442
7639
|
const handleLint = useStaticCallback((lint = []) => {
|
|
7443
7640
|
const syntaxError = lint.some(report => report.type === 'Syntax Error');
|
|
7444
7641
|
if (syntaxError) {
|
|
@@ -7505,12 +7702,26 @@ function FeelTextfield(props) {
|
|
|
7505
7702
|
if (feelActive || isPopupOpen) {
|
|
7506
7703
|
return;
|
|
7507
7704
|
}
|
|
7508
|
-
const
|
|
7509
|
-
if (
|
|
7705
|
+
const feelData = event.clipboardData.getData('application/FEEL');
|
|
7706
|
+
if (feelData) {
|
|
7510
7707
|
setTimeout(() => {
|
|
7511
7708
|
handleFeelToggle();
|
|
7512
7709
|
setFocus();
|
|
7513
7710
|
});
|
|
7711
|
+
return;
|
|
7712
|
+
}
|
|
7713
|
+
const input = event.target;
|
|
7714
|
+
const isFieldEmpty = !input.value;
|
|
7715
|
+
const isAllSelected = input.selectionStart === 0 && input.selectionEnd === input.value.length;
|
|
7716
|
+
if (isFieldEmpty || isAllSelected) {
|
|
7717
|
+
const textData = event.clipboardData.getData('text');
|
|
7718
|
+
const trimmedValue = textData.trim();
|
|
7719
|
+
setLocalValue(trimmedValue);
|
|
7720
|
+
handleInput(trimmedValue);
|
|
7721
|
+
if (!feelActive && minDash.isString(trimmedValue) && trimmedValue.startsWith('=')) {
|
|
7722
|
+
setFocus(trimmedValue.length - 1);
|
|
7723
|
+
}
|
|
7724
|
+
event.preventDefault();
|
|
7514
7725
|
}
|
|
7515
7726
|
};
|
|
7516
7727
|
containerRef.current.addEventListener('copy', copyHandler);
|
|
@@ -7546,11 +7757,12 @@ function FeelTextfield(props) {
|
|
|
7546
7757
|
ref: containerRef,
|
|
7547
7758
|
children: [jsxRuntime.jsx(FeelIndicator, {
|
|
7548
7759
|
active: feelActive,
|
|
7549
|
-
disabled: feel
|
|
7760
|
+
disabled: !isFeelOptional(feel) || disabled,
|
|
7550
7761
|
onClick: handleFeelToggle
|
|
7551
7762
|
}), feelActive ? jsxRuntime.jsx(FeelEditor, {
|
|
7552
7763
|
name: id,
|
|
7553
7764
|
onInput: handleLocalInput,
|
|
7765
|
+
onKeyDown: handleOnKeyDown,
|
|
7554
7766
|
contentAttributes: {
|
|
7555
7767
|
'id': prefixId$5(id),
|
|
7556
7768
|
'aria-label': label
|
|
@@ -7573,6 +7785,7 @@ function FeelTextfield(props) {
|
|
|
7573
7785
|
...props,
|
|
7574
7786
|
popupOpen: isPopupOpen,
|
|
7575
7787
|
onInput: handleLocalInput,
|
|
7788
|
+
onKeyDown: handleOnKeyDown,
|
|
7576
7789
|
onBlur: handleOnBlur,
|
|
7577
7790
|
contentAttributes: {
|
|
7578
7791
|
'id': prefixId$5(id),
|
|
@@ -7591,6 +7804,7 @@ const OptionalFeelInput = React.forwardRef((props, ref) => {
|
|
|
7591
7804
|
id,
|
|
7592
7805
|
disabled,
|
|
7593
7806
|
onInput,
|
|
7807
|
+
onKeyDown,
|
|
7594
7808
|
value,
|
|
7595
7809
|
onFocus,
|
|
7596
7810
|
onBlur,
|
|
@@ -7626,6 +7840,7 @@ const OptionalFeelInput = React.forwardRef((props, ref) => {
|
|
|
7626
7840
|
class: "bio-properties-panel-input",
|
|
7627
7841
|
onInput: e => onInput(e.target.value),
|
|
7628
7842
|
onFocus: onFocus,
|
|
7843
|
+
onKeyDown: onKeyDown,
|
|
7629
7844
|
onBlur: onBlur,
|
|
7630
7845
|
placeholder: placeholder,
|
|
7631
7846
|
value: value || ''
|
|
@@ -7999,6 +8214,87 @@ function isEdited$5(node) {
|
|
|
7999
8214
|
function prefixId$5(id) {
|
|
8000
8215
|
return `bio-properties-panel-${id}`;
|
|
8001
8216
|
}
|
|
8217
|
+
|
|
8218
|
+
/**
|
|
8219
|
+
* Determine if FEEL is optional for the configured {@link FeelType}.
|
|
8220
|
+
*
|
|
8221
|
+
* @param {FeelType} feelType
|
|
8222
|
+
*
|
|
8223
|
+
* @return {boolean}
|
|
8224
|
+
*/
|
|
8225
|
+
function isFeelOptional(feelType) {
|
|
8226
|
+
return feelType === 'optional' || feelType === 'optional-default-enabled';
|
|
8227
|
+
}
|
|
8228
|
+
|
|
8229
|
+
/**
|
|
8230
|
+
* Determine if FEEL editing is currently active.
|
|
8231
|
+
*
|
|
8232
|
+
* @param {FeelType} feelType
|
|
8233
|
+
* @param {string} localValue
|
|
8234
|
+
*
|
|
8235
|
+
* @return {boolean}
|
|
8236
|
+
*/
|
|
8237
|
+
function isFeelActive(feelType, localValue) {
|
|
8238
|
+
if (feelType === 'required') {
|
|
8239
|
+
return true;
|
|
8240
|
+
}
|
|
8241
|
+
if (minDash.isString(localValue)) {
|
|
8242
|
+
if (localValue.startsWith('=')) {
|
|
8243
|
+
return true;
|
|
8244
|
+
}
|
|
8245
|
+
}
|
|
8246
|
+
return false;
|
|
8247
|
+
}
|
|
8248
|
+
|
|
8249
|
+
/**
|
|
8250
|
+
* @template T
|
|
8251
|
+
* @param {T} value
|
|
8252
|
+
*
|
|
8253
|
+
* @return {string|T}
|
|
8254
|
+
*/
|
|
8255
|
+
function getFeelValue(value) {
|
|
8256
|
+
if (minDash.isString(value) && value.startsWith('=')) {
|
|
8257
|
+
return value.substring(1);
|
|
8258
|
+
}
|
|
8259
|
+
return value;
|
|
8260
|
+
}
|
|
8261
|
+
|
|
8262
|
+
/**
|
|
8263
|
+
* Initialize local FEEL value.
|
|
8264
|
+
*
|
|
8265
|
+
* `optional-default-enabled` starts in FEEL mode if no value or empty string is provided.
|
|
8266
|
+
*
|
|
8267
|
+
* @template T
|
|
8268
|
+
* @param {FeelType} feelType
|
|
8269
|
+
* @param {T} value
|
|
8270
|
+
*
|
|
8271
|
+
* @return {string|T}
|
|
8272
|
+
*/
|
|
8273
|
+
function getInitialFeelLocalValue(feelType, value) {
|
|
8274
|
+
if (feelType === 'optional-default-enabled' && (value === undefined || value === '')) {
|
|
8275
|
+
return '=';
|
|
8276
|
+
}
|
|
8277
|
+
return value;
|
|
8278
|
+
}
|
|
8279
|
+
|
|
8280
|
+
/**
|
|
8281
|
+
* @typedef { { value: string, label: string, disabled: boolean, children: { value: string, label: string, disabled: boolean } } } Option
|
|
8282
|
+
*/
|
|
8283
|
+
|
|
8284
|
+
/**
|
|
8285
|
+
* Provides basic select input.
|
|
8286
|
+
*
|
|
8287
|
+
* @param {object} props
|
|
8288
|
+
* @param {string} props.id
|
|
8289
|
+
* @param {string[]} props.path
|
|
8290
|
+
* @param {string} props.label
|
|
8291
|
+
* @param {Function} props.onChange
|
|
8292
|
+
* @param {Function} props.onFocus
|
|
8293
|
+
* @param {Function} props.onBlur
|
|
8294
|
+
* @param {Array<Option>} [props.options]
|
|
8295
|
+
* @param {string} props.value
|
|
8296
|
+
* @param {boolean} [props.disabled]
|
|
8297
|
+
*/
|
|
8002
8298
|
function Select(props) {
|
|
8003
8299
|
const {
|
|
8004
8300
|
id,
|
|
@@ -8164,12 +8460,13 @@ function TextArea(props) {
|
|
|
8164
8460
|
id,
|
|
8165
8461
|
label,
|
|
8166
8462
|
debounce,
|
|
8167
|
-
onInput,
|
|
8463
|
+
onInput: commitValue,
|
|
8168
8464
|
value = '',
|
|
8169
8465
|
disabled,
|
|
8170
8466
|
monospace,
|
|
8171
8467
|
onFocus,
|
|
8172
8468
|
onBlur,
|
|
8469
|
+
onPaste,
|
|
8173
8470
|
autoResize = true,
|
|
8174
8471
|
placeholder,
|
|
8175
8472
|
rows = autoResize ? 1 : 2,
|
|
@@ -8177,16 +8474,16 @@ function TextArea(props) {
|
|
|
8177
8474
|
} = props;
|
|
8178
8475
|
const [localValue, setLocalValue] = hooks.useState(value);
|
|
8179
8476
|
const ref = useShowEntryEvent(id);
|
|
8477
|
+
const onInput = hooks.useCallback(newValue => {
|
|
8478
|
+
const newModelValue = newValue === '' ? undefined : newValue;
|
|
8479
|
+
commitValue(newModelValue);
|
|
8480
|
+
}, [commitValue]);
|
|
8180
8481
|
const visible = useElementVisible(ref.current);
|
|
8181
8482
|
|
|
8182
8483
|
/**
|
|
8183
8484
|
* @type { import('min-dash').DebouncedFunction }
|
|
8184
8485
|
*/
|
|
8185
|
-
const
|
|
8186
|
-
const handleInput = newValue => {
|
|
8187
|
-
const newModelValue = newValue === '' ? undefined : newValue;
|
|
8188
|
-
handleInputCallback(newModelValue);
|
|
8189
|
-
};
|
|
8486
|
+
const handleInput = useDebounce(onInput, debounce);
|
|
8190
8487
|
const handleLocalInput = e => {
|
|
8191
8488
|
autoResize && resizeToContents(e.target);
|
|
8192
8489
|
if (e.target.value === localValue) {
|
|
@@ -8199,11 +8496,40 @@ function TextArea(props) {
|
|
|
8199
8496
|
const trimmedValue = e.target.value.trim();
|
|
8200
8497
|
|
|
8201
8498
|
// trim and commit on blur
|
|
8499
|
+
handleInput.cancel?.();
|
|
8202
8500
|
onInput(trimmedValue);
|
|
8501
|
+
setLocalValue(trimmedValue);
|
|
8203
8502
|
if (onBlur) {
|
|
8204
8503
|
onBlur(e);
|
|
8205
8504
|
}
|
|
8206
8505
|
};
|
|
8506
|
+
const handleOnPaste = e => {
|
|
8507
|
+
const input = e.target;
|
|
8508
|
+
const isFieldEmpty = !input.value;
|
|
8509
|
+
const isAllSelected = input.selectionStart === 0 && input.selectionEnd === input.value.length;
|
|
8510
|
+
|
|
8511
|
+
// Trim and handle paste if field is empty or all content is selected
|
|
8512
|
+
if (isFieldEmpty || isAllSelected) {
|
|
8513
|
+
const trimmedValue = e.clipboardData.getData('text').trim();
|
|
8514
|
+
setLocalValue(trimmedValue);
|
|
8515
|
+
handleInput(trimmedValue);
|
|
8516
|
+
if (onPaste) {
|
|
8517
|
+
onPaste(e);
|
|
8518
|
+
}
|
|
8519
|
+
e.preventDefault();
|
|
8520
|
+
return;
|
|
8521
|
+
}
|
|
8522
|
+
|
|
8523
|
+
// Allow default paste behavior for normal text editing
|
|
8524
|
+
if (onPaste) {
|
|
8525
|
+
onPaste(e);
|
|
8526
|
+
}
|
|
8527
|
+
};
|
|
8528
|
+
const handleOnKeyDown = e => {
|
|
8529
|
+
if (isCmdWithChar(e)) {
|
|
8530
|
+
handleInput.flush?.();
|
|
8531
|
+
}
|
|
8532
|
+
};
|
|
8207
8533
|
hooks.useLayoutEffect(() => {
|
|
8208
8534
|
autoResize && resizeToContents(ref.current);
|
|
8209
8535
|
}, []);
|
|
@@ -8235,7 +8561,9 @@ function TextArea(props) {
|
|
|
8235
8561
|
class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : '', autoResize ? 'auto-resize' : ''),
|
|
8236
8562
|
onInput: handleLocalInput,
|
|
8237
8563
|
onFocus: onFocus,
|
|
8564
|
+
onKeyDown: handleOnKeyDown,
|
|
8238
8565
|
onBlur: handleOnBlur,
|
|
8566
|
+
onPaste: handleOnPaste,
|
|
8239
8567
|
placeholder: placeholder,
|
|
8240
8568
|
rows: rows,
|
|
8241
8569
|
value: localValue,
|
|
@@ -8256,6 +8584,7 @@ function TextArea(props) {
|
|
|
8256
8584
|
* @param {Function} props.setValue
|
|
8257
8585
|
* @param {Function} props.onFocus
|
|
8258
8586
|
* @param {Function} props.onBlur
|
|
8587
|
+
* @param {Function} props.onPaste
|
|
8259
8588
|
* @param {number} props.rows
|
|
8260
8589
|
* @param {boolean} props.monospace
|
|
8261
8590
|
* @param {Function} [props.validate]
|
|
@@ -8276,6 +8605,7 @@ function TextAreaEntry(props) {
|
|
|
8276
8605
|
validate,
|
|
8277
8606
|
onFocus,
|
|
8278
8607
|
onBlur,
|
|
8608
|
+
onPaste,
|
|
8279
8609
|
placeholder,
|
|
8280
8610
|
autoResize,
|
|
8281
8611
|
tooltip
|
|
@@ -8311,6 +8641,7 @@ function TextAreaEntry(props) {
|
|
|
8311
8641
|
onInput: onInput,
|
|
8312
8642
|
onFocus: onFocus,
|
|
8313
8643
|
onBlur: onBlur,
|
|
8644
|
+
onPaste: onPaste,
|
|
8314
8645
|
rows: rows,
|
|
8315
8646
|
debounce: debounce,
|
|
8316
8647
|
monospace: monospace,
|
|
@@ -8344,32 +8675,57 @@ function Textfield(props) {
|
|
|
8344
8675
|
disabled = false,
|
|
8345
8676
|
id,
|
|
8346
8677
|
label,
|
|
8347
|
-
onInput,
|
|
8678
|
+
onInput: commitValue,
|
|
8348
8679
|
onFocus,
|
|
8349
8680
|
onBlur,
|
|
8681
|
+
onPaste,
|
|
8350
8682
|
placeholder,
|
|
8351
8683
|
value = '',
|
|
8352
8684
|
tooltip
|
|
8353
8685
|
} = props;
|
|
8354
8686
|
const [localValue, setLocalValue] = hooks.useState(value || '');
|
|
8355
8687
|
const ref = useShowEntryEvent(id);
|
|
8688
|
+
const onInput = hooks.useCallback(newValue => {
|
|
8689
|
+
const newModelValue = newValue === '' ? undefined : newValue;
|
|
8690
|
+
commitValue(newModelValue);
|
|
8691
|
+
}, [commitValue]);
|
|
8356
8692
|
|
|
8357
8693
|
/**
|
|
8358
8694
|
* @type { import('min-dash').DebouncedFunction }
|
|
8359
8695
|
*/
|
|
8360
|
-
const
|
|
8696
|
+
const handleInput = useDebounce(onInput, debounce);
|
|
8361
8697
|
const handleOnBlur = e => {
|
|
8362
8698
|
const trimmedValue = e.target.value.trim();
|
|
8363
8699
|
|
|
8364
8700
|
// trim and commit on blur
|
|
8701
|
+
handleInput.cancel?.();
|
|
8365
8702
|
onInput(trimmedValue);
|
|
8703
|
+
setLocalValue(trimmedValue);
|
|
8366
8704
|
if (onBlur) {
|
|
8367
8705
|
onBlur(e);
|
|
8368
8706
|
}
|
|
8369
8707
|
};
|
|
8370
|
-
const
|
|
8371
|
-
const
|
|
8372
|
-
|
|
8708
|
+
const handleOnPaste = e => {
|
|
8709
|
+
const input = e.target;
|
|
8710
|
+
const isFieldEmpty = !input.value;
|
|
8711
|
+
const isAllSelected = input.selectionStart === 0 && input.selectionEnd === input.value.length;
|
|
8712
|
+
|
|
8713
|
+
// Trim and handle paste if field is empty or all content is selected (overwrite)
|
|
8714
|
+
if (isFieldEmpty || isAllSelected) {
|
|
8715
|
+
const trimmedValue = e.clipboardData.getData('text').trim();
|
|
8716
|
+
setLocalValue(trimmedValue);
|
|
8717
|
+
handleInput(trimmedValue);
|
|
8718
|
+
if (onPaste) {
|
|
8719
|
+
onPaste(e);
|
|
8720
|
+
}
|
|
8721
|
+
e.preventDefault();
|
|
8722
|
+
return;
|
|
8723
|
+
}
|
|
8724
|
+
|
|
8725
|
+
// Allow default paste behavior for normal text editing
|
|
8726
|
+
if (onPaste) {
|
|
8727
|
+
onPaste(e);
|
|
8728
|
+
}
|
|
8373
8729
|
};
|
|
8374
8730
|
const handleLocalInput = e => {
|
|
8375
8731
|
if (e.target.value === localValue) {
|
|
@@ -8384,6 +8740,11 @@ function Textfield(props) {
|
|
|
8384
8740
|
}
|
|
8385
8741
|
setLocalValue(value);
|
|
8386
8742
|
}, [value]);
|
|
8743
|
+
const handleOnKeyDown = e => {
|
|
8744
|
+
if (isCmdWithChar(e)) {
|
|
8745
|
+
handleInput.flush?.();
|
|
8746
|
+
}
|
|
8747
|
+
};
|
|
8387
8748
|
return jsxRuntime.jsxs("div", {
|
|
8388
8749
|
class: "bio-properties-panel-textfield",
|
|
8389
8750
|
children: [jsxRuntime.jsx("label", {
|
|
@@ -8406,7 +8767,9 @@ function Textfield(props) {
|
|
|
8406
8767
|
class: "bio-properties-panel-input",
|
|
8407
8768
|
onInput: handleLocalInput,
|
|
8408
8769
|
onFocus: onFocus,
|
|
8770
|
+
onKeyDown: handleOnKeyDown,
|
|
8409
8771
|
onBlur: handleOnBlur,
|
|
8772
|
+
onPaste: handleOnPaste,
|
|
8410
8773
|
placeholder: placeholder,
|
|
8411
8774
|
value: localValue
|
|
8412
8775
|
})]
|
|
@@ -8441,6 +8804,7 @@ function TextfieldEntry(props) {
|
|
|
8441
8804
|
validate,
|
|
8442
8805
|
onFocus,
|
|
8443
8806
|
onBlur,
|
|
8807
|
+
onPaste,
|
|
8444
8808
|
placeholder,
|
|
8445
8809
|
tooltip
|
|
8446
8810
|
} = props;
|
|
@@ -8476,6 +8840,7 @@ function TextfieldEntry(props) {
|
|
|
8476
8840
|
onInput: onInput,
|
|
8477
8841
|
onFocus: onFocus,
|
|
8478
8842
|
onBlur: onBlur,
|
|
8843
|
+
onPaste: onPaste,
|
|
8479
8844
|
placeholder: placeholder,
|
|
8480
8845
|
value: value,
|
|
8481
8846
|
tooltip: tooltip,
|
|
@@ -8745,6 +9110,7 @@ function Title(props) {
|
|
|
8745
9110
|
class: "bio-properties-panel-popup__title",
|
|
8746
9111
|
children: title
|
|
8747
9112
|
}), children, showCloseButton && jsxRuntime.jsx("button", {
|
|
9113
|
+
type: "button",
|
|
8748
9114
|
title: closeButtonTooltip,
|
|
8749
9115
|
class: "bio-properties-panel-popup__close",
|
|
8750
9116
|
onClick: onClose,
|
|
@@ -8786,6 +9152,25 @@ function cancel(event) {
|
|
|
8786
9152
|
event.preventDefault();
|
|
8787
9153
|
event.stopPropagation();
|
|
8788
9154
|
}
|
|
9155
|
+
|
|
9156
|
+
/**
|
|
9157
|
+
* @typedef {Object} FeelPopupProps
|
|
9158
|
+
* @property {string} entryId
|
|
9159
|
+
* @property {Function} onInput
|
|
9160
|
+
* @property {Function} onClose
|
|
9161
|
+
* @property {string} title
|
|
9162
|
+
* @property {'feel'|'feelers'} type
|
|
9163
|
+
* @property {string} value
|
|
9164
|
+
* @property {Array} [links]
|
|
9165
|
+
* @property {Array|Object} [variables]
|
|
9166
|
+
* @property {Object} [position]
|
|
9167
|
+
* @property {string} [hostLanguage]
|
|
9168
|
+
* @property {boolean} [singleLine]
|
|
9169
|
+
* @property {HTMLElement} [sourceElement]
|
|
9170
|
+
* @property {HTMLElement|string} [tooltipContainer]
|
|
9171
|
+
* @property {Object} [eventBus]
|
|
9172
|
+
*/
|
|
9173
|
+
|
|
8789
9174
|
const FEEL_POPUP_WIDTH = 700;
|
|
8790
9175
|
const FEEL_POPUP_HEIGHT = 250;
|
|
8791
9176
|
|