@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.esm.js CHANGED
@@ -283,7 +283,7 @@ function TooltipWrapper(props) {
283
283
  return jsx(Tooltip, {
284
284
  ...props,
285
285
  value: value,
286
- forId: prefixId$9(forId)
286
+ forId: `bio-properties-panel-${forId}`
287
287
  });
288
288
  }
289
289
  function Tooltip(props) {
@@ -294,71 +294,52 @@ function Tooltip(props) {
294
294
  direction = 'right',
295
295
  position
296
296
  } = props;
297
- const [visible, setShow] = useState(false);
298
- const [focusedViaKeyboard, setFocusedViaKeyboard] = useState(false);
297
+ const [visible, setVisible] = useState(false);
298
+
299
+ // Tooltip will be shown after SHOW_DELAY ms from hovering over the source element.
300
+ const SHOW_DELAY = 200;
299
301
  let timeout = null;
300
302
  const wrapperRef = useRef(null);
301
303
  const tooltipRef = useRef(null);
302
- const showTooltip = async event => {
303
- const show = () => setShow(true);
304
- if (!visible && !timeout) {
305
- if (event instanceof MouseEvent) {
306
- timeout = setTimeout(show, 200);
307
- } else {
308
- show();
309
- setFocusedViaKeyboard(true);
310
- }
304
+ const show = (_, delay) => {
305
+ if (visible) return;
306
+ if (delay) {
307
+ timeout = setTimeout(() => {
308
+ setVisible(true);
309
+ }, SHOW_DELAY);
310
+ } else {
311
+ setVisible(true);
311
312
  }
312
313
  };
313
- const hideTooltip = () => {
314
- setShow(false);
315
- setFocusedViaKeyboard(false);
316
- };
317
- const hideTooltipViaEscape = e => {
318
- e.code === 'Escape' && hideTooltip();
314
+ const hide = () => {
315
+ clearTimeout(timeout);
316
+ setVisible(false);
319
317
  };
320
- const isTooltipHovered = ({
321
- x,
322
- y
318
+ const handleMouseLeave = ({
319
+ relatedTarget
323
320
  }) => {
324
- const tooltip = tooltipRef.current;
325
- const wrapper = wrapperRef.current;
326
- return tooltip && (inBounds(x, y, wrapper.getBoundingClientRect()) || inBounds(x, y, tooltip.getBoundingClientRect()));
321
+ // Don't hide the tooltip when moving mouse between the wrapper and the tooltip.
322
+ if (relatedTarget === wrapperRef.current || relatedTarget === tooltipRef.current || relatedTarget?.parentElement === tooltipRef.current) {
323
+ return;
324
+ }
325
+ hide();
327
326
  };
328
- useEffect(() => {
327
+ const handleFocusOut = e => {
329
328
  const {
330
- current
331
- } = wrapperRef;
332
- if (!current) {
329
+ target
330
+ } = e;
331
+
332
+ // Don't hide the tooltip if the wrapper or the tooltip itself is clicked.
333
+ const isHovered = target.matches(':hover') || tooltipRef.current?.matches(':hover');
334
+ if (target === wrapperRef.current && isHovered) {
335
+ e.stopPropagation();
333
336
  return;
334
337
  }
335
- const hideHoveredTooltip = e => {
336
- const isFocused = document.activeElement === wrapperRef.current || document.activeElement.closest('.bio-properties-panel-tooltip');
337
- if (visible && !isTooltipHovered({
338
- x: e.x,
339
- y: e.y
340
- }) && !(isFocused && focusedViaKeyboard)) {
341
- hideTooltip();
342
- }
343
- };
344
- const hideFocusedTooltip = e => {
345
- const {
346
- relatedTarget
347
- } = e;
348
- const isTooltipChild = el => !!el.closest('.bio-properties-panel-tooltip');
349
- if (visible && !isHovered(wrapperRef.current) && relatedTarget && !isTooltipChild(relatedTarget)) {
350
- hideTooltip();
351
- }
352
- };
353
- document.addEventListener('wheel', hideHoveredTooltip);
354
- document.addEventListener('focusout', hideFocusedTooltip);
355
- document.addEventListener('mousemove', hideHoveredTooltip);
356
- return () => {
357
- document.removeEventListener('wheel', hideHoveredTooltip);
358
- document.removeEventListener('mousemove', hideHoveredTooltip);
359
- document.removeEventListener('focusout', hideFocusedTooltip);
360
- };
361
- }, [wrapperRef.current, visible, focusedViaKeyboard]);
338
+ hide();
339
+ };
340
+ const hideTooltipViaEscape = e => {
341
+ e.code === 'Escape' && hide();
342
+ };
362
343
  const renderTooltip = () => {
363
344
  return jsxs("div", {
364
345
  class: `bio-properties-panel-tooltip ${direction}`,
@@ -368,6 +349,7 @@ function Tooltip(props) {
368
349
  style: position || getTooltipPosition(wrapperRef.current),
369
350
  ref: tooltipRef,
370
351
  onClick: e => e.stopPropagation(),
352
+ onMouseLeave: handleMouseLeave,
371
353
  children: [jsx("div", {
372
354
  class: "bio-properties-panel-tooltip-content",
373
355
  children: value
@@ -380,39 +362,23 @@ function Tooltip(props) {
380
362
  class: "bio-properties-panel-tooltip-wrapper",
381
363
  tabIndex: "0",
382
364
  ref: wrapperRef,
383
- onMouseEnter: showTooltip,
384
- onMouseLeave: () => {
385
- clearTimeout(timeout);
386
- timeout = null;
387
- },
388
- onFocus: showTooltip,
365
+ onMouseEnter: e => show(e, true),
366
+ onMouseLeave: handleMouseLeave,
367
+ onFocus: show,
368
+ onBlur: handleFocusOut,
389
369
  onKeyDown: hideTooltipViaEscape,
390
370
  children: [props.children, visible ? parent ? createPortal(renderTooltip(), parent.current) : renderTooltip() : null]
391
371
  });
392
372
  }
393
373
 
394
374
  // helper
395
- function inBounds(x, y, bounds) {
396
- const {
397
- top,
398
- right,
399
- bottom,
400
- left
401
- } = bounds;
402
- return x >= left && x <= right && y >= top && y <= bottom;
403
- }
375
+
404
376
  function getTooltipPosition(refElement) {
405
377
  const refPosition = refElement.getBoundingClientRect();
406
378
  const right = `calc(100% - ${refPosition.x}px)`;
407
379
  const top = `${refPosition.top - 10}px`;
408
380
  return `right: ${right}; top: ${top};`;
409
381
  }
410
- function isHovered(element) {
411
- return element.matches(':hover');
412
- }
413
- function prefixId$9(id) {
414
- return `bio-properties-panel-${id}`;
415
- }
416
382
 
417
383
  /**
418
384
  * Accesses the global DescriptionContext and returns a description for a given id and element.
@@ -1982,6 +1948,7 @@ function FeelTextfieldComponent(props) {
1982
1948
  label,
1983
1949
  hostLanguage,
1984
1950
  onInput,
1951
+ onBlur,
1985
1952
  onError,
1986
1953
  placeholder,
1987
1954
  feel,
@@ -2047,6 +2014,12 @@ function FeelTextfieldComponent(props) {
2047
2014
  setFocus(-1);
2048
2015
  }
2049
2016
  };
2017
+ const handleOnBlur = e => {
2018
+ if (onBlur) {
2019
+ onBlur(e);
2020
+ }
2021
+ setLocalValue(e.target.value.trim());
2022
+ };
2050
2023
  const handleLint = useStaticCallback((lint = []) => {
2051
2024
  const syntaxError = lint.some(report => report.type === 'Syntax Error');
2052
2025
  if (syntaxError) {
@@ -2168,6 +2141,7 @@ function FeelTextfieldComponent(props) {
2168
2141
  ...props,
2169
2142
  popupOpen: popuOpen,
2170
2143
  onInput: handleLocalInput,
2144
+ onBlur: handleOnBlur,
2171
2145
  contentAttributes: {
2172
2146
  'id': prefixId$5(id),
2173
2147
  'aria-label': label
@@ -3996,6 +3970,12 @@ function TextArea(props) {
3996
3970
  autoResize && resizeToContents(e.target);
3997
3971
  setLocalValue(e.target.value);
3998
3972
  };
3973
+ const handleOnBlur = e => {
3974
+ if (onBlur) {
3975
+ onBlur(e);
3976
+ }
3977
+ setLocalValue(e.target.value.trim());
3978
+ };
3999
3979
  useLayoutEffect(() => {
4000
3980
  autoResize && resizeToContents(ref.current);
4001
3981
  }, []);
@@ -4027,7 +4007,7 @@ function TextArea(props) {
4027
4007
  class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : '', autoResize ? 'auto-resize' : ''),
4028
4008
  onInput: handleInput,
4029
4009
  onFocus: onFocus,
4030
- onBlur: onBlur,
4010
+ onBlur: handleOnBlur,
4031
4011
  placeholder: placeholder,
4032
4012
  rows: rows,
4033
4013
  value: localValue,
@@ -4146,6 +4126,12 @@ function Textfield(props) {
4146
4126
  const handleInputCallback = useMemo(() => {
4147
4127
  return debounce(target => onInput(target.value.length ? target.value : undefined));
4148
4128
  }, [onInput, debounce]);
4129
+ const handleOnBlur = e => {
4130
+ if (onBlur) {
4131
+ onBlur(e);
4132
+ }
4133
+ setLocalValue(e.target.value.trim());
4134
+ };
4149
4135
  const handleInput = e => {
4150
4136
  handleInputCallback(e.target);
4151
4137
  setLocalValue(e.target.value);
@@ -4178,7 +4164,7 @@ function Textfield(props) {
4178
4164
  class: "bio-properties-panel-input",
4179
4165
  onInput: handleInput,
4180
4166
  onFocus: onFocus,
4181
- onBlur: onBlur,
4167
+ onBlur: handleOnBlur,
4182
4168
  placeholder: placeholder,
4183
4169
  value: localValue
4184
4170
  })]