@oatfi/ui 0.3.0 → 0.5.0

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
@@ -1,6 +1,6 @@
1
- import { createTheme, ThemeProvider as ThemeProvider$2 } from '@mui/material/styles';
1
+ import { createTheme, ThemeProvider as ThemeProvider$2, useTheme as useTheme$2, alpha } from '@mui/material/styles';
2
2
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
- import { useMemo, useId, useRef, useState } from 'react';
3
+ import React, { useMemo, useId, useRef, useState } from 'react';
4
4
  import styled, { createGlobalStyle, ThemeProvider as ThemeProvider$1, useTheme as useTheme$1 } from 'styled-components';
5
5
  import { TextField, InputAdornment, IconButton, FormControl, InputLabel as InputLabel$1, Select, MenuItem, FormHelperText, Autocomplete, Box, CircularProgress } from '@mui/material';
6
6
  import CalendarMonthIcon from '@mui/icons-material/CalendarMonth';
@@ -10,6 +10,17 @@ import IconButton$1 from '@mui/material/IconButton';
10
10
  import Menu from '@mui/material/Menu';
11
11
  import MenuItem$1 from '@mui/material/MenuItem';
12
12
  import MoreVertIcon from '@mui/icons-material/MoreVert';
13
+ import DescriptionIcon from '@mui/icons-material/Description';
14
+ import CircularProgress$1 from '@mui/material/CircularProgress';
15
+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
16
+ import LinkIcon from '@mui/icons-material/Link';
17
+ import RefreshIcon from '@mui/icons-material/Refresh';
18
+ import Box$1 from '@mui/material/Box';
19
+ import Button$1 from '@mui/material/Button';
20
+ import CheckRoundedIcon from '@mui/icons-material/CheckRounded';
21
+ import Stack from '@mui/material/Stack';
22
+ import LockIcon from '@mui/icons-material/Lock';
23
+ import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
13
24
 
14
25
  const defaultTheme = {
15
26
  colors: {
@@ -429,7 +440,7 @@ const Container = styled.div`
429
440
  max-width: 1000px;
430
441
  margin: 0 auto;
431
442
  `;
432
- const Content = styled.div`
443
+ const Content$1 = styled.div`
433
444
  margin-top: 1.5rem;
434
445
  margin-bottom: 1.5rem;
435
446
  `;
@@ -1023,6 +1034,14 @@ function SearchDropdown({
1023
1034
  );
1024
1035
  }
1025
1036
 
1037
+ function formatFileSize(bytes) {
1038
+ if (bytes === 0) return "0 Bytes";
1039
+ const k = 1024;
1040
+ const sizes = ["Bytes", "KB", "MB", "GB"];
1041
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
1042
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
1043
+ }
1044
+
1026
1045
  const FileInputContainer = styled.div`
1027
1046
  display: flex;
1028
1047
  flex-direction: column;
@@ -1107,13 +1126,6 @@ const FileRequirements = styled.div`
1107
1126
  border: 1px solid ${({ theme }) => theme.border.color};
1108
1127
  border-radius: ${({ theme }) => theme.border.radius};
1109
1128
  `;
1110
- const formatFileSize = (bytes) => {
1111
- if (bytes === 0) return "0 Bytes";
1112
- const k = 1024;
1113
- const sizes = ["Bytes", "KB", "MB", "GB"];
1114
- const i = Math.floor(Math.log(bytes) / Math.log(k));
1115
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
1116
- };
1117
1129
  function FileInput({
1118
1130
  label,
1119
1131
  error,
@@ -1481,6 +1493,46 @@ function Loader({ className, size, label = "Loading", testId }) {
1481
1493
  );
1482
1494
  }
1483
1495
 
1496
+ const Root$1 = styled.footer`
1497
+ margin-top: 2rem;
1498
+ padding-top: 0.75rem;
1499
+ border-top: ${({ theme }) => `${theme.border.width} solid ${theme.colors.border}`};
1500
+ text-align: center;
1501
+ font-family: ${({ theme }) => theme.typography.fontFamily};
1502
+ font-size: 0.8125rem;
1503
+ line-height: 1.4;
1504
+ color: ${({ theme }) => theme.colors.secondary};
1505
+ `;
1506
+ const Title = styled.p`
1507
+ margin: 0 0 0.25rem;
1508
+ font-weight: 600;
1509
+ color: ${({ theme }) => theme.colors.primary};
1510
+ `;
1511
+ const Anchor = styled.a`
1512
+ color: ${({ theme }) => theme.colors.accent};
1513
+ text-decoration: none;
1514
+
1515
+ &:hover,
1516
+ &:focus-visible {
1517
+ text-decoration: underline;
1518
+ }
1519
+ `;
1520
+ function Footnote({ title, text, links = [], className, testId }) {
1521
+ return /* @__PURE__ */ jsxs(Root$1, { className, "data-testid": testId, children: [
1522
+ title && /* @__PURE__ */ jsx(Title, { children: title }),
1523
+ /* @__PURE__ */ jsxs("p", { style: { margin: 0 }, children: [
1524
+ text && /* @__PURE__ */ jsxs(Fragment, { children: [
1525
+ text,
1526
+ " "
1527
+ ] }),
1528
+ links.map((link, index) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
1529
+ index > 0 && /* @__PURE__ */ jsx(Fragment, { children: " \xB7 " }),
1530
+ /* @__PURE__ */ jsx(Anchor, { href: link.href, target: "_blank", rel: "noopener noreferrer", children: link.label })
1531
+ ] }, link.href))
1532
+ ] })
1533
+ ] });
1534
+ }
1535
+
1484
1536
  function DotsMenu({
1485
1537
  options,
1486
1538
  iconSize = "medium",
@@ -1534,6 +1586,768 @@ function DotsMenu({
1534
1586
  ] });
1535
1587
  }
