fluentui-extended 2026.2.12 → 2026.2.13

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
@@ -59,11 +59,17 @@ var useLookupStyles = reactComponents.makeStyles({
59
59
  width: "20px",
60
60
  height: "20px"
61
61
  },
62
- dropdownSurface: {
62
+ dropdownPortal: {
63
+ position: "absolute",
63
64
  padding: 0,
64
- marginTop: "4px",
65
65
  minWidth: "220px",
66
- zIndex: 1e3
66
+ zIndex: 1e6,
67
+ backgroundColor: reactComponents.tokens.colorNeutralBackground1,
68
+ borderRadius: reactComponents.tokens.borderRadiusXLarge,
69
+ boxShadow: reactComponents.tokens.shadow16,
70
+ border: `1px solid ${reactComponents.tokens.colorNeutralStroke1}`,
71
+ boxSizing: "border-box",
72
+ overflow: "hidden"
67
73
  },
68
74
  dropdownContent: {
69
75
  maxHeight: "350px",
@@ -205,7 +211,8 @@ var useLookupStyles = reactComponents.makeStyles({
205
211
  alignItems: "center",
206
212
  justifyContent: "space-between",
207
213
  borderRadius: reactComponents.tokens.borderRadiusMedium,
208
- padding: "4px 12px",
214
+ padding: "6px 12px",
215
+ minHeight: "24px",
209
216
  backgroundColor: reactComponents.tokens.colorNeutralBackground3,
210
217
  backgroundImage: `repeating-linear-gradient(
211
218
  -45deg,
@@ -226,6 +233,7 @@ var useLookupStyles = reactComponents.makeStyles({
226
233
  alignItems: "center",
227
234
  justifyContent: "space-between",
228
235
  padding: "6px 12px",
236
+ minHeight: "24px",
229
237
  borderTop: `1px solid ${reactComponents.tokens.colorNeutralStroke2}`,
230
238
  backgroundColor: reactComponents.tokens.colorNeutralBackground1,
231
239
  fontSize: reactComponents.tokens.fontSizeBase200,
@@ -274,7 +282,7 @@ var Lookup = ({
274
282
  const dropdownRef = React3__namespace.useRef(null);
275
283
  const debounceRef = React3__namespace.useRef();
276
284
  const justSelectedRef = React3__namespace.useRef(false);
277
- const [dropdownWidth, setDropdownWidth] = React3__namespace.useState();
285
+ const [dropdownPosition, setDropdownPosition] = React3__namespace.useState({ top: 0, left: 0, width: 0 });
278
286
  const selectedOption = React3__namespace.useMemo(
279
287
  () => selectedOptionProp ?? options.find((opt) => opt.key === selectedKey) ?? internalSelectedOption,
280
288
  [selectedOptionProp, options, selectedKey, internalSelectedOption]
@@ -300,6 +308,15 @@ var Lookup = ({
300
308
  }
301
309
  return selectedOption?.text ?? "";
302
310
  }, [isOpen, searchText, selectedOption]);
311
+ const openDropdown = React3__namespace.useCallback(() => {
312
+ if (disabled) return;
313
+ setIsOpen(true);
314
+ }, [disabled]);
315
+ const closeDropdown = React3__namespace.useCallback(() => {
316
+ setIsOpen(false);
317
+ setSearchText("");
318
+ setHighlightedIndex(-1);
319
+ }, []);
303
320
  const handleSearchChange = React3__namespace.useCallback(
304
321
  (value) => {
305
322
  setSearchText(value);
@@ -320,10 +337,10 @@ var Lookup = ({
320
337
  const value = e.target.value;
321
338
  handleSearchChange(value);
322
339
  if (!isOpen) {
323
- setIsOpen(true);
340
+ openDropdown();
324
341
  }
325
342
  },
326
- [handleSearchChange, isOpen]
343
+ [handleSearchChange, isOpen, openDropdown]
327
344
  );
328
345
  const handleSelectOption = React3__namespace.useCallback(
329
346
  (option) => {
@@ -353,13 +370,10 @@ var Lookup = ({
353
370
  (e) => {
354
371
  if (disabled) return;
355
372
  switch (e.key) {
356
- case " ":
357
- e.stopPropagation();
358
- break;
359
373
  case "ArrowDown":
360
374
  e.preventDefault();
361
375
  if (!isOpen) {
362
- setIsOpen(true);
376
+ openDropdown();
363
377
  } else {
364
378
  setHighlightedIndex(
365
379
  (prev) => prev < filteredOptions.length - 1 ? prev + 1 : 0
@@ -382,27 +396,34 @@ var Lookup = ({
382
396
  break;
383
397
  case "Escape":
384
398
  e.preventDefault();
385
- setIsOpen(false);
386
- setSearchText("");
387
- setHighlightedIndex(-1);
399
+ closeDropdown();
388
400
  break;
389
401
  case "Tab":
390
- setIsOpen(false);
391
- setSearchText("");
402
+ closeDropdown();
392
403
  break;
393
404
  }
394
405
  },
395
- [disabled, isOpen, highlightedIndex, filteredOptions, handleSelectOption]
406
+ [disabled, isOpen, highlightedIndex, filteredOptions, handleSelectOption, openDropdown, closeDropdown]
396
407
  );
397
- const handleFocus = React3__namespace.useCallback(() => {
398
- if (!disabled) {
399
- if (justSelectedRef.current) {
400
- justSelectedRef.current = false;
401
- return;
408
+ const handleFocus = React3__namespace.useCallback(
409
+ (e) => {
410
+ if (!disabled) {
411
+ if (justSelectedRef.current) {
412
+ justSelectedRef.current = false;
413
+ return;
414
+ }
415
+ openDropdown();
402
416
  }
403
- setIsOpen(true);
417
+ inputProps.onFocus?.(e);
418
+ },
419
+ [disabled, openDropdown, inputProps.onFocus]
420
+ );
421
+ const handleWrapperClick = React3__namespace.useCallback(() => {
422
+ if (!disabled && !isOpen) {
423
+ openDropdown();
424
+ inputRef.current?.focus();
404
425
  }
405
- }, [disabled]);
426
+ }, [disabled, isOpen, openDropdown]);
406
427
  React3__namespace.useEffect(() => {
407
428
  return () => {
408
429
  if (debounceRef.current) {
@@ -419,74 +440,59 @@ var Lookup = ({
419
440
  }
420
441
  }, [highlightedIndex]);
421
442
  React3__namespace.useEffect(() => {
422
- if (!isOpen || !matchInputWidth) {
423
- return;
424
- }
425
- const updateWidth = () => {
426
- const width = inputWrapperRef.current?.getBoundingClientRect().width;
427
- if (width && width > 0) {
428
- setDropdownWidth(width);
443
+ if (!isOpen) return;
444
+ const updatePosition = () => {
445
+ const rect = inputWrapperRef.current?.getBoundingClientRect();
446
+ if (rect) {
447
+ setDropdownPosition({
448
+ top: rect.bottom + 4 + window.scrollY,
449
+ left: rect.left + window.scrollX,
450
+ width: matchInputWidth ? rect.width : 0
451
+ });
429
452
  }
430
453
  };
431
- updateWidth();
454
+ updatePosition();
455
+ let resizeObserver;
432
456
  if (typeof ResizeObserver !== "undefined" && inputWrapperRef.current) {
433
- const resizeObserver = new ResizeObserver(() => updateWidth());
457
+ resizeObserver = new ResizeObserver(() => updatePosition());
434
458
  resizeObserver.observe(inputWrapperRef.current);
435
- return () => resizeObserver.disconnect();
436
- }
437
- window.addEventListener("resize", updateWidth);
438
- return () => window.removeEventListener("resize", updateWidth);
439
- }, [isOpen, matchInputWidth]);
440
- React3__namespace.useEffect(() => {
441
- if (!isOpen) {
442
- return;
443
459
  }
444
- const closeOnScroll = (event) => {
445
- const target = event.target;
446
- if (target && (dropdownRef.current?.contains(target) || inputWrapperRef.current?.contains(target))) {
447
- return;
448
- }
449
- setIsOpen(false);
450
- setSearchText("");
451
- setHighlightedIndex(-1);
460
+ window.addEventListener("resize", updatePosition);
461
+ window.addEventListener("scroll", updatePosition, true);
462
+ return () => {
463
+ resizeObserver?.disconnect();
464
+ window.removeEventListener("resize", updatePosition);
465
+ window.removeEventListener("scroll", updatePosition, true);
452
466
  };
453
- window.addEventListener("scroll", closeOnScroll, true);
454
- return () => window.removeEventListener("scroll", closeOnScroll, true);
455
- }, [isOpen]);
467
+ }, [isOpen, matchInputWidth]);
456
468
  React3__namespace.useEffect(() => {
457
- if (!isOpen) {
458
- return;
459
- }
469
+ if (!isOpen) return;
460
470
  const handlePointerDownOutside = (event) => {
461
471
  const target = event.target;
462
- if (!target) {
463
- return;
464
- }
472
+ if (!target) return;
465
473
  const insideInput = inputWrapperRef.current?.contains(target);
466
474
  const insideDropdown = dropdownRef.current?.contains(target);
467
475
  if (!insideInput && !insideDropdown) {
468
- setIsOpen(false);
469
- setSearchText("");
470
- setHighlightedIndex(-1);
476
+ closeDropdown();
471
477
  }
472
478
  };
473
- document.addEventListener("mousedown", handlePointerDownOutside);
474
- return () => document.removeEventListener("mousedown", handlePointerDownOutside);
475
- }, [isOpen]);
479
+ const rafId = requestAnimationFrame(() => {
480
+ document.addEventListener("mousedown", handlePointerDownOutside);
481
+ });
482
+ return () => {
483
+ cancelAnimationFrame(rafId);
484
+ document.removeEventListener("mousedown", handlePointerDownOutside);
485
+ };
486
+ }, [isOpen, closeDropdown]);
487
+ const showDropdown = isOpen && !disabled;
476
488
  return /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.root }, /* @__PURE__ */ React3__namespace.createElement(
477
- reactComponents.Popover,
489
+ "div",
478
490
  {
479
- open: isOpen && !disabled,
480
- onOpenChange: (_e, data) => {
481
- if (data.open && !disabled) {
482
- setIsOpen(true);
483
- }
484
- },
485
- trapFocus: false,
486
- withArrow: false,
487
- positioning: "below-start"
491
+ className: styles.inputWrapper,
492
+ ref: inputWrapperRef,
493
+ onClick: handleWrapperClick
488
494
  },
489
- /* @__PURE__ */ React3__namespace.createElement(reactComponents.PopoverTrigger, { disableButtonEnhancement: true }, /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.inputWrapper, ref: inputWrapperRef }, /* @__PURE__ */ React3__namespace.createElement(
495
+ /* @__PURE__ */ React3__namespace.createElement(
490
496
  reactComponents.Input,
491
497
  {
492
498
  ...inputProps,
@@ -517,78 +523,81 @@ var Lookup = ({
517
523
  }
518
524
  ), loading ? /* @__PURE__ */ React3__namespace.createElement(reactComponents.Spinner, { size: "tiny" }) : /* @__PURE__ */ React3__namespace.createElement("span", { className: styles.chevronIcon }, /* @__PURE__ */ React3__namespace.createElement(reactIcons.ChevronDownRegular, null)))
519
525
  }
520
- ))),
526
+ )
527
+ ), showDropdown && /* @__PURE__ */ React3__namespace.createElement(reactComponents.Portal, null, /* @__PURE__ */ React3__namespace.createElement(
528
+ "div",
529
+ {
530
+ className: styles.dropdownPortal,
531
+ style: {
532
+ top: dropdownPosition.top,
533
+ left: dropdownPosition.left,
534
+ ...matchInputWidth && dropdownPosition.width > 0 ? { width: dropdownPosition.width } : { minWidth: 220 }
535
+ }
536
+ },
521
537
  /* @__PURE__ */ React3__namespace.createElement(
522
- reactComponents.PopoverSurface,
538
+ "div",
523
539
  {
524
- className: styles.dropdownSurface,
525
- style: matchInputWidth && dropdownWidth ? { width: `${dropdownWidth}px` } : void 0
540
+ id: `${lookupId}-listbox`,
541
+ className: styles.dropdownContent,
542
+ ref: dropdownRef,
543
+ role: "listbox",
544
+ "aria-labelledby": lookupId
526
545
  },
527
- /* @__PURE__ */ React3__namespace.createElement(
528
- "div",
529
- {
530
- id: `${lookupId}-listbox`,
531
- className: styles.dropdownContent,
532
- ref: dropdownRef,
533
- role: "listbox",
534
- "aria-labelledby": lookupId
535
- },
536
- header && /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.headerWrapper }, /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.header }, header)),
537
- loading ? /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.loadingContainer }, /* @__PURE__ */ React3__namespace.createElement(reactComponents.Spinner, { size: "small", label: "Loading..." })) : filteredOptions.length === 0 ? /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.noResults }, noResultsMessage) : /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.optionsContainer }, /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.optionsList }, filteredOptions.map((option, index) => {
538
- const isExpanded = expandedKeys.has(option.key);
539
- const hasDetails = option.details && option.details.length > 0;
540
- const handleExpandClick = (e) => {
541
- e.stopPropagation();
542
- setExpandedKeys((prev) => {
543
- const next = new Set(prev);
544
- if (next.has(option.key)) {
545
- next.delete(option.key);
546
- } else {
547
- next.add(option.key);
548
- }
549
- return next;
550
- });
551
- };
552
- return /* @__PURE__ */ React3__namespace.createElement(
553
- "div",
546
+ header && /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.headerWrapper }, /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.header }, header)),
547
+ loading ? /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.loadingContainer }, /* @__PURE__ */ React3__namespace.createElement(reactComponents.Spinner, { size: "small", label: "Loading..." })) : filteredOptions.length === 0 ? /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.noResults }, noResultsMessage) : /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.optionsContainer }, /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.optionsList }, filteredOptions.map((option, index) => {
548
+ const isExpanded = expandedKeys.has(option.key);
549
+ const hasDetails = option.details && option.details.length > 0;
550
+ const handleExpandClick = (e) => {
551
+ e.stopPropagation();
552
+ setExpandedKeys((prev) => {
553
+ const next = new Set(prev);
554
+ if (next.has(option.key)) {
555
+ next.delete(option.key);
556
+ } else {
557
+ next.add(option.key);
558
+ }
559
+ return next;
560
+ });
561
+ };
562
+ return /* @__PURE__ */ React3__namespace.createElement(
563
+ "div",
564
+ {
565
+ key: option.key,
566
+ id: `${lookupId}-option-${option.key}`,
567
+ role: "option",
568
+ "data-index": index,
569
+ "aria-selected": option.key === selectedOption?.key ? true : false,
570
+ "aria-disabled": option.disabled === true ? true : void 0,
571
+ className: reactComponents.mergeClasses(
572
+ styles.option,
573
+ index === highlightedIndex && styles.optionHighlighted,
574
+ option.key === selectedOption?.key && styles.optionSelected,
575
+ option.disabled && styles.optionDisabled
576
+ ),
577
+ onClick: () => handleSelectOption(option),
578
+ onMouseEnter: () => setHighlightedIndex(index)
579
+ },
580
+ option.icon && /* @__PURE__ */ React3__namespace.createElement("span", { className: styles.optionIcon }, option.icon),
581
+ /* @__PURE__ */ React3__namespace.createElement("span", { className: styles.optionContent }, /* @__PURE__ */ React3__namespace.createElement("span", { className: styles.optionText }, option.text), option.secondaryText && /* @__PURE__ */ React3__namespace.createElement("span", { className: styles.optionSecondaryText }, option.secondaryText), isExpanded && hasDetails && /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.optionDetails }, option.details.map((detail, detailIndex) => /* @__PURE__ */ React3__namespace.createElement("div", { key: detailIndex, className: styles.optionDetailRow }, detail.label && /* @__PURE__ */ React3__namespace.createElement("span", { className: styles.optionDetailLabel }, detail.label, ":"), /* @__PURE__ */ React3__namespace.createElement("span", { className: styles.optionDetailValue }, detail.value))))),
582
+ hasDetails && /* @__PURE__ */ React3__namespace.createElement(
583
+ "span",
554
584
  {
555
- key: option.key,
556
- id: `${lookupId}-option-${option.key}`,
557
- role: "option",
558
- "data-index": index,
559
- "aria-selected": option.key === selectedOption?.key ? "true" : "false",
560
- "aria-disabled": option.disabled ? "true" : void 0,
585
+ role: "button",
586
+ tabIndex: -1,
561
587
  className: reactComponents.mergeClasses(
562
- styles.option,
563
- index === highlightedIndex && styles.optionHighlighted,
564
- option.key === selectedOption?.key && styles.optionSelected,
565
- option.disabled && styles.optionDisabled
588
+ styles.optionExpandButton,
589
+ isExpanded && styles.optionExpandButtonExpanded
566
590
  ),
567
- onClick: () => handleSelectOption(option),
568
- onMouseEnter: () => setHighlightedIndex(index)
591
+ onClick: handleExpandClick,
592
+ "aria-label": isExpanded ? "Collapse details" : "Expand details"
569
593
  },
570
- option.icon && /* @__PURE__ */ React3__namespace.createElement("span", { className: styles.optionIcon }, option.icon),
571
- /* @__PURE__ */ React3__namespace.createElement("span", { className: styles.optionContent }, /* @__PURE__ */ React3__namespace.createElement("span", { className: styles.optionText }, option.text), option.secondaryText && /* @__PURE__ */ React3__namespace.createElement("span", { className: styles.optionSecondaryText }, option.secondaryText), isExpanded && hasDetails && /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.optionDetails }, option.details.map((detail, detailIndex) => /* @__PURE__ */ React3__namespace.createElement("div", { key: detailIndex, className: styles.optionDetailRow }, detail.label && /* @__PURE__ */ React3__namespace.createElement("span", { className: styles.optionDetailLabel }, detail.label, ":"), /* @__PURE__ */ React3__namespace.createElement("span", { className: styles.optionDetailValue }, detail.value))))),
572
- hasDetails && /* @__PURE__ */ React3__namespace.createElement(
573
- "span",
574
- {
575
- role: "button",
576
- tabIndex: -1,
577
- className: reactComponents.mergeClasses(
578
- styles.optionExpandButton,
579
- isExpanded && styles.optionExpandButtonExpanded
580
- ),
581
- onClick: handleExpandClick,
582
- "aria-label": isExpanded ? "Collapse details" : "Expand details"
583
- },
584
- /* @__PURE__ */ React3__namespace.createElement(reactIcons.ChevronDownRegular, null)
585
- )
586
- );
587
- }))),
588
- footer && /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.footerWrapper }, /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.footer }, footer))
589
- )
594
+ /* @__PURE__ */ React3__namespace.createElement(reactIcons.ChevronDownRegular, null)
595
+ )
596
+ );
597
+ }))),
598
+ footer && /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.footerWrapper }, /* @__PURE__ */ React3__namespace.createElement("div", { className: styles.footer }, footer))
590
599
  )
591
- ));
600
+ )));
592
601
  };
593
602
  Lookup.displayName = "Lookup";
594
603
  var gridWithBetween = "minmax(0, 1.6fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) auto";