@simplybusiness/mobius 6.5.2 → 6.5.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/CHANGELOG.md +7 -0
- package/dist/cjs/index.js +57 -9
- package/dist/esm/index.js +58 -10
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/components/Combobox/Combobox.test.tsx +1 -1
- package/src/components/Combobox/Combobox.tsx +81 -18
- package/src/components/TextOrHTML/TextOrHTML.test.tsx +59 -0
- package/src/components/TextOrHTML/TextOrHTML.tsx +6 -2
package/CHANGELOG.md
CHANGED
package/dist/cjs/index.js
CHANGED
|
@@ -1575,6 +1575,8 @@ var ComboboxInner = (0, import_react24.forwardRef)(
|
|
|
1575
1575
|
const listboxId = (0, import_react24.useId)();
|
|
1576
1576
|
const statusId = (0, import_react24.useId)();
|
|
1577
1577
|
const blurTimeoutRef = (0, import_react24.useRef)(null);
|
|
1578
|
+
const userInteractedRef = (0, import_react24.useRef)(false);
|
|
1579
|
+
const justSelectedRef = (0, import_react24.useRef)(false);
|
|
1578
1580
|
const { down } = useBreakpoint();
|
|
1579
1581
|
const isMobile = down("md");
|
|
1580
1582
|
const handleFocus = (e) => {
|
|
@@ -1584,8 +1586,31 @@ var ComboboxInner = (0, import_react24.forwardRef)(
|
|
|
1584
1586
|
clearTimeout(blurTimeoutRef.current);
|
|
1585
1587
|
blurTimeoutRef.current = null;
|
|
1586
1588
|
}
|
|
1587
|
-
|
|
1589
|
+
const isNaturalFocus = userInteractedRef.current || e.relatedTarget !== null;
|
|
1590
|
+
if (userInteractedRef.current) {
|
|
1591
|
+
userInteractedRef.current = false;
|
|
1592
|
+
}
|
|
1593
|
+
if (justSelectedRef.current && !isNaturalFocus) {
|
|
1594
|
+
justSelectedRef.current = false;
|
|
1595
|
+
return;
|
|
1596
|
+
}
|
|
1597
|
+
if (isNaturalFocus) {
|
|
1598
|
+
setIsOpen(true);
|
|
1599
|
+
justSelectedRef.current = false;
|
|
1600
|
+
}
|
|
1588
1601
|
};
|
|
1602
|
+
(0, import_react24.useEffect)(() => {
|
|
1603
|
+
if (!inputRef || typeof inputRef === "function") return;
|
|
1604
|
+
const inputElement = inputRef.current;
|
|
1605
|
+
if (!inputElement) return;
|
|
1606
|
+
const handleMouseDown = () => {
|
|
1607
|
+
userInteractedRef.current = true;
|
|
1608
|
+
};
|
|
1609
|
+
inputElement.addEventListener("mousedown", handleMouseDown);
|
|
1610
|
+
return () => {
|
|
1611
|
+
inputElement.removeEventListener("mousedown", handleMouseDown);
|
|
1612
|
+
};
|
|
1613
|
+
}, [inputRef]);
|
|
1589
1614
|
useOnUnmount(() => {
|
|
1590
1615
|
if (blurTimeoutRef.current) {
|
|
1591
1616
|
clearTimeout(blurTimeoutRef.current);
|
|
@@ -1594,7 +1619,11 @@ var ComboboxInner = (0, import_react24.forwardRef)(
|
|
|
1594
1619
|
const handleInputChange = (e) => {
|
|
1595
1620
|
const newValue = e.target.value;
|
|
1596
1621
|
setInputValue(newValue);
|
|
1622
|
+
justSelectedRef.current = false;
|
|
1597
1623
|
setIsChanging(true);
|
|
1624
|
+
if (!asyncOptions) {
|
|
1625
|
+
setIsOpen(true);
|
|
1626
|
+
}
|
|
1598
1627
|
clearHighlight();
|
|
1599
1628
|
onChange?.(e);
|
|
1600
1629
|
};
|
|
@@ -1607,6 +1636,7 @@ var ComboboxInner = (0, import_react24.forwardRef)(
|
|
|
1607
1636
|
return;
|
|
1608
1637
|
}
|
|
1609
1638
|
skipNextDebounceRef.current = true;
|
|
1639
|
+
justSelectedRef.current = true;
|
|
1610
1640
|
setIsChanging(false);
|
|
1611
1641
|
setIsOpen(false);
|
|
1612
1642
|
setInputValue(val);
|
|
@@ -1637,11 +1667,15 @@ var ComboboxInner = (0, import_react24.forwardRef)(
|
|
|
1637
1667
|
return `${listboxId}-option-${highlightedIndex}`;
|
|
1638
1668
|
};
|
|
1639
1669
|
const handleBlur = (e) => {
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1670
|
+
if (!justSelectedRef.current) {
|
|
1671
|
+
const typedText = inputValue.trim().toLowerCase();
|
|
1672
|
+
const highlightedOption = getHighlightedOption();
|
|
1673
|
+
const label = getOptionLabel(highlightedOption);
|
|
1674
|
+
if (typedText === label?.toLowerCase()) {
|
|
1675
|
+
setTimeout(() => {
|
|
1676
|
+
handleOptionSelect(highlightedOption);
|
|
1677
|
+
}, 0);
|
|
1678
|
+
}
|
|
1645
1679
|
}
|
|
1646
1680
|
blurTimeoutRef.current = setTimeout(() => {
|
|
1647
1681
|
onBlur?.(e);
|
|
@@ -1652,21 +1686,25 @@ var ComboboxInner = (0, import_react24.forwardRef)(
|
|
|
1652
1686
|
switch (e.key) {
|
|
1653
1687
|
case "ArrowDown":
|
|
1654
1688
|
e.preventDefault();
|
|
1689
|
+
justSelectedRef.current = false;
|
|
1655
1690
|
setIsOpen(true);
|
|
1656
1691
|
highlightNextOption();
|
|
1657
1692
|
break;
|
|
1658
1693
|
case "ArrowUp":
|
|
1659
1694
|
e.preventDefault();
|
|
1695
|
+
justSelectedRef.current = false;
|
|
1660
1696
|
setIsOpen(true);
|
|
1661
1697
|
highlightPreviousOption();
|
|
1662
1698
|
break;
|
|
1663
1699
|
case "Home":
|
|
1664
1700
|
e.preventDefault();
|
|
1701
|
+
justSelectedRef.current = false;
|
|
1665
1702
|
setIsOpen(true);
|
|
1666
1703
|
highlightFirstOption();
|
|
1667
1704
|
break;
|
|
1668
1705
|
case "End":
|
|
1669
1706
|
e.preventDefault();
|
|
1707
|
+
justSelectedRef.current = false;
|
|
1670
1708
|
setIsOpen(true);
|
|
1671
1709
|
highlightLastOption();
|
|
1672
1710
|
break;
|
|
@@ -1707,8 +1745,16 @@ var ComboboxInner = (0, import_react24.forwardRef)(
|
|
|
1707
1745
|
},
|
|
1708
1746
|
className
|
|
1709
1747
|
);
|
|
1748
|
+
const getStatusMessage = () => {
|
|
1749
|
+
if (isLoading) return "Loading options";
|
|
1750
|
+
if (!filteredOptions || filteredOptions.length === 0) {
|
|
1751
|
+
return isChanging ? "No options found" : "";
|
|
1752
|
+
}
|
|
1753
|
+
const count = isOptionGroup(filteredOptions) ? filteredOptions.reduce((sum, group) => sum + group.options.length, 0) : filteredOptions.length;
|
|
1754
|
+
return isOpen && isChanging ? `${count} option${count === 1 ? "" : "s"} available` : "";
|
|
1755
|
+
};
|
|
1710
1756
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { id, "data-testid": "mobius-combobox__wrapper", className: classes, children: [
|
|
1711
|
-
|
|
1757
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1712
1758
|
VisuallyHidden,
|
|
1713
1759
|
{
|
|
1714
1760
|
role: "status",
|
|
@@ -1716,7 +1762,7 @@ var ComboboxInner = (0, import_react24.forwardRef)(
|
|
|
1716
1762
|
id: statusId,
|
|
1717
1763
|
elementType: "div",
|
|
1718
1764
|
className: "mobius-combobox__status",
|
|
1719
|
-
children:
|
|
1765
|
+
children: getStatusMessage()
|
|
1720
1766
|
}
|
|
1721
1767
|
),
|
|
1722
1768
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
@@ -1735,6 +1781,7 @@ var ComboboxInner = (0, import_react24.forwardRef)(
|
|
|
1735
1781
|
"aria-describedby": isLoading ? statusId : void 0,
|
|
1736
1782
|
"aria-autocomplete": "list",
|
|
1737
1783
|
"aria-haspopup": "listbox",
|
|
1784
|
+
"aria-owns": listboxId,
|
|
1738
1785
|
"aria-controls": listboxId,
|
|
1739
1786
|
"aria-expanded": isOpen,
|
|
1740
1787
|
"aria-activedescendant": highlightedIndex === -1 ? void 0 : getHighlightedOptionId(),
|
|
@@ -4382,11 +4429,12 @@ var TextOrHTML = (0, import_react79.forwardRef)(
|
|
|
4382
4429
|
...textProps
|
|
4383
4430
|
}, ref) => {
|
|
4384
4431
|
const DangerousComponent = htmlElementType;
|
|
4432
|
+
const dangerousHTML = (0, import_react79.useMemo)(() => ({ __html: text }), [text]);
|
|
4385
4433
|
const dangerousElement = /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
4386
4434
|
DangerousComponent,
|
|
4387
4435
|
{
|
|
4388
4436
|
className: htmlClassName,
|
|
4389
|
-
dangerouslySetInnerHTML:
|
|
4437
|
+
dangerouslySetInnerHTML: dangerousHTML
|
|
4390
4438
|
}
|
|
4391
4439
|
);
|
|
4392
4440
|
if (textWrapper) {
|
package/dist/esm/index.js
CHANGED
|
@@ -1464,6 +1464,8 @@ var ComboboxInner = forwardRef6(
|
|
|
1464
1464
|
const listboxId = useId4();
|
|
1465
1465
|
const statusId = useId4();
|
|
1466
1466
|
const blurTimeoutRef = useRef7(null);
|
|
1467
|
+
const userInteractedRef = useRef7(false);
|
|
1468
|
+
const justSelectedRef = useRef7(false);
|
|
1467
1469
|
const { down } = useBreakpoint();
|
|
1468
1470
|
const isMobile = down("md");
|
|
1469
1471
|
const handleFocus = (e) => {
|
|
@@ -1473,8 +1475,31 @@ var ComboboxInner = forwardRef6(
|
|
|
1473
1475
|
clearTimeout(blurTimeoutRef.current);
|
|
1474
1476
|
blurTimeoutRef.current = null;
|
|
1475
1477
|
}
|
|
1476
|
-
|
|
1478
|
+
const isNaturalFocus = userInteractedRef.current || e.relatedTarget !== null;
|
|
1479
|
+
if (userInteractedRef.current) {
|
|
1480
|
+
userInteractedRef.current = false;
|
|
1481
|
+
}
|
|
1482
|
+
if (justSelectedRef.current && !isNaturalFocus) {
|
|
1483
|
+
justSelectedRef.current = false;
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
if (isNaturalFocus) {
|
|
1487
|
+
setIsOpen(true);
|
|
1488
|
+
justSelectedRef.current = false;
|
|
1489
|
+
}
|
|
1477
1490
|
};
|
|
1491
|
+
useEffect14(() => {
|
|
1492
|
+
if (!inputRef || typeof inputRef === "function") return;
|
|
1493
|
+
const inputElement = inputRef.current;
|
|
1494
|
+
if (!inputElement) return;
|
|
1495
|
+
const handleMouseDown = () => {
|
|
1496
|
+
userInteractedRef.current = true;
|
|
1497
|
+
};
|
|
1498
|
+
inputElement.addEventListener("mousedown", handleMouseDown);
|
|
1499
|
+
return () => {
|
|
1500
|
+
inputElement.removeEventListener("mousedown", handleMouseDown);
|
|
1501
|
+
};
|
|
1502
|
+
}, [inputRef]);
|
|
1478
1503
|
useOnUnmount(() => {
|
|
1479
1504
|
if (blurTimeoutRef.current) {
|
|
1480
1505
|
clearTimeout(blurTimeoutRef.current);
|
|
@@ -1483,7 +1508,11 @@ var ComboboxInner = forwardRef6(
|
|
|
1483
1508
|
const handleInputChange = (e) => {
|
|
1484
1509
|
const newValue = e.target.value;
|
|
1485
1510
|
setInputValue(newValue);
|
|
1511
|
+
justSelectedRef.current = false;
|
|
1486
1512
|
setIsChanging(true);
|
|
1513
|
+
if (!asyncOptions) {
|
|
1514
|
+
setIsOpen(true);
|
|
1515
|
+
}
|
|
1487
1516
|
clearHighlight();
|
|
1488
1517
|
onChange?.(e);
|
|
1489
1518
|
};
|
|
@@ -1496,6 +1525,7 @@ var ComboboxInner = forwardRef6(
|
|
|
1496
1525
|
return;
|
|
1497
1526
|
}
|
|
1498
1527
|
skipNextDebounceRef.current = true;
|
|
1528
|
+
justSelectedRef.current = true;
|
|
1499
1529
|
setIsChanging(false);
|
|
1500
1530
|
setIsOpen(false);
|
|
1501
1531
|
setInputValue(val);
|
|
@@ -1526,11 +1556,15 @@ var ComboboxInner = forwardRef6(
|
|
|
1526
1556
|
return `${listboxId}-option-${highlightedIndex}`;
|
|
1527
1557
|
};
|
|
1528
1558
|
const handleBlur = (e) => {
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1559
|
+
if (!justSelectedRef.current) {
|
|
1560
|
+
const typedText = inputValue.trim().toLowerCase();
|
|
1561
|
+
const highlightedOption = getHighlightedOption();
|
|
1562
|
+
const label = getOptionLabel(highlightedOption);
|
|
1563
|
+
if (typedText === label?.toLowerCase()) {
|
|
1564
|
+
setTimeout(() => {
|
|
1565
|
+
handleOptionSelect(highlightedOption);
|
|
1566
|
+
}, 0);
|
|
1567
|
+
}
|
|
1534
1568
|
}
|
|
1535
1569
|
blurTimeoutRef.current = setTimeout(() => {
|
|
1536
1570
|
onBlur?.(e);
|
|
@@ -1541,21 +1575,25 @@ var ComboboxInner = forwardRef6(
|
|
|
1541
1575
|
switch (e.key) {
|
|
1542
1576
|
case "ArrowDown":
|
|
1543
1577
|
e.preventDefault();
|
|
1578
|
+
justSelectedRef.current = false;
|
|
1544
1579
|
setIsOpen(true);
|
|
1545
1580
|
highlightNextOption();
|
|
1546
1581
|
break;
|
|
1547
1582
|
case "ArrowUp":
|
|
1548
1583
|
e.preventDefault();
|
|
1584
|
+
justSelectedRef.current = false;
|
|
1549
1585
|
setIsOpen(true);
|
|
1550
1586
|
highlightPreviousOption();
|
|
1551
1587
|
break;
|
|
1552
1588
|
case "Home":
|
|
1553
1589
|
e.preventDefault();
|
|
1590
|
+
justSelectedRef.current = false;
|
|
1554
1591
|
setIsOpen(true);
|
|
1555
1592
|
highlightFirstOption();
|
|
1556
1593
|
break;
|
|
1557
1594
|
case "End":
|
|
1558
1595
|
e.preventDefault();
|
|
1596
|
+
justSelectedRef.current = false;
|
|
1559
1597
|
setIsOpen(true);
|
|
1560
1598
|
highlightLastOption();
|
|
1561
1599
|
break;
|
|
@@ -1596,8 +1634,16 @@ var ComboboxInner = forwardRef6(
|
|
|
1596
1634
|
},
|
|
1597
1635
|
className
|
|
1598
1636
|
);
|
|
1637
|
+
const getStatusMessage = () => {
|
|
1638
|
+
if (isLoading) return "Loading options";
|
|
1639
|
+
if (!filteredOptions || filteredOptions.length === 0) {
|
|
1640
|
+
return isChanging ? "No options found" : "";
|
|
1641
|
+
}
|
|
1642
|
+
const count = isOptionGroup(filteredOptions) ? filteredOptions.reduce((sum, group) => sum + group.options.length, 0) : filteredOptions.length;
|
|
1643
|
+
return isOpen && isChanging ? `${count} option${count === 1 ? "" : "s"} available` : "";
|
|
1644
|
+
};
|
|
1599
1645
|
return /* @__PURE__ */ jsxs7("div", { id, "data-testid": "mobius-combobox__wrapper", className: classes, children: [
|
|
1600
|
-
|
|
1646
|
+
/* @__PURE__ */ jsx12(
|
|
1601
1647
|
VisuallyHidden,
|
|
1602
1648
|
{
|
|
1603
1649
|
role: "status",
|
|
@@ -1605,7 +1651,7 @@ var ComboboxInner = forwardRef6(
|
|
|
1605
1651
|
id: statusId,
|
|
1606
1652
|
elementType: "div",
|
|
1607
1653
|
className: "mobius-combobox__status",
|
|
1608
|
-
children:
|
|
1654
|
+
children: getStatusMessage()
|
|
1609
1655
|
}
|
|
1610
1656
|
),
|
|
1611
1657
|
/* @__PURE__ */ jsx12(
|
|
@@ -1624,6 +1670,7 @@ var ComboboxInner = forwardRef6(
|
|
|
1624
1670
|
"aria-describedby": isLoading ? statusId : void 0,
|
|
1625
1671
|
"aria-autocomplete": "list",
|
|
1626
1672
|
"aria-haspopup": "listbox",
|
|
1673
|
+
"aria-owns": listboxId,
|
|
1627
1674
|
"aria-controls": listboxId,
|
|
1628
1675
|
"aria-expanded": isOpen,
|
|
1629
1676
|
"aria-activedescendant": highlightedIndex === -1 ? void 0 : getHighlightedOptionId(),
|
|
@@ -4302,7 +4349,7 @@ var TextArea = forwardRef52((props, ref) => {
|
|
|
4302
4349
|
TextArea.displayName = "TextArea";
|
|
4303
4350
|
|
|
4304
4351
|
// src/components/TextOrHTML/TextOrHTML.tsx
|
|
4305
|
-
import { forwardRef as forwardRef53 } from "react";
|
|
4352
|
+
import { forwardRef as forwardRef53, useMemo as useMemo5 } from "react";
|
|
4306
4353
|
import { jsx as jsx68 } from "react/jsx-runtime";
|
|
4307
4354
|
var TextOrHTML = forwardRef53(
|
|
4308
4355
|
({
|
|
@@ -4313,11 +4360,12 @@ var TextOrHTML = forwardRef53(
|
|
|
4313
4360
|
...textProps
|
|
4314
4361
|
}, ref) => {
|
|
4315
4362
|
const DangerousComponent = htmlElementType;
|
|
4363
|
+
const dangerousHTML = useMemo5(() => ({ __html: text }), [text]);
|
|
4316
4364
|
const dangerousElement = /* @__PURE__ */ jsx68(
|
|
4317
4365
|
DangerousComponent,
|
|
4318
4366
|
{
|
|
4319
4367
|
className: htmlClassName,
|
|
4320
|
-
dangerouslySetInnerHTML:
|
|
4368
|
+
dangerouslySetInnerHTML: dangerousHTML
|
|
4321
4369
|
}
|
|
4322
4370
|
);
|
|
4323
4371
|
if (textWrapper) {
|