1536
1588
 
1589
+ const AsteriskMark = styled.sup`
1590
+ color: ${({ theme }) => theme.colors.accent};
1591
+ font-weight: 600;
1592
+ margin-left: 1px;
1593
+ font-size: 0.95em;
1594
+ `;
1595
+ const AsteriskNote = styled.p`
1596
+ font-size: 12px;
1597
+ color: ${({ theme }) => theme.colors.secondary};
1598
+ margin: 14px 4px 0;
1599
+ line-height: 1.5;
1600
+ font-style: italic;
1601
+
1602
+ .asterisk {
1603
+ font-style: normal;
1604
+ color: ${({ theme }) => theme.colors.accent};
1605
+ font-weight: 600;
1606
+ margin-right: 2px;
1607
+ }
1608
+ `;
1609
+
1610
+ const background = (theme, variant) => {
1611
+ if (variant === "filled") return theme.colors.accent;
1612
+ if (variant === "success" || variant === "neutral") return theme.colors.background;
1613
+ return `${theme.colors.accent}14`;
1614
+ };
1615
+ const foreground = (theme, variant) => {
1616
+ if (variant === "filled") return theme.colors.background;
1617
+ if (variant === "success") return theme.colors.success;
1618
+ if (variant === "neutral") return theme.colors.secondary;
1619
+ return theme.colors.accent;
1620
+ };
1621
+ const outline = (theme, variant) => {
1622
+ if (variant === "success") return `1px solid ${theme.colors.success}`;
1623
+ if (variant === "neutral") return `1px solid ${theme.colors.border}`;
1624
+ if (variant === "filled") return `1px solid ${theme.colors.accent}`;
1625
+ return "none";
1626
+ };
1627
+ const Badge = styled.span`
1628
+ font-size: 10px;
1629
+ padding: 2px 8px;
1630
+ border-radius: 4px;
1631
+ font-weight: 600;
1632
+ letter-spacing: 0.04em;
1633
+ text-transform: uppercase;
1634
+ white-space: nowrap;
1635
+ background: ${({ theme, $variant }) => background(theme, $variant)};
1636
+ color: ${({ theme, $variant }) => foreground(theme, $variant)};
1637
+ border: ${({ theme, $variant }) => outline(theme, $variant)};
1638
+ `;
1639
+
1640
+ const Zone = styled.div`
1641
+ display: flex;
1642
+ flex-direction: column;
1643
+ align-items: center;
1644
+ justify-content: center;
1645
+ gap: 4px;
1646
+ width: 100%;
1647
+ min-height: 100px;
1648
+ border: 1px dashed ${({ theme }) => theme.colors.border};
1649
+ border-radius: ${({ theme }) => theme.border.radius};
1650
+ padding: 16px;
1651
+ text-align: center;
1652
+ background: ${({ theme }) => theme.colors.surface};
1653
+ cursor: pointer;
1654
+ transition:
1655
+ border-color 0.15s ease,
1656
+ background 0.15s ease;
1657
+
1658
+ ${({ $dragging, theme }) => $dragging && `
1659
+ border-color: ${theme.colors.accent};
1660
+ background: ${theme.colors.accent}14;
1661
+ `}
1662
+
1663
+ &:hover {
1664
+ border-color: ${({ theme }) => theme.colors.accent};
1665
+ background: ${({ theme }) => `${theme.colors.accent}14`};
1666
+ }
1667
+
1668
+ &:focus-visible {
1669
+ outline: none;
1670
+ border-color: ${({ theme }) => theme.colors.accent};
1671
+ box-shadow: 0 0 0 3px ${({ theme }) => `${theme.colors.accent}26`};
1672
+ }
1673
+ `;
1674
+ const ZoneIcon = styled(CloudUploadIcon)`
1675
+ color: ${({ theme }) => theme.colors.secondary};
1676
+ `;
1677
+ const ZoneText = styled.p`
1678
+ font-size: 13px;
1679
+ margin: 0;
1680
+ color: ${({ theme }) => theme.colors.primary};
1681
+
1682
+ span {
1683
+ color: ${({ theme }) => theme.colors.accent};
1684
+ }
1685
+ `;
1686
+ const ZoneHint = styled.p`
1687
+ font-size: 11px;
1688
+ color: ${({ theme }) => theme.colors.secondary};
1689
+ margin: 0;
1690
+ `;
1691
+ const HiddenInput = styled.input`
1692
+ display: none;
1693
+ `;
1694
+ const FileList = styled.div`
1695
+ margin-top: 10px;
1696
+ display: flex;
1697
+ flex-direction: column;
1698
+ gap: 6px;
1699
+ `;
1700
+ const FileItem = styled.div`
1701
+ display: flex;
1702
+ align-items: center;
1703
+ gap: 10px;
1704
+ padding: 8px 12px;
1705
+ background: ${({ theme }) => theme.colors.background};
1706
+ border: 1px solid ${({ theme }) => theme.colors.border};
1707
+ border-radius: 4px;
1708
+ font-size: 13px;
1709
+
1710
+ .file-icon {
1711
+ color: ${({ theme }) => theme.colors.secondary};
1712
+ font-size: 18px;
1713
+ flex-shrink: 0;
1714
+ }
1715
+
1716
+ .file-name {
1717
+ flex: 1;
1718
+ min-width: 0;
1719
+ overflow: hidden;
1720
+ text-overflow: ellipsis;
1721
+ white-space: nowrap;
1722
+ color: ${({ theme }) => theme.colors.primary};
1723
+ }
1724
+
1725
+ .file-size {
1726
+ color: ${({ theme }) => theme.colors.secondary};
1727
+ font-size: 12px;
1728
+ flex-shrink: 0;
1729
+ }
1730
+ `;
1731
+ const RemoveButton = styled.button`
1732
+ display: inline-flex;
1733
+ align-items: center;
1734
+ justify-content: center;
1735
+ width: 24px;
1736
+ height: 24px;
1737
+ padding: 0;
1738
+ border: none;
1739
+ background: transparent;
1740
+ color: ${({ theme }) => theme.colors.secondary};
1741
+ border-radius: 4px;
1742
+ cursor: pointer;
1743
+ flex-shrink: 0;
1744
+ transition:
1745
+ background 0.15s ease,
1746
+ color 0.15s ease;
1747
+
1748
+ &:hover {
1749
+ background: ${({ theme }) => theme.colors.surface};
1750
+ color: ${({ theme }) => theme.colors.error};
1751
+ }
1752
+
1753
+ &:disabled {
1754
+ cursor: not-allowed;
1755
+ opacity: 0.6;
1756
+ }
1757
+
1758
+ svg {
1759
+ font-size: 16px;
1760
+ }
1761
+ `;
1762
+ function UploadZone({
1763
+ accept,
1764
+ hint,
1765
+ files = [],
1766
+ onAdd,
1767
+ onRemove,
1768
+ removingIds,
1769
+ disabled = false,
1770
+ inputId,
1771
+ testId
1772
+ }) {
1773
+ const inputRef = useRef(null);
1774
+ const [dragging, setDragging] = useState(false);
1775
+ const openPicker = () => {
1776
+ if (!disabled) inputRef.current?.click();
1777
+ };
1778
+ const handleKeyDown = (event) => {
1779
+ if (event.key === "Enter" || event.key === " ") {
1780
+ event.preventDefault();
1781
+ openPicker();
1782
+ }
1783
+ };
1784
+ const handleChange = (event) => {
1785
+ if (event.target.files?.length) onAdd(event.target.files);
1786
+ event.target.value = "";
1787
+ };
1788
+ const handleDrop = (event) => {
1789
+ event.preventDefault();
1790
+ setDragging(false);
1791
+ if (disabled) return;
1792
+ if (event.dataTransfer.files?.length) onAdd(event.dataTransfer.files);
1793
+ };
1794
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1795
+ /* @__PURE__ */ jsxs(
1796
+ Zone,
1797
+ {
1798
+ role: "button",
1799
+ tabIndex: disabled ? -1 : 0,
1800
+ "aria-disabled": disabled,
1801
+ $dragging: dragging,
1802
+ onClick: openPicker,
1803
+ onKeyDown: handleKeyDown,
1804
+ onDragOver: (event) => {
1805
+ event.preventDefault();
1806
+ if (!disabled) setDragging(true);
1807
+ },
1808
+ onDragLeave: () => setDragging(false),
1809
+ onDrop: handleDrop,
1810
+ children: [
1811
+ /* @__PURE__ */ jsx(
1812
+ HiddenInput,
1813
+ {
1814
+ id: inputId,
1815
+ ref: inputRef,
1816
+ type: "file",
1817
+ multiple: true,
1818
+ accept,
1819
+ disabled,
1820
+ onChange: handleChange,
1821
+ "data-testid": testId
1822
+ }
1823
+ ),
1824
+ /* @__PURE__ */ jsx(ZoneIcon, { fontSize: "medium", "aria-hidden": "true" }),
1825
+ /* @__PURE__ */ jsxs(ZoneText, { children: [
1826
+ "Drop files or ",
1827
+ /* @__PURE__ */ jsx("span", { children: "browse" })
1828
+ ] }),
1829
+ /* @__PURE__ */ jsx(ZoneHint, { children: hint })
1830
+ ]
1831
+ }
1832
+ ),
1833
+ files.length > 0 && /* @__PURE__ */ jsx(FileList, { children: files.map((file) => {
1834
+ const isRemoving = removingIds?.has(file.id);
1835
+ return /* @__PURE__ */ jsxs(FileItem, { children: [
1836
+ /* @__PURE__ */ jsx(DescriptionIcon, { className: "file-icon", "aria-hidden": "true" }),
1837
+ /* @__PURE__ */ jsx("span", { className: "file-name", children: file.fileName }),
1838
+ /* @__PURE__ */ jsx("span", { className: "file-size", children: formatFileSize(file.fileSize) }),
1839
+ isRemoving ? /* @__PURE__ */ jsx(CircularProgress$1, { size: 16, color: "secondary" }) : /* @__PURE__ */ jsx(
1840
+ RemoveButton,
1841
+ {
1842
+ type: "button",
1843
+ "aria-label": `Remove ${file.fileName}`,
1844
+ disabled,
1845
+ onClick: () => onRemove(file.id),
1846
+ children: /* @__PURE__ */ jsx(CloseIcon, { "aria-hidden": "true" })
1847
+ }
1848
+ )
1849
+ ] }, file.id);
1850
+ }) })
1851
+ ] });
1852
+ }
1853
+
1854
+ const Wrapper = styled.div`
1855
+ background: ${({ theme }) => theme.colors.background};
1856
+ border: 1px solid ${({ theme, $open }) => $open ? theme.colors.secondary : theme.colors.border};
1857
+ border-radius: ${({ theme }) => theme.border.radius};
1858
+ overflow: hidden;
1859
+ transition: border-color 0.15s ease;
1860
+
1861
+ ${({ $open }) => $open && "grid-column: 1 / -1;"}
1862
+ `;
1863
+ const Summary = styled.button`
1864
+ width: 100%;
1865
+ text-align: left;
1866
+ cursor: pointer;
1867
+ padding: 12px 16px;
1868
+ display: flex;
1869
+ align-items: center;
1870
+ gap: 12px;
1871
+ background: transparent;
1872
+ border: none;
1873
+ transition: background 0.15s ease;
1874
+
1875
+ &:hover {
1876
+ background: ${({ theme }) => theme.colors.surface};
1877
+ }
1878
+
1879
+ &:focus-visible {
1880
+ outline: none;
1881
+ box-shadow: inset 0 0 0 2px ${({ theme }) => `${theme.colors.accent}40`};
1882
+ }
1883
+ `;
1884
+ const SummaryText = styled.div`
1885
+ flex: 1;
1886
+ min-width: 0;
1887
+ `;
1888
+ const Chevron = styled(ExpandMoreIcon)`
1889
+ color: ${({ theme }) => theme.colors.secondary};
1890
+ transition: transform 0.2s ease;
1891
+ transform: rotate(${({ $open }) => $open ? "180deg" : "0deg"});
1892
+ flex-shrink: 0;
1893
+ `;
1894
+ const Content = styled.div`
1895
+ padding: 12px 16px 14px;
1896
+ `;
1897
+ const Note = styled(AsteriskNote)`
1898
+ margin: 4px 0 0;
1899
+ `;
1900
+ function CollapsibleSource({
1901
+ title,
1902
+ desc,
1903
+ note,
1904
+ open = false,
1905
+ onToggle,
1906
+ children,
1907
+ testId
1908
+ }) {
1909
+ const contentId = useId();
1910
+ return /* @__PURE__ */ jsxs(Wrapper, { $open: open, children: [
1911
+ /* @__PURE__ */ jsxs(
1912
+ Summary,
1913
+ {
1914
+ type: "button",
1915
+ "aria-expanded": open,
1916
+ "aria-controls": contentId,
1917
+ onClick: onToggle,
1918
+ "data-testid": testId,
1919
+ children: [
1920
+ /* @__PURE__ */ jsxs(SummaryText, { children: [
1921
+ /* @__PURE__ */ jsxs(FormSubtitle, { style: { margin: 0 }, children: [
1922
+ title,
1923
+ note ? /* @__PURE__ */ jsx(AsteriskMark, { "aria-hidden": "true", children: "*" }) : null
1924
+ ] }),
1925
+ desc ? /* @__PURE__ */ jsx(Body100, { color: "secondary", style: { margin: "2px 0 0" }, children: desc }) : null,
1926
+ note ? /* @__PURE__ */ jsxs(Note, { children: [
1927
+ /* @__PURE__ */ jsx("span", { className: "asterisk", "aria-hidden": "true", children: "*" }),
1928
+ note
1929
+ ] }) : null
1930
+ ] }),
1931
+ /* @__PURE__ */ jsx(Chevron, { $open: open, "aria-hidden": "true" })
1932
+ ]
1933
+ }
1934
+ ),
1935
+ open && /* @__PURE__ */ jsx(Content, { id: contentId, children })
1936
+ ] });
1937
+ }
1938
+
1939
+ const maskOf$1 = (plaidData) => {
1940
+ const account = plaidData?.accounts?.[0];
1941
+ return account?.mask || account?.accountMask || null;
1942
+ };
1943
+ function PlaidTile({ plaidData, onConnect, isConnecting = false, testId }) {
1944
+ const { palette, shape } = useTheme$2();
1945
+ const connected = Boolean(plaidData);
1946
+ const institutionName = plaidData?.institution?.name || "Your bank";
1947
+ const mask = maskOf$1(plaidData);
1948
+ const accentColor = connected ? palette.success.dark : palette.primary.main;
1949
+ return /* @__PURE__ */ jsxs(
1950
+ Box$1,
1951
+ {
1952
+ component: "section",
1953
+ "aria-labelledby": "plaid-tile-title",
1954
+ sx: {
1955
+ display: "flex",
1956
+ alignItems: "center",
1957
+ justifyContent: "space-between",
1958
+ gap: "14px",
1959
+ flexWrap: "wrap",
1960
+ padding: "16px 18px",
1961
+ marginBottom: "14px",
1962
+ borderRadius: `${shape.borderRadius}px`,
1963
+ border: `1px solid ${accentColor}`,
1964
+ backgroundColor: connected ? alpha(palette.success.main, 0.08) : palette.background.default,
1965
+ transition: "border-color 0.15s ease, background 0.15s ease"
1966
+ },
1967
+ children: [
1968
+ /* @__PURE__ */ jsxs(Box$1, { sx: { flex: 1, minWidth: 220 }, children: [
1969
+ /* @__PURE__ */ jsxs(Box$1, { sx: { display: "flex", alignItems: "center", gap: "10px", marginBottom: "2px" }, children: [
1970
+ /* @__PURE__ */ jsx(FormSubtitle, { id: "plaid-tile-title", style: { margin: 0, fontWeight: 600 }, children: connected ? "Connected via Plaid" : "Connect via Plaid" }),
1971
+ /* @__PURE__ */ jsx(Badge, { $variant: connected ? "success" : "info", children: connected ? "Verified" : "Recommended" })
1972
+ ] }),
1973
+ connected ? /* @__PURE__ */ jsxs(Body100, { style: { margin: 0, color: palette.success.dark, fontWeight: 500 }, children: [
1974
+ institutionName,
1975
+ mask ? ` \xB7\xB7\xB7\xB7${mask}` : ""
1976
+ ] }) : /* @__PURE__ */ jsx(Body100, { color: "secondary", style: { margin: 0 }, children: "Securely link your bank in seconds. Best signal for fastest decisions." })
1977
+ ] }),
1978
+ connected ? /* @__PURE__ */ jsx(
1979
+ Button$1,
1980
+ {
1981
+ size: "small",
1982
+ variant: "outlined",
1983
+ color: "inherit",
1984
+ type: "button",
1985
+ onClick: onConnect,
1986
+ disabled: isConnecting,
1987
+ "data-testid": testId,
1988
+ startIcon: /* @__PURE__ */ jsx(RefreshIcon, { fontSize: "small" }),
1989
+ sx: { flexShrink: 0, textTransform: "none" },
1990
+ children: isConnecting ? "Connecting\u2026" : "Reconnect"
1991
+ }
1992
+ ) : /* @__PURE__ */ jsx(
1993
+ Button$1,
1994
+ {
1995
+ size: "small",
1996
+ variant: "contained",
1997
+ color: "primary",
1998
+ type: "button",
1999
+ onClick: onConnect,
2000
+ disabled: isConnecting,
2001
+ "data-testid": testId,
2002
+ startIcon: /* @__PURE__ */ jsx(LinkIcon, { fontSize: "small" }),
2003
+ sx: { flexShrink: 0, textTransform: "none" },
2004
+ children: isConnecting ? "Connecting\u2026" : "Connect bank account"
2005
+ }
2006
+ )
2007
+ ]
2008
+ }
2009
+ );
2010
+ }
2011
+
2012
+ const Root = styled.div`
2013
+ background-color: ${({ theme }) => theme.colors.surface};
2014
+ border: 1px solid ${({ theme }) => theme.colors.border};
2015
+ border-radius: ${({ theme }) => theme.border.radius};
2016
+ padding: 1.5rem;
2017
+ overflow-y: auto;
2018
+ max-height: 400px;
2019
+ margin-bottom: 1rem;
2020
+ font-size: 14px;
2021
+ line-height: 1.6;
2022
+ `;
2023
+ function TermsDocument({ html, className, testId }) {
2024
+ return /* @__PURE__ */ jsx(
2025
+ Root,
2026
+ {
2027
+ className,
2028
+ "data-testid": testId,
2029
+ dangerouslySetInnerHTML: { __html: html }
2030
+ }
2031
+ );
2032
+ }
2033
+ const HelperText = styled.span`
2034
+ display: block;
2035
+ font-size: 12.5px;
2036
+ color: ${({ theme }) => theme.colors.secondary};
2037
+ text-align: right;
2038
+ margin-top: 0.5rem;
2039
+ `;
2040
+
2041
+ const DECLINED = /* @__PURE__ */ new Set([
2042
+ "CLOSED_NO_DECISION",
2043
+ "DECLINED",
2044
+ "DENIED",
2045
+ "ERROR",
2046
+ "N/A",
2047
+ "REJECTED"
2048
+ ]);
2049
+ function UnderwritingStatus({
2050
+ status,
2051
+ creditLimit,
2052
+ children,
2053
+ testId
2054
+ }) {
2055
+ if (status === "PROCESSING") {
2056
+ return /* @__PURE__ */ jsxs("div", { "data-testid": testId, children: [
2057
+ /* @__PURE__ */ jsx(H3, { children: "Your application is being reviewed" }),
2058
+ /* @__PURE__ */ jsxs(Stack, { width: "100%", alignItems: "center", gap: "16px", children: [
2059
+ /* @__PURE__ */ jsx(Loader, {}),
2060
+ /* @__PURE__ */ jsx(Body200, { children: "We are underwriting your business. This process can take a minute or two." })
2061
+ ] })
2062
+ ] });
2063
+ }
2064
+ if (status === "APPROVED") {
2065
+ return /* @__PURE__ */ jsxs("div", { "data-testid": testId, children: [
2066
+ /* @__PURE__ */ jsx(H3, { children: "Congrats!" }),
2067
+ /* @__PURE__ */ jsxs(Body200, { children: [
2068
+ "You have been approved.",
2069
+ creditLimit ? /* @__PURE__ */ jsxs(Fragment, { children: [
2070
+ " Your credit limit is: ",
2071
+ creditLimit
2072
+ ] }) : null
2073
+ ] }),
2074
+ /* @__PURE__ */ jsx(Box$1, { sx: { display: "flex", justifyContent: "center", alignItems: "center" }, children: /* @__PURE__ */ jsx(CheckRoundedIcon, { color: "success", sx: { fontSize: "5rem" } }) }),
2075
+ children
2076
+ ] });
2077
+ }
2078
+ if (status && DECLINED.has(status)) {
2079
+ return /* @__PURE__ */ jsxs("div", { "data-testid": testId, children: [
2080
+ /* @__PURE__ */ jsx(H3, { children: "Sorry, we cannot approve your application" }),
2081
+ /* @__PURE__ */ jsx(Body200, { children: "We are sorry to inform you that we cannot approve your application. Please try again later." })
2082
+ ] });
2083
+ }
2084
+ return /* @__PURE__ */ jsxs("div", { "data-testid": testId, children: [
2085
+ /* @__PURE__ */ jsx(H3, { children: "Your application is being reviewed" }),
2086
+ /* @__PURE__ */ jsx(Body200, { children: "We are reviewing your application and will reach out within 2 business days." })
2087
+ ] });
2088
+ }
2089
+
2090
+ const MethodCard = styled.div`
2091
+ display: flex;
2092
+ gap: 12px;
2093
+ align-items: flex-start;
2094
+ padding: 14px 16px;
2095
+ margin-bottom: 10px;
2096
+ border-radius: ${({ theme }) => theme.border.radius};
2097
+ border: 1px solid
2098
+ ${({ theme, $default }) => $default ? theme.colors.accent : theme.colors.border};
2099
+ background: ${({ theme, $default, $readonly }) => $default ? `${theme.colors.accent}14` : $readonly ? theme.colors.surface : theme.colors.background};
2100
+ transition:
2101
+ border-color 0.15s ease,
2102
+ background 0.15s ease;
2103
+ `;
2104
+ const MethodBody = styled.div`
2105
+ flex: 1;
2106
+ min-width: 0;
2107
+ `;
2108
+ const MethodHeader = styled.div`
2109
+ display: flex;
2110
+ align-items: center;
2111
+ justify-content: space-between;
2112
+ gap: 8px;
2113
+ margin-bottom: ${({ $tight }) => $tight ? "6px" : "12px"};
2114
+ `;
2115
+ const MethodTitle = styled.span`
2116
+ display: flex;
2117
+ align-items: center;
2118
+ gap: 8px;
2119
+ flex-wrap: wrap;
2120
+ font-size: 14px;
2121
+ font-weight: 600;
2122
+ color: ${({ theme }) => theme.colors.primary};
2123
+ `;
2124
+ const FieldsGrid = styled.div`
2125
+ display: grid;
2126
+ grid-template-columns: 1fr 1fr;
2127
+ gap: 10px;
2128
+
2129
+ @media (max-width: 540px) {
2130
+ grid-template-columns: 1fr;
2131
+ }
2132
+ `;
2133
+ const Banner = styled.div`
2134
+ display: flex;
2135
+ gap: 10px;
2136
+ align-items: flex-start;
2137
+ padding: 10px 14px;
2138
+ background: ${({ theme }) => `${theme.colors.accent}14`};
2139
+ border-left: 3px solid ${({ theme }) => theme.colors.accent};
2140
+ border-radius: ${({ theme }) => theme.border.radius};
2141
+ margin-bottom: 1.25rem;
2142
+
2143
+ svg {
2144
+ color: ${({ theme }) => theme.colors.accent};
2145
+ flex-shrink: 0;
2146
+ margin-top: 1px;
2147
+ }
2148
+
2149
+ p {
2150
+ font-size: 13px;
2151
+ color: ${({ theme }) => theme.colors.accent};
2152
+ margin: 0;
2153
+ line-height: 1.5;
2154
+ }
2155
+ `;
2156
+ const FooterActions = styled.div`
2157
+ display: flex;
2158
+ justify-content: space-between;
2159
+ align-items: center;
2160
+ gap: 12px;
2161
+ margin-top: 1.25rem;
2162
+ flex-wrap: wrap;
2163
+
2164
+ button {
2165
+ margin-top: 0;
2166
+ }
2167
+ `;
2168
+ const FooterRight = styled.div`
2169
+ display: flex;
2170
+ align-items: center;
2171
+ gap: 14px;
2172
+ `;
2173
+
2174
+ const maskOf = (plaidData) => {
2175
+ const account = plaidData?.accounts?.[0];
2176
+ return account?.mask || account?.accountMask || null;
2177
+ };
2178
+ function PlaidMethodCard({
2179
+ plaidData,
2180
+ isDefault = false,
2181
+ onSelectDefault,
2182
+ name = "default-method",
2183
+ testId
2184
+ }) {
2185
+ const institutionName = plaidData?.institution?.name || "Your bank";
2186
+ const mask = maskOf(plaidData);
2187
+ return /* @__PURE__ */ jsxs(MethodCard, { as: "label", htmlFor: "default-plaid", $default: isDefault, $readonly: true, children: [
2188
+ /* @__PURE__ */ jsx(
2189
+ RadioInput,
2190
+ {
2191
+ type: "radio",
2192
+ id: "default-plaid",
2193
+ name,
2194
+ checked: isDefault,
2195
+ onChange: onSelectDefault,
2196
+ "data-testid": testId
2197
+ }
2198
+ ),
2199
+ /* @__PURE__ */ jsxs(MethodBody, { children: [
2200
+ /* @__PURE__ */ jsxs(MethodHeader, { $tight: true, children: [
2201
+ /* @__PURE__ */ jsxs(MethodTitle, { children: [
2202
+ institutionName,
2203
+ /* @__PURE__ */ jsx(Badge, { $variant: "neutral", children: "Via Plaid" }),
2204
+ isDefault && /* @__PURE__ */ jsx(Badge, { $variant: "filled", children: "Default" })
2205
+ ] }),
2206
+ /* @__PURE__ */ jsx(LockIcon, { fontSize: "small", titleAccess: "Managed via Plaid" })
2207
+ ] }),
2208
+ /* @__PURE__ */ jsx(Body200, { color: "secondary", style: { margin: 0 }, children: mask ? `Account \xB7\xB7\xB7\xB7${mask}` : "Connected account" })
2209
+ ] })
2210
+ ] });
2211
+ }
2212
+
2213
+ function ManualMethodCard({
2214
+ index,
2215
+ value,
2216
+ isDefault = false,
2217
+ trashDisabled = false,
2218
+ disabled = false,
2219
+ accountError,
2220
+ routingError,
2221
+ onSelectDefault,
2222
+ onChangeField,
2223
+ onBlurField,
2224
+ onRemove,
2225
+ name = "default-method"
2226
+ }) {
2227
+ const radioId = `default-${value.id}`;
2228
+ return /* @__PURE__ */ jsxs(MethodCard, { $default: isDefault, children: [
2229
+ /* @__PURE__ */ jsx(
2230
+ RadioInput,
2231
+ {
2232
+ type: "radio",
2233
+ id: radioId,
2234
+ name,
2235
+ checked: isDefault,
2236
+ onChange: onSelectDefault,
2237
+ disabled
2238
+ }
2239
+ ),
2240
+ /* @__PURE__ */ jsxs(MethodBody, { children: [
2241
+ /* @__PURE__ */ jsxs(MethodHeader, { children: [
2242
+ /* @__PURE__ */ jsxs(MethodTitle, { children: [
2243
+ /* @__PURE__ */ jsxs(Body200, { as: "label", htmlFor: radioId, style: { margin: 0, cursor: "pointer" }, children: [
2244
+ "Account ",
2245
+ index + 1
2246
+ ] }),
2247
+ isDefault && /* @__PURE__ */ jsx(Badge, { $variant: "filled", children: "Default" })
2248
+ ] }),
2249
+ /* @__PURE__ */ jsx(
2250
+ IconButton$1,
2251
+ {
2252
+ size: "small",
2253
+ type: "button",
2254
+ onClick: onRemove,
2255
+ disabled: disabled || trashDisabled,
2256
+ "aria-label": "Remove this account",
2257
+ title: trashDisabled ? "At least one account is required" : "Remove this account",
2258
+ children: /* @__PURE__ */ jsx(DeleteOutlineIcon, { fontSize: "small" })
2259
+ }
2260
+ )
2261
+ ] }),
2262
+ /* @__PURE__ */ jsxs(FieldsGrid, { children: [
2263
+ /* @__PURE__ */ jsx("div", { onBlur: () => onBlurField("account"), children: /* @__PURE__ */ jsx(
2264
+ TextInput,
2265
+ {
2266
+ label: "Account number",
2267
+ placeholder: "Account number",
2268
+ value: value.account,
2269
+ onChange: (next) => onChangeField("account", next),
2270
+ error: accountError,
2271
+ disabled,
2272
+ onlyNumbers: true
2273
+ }
2274
+ ) }),
2275
+ /* @__PURE__ */ jsx("div", { onBlur: () => onBlurField("routing"), children: /* @__PURE__ */ jsx(
2276
+ TextInput,
2277
+ {
2278
+ label: "Routing number",
2279
+ placeholder: "Routing number",
2280
+ value: value.routing,
2281
+ onChange: (next) => onChangeField("routing", next),
2282
+ error: routingError,
2283
+ disabled,
2284
+ onlyNumbers: true
2285
+ }
2286
+ ) })
2287
+ ] })
2288
+ ] })
2289
+ ] });
2290
+ }
2291
+
2292
+ const ConsentRow = styled.label`
2293
+ display: flex;
2294
+ align-items: center;
2295
+ padding: 12px 14px;
2296
+ background: ${({ theme }) => theme.colors.surface};
2297
+ border-radius: ${({ theme }) => theme.border.radius};
2298
+ margin: 1.25rem 0;
2299
+ cursor: pointer;
2300
+ gap: 10px;
2301
+ `;
2302
+ function AchVerificationConsent({
2303
+ consentGiven = false,
2304
+ onChange,
2305
+ disabled = false,
2306
+ actionLabel = "Continue",
2307
+ testId
2308
+ }) {
2309
+ return /* @__PURE__ */ jsxs(ConsentRow, { children: [
2310
+ /* @__PURE__ */ jsx(
2311
+ CheckboxInput,
2312
+ {
2313
+ type: "checkbox",
2314
+ checked: consentGiven,
2315
+ onChange: (event) => onChange(event.target.checked),
2316
+ disabled,
2317
+ "data-testid": testId
2318
+ }
2319
+ ),
2320
+ /* @__PURE__ */ jsxs(Body100, { style: { margin: 0 }, children: [
2321
+ "By clicking ",
2322
+ actionLabel,
2323
+ ", I agree to the",
2324
+ " ",
2325
+ /* @__PURE__ */ jsx(
2326
+ "a",
2327
+ {
2328
+ href: "https://oatfi.com/payment-method-verification-consent",
2329
+ target: "_blank",
2330
+ rel: "noopener noreferrer",
2331
+ children: "payment method verification"
2332
+ }
2333
+ ),
2334
+ " ",
2335
+ "and acknowledge the",
2336
+ " ",
2337
+ /* @__PURE__ */ jsx(
2338
+ "a",
2339
+ {
2340
+ href: "https://oatfi.com/usa-patriot-act-disclosure-page",
2341
+ target: "_blank",
2342
+ rel: "noopener noreferrer",
2343
+ children: "USA PATRIOT Act disclosure"
2344
+ }
2345
+ ),
2346
+ "."
2347
+ ] })
2348
+ ] });
2349
+ }
2350
+
1537
2351
  const PreviewCard = styled.div`
1538
2352
  display: flex;
1539
2353
  gap: 2rem;
@@ -1605,5 +2419,5 @@ function Preview({ branding, className }) {
1605
2419
  return /* @__PURE__ */ jsx(ThemeProvider, { branding, children: /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(PreviewContent, {}) }) });
1606
2420
  }
1607
2421
 
1608
- export { AutocompleteInput, BaseInput, Body100, Body200, Body400, Button, ButtonContainer, CheckboxInput, Container, Content, CurrencyInput, DateInput, DetailElement, DetailRow, DetailsContainer, DotsMenu, DropDown, DropdownContainer, DropdownItem, DropdownList, EmailInput, FileInput, FlexColumnWrapper, FlexRowWrapper, Form, FormActions, FormCheckboxLabel, FormColumn, FormRow, FormSubtitle, FormTitle, H1, H2, H3, InputError, InputLabel, InputWrapper, Loader, NoResults, PhoneInput, Preview, RadioInput, SSNInput, SearchDropdown, SelectInput, StatusTag, Stepper, Tabs, TaxIdInput, TermsList, TextInput, ThemeProvider, buildMuiTheme, defaultTheme, mergeBranding, useTheme };
2422
+ export { AchVerificationConsent, AsteriskMark, AsteriskNote, AutocompleteInput, Badge, Banner, BaseInput, Body100, Body200, Body400, Button, ButtonContainer, CheckboxInput, CollapsibleSource, Container, Content$1 as Content, CurrencyInput, DateInput, DetailElement, DetailRow, DetailsContainer, DotsMenu, DropDown, DropdownContainer, DropdownItem, DropdownList, EmailInput, FieldsGrid, FileInput, FlexColumnWrapper, FlexRowWrapper, FooterActions, FooterRight, Footnote, Form, FormActions, FormCheckboxLabel, FormColumn, FormRow, FormSubtitle, FormTitle, H1, H2, H3, HelperText, InputError, InputLabel, InputWrapper, Loader, ManualMethodCard, MethodBody, MethodCard, MethodHeader, MethodTitle, NoResults, PhoneInput, PlaidMethodCard, PlaidTile, Preview, RadioInput, SSNInput, SearchDropdown, SelectInput, StatusTag, Stepper, Tabs, TaxIdInput, TermsDocument, TermsList, TextInput, ThemeProvider, UnderwritingStatus, UploadZone, buildMuiTheme, defaultTheme, mergeBranding, useTheme };
1609
2423
  //# sourceMappingURL=index.esm.js.map