@bpmn-io/properties-panel 3.26.1 → 3.26.3

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/index.js CHANGED
@@ -304,7 +304,7 @@ function TooltipWrapper(props) {
304
304
  return jsxRuntime.jsx(Tooltip, {
305
305
  ...props,
306
306
  value: value,
307
- forId: prefixId$9(forId)
307
+ forId: `bio-properties-panel-${forId}`
308
308
  });
309
309
  }
310
310
  function Tooltip(props) {
@@ -315,71 +315,52 @@ function Tooltip(props) {
315
315
  direction = 'right',
316
316
  position
317
317
  } = props;
318
- const [visible, setShow] = hooks.useState(false);
319
- const [focusedViaKeyboard, setFocusedViaKeyboard] = hooks.useState(false);
318
+ const [visible, setVisible] = hooks.useState(false);
319
+
320
+ // Tooltip will be shown after SHOW_DELAY ms from hovering over the source element.
321
+ const SHOW_DELAY = 200;
320
322
  let timeout = null;
321
323
  const wrapperRef = hooks.useRef(null);
322
324
  const tooltipRef = hooks.useRef(null);
323
- const showTooltip = async event => {
324
- const show = () => setShow(true);
325
- if (!visible && !timeout) {
326
- if (event instanceof MouseEvent) {
327
- timeout = setTimeout(show, 200);
328
- } else {
329
- show();
330
- setFocusedViaKeyboard(true);
331
- }
325
+ const show = (_, delay) => {
326
+ if (visible) return;
327
+ if (delay) {
328
+ timeout = setTimeout(() => {
329
+ setVisible(true);
330
+ }, SHOW_DELAY);
331
+ } else {
332
+ setVisible(true);
332
333
  }
333
334
  };
334
- const hideTooltip = () => {
335
- setShow(false);
336
- setFocusedViaKeyboard(false);
337
- };
338
- const hideTooltipViaEscape = e => {
339
- e.code === 'Escape' && hideTooltip();
335
+ const hide = () => {
336
+ clearTimeout(timeout);
337
+ setVisible(false);
340
338
  };
341
- const isTooltipHovered = ({
342
- x,
343
- y
339
+ const handleMouseLeave = ({
340
+ relatedTarget
344
341
  }) => {
345
- const tooltip = tooltipRef.current;
346
- const wrapper = wrapperRef.current;
347
- return tooltip && (inBounds(x, y, wrapper.getBoundingClientRect()) || inBounds(x, y, tooltip.getBoundingClientRect()));
342
+ // Don't hide the tooltip when moving mouse between the wrapper and the tooltip.
343
+ if (relatedTarget === wrapperRef.current || relatedTarget === tooltipRef.current || relatedTarget?.parentElement === tooltipRef.current) {
344
+ return;
345
+ }
346
+ hide();
348
347
  };
349
- hooks.useEffect(() => {
348
+ const handleFocusOut = e => {
350
349
  const {
351
- current
352
- } = wrapperRef;
353
- if (!current) {
350
+ target
351
+ } = e;
352
+
353
+ // Don't hide the tooltip if the wrapper or the tooltip itself is clicked.
354
+ const isHovered = target.matches(':hover') || tooltipRef.current?.matches(':hover');
355
+ if (target === wrapperRef.current && isHovered) {
356
+ e.stopPropagation();
354
357
  return;
355
358
  }
356
- const hideHoveredTooltip = e => {
357
- const isFocused = document.activeElement === wrapperRef.current || document.activeElement.closest('.bio-properties-panel-tooltip');
358
- if (visible && !isTooltipHovered({
359
- x: e.x,
360
- y: e.y
361
- }) && !(isFocused && focusedViaKeyboard)) {
362
- hideTooltip();
363
- }
364
- };
365
- const hideFocusedTooltip = e => {
366
- const {
367
- relatedTarget
368
- } = e;
369
- const isTooltipChild = el => !!el.closest('.bio-properties-panel-tooltip');
370
- if (visible && !isHovered(wrapperRef.current) && relatedTarget && !isTooltipChild(relatedTarget)) {
371
- hideTooltip();
372
- }
373
- };
374
- document.addEventListener('wheel', hideHoveredTooltip);
375
- document.addEventListener('focusout', hideFocusedTooltip);
376
- document.addEventListener('mousemove', hideHoveredTooltip);
377
- return () => {
378
- document.removeEventListener('wheel', hideHoveredTooltip);
379
- document.removeEventListener('mousemove', hideHoveredTooltip);
380
- document.removeEventListener('focusout', hideFocusedTooltip);
381
- };
382
- }, [wrapperRef.current, visible, focusedViaKeyboard]);
359
+ hide();
360
+ };
361
+ const hideTooltipViaEscape = e => {
362
+ e.code === 'Escape' && hide();
363
+ };
383
364
  const renderTooltip = () => {
384
365
  return jsxRuntime.jsxs("div", {
385
366
  class: `bio-properties-panel-tooltip ${direction}`,
@@ -389,6 +370,7 @@ function Tooltip(props) {
389
370
  style: position || getTooltipPosition(wrapperRef.current),
390
371
  ref: tooltipRef,
391
372
  onClick: e => e.stopPropagation(),
373
+ onMouseLeave: handleMouseLeave,
392
374
  children: [jsxRuntime.jsx("div", {
393
375
  class: "bio-properties-panel-tooltip-content",
394
376
  children: value
@@ -401,39 +383,23 @@ function Tooltip(props) {
401
383
  class: "bio-properties-panel-tooltip-wrapper",
402
384
  tabIndex: "0",
403
385
  ref: wrapperRef,
404
- onMouseEnter: showTooltip,
405
- onMouseLeave: () => {
406
- clearTimeout(timeout);
407
- timeout = null;
408
- },
409
- onFocus: showTooltip,
386
+ onMouseEnter: e => show(e, true),
387
+ onMouseLeave: handleMouseLeave,
388
+ onFocus: show,
389
+ onBlur: handleFocusOut,
410
390
  onKeyDown: hideTooltipViaEscape,
411
391
  children: [props.children, visible ? parent ? compat.createPortal(renderTooltip(), parent.current) : renderTooltip() : null]
412
392
  });
413
393
  }
414
394
 
415
395
  // helper
416
- function inBounds(x, y, bounds) {
417
- const {
418
- top,
419
- right,
420
- bottom,
421
- left
422
- } = bounds;
423
- return x >= left && x <= right && y >= top && y <= bottom;
424
- }
396
+
425
397
  function getTooltipPosition(refElement) {
426
398
  const refPosition = refElement.getBoundingClientRect();
427
399
  const right = `calc(100% - ${refPosition.x}px)`;
428
400
  const top = `${refPosition.top - 10}px`;
429
401
  return `right: ${right}; top: ${top};`;
430
402
  }
431
- function isHovered(element) {
432
- return element.matches(':hover');
433
- }
434
- function prefixId$9(id) {
435
- return `bio-properties-panel-${id}`;
436
- }
437
403
 
438
404
  /**
439
405
  * Accesses the global DescriptionContext and returns a description for a given id and element.
@@ -2003,6 +1969,7 @@ function FeelTextfieldComponent(props) {
2003
1969
  label,
2004
1970
  hostLanguage,
2005
1971
  onInput,
1972
+ onBlur,
2006
1973
  onError,
2007
1974
  placeholder,
2008
1975
  feel,
@@ -2068,6 +2035,12 @@ function FeelTextfieldComponent(props) {
2068
2035
  setFocus(-1);
2069
2036
  }
2070
2037
  };
2038
+ const handleOnBlur = e => {
2039
+ if (onBlur) {
2040
+ onBlur(e);
2041
+ }
2042
+ setLocalValue(e.target.value.trim());
2043
+ };
2071
2044
  const handleLint = useStaticCallback((lint = []) => {
2072
2045
  const syntaxError = lint.some(report => report.type === 'Syntax Error');
2073
2046
  if (syntaxError) {
@@ -2189,6 +2162,7 @@ function FeelTextfieldComponent(props) {
2189
2162
  ...props,
2190
2163
  popupOpen: popuOpen,
2191
2164
  onInput: handleLocalInput,
2165
+ onBlur: handleOnBlur,
2192
2166
  contentAttributes: {
2193
2167
  'id': prefixId$5(id),
2194
2168
  'aria-label': label
@@ -4017,6 +3991,12 @@ function TextArea(props) {
4017
3991
  autoResize && resizeToContents(e.target);
4018
3992
  setLocalValue(e.target.value);
4019
3993
  };
3994
+ const handleOnBlur = e => {
3995
+ if (onBlur) {
3996
+ onBlur(e);
3997
+ }
3998
+ setLocalValue(e.target.value.trim());
3999
+ };
4020
4000
  hooks.useLayoutEffect(() => {
4021
4001
  autoResize && resizeToContents(ref.current);
4022
4002
  }, []);
@@ -4048,7 +4028,7 @@ function TextArea(props) {
4048
4028
  class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : '', autoResize ? 'auto-resize' : ''),
4049
4029
  onInput: handleInput,
4050
4030
  onFocus: onFocus,
4051
- onBlur: onBlur,
4031
+ onBlur: handleOnBlur,
4052
4032
  placeholder: placeholder,
4053
4033
  rows: rows,
4054
4034
  value: localValue,
@@ -4167,6 +4147,12 @@ function Textfield(props) {
4167
4147
  const handleInputCallback = hooks.useMemo(() => {
4168
4148
  return debounce(target => onInput(target.value.length ? target.value : undefined));
4169
4149
  }, [onInput, debounce]);
4150
+ const handleOnBlur = e => {
4151
+ if (onBlur) {
4152
+ onBlur(e);
4153
+ }
4154
+ setLocalValue(e.target.value.trim());
4155
+ };
4170
4156
  const handleInput = e => {
4171
4157
  handleInputCallback(e.target);
4172
4158
  setLocalValue(e.target.value);
@@ -4199,7 +4185,7 @@ function Textfield(props) {
4199
4185
  class: "bio-properties-panel-input",
4200
4186
  onInput: handleInput,
4201
4187
  onFocus: onFocus,
4202
- onBlur: onBlur,
4188
+ onBlur: handleOnBlur,
4203
4189
  placeholder: placeholder,
4204
4190
  value: localValue
4205
4191
  })